1 #include <stdlib.h>
2 #include <string.h>
3 #include <sys/mman.h>
4 #include <unistd.h>
5 #include <inttypes.h>
6 
7 #define XC_WANT_COMPAT_MAP_FOREIGN_API
8 #include <xenctrl.h>
9 #include <xenguest.h>
10 
11 #include <xen-tools/common-macros.h>
12 
13 #define M2P_SIZE(_m)    ROUNDUP(((_m) * sizeof(xen_pfn_t)), 21)
14 #define is_mapped(pfn_type) (!((pfn_type) & 0x80000000UL))
15 
16 #define ERROR(msg, args...) fprintf(stderr, msg, ## args)
17 
18 static xc_interface *xch;
19 
help_func(int argc,char * argv[])20 int help_func(int argc, char *argv[])
21 {
22     fprintf(stderr,
23             "Usage: xen-mfndump <command> [args]\n"
24             "Commands:\n"
25             "  help                      show this help\n"
26             "  dump-m2p                  show M2P\n"
27             "  dump-p2m    <domid>       show P2M of <domid>\n"
28             "  dump-ptes   <domid> <mfn> show the PTEs in <mfn>\n"
29             "  lookup-pte  <domid> <mfn> find the PTE mapping <mfn>\n"
30             "  memcmp-mfns <domid1> <mfn1> <domid2> <mfn2>\n"
31             "                            compare content of <mfn1> & <mfn2>\n"
32            );
33 
34     return 0;
35 }
36 
dump_m2p_func(int argc,char * argv[])37 int dump_m2p_func(int argc, char *argv[])
38 {
39     unsigned long i;
40     unsigned long max_mfn;
41     xen_pfn_t *m2p_table;
42 
43     if ( argc > 0 )
44     {
45         help_func(0, NULL);
46         return 1;
47     }
48 
49     /* Map M2P and obtain gpfn */
50     if ( xc_maximum_ram_page(xch, &max_mfn) < 0 )
51     {
52         ERROR("Failed to get the maximum mfn");
53         return -1;
54     }
55 
56     if ( !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) )
57     {
58         ERROR("Failed to map live M2P table");
59         return -1;
60     }
61 
62     printf(" --- Dumping M2P ---\n");
63     printf(" Max MFN: %lu\n", max_mfn);
64     for ( i = 0; i < max_mfn; i++ )
65     {
66         printf("  mfn=0x%lx ==> pfn=0x%lx\n", i, m2p_table[i]);
67     }
68     printf(" --- End of M2P ---\n");
69 
70     munmap(m2p_table, M2P_SIZE(max_mfn));
71     return 0;
72 }
73 
dump_p2m_func(int argc,char * argv[])74 int dump_p2m_func(int argc, char *argv[])
75 {
76     struct xc_domain_meminfo minfo;
77     xc_domaininfo_t info;
78     unsigned long i;
79     int domid;
80 
81     if ( argc < 1 )
82     {
83         help_func(0, NULL);
84         return 1;
85     }
86     domid = atoi(argv[0]);
87 
88     if ( xc_domain_getinfo_single(xch, domid, &info) < 0 )
89     {
90         ERROR("Failed to obtain info for domain %d\n", domid);
91         return -1;
92     }
93 
94     /* Retrieve all the info about the domain's memory */
95     memset(&minfo, 0, sizeof(minfo));
96     if ( xc_map_domain_meminfo(xch, domid, &minfo) )
97     {
98         ERROR("Could not map domain %d memory information\n", domid);
99         return -1;
100     }
101 
102     printf(" --- Dumping P2M for domain %d ---\n", domid);
103     printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n",
104            minfo.guest_width, minfo.pt_levels, minfo.p2m_size);
105     for ( i = 0; i < minfo.p2m_size; i++ )
106     {
107         unsigned long pagetype = minfo.pfn_type[i] &
108                                      XEN_DOMCTL_PFINFO_LTAB_MASK;
109         xen_pfn_t mfn;
110 
111         if ( minfo.guest_width == sizeof(uint64_t) )
112             mfn = ((uint64_t*)minfo.p2m_table)[i];
113         else
114         {
115             mfn = ((uint32_t*)minfo.p2m_table)[i];
116 #ifdef __x86_64__
117             if ( mfn == ~0U ) /* Expand a 32bit guest's idea of INVALID_MFN */
118                 mfn = ~0UL;
119 #endif
120         }
121 
122         printf("  pfn=0x%lx ==> mfn=0x%lx (type 0x%lx)", i, mfn,
123                pagetype >> XEN_DOMCTL_PFINFO_LTAB_SHIFT);
124 
125         switch ( pagetype >> XEN_DOMCTL_PFINFO_LTAB_SHIFT )
126         {
127         case 0x0: /* NOTAB */
128             printf("\n");
129             break;
130         case 0x1 ... 0x4: /* L1 -> L4 */
131             printf(" L%lu\n", pagetype >> XEN_DOMCTL_PFINFO_LTAB_SHIFT);
132             break;
133         case 0x9 ... 0xc: /* Pinned L1 -> L4 */
134             printf(" pinned L%lu\n",
135                    (pagetype >> XEN_DOMCTL_PFINFO_LTAB_SHIFT) & 7);
136             break;
137         case 0xd: /* BROKEN */
138             printf(" broken\n");
139             break;
140         case 0xe: /* XALLOC */
141             printf(" xalloc\n");
142             break;
143         case 0xf: /* XTAB */
144             printf(" invalid\n");
145             break;
146         default:
147             printf(" <invalid type>\n");
148             break;
149         }
150     }
151     printf(" --- End of P2M for domain %d ---\n", domid);
152 
153     xc_unmap_domain_meminfo(xch, &minfo);
154     return 0;
155 }
156 
dump_ptes_func(int argc,char * argv[])157 int dump_ptes_func(int argc, char *argv[])
158 {
159     struct xc_domain_meminfo minfo;
160     xc_domaininfo_t info;
161     void *page = NULL;
162     unsigned long i, max_mfn;
163     int domid, pte_num, rc = 0;
164     xen_pfn_t pfn, mfn, *m2p_table;
165 
166     if ( argc < 2 )
167     {
168         help_func(0, NULL);
169         return 1;
170     }
171     domid = atoi(argv[0]);
172     mfn = strtoul(argv[1], NULL, 16);
173 
174     if ( xc_domain_getinfo_single(xch, domid, &info) < 0 )
175     {
176         ERROR("Failed to obtain info for domain %d\n", domid);
177         return -1;
178     }
179 
180     /* Retrieve all the info about the domain's memory */
181     memset(&minfo, 0, sizeof(minfo));
182     if ( xc_map_domain_meminfo(xch, domid, &minfo) )
183     {
184         ERROR("Could not map domain %d memory information\n", domid);
185         return -1;
186     }
187 
188     /* Map M2P and obtain gpfn */
189     rc = xc_maximum_ram_page(xch, &max_mfn);
190     if ( rc || (mfn > max_mfn) ||
191          !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) )
192     {
193         xc_unmap_domain_meminfo(xch, &minfo);
194         ERROR("Failed to map live M2P table");
195         return -1;
196     }
197 
198     pfn = m2p_table[mfn];
199     if ( pfn >= minfo.p2m_size )
200     {
201         ERROR("pfn 0x%lx out of range for domain %d\n", pfn, domid);
202         rc = -1;
203         goto out;
204     }
205 
206     if ( !(minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) )
207     {
208         ERROR("pfn 0x%lx for domain %d is not a PT\n", pfn, domid);
209         rc = -1;
210         goto out;
211     }
212 
213     page = xc_map_foreign_range(xch, domid, XC_PAGE_SIZE, PROT_READ,
214                                 minfo.p2m_table[pfn]);
215     if ( !page )
216     {
217         ERROR("Failed to map 0x%lx\n", minfo.p2m_table[pfn]);
218         rc = -1;
219         goto out;
220     }
221 
222     pte_num = XC_PAGE_SIZE / 8;
223 
224     printf(" --- Dumping %d PTEs for domain %d ---\n", pte_num, domid);
225     printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n",
226            minfo.guest_width, minfo.pt_levels, minfo.p2m_size);
227     printf(" pfn: 0x%lx, mfn: 0x%lx",
228            pfn, minfo.p2m_table[pfn]);
229     switch ( minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK )
230     {
231         case XEN_DOMCTL_PFINFO_L1TAB:
232             printf(", L1 table");
233             break;
234         case XEN_DOMCTL_PFINFO_L2TAB:
235             printf(", L2 table");
236             break;
237         case XEN_DOMCTL_PFINFO_L3TAB:
238             printf(", L3 table");
239             break;
240         case XEN_DOMCTL_PFINFO_L4TAB:
241             printf(", L4 table");
242             break;
243     }
244     if ( minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LPINTAB )
245         printf (" [pinned]");
246     if ( is_mapped(minfo.p2m_table[pfn]) )
247         printf(" [mapped]");
248     printf("\n");
249 
250     for ( i = 0; i < pte_num; i++ )
251         printf("  pte[%lu]: 0x%"PRIx64"\n", i, ((const uint64_t*)page)[i]);
252 
253     printf(" --- End of PTEs for domain %d, pfn=0x%lx (mfn=0x%lx) ---\n",
254            domid, pfn, minfo.p2m_table[pfn]);
255 
256  out:
257     if ( page )
258         munmap(page, XC_PAGE_SIZE);
259     xc_unmap_domain_meminfo(xch, &minfo);
260     munmap(m2p_table, M2P_SIZE(max_mfn));
261     return rc;
262 }
263 
lookup_pte_func(int argc,char * argv[])264 int lookup_pte_func(int argc, char *argv[])
265 {
266     struct xc_domain_meminfo minfo;
267     xc_domaininfo_t info;
268     unsigned long i, j;
269     int domid, pte_num;
270     xen_pfn_t mfn;
271 
272     if ( argc < 2 )
273     {
274         help_func(0, NULL);
275         return 1;
276     }
277     domid = atoi(argv[0]);
278     mfn = strtoul(argv[1], NULL, 16);
279 
280     if ( xc_domain_getinfo_single(xch, domid, &info) < 0 )
281     {
282         ERROR("Failed to obtain info for domain %d\n", domid);
283         return -1;
284     }
285 
286     /* Retrieve all the info about the domain's memory */
287     memset(&minfo, 0, sizeof(minfo));
288     if ( xc_map_domain_meminfo(xch, domid, &minfo) )
289     {
290         ERROR("Could not map domain %d memory information\n", domid);
291         return -1;
292     }
293 
294     pte_num = XC_PAGE_SIZE / 8;
295 
296     printf(" --- Lookig for PTEs mapping mfn 0x%lx for domain %d ---\n",
297            mfn, domid);
298     printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n",
299            minfo.guest_width, minfo.pt_levels, minfo.p2m_size);
300 
301     for ( i = 0; i < minfo.p2m_size; i++ )
302     {
303         void *page;
304 
305         if ( !(minfo.pfn_type[i] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) )
306             continue;
307 
308         page = xc_map_foreign_range(xch, domid, XC_PAGE_SIZE, PROT_READ,
309                                     minfo.p2m_table[i]);
310         if ( !page )
311             continue;
312 
313         for ( j = 0; j < pte_num; j++ )
314         {
315             uint64_t pte = ((const uint64_t*)page)[j];
316 
317 #define __MADDR_BITS_X86  ((minfo.guest_width == 8) ? 52 : 44)
318 #define __MFN_MASK_X86    ((1ULL << (__MADDR_BITS_X86 - XC_PAGE_SHIFT)) - 1)
319             if ( ((pte >> XC_PAGE_SHIFT) & __MFN_MASK_X86) == mfn)
320                 printf("  0x%lx <-- [0x%lx][%lu]: 0x%"PRIx64"\n",
321                        mfn, minfo.p2m_table[i], j, pte);
322 #undef __MADDR_BITS_X86
323 #undef __MFN_MASK_X8
324         }
325 
326         munmap(page, XC_PAGE_SIZE);
327     }
328 
329     xc_unmap_domain_meminfo(xch, &minfo);
330 
331     return 1;
332 }
333 
memcmp_mfns_func(int argc,char * argv[])334 int memcmp_mfns_func(int argc, char *argv[])
335 {
336     xc_domaininfo_t info1, info2;
337     void *page1 = NULL, *page2 = NULL;
338     int domid1, domid2;
339     xen_pfn_t mfn1, mfn2;
340     int rc = 0;
341 
342     if ( argc < 4 )
343     {
344         help_func(0, NULL);
345         return 1;
346     }
347     domid1 = atoi(argv[0]);
348     domid2 = atoi(argv[2]);
349     mfn1 = strtoul(argv[1], NULL, 16);
350     mfn2 = strtoul(argv[3], NULL, 16);
351 
352     if ( xc_domain_getinfo_single(xch, domid1, &info1) < 0 ||
353          xc_domain_getinfo_single(xch, domid2, &info2) < 0)
354     {
355         ERROR("Failed to obtain info for domains\n");
356         return -1;
357     }
358 
359     page1 = xc_map_foreign_range(xch, domid1, XC_PAGE_SIZE, PROT_READ, mfn1);
360     page2 = xc_map_foreign_range(xch, domid2, XC_PAGE_SIZE, PROT_READ, mfn2);
361     if ( !page1 || !page2 )
362     {
363         ERROR("Failed to map either 0x%lx[dom %d] or 0x%lx[dom %d]\n",
364               mfn1, domid1, mfn2, domid2);
365         rc = -1;
366         goto out;
367     }
368 
369     printf(" --- Comparing the content of 2 MFNs ---\n");
370     printf(" 1: 0x%lx[dom %d], 2: 0x%lx[dom %d]\n",
371            mfn1, domid1, mfn2, domid2);
372     printf("  memcpy(1, 2) = %d\n", memcmp(page1, page2, XC_PAGE_SIZE));
373 
374  out:
375     if ( page1 )
376         munmap(page1, XC_PAGE_SIZE);
377     if ( page2 )
378         munmap(page2, XC_PAGE_SIZE);
379     return rc;
380 }
381 
382 
383 
384 struct {
385     const char *name;
386     int (*func)(int argc, char *argv[]);
387 } opts[] = {
388     { "help", help_func },
389     { "dump-m2p", dump_m2p_func },
390     { "dump-p2m", dump_p2m_func },
391     { "dump-ptes", dump_ptes_func },
392     { "lookup-pte", lookup_pte_func },
393     { "memcmp-mfns", memcmp_mfns_func},
394 };
395 
main(int argc,char * argv[])396 int main(int argc, char *argv[])
397 {
398     int i, ret;
399 
400     if (argc < 2)
401     {
402         help_func(0, NULL);
403         return 1;
404     }
405 
406     xch = xc_interface_open(0, 0, 0);
407     if ( !xch )
408     {
409         fprintf(stderr, "Failed to open an xc handler");
410         return 1;
411     }
412 
413     for ( i = 0; i < ARRAY_SIZE(opts); i++ )
414     {
415         if ( !strncmp(opts[i].name, argv[1], strlen(argv[1])) )
416             break;
417     }
418 
419     if ( i == ARRAY_SIZE(opts) )
420     {
421         fprintf(stderr, "Unknown option '%s'", argv[1]);
422         help_func(0, NULL);
423         return 1;
424     }
425 
426     ret = opts[i].func(argc - 2, argv + 2);
427 
428     xc_interface_close(xch);
429 
430     return !!ret;
431 }
432 
433 /*
434  * Local variables:
435  * mode: C
436  * c-set-style: "BSD"
437  * c-basic-offset: 4
438  * tab-width: 4
439  * indent-tabs-mode: nil
440  * End:
441  */
442