qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com>
Subject: [Qemu-devel] [PULL 56/60] dump: add Windows live system dump
Date: Thu, 28 Jun 2018 22:05:06 +0200	[thread overview]
Message-ID: <1530216310-52873-57-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1530216310-52873-1-git-send-email-pbonzini@redhat.com>

From: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com>

Unlike dying Windows, live system memory doesn't contain
correct register contexts. But they can be populated with QEMU register
values.
After this patch, QEMU will be able to produce guest Windows live system
dump.

Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com>
Message-Id: <20180517162342.4330-5-viktor.prutyanov@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 win_dump.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 win_dump.h |  95 +++++++++++++++++++++++++++++++++++--
 2 files changed, 246 insertions(+), 5 deletions(-)

diff --git a/win_dump.c b/win_dump.c
index 2d9afb5..b15c191 100644
--- a/win_dump.c
+++ b/win_dump.c
@@ -97,6 +97,14 @@ static void patch_bugcheck_data(WinDumpHeader64 *h, Error **errp)
         error_setg(errp, "win-dump: failed to read bugcheck data");
         return;
     }
+
+    /*
+     * If BugcheckCode wasn't saved, we consider guest OS as alive.
+     */
+
+    if (!h->BugcheckCode) {
+        h->BugcheckCode = LIVE_SYSTEM_DUMP;
+    }
 }
 
 /*
@@ -177,12 +185,139 @@ try_again:
     h->KdDebuggerDataBlock = KdDebuggerDataBlock;
 }
 
+struct saved_context {
+    WinContext ctx;
+    uint64_t addr;
+};
+
+static void patch_and_save_context(WinDumpHeader64 *h,
+                                   struct saved_context *saved_ctx,
+                                   Error **errp)
+{
+    uint64_t KiProcessorBlock;
+    uint16_t OffsetPrcbContext;
+    CPUState *cpu;
+    int i = 0;
+
+    if (cpu_memory_rw_debug(first_cpu,
+            h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
+            (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) {
+        error_setg(errp, "win-dump: failed to read KiProcessorBlock");
+        return;
+    }
+
+    if (cpu_memory_rw_debug(first_cpu,
+            h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
+            (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
+        error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
+        return;
+    }
+
+    CPU_FOREACH(cpu) {
+        X86CPU *x86_cpu = X86_CPU(cpu);
+        CPUX86State *env = &x86_cpu->env;
+        uint64_t Prcb;
+        uint64_t Context;
+        WinContext ctx;
+
+        if (cpu_memory_rw_debug(first_cpu,
+                KiProcessorBlock + i * sizeof(uint64_t),
+                (uint8_t *)&Prcb, sizeof(Prcb), 0)) {
+            error_setg(errp, "win-dump: failed to read"
+                             " CPU #%d PRCB location", i);
+            return;
+        }
+
+        if (cpu_memory_rw_debug(first_cpu,
+                Prcb + OffsetPrcbContext,
+                (uint8_t *)&Context, sizeof(Context), 0)) {
+            error_setg(errp, "win-dump: failed to read"
+                             " CPU #%d ContextFrame location", i);
+            return;
+        }
+
+        saved_ctx[i].addr = Context;
+
+        ctx = (WinContext){
+            .ContextFlags = WIN_CTX_ALL,
+            .MxCsr = env->mxcsr,
+
+            .SegEs = env->segs[0].selector,
+            .SegCs = env->segs[1].selector,
+            .SegSs = env->segs[2].selector,
+            .SegDs = env->segs[3].selector,
+            .SegFs = env->segs[4].selector,
+            .SegGs = env->segs[5].selector,
+            .EFlags = cpu_compute_eflags(env),
+
+            .Dr0 = env->dr[0],
+            .Dr1 = env->dr[1],
+            .Dr2 = env->dr[2],
+            .Dr3 = env->dr[3],
+            .Dr6 = env->dr[6],
+            .Dr7 = env->dr[7],
+
+            .Rax = env->regs[R_EAX],
+            .Rbx = env->regs[R_EBX],
+            .Rcx = env->regs[R_ECX],
+            .Rdx = env->regs[R_EDX],
+            .Rsp = env->regs[R_ESP],
+            .Rbp = env->regs[R_EBP],
+            .Rsi = env->regs[R_ESI],
+            .Rdi = env->regs[R_EDI],
+            .R8  = env->regs[8],
+            .R9  = env->regs[9],
+            .R10 = env->regs[10],
+            .R11 = env->regs[11],
+            .R12 = env->regs[12],
+            .R13 = env->regs[13],
+            .R14 = env->regs[14],
+            .R15 = env->regs[15],
+
+            .Rip = env->eip,
+            .FltSave = {
+                .MxCsr = env->mxcsr,
+            },
+        };
+
+        if (cpu_memory_rw_debug(first_cpu, Context,
+                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) {
+            error_setg(errp, "win-dump: failed to save CPU #%d context", i);
+            return;
+        }
+
+        if (cpu_memory_rw_debug(first_cpu, Context,
+                (uint8_t *)&ctx, sizeof(WinContext), 1)) {
+            error_setg(errp, "win-dump: failed to write CPU #%d context", i);
+            return;
+        }
+
+        i++;
+    }
+}
+
+static void restore_context(WinDumpHeader64 *h,
+                            struct saved_context *saved_ctx)
+{
+    int i;
+    Error *err = NULL;
+
+    for (i = 0; i < h->NumberProcessors; i++) {
+        if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
+                (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) {
+            error_setg(&err, "win-dump: failed to restore CPU #%d context", i);
+            warn_report_err(err);
+        }
+    }
+}
+
 void create_win_dump(DumpState *s, Error **errp)
 {
     WinDumpHeader64 *h = (WinDumpHeader64 *)(s->guest_note +
             VMCOREINFO_ELF_NOTE_HDR_SIZE);
     X86CPU *first_x86_cpu = X86_CPU(first_cpu);
     uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
+    struct saved_context *saved_ctx = NULL;
     Error *local_err = NULL;
 
     if (s->guest_note_size != sizeof(WinDumpHeader64) +
@@ -212,20 +347,37 @@ void create_win_dump(DumpState *s, Error **errp)
 
     patch_header(h);
 
+    saved_ctx = g_new(struct saved_context, h->NumberProcessors);
+
+    /*
+     * Always patch context because there is no way
+     * to determine if the system-saved context is valid
+     */
+
+    patch_and_save_context(h, saved_ctx, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto out_free;
+    }
+
     s->total_size = h->RequiredDumpSpace;
 
     s->written_size = qemu_write_full(s->fd, h, sizeof(*h));
     if (s->written_size != sizeof(*h)) {
         error_setg(errp, QERR_IO_ERROR);
-        goto out_cr3;
+        goto out_restore;
     }
 
     write_runs(s, h, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
-        goto out_cr3;
+        goto out_restore;
     }
 
+out_restore:
+    restore_context(h, saved_ctx);
+out_free:
+    g_free(saved_ctx);
 out_cr3:
     first_x86_cpu->env.cr[3] = saved_cr3;
 
diff --git a/win_dump.h b/win_dump.h
index 2812418..f9e1faf 100644
--- a/win_dump.h
+++ b/win_dump.h
@@ -80,8 +80,97 @@ typedef struct WinDumpHeader64 {
 
 void create_win_dump(DumpState *s, Error **errp);
 
-#define KDBG_OWNER_TAG_OFFSET64         0x10
-#define KDBG_KI_BUGCHECK_DATA_OFFSET64  0x88
-#define KDBG_MM_PFN_DATABASE_OFFSET64   0xC0
+#define KDBG_OWNER_TAG_OFFSET64             0x10
+#define KDBG_MM_PFN_DATABASE_OFFSET64       0xC0
+#define KDBG_KI_BUGCHECK_DATA_OFFSET64      0x88
+#define KDBG_KI_PROCESSOR_BLOCK_OFFSET64    0x218
+#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64   0x338
 
 #define VMCOREINFO_ELF_NOTE_HDR_SIZE    24
+
+#define WIN_CTX_X64 0x00100000L
+
+#define WIN_CTX_CTL 0x00000001L
+#define WIN_CTX_INT 0x00000002L
+#define WIN_CTX_SEG 0x00000004L
+#define WIN_CTX_FP  0x00000008L
+#define WIN_CTX_DBG 0x00000010L
+
+#define WIN_CTX_FULL    (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
+#define WIN_CTX_ALL     (WIN_CTX_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
+
+#define LIVE_SYSTEM_DUMP    0x00000161
+
+typedef struct WinM128A {
+    uint64_t low;
+    int64_t high;
+} QEMU_ALIGNED(16) WinM128A;
+
+typedef struct WinContext {
+    uint64_t PHome[6];
+
+    uint32_t ContextFlags;
+    uint32_t MxCsr;
+
+    uint16_t SegCs;
+    uint16_t SegDs;
+    uint16_t SegEs;
+    uint16_t SegFs;
+    uint16_t SegGs;
+    uint16_t SegSs;
+    uint32_t EFlags;
+
+    uint64_t Dr0;
+    uint64_t Dr1;
+    uint64_t Dr2;
+    uint64_t Dr3;
+    uint64_t Dr6;
+    uint64_t Dr7;
+
+    uint64_t Rax;
+    uint64_t Rcx;
+    uint64_t Rdx;
+    uint64_t Rbx;
+    uint64_t Rsp;
+    uint64_t Rbp;
+    uint64_t Rsi;
+    uint64_t Rdi;
+    uint64_t R8;
+    uint64_t R9;
+    uint64_t R10;
+    uint64_t R11;
+    uint64_t R12;
+    uint64_t R13;
+    uint64_t R14;
+    uint64_t R15;
+
+    uint64_t Rip;
+
+    struct {
+        uint16_t ControlWord;
+        uint16_t StatusWord;
+        uint8_t TagWord;
+        uint8_t Reserved1;
+        uint16_t ErrorOpcode;
+        uint32_t ErrorOffset;
+        uint16_t ErrorSelector;
+        uint16_t Reserved2;
+        uint32_t DataOffset;
+        uint16_t DataSelector;
+        uint16_t Reserved3;
+        uint32_t MxCsr;
+        uint32_t MxCsr_Mask;
+        WinM128A FloatRegisters[8];
+        WinM128A XmmRegisters[16];
+        uint8_t Reserved4[96];
+    } FltSave;
+
+    WinM128A VectorRegister[26];
+    uint64_t VectorControl;
+
+    uint64_t DebugControl;
+    uint64_t LastBranchToRip;
+    uint64_t LastBranchFromRip;
+    uint64_t LastExceptionToRip;
+    uint64_t LastExceptionFromRip;
+} QEMU_ALIGNED(16) WinContext;
-- 
1.8.3.1

  parent reply	other threads:[~2018-06-28 20:06 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-28 20:04 [Qemu-devel] [PULL 00/60] Misc patches for soft freeze Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 01/60] exec: Fix MAP_RAM for cached access Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 02/60] move public invalidate APIs out of translate-all.{c, h}, clean up Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 03/60] chardev: don't splatter terminal settings on exit if not previously set Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 04/60] main-loop: document IOCanReadHandler Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 05/60] hw/char/serial: Only retry if qemu_chr_fe_write returns 0 Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 06/60] target/i386: Fix BLSR and BLSI Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 07/60] whpx: commit missing file Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 08/60] memory-device: turn alignment assert into check Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 09/60] exec: check that alignment is a power of two Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 10/60] kvm: Delete the slot if and only if the KVM_MEM_READONLY flag is changed Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 11/60] tests/atomic_add-bench: add -m option to use mutexes Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 12/60] qemu-thread: introduce qemu-thread-common.h Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 13/60] QemuMutex: support --enable-debug-mutex Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 14/60] configure: enable debug-mutex if debug enabled Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 15/60] Replace '-enable-kvm' with '-accel kvm' in docs and help texts Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 16/60] qemu-options: Add missing newline to -accel help text Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 17/60] pc-dimm: remove leftover "struct pc_dimms_capacity" Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 18/60] pc: rename pc_dimm_(plug|unplug|...)* into pc_memory_(plug|unplug|...)* Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 19/60] pc-dimm: rename pc_dimm_memory_* to pc_dimm_* Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 20/60] pc-dimm: remove pc_dimm_get_free_slot() from header Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 21/60] pc: factor out pc specific dimm checks into pc_memory_pre_plug() Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 22/60] nvdimm: no need to overwrite get_vmstate_memory_region() Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 23/60] hostmem: drop error variable from host_memory_backend_get_memory() Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 24/60] pc-dimm: merge get_(vmstate_)memory_region() Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 25/60] nvdimm: convert "unarmed" into a static property Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 26/60] nvdimm: convert nvdimm_mr into a pointer Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 27/60] nvdimm: make get_memory_region() perform checks and initialization Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 28/60] pc-dimm: get_memory_region() will not fail after realize Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 29/60] numa: report all DIMM/NVDIMMs as plugged memory Paolo Bonzini
2018-06-28 20:12   ` David Hildenbrand
2018-06-28 20:04 ` [Qemu-devel] [PULL 30/60] osdep: work around Coverity parsing errors Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 31/60] Deprecate the -enable-hax option Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 32/60] pr-helper: fix --socket-path default in help Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 33/60] pr-helper: fix assertion failure on failed multipath PERSISTENT RESERVE IN Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 34/60] pr-manager-helper: avoid SIGSEGV when writing to the socket fail Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 35/60] pr-manager: put stubs in .c file Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 36/60] pr-manager: add query-pr-managers QMP command Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 37/60] pr-manager-helper: report event on connection/disconnection Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 38/60] hw/mips/jazz: create ESP device directly via qdev Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 39/60] esp: remove legacy esp_init() function Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 40/60] WHPX workaround bug in OSVW handling Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 41/60] WHPX: register for unrecognized MSR exits Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 42/60] memory/hmp: Print owners/parents in "info mtree" Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 43/60] target-i386: Add NMI interception to SVM Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 44/60] target-i386: Allow interrupt injection after STGI Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 45/60] target-i386: Mark cpu_vmexit noreturn Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 46/60] doc: another fix to "info pic" Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 47/60] ioapic: support " Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 48/60] ioapic: some proper indents when dump info Paolo Bonzini
2018-06-28 20:04 ` [Qemu-devel] [PULL 49/60] ioapic: support "info irq" Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 50/60] hmp: obsolete "info ioapic" Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 51/60] kvm: support -overcommit cpu-pm=on|off Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 52/60] i386/cpu: make -cpu host support monitor/mwait Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 53/60] dump: add Windows dump format to dump-guest-memory Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 54/60] dump: use system context in Windows dump Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 55/60] dump: add fallback KDBG using " Paolo Bonzini
2018-06-28 20:05 ` Paolo Bonzini [this message]
2018-06-28 20:05 ` [Qemu-devel] [PULL 57/60] hw/scsi: cleanups before VPD BL emulation Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 58/60] hw/scsi: centralize SG_IO calls into single function Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 59/60] hw/scsi: add VPD Block Limits emulation Paolo Bonzini
2018-06-28 20:05 ` [Qemu-devel] [PULL 60/60] tests/boot-serial: Do not delete the output file in case of errors Paolo Bonzini
2018-06-29  9:25 ` [Qemu-devel] [PULL 00/60] Misc patches for soft freeze Peter Maydell
2018-06-29  9:44   ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1530216310-52873-57-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=viktor.prutyanov@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).