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 addr		Physical address within page
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,physaddr_t addr)173 xengrant_permit_access ( struct xen_hypervisor *xen, grant_ref_t ref,
174 			 domid_t domid, unsigned int subflags,
175 			 physaddr_t addr ) {
176 	struct grant_entry_header *hdr = xengrant_header ( xen, ref );
177 	struct grant_entry_v1 *v1 = xengrant_v1 ( hdr );
178 	union grant_entry_v2 *v2 = xengrant_v2 ( hdr );
179 	unsigned long frame = ( addr / PAGE_SIZE );
180 
181 	/* Fail (for test purposes) if applicable */
182 	if ( ( XENGRANT_FAIL_RATE > 0 ) &&
183 	     ( random() % XENGRANT_FAIL_RATE ) == 0 ) {
184 		return -EAGAIN;
185 	}
186 
187 	/* Record frame number.  This may fail on a 64-bit system if
188 	 * we are using v1 grant tables.  On a 32-bit system, there is
189 	 * no way for this code path to fail (with either v1 or v2
190 	 * grant tables); we allow the compiler to optimise the
191 	 * failure paths away to save space.
192 	 */
193 	if ( sizeof ( physaddr_t ) == sizeof ( uint64_t ) ) {
194 
195 		/* 64-bit system */
196 		if ( xen->grant.shift ) {
197 			/* Version 2 table: no possible failure */
198 			writeq ( frame, &v2->full_page.frame );
199 		} else {
200 			/* Version 1 table: may fail if address above 16TB */
201 			if ( frame > 0xffffffffUL )
202 				return -ERANGE;
203 			writel ( frame, &v1->frame );
204 		}
205 
206 	} else {
207 
208 		/* 32-bit system */
209 		if ( xen->grant.shift ) {
210 			/* Version 2 table: no possible failure */
211 			writel ( frame, &v2->full_page.frame );
212 		} else {
213 			/* Version 1 table: no possible failure */
214 			writel ( frame, &v1->frame );
215 		}
216 	}
217 
218 	/* Record domain ID and flags */
219 	writew ( domid, &hdr->domid );
220 	wmb();
221 	writew ( ( GTF_permit_access | subflags ), &hdr->flags );
222 	wmb();
223 
224 	return 0;
225 }
226 
227 extern int xengrant_init ( struct xen_hypervisor *xen );
228 extern int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs,
229 			    unsigned int count );
230 extern void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
231 			    unsigned int count );
232 
233 #endif /* _IPXE_XENGRANT_H */
234