Add qemu 2.4.0
[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
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <strings.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <ipxe/io.h>
27 #include <ipxe/xen.h>
28 #include <ipxe/xengrant.h>
29
30 /** @file
31  *
32  * Xen grant tables
33  *
34  */
35
36 /** Grant table version to try setting
37  *
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.
45  *
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.
50  *
51  * Avoid this problem by attempting to use version 1 tables, since
52  * otherwise we may render Windows unable to boot.
53  *
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
56  * requested version).
57  */
58 #define XENGRANT_TRY_VERSION 1
59
60 /**
61  * Initialise grant table
62  *
63  * @v xen               Xen hypervisor
64  * @ret rc              Return status code
65  */
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;
72         unsigned int version;
73         int xenrc;
74         int rc;
75
76         /* Get grant table size */
77         size.dom = DOMID_SELF;
78         if ( ( xenrc = xengrant_query_size ( xen, &size ) ) != 0 ) {
79                 rc = -EXEN ( xenrc );
80                 DBGC ( xen, "XENGRANT could not get table size: %s\n",
81                        strerror ( rc ) );
82                 return rc;
83         }
84         xen->grant.len = ( size.nr_frames * PAGE_SIZE );
85
86         /* Set grant table version, if applicable */
87         set_version.version = XENGRANT_TRY_VERSION;
88         if ( ( xenrc = xengrant_set_version ( xen, &set_version ) ) != 0 ) {
89                 rc = -EXEN ( xenrc );
90                 DBGC ( xen, "XENGRANT could not set version %d: %s\n",
91                        XENGRANT_TRY_VERSION, strerror ( rc ) );
92                 /* Continue; use whatever version is current */
93         }
94
95         /* Get grant table version */
96         get_version.dom = DOMID_SELF;
97         get_version.pad = 0;
98         if ( ( xenrc = xengrant_get_version ( xen, &get_version ) ) == 0 ) {
99                 version = get_version.version;
100                 switch ( version ) {
101
102                 case 0:
103                         /* Version not yet specified: will be version 1 */
104                         version = 1;
105                         break;
106
107                 case 1 :
108                         /* Version 1 table: nothing special to do */
109                         break;
110
111                 case 2:
112                         /* Version 2 table: configure shift appropriately */
113                         xen->grant.shift = ( fls ( sizeof ( *v2 ) /
114                                                    sizeof ( *v1 ) ) - 1 );
115                         break;
116
117                 default:
118                         /* Unsupported version */
119                         DBGC ( xen, "XENGRANT detected unsupported version "
120                                "%d\n", version );
121                         return -ENOTSUP;
122
123                 }
124         } else {
125                 rc = -EXEN ( xenrc );
126                 DBGC ( xen, "XENGRANT could not get version (assuming v1): "
127                        "%s\n", strerror ( rc ) );
128                 version = 1;
129         }
130
131         DBGC ( xen, "XENGRANT using v%d table with %d entries\n",
132                version, xengrant_entries ( xen ) );
133         return 0;
134 }
135
136 /**
137  * Allocate grant references
138  *
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
143  */
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;
150         unsigned int avail;
151         unsigned int ref;
152
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 );
158                 return -ENOBUFS;
159         }
160         DBGC ( xen, "XENGRANT allocating %d references (from %d of %d "
161                "available)\n", count, avail, entries );
162
163         /* Update number of references used */
164         xen->grant.used += count;
165
166         /* Find unused references */
167         for ( ref = xen->grant.ref ; count ; ref = ( ( ref + 1 ) & mask ) ) {
168
169                 /* Sanity check */
170                 assert ( check++ < entries );
171
172                 /* Skip reserved references */
173                 if ( ref < GNTTAB_NR_RESERVED_ENTRIES )
174                         continue;
175
176                 /* Skip in-use references */
177                 hdr = xengrant_header ( xen, ref );
178                 if ( readw ( &hdr->flags ) & GTF_type_mask )
179                         continue;
180                 if ( readw ( &hdr->domid ) == DOMID_SELF )
181                         continue;
182
183                 /* Zero reference */
184                 xengrant_zero ( xen, hdr );
185
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.
189                  */
190                 writew ( DOMID_SELF, &hdr->domid );
191                 DBGC2 ( xen, "XENGRANT allocated ref %d\n", ref );
192
193                 /* Record reference */
194                 refs[--count] = ref;
195         }
196
197         /* Update cursor */
198         xen->grant.ref = ref;
199
200         return 0;
201 }
202
203 /**
204  * Free grant references
205  *
206  * @v xen               Xen hypervisor
207  * @v refs              Grant references
208  * @v count             Number of references
209  */
210 void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
211                      unsigned int count ) {
212         struct grant_entry_header *hdr;
213         unsigned int ref;
214         unsigned int i;
215
216         /* Free references */
217         for ( i = 0 ; i < count ; i++ ) {
218
219                 /* Sanity check */
220                 ref = refs[i];
221                 assert ( ref < xengrant_entries ( xen ) );
222
223                 /* Zero reference */
224                 hdr = xengrant_header ( xen, ref );
225                 xengrant_zero ( xen, hdr );
226                 DBGC2 ( xen, "XENGRANT freed ref %d\n", ref );
227         }
228 }