| #ifndef _IPXE_XENGRANT_H |
| #define _IPXE_XENGRANT_H |
| |
| /** @file |
| * |
| * Xen grant tables |
| * |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); |
| |
| #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 |
| * |
| * @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 ); |
| } |
| |
| /** |
| * 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 |
| * @v ref Grant reference |
| */ |
| static inline __attribute__ (( always_inline )) void |
| xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) { |
| struct grant_entry_header *hdr = xengrant_header ( xen, ref ); |
| |
| /* Sanity check */ |
| assert ( ( readw ( &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, &hdr->flags ); |
| |
| /* Leave reference marked as in-use (see xengrant_alloc()) */ |
| writew ( DOMID_SELF, &hdr->domid ); |
| } |
| |
| /** |
| * Permit access to a page |
| * |
| * @v xen Xen hypervisor |
| * @v ref Grant reference |
| * @v domid Domain ID |
| * @v subflags Additional flags |
| * @v addr Physical address within page |
| * @ret rc Return status code |
| */ |
| static inline __attribute__ (( always_inline )) int |
| xengrant_permit_access ( struct xen_hypervisor *xen, grant_ref_t ref, |
| domid_t domid, unsigned int subflags, |
| physaddr_t addr ) { |
| 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 = ( addr / PAGE_SIZE ); |
| |
| /* 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 ) ) { |
| |
| /* 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 { |
| |
| /* 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 ), &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, |
| unsigned int count ); |
| |
| #endif /* _IPXE_XENGRANT_H */ |