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