[xen] Use version 1 grant tables by default

Using version 1 grant tables limits guests to using 16TB of grantable
RAM, and prevents the use of subpage grants.  Some versions of the Xen
hypervisor refuse to allow the grant table version to be set after the
first grant references have been created, so the loaded operating
system may be stuck with whatever choice we make here.  We therefore
currently use version 2 grant tables, since they give the most
flexibility to the loaded OS.

Current versions (7.2.0) of the Windows PV drivers have no support for
version 2 grant tables, and will merrily create version 1 entries in
what the hypervisor believes to be a version 2 table.  This causes
some confusion.

Avoid this problem by attempting to use version 1 tables, since
otherwise we may render Windows unable to boot.

Play nicely with other potential bootloaders by accepting either
version 1 or version 2 grant tables (if we are unable to set our
requested version).

Note that the use of version 1 tables on a 64-bit system introduces a
possible failure path in which a frame number cannot fit into the
32-bit field within the v1 structure.  This in turn introduces
additional failure paths into netfront_transmit() and
netfront_refill_rx().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2014-08-13 17:23:11 +01:00
parent 3f39f9fcb3
commit be79ca535a
5 changed files with 351 additions and 111 deletions

View File

@@ -145,22 +145,24 @@ static void hvm_unmap_hypercall ( struct hvm_device *hvm ) {
*
* @v hvm HVM device
* @v space Source mapping space
* @v pages Number of pages
* @v len Length (must be a multiple of PAGE_SIZE)
* @ret mmio MMIO space address, or NULL on error
*/
static void * hvm_ioremap ( struct hvm_device *hvm, unsigned int space,
unsigned int pages ) {
size_t len ) {
struct xen_add_to_physmap add;
struct xen_remove_from_physmap remove;
unsigned int pages = ( len / PAGE_SIZE );
physaddr_t mmio_phys;
unsigned int i;
size_t len;
void *mmio;
int xenrc;
int rc;
/* Sanity check */
assert ( ( len % PAGE_SIZE ) == 0 );
/* Check for available space */
len = ( pages * PAGE_SIZE );
if ( ( hvm->mmio_offset + len ) > hvm->mmio_len ) {
DBGC ( hvm, "HVM could not allocate %zd bytes of MMIO space "
"(%zd of %zd remaining)\n", len,
@@ -218,12 +220,12 @@ static void * hvm_ioremap ( struct hvm_device *hvm, unsigned int space,
*
* @v hvm HVM device
* @v mmio MMIO space address
* @v pages Number of pages
* @v len Length (must be a multiple of PAGE_SIZE)
*/
static void hvm_iounmap ( struct hvm_device *hvm, void *mmio,
unsigned int pages ) {
static void hvm_iounmap ( struct hvm_device *hvm, void *mmio, size_t len ) {
struct xen_remove_from_physmap remove;
physaddr_t mmio_phys = virt_to_phys ( mmio );
unsigned int pages = ( len / PAGE_SIZE );
unsigned int i;
int xenrc;
int rc;
@@ -258,7 +260,8 @@ static int hvm_map_shared_info ( struct hvm_device *hvm ) {
int rc;
/* Map shared info page */
hvm->xen.shared = hvm_ioremap ( hvm, XENMAPSPACE_shared_info, 1 );
hvm->xen.shared = hvm_ioremap ( hvm, XENMAPSPACE_shared_info,
PAGE_SIZE );
if ( ! hvm->xen.shared ) {
rc = -ENOMEM;
goto err_alloc;
@@ -273,7 +276,7 @@ static int hvm_map_shared_info ( struct hvm_device *hvm ) {
return 0;
hvm_iounmap ( hvm, hvm->xen.shared, 1 );
hvm_iounmap ( hvm, hvm->xen.shared, PAGE_SIZE );
err_alloc:
return rc;
}
@@ -286,7 +289,7 @@ static int hvm_map_shared_info ( struct hvm_device *hvm ) {
static void hvm_unmap_shared_info ( struct hvm_device *hvm ) {
/* Unmap shared info page */
hvm_iounmap ( hvm, hvm->xen.shared, 1 );
hvm_iounmap ( hvm, hvm->xen.shared, PAGE_SIZE );
}
/**
@@ -296,56 +299,26 @@ static void hvm_unmap_shared_info ( struct hvm_device *hvm ) {
* @ret rc Return status code
*/
static int hvm_map_grant ( struct hvm_device *hvm ) {
struct gnttab_query_size size;
struct gnttab_set_version version;
physaddr_t grant_phys;
size_t len;
int xenrc;
int rc;
/* Get grant table size */
size.dom = DOMID_SELF;
if ( ( xenrc = xengrant_query_size ( &hvm->xen, &size ) ) != 0 ) {
rc = -EXEN ( xenrc );
DBGC ( hvm, "HVM could not get grant table size: %s\n",
/* Initialise grant table */
if ( ( rc = xengrant_init ( &hvm->xen ) ) != 0 ) {
DBGC ( hvm, "HVM could not initialise grant table: %s\n",
strerror ( rc ) );
goto err_query_size;
}
len = ( size.nr_frames * PAGE_SIZE );
/* Configure to use version 2 tables */
version.version = 2;
if ( ( xenrc = xengrant_set_version ( &hvm->xen, &version ) ) != 0 ) {
rc = -EXEN ( xenrc );
DBGC ( hvm, "HVM could not set version 2 grant table: %s\n",
strerror ( rc ) );
goto err_set_version;
}
if ( version.version != 2 ) {
DBGC ( hvm, "HVM could not set version 2 grant table\n" );
rc = -ENOTTY;
goto err_set_version;
return rc;
}
/* Map grant table */
hvm->xen.grant.table = hvm_ioremap ( hvm, XENMAPSPACE_grant_table,
size.nr_frames );
if ( ! hvm->xen.grant.table ) {
rc = -ENODEV;
goto err_ioremap;
}
hvm->xen.grant.len );
if ( ! hvm->xen.grant.table )
return -ENODEV;
grant_phys = virt_to_phys ( hvm->xen.grant.table );
DBGC2 ( hvm, "HVM mapped grant table at [%08lx,%08lx)\n",
grant_phys, ( grant_phys + len ) );
hvm->xen.grant.count = ( len / sizeof ( hvm->xen.grant.table[0] ) );
grant_phys, ( grant_phys + hvm->xen.grant.len ) );
return 0;
hvm_iounmap ( hvm, hvm->xen.grant.table, size.nr_frames );
err_ioremap:
err_set_version:
err_query_size:
return rc;
}
/**
@@ -354,11 +327,9 @@ static int hvm_map_grant ( struct hvm_device *hvm ) {
* @v hvm HVM device
*/
static void hvm_unmap_grant ( struct hvm_device *hvm ) {
size_t len;
/* Unmap grant table */
len = ( hvm->xen.grant.count * sizeof ( hvm->xen.grant.table[0] ) );
hvm_iounmap ( hvm, hvm->xen.grant.table, ( len / PAGE_SIZE ) );
hvm_iounmap ( hvm, hvm->xen.grant.table, hvm->xen.grant.len );
}
/**