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