#ifndef _IPXE_XENGRANT_H #define _IPXE_XENGRANT_H /** @file * * Xen grant tables * */ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include #include #include /** 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 page Page start * @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, void *page ) { 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 ); /* 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 */