2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER );
28 #include <ipxe/xengrant.h>
36 /** Grant table version to try setting
38 * Using version 1 grant tables limits guests to using 16TB of
39 * grantable RAM, and prevents the use of subpage grants. Some
40 * versions of the Xen hypervisor refuse to allow the grant table
41 * version to be set after the first grant references have been
42 * created, so the loaded operating system may be stuck with whatever
43 * choice we make here. We therefore currently use version 2 grant
44 * tables, since they give the most flexibility to the loaded OS.
46 * Current versions (7.2.0) of the Windows PV drivers have no support
47 * for version 2 grant tables, and will merrily create version 1
48 * entries in what the hypervisor believes to be a version 2 table.
49 * This causes some confusion.
51 * Avoid this problem by attempting to use version 1 tables, since
52 * otherwise we may render Windows unable to boot.
54 * Play nicely with other potential bootloaders by accepting either
55 * version 1 or version 2 grant tables (if we are unable to set our
58 #define XENGRANT_TRY_VERSION 1
61 * Initialise grant table
63 * @v xen Xen hypervisor
64 * @ret rc Return status code
66 int xengrant_init ( struct xen_hypervisor *xen ) {
67 struct gnttab_query_size size;
68 struct gnttab_set_version set_version;
69 struct gnttab_get_version get_version;
70 struct grant_entry_v1 *v1;
71 union grant_entry_v2 *v2;
76 /* Get grant table size */
77 size.dom = DOMID_SELF;
78 if ( ( xenrc = xengrant_query_size ( xen, &size ) ) != 0 ) {
80 DBGC ( xen, "XENGRANT could not get table size: %s\n",
84 xen->grant.len = ( size.nr_frames * PAGE_SIZE );
86 /* Set grant table version, if applicable */
87 set_version.version = XENGRANT_TRY_VERSION;
88 if ( ( xenrc = xengrant_set_version ( xen, &set_version ) ) != 0 ) {
90 DBGC ( xen, "XENGRANT could not set version %d: %s\n",
91 XENGRANT_TRY_VERSION, strerror ( rc ) );
92 /* Continue; use whatever version is current */
95 /* Get grant table version */
96 get_version.dom = DOMID_SELF;
98 if ( ( xenrc = xengrant_get_version ( xen, &get_version ) ) == 0 ) {
99 version = get_version.version;
103 /* Version not yet specified: will be version 1 */
108 /* Version 1 table: nothing special to do */
112 /* Version 2 table: configure shift appropriately */
113 xen->grant.shift = ( fls ( sizeof ( *v2 ) /
114 sizeof ( *v1 ) ) - 1 );
118 /* Unsupported version */
119 DBGC ( xen, "XENGRANT detected unsupported version "
125 rc = -EXEN ( xenrc );
126 DBGC ( xen, "XENGRANT could not get version (assuming v1): "
127 "%s\n", strerror ( rc ) );
131 DBGC ( xen, "XENGRANT using v%d table with %d entries\n",
132 version, xengrant_entries ( xen ) );
137 * Allocate grant references
139 * @v xen Xen hypervisor
140 * @v refs Grant references to fill in
141 * @v count Number of references
142 * @ret rc Return status code
144 int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs,
145 unsigned int count ) {
146 struct grant_entry_header *hdr;
147 unsigned int entries = xengrant_entries ( xen );
148 unsigned int mask = ( entries - 1 );
149 unsigned int check = 0;
153 /* Fail unless we have enough references available */
154 avail = ( entries - xen->grant.used - GNTTAB_NR_RESERVED_ENTRIES );
155 if ( avail < count ) {
156 DBGC ( xen, "XENGRANT cannot allocate %d references (only %d "
157 "of %d available)\n", count, avail, entries );
160 DBGC ( xen, "XENGRANT allocating %d references (from %d of %d "
161 "available)\n", count, avail, entries );
163 /* Update number of references used */
164 xen->grant.used += count;
166 /* Find unused references */
167 for ( ref = xen->grant.ref ; count ; ref = ( ( ref + 1 ) & mask ) ) {
170 assert ( check++ < entries );
172 /* Skip reserved references */
173 if ( ref < GNTTAB_NR_RESERVED_ENTRIES )
176 /* Skip in-use references */
177 hdr = xengrant_header ( xen, ref );
178 if ( readw ( &hdr->flags ) & GTF_type_mask )
180 if ( readw ( &hdr->domid ) == DOMID_SELF )
184 xengrant_zero ( xen, hdr );
186 /* Mark reference as in-use. We leave the flags as
187 * empty (to avoid creating a valid grant table entry)
188 * and set the domid to DOMID_SELF.
190 writew ( DOMID_SELF, &hdr->domid );
191 DBGC2 ( xen, "XENGRANT allocated ref %d\n", ref );
193 /* Record reference */
198 xen->grant.ref = ref;
204 * Free grant references
206 * @v xen Xen hypervisor
207 * @v refs Grant references
208 * @v count Number of references
210 void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
211 unsigned int count ) {
212 struct grant_entry_header *hdr;
216 /* Free references */
217 for ( i = 0 ; i < count ; i++ ) {
221 assert ( ref < xengrant_entries ( xen ) );
224 hdr = xengrant_header ( xen, ref );
225 xengrant_zero ( xen, hdr );
226 DBGC2 ( xen, "XENGRANT freed ref %d\n", ref );