summaryrefslogtreecommitdiffstats
path: root/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/include')
-rw-r--r--src/include/ipxe/xen.h8
-rw-r--r--src/include/ipxe/xengrant.h148
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,