12da91b54SViktor Prutyanov /* 22da91b54SViktor Prutyanov * Windows crashdump 32da91b54SViktor Prutyanov * 42da91b54SViktor Prutyanov * Copyright (c) 2018 Virtuozzo International GmbH 52da91b54SViktor Prutyanov * 62da91b54SViktor Prutyanov * This work is licensed under the terms of the GNU GPL, version 2 or later. 72da91b54SViktor Prutyanov * See the COPYING file in the top-level directory. 82da91b54SViktor Prutyanov * 92da91b54SViktor Prutyanov */ 102da91b54SViktor Prutyanov 112da91b54SViktor Prutyanov #include "qemu/osdep.h" 122da91b54SViktor Prutyanov #include "qemu/cutils.h" 132da91b54SViktor Prutyanov #include "elf.h" 142da91b54SViktor Prutyanov #include "exec/hwaddr.h" 152da91b54SViktor Prutyanov #include "monitor/monitor.h" 162da91b54SViktor Prutyanov #include "sysemu/kvm.h" 172da91b54SViktor Prutyanov #include "sysemu/dump.h" 182da91b54SViktor Prutyanov #include "sysemu/memory_mapping.h" 192da91b54SViktor Prutyanov #include "sysemu/cpus.h" 202da91b54SViktor Prutyanov #include "qapi/error.h" 212da91b54SViktor Prutyanov #include "qapi/qmp/qerror.h" 222da91b54SViktor Prutyanov #include "qemu/error-report.h" 232da91b54SViktor Prutyanov #include "hw/misc/vmcoreinfo.h" 242da91b54SViktor Prutyanov #include "win_dump.h" 252da91b54SViktor Prutyanov 26*fb21efe9SViktor Prutyanov #define WIN_DUMP_PTR_SIZE sizeof(uint64_t) 27*fb21efe9SViktor Prutyanov 28*fb21efe9SViktor Prutyanov #define _WIN_DUMP_FIELD(f) (h->f) 29*fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field) 30*fb21efe9SViktor Prutyanov 31*fb21efe9SViktor Prutyanov #define _WIN_DUMP_FIELD_PTR(f) ((void *)&h->f) 32*fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field) 33*fb21efe9SViktor Prutyanov 34*fb21efe9SViktor Prutyanov #define _WIN_DUMP_FIELD_SIZE(f) sizeof(h->f) 35*fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field) 36*fb21efe9SViktor Prutyanov 37*fb21efe9SViktor Prutyanov #define WIN_DUMP_CTX_SIZE sizeof(WinContext64) 38*fb21efe9SViktor Prutyanov 39*fb21efe9SViktor Prutyanov static size_t write_run(uint64_t base_page, uint64_t page_count, 40*fb21efe9SViktor Prutyanov int fd, Error **errp) 412da91b54SViktor Prutyanov { 422da91b54SViktor Prutyanov void *buf; 43*fb21efe9SViktor Prutyanov uint64_t addr = base_page << TARGET_PAGE_BITS; 44*fb21efe9SViktor Prutyanov uint64_t size = page_count << TARGET_PAGE_BITS; 457184de64SViktor Prutyanov uint64_t len, l; 467184de64SViktor Prutyanov size_t total = 0; 477184de64SViktor Prutyanov 487184de64SViktor Prutyanov while (size) { 497184de64SViktor Prutyanov len = size; 502da91b54SViktor Prutyanov 512da91b54SViktor Prutyanov buf = cpu_physical_memory_map(addr, &len, false); 522da91b54SViktor Prutyanov if (!buf) { 537184de64SViktor Prutyanov error_setg(errp, "win-dump: failed to map physical range" 547184de64SViktor Prutyanov " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1); 552da91b54SViktor Prutyanov return 0; 562da91b54SViktor Prutyanov } 572da91b54SViktor Prutyanov 587184de64SViktor Prutyanov l = qemu_write_full(fd, buf, len); 592da91b54SViktor Prutyanov cpu_physical_memory_unmap(buf, addr, false, len); 607184de64SViktor Prutyanov if (l != len) { 617184de64SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 627184de64SViktor Prutyanov return 0; 637184de64SViktor Prutyanov } 642da91b54SViktor Prutyanov 657184de64SViktor Prutyanov addr += l; 667184de64SViktor Prutyanov size -= l; 677184de64SViktor Prutyanov total += l; 687184de64SViktor Prutyanov } 697184de64SViktor Prutyanov 707184de64SViktor Prutyanov return total; 712da91b54SViktor Prutyanov } 722da91b54SViktor Prutyanov 732da91b54SViktor Prutyanov static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp) 742da91b54SViktor Prutyanov { 75*fb21efe9SViktor Prutyanov uint64_t BasePage, PageCount; 762da91b54SViktor Prutyanov Error *local_err = NULL; 772da91b54SViktor Prutyanov int i; 782da91b54SViktor Prutyanov 79*fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) { 80*fb21efe9SViktor Prutyanov BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage); 81*fb21efe9SViktor Prutyanov PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount); 82*fb21efe9SViktor Prutyanov s->written_size += write_run(BasePage, PageCount, s->fd, &local_err); 832da91b54SViktor Prutyanov if (local_err) { 842da91b54SViktor Prutyanov error_propagate(errp, local_err); 852da91b54SViktor Prutyanov return; 862da91b54SViktor Prutyanov } 872da91b54SViktor Prutyanov } 882da91b54SViktor Prutyanov } 892da91b54SViktor Prutyanov 90*fb21efe9SViktor Prutyanov static int cpu_read_ptr(CPUState *cpu, uint64_t addr, uint64_t *ptr) 91*fb21efe9SViktor Prutyanov { 92*fb21efe9SViktor Prutyanov int ret; 93*fb21efe9SViktor Prutyanov uint64_t ptr64; 94*fb21efe9SViktor Prutyanov 95*fb21efe9SViktor Prutyanov ret = cpu_memory_rw_debug(cpu, addr, &ptr64, WIN_DUMP_PTR_SIZE, 0); 96*fb21efe9SViktor Prutyanov 97*fb21efe9SViktor Prutyanov *ptr = ptr64; 98*fb21efe9SViktor Prutyanov 99*fb21efe9SViktor Prutyanov return ret; 100*fb21efe9SViktor Prutyanov } 101*fb21efe9SViktor Prutyanov 1022da91b54SViktor Prutyanov static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp) 1032da91b54SViktor Prutyanov { 1042da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 105*fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET64, 106*fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_PTR(PfnDatabase), 107*fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) { 1082da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read MmPfnDatabase"); 1092da91b54SViktor Prutyanov return; 1102da91b54SViktor Prutyanov } 1112da91b54SViktor Prutyanov } 1122da91b54SViktor Prutyanov 1132da91b54SViktor Prutyanov static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp) 1142da91b54SViktor Prutyanov { 1152da91b54SViktor Prutyanov uint64_t KiBugcheckData; 1162da91b54SViktor Prutyanov 117*fb21efe9SViktor Prutyanov if (cpu_read_ptr(first_cpu, 118*fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + 119*fb21efe9SViktor Prutyanov KDBG_KI_BUGCHECK_DATA_OFFSET64, 120*fb21efe9SViktor Prutyanov &KiBugcheckData)) { 1212da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read KiBugcheckData"); 1222da91b54SViktor Prutyanov return; 1232da91b54SViktor Prutyanov } 1242da91b54SViktor Prutyanov 125*fb21efe9SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, KiBugcheckData, 126*fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(BugcheckData), 127*fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) { 1282da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read bugcheck data"); 1292da91b54SViktor Prutyanov return; 1302da91b54SViktor Prutyanov } 1312ad9b50fSViktor Prutyanov 1322ad9b50fSViktor Prutyanov /* 1332ad9b50fSViktor Prutyanov * If BugcheckCode wasn't saved, we consider guest OS as alive. 1342ad9b50fSViktor Prutyanov */ 1352ad9b50fSViktor Prutyanov 136*fb21efe9SViktor Prutyanov if (!WIN_DUMP_FIELD(BugcheckCode)) { 137*fb21efe9SViktor Prutyanov *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP; 1382ad9b50fSViktor Prutyanov } 1392da91b54SViktor Prutyanov } 1402da91b54SViktor Prutyanov 1412da91b54SViktor Prutyanov /* 1422da91b54SViktor Prutyanov * This routine tries to correct mistakes in crashdump header. 1432da91b54SViktor Prutyanov */ 1442da91b54SViktor Prutyanov static void patch_header(WinDumpHeader64 *h) 1452da91b54SViktor Prutyanov { 1462da91b54SViktor Prutyanov Error *local_err = NULL; 1472da91b54SViktor Prutyanov 1482da91b54SViktor Prutyanov h->RequiredDumpSpace = sizeof(WinDumpHeader64) + 1492da91b54SViktor Prutyanov (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 1502da91b54SViktor Prutyanov h->PhysicalMemoryBlock.unused = 0; 1512da91b54SViktor Prutyanov h->unused1 = 0; 1522da91b54SViktor Prutyanov 1532da91b54SViktor Prutyanov patch_mm_pfn_database(h, &local_err); 1542da91b54SViktor Prutyanov if (local_err) { 1552da91b54SViktor Prutyanov warn_report_err(local_err); 1562da91b54SViktor Prutyanov local_err = NULL; 1572da91b54SViktor Prutyanov } 1582da91b54SViktor Prutyanov patch_bugcheck_data(h, &local_err); 1592da91b54SViktor Prutyanov if (local_err) { 1602da91b54SViktor Prutyanov warn_report_err(local_err); 1612da91b54SViktor Prutyanov } 1622da91b54SViktor Prutyanov } 1632da91b54SViktor Prutyanov 1642da91b54SViktor Prutyanov static void check_header(WinDumpHeader64 *h, Error **errp) 1652da91b54SViktor Prutyanov { 1662da91b54SViktor Prutyanov const char Signature[] = "PAGE"; 1672da91b54SViktor Prutyanov const char ValidDump[] = "DU64"; 1682da91b54SViktor Prutyanov 1692da91b54SViktor Prutyanov if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { 1702da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 1712da91b54SViktor Prutyanov " got '%.4s'", Signature, h->Signature); 1722da91b54SViktor Prutyanov return; 1732da91b54SViktor Prutyanov } 1742da91b54SViktor Prutyanov 1752da91b54SViktor Prutyanov if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) { 1762da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 1772da91b54SViktor Prutyanov " got '%.4s'", ValidDump, h->ValidDump); 1782da91b54SViktor Prutyanov return; 1792da91b54SViktor Prutyanov } 1802da91b54SViktor Prutyanov } 1812da91b54SViktor Prutyanov 1822da91b54SViktor Prutyanov static void check_kdbg(WinDumpHeader64 *h, Error **errp) 1832da91b54SViktor Prutyanov { 1842da91b54SViktor Prutyanov const char OwnerTag[] = "KDBG"; 1852da91b54SViktor Prutyanov char read_OwnerTag[4]; 186*fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 1872ababfccSViktor Prutyanov bool try_fallback = true; 1882da91b54SViktor Prutyanov 1892ababfccSViktor Prutyanov try_again: 1902da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 1912ababfccSViktor Prutyanov KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64, 1922da91b54SViktor Prutyanov (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { 1932da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read OwnerTag"); 1942da91b54SViktor Prutyanov return; 1952da91b54SViktor Prutyanov } 1962da91b54SViktor Prutyanov 1972da91b54SViktor Prutyanov if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) { 1982ababfccSViktor Prutyanov if (try_fallback) { 1992ababfccSViktor Prutyanov /* 2002ababfccSViktor Prutyanov * If attempt to use original KDBG failed 2012ababfccSViktor Prutyanov * (most likely because of its encryption), 2022ababfccSViktor Prutyanov * we try to use KDBG obtained by guest driver. 2032ababfccSViktor Prutyanov */ 2042ababfccSViktor Prutyanov 205*fb21efe9SViktor Prutyanov KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1); 2062ababfccSViktor Prutyanov try_fallback = false; 2072ababfccSViktor Prutyanov goto try_again; 2082ababfccSViktor Prutyanov } else { 2092da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid KDBG OwnerTag," 2102ababfccSViktor Prutyanov " expected '%.4s', got '%.4s'", 2112da91b54SViktor Prutyanov OwnerTag, read_OwnerTag); 2122da91b54SViktor Prutyanov return; 2132da91b54SViktor Prutyanov } 2142da91b54SViktor Prutyanov } 2152da91b54SViktor Prutyanov 2162ababfccSViktor Prutyanov h->KdDebuggerDataBlock = KdDebuggerDataBlock; 2172ababfccSViktor Prutyanov } 2182ababfccSViktor Prutyanov 2192ad9b50fSViktor Prutyanov struct saved_context { 220a64b4e17SViktor Prutyanov WinContext64 ctx; 2212ad9b50fSViktor Prutyanov uint64_t addr; 2222ad9b50fSViktor Prutyanov }; 2232ad9b50fSViktor Prutyanov 2242ad9b50fSViktor Prutyanov static void patch_and_save_context(WinDumpHeader64 *h, 2252ad9b50fSViktor Prutyanov struct saved_context *saved_ctx, 2262ad9b50fSViktor Prutyanov Error **errp) 2272ad9b50fSViktor Prutyanov { 228*fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2292ad9b50fSViktor Prutyanov uint64_t KiProcessorBlock; 2302ad9b50fSViktor Prutyanov uint16_t OffsetPrcbContext; 2312ad9b50fSViktor Prutyanov CPUState *cpu; 2322ad9b50fSViktor Prutyanov int i = 0; 2332ad9b50fSViktor Prutyanov 234*fb21efe9SViktor Prutyanov if (cpu_read_ptr(first_cpu, 235*fb21efe9SViktor Prutyanov KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64, 236*fb21efe9SViktor Prutyanov &KiProcessorBlock)) { 2372ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read KiProcessorBlock"); 2382ad9b50fSViktor Prutyanov return; 2392ad9b50fSViktor Prutyanov } 2402ad9b50fSViktor Prutyanov 2412ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 242*fb21efe9SViktor Prutyanov KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64, 2432ad9b50fSViktor Prutyanov (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) { 2442ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read OffsetPrcbContext"); 2452ad9b50fSViktor Prutyanov return; 2462ad9b50fSViktor Prutyanov } 2472ad9b50fSViktor Prutyanov 2482ad9b50fSViktor Prutyanov CPU_FOREACH(cpu) { 2492ad9b50fSViktor Prutyanov X86CPU *x86_cpu = X86_CPU(cpu); 2502ad9b50fSViktor Prutyanov CPUX86State *env = &x86_cpu->env; 2512ad9b50fSViktor Prutyanov uint64_t Prcb; 2522ad9b50fSViktor Prutyanov uint64_t Context; 253a64b4e17SViktor Prutyanov WinContext64 ctx; 2542ad9b50fSViktor Prutyanov 255*fb21efe9SViktor Prutyanov if (cpu_read_ptr(first_cpu, 256*fb21efe9SViktor Prutyanov KiProcessorBlock + i * WIN_DUMP_PTR_SIZE, 257*fb21efe9SViktor Prutyanov &Prcb)) { 2582ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2592ad9b50fSViktor Prutyanov " CPU #%d PRCB location", i); 2602ad9b50fSViktor Prutyanov return; 2612ad9b50fSViktor Prutyanov } 2622ad9b50fSViktor Prutyanov 263*fb21efe9SViktor Prutyanov if (cpu_read_ptr(first_cpu, 2642ad9b50fSViktor Prutyanov Prcb + OffsetPrcbContext, 265*fb21efe9SViktor Prutyanov &Context)) { 2662ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2672ad9b50fSViktor Prutyanov " CPU #%d ContextFrame location", i); 2682ad9b50fSViktor Prutyanov return; 2692ad9b50fSViktor Prutyanov } 2702ad9b50fSViktor Prutyanov 2712ad9b50fSViktor Prutyanov saved_ctx[i].addr = Context; 2722ad9b50fSViktor Prutyanov 273a64b4e17SViktor Prutyanov ctx = (WinContext64){ 274a64b4e17SViktor Prutyanov .ContextFlags = WIN_CTX64_ALL, 2752ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 2762ad9b50fSViktor Prutyanov 2772ad9b50fSViktor Prutyanov .SegEs = env->segs[0].selector, 2782ad9b50fSViktor Prutyanov .SegCs = env->segs[1].selector, 2792ad9b50fSViktor Prutyanov .SegSs = env->segs[2].selector, 2802ad9b50fSViktor Prutyanov .SegDs = env->segs[3].selector, 2812ad9b50fSViktor Prutyanov .SegFs = env->segs[4].selector, 2822ad9b50fSViktor Prutyanov .SegGs = env->segs[5].selector, 2832ad9b50fSViktor Prutyanov .EFlags = cpu_compute_eflags(env), 2842ad9b50fSViktor Prutyanov 2852ad9b50fSViktor Prutyanov .Dr0 = env->dr[0], 2862ad9b50fSViktor Prutyanov .Dr1 = env->dr[1], 2872ad9b50fSViktor Prutyanov .Dr2 = env->dr[2], 2882ad9b50fSViktor Prutyanov .Dr3 = env->dr[3], 2892ad9b50fSViktor Prutyanov .Dr6 = env->dr[6], 2902ad9b50fSViktor Prutyanov .Dr7 = env->dr[7], 2912ad9b50fSViktor Prutyanov 2922ad9b50fSViktor Prutyanov .Rax = env->regs[R_EAX], 2932ad9b50fSViktor Prutyanov .Rbx = env->regs[R_EBX], 2942ad9b50fSViktor Prutyanov .Rcx = env->regs[R_ECX], 2952ad9b50fSViktor Prutyanov .Rdx = env->regs[R_EDX], 2962ad9b50fSViktor Prutyanov .Rsp = env->regs[R_ESP], 2972ad9b50fSViktor Prutyanov .Rbp = env->regs[R_EBP], 2982ad9b50fSViktor Prutyanov .Rsi = env->regs[R_ESI], 2992ad9b50fSViktor Prutyanov .Rdi = env->regs[R_EDI], 3002ad9b50fSViktor Prutyanov .R8 = env->regs[8], 3012ad9b50fSViktor Prutyanov .R9 = env->regs[9], 3022ad9b50fSViktor Prutyanov .R10 = env->regs[10], 3032ad9b50fSViktor Prutyanov .R11 = env->regs[11], 3042ad9b50fSViktor Prutyanov .R12 = env->regs[12], 3052ad9b50fSViktor Prutyanov .R13 = env->regs[13], 3062ad9b50fSViktor Prutyanov .R14 = env->regs[14], 3072ad9b50fSViktor Prutyanov .R15 = env->regs[15], 3082ad9b50fSViktor Prutyanov 3092ad9b50fSViktor Prutyanov .Rip = env->eip, 3102ad9b50fSViktor Prutyanov .FltSave = { 3112ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3122ad9b50fSViktor Prutyanov }, 3132ad9b50fSViktor Prutyanov }; 3142ad9b50fSViktor Prutyanov 3152ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 316*fb21efe9SViktor Prutyanov &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 0)) { 3172ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to save CPU #%d context", i); 3182ad9b50fSViktor Prutyanov return; 3192ad9b50fSViktor Prutyanov } 3202ad9b50fSViktor Prutyanov 3212ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 322*fb21efe9SViktor Prutyanov &ctx, WIN_DUMP_CTX_SIZE, 1)) { 3232ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to write CPU #%d context", i); 3242ad9b50fSViktor Prutyanov return; 3252ad9b50fSViktor Prutyanov } 3262ad9b50fSViktor Prutyanov 3272ad9b50fSViktor Prutyanov i++; 3282ad9b50fSViktor Prutyanov } 3292ad9b50fSViktor Prutyanov } 3302ad9b50fSViktor Prutyanov 3312ad9b50fSViktor Prutyanov static void restore_context(WinDumpHeader64 *h, 3322ad9b50fSViktor Prutyanov struct saved_context *saved_ctx) 3332ad9b50fSViktor Prutyanov { 3342ad9b50fSViktor Prutyanov int i; 3352ad9b50fSViktor Prutyanov 336*fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) { 3372ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr, 338*fb21efe9SViktor Prutyanov &saved_ctx[i].ctx, WIN_DUMP_CTX_SIZE, 1)) { 339b0e70950SVladimir Sementsov-Ogievskiy warn_report("win-dump: failed to restore CPU #%d context", i); 3402ad9b50fSViktor Prutyanov } 3412ad9b50fSViktor Prutyanov } 3422ad9b50fSViktor Prutyanov } 3432ad9b50fSViktor Prutyanov 3442da91b54SViktor Prutyanov void create_win_dump(DumpState *s, Error **errp) 3452da91b54SViktor Prutyanov { 3462da91b54SViktor Prutyanov WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note + 3472da91b54SViktor Prutyanov VMCOREINFO_ELF_NOTE_HDR_SIZE); 34892d1b3d5SViktor Prutyanov X86CPU *first_x86_cpu = X86_CPU(first_cpu); 34992d1b3d5SViktor Prutyanov uint64_t saved_cr3 = first_x86_cpu->env.cr[3]; 3502ad9b50fSViktor Prutyanov struct saved_context *saved_ctx = NULL; 3512da91b54SViktor Prutyanov Error *local_err = NULL; 3522da91b54SViktor Prutyanov 3532da91b54SViktor Prutyanov if (s->guest_note_size != sizeof(WinDumpHeader64) + 3542da91b54SViktor Prutyanov VMCOREINFO_ELF_NOTE_HDR_SIZE) { 3552da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid vmcoreinfo note size"); 3562da91b54SViktor Prutyanov return; 3572da91b54SViktor Prutyanov } 3582da91b54SViktor Prutyanov 3592da91b54SViktor Prutyanov check_header(h, &local_err); 3602da91b54SViktor Prutyanov if (local_err) { 3612da91b54SViktor Prutyanov error_propagate(errp, local_err); 3622da91b54SViktor Prutyanov return; 3632da91b54SViktor Prutyanov } 3642da91b54SViktor Prutyanov 36592d1b3d5SViktor Prutyanov /* 36692d1b3d5SViktor Prutyanov * Further access to kernel structures by virtual addresses 36792d1b3d5SViktor Prutyanov * should be made from system context. 36892d1b3d5SViktor Prutyanov */ 36992d1b3d5SViktor Prutyanov 370*fb21efe9SViktor Prutyanov first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase); 37192d1b3d5SViktor Prutyanov 3722da91b54SViktor Prutyanov check_kdbg(h, &local_err); 3732da91b54SViktor Prutyanov if (local_err) { 3742da91b54SViktor Prutyanov error_propagate(errp, local_err); 37592d1b3d5SViktor Prutyanov goto out_cr3; 3762da91b54SViktor Prutyanov } 3772da91b54SViktor Prutyanov 3782da91b54SViktor Prutyanov patch_header(h); 3792da91b54SViktor Prutyanov 380*fb21efe9SViktor Prutyanov saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors)); 3812ad9b50fSViktor Prutyanov 3822ad9b50fSViktor Prutyanov /* 3832ad9b50fSViktor Prutyanov * Always patch context because there is no way 3842ad9b50fSViktor Prutyanov * to determine if the system-saved context is valid 3852ad9b50fSViktor Prutyanov */ 3862ad9b50fSViktor Prutyanov 3872ad9b50fSViktor Prutyanov patch_and_save_context(h, saved_ctx, &local_err); 3882ad9b50fSViktor Prutyanov if (local_err) { 3892ad9b50fSViktor Prutyanov error_propagate(errp, local_err); 3902ad9b50fSViktor Prutyanov goto out_free; 3912ad9b50fSViktor Prutyanov } 3922ad9b50fSViktor Prutyanov 393*fb21efe9SViktor Prutyanov s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace); 3942da91b54SViktor Prutyanov 3952da91b54SViktor Prutyanov s->written_size = qemu_write_full(s->fd, h, sizeof(*h)); 3962da91b54SViktor Prutyanov if (s->written_size != sizeof(*h)) { 3972da91b54SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 3982ad9b50fSViktor Prutyanov goto out_restore; 3992da91b54SViktor Prutyanov } 4002da91b54SViktor Prutyanov 4012da91b54SViktor Prutyanov write_runs(s, h, &local_err); 4022da91b54SViktor Prutyanov if (local_err) { 4032da91b54SViktor Prutyanov error_propagate(errp, local_err); 4042ad9b50fSViktor Prutyanov goto out_restore; 4052da91b54SViktor Prutyanov } 40692d1b3d5SViktor Prutyanov 4072ad9b50fSViktor Prutyanov out_restore: 4082ad9b50fSViktor Prutyanov restore_context(h, saved_ctx); 4092ad9b50fSViktor Prutyanov out_free: 4102ad9b50fSViktor Prutyanov g_free(saved_ctx); 41192d1b3d5SViktor Prutyanov out_cr3: 41292d1b3d5SViktor Prutyanov first_x86_cpu->env.cr[3] = saved_cr3; 41392d1b3d5SViktor Prutyanov 41492d1b3d5SViktor Prutyanov return; 4152da91b54SViktor Prutyanov } 416