1 #ifndef _IPXE_XENGRANT_H
2 #define _IPXE_XENGRANT_H
3
4 /** @file
5 *
6 * Xen grant tables
7 *
8 */
9
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <ipxe/io.h>
15 #include <ipxe/xen.h>
16 #include <xen/grant_table.h>
17
18 /** Induced failure rate (for testing) */
19 #define XENGRANT_FAIL_RATE 0
20
21 /**
22 * Query grant table size
23 *
24 * @v xen Xen hypervisor
25 * @v size Table size
26 * @ret xenrc Xen status code
27 */
28 static inline __attribute__ (( always_inline )) int
xengrant_query_size(struct xen_hypervisor * xen,struct gnttab_query_size * size)29 xengrant_query_size ( struct xen_hypervisor *xen,
30 struct gnttab_query_size *size ) {
31
32 return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
33 GNTTABOP_query_size,
34 virt_to_phys ( size ), 1 );
35 }
36
37 /**
38 * Set grant table version
39 *
40 * @v xen Xen hypervisor
41 * @v version Version
42 * @ret xenrc Xen status code
43 */
44 static inline __attribute__ (( always_inline )) int
xengrant_set_version(struct xen_hypervisor * xen,struct gnttab_set_version * version)45 xengrant_set_version ( struct xen_hypervisor *xen,
46 struct gnttab_set_version *version ) {
47
48 return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
49 GNTTABOP_set_version,
50 virt_to_phys ( version ), 1 );
51 }
52
53 /**
54 * Get grant table version
55 *
56 * @v xen Xen hypervisor
57 * @v version Version
58 * @ret xenrc Xen status code
59 */
60 static inline __attribute__ (( always_inline )) int
xengrant_get_version(struct xen_hypervisor * xen,struct gnttab_get_version * version)61 xengrant_get_version ( struct xen_hypervisor *xen,
62 struct gnttab_get_version *version ) {
63
64 return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
65 GNTTABOP_get_version,
66 virt_to_phys ( version ), 1 );
67 }
68
69 /**
70 * Get number of grant table entries
71 *
72 * @v xen Xen hypervisor
73 * @ret entries Number of grant table entries
74 */
75 static inline __attribute__ (( always_inline )) unsigned int
xengrant_entries(struct xen_hypervisor * xen)76 xengrant_entries ( struct xen_hypervisor *xen ) {
77
78 return ( ( xen->grant.len / sizeof ( xen->grant.table[0] ) )
79 >> xen->grant.shift );
80 }
81
82 /**
83 * Get grant table entry header
84 *
85 * @v xen Xen hypervisor
86 * @v ref Grant reference
87 * @ret hdr Grant table entry header
88 */
89 static inline __attribute__ (( always_inline )) struct grant_entry_header *
xengrant_header(struct xen_hypervisor * xen,grant_ref_t ref)90 xengrant_header ( struct xen_hypervisor *xen, grant_ref_t ref ) {
91 struct grant_entry_v1 *v1;
92
93 v1 = &xen->grant.table[ ref << xen->grant.shift ];
94 return ( container_of ( &v1->flags, struct grant_entry_header, flags ));
95 }
96
97 /**
98 * Get version 1 grant table entry
99 *
100 * @v hdr Grant table entry header
101 * @ret v1 Version 1 grant table entry
102 */
103 static inline __attribute__ (( always_inline )) struct grant_entry_v1 *
xengrant_v1(struct grant_entry_header * hdr)104 xengrant_v1 ( struct grant_entry_header *hdr ) {
105
106 return ( container_of ( &hdr->flags, struct grant_entry_v1, flags ) );
107 }
108
109 /**
110 * Get version 2 grant table entry
111 *
112 * @v hdr Grant table entry header
113 * @ret v2 Version 2 grant table entry
114 */
115 static inline __attribute__ (( always_inline )) union grant_entry_v2 *
xengrant_v2(struct grant_entry_header * hdr)116 xengrant_v2 ( struct grant_entry_header *hdr ) {
117
118 return ( container_of ( &hdr->flags, union grant_entry_v2, hdr.flags ));
119 }
120
121 /**
122 * Zero grant table entry
123 *
124 * @v xen Xen hypervisor
125 * @v hdr Grant table entry header
126 */
xengrant_zero(struct xen_hypervisor * xen,struct grant_entry_header * hdr)127 static inline void xengrant_zero ( struct xen_hypervisor *xen,
128 struct grant_entry_header *hdr ) {
129 uint32_t *dword = ( ( uint32_t * ) hdr );
130 unsigned int i = ( ( sizeof ( xen->grant.table[0] ) / sizeof ( *dword ))
131 << xen->grant.shift );
132
133 while ( i-- )
134 writel ( 0, dword++ );
135 }
136
137 /**
138 * Invalidate access to a page
139 *
140 * @v xen Xen hypervisor
141 * @v ref Grant reference
142 */
143 static inline __attribute__ (( always_inline )) void
xengrant_invalidate(struct xen_hypervisor * xen,grant_ref_t ref)144 xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) {
145 struct grant_entry_header *hdr = xengrant_header ( xen, ref );
146
147 /* Sanity check */
148 assert ( ( readw ( &hdr->flags ) &
149 ( GTF_reading | GTF_writing ) ) == 0 );
150
151 /* This should apparently be done using a cmpxchg instruction.
152 * We omit this: partly in the interests of simplicity, but
153 * mainly since our control flow generally does not permit
154 * failure paths to themselves fail.
155 */
156 writew ( 0, &hdr->flags );
157
158 /* Leave reference marked as in-use (see xengrant_alloc()) */
159 writew ( DOMID_SELF, &hdr->domid );
160 }
161
162 /**
163 * Permit access to a page
164 *
165 * @v xen Xen hypervisor
166 * @v ref Grant reference
167 * @v domid Domain ID
168 * @v subflags Additional flags
169 * @v page Page start
170 * @ret rc Return status code
171 */
172 static inline __attribute__ (( always_inline )) int
xengrant_permit_access(struct xen_hypervisor * xen,grant_ref_t ref,domid_t domid,unsigned int subflags,void * page)173 xengrant_permit_access ( struct xen_hypervisor *xen, grant_ref_t ref,
174 domid_t domid, unsigned int subflags, void *page ) {
175 struct grant_entry_header *hdr = xengrant_header ( xen, ref );
176 struct grant_entry_v1 *v1 = xengrant_v1 ( hdr );
177 union grant_entry_v2 *v2 = xengrant_v2 ( hdr );
178 unsigned long frame = ( virt_to_phys ( page ) / PAGE_SIZE );
179
180 /* Fail (for test purposes) if applicable */
181 if ( ( XENGRANT_FAIL_RATE > 0 ) &&
182 ( random() % XENGRANT_FAIL_RATE ) == 0 ) {
183 return -EAGAIN;
184 }
185
186 /* Record frame number. This may fail on a 64-bit system if
187 * we are using v1 grant tables. On a 32-bit system, there is
188 * no way for this code path to fail (with either v1 or v2
189 * grant tables); we allow the compiler to optimise the
190 * failure paths away to save space.
191 */
192 if ( sizeof ( physaddr_t ) == sizeof ( uint64_t ) ) {
193
194 /* 64-bit system */
195 if ( xen->grant.shift ) {
196 /* Version 2 table: no possible failure */
197 writeq ( frame, &v2->full_page.frame );
198 } else {
199 /* Version 1 table: may fail if address above 16TB */
200 if ( frame > 0xffffffffUL )
201 return -ERANGE;
202 writel ( frame, &v1->frame );
203 }
204
205 } else {
206
207 /* 32-bit system */
208 if ( xen->grant.shift ) {
209 /* Version 2 table: no possible failure */
210 writel ( frame, &v2->full_page.frame );
211 } else {
212 /* Version 1 table: no possible failure */
213 writel ( frame, &v1->frame );
214 }
215 }
216
217 /* Record domain ID and flags */
218 writew ( domid, &hdr->domid );
219 wmb();
220 writew ( ( GTF_permit_access | subflags ), &hdr->flags );
221 wmb();
222
223 return 0;
224 }
225
226 extern int xengrant_init ( struct xen_hypervisor *xen );
227 extern int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs,
228 unsigned int count );
229 extern void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
230 unsigned int count );
231
232 #endif /* _IPXE_XENGRANT_H */
233