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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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  */
71 int xengrant_init ( struct xen_hypervisor *xen ) {
72  struct gnttab_query_size size;
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 }
int xengrant_init(struct xen_hypervisor *xen)
Initialise grant table.
Definition: xengrant.c:71
iPXE I/O API
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
Error codes.
struct golan_inbox_hdr hdr
Message header.
Definition: CIB_PRM.h:28
uint16_t readw(volatile uint16_t *io_addr)
Read 16-bit word from memory-mapped device.
uint16_t size
Buffer size.
Definition: dwmac.h:14
#define DBGC(...)
Definition: compiler.h:505
#define GNTTAB_NR_RESERVED_ENTRIES
Definition: grant_table.h:136
v1
Definition: xengrant.h:94
#define PAGE_SIZE
Page size.
Definition: io.h:28
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
uint32_t grant_ref_t
Definition: grant_table.h:100
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
#define EXEN(xenrc)
Convert a Xen status code to an iPXE status code.
Definition: xen.h:87
A Xen hypervisor.
Definition: xen.h:51
Xen interface.
FILE_SECBOOT(PERMITTED)
u32 version
Driver version.
Definition: ath9k_hw.c:1985
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static unsigned int count
Number of entries.
Definition: dwmac.h:225
#define GTF_type_mask
Definition: grant_table.h:153
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static const char grant_ref_t unsigned int struct io_buffer grant_ref_t * refs
Definition: netfront.h:94
Definition: grant_table.h:118
void xengrant_free(struct xen_hypervisor *xen, grant_ref_t *refs, unsigned int count)
Free grant references.
Definition: xengrant.c:215
unsigned int ref
Most recently used grant reference.
Definition: xen.h:39
union grant_entry_v2 * v2
Definition: xengrant.h:179
#define ENOBUFS
No buffer space available.
Definition: errno.h:499
#define DBGC2(...)
Definition: compiler.h:522
#define XENGRANT_TRY_VERSION
Grant table version to try setting.
Definition: xengrant.c:63
unsigned int shift
Entry size shift (for later version tables)
Definition: xen.h:35
struct xen_grant grant
Grant table.
Definition: xen.h:57
#define writew
Definition: w89c840.c:159
#define DOMID_SELF
Definition: xen.h:568
size_t len
Total grant table length.
Definition: xen.h:33
static const char grant_ref_t ref
Definition: netfront.h:92
Xen grant tables.
static void xengrant_zero(struct xen_hypervisor *xen, struct grant_entry_header *hdr)
Zero grant table entry.
Definition: xengrant.h:128
#define fls(x)
Find last (i.e.
Definition: strings.h:167
int xengrant_alloc(struct xen_hypervisor *xen, grant_ref_t *refs, unsigned int count)
Allocate grant references.
Definition: xengrant.c:149
unsigned int used
Number of grant table entries in use.
Definition: xen.h:37
String functions.
struct xen_hypervisor * xen
Xen hypervisor.
Definition: xenbus.h:23