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