1 /*
2 * xen-hvmctx.c
3 *
4 * Print out the contents of a HVM save record in a human-readable way.
5 *
6 * Tim Deegan <Tim.Deegan@citrix.com>
7 * Copyright (c) 2008 Citrix Systems, Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to
11 * deal in the Software without restriction, including without limitation the
12 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 * sell copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 */
27
28 #include <inttypes.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <stdint.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <arpa/inet.h>
40
41 #define BITS_PER_LONG __WORDSIZE
42 #define BITS_TO_LONGS(bits) \
43 (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
44 #define DECLARE_BITMAP(name,bits) \
45 unsigned long name[BITS_TO_LONGS(bits)]
46
47 #include <xenctrl.h>
48 #include <xen/xen.h>
49 #include <xen/domctl.h>
50 #include <xen/hvm/save.h>
51
52 static uint8_t *buf = NULL;
53 static uint32_t len;
54 static uint32_t off;
55
56 #define READ(_x) do { \
57 if ( len - off < sizeof (_x) ) \
58 { \
59 fprintf(stderr, "Error: need another %u bytes, only %u available", \
60 (unsigned int)sizeof(_x), len - off); \
61 exit(1); \
62 } \
63 memcpy(&(_x), buf + off, sizeof (_x)); \
64 off += sizeof (_x); \
65 } while (0)
66
dump_header(void)67 static void dump_header(void)
68 {
69 HVM_SAVE_TYPE(HEADER) h;
70 READ(h);
71 printf(" Header: magic %#lx, version %lu\n",
72 (unsigned long) h.magic, (unsigned long) h.version);
73 printf(" Xen changeset %llx\n",
74 (unsigned long long) h.changeset);
75 printf(" CPUID[0][%%eax] 0x%.8lx\n", (unsigned long) h.cpuid);
76 printf(" gtsc_khz %lu\n", (unsigned long) h.gtsc_khz);
77 }
78
79 struct fpu_mm {
80 uint64_t lo;
81 uint16_t hi;
82 uint16_t pad[3];
83 } __attribute__((packed));
84
85 struct fpu_xmm {
86 uint64_t lo;
87 uint64_t hi;
88 };
89
90 struct fpu_regs {
91 uint16_t fcw;
92 uint16_t fsw;
93 uint8_t ftw;
94 uint8_t res0;
95 uint16_t fop;
96 uint64_t fpuip;
97 uint64_t fpudp;
98 uint32_t mxcsr;
99 uint32_t mxcsr_mask;
100 struct fpu_mm mm[8];
101 struct fpu_xmm xmm[16];
102 uint64_t res1[12];
103 } __attribute__((packed));
104
dump_fpu(void * p)105 static void dump_fpu(void *p)
106 {
107 struct fpu_regs *r = p;
108 int i;
109
110 printf(" FPU: fcw 0x%4.4x fsw 0x%4.4x\n"
111 " ftw 0x%2.2x (0x%2.2x) fop 0x%4.4x\n"
112 " fpuip 0x%16.16"PRIx64" fpudp 0x%16.16"PRIx64"\n"
113 " mxcsr 0x%8.8lx mask 0x%8.8lx\n",
114 (unsigned)r->fcw, (unsigned)r->fsw,
115 (unsigned)r->ftw, (unsigned)r->res0, (unsigned)r->fop,
116 r->fpuip, r->fpudp,
117 (unsigned long)r->mxcsr, (unsigned long)r->mxcsr_mask);
118
119 for ( i = 0 ; i < 8 ; i++ )
120 printf(" mm%i 0x%4.4x%16.16"PRIx64" (0x%4.4x%4.4x%4.4x)\n",
121 i, r->mm[i].hi, r->mm[i].lo,
122 r->mm[i].pad[2], r->mm[i].pad[1], r->mm[i].pad[0]);
123
124 for ( i = 0 ; i < 16 ; i++ )
125 printf(" xmm%2.2i 0x%16.16"PRIx64"%16.16"PRIx64"\n",
126 i, r->xmm[i].hi, r->xmm[i].lo);
127
128 for ( i = 0 ; i < 6 ; i++ )
129 printf(" (0x%16.16"PRIx64"%16.16"PRIx64")\n",
130 r->res1[2*i+1], r->res1[2*i]);
131 }
132
dump_cpu(void)133 static void dump_cpu(void)
134 {
135 HVM_SAVE_TYPE(CPU) c;
136 READ(c);
137 printf(" CPU: rax 0x%16.16llx rbx 0x%16.16llx\n"
138 " rcx 0x%16.16llx rdx 0x%16.16llx\n"
139 " rbp 0x%16.16llx rsi 0x%16.16llx\n"
140 " rdi 0x%16.16llx rsp 0x%16.16llx\n"
141 " r8 0x%16.16llx r9 0x%16.16llx\n"
142 " r10 0x%16.16llx r11 0x%16.16llx\n"
143 " r12 0x%16.16llx r13 0x%16.16llx\n"
144 " r14 0x%16.16llx r15 0x%16.16llx\n"
145 " rip 0x%16.16llx rflags 0x%16.16llx\n"
146 " cr0 0x%16.16llx cr2 0x%16.16llx\n"
147 " cr3 0x%16.16llx cr4 0x%16.16llx\n"
148 " dr0 0x%16.16llx dr1 0x%16.16llx\n"
149 " dr2 0x%16.16llx dr3 0x%16.16llx\n"
150 " dr6 0x%16.16llx dr7 0x%16.16llx\n"
151 " cs %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.8" PRIx32 " / %#7.4" PRIx32 ")\n"
152 " es %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.8" PRIx32 " / %#7.4" PRIx32 ")\n"
153 " ds %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.8" PRIx32 " / %#7.4" PRIx32 ")\n"
154 " fs %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.8" PRIx32 " / %#7.4" PRIx32 ")\n"
155 " gs %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.8" PRIx32 " / %#7.4" PRIx32 ")\n"
156 " ss %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.8" PRIx32 " / %#7.4" PRIx32 ")\n"
157 " tr %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.4" PRIx32 " / %#7.4" PRIx32 ")\n"
158 " ldtr %#6.4" PRIx32 " (%#18.8" PRIx64 " + %#10.4" PRIx32 " / %#7.4" PRIx32 ")\n"
159 " idtr (%#18.8" PRIx64 " + %#10.4" PRIx32 ")\n"
160 " gdtr (%#18.8" PRIx64 " + %#10.4" PRIx32 ")\n"
161 " sysenter cs 0x%8.8llx eip 0x%16.16llx esp 0x%16.16llx\n"
162 " shadow gs %#18.16" PRIx64 " efer %#18.8" PRIx64 "\n"
163 " lstar %#18.16" PRIx64 " cstar %#18.16" PRIx64 "\n"
164 " star %#18.16" PRIx64 " sfmask %#18.8" PRIx64 "\n"
165 " tsc 0x%16.16llx\n"
166 " event 0x%8.8lx error 0x%8.8lx\n",
167 (unsigned long long) c.rax, (unsigned long long) c.rbx,
168 (unsigned long long) c.rcx, (unsigned long long) c.rdx,
169 (unsigned long long) c.rbp, (unsigned long long) c.rsi,
170 (unsigned long long) c.rdi, (unsigned long long) c.rsp,
171 (unsigned long long) c.r8, (unsigned long long) c.r9,
172 (unsigned long long) c.r10, (unsigned long long) c.r11,
173 (unsigned long long) c.r12, (unsigned long long) c.r13,
174 (unsigned long long) c.r14, (unsigned long long) c.r15,
175 (unsigned long long) c.rip, (unsigned long long) c.rflags,
176 (unsigned long long) c.cr0, (unsigned long long) c.cr2,
177 (unsigned long long) c.cr3, (unsigned long long) c.cr4,
178 (unsigned long long) c.dr0, (unsigned long long) c.dr1,
179 (unsigned long long) c.dr2, (unsigned long long) c.dr3,
180 (unsigned long long) c.dr6, (unsigned long long) c.dr7,
181 c.cs_sel, c.cs_base, c.cs_limit, c.cs_arbytes,
182 c.ds_sel, c.ds_base, c.ds_limit, c.ds_arbytes,
183 c.es_sel, c.es_base, c.es_limit, c.es_arbytes,
184 c.fs_sel, c.fs_base, c.fs_limit, c.fs_arbytes,
185 c.gs_sel, c.gs_base, c.gs_limit, c.gs_arbytes,
186 c.ss_sel, c.ss_base, c.ss_limit, c.ss_arbytes,
187 c.tr_sel, c.tr_base, c.tr_limit, c.tr_arbytes,
188 c.ldtr_sel, c.ldtr_base, c.ldtr_limit, c.ldtr_arbytes,
189 c.idtr_base, c.idtr_limit,
190 c.gdtr_base, c.gdtr_limit,
191 (unsigned long long) c.sysenter_cs,
192 (unsigned long long) c.sysenter_eip,
193 (unsigned long long) c.sysenter_esp,
194 c.shadow_gs, c.msr_efer,
195 c.msr_lstar, c.msr_cstar,
196 c.msr_star, c.msr_syscall_mask,
197 (unsigned long long) c.tsc,
198 (unsigned long) c.pending_event, (unsigned long) c.error_code);
199
200 if ( c.flags & XEN_X86_FPU_INITIALISED )
201 dump_fpu(&c.fpu_regs);
202 }
203
204
dump_pic(void)205 static void dump_pic(void)
206 {
207 HVM_SAVE_TYPE(PIC) p;
208 READ(p);
209 printf(" PIC: IRQ base %#x, irr %#x, imr %#x, isr %#x\n",
210 p.irq_base, p.irr, p.imr, p.isr);
211
212 printf(" init_state %u, priority_add %u, readsel_isr %u, poll %u\n",
213 p.init_state, p.priority_add, p.readsel_isr, p.poll);
214 printf(" auto_eoi %u, rotate_on_auto_eoi %u\n",
215 p.auto_eoi, p.rotate_on_auto_eoi);
216 printf(" special_fully_nested_mode %u, special_mask_mode %u\n",
217 p.special_fully_nested_mode, p.special_mask_mode);
218 printf(" is_master %u, elcr %#x, int_output %#x\n",
219 p.is_master, p.elcr, p.int_output);
220 }
221
222
dump_ioapic(void)223 static void dump_ioapic(void)
224 {
225 int i;
226 HVM_SAVE_TYPE(IOAPIC) p;
227 READ(p);
228 printf(" IOAPIC: base_address %#llx, ioregsel %#x id %#x\n",
229 (unsigned long long) p.base_address, p.ioregsel, p.id);
230 for ( i = 0; i < VIOAPIC_NUM_PINS; i++ )
231 {
232 printf(" pin %.2i: 0x%.16llx\n", i,
233 (unsigned long long) p.redirtbl[i].bits);
234 }
235 }
236
dump_lapic(void)237 static void dump_lapic(void)
238 {
239 HVM_SAVE_TYPE(LAPIC) p;
240 READ(p);
241 printf(" LAPIC: base_msr %#llx, disabled %#x, timer_divisor %#x\n",
242 (unsigned long long) p.apic_base_msr, p.disabled, p.timer_divisor);
243 }
244
dump_lapic_regs(void)245 static void dump_lapic_regs(void)
246 {
247 unsigned int i;
248 HVM_SAVE_TYPE(LAPIC_REGS) r;
249 READ(r);
250 printf(" LAPIC registers:\n");
251 for ( i = 0 ; i < 0x400 ; i += 32 )
252 {
253 printf(" 0x%03x: 0x%08" PRIx32 " 0x%03x: 0x%08" PRIx32 "\n",
254 i, *(uint32_t *)&r.data[i],
255 i + 16, *(uint32_t *)&r.data[i + 16]);
256 }
257 }
258
dump_pci_irq(void)259 static void dump_pci_irq(void)
260 {
261 HVM_SAVE_TYPE(PCI_IRQ) i;
262 READ(i);
263 printf(" PCI IRQs: 0x%16.16llx%16.16llx\n",
264 (unsigned long long) i.pad[0], (unsigned long long) i.pad[1]);
265 }
266
dump_isa_irq(void)267 static void dump_isa_irq(void)
268 {
269 HVM_SAVE_TYPE(ISA_IRQ) i;
270 READ(i);
271 printf(" ISA IRQs: 0x%4.4llx\n",
272 (unsigned long long) i.pad[0]);
273 }
274
dump_pci_link(void)275 static void dump_pci_link(void)
276 {
277 HVM_SAVE_TYPE(PCI_LINK) l;
278 READ(l);
279 printf(" PCI LINK: %u %u %u %u\n",
280 l.route[0], l.route[1], l.route[2], l.route[3]);
281 }
282
dump_pit(void)283 static void dump_pit(void)
284 {
285 int i;
286 HVM_SAVE_TYPE(PIT) p;
287 READ(p);
288 printf(" PIT: speaker %s\n", p.speaker_data_on ? "on" : "off");
289 for ( i = 0 ; i < 2 ; i++ )
290 {
291 printf(" ch %1i: count %#x, latched_count %#x, count_latched %u\n",
292 i, p.channels[i].count, p.channels[i].latched_count,
293 p.channels[i].count_latched);
294 printf(" status %#x, status_latched %#x\n",
295 p.channels[i].status, p.channels[i].status_latched);
296 printf(" rd_state %#x, wr_state %#x, wr_latch %#x, rw_mode %#x\n",
297 p.channels[i].read_state, p.channels[i].write_state,
298 p.channels[i].write_latch, p.channels[i].rw_mode);
299 printf(" mode %#x, bcd %#x, gate %#x\n",
300 p.channels[i].mode, p.channels[i].bcd, p.channels[i].gate);
301 }
302 }
303
dump_rtc(void)304 static void dump_rtc(void)
305 {
306 HVM_SAVE_TYPE(RTC) r;
307 READ(r);
308 printf(" RTC: regs 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
309 r.cmos_data[0], r.cmos_data[1], r.cmos_data[2], r.cmos_data[3],
310 r.cmos_data[4], r.cmos_data[5], r.cmos_data[6], r.cmos_data[7]);
311 printf(" 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x, index 0x%2.2x\n",
312 r.cmos_data[8], r.cmos_data[9], r.cmos_data[10], r.cmos_data[11],
313 r.cmos_data[12], r.cmos_data[13], r.cmos_index);
314
315 }
316
dump_hpet(void)317 static void dump_hpet(void)
318 {
319 HVM_SAVE_TYPE(HPET) h;
320 unsigned int i;
321
322 READ(h);
323 printf(" HPET: capability %#" PRIx64 " config %#" PRIx64 "\n",
324 h.capability, h.config);
325 printf(" isr %#" PRIx64 " counter %#" PRIx64 "\n",
326 h.isr, h.mc64);
327 for ( i = 0; i < HPET_TIMER_NUM; i++ )
328 {
329 printf(" timer%u config %#18.16" PRIx64 " cmp %#18.8" PRIx64 "\n",
330 i, h.timers[i].config, h.timers[i].cmp);
331 printf(" timer%u period %#18.8" PRIx64 " fsb %#18.8" PRIx64 "\n",
332 i, h.period[i], h.timers[i].fsb);
333 }
334 }
335
dump_pmtimer(void)336 static void dump_pmtimer(void)
337 {
338 HVM_SAVE_TYPE(PMTIMER) p;
339 READ(p);
340 printf(" ACPI PM: TMR_VAL 0x%x, PM1a_STS 0x%x, PM1a_EN 0x%x\n",
341 p.tmr_val, (unsigned) p.pm1a_sts, (unsigned) p.pm1a_en);
342 }
343
dump_mtrr(void)344 static void dump_mtrr(void)
345 {
346 HVM_SAVE_TYPE(MTRR) p;
347 unsigned int i;
348
349 READ(p);
350 printf(" MTRR: PAT %#" PRIx64 ", cap %#" PRIx64 ", default %#" PRIx64 "\n",
351 p.msr_pat_cr, p.msr_mtrr_cap, p.msr_mtrr_def_type);
352 for ( i = 0 ; i < MTRR_VCNT ; i++ )
353 printf(" var %u %#18.13" PRIx64 " %#18.13" PRIx64 "\n", i,
354 p.msr_mtrr_var[2 * i], p.msr_mtrr_var[2 * i + 1]);
355 for ( i = 0 ; i < NUM_FIXED_MSR ; i++ )
356 printf(" fixed %02x %#18.16" PRIx64 "\n",
357 i, p.msr_mtrr_fixed[i]);
358 }
359
dump_viridian_domain(void)360 static void dump_viridian_domain(void)
361 {
362 HVM_SAVE_TYPE(VIRIDIAN_DOMAIN) p;
363 READ(p);
364 printf(" VIRIDIAN_DOMAIN: hypercall gpa 0x%llx, guest_os_id 0x%llx\n",
365 (unsigned long long) p.hypercall_gpa,
366 (unsigned long long) p.guest_os_id);
367 }
368
dump_viridian_vcpu(void)369 static void dump_viridian_vcpu(void)
370 {
371 HVM_SAVE_TYPE(VIRIDIAN_VCPU) p;
372 READ(p);
373 printf(" VIRIDIAN_VCPU: vp_assist_msr 0x%llx, apic_assist_pending %s\n",
374 (unsigned long long) p.vp_assist_msr,
375 p.apic_assist_pending ? "true" : "false");
376 }
377
dump_vmce_vcpu(void)378 static void dump_vmce_vcpu(void)
379 {
380 HVM_SAVE_TYPE(VMCE_VCPU) p;
381 READ(p);
382 printf(" VMCE_VCPU: caps %" PRIx64 "\n", p.caps);
383 printf(" VMCE_VCPU: bank0 mci_ctl2 %" PRIx64 "\n", p.mci_ctl2_bank0);
384 printf(" VMCE_VCPU: bank1 mci_ctl2 %" PRIx64 "\n", p.mci_ctl2_bank1);
385 }
386
dump_tsc_adjust(void)387 static void dump_tsc_adjust(void)
388 {
389 HVM_SAVE_TYPE(TSC_ADJUST) p;
390 READ(p);
391 printf(" TSC_ADJUST: tsc_adjust %" PRIx64 "\n", p.tsc_adjust);
392 }
393
main(int argc,char ** argv)394 int main(int argc, char **argv)
395 {
396 int entry, domid;
397 xc_interface *xch;
398
399 struct hvm_save_descriptor desc;
400
401 if ( argc != 2 || !argv[1] || (domid = atoi(argv[1])) < 0 )
402 {
403 fprintf(stderr, "usage: %s <domid>\n", argv[0]);
404 exit(1);
405 }
406
407 xch = xc_interface_open(0,0,0);
408 if ( !xch )
409 {
410 fprintf(stderr, "Error: can't open libxc handle\n");
411 exit(1);
412 }
413 len = xc_domain_hvm_getcontext(xch, domid, 0, 0);
414 if ( len == (uint32_t) -1 )
415 {
416 fprintf(stderr, "Error: can't get record length for dom %i\n", domid);
417 exit(1);
418 }
419 buf = malloc(len);
420 if ( buf == NULL )
421 {
422 fprintf(stderr, "Error: can't allocate %u bytes\n", len);
423 exit(1);
424 }
425 len = xc_domain_hvm_getcontext(xch, domid, buf, len);
426 if ( len == (uint32_t) -1 )
427 {
428 fprintf(stderr, "Error: can't get HVM record for dom %i\n", domid);
429 exit(1);
430 }
431 off = 0;
432
433 /* Say hello */
434 printf("HVM save record for domain %i\n", domid);
435
436 entry = 0;
437 do {
438 READ(desc);
439 printf("Entry %i: type %u instance %u, length %u\n",
440 entry++, (unsigned) desc.typecode,
441 (unsigned) desc.instance, (unsigned) desc.length);
442 switch (desc.typecode)
443 {
444 case HVM_SAVE_CODE(HEADER): dump_header(); break;
445 case HVM_SAVE_CODE(CPU): dump_cpu(); break;
446 case HVM_SAVE_CODE(PIC): dump_pic(); break;
447 case HVM_SAVE_CODE(IOAPIC): dump_ioapic(); break;
448 case HVM_SAVE_CODE(LAPIC): dump_lapic(); break;
449 case HVM_SAVE_CODE(LAPIC_REGS): dump_lapic_regs(); break;
450 case HVM_SAVE_CODE(PCI_IRQ): dump_pci_irq(); break;
451 case HVM_SAVE_CODE(ISA_IRQ): dump_isa_irq(); break;
452 case HVM_SAVE_CODE(PCI_LINK): dump_pci_link(); break;
453 case HVM_SAVE_CODE(PIT): dump_pit(); break;
454 case HVM_SAVE_CODE(RTC): dump_rtc(); break;
455 case HVM_SAVE_CODE(HPET): dump_hpet(); break;
456 case HVM_SAVE_CODE(PMTIMER): dump_pmtimer(); break;
457 case HVM_SAVE_CODE(MTRR): dump_mtrr(); break;
458 case HVM_SAVE_CODE(VIRIDIAN_DOMAIN): dump_viridian_domain(); break;
459 case HVM_SAVE_CODE(VIRIDIAN_VCPU): dump_viridian_vcpu(); break;
460 case HVM_SAVE_CODE(VMCE_VCPU): dump_vmce_vcpu(); break;
461 case HVM_SAVE_CODE(TSC_ADJUST): dump_tsc_adjust(); break;
462 case HVM_SAVE_CODE(END): break;
463 default:
464 printf(" ** Don't understand type %u: skipping\n",
465 (unsigned) desc.typecode);
466 off += (desc.length);
467 }
468 } while ( desc.typecode != HVM_SAVE_CODE(END) && off < len );
469
470 return 0;
471 }
472
473 /*
474 * Local variables:
475 * mode: C
476 * c-file-style: "BSD"
477 * c-basic-offset: 4
478 * tab-width: 4
479 * indent-tabs-mode: nil
480 * End:
481 */
482