summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/include/ipxe/xengrant.h
blob: 451a3ceeeb34ed55b58679c26985b3d0679a6a41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#ifndef _IPXE_XENGRANT_H
#define _IPXE_XENGRANT_H

/** @file
 *
 * Xen grant tables
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <stdint.h>
#include <stdlib.h>
#include <ipxe/io.h>
#include <ipxe/xen.h>
#include <xen/grant_table.h>

/** Induced failure rate (for testing) */
#define XENGRANT_FAIL_RATE 0

/**
 * Query grant table size
 *
 * @v xen		Xen hypervisor
 * @v size		Table size
 * @ret xenrc		Xen status code
 */
static inline __attribute__ (( always_inline )) int
xengrant_query_size ( struct xen_hypervisor *xen,
		      struct gnttab_query_size *size ) {

	return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
				 GNTTABOP_query_size,
				 virt_to_phys ( size ), 1 );
}

/**
 * Set grant table version
 *
 * @v xen		Xen hypervisor
 * @v version		Version
 * @ret xenrc		Xen status code
 */
static inline __attribute__ (( always_inline )) int
xengrant_set_version ( struct xen_hypervisor *xen,
		       struct gnttab_set_version *version ) {

	return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
				 GNTTABOP_set_version,
				 virt_to_phys ( version ), 1 );
}

/**
 * Get grant table version
 *
 * @v xen		Xen hypervisor
 * @v version		Version
 * @ret xenrc		Xen status code
 */
static inline __attribute__ (( always_inline )) int
xengrant_get_version ( struct xen_hypervisor *xen,
		       struct gnttab_get_version *version ) {

	return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op,
				 GNTTABOP_get_version,
				 virt_to_phys ( version ), 1 );
}

/**
 * Get number of grant table entries
 *
 * @v xen		Xen hypervisor
 * @ret entries		Number of grant table entries
 */
static inline __attribute__ (( always_inline )) unsigned int
xengrant_entries ( struct xen_hypervisor *xen ) {

	return ( ( xen->grant.len / sizeof ( xen->grant.table[0] ) )
		 >> xen->grant.shift );
}

/**
 * Get grant table entry header
 *
 * @v xen		Xen hypervisor
 * @v ref		Grant reference
 * @ret hdr		Grant table entry header
 */
static inline __attribute__ (( always_inline )) struct grant_entry_header *
xengrant_header ( struct xen_hypervisor *xen, grant_ref_t ref ) {
	struct grant_entry_v1 *v1;

	v1 = &xen->grant.table[ ref << xen->grant.shift ];
	return ( container_of ( &v1->flags, struct grant_entry_header, flags ));
}

/**
 * Get version 1 grant table entry
 *
 * @v hdr		Grant table entry header
 * @ret v1		Version 1 grant table entry
 */
static inline __attribute__ (( always_inline )) struct grant_entry_v1 *
xengrant_v1 ( struct grant_entry_header *hdr ) {

	return ( container_of ( &hdr->flags, struct grant_entry_v1, flags ) );
}

/**
 * Get version 2 grant table entry
 *
 * @v hdr		Grant table entry header
 * @ret v2		Version 2 grant table entry
 */
static inline __attribute__ (( always_inline )) union grant_entry_v2 *
xengrant_v2 ( struct grant_entry_header *hdr ) {

	return ( container_of ( &hdr->flags, union grant_entry_v2, hdr.flags ));
}

/**
 * Zero grant table entry
 *
 * @v xen		Xen hypervisor
 * @v hdr		Grant table entry header
 */
static inline void xengrant_zero ( struct xen_hypervisor *xen,
				   struct grant_entry_header *hdr ) {
	uint32_t *dword = ( ( uint32_t * ) hdr );
	unsigned int i = ( ( sizeof ( xen->grant.table[0] ) / sizeof ( *dword ))
			   << xen->grant.shift );

	while ( i-- )
		writel ( 0, dword++ );
}

/**
 * Invalidate access to a page
 *
 * @v xen		Xen hypervisor
 * @v ref		Grant reference
 */
static inline __attribute__ (( always_inline )) void
xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) {
	struct grant_entry_header *hdr = xengrant_header ( xen, ref );

	/* Sanity check */
	assert ( ( readw ( &hdr->flags ) &
		   ( GTF_reading | GTF_writing ) ) == 0 );

	/* This should apparently be done using a cmpxchg instruction.
	 * We omit this: partly in the interests of simplicity, but
	 * mainly since our control flow generally does not permit
	 * failure paths to themselves fail.
	 */
	writew ( 0, &hdr->flags );

	/* Leave reference marked as in-use (see xengrant_alloc()) */
	writew ( DOMID_SELF, &hdr->domid );
}

/**
 * Permit access to a page
 *
 * @v xen		Xen hypervisor
 * @v ref		Grant reference
 * @v domid		Domain ID
 * @v subflags		Additional flags
 * @v page		Page start
 * @ret rc		Return status code
 */
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 ) {
	struct grant_entry_header *hdr = xengrant_header ( xen, ref );
	struct grant_entry_v1 *v1 = xengrant_v1 ( hdr );
	union grant_entry_v2 *v2 = xengrant_v2 ( hdr );
	unsigned long frame = ( virt_to_phys ( page ) / PAGE_SIZE );

	/* Fail (for test purposes) if applicable */
	if ( ( XENGRANT_FAIL_RATE > 0 ) &&
	     ( random() % XENGRANT_FAIL_RATE ) == 0 ) {
		return -EAGAIN;
	}

	/* Record frame number.  This may fail on a 64-bit system if
	 * we are using v1 grant tables.  On a 32-bit system, there is
	 * no way for this code path to fail (with either v1 or v2
	 * grant tables); we allow the compiler to optimise the
	 * failure paths away to save space.
	 */
	if ( sizeof ( physaddr_t ) == sizeof ( uint64_t ) ) {

		/* 64-bit system */
		if ( xen->grant.shift ) {
			/* Version 2 table: no possible failure */
			writeq ( frame, &v2->full_page.frame );
		} else {
			/* Version 1 table: may fail if address above 16TB */
			if ( frame > 0xffffffffUL )
				return -ERANGE;
			writel ( frame, &v1->frame );
		}

	} else {

		/* 32-bit system */
		if ( xen->grant.shift ) {
			/* Version 2 table: no possible failure */
			writel ( frame, &v2->full_page.frame );
		} else {
			/* Version 1 table: no possible failure */
			writel ( frame, &v1->frame );
		}
	}

	/* Record domain ID and flags */
	writew ( domid, &hdr->domid );
	wmb();
	writew ( ( GTF_permit_access | subflags ), &hdr->flags );
	wmb();

	return 0;
}

extern int xengrant_init ( struct xen_hypervisor *xen );
extern int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs,
			    unsigned int count );
extern void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs,
			    unsigned int count );

#endif /* _IPXE_XENGRANT_H */