iPXE
xenbus.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <ipxe/malloc.h>
31 #include <ipxe/device.h>
32 #include <ipxe/timer.h>
33 #include <ipxe/nap.h>
34 #include <ipxe/xen.h>
35 #include <ipxe/xenstore.h>
36 #include <ipxe/xenbus.h>
37 
38 /** @file
39  *
40  * Xen device bus
41  *
42  */
43 
44 /* Disambiguate the various error causes */
45 #define ETIMEDOUT_UNKNOWN \
46  __einfo_error ( EINFO_ETIMEDOUT_UNKNOWN )
47 #define EINFO_ETIMEDOUT_UNKNOWN \
48  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateUnknown, \
49  "Unknown" )
50 #define ETIMEDOUT_INITIALISING \
51  __einfo_error ( EINFO_ETIMEDOUT_INITIALISING )
52 #define EINFO_ETIMEDOUT_INITIALISING \
53  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitialising, \
54  "Initialising" )
55 #define ETIMEDOUT_INITWAIT \
56  __einfo_error ( EINFO_ETIMEDOUT_INITWAIT )
57 #define EINFO_ETIMEDOUT_INITWAIT \
58  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitWait, \
59  "InitWait" )
60 #define ETIMEDOUT_INITIALISED \
61  __einfo_error ( EINFO_ETIMEDOUT_INITIALISED )
62 #define EINFO_ETIMEDOUT_INITIALISED \
63  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitialised, \
64  "Initialised" )
65 #define ETIMEDOUT_CONNECTED \
66  __einfo_error ( EINFO_ETIMEDOUT_CONNECTED )
67 #define EINFO_ETIMEDOUT_CONNECTED \
68  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateConnected, \
69  "Connected" )
70 #define ETIMEDOUT_CLOSING \
71  __einfo_error ( EINFO_ETIMEDOUT_CLOSING )
72 #define EINFO_ETIMEDOUT_CLOSING \
73  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateClosing, \
74  "Closing" )
75 #define ETIMEDOUT_CLOSED \
76  __einfo_error ( EINFO_ETIMEDOUT_CLOSED )
77 #define EINFO_ETIMEDOUT_CLOSED \
78  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateClosed, \
79  "Closed" )
80 #define ETIMEDOUT_RECONFIGURING \
81  __einfo_error ( EINFO_ETIMEDOUT_RECONFIGURING )
82 #define EINFO_ETIMEDOUT_RECONFIGURING \
83  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateReconfiguring, \
84  "Reconfiguring" )
85 #define ETIMEDOUT_RECONFIGURED \
86  __einfo_error ( EINFO_ETIMEDOUT_RECONFIGURED )
87 #define EINFO_ETIMEDOUT_RECONFIGURED \
88  __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateReconfigured, \
89  "Reconfigured" )
90 #define ETIMEDOUT_STATE( state ) \
91  EUNIQ ( EINFO_ETIMEDOUT, (state), ETIMEDOUT_UNKNOWN, \
92  ETIMEDOUT_INITIALISING, ETIMEDOUT_INITWAIT, \
93  ETIMEDOUT_INITIALISED, ETIMEDOUT_CONNECTED, \
94  ETIMEDOUT_CLOSING, ETIMEDOUT_CLOSED, \
95  ETIMEDOUT_RECONFIGURING, ETIMEDOUT_RECONFIGURED )
96 
97 /** Maximum time to wait for backend to reach a given state, in ticks */
98 #define XENBUS_BACKEND_TIMEOUT ( 5 * TICKS_PER_SEC )
99 
100 /**
101  * Set device state
102  *
103  * @v xendev Xen device
104  * @v state New state
105  * @ret rc Return status code
106  */
107 int xenbus_set_state ( struct xen_device *xendev, int state ) {
108  int rc;
109 
110  /* Attempt to set state */
111  if ( ( rc = xenstore_write_num ( xendev->xen, state, xendev->key,
112  "state", NULL ) ) != 0 ) {
113  DBGC ( xendev, "XENBUS %s could not set state=\"%d\": %s\n",
114  xendev->key, state, strerror ( rc ) );
115  return rc;
116  }
117 
118  return 0;
119 }
120 
121 /**
122  * Get backend state
123  *
124  * @v xendev Xen device
125  * @ret state Backend state, or negative error
126  */
127 int xenbus_backend_state ( struct xen_device *xendev ) {
128  unsigned long state;
129  int rc;
130 
131  /* Attempt to get backend state */
132  if ( ( rc = xenstore_read_num ( xendev->xen, &state, xendev->backend,
133  "state", NULL ) ) != 0 ) {
134  DBGC ( xendev, "XENBUS %s could not read %s/state: %s\n",
135  xendev->key, xendev->backend, strerror ( rc ) );
136  return rc;
137  }
138 
139  return state;
140 }
141 
142 /**
143  * Wait for backend to reach a given state
144  *
145  * @v xendev Xen device
146  * @v state Desired backend state
147  * @ret rc Return status code
148  */
149 int xenbus_backend_wait ( struct xen_device *xendev, int state ) {
150  unsigned long started = currticks();
151  unsigned long elapsed;
152  unsigned int attempts = 0;
153  int current_state;
154  int rc;
155 
156  /* Wait for backend to reach this state */
157  do {
158 
159  /* Get current backend state */
160  current_state = xenbus_backend_state ( xendev );
161  if ( current_state < 0 ) {
162  rc = current_state;
163  return rc;
164  }
165  if ( current_state == state )
166  return 0;
167 
168  /* Allow time for backend to react */
169  cpu_nap();
170 
171  /* XenStore is a very slow interface; any fixed delay
172  * time would be dwarfed by the XenStore access time.
173  * We therefore use wall clock to time out this
174  * operation.
175  */
176  elapsed = ( currticks() - started );
177  attempts++;
178 
179  } while ( elapsed < XENBUS_BACKEND_TIMEOUT );
180 
181  /* Construct status code from current backend state */
182  rc = -ETIMEDOUT_STATE ( current_state );
183  DBGC ( xendev, "XENBUS %s timed out after %d attempts waiting for "
184  "%s/state=\"%d\": %s\n", xendev->key, attempts, xendev->backend,
185  state, strerror ( rc ) );
186 
187  return rc;
188 }
189 
190 /**
191  * Find driver for Xen device
192  *
193  * @v type Device type
194  * @ret driver Driver, or NULL
195  */
196 static struct xen_driver * xenbus_find_driver ( const char *type ) {
197  struct xen_driver *xendrv;
198 
199  for_each_table_entry ( xendrv, XEN_DRIVERS ) {
200  if ( strcmp ( xendrv->type, type ) == 0 )
201  return xendrv;
202  }
203  return NULL;
204 }
205 
206 /**
207  * Probe Xen device
208  *
209  * @v xen Xen hypervisor
210  * @v parent Parent device
211  * @v instance Device instance
212  * @v driver Device driver
213  * @ret rc Return status code
214  */
215 static int xenbus_probe_device ( struct xen_hypervisor *xen,
216  struct device *parent, const char *instance,
217  struct xen_driver *driver ) {
218  const char *type = driver->type;
219  struct xen_device *xendev;
220  size_t key_len;
221  int rc;
222 
223  /* Allocate and initialise structure */
224  key_len = ( 7 /* "device/" */ + strlen ( type ) + 1 /* "/" */ +
225  strlen ( instance ) + 1 /* NUL */ );
226  xendev = zalloc ( sizeof ( *xendev ) + key_len );
227  if ( ! xendev ) {
228  rc = -ENOMEM;
229  goto err_alloc;
230  }
231  snprintf ( xendev->dev.name, sizeof ( xendev->dev.name ), "%s/%s",
232  type, instance );
233  xendev->dev.desc.bus_type = BUS_TYPE_XEN;
234  INIT_LIST_HEAD ( &xendev->dev.children );
235  list_add_tail ( &xendev->dev.siblings, &parent->children );
236  xendev->dev.parent = parent;
237  xendev->xen = xen;
238  xendev->key = ( ( void * ) ( xendev + 1 ) );
239  snprintf ( xendev->key, key_len, "device/%s/%s", type, instance );
240  xendev->driver = driver;
241  xendev->dev.driver_name = driver->name;
242  DBGC ( xendev, "XENBUS %s has driver \"%s\"\n", xendev->key,
243  xendev->driver->name );
244 
245  /* Read backend key */
246  if ( ( rc = xenstore_read ( xen, &xendev->backend, xendev->key,
247  "backend", NULL ) ) != 0 ) {
248  DBGC ( xendev, "XENBUS %s could not read backend: %s\n",
249  xendev->key, strerror ( rc ) );
250  goto err_read_backend;
251  }
252 
253  /* Read backend domain ID */
254  if ( ( rc = xenstore_read_num ( xen, &xendev->backend_id, xendev->key,
255  "backend-id", NULL ) ) != 0 ) {
256  DBGC ( xendev, "XENBUS %s could not read backend-id: %s\n",
257  xendev->key, strerror ( rc ) );
258  goto err_read_backend_id;
259  }
260  DBGC ( xendev, "XENBUS %s backend=\"%s\" in domain %ld\n",
261  xendev->key, xendev->backend, xendev->backend_id );
262 
263  /* Probe driver */
264  if ( ( rc = xendev->driver->probe ( xendev ) ) != 0 ) {
265  DBGC ( xendev, "XENBUS could not probe %s: %s\n",
266  xendev->key, strerror ( rc ) );
267  goto err_probe;
268  }
269 
270  return 0;
271 
272  xendev->driver->remove ( xendev );
273  err_probe:
274  err_read_backend_id:
275  free ( xendev->backend );
276  err_read_backend:
277  list_del ( &xendev->dev.siblings );
278  free ( xendev );
279  err_alloc:
280  return rc;
281 }
282 
283 /**
284  * Remove Xen device
285  *
286  * @v xendev Xen device
287  */
288 static void xenbus_remove_device ( struct xen_device *xendev ) {
289 
290  /* Remove device */
291  xendev->driver->remove ( xendev );
292  free ( xendev->backend );
293  list_del ( &xendev->dev.siblings );
294  free ( xendev );
295 }
296 
297 /**
298  * Probe Xen devices of a given type
299  *
300  * @v xen Xen hypervisor
301  * @v parent Parent device
302  * @v type Device type
303  * @ret rc Return status code
304  */
305 static int xenbus_probe_type ( struct xen_hypervisor *xen,
306  struct device *parent, const char *type ) {
307  struct xen_driver *driver;
308  char *children;
309  char *child;
310  size_t len;
311  int rc;
312 
313  /* Look for a driver */
314  driver = xenbus_find_driver ( type );
315  if ( ! driver ) {
316  DBGC ( xen, "XENBUS has no driver for \"%s\" devices\n", type );
317  /* Not a fatal error */
318  rc = 0;
319  goto err_no_driver;
320  }
321 
322  /* Get children of this key */
323  if ( ( rc = xenstore_directory ( xen, &children, &len, "device",
324  type, NULL ) ) != 0 ) {
325  DBGC ( xen, "XENBUS could not list \"%s\" devices: %s\n",
326  type, strerror ( rc ) );
327  goto err_directory;
328  }
329 
330  /* Probe each child */
331  for ( child = children ; child < ( children + len ) ;
332  child += ( strlen ( child ) + 1 /* NUL */ ) ) {
333  if ( ( rc = xenbus_probe_device ( xen, parent, child,
334  driver ) ) != 0 )
335  goto err_probe_device;
336  }
337 
338  free ( children );
339  return 0;
340 
341  err_probe_device:
342  free ( children );
343  err_directory:
344  err_no_driver:
345  return rc;
346 }
347 
348 /**
349  * Probe Xen bus
350  *
351  * @v xen Xen hypervisor
352  * @v parent Parent device
353  * @ret rc Return status code
354  */
355 int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent ) {
356  char *types;
357  char *type;
358  size_t len;
359  int rc;
360 
361  /* Get children of "device" key */
362  if ( ( rc = xenstore_directory ( xen, &types, &len, "device",
363  NULL ) ) != 0 ) {
364  DBGC ( xen, "XENBUS could not list device types: %s\n",
365  strerror ( rc ) );
366  goto err_directory;
367  }
368 
369  /* Probe each child type */
370  for ( type = types ; type < ( types + len ) ;
371  type += ( strlen ( type ) + 1 /* NUL */ ) ) {
372  if ( ( rc = xenbus_probe_type ( xen, parent, type ) ) != 0 )
373  goto err_probe_type;
374  }
375 
376  free ( types );
377  return 0;
378 
379  xenbus_remove ( xen, parent );
380  err_probe_type:
381  free ( types );
382  err_directory:
383  return rc;
384 }
385 
386 /**
387  * Remove Xen bus
388  *
389  * @v xen Xen hypervisor
390  * @v parent Parent device
391  */
393  struct device *parent ) {
394  struct xen_device *xendev;
395  struct xen_device *tmp;
396 
397  /* Remove devices */
398  list_for_each_entry_safe ( xendev, tmp, &parent->children,
399  dev.siblings ) {
400  xenbus_remove_device ( xendev );
401  }
402 }
CPU sleeping.
char * backend
Backend XenStore key.
Definition: xenbus.h:27
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define XEN_DRIVERS
Xen device driver table.
Definition: xenbus.h:56
uint8_t state
State.
Definition: eth_slow.h:48
int xenbus_backend_wait(struct xen_device *xendev, int state)
Wait for backend to reach a given state.
Definition: xenbus.c:149
Error codes.
uint32_t type
Operating system type.
Definition: ena.h:12
#define DBGC(...)
Definition: compiler.h:505
char name[40]
Name.
Definition: device.h:79
const char * type
Device type.
Definition: xenbus.h:41
iPXE timers
int xenstore_read(struct xen_hypervisor *xen, char **value,...)
Read XenStore value.
Definition: xenstore.c:372
static int xenbus_probe_type(struct xen_hypervisor *xen, struct device *parent, const char *type)
Probe Xen devices of a given type.
Definition: xenbus.c:305
int xenstore_write_num(struct xen_hypervisor *xen, unsigned long num,...)
Write XenStore numeric value.
Definition: xenstore.c:461
struct device * parent
Bus device.
Definition: device.h:89
Dynamic memory allocation.
A Xen hypervisor.
Definition: xen.h:51
int xenbus_probe(struct xen_hypervisor *xen, struct device *parent)
Probe Xen bus.
Definition: xenbus.c:355
Xen interface.
unsigned long tmp
Definition: linux_pci.h:65
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
A Xen device.
Definition: xenbus.h:19
#define ENOMEM
Not enough space.
Definition: errno.h:535
A hardware device.
Definition: device.h:77
char unsigned long const char unsigned long char ** children
Definition: xenstore.h:26
static int started
"startup() has been called" flag
Definition: init.c:38
struct xen_driver * driver
Driver.
Definition: xenbus.h:31
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:94
ring len
Length.
Definition: dwmac.h:231
const char * name
Name.
Definition: xenbus.h:39
const char * driver_name
Driver name.
Definition: device.h:81
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:459
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
static struct xen_driver * xenbus_find_driver(const char *type)
Find driver for Xen device.
Definition: xenbus.c:196
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
int xenstore_directory(struct xen_hypervisor *xen, char **children, size_t *len,...)
Read XenStore directory.
Definition: xenstore.c:504
Xen device bus.
struct list_head siblings
Devices on the same bus.
Definition: device.h:85
unsigned long backend_id
Backend domain ID.
Definition: xenbus.h:29
int xenstore_read_num(struct xen_hypervisor *xen, unsigned long *num,...)
Read XenStore numeric value.
Definition: xenstore.c:391
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
#define ETIMEDOUT_STATE(state)
Definition: xenbus.c:90
FILE_SECBOOT(PERMITTED)
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:46
int(* probe)(struct xen_device *xendev)
Probe device.
Definition: xenbus.h:47
unsigned int bus_type
Bus type.
Definition: device.h:25
void cpu_nap(void)
Sleep with interrupts enabled until next CPU interrupt.
int strcmp(const char *first, const char *second)
Compare strings.
Definition: string.c:174
#define XENBUS_BACKEND_TIMEOUT
Maximum time to wait for backend to reach a given state, in ticks.
Definition: xenbus.c:98
void(* remove)(struct xen_device *xendev)
Remove device.
Definition: xenbus.h:52
struct list_head children
Devices attached to this device.
Definition: device.h:87
char * key
XenStore key.
Definition: xenbus.h:25
struct device_description desc
Device description.
Definition: device.h:83
static int xenbus_probe_device(struct xen_hypervisor *xen, struct device *parent, const char *instance, struct xen_driver *driver)
Probe Xen device.
Definition: xenbus.c:215
void xenbus_remove(struct xen_hypervisor *xen __unused, struct device *parent)
Remove Xen bus.
Definition: xenbus.c:392
Device model.
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:383
struct device dev
Generic iPXE device.
Definition: xenbus.h:21
A Xen device driver.
Definition: xenbus.h:37
#define BUS_TYPE_XEN
Xen bus type.
Definition: device.h:65
unsigned long currticks(void)
Get current system time in ticks.
Definition: timer.c:43
int xenbus_backend_state(struct xen_device *xendev)
Get backend state.
Definition: xenbus.c:127
int xenbus_set_state(struct xen_device *xendev, int state)
Set device state.
Definition: xenbus.c:107
XenStore interface.
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
struct xen_hypervisor * xen
Xen hypervisor.
Definition: xenbus.h:23
static void xenbus_remove_device(struct xen_device *xendev)
Remove Xen device.
Definition: xenbus.c:288