[xen] Add basic support for PV-HVM domains

Add basic support for Xen PV-HVM domains (detected via the Xen
platform PCI device with IDs 5853:0001), including support for
accessing configuration via XenStore and enumerating devices via
XenBus.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2014-07-28 23:38:30 +01:00
parent ec94a8798f
commit 036af27a45
18 changed files with 2272 additions and 0 deletions

View File

@@ -60,6 +60,9 @@ struct device_description {
/** EFI bus type */
#define BUS_TYPE_EFI 7
/** Xen bus type */
#define BUS_TYPE_XEN 8
/** A hardware device */
struct device {
/** Name */

View File

@@ -301,6 +301,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_memmap_settings ( ERRFILE_OTHER | 0x003f0000 )
#define ERRFILE_param_cmd ( ERRFILE_OTHER | 0x00400000 )
#define ERRFILE_deflate ( ERRFILE_OTHER | 0x00410000 )
#define ERRFILE_xenstore ( ERRFILE_OTHER | 0x00420000 )
#define ERRFILE_xenbus ( ERRFILE_OTHER | 0x00430000 )
#define ERRFILE_xengrant ( ERRFILE_OTHER | 0x00440000 )
/** @} */

73
src/include/ipxe/xen.h Normal file
View File

@@ -0,0 +1,73 @@
#ifndef _IPXE_XEN_H
#define _IPXE_XEN_H
/** @file
*
* Xen interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
/* Define Xen interface version before including any Xen header files */
#define __XEN_INTERFACE_VERSION__ 0x00040400
#include <stdint.h>
#include <ipxe/uaccess.h>
#include <xen/xen.h>
#include <xen/event_channel.h>
/* Memory barrier macros used by ring.h */
#define xen_mb() mb()
#define xen_rmb() rmb()
#define xen_wmb() wmb()
struct xen_hypercall;
/** A Xen grant table */
struct xen_grant {
/** Grant table entries */
union grant_entry_v2 *table;
/** Number of grant table entries (must be a power of two) */
unsigned int count;
/** Number of grant table entries in use */
unsigned int used;
/** Most recently used grant reference */
unsigned int ref;
};
/** A XenStore */
struct xen_store {
/** XenStore domain interface */
struct xenstore_domain_interface *intf;
/** Event channel */
evtchn_port_t port;
};
/** A Xen hypervisor */
struct xen_hypervisor {
/** Hypercall table */
struct xen_hypercall *hypercall;
/** Shared info page */
struct shared_info *shared;
/** Grant table */
struct xen_grant grant;
/** XenStore */
struct xen_store store;
};
#include <bits/xen.h>
/**
* Convert a Xen status code to an iPXE status code
*
* @v xenrc Xen status code (negated)
* @ret rc iPXE status code (before negation)
*
* Xen status codes are defined in the file include/xen/errno.h in the
* Xen repository. They happen to match the Linux error codes, some
* of which can be found in our include/ipxe/errno/linux.h.
*/
#define EXEN( xenrc ) EPLATFORM ( EINFO_EPLATFORM, -(xenrc) )
#endif /* _IPXE_XEN_H */

85
src/include/ipxe/xenbus.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef _IPXE_XENBUS_H
#define _IPXE_XENBUS_H
/** @file
*
* Xen device bus
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/device.h>
#include <ipxe/tables.h>
#include <ipxe/xen.h>
#include <xen/io/xenbus.h>
/** A Xen device */
struct xen_device {
/** Generic iPXE device */
struct device dev;
/** Xen hypervisor */
struct xen_hypervisor *xen;
/** XenStore key */
char *key;
/** Backend XenStore key */
char *backend;
/** Backend domain ID */
unsigned long backend_id;
/** Driver */
struct xen_driver *driver;
/** Driver-private data */
void *priv;
};
/** A Xen device driver */
struct xen_driver {
/** Name */
const char *name;
/** Device type */
const char *type;
/** Probe device
*
* @v xendev Xen device
* @ret rc Return status code
*/
int ( * probe ) ( struct xen_device *xendev );
/** Remove device
*
* @v xendev Xen device
*/
void ( * remove ) ( struct xen_device *xendev );
};
/** Xen device driver table */
#define XEN_DRIVERS __table ( struct xen_driver, "xen_drivers" )
/** Declare a Xen device driver */
#define __xen_driver __table_entry ( XEN_DRIVERS, 01 )
/**
* Set Xen device driver-private data
*
* @v xendev Xen device
* @v priv Private data
*/
static inline void xen_set_drvdata ( struct xen_device *xendev, void *priv ) {
xendev->priv = priv;
}
/**
* Get Xen device driver-private data
*
* @v xendev Xen device
* @ret priv Private data
*/
static inline void * xen_get_drvdata ( struct xen_device *xendev ) {
return xendev->priv;
}
extern int xenbus_set_state ( struct xen_device *xendev, int state );
extern int xenbus_backend_wait ( struct xen_device *xendev, int state );
extern int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent );
extern void xenbus_remove ( struct xen_hypervisor *xen, struct device *parent );
#endif /* _IPXE_XENBUS_H */

View File

@@ -0,0 +1,59 @@
#ifndef _IPXE_XENEVENT_H
#define _IPXE_XENEVENT_H
/** @file
*
* Xen events
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xen.h>
#include <xen/event_channel.h>
/**
* Close event channel
*
* @v xen Xen hypervisor
* @v close Event descriptor
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xenevent_close ( struct xen_hypervisor *xen, struct evtchn_close *close ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_event_channel_op,
EVTCHNOP_close, virt_to_phys ( close ) );
}
/**
* Send event
*
* @v xen Xen hypervisor
* @v send Event descriptor
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xenevent_send ( struct xen_hypervisor *xen, struct evtchn_send *send ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_event_channel_op,
EVTCHNOP_send, virt_to_phys ( send ) );
}
/**
* Allocate an unbound event channel
*
* @v xen Xen hypervisor
* @v alloc_unbound Event descriptor
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xenevent_alloc_unbound ( struct xen_hypervisor *xen,
struct evtchn_alloc_unbound *alloc_unbound ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_event_channel_op,
EVTCHNOP_alloc_unbound,
virt_to_phys ( alloc_unbound ) );
}
#endif /* _IPXE_XENEVENT_H */

102
src/include/ipxe/xengrant.h Normal file
View File

@@ -0,0 +1,102 @@
#ifndef _IPXE_XENGRANT_H
#define _IPXE_XENGRANT_H
/** @file
*
* Xen grant tables
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <ipxe/io.h>
#include <ipxe/xen.h>
#include <xen/grant_table.h>
/**
* Query grant table size
*
* @v xen Xen hypervisor
* @v size Table size
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xengrant_query_size ( struct xen_hypervisor *xen,
struct gnttab_query_size *size ) {
return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
GNTTABOP_query_size,
virt_to_phys ( size ), 1 );
}
/**
* Set grant table version
*
* @v xen Xen hypervisor
* @v version Version
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xengrant_set_version ( struct xen_hypervisor *xen,
struct gnttab_set_version *version ) {
return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
GNTTABOP_set_version,
virt_to_phys ( version ), 1 );
}
/**
* Invalidate access to a page
*
* @v xen Xen hypervisor
* @v ref Grant reference
*/
static inline __attribute__ (( always_inline )) void
xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) {
union grant_entry_v2 *entry = &xen->grant.table[ref];
/* Sanity check */
assert ( ( readw ( &entry->hdr.flags ) &
( GTF_reading | GTF_writing ) ) == 0 );
/* This should apparently be done using a cmpxchg instruction.
* We omit this: partly in the interests of simplicity, but
* mainly since our control flow generally does not permit
* failure paths to themselves fail.
*/
writew ( 0, &entry->hdr.flags );
}
/**
* Permit access to a page
*
* @v xen Xen hypervisor
* @v ref Grant reference
* @v domid Domain ID
* @v subflags Additional flags
* @v page Page start
*/
static inline __attribute__ (( always_inline )) void
xengrant_permit_access ( struct xen_hypervisor *xen, grant_ref_t ref,
domid_t domid, unsigned int subflags, void *page ) {
union grant_entry_v2 *entry = &xen->grant.table[ref];
unsigned long frame = ( virt_to_phys ( page ) / PAGE_SIZE );
writew ( domid, &entry->full_page.hdr.domid );
if ( sizeof ( physaddr_t ) == sizeof ( uint64_t ) ) {
writeq ( frame, &entry->full_page.frame );
} else {
writel ( frame, &entry->full_page.frame );
}
wmb();
writew ( ( GTF_permit_access | subflags ), &entry->full_page.hdr.flags);
wmb();
}
extern int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs,
unsigned int count );
extern void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
unsigned int count );
#endif /* _IPXE_XENGRANT_H */

46
src/include/ipxe/xenmem.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef _IPXE_XENMEM_H
#define _IPXE_XENMEM_H
/** @file
*
* Xen memory operations
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xen.h>
#include <xen/memory.h>
/**
* Add page to physical address space
*
* @v xen Xen hypervisor
* @v add Page mapping descriptor
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xenmem_add_to_physmap ( struct xen_hypervisor *xen,
struct xen_add_to_physmap *add ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_memory_op,
XENMEM_add_to_physmap, virt_to_phys ( add ) );
}
/**
* Remove page from physical address space
*
* @v xen Xen hypervisor
* @v remove Page mapping descriptor
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xenmem_remove_from_physmap ( struct xen_hypervisor *xen,
struct xen_remove_from_physmap *remove ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_memory_op,
XENMEM_remove_from_physmap,
virt_to_phys ( remove ) );
}
#endif /* _IPXE_XENMEM_H */

View File

@@ -0,0 +1,29 @@
#ifndef _IPXE_XENSTORE_H
#define _IPXE_XENSTORE_H
/** @file
*
* XenStore interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xen.h>
extern __attribute__ (( sentinel )) int
xenstore_read ( struct xen_hypervisor *xen, char **value, ... );
extern __attribute__ (( sentinel )) int
xenstore_read_num ( struct xen_hypervisor *xen, unsigned long *num, ... );
extern __attribute__ (( sentinel )) int
xenstore_write ( struct xen_hypervisor *xen, const char *value, ... );
extern __attribute__ (( sentinel )) int
xenstore_write_num ( struct xen_hypervisor *xen, unsigned long num, ... );
extern __attribute__ (( sentinel )) int
xenstore_rm ( struct xen_hypervisor *xen, ... );
extern __attribute__ (( sentinel )) int
xenstore_directory ( struct xen_hypervisor *xen, char **children, size_t *len,
... );
extern void xenstore_dump ( struct xen_hypervisor *xen, const char *key );
#endif /* _IPXE_XENSTORE_H */

44
src/include/ipxe/xenver.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef _IPXE_XENVER_H
#define _IPXE_VENVER_H
/** @file
*
* Xen version
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xen.h>
#include <xen/version.h>
/**
* Get Xen version
*
* @v xen Xen hypervisor
* @ret version Version (major.minor: 16 bits each)
*/
static inline __attribute__ (( always_inline )) uint32
xenver_version ( struct xen_hypervisor *xen ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_xen_version,
XENVER_version, 0 );
}
/**
* Get Xen extra version string
*
* @v xen Xen hypervisor
* @v extraversion Extra version string to fill in
* @ret xenrc Xen status code
*/
static inline __attribute__ (( always_inline )) int
xenver_extraversion ( struct xen_hypervisor *xen,
xen_extraversion_t *extraversion ) {
return xen_hypercall_2 ( xen, __HYPERVISOR_xen_version,
XENVER_extraversion,
virt_to_phys ( extraversion ) );
}
#endif /* _IPXE_XENVER_H */