iPXE
xengrant.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdint.h>
28#include <strings.h>
29#include <errno.h>
30#include <assert.h>
31#include <ipxe/io.h>
32#include <ipxe/xen.h>
33#include <ipxe/xengrant.h>
34
35/** @file
36 *
37 * Xen grant tables
38 *
39 */
40
41/** Grant table version to try setting
42 *
43 * Using version 1 grant tables limits guests to using 16TB of
44 * grantable RAM, and prevents the use of subpage grants. Some
45 * versions of the Xen hypervisor refuse to allow the grant table
46 * version to be set after the first grant references have been
47 * created, so the loaded operating system may be stuck with whatever
48 * choice we make here. We therefore currently use version 2 grant
49 * tables, since they give the most flexibility to the loaded OS.
50 *
51 * Current versions (7.2.0) of the Windows PV drivers have no support
52 * for version 2 grant tables, and will merrily create version 1
53 * entries in what the hypervisor believes to be a version 2 table.
54 * This causes some confusion.
55 *
56 * Avoid this problem by attempting to use version 1 tables, since
57 * otherwise we may render Windows unable to boot.
58 *
59 * Play nicely with other potential bootloaders by accepting either
60 * version 1 or version 2 grant tables (if we are unable to set our
61 * requested version).
62 */
63#define XENGRANT_TRY_VERSION 1
64
65/**
66 * Initialise grant table
67 *
68 * @v xen Xen hypervisor
69 * @ret rc Return status code
70 */
71int xengrant_init ( struct xen_hypervisor *xen ) {
73 struct gnttab_set_version set_version;
74 struct gnttab_get_version get_version;
75 struct grant_entry_v1 *v1;
76 union grant_entry_v2 *v2;
77 unsigned int version;
78 int xenrc;
79 int rc;
80
81 /* Get grant table size */
82 size.dom = DOMID_SELF;
83 if ( ( xenrc = xengrant_query_size ( xen, &size ) ) != 0 ) {
84 rc = -EXEN ( xenrc );
85 DBGC ( xen, "XENGRANT could not get table size: %s\n",
86 strerror ( rc ) );
87 return rc;
88 }
89 xen->grant.len = ( size.nr_frames * PAGE_SIZE );
90
91 /* Set grant table version, if applicable */
92 set_version.version = XENGRANT_TRY_VERSION;
93 if ( ( xenrc = xengrant_set_version ( xen, &set_version ) ) != 0 ) {
94 rc = -EXEN ( xenrc );
95 DBGC ( xen, "XENGRANT could not set version %d: %s\n",
97 /* Continue; use whatever version is current */
98 }
99
100 /* Get grant table version */
101 get_version.dom = DOMID_SELF;
102 get_version.pad = 0;
103 if ( ( xenrc = xengrant_get_version ( xen, &get_version ) ) == 0 ) {
104 version = get_version.version;
105 switch ( version ) {
106
107 case 0:
108 /* Version not yet specified: will be version 1 */
109 version = 1;
110 break;
111
112 case 1 :
113 /* Version 1 table: nothing special to do */
114 break;
115
116 case 2:
117 /* Version 2 table: configure shift appropriately */
118 xen->grant.shift = ( fls ( sizeof ( *v2 ) /
119 sizeof ( *v1 ) ) - 1 );
120 break;
121
122 default:
123 /* Unsupported version */
124 DBGC ( xen, "XENGRANT detected unsupported version "
125 "%d\n", version );
126 return -ENOTSUP;
127
128 }
129 } else {
130 rc = -EXEN ( xenrc );
131 DBGC ( xen, "XENGRANT could not get version (assuming v1): "
132 "%s\n", strerror ( rc ) );
133 version = 1;
134 }
135
136 DBGC ( xen, "XENGRANT using v%d table with %d entries\n",
137 version, xengrant_entries ( xen ) );
138 return 0;
139}
140
141/**
142 * Allocate grant references
143 *
144 * @v xen Xen hypervisor
145 * @v refs Grant references to fill in
146 * @v count Number of references
147 * @ret rc Return status code
148 */
150 unsigned int count ) {
151 struct grant_entry_header *hdr;
152 unsigned int entries = xengrant_entries ( xen );
153 unsigned int mask = ( entries - 1 );
154 unsigned int check = 0;
155 unsigned int avail;
156 unsigned int ref;
157
158 /* Fail unless we have enough references available */
159 avail = ( entries - xen->grant.used - GNTTAB_NR_RESERVED_ENTRIES );
160 if ( avail < count ) {
161 DBGC ( xen, "XENGRANT cannot allocate %d references (only %d "
162 "of %d available)\n", count, avail, entries );
163 return -ENOBUFS;
164 }
165 DBGC ( xen, "XENGRANT allocating %d references (from %d of %d "
166 "available)\n", count, avail, entries );
167
168 /* Update number of references used */
169 xen->grant.used += count;
170
171 /* Find unused references */
172 for ( ref = xen->grant.ref ; count ; ref = ( ( ref + 1 ) & mask ) ) {
173
174 /* Sanity check */
175 assert ( check++ < entries );
176
177 /* Skip reserved references */
179 continue;
180
181 /* Skip in-use references */
182 hdr = xengrant_header ( xen, ref );
183 if ( readw ( &hdr->flags ) & GTF_type_mask )
184 continue;
185 if ( readw ( &hdr->domid ) == DOMID_SELF )
186 continue;
187
188 /* Zero reference */
189 xengrant_zero ( xen, hdr );
190
191 /* Mark reference as in-use. We leave the flags as
192 * empty (to avoid creating a valid grant table entry)
193 * and set the domid to DOMID_SELF.
194 */
195 writew ( DOMID_SELF, &hdr->domid );
196 DBGC2 ( xen, "XENGRANT allocated ref %d\n", ref );
197
198 /* Record reference */
199 refs[--count] = ref;
200 }
201
202 /* Update cursor */
203 xen->grant.ref = ref;
204
205 return 0;
206}
207
208/**
209 * Free grant references
210 *
211 * @v xen Xen hypervisor
212 * @v refs Grant references
213 * @v count Number of references
214 */
216 unsigned int count ) {
217 struct grant_entry_header *hdr;
218 unsigned int ref;
219 unsigned int i;
220
221 /* Free references */
222 for ( i = 0 ; i < count ; i++ ) {
223
224 /* Sanity check */
225 ref = refs[i];
226 assert ( ref < xengrant_entries ( xen ) );
227
228 /* Zero reference */
229 hdr = xengrant_header ( xen, ref );
230 xengrant_zero ( xen, hdr );
231 DBGC2 ( xen, "XENGRANT freed ref %d\n", ref );
232 }
233}
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
u32 version
Driver version.
Definition ath9k_hw.c:1985
Error codes.
#define GNTTAB_NR_RESERVED_ENTRIES
#define GTF_type_mask
#define grant_entry_v1
uint32_t grant_ref_t
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
uint16_t size
Buffer size.
Definition dwmac.h:3
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ENOBUFS
No buffer space available.
Definition errno.h:499
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
iPXE I/O API
#define PAGE_SIZE
Page size.
Definition io.h:28
Xen interface.
#define EXEN(xenrc)
Convert a Xen status code to an iPXE status code.
Definition xen.h:87
String functions.
#define fls(x)
Find last (i.e.
Definition strings.h:167
#define DOMID_SELF
Definition xen.h:581
static const char grant_ref_t ref
Definition netfront.h:93
static const char grant_ref_t unsigned int struct io_buffer grant_ref_t * refs
Definition netfront.h:94
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
unsigned int used
Number of grant table entries in use.
Definition xen.h:37
unsigned int shift
Entry size shift (for later version tables)
Definition xen.h:35
size_t len
Total grant table length.
Definition xen.h:33
unsigned int ref
Most recently used grant reference.
Definition xen.h:39
A Xen hypervisor.
Definition xen.h:51
struct xen_grant grant
Grant table.
Definition xen.h:57
#define writew
Definition w89c840.c:159
#define readw
Definition w89c840.c:156
int xengrant_alloc(struct xen_hypervisor *xen, grant_ref_t *refs, unsigned int count)
Allocate grant references.
Definition xengrant.c:149
void xengrant_free(struct xen_hypervisor *xen, grant_ref_t *refs, unsigned int count)
Free grant references.
Definition xengrant.c:215
int xengrant_init(struct xen_hypervisor *xen)
Initialise grant table.
Definition xengrant.c:71
#define XENGRANT_TRY_VERSION
Grant table version to try setting.
Definition xengrant.c:63
Xen grant tables.
static void xengrant_zero(struct xen_hypervisor *xen, struct grant_entry_header *hdr)
Zero grant table entry.
Definition xengrant.h:128
v1
Definition xengrant.h:94
union grant_entry_v2 * v2
Definition xengrant.h:179