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