1 #include <err.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/mman.h>
6
7 #include <xenctrl.h>
8 #include <xenforeignmemory.h>
9 #include <xengnttab.h>
10 #include <xen-tools/common-macros.h>
11
12 static unsigned int nr_failures;
13 #define fail(fmt, ...) \
14 ({ \
15 nr_failures++; \
16 (void)printf(fmt, ##__VA_ARGS__); \
17 })
18
19 static xc_interface *xch;
20 static xenforeignmemory_handle *fh;
21 static xengnttab_handle *gh;
22
23 static xc_physinfo_t physinfo;
24
test_gnttab(uint32_t domid,unsigned int nr_frames,unsigned long gfn)25 static void test_gnttab(uint32_t domid, unsigned int nr_frames,
26 unsigned long gfn)
27 {
28 xenforeignmemory_resource_handle *res;
29 grant_entry_v1_t *gnttab = NULL;
30 size_t size;
31 int rc;
32 uint32_t refs[nr_frames], domids[nr_frames];
33 void *grants;
34
35 printf(" Test grant table\n");
36
37 /* Obtain the grant table resource size. */
38 rc = xenforeignmemory_resource_size(
39 fh, domid, XENMEM_resource_grant_table,
40 XENMEM_resource_grant_table_id_shared, &size);
41
42 /*
43 * A failure of this call indicates missing kernel support for size
44 * ioctl(), or missing Xen acquire_resource support.
45 */
46 if ( rc )
47 return fail(" Fail: Get size: %d - %s\n", errno, strerror(errno));
48
49 /*
50 * Getting 32 frames back instead of nr_frames indicates Xen is missing
51 * the bugfix to make size requests actually return real data.
52 */
53 if ( (size >> XC_PAGE_SHIFT) != nr_frames )
54 return fail(" Fail: Get size: expected %u frames, got %zu\n",
55 nr_frames, size >> XC_PAGE_SHIFT);
56
57 /* Map the entire grant table. */
58 res = xenforeignmemory_map_resource(
59 fh, domid, XENMEM_resource_grant_table,
60 XENMEM_resource_grant_table_id_shared, 0, size >> XC_PAGE_SHIFT,
61 (void **)&gnttab, PROT_READ | PROT_WRITE, 0);
62
63 /*
64 * Failure here with E2BIG indicates Xen is missing the bugfix to map
65 * resources larger than 32 frames.
66 */
67 if ( !res )
68 return fail(" Fail: Map grant table %d - %s\n",
69 errno, strerror(errno));
70
71 /* Put each gref at a unique offset in its frame. */
72 for ( unsigned int i = 0; i < nr_frames; i++ )
73 {
74 unsigned int gref = i * (XC_PAGE_SIZE / sizeof(*gnttab)) + i;
75
76 refs[i] = gref;
77 domids[i] = domid;
78
79 gnttab[gref].domid = 0;
80 gnttab[gref].frame = gfn;
81 gnttab[gref].flags = GTF_permit_access;
82 }
83
84 /* Map grants. */
85 grants = xengnttab_map_grant_refs(gh, nr_frames, domids, refs,
86 PROT_READ | PROT_WRITE);
87
88 /*
89 * Failure here indicates either that the frames were not mapped
90 * in the correct order or xenforeignmemory_map_resource() didn't
91 * give us the frames we asked for to begin with.
92 */
93 if ( grants == NULL )
94 {
95 fail(" Fail: Map grants %d - %s\n", errno, strerror(errno));
96 goto out;
97 }
98
99 /* Unmap grants. */
100 rc = xengnttab_unmap(gh, grants, nr_frames);
101
102 if ( rc )
103 fail(" Fail: Unmap grants %d - %s\n", errno, strerror(errno));
104
105 /* Unmap grant table. */
106 out:
107 rc = xenforeignmemory_unmap_resource(fh, res);
108 if ( rc )
109 return fail(" Fail: Unmap grant table %d - %s\n",
110 errno, strerror(errno));
111
112 /*
113 * Verify that an attempt to map the status frames fails, as the domain is
114 * in gnttab v1 mode.
115 */
116 res = xenforeignmemory_map_resource(
117 fh, domid, XENMEM_resource_grant_table,
118 XENMEM_resource_grant_table_id_status, 0, 1,
119 (void **)&gnttab, PROT_READ | PROT_WRITE, 0);
120
121 if ( res )
122 {
123 fail(" Fail: Managed to map gnttab v2 status frames in v1 mode\n");
124 xenforeignmemory_unmap_resource(fh, res);
125 }
126
127 /*
128 * If this check starts failing, you've found the right place to test your
129 * addition to the Acquire Resource infrastructure.
130 */
131 rc = xenforeignmemory_resource_size(fh, domid, 3, 0, &size);
132
133 /* Check that Xen rejected the resource type. */
134 if ( !rc )
135 fail(" Fail: Expected error on an invalid resource type, got success\n");
136 }
137
test_domain_configurations(void)138 static void test_domain_configurations(void)
139 {
140 static struct test {
141 const char *name;
142 struct xen_domctl_createdomain create;
143 } tests[] = {
144 #if defined(__x86_64__) || defined(__i386__)
145 {
146 .name = "x86 PV",
147 .create = {
148 .max_vcpus = 2,
149 .max_grant_frames = 40,
150 .grant_opts = XEN_DOMCTL_GRANT_version(1),
151 },
152 },
153 {
154 .name = "x86 PVH",
155 .create = {
156 .flags = XEN_DOMCTL_CDF_hvm,
157 .max_vcpus = 2,
158 .max_grant_frames = 40,
159 .grant_opts = XEN_DOMCTL_GRANT_version(1),
160 .arch = {
161 .emulation_flags = XEN_X86_EMU_LAPIC,
162 },
163 },
164 },
165 #elif defined(__aarch64__) || defined(__arm__)
166 {
167 .name = "ARM",
168 .create = {
169 .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
170 .max_vcpus = 2,
171 .max_grant_frames = 40,
172 .grant_opts = XEN_DOMCTL_GRANT_version(1),
173 },
174 },
175 #endif
176 };
177
178 for ( unsigned int i = 0; i < ARRAY_SIZE(tests); ++i )
179 {
180 struct test *t = &tests[i];
181 uint32_t domid = 0;
182 int rc;
183 xen_pfn_t ram[1] = { 0 };
184
185 printf("Test %s\n", t->name);
186
187 #if defined(__x86_64__) || defined(__i386__)
188 if ( t->create.flags & XEN_DOMCTL_CDF_hvm )
189 {
190 if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm) )
191 {
192 printf(" Skip: HVM not available\n");
193 continue;
194 }
195
196 /*
197 * On x86, use HAP guests if possible, but skip if neither HAP nor
198 * SHADOW is available.
199 */
200 if ( physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap )
201 t->create.flags |= XEN_DOMCTL_CDF_hap;
202 else if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow) )
203 {
204 printf(" Skip: Neither HAP or SHADOW available\n");
205 continue;
206 }
207 }
208 else
209 {
210 if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_pv) )
211 {
212 printf(" Skip: PV not available\n");
213 continue;
214 }
215 }
216 #endif
217
218 rc = xc_domain_create(xch, &domid, &t->create);
219 if ( rc )
220 {
221 if ( errno == EINVAL || errno == EOPNOTSUPP )
222 printf(" Skip: %d - %s\n", errno, strerror(errno));
223 else
224 fail(" Domain create failure: %d - %s\n",
225 errno, strerror(errno));
226 continue;
227 }
228
229 printf(" Created d%u\n", domid);
230
231 rc = xc_domain_setmaxmem(xch, domid, -1);
232 if ( rc )
233 {
234 fail(" Failed to set max memory for domain: %d - %s\n",
235 errno, strerror(errno));
236 goto test_done;
237 }
238
239 rc = xc_domain_populate_physmap_exact(
240 xch, domid, ARRAY_SIZE(ram), 0, 0, ram);
241 if ( rc )
242 {
243 fail(" Failed to populate physmap domain: %d - %s\n",
244 errno, strerror(errno));
245 goto test_done;
246 }
247
248 test_gnttab(domid, t->create.max_grant_frames, ram[0]);
249
250 test_done:
251 rc = xc_domain_destroy(xch, domid);
252 if ( rc )
253 fail(" Failed to destroy domain: %d - %s\n",
254 errno, strerror(errno));
255 }
256 }
257
main(int argc,char ** argv)258 int main(int argc, char **argv)
259 {
260 int rc;
261
262 printf("XENMEM_acquire_resource tests\n");
263
264 xch = xc_interface_open(NULL, NULL, 0);
265 fh = xenforeignmemory_open(NULL, 0);
266 gh = xengnttab_open(NULL, 0);
267
268 if ( !xch )
269 err(1, "xc_interface_open");
270 if ( !fh )
271 err(1, "xenforeignmemory_open");
272 if ( !gh )
273 err(1, "xengnttab_open");
274
275 rc = xc_physinfo(xch, &physinfo);
276 if ( rc )
277 err(1, "Failed to obtain physinfo");
278
279 test_domain_configurations();
280
281 return !!nr_failures;
282 }
283
284 /*
285 * Local variables:
286 * mode: C
287 * c-file-style: "BSD"
288 * c-basic-offset: 4
289 * tab-width: 4
290 * indent-tabs-mode: nil
291 * End:
292 */
293