diff options
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/ipxe/xen.h | 8 | ||||
| -rw-r--r-- | src/include/ipxe/xengrant.h | 148 |
2 files changed, 144 insertions, 12 deletions
diff --git a/src/include/ipxe/xen.h b/src/include/ipxe/xen.h index 546b0c348..60aabe03e 100644 --- a/src/include/ipxe/xen.h +++ b/src/include/ipxe/xen.h @@ -27,9 +27,11 @@ 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; + struct grant_entry_v1 *table; + /** Total grant table length */ + size_t len; + /** Entry size shift (for later version tables) */ + unsigned int shift; /** Number of grant table entries in use */ unsigned int used; /** Most recently used grant reference */ diff --git a/src/include/ipxe/xengrant.h b/src/include/ipxe/xengrant.h index 776eb9273..f9b3beb21 100644 --- a/src/include/ipxe/xengrant.h +++ b/src/include/ipxe/xengrant.h @@ -10,10 +10,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> +#include <stdlib.h> #include <ipxe/io.h> #include <ipxe/xen.h> #include <xen/grant_table.h> +/** Induced failure rate (for testing) */ +#define XENGRANT_FAIL_RATE 0 + /** * Query grant table size * @@ -47,6 +51,90 @@ xengrant_set_version ( struct xen_hypervisor *xen, } /** + * Get grant table version + * + * @v xen Xen hypervisor + * @v version Version + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xengrant_get_version ( struct xen_hypervisor *xen, + struct gnttab_get_version *version ) { + + return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op, + GNTTABOP_get_version, + virt_to_phys ( version ), 1 ); +} + +/** + * Get number of grant table entries + * + * @v xen Xen hypervisor + * @ret entries Number of grant table entries + */ +static inline __attribute__ (( always_inline )) unsigned int +xengrant_entries ( struct xen_hypervisor *xen ) { + + return ( ( xen->grant.len / sizeof ( xen->grant.table[0] ) ) + >> xen->grant.shift ); +} + +/** + * Get grant table entry header + * + * @v xen Xen hypervisor + * @v ref Grant reference + * @ret hdr Grant table entry header + */ +static inline __attribute__ (( always_inline )) struct grant_entry_header * +xengrant_header ( struct xen_hypervisor *xen, grant_ref_t ref ) { + struct grant_entry_v1 *v1; + + v1 = &xen->grant.table[ ref << xen->grant.shift ]; + return ( container_of ( &v1->flags, struct grant_entry_header, flags )); +} + +/** + * Get version 1 grant table entry + * + * @v hdr Grant table entry header + * @ret v1 Version 1 grant table entry + */ +static inline __attribute__ (( always_inline )) struct grant_entry_v1 * +xengrant_v1 ( struct grant_entry_header *hdr ) { + + return ( container_of ( &hdr->flags, struct grant_entry_v1, flags ) ); +} + +/** + * Get version 2 grant table entry + * + * @v hdr Grant table entry header + * @ret v2 Version 2 grant table entry + */ +static inline __attribute__ (( always_inline )) union grant_entry_v2 * +xengrant_v2 ( struct grant_entry_header *hdr ) { + + return ( container_of ( &hdr->flags, union grant_entry_v2, hdr.flags )); +} + +/** + * Zero grant table entry + * + * @v xen Xen hypervisor + * @v hdr Grant table entry header + */ +static inline void xengrant_zero ( struct xen_hypervisor *xen, + struct grant_entry_header *hdr ) { + uint32_t *dword = ( ( uint32_t * ) hdr ); + unsigned int i = ( ( sizeof ( xen->grant.table[0] ) / sizeof ( *dword )) + << xen->grant.shift ); + + while ( i-- ) + writel ( 0, dword++ ); +} + +/** * Invalidate access to a page * * @v xen Xen hypervisor @@ -54,10 +142,10 @@ xengrant_set_version ( struct xen_hypervisor *xen, */ 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]; + struct grant_entry_header *hdr = xengrant_header ( xen, ref ); /* Sanity check */ - assert ( ( readw ( &entry->hdr.flags ) & + assert ( ( readw ( &hdr->flags ) & ( GTF_reading | GTF_writing ) ) == 0 ); /* This should apparently be done using a cmpxchg instruction. @@ -65,7 +153,10 @@ xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) { * mainly since our control flow generally does not permit * failure paths to themselves fail. */ - writew ( 0, &entry->hdr.flags ); + writew ( 0, &hdr->flags ); + + /* Leave reference marked as in-use (see xengrant_alloc()) */ + writew ( DOMID_SELF, &hdr->domid ); } /** @@ -76,24 +167,63 @@ xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) { * @v domid Domain ID * @v subflags Additional flags * @v page Page start + * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int 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]; + struct grant_entry_header *hdr = xengrant_header ( xen, ref ); + struct grant_entry_v1 *v1 = xengrant_v1 ( hdr ); + union grant_entry_v2 *v2 = xengrant_v2 ( hdr ); unsigned long frame = ( virt_to_phys ( page ) / PAGE_SIZE ); - writew ( domid, &entry->full_page.hdr.domid ); + /* Fail (for test purposes) if applicable */ + if ( ( XENGRANT_FAIL_RATE > 0 ) && + ( random() % XENGRANT_FAIL_RATE ) == 0 ) { + return -EAGAIN; + } + + /* Record frame number. This may fail on a 64-bit system if + * we are using v1 grant tables. On a 32-bit system, there is + * no way for this code path to fail (with either v1 or v2 + * grant tables); we allow the compiler to optimise the + * failure paths away to save space. + */ if ( sizeof ( physaddr_t ) == sizeof ( uint64_t ) ) { - writeq ( frame, &entry->full_page.frame ); + + /* 64-bit system */ + if ( xen->grant.shift ) { + /* Version 2 table: no possible failure */ + writeq ( frame, &v2->full_page.frame ); + } else { + /* Version 1 table: may fail if address above 16TB */ + if ( frame > 0xffffffffUL ) + return -ERANGE; + writel ( frame, &v1->frame ); + } + } else { - writel ( frame, &entry->full_page.frame ); + + /* 32-bit system */ + if ( xen->grant.shift ) { + /* Version 2 table: no possible failure */ + writel ( frame, &v2->full_page.frame ); + } else { + /* Version 1 table: no possible failure */ + writel ( frame, &v1->frame ); + } } + + /* Record domain ID and flags */ + writew ( domid, &hdr->domid ); wmb(); - writew ( ( GTF_permit_access | subflags ), &entry->full_page.hdr.flags); + writew ( ( GTF_permit_access | subflags ), &hdr->flags ); wmb(); + + return 0; } +extern int xengrant_init ( struct xen_hypervisor *xen ); 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, |
