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