These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / interface / xen / xengrant.c
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
26 #include <stdint.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <ipxe/io.h>
31 #include <ipxe/xen.h>
32 #include <ipxe/xengrant.h>
33
34 /** @file
35  *
36  * Xen grant tables
37  *
38  */
39
40 /** Grant table version to try setting
41  *
42  * Using version 1 grant tables limits guests to using 16TB of
43  * grantable RAM, and prevents the use of subpage grants.  Some
44  * versions of the Xen hypervisor refuse to allow the grant table
45  * version to be set after the first grant references have been
46  * created, so the loaded operating system may be stuck with whatever
47  * choice we make here.  We therefore currently use version 2 grant
48  * tables, since they give the most flexibility to the loaded OS.
49  *
50  * Current versions (7.2.0) of the Windows PV drivers have no support
51  * for version 2 grant tables, and will merrily create version 1
52  * entries in what the hypervisor believes to be a version 2 table.
53  * This causes some confusion.
54  *
55  * Avoid this problem by attempting to use version 1 tables, since
56  * otherwise we may render Windows unable to boot.
57  *
58  * Play nicely with other potential bootloaders by accepting either
59  * version 1 or version 2 grant tables (if we are unable to set our
60  * requested version).
61  */
62 #define XENGRANT_TRY_VERSION 1
63
64 /**
65  * Initialise grant table
66  *
67  * @v xen               Xen hypervisor
68  * @ret rc              Return status code
69  */
70 int xengrant_init ( struct xen_hypervisor *xen ) {
71         struct gnttab_query_size size;
72         struct gnttab_set_version set_version;
73         struct gnttab_get_version get_version;
74         struct grant_entry_v1 *v1;
75         union grant_entry_v2 *v2;
76         unsigned int version;
77         int xenrc;
78         int rc;
79
80         /* Get grant table size */
81         size.dom = DOMID_SELF;
82         if ( ( xenrc = xengrant_query_size ( xen, &size ) ) != 0 ) {
83                 rc = -EXEN ( xenrc );
84                 DBGC ( xen, "XENGRANT could not get table size: %s\n",
85                        strerror ( rc ) );
86                 return rc;
87         }
88         xen->grant.len = ( size.nr_frames * PAGE_SIZE );
89
90         /* Set grant table version, if applicable */
91         set_version.version = XENGRANT_TRY_VERSION;
92         if ( ( xenrc = xengrant_set_version ( xen, &set_version ) ) != 0 ) {
93                 rc = -EXEN ( xenrc );
94                 DBGC ( xen, "XENGRANT could not set version %d: %s\n",
95                        XENGRANT_TRY_VERSION, strerror ( rc ) );
96                 /* Continue; use whatever version is current */
97         }
98
99         /* Get grant table version */
100         get_version.dom = DOMID_SELF;
101         get_version.pad = 0;
102         if ( ( xenrc = xengrant_get_version ( xen, &get_version ) ) == 0 ) {
103                 version = get_version.version;
104                 switch ( version ) {
105
106                 case 0:
107                         /* Version not yet specified: will be version 1 */
108                         version = 1;
109                         break;
110
111                 case 1 :
112                         /* Version 1 table: nothing special to do */
113                         break;
114
115                 case 2:
116                         /* Version 2 table: configure shift appropriately */
117                         xen->grant.shift = ( fls ( sizeof ( *v2 ) /
118                                                    sizeof ( *v1 ) ) - 1 );
119                         break;
120
121                 default:
122                         /* Unsupported version */
123                         DBGC ( xen, "XENGRANT detected unsupported version "
124                                "%d\n", version );
125                         return -ENOTSUP;
126
127                 }
128         } else {
129                 rc = -EXEN ( xenrc );
130                 DBGC ( xen, "XENGRANT could not get version (assuming v1): "
131                        "%s\n", strerror ( rc ) );
132                 version = 1;
133         }
134
135         DBGC ( xen, "XENGRANT using v%d table with %d entries\n",
136                version, xengrant_entries ( xen ) );
137         return 0;
138 }
139
140 /**
141  * Allocate grant references
142  *
143  * @v xen               Xen hypervisor
144  * @v refs              Grant references to fill in
145  * @v count             Number of references
146  * @ret rc              Return status code
147  */
148 int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs,
149                      unsigned int count ) {
150         struct grant_entry_header *hdr;
151         unsigned int entries = xengrant_entries ( xen );
152         unsigned int mask = ( entries - 1 );
153         unsigned int check = 0;
154         unsigned int avail;
155         unsigned int ref;
156
157         /* Fail unless we have enough references available */
158         avail = ( entries - xen->grant.used - GNTTAB_NR_RESERVED_ENTRIES );
159         if ( avail < count ) {
160                 DBGC ( xen, "XENGRANT cannot allocate %d references (only %d "
161                        "of %d available)\n", count, avail, entries );
162                 return -ENOBUFS;
163         }
164         DBGC ( xen, "XENGRANT allocating %d references (from %d of %d "
165                "available)\n", count, avail, entries );
166
167         /* Update number of references used */
168         xen->grant.used += count;
169
170         /* Find unused references */
171         for ( ref = xen->grant.ref ; count ; ref = ( ( ref + 1 ) & mask ) ) {
172
173                 /* Sanity check */
174                 assert ( check++ < entries );
175
176                 /* Skip reserved references */
177                 if ( ref < GNTTAB_NR_RESERVED_ENTRIES )
178                         continue;
179
180                 /* Skip in-use references */
181                 hdr = xengrant_header ( xen, ref );
182                 if ( readw ( &hdr->flags ) & GTF_type_mask )
183                         continue;
184                 if ( readw ( &hdr->domid ) == DOMID_SELF )
185                         continue;
186
187                 /* Zero reference */
188                 xengrant_zero ( xen, hdr );
189
190                 /* Mark reference as in-use.  We leave the flags as
191                  * empty (to avoid creating a valid grant table entry)
192                  * and set the domid to DOMID_SELF.
193                  */
194                 writew ( DOMID_SELF, &hdr->domid );
195                 DBGC2 ( xen, "XENGRANT allocated ref %d\n", ref );
196
197                 /* Record reference */
198                 refs[--count] = ref;
199         }
200
201         /* Update cursor */
202         xen->grant.ref = ref;
203
204         return 0;
205 }
206
207 /**
208  * Free grant references
209  *
210  * @v xen               Xen hypervisor
211  * @v refs              Grant references
212  * @v count             Number of references
213  */
214 void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
215                      unsigned int count ) {
216         struct grant_entry_header *hdr;
217         unsigned int ref;
218         unsigned int i;
219
220         /* Free references */
221         for ( i = 0 ; i < count ; i++ ) {
222
223                 /* Sanity check */
224                 ref = refs[i];
225                 assert ( ref < xengrant_entries ( xen ) );
226
227                 /* Zero reference */
228                 hdr = xengrant_header ( xen, ref );
229                 xengrant_zero ( xen, hdr );
230                 DBGC2 ( xen, "XENGRANT freed ref %d\n", ref );
231         }
232 }