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
test_domain_configurations(void)128 static void test_domain_configurations(void)
129 {
130 static struct test {
131 const char *name;
132 struct xen_domctl_createdomain create;
133 } tests[] = {
134 #if defined(__x86_64__) || defined(__i386__)
135 {
136 .name = "x86 PV",
137 .create = {
138 .max_vcpus = 2,
139 .max_grant_frames = 40,
140 .grant_opts = XEN_DOMCTL_GRANT_version(1),
141 },
142 },
143 {
144 .name = "x86 PVH",
145 .create = {
146 .flags = XEN_DOMCTL_CDF_hvm,
147 .max_vcpus = 2,
148 .max_grant_frames = 40,
149 .grant_opts = XEN_DOMCTL_GRANT_version(1),
150 .arch = {
151 .emulation_flags = XEN_X86_EMU_LAPIC,
152 },
153 },
154 },
155 #elif defined(__aarch64__) || defined(__arm__)
156 {
157 .name = "ARM",
158 .create = {
159 .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
160 .max_vcpus = 2,
161 .max_grant_frames = 40,
162 .grant_opts = XEN_DOMCTL_GRANT_version(1),
163 },
164 },
165 #endif
166 };
167
168 for ( unsigned int i = 0; i < ARRAY_SIZE(tests); ++i )
169 {
170 struct test *t = &tests[i];
171 uint32_t domid = 0;
172 int rc;
173 xen_pfn_t ram[1] = { 0 };
174
175 printf("Test %s\n", t->name);
176
177 #if defined(__x86_64__) || defined(__i386__)
178 if ( t->create.flags & XEN_DOMCTL_CDF_hvm )
179 {
180 if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm) )
181 {
182 printf(" Skip: HVM not available\n");
183 continue;
184 }
185
186 /*
187 * On x86, use HAP guests if possible, but skip if neither HAP nor
188 * SHADOW is available.
189 */
190 if ( physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap )
191 t->create.flags |= XEN_DOMCTL_CDF_hap;
192 else if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow) )
193 {
194 printf(" Skip: Neither HAP or SHADOW available\n");
195 continue;
196 }
197 }
198 else
199 {
200 if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_pv) )
201 {
202 printf(" Skip: PV not available\n");
203 continue;
204 }
205 }
206 #endif
207
208 rc = xc_domain_create(xch, &domid, &t->create);
209 if ( rc )
210 {
211 if ( errno == EINVAL || errno == EOPNOTSUPP )
212 printf(" Skip: %d - %s\n", errno, strerror(errno));
213 else
214 fail(" Domain create failure: %d - %s\n",
215 errno, strerror(errno));
216 continue;
217 }
218
219 printf(" Created d%u\n", domid);
220
221 rc = xc_domain_setmaxmem(xch, domid, -1);
222 if ( rc )
223 {
224 fail(" Failed to set max memory for domain: %d - %s\n",
225 errno, strerror(errno));
226 goto test_done;
227 }
228
229 rc = xc_domain_populate_physmap_exact(
230 xch, domid, ARRAY_SIZE(ram), 0, 0, ram);
231 if ( rc )
232 {
233 fail(" Failed to populate physmap domain: %d - %s\n",
234 errno, strerror(errno));
235 goto test_done;
236 }
237
238 test_gnttab(domid, t->create.max_grant_frames, ram[0]);
239
240 test_done:
241 rc = xc_domain_destroy(xch, domid);
242 if ( rc )
243 fail(" Failed to destroy domain: %d - %s\n",
244 errno, strerror(errno));
245 }
246 }
247
main(int argc,char ** argv)248 int main(int argc, char **argv)
249 {
250 int rc;
251
252 printf("XENMEM_acquire_resource tests\n");
253
254 xch = xc_interface_open(NULL, NULL, 0);
255 fh = xenforeignmemory_open(NULL, 0);
256 gh = xengnttab_open(NULL, 0);
257
258 if ( !xch )
259 err(1, "xc_interface_open");
260 if ( !fh )
261 err(1, "xenforeignmemory_open");
262 if ( !gh )
263 err(1, "xengnttab_open");
264
265 rc = xc_physinfo(xch, &physinfo);
266 if ( rc )
267 err(1, "Failed to obtain physinfo");
268
269 test_domain_configurations();
270
271 return !!nr_failures;
272 }
273
274 /*
275 * Local variables:
276 * mode: C
277 * c-file-style: "BSD"
278 * c-basic-offset: 4
279 * tab-width: 4
280 * indent-tabs-mode: nil
281 * End:
282 */
283