6.4 Connecting Devices with XenBus
The XenBus, in the context of device drivers, is an informal protocol built on top of the XenStore, which provides a way of enumerating the (virtual) devices available to a given domain, and connecting to them. Implementing the XenBus interface is not required when porting a kernel to Xen. It is predominantly used in Linux to isolate the Xen-specific code behind a relatively abstract interface.
The XenBus interface is intended to roughly mirror that of a device bus such as PCI. It is defined in linux-2.6-xen-sparse/include/xen/xenbus.h2. Each virtual device has three major components:
- A shared memory page containing the ring buffers
- An event channel signaling activity in the ring
- A XenStore entry containing configuration information
These components are tied together in the bus interface by the structure shown in Listing 6.1. This device structure is passed as an argument to a number of other functions, which (between them) implement the driver for the device.
Listing 6.1. The structure defining a XenBus device
[from: linux-2.6-xensparse/include/xen/xenbus.h]
71 struct xenbus_device { 72 const char *devicetype; 73 const char *nodename; 74 const char *otherend; 75 int otherend_id; 76 struct xenbus_watch otherend_watch; 77 struct device dev; 78 enum xenbus_state state; 79 struct completion down; 80 };
The exact definition of this structure is tied quite closely to Linux; the device struct, for example, represents a Linux device. It can, however, be used as a good starting point for building a similar abstraction layer for other systems.
The core component of the XenBus interface, indeed the only part that needs to be implemented by all systems wanting to use the paravirtualized devices available to Xen guests, is the xenbus_state enumerated type. Each device has such a type associated with it.
The XenBus state, unlike the rest of the XenBus interface, is defined by Xen, in the io/xenbus.h public header. This is used while negotiating a connection between the two halves of the device driver. There are seven states defined. In normal operation, the state should be gradually incremented as the device is initialized, connected, and then disconnected. The possible states are:
- XenbusStateUnknown represents the initial state of the device on the bus, before either end has been connected.
- XenbusStateInitialising is the state while the back end is in process of initializing itself.
- XenbusStateInitWait should be entered by the back end while it is waiting for information before completing initialization. The source of the information can be hot-plug notifications within the Domain 0 kernel, or further information from the connecting guest. The meaning of this state is that the driver itself is initialized, but needs more information before it can be connected to.
- XenbusStateInitialised should be set to indicate that the back end is now ready for connection. After the bus is in this state, the front end may proceed to connect.
- XenbusStateConnected is the normal state of the bus. For most of the duration of a guest's run, the bus will be in this state indicating that the front and back ends are communicating normally.
- XenbusStateClosing is set to indicate that the device has become unavailable. The front and back halves of the driver are still connected at this point, but the back end is no longer doing anything sensible with the commands received from the front. When this state is entered, the front end should begin a graceful shutdown.
- XenbusStateClosed is the final state, once the two halves of the driver have disconnected from each other.
Not all drivers make use of the XenBus mechanism. The two notable exceptions are the console and XenStore. Both of these are mapped directly from the start info page, and have no information in the XenStore. In the case of the console, this is so that a guest kernel can start outputting debugging information to the console as soon as possible. In the case of the XenStore, it is obvious that the device can't use XenBus, because XenBus is built on top of the XenStore, and the XenStore cannot be used to get information required to map itself.