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