1*2da91b54SViktor Prutyanov /* 2*2da91b54SViktor Prutyanov * Windows crashdump 3*2da91b54SViktor Prutyanov * 4*2da91b54SViktor Prutyanov * Copyright (c) 2018 Virtuozzo International GmbH 5*2da91b54SViktor Prutyanov * 6*2da91b54SViktor Prutyanov * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*2da91b54SViktor Prutyanov * See the COPYING file in the top-level directory. 8*2da91b54SViktor Prutyanov * 9*2da91b54SViktor Prutyanov */ 10*2da91b54SViktor Prutyanov 11*2da91b54SViktor Prutyanov #include "qemu/osdep.h" 12*2da91b54SViktor Prutyanov #include "qemu/cutils.h" 13*2da91b54SViktor Prutyanov #include "elf.h" 14*2da91b54SViktor Prutyanov #include "cpu.h" 15*2da91b54SViktor Prutyanov #include "exec/hwaddr.h" 16*2da91b54SViktor Prutyanov #include "monitor/monitor.h" 17*2da91b54SViktor Prutyanov #include "sysemu/kvm.h" 18*2da91b54SViktor Prutyanov #include "sysemu/dump.h" 19*2da91b54SViktor Prutyanov #include "sysemu/sysemu.h" 20*2da91b54SViktor Prutyanov #include "sysemu/memory_mapping.h" 21*2da91b54SViktor Prutyanov #include "sysemu/cpus.h" 22*2da91b54SViktor Prutyanov #include "qapi/error.h" 23*2da91b54SViktor Prutyanov #include "qapi/qmp/qerror.h" 24*2da91b54SViktor Prutyanov #include "qemu/error-report.h" 25*2da91b54SViktor Prutyanov #include "hw/misc/vmcoreinfo.h" 26*2da91b54SViktor Prutyanov #include "win_dump.h" 27*2da91b54SViktor Prutyanov 28*2da91b54SViktor Prutyanov static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp) 29*2da91b54SViktor Prutyanov { 30*2da91b54SViktor Prutyanov void *buf; 31*2da91b54SViktor Prutyanov uint64_t addr = run->BasePage << TARGET_PAGE_BITS; 32*2da91b54SViktor Prutyanov uint64_t size = run->PageCount << TARGET_PAGE_BITS; 33*2da91b54SViktor Prutyanov uint64_t len = size; 34*2da91b54SViktor Prutyanov 35*2da91b54SViktor Prutyanov buf = cpu_physical_memory_map(addr, &len, false); 36*2da91b54SViktor Prutyanov if (!buf) { 37*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to map run"); 38*2da91b54SViktor Prutyanov return 0; 39*2da91b54SViktor Prutyanov } 40*2da91b54SViktor Prutyanov if (len != size) { 41*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to map entire run"); 42*2da91b54SViktor Prutyanov len = 0; 43*2da91b54SViktor Prutyanov goto out_unmap; 44*2da91b54SViktor Prutyanov } 45*2da91b54SViktor Prutyanov 46*2da91b54SViktor Prutyanov len = qemu_write_full(fd, buf, len); 47*2da91b54SViktor Prutyanov if (len != size) { 48*2da91b54SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 49*2da91b54SViktor Prutyanov } 50*2da91b54SViktor Prutyanov 51*2da91b54SViktor Prutyanov out_unmap: 52*2da91b54SViktor Prutyanov cpu_physical_memory_unmap(buf, addr, false, len); 53*2da91b54SViktor Prutyanov 54*2da91b54SViktor Prutyanov return len; 55*2da91b54SViktor Prutyanov } 56*2da91b54SViktor Prutyanov 57*2da91b54SViktor Prutyanov static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp) 58*2da91b54SViktor Prutyanov { 59*2da91b54SViktor Prutyanov WinDumpPhyMemDesc64 *desc = &h->PhysicalMemoryBlock; 60*2da91b54SViktor Prutyanov WinDumpPhyMemRun64 *run = desc->Run; 61*2da91b54SViktor Prutyanov Error *local_err = NULL; 62*2da91b54SViktor Prutyanov int i; 63*2da91b54SViktor Prutyanov 64*2da91b54SViktor Prutyanov for (i = 0; i < desc->NumberOfRuns; i++) { 65*2da91b54SViktor Prutyanov s->written_size += write_run(run + i, s->fd, &local_err); 66*2da91b54SViktor Prutyanov if (local_err) { 67*2da91b54SViktor Prutyanov error_propagate(errp, local_err); 68*2da91b54SViktor Prutyanov return; 69*2da91b54SViktor Prutyanov } 70*2da91b54SViktor Prutyanov } 71*2da91b54SViktor Prutyanov } 72*2da91b54SViktor Prutyanov 73*2da91b54SViktor Prutyanov static void patch_mm_pfn_database(WinDumpHeader64 *h, Error **errp) 74*2da91b54SViktor Prutyanov { 75*2da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 76*2da91b54SViktor Prutyanov h->KdDebuggerDataBlock + KDBG_MM_PFN_DATABASE_OFFSET64, 77*2da91b54SViktor Prutyanov (uint8_t *)&h->PfnDatabase, sizeof(h->PfnDatabase), 0)) { 78*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read MmPfnDatabase"); 79*2da91b54SViktor Prutyanov return; 80*2da91b54SViktor Prutyanov } 81*2da91b54SViktor Prutyanov } 82*2da91b54SViktor Prutyanov 83*2da91b54SViktor Prutyanov static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp) 84*2da91b54SViktor Prutyanov { 85*2da91b54SViktor Prutyanov uint64_t KiBugcheckData; 86*2da91b54SViktor Prutyanov 87*2da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 88*2da91b54SViktor Prutyanov h->KdDebuggerDataBlock + KDBG_KI_BUGCHECK_DATA_OFFSET64, 89*2da91b54SViktor Prutyanov (uint8_t *)&KiBugcheckData, sizeof(KiBugcheckData), 0)) { 90*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read KiBugcheckData"); 91*2da91b54SViktor Prutyanov return; 92*2da91b54SViktor Prutyanov } 93*2da91b54SViktor Prutyanov 94*2da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 95*2da91b54SViktor Prutyanov KiBugcheckData, 96*2da91b54SViktor Prutyanov h->BugcheckData, sizeof(h->BugcheckData), 0)) { 97*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read bugcheck data"); 98*2da91b54SViktor Prutyanov return; 99*2da91b54SViktor Prutyanov } 100*2da91b54SViktor Prutyanov } 101*2da91b54SViktor Prutyanov 102*2da91b54SViktor Prutyanov /* 103*2da91b54SViktor Prutyanov * This routine tries to correct mistakes in crashdump header. 104*2da91b54SViktor Prutyanov */ 105*2da91b54SViktor Prutyanov static void patch_header(WinDumpHeader64 *h) 106*2da91b54SViktor Prutyanov { 107*2da91b54SViktor Prutyanov Error *local_err = NULL; 108*2da91b54SViktor Prutyanov 109*2da91b54SViktor Prutyanov h->RequiredDumpSpace = sizeof(WinDumpHeader64) + 110*2da91b54SViktor Prutyanov (h->PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 111*2da91b54SViktor Prutyanov h->PhysicalMemoryBlock.unused = 0; 112*2da91b54SViktor Prutyanov h->unused1 = 0; 113*2da91b54SViktor Prutyanov 114*2da91b54SViktor Prutyanov /* 115*2da91b54SViktor Prutyanov * We assume h->DirectoryBase and current CR3 are the same when we access 116*2da91b54SViktor Prutyanov * memory by virtual address. In other words, we suppose current context 117*2da91b54SViktor Prutyanov * is system context. It is definetely true in case of BSOD. 118*2da91b54SViktor Prutyanov */ 119*2da91b54SViktor Prutyanov 120*2da91b54SViktor Prutyanov patch_mm_pfn_database(h, &local_err); 121*2da91b54SViktor Prutyanov if (local_err) { 122*2da91b54SViktor Prutyanov warn_report_err(local_err); 123*2da91b54SViktor Prutyanov local_err = NULL; 124*2da91b54SViktor Prutyanov } 125*2da91b54SViktor Prutyanov patch_bugcheck_data(h, &local_err); 126*2da91b54SViktor Prutyanov if (local_err) { 127*2da91b54SViktor Prutyanov warn_report_err(local_err); 128*2da91b54SViktor Prutyanov } 129*2da91b54SViktor Prutyanov } 130*2da91b54SViktor Prutyanov 131*2da91b54SViktor Prutyanov static void check_header(WinDumpHeader64 *h, Error **errp) 132*2da91b54SViktor Prutyanov { 133*2da91b54SViktor Prutyanov const char Signature[] = "PAGE"; 134*2da91b54SViktor Prutyanov const char ValidDump[] = "DU64"; 135*2da91b54SViktor Prutyanov 136*2da91b54SViktor Prutyanov if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { 137*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 138*2da91b54SViktor Prutyanov " got '%.4s'", Signature, h->Signature); 139*2da91b54SViktor Prutyanov return; 140*2da91b54SViktor Prutyanov } 141*2da91b54SViktor Prutyanov 142*2da91b54SViktor Prutyanov if (memcmp(h->ValidDump, ValidDump, sizeof(h->ValidDump))) { 143*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 144*2da91b54SViktor Prutyanov " got '%.4s'", ValidDump, h->ValidDump); 145*2da91b54SViktor Prutyanov return; 146*2da91b54SViktor Prutyanov } 147*2da91b54SViktor Prutyanov } 148*2da91b54SViktor Prutyanov 149*2da91b54SViktor Prutyanov static void check_kdbg(WinDumpHeader64 *h, Error **errp) 150*2da91b54SViktor Prutyanov { 151*2da91b54SViktor Prutyanov const char OwnerTag[] = "KDBG"; 152*2da91b54SViktor Prutyanov char read_OwnerTag[4]; 153*2da91b54SViktor Prutyanov 154*2da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 155*2da91b54SViktor Prutyanov h->KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET64, 156*2da91b54SViktor Prutyanov (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { 157*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read OwnerTag"); 158*2da91b54SViktor Prutyanov return; 159*2da91b54SViktor Prutyanov } 160*2da91b54SViktor Prutyanov 161*2da91b54SViktor Prutyanov if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) { 162*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid KDBG OwnerTag," 163*2da91b54SViktor Prutyanov " expected '%.4s', got '%.4s'," 164*2da91b54SViktor Prutyanov " KdDebuggerDataBlock seems to be encrypted", 165*2da91b54SViktor Prutyanov OwnerTag, read_OwnerTag); 166*2da91b54SViktor Prutyanov return; 167*2da91b54SViktor Prutyanov } 168*2da91b54SViktor Prutyanov } 169*2da91b54SViktor Prutyanov 170*2da91b54SViktor Prutyanov void create_win_dump(DumpState *s, Error **errp) 171*2da91b54SViktor Prutyanov { 172*2da91b54SViktor Prutyanov WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note + 173*2da91b54SViktor Prutyanov VMCOREINFO_ELF_NOTE_HDR_SIZE); 174*2da91b54SViktor Prutyanov Error *local_err = NULL; 175*2da91b54SViktor Prutyanov 176*2da91b54SViktor Prutyanov if (s->guest_note_size != sizeof(WinDumpHeader64) + 177*2da91b54SViktor Prutyanov VMCOREINFO_ELF_NOTE_HDR_SIZE) { 178*2da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid vmcoreinfo note size"); 179*2da91b54SViktor Prutyanov return; 180*2da91b54SViktor Prutyanov } 181*2da91b54SViktor Prutyanov 182*2da91b54SViktor Prutyanov check_header(h, &local_err); 183*2da91b54SViktor Prutyanov if (local_err) { 184*2da91b54SViktor Prutyanov error_propagate(errp, local_err); 185*2da91b54SViktor Prutyanov return; 186*2da91b54SViktor Prutyanov } 187*2da91b54SViktor Prutyanov 188*2da91b54SViktor Prutyanov check_kdbg(h, &local_err); 189*2da91b54SViktor Prutyanov if (local_err) { 190*2da91b54SViktor Prutyanov error_propagate(errp, local_err); 191*2da91b54SViktor Prutyanov return; 192*2da91b54SViktor Prutyanov } 193*2da91b54SViktor Prutyanov 194*2da91b54SViktor Prutyanov patch_header(h); 195*2da91b54SViktor Prutyanov 196*2da91b54SViktor Prutyanov s->total_size = h->RequiredDumpSpace; 197*2da91b54SViktor Prutyanov 198*2da91b54SViktor Prutyanov s->written_size = qemu_write_full(s->fd, h, sizeof(*h)); 199*2da91b54SViktor Prutyanov if (s->written_size != sizeof(*h)) { 200*2da91b54SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 201*2da91b54SViktor Prutyanov return; 202*2da91b54SViktor Prutyanov } 203*2da91b54SViktor Prutyanov 204*2da91b54SViktor Prutyanov write_runs(s, h, &local_err); 205*2da91b54SViktor Prutyanov if (local_err) { 206*2da91b54SViktor Prutyanov error_propagate(errp, local_err); 207*2da91b54SViktor Prutyanov return; 208*2da91b54SViktor Prutyanov } 209*2da91b54SViktor Prutyanov } 210