233 lines
6.0 KiB
C
233 lines
6.0 KiB
C
#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 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 */
|