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