kvm-guest-drivers-windows
232 строки · 6.7 Кб
1/*
2* This file contains driver routines
3*
4* Copyright (C) 2018 Virtuozzo International GmbH
5*
6*/
7#include "driver.h"
8#include "fwcfg.h"
9#include "trace.h"
10#include "driver.tmh"
11
12#ifdef ALLOC_PRAGMA
13#pragma alloc_text(INIT, DriverEntry)
14#pragma alloc_text(PAGE, FwCfgEvtDeviceAdd)
15#pragma alloc_text(PAGE, FwCfgEvtDriverCleanup)
16#endif
17
18NTSTATUS VMCoreInfoFill(PDEVICE_CONTEXT ctx)
19{
20NTSTATUS status;
21PUCHAR hdr_buf;
22ULONG bufSizeNeeded;
23
24TraceEvents(TRACE_LEVEL_VERBOSE, DBG_ALL, "Obtaining header");
25
26hdr_buf = (PUCHAR)ctx->vmci_data.pNote + FIELD_OFFSET(VMCI_ELF64_NOTE, n_desc);
27status = KeInitializeCrashDumpHeader(DUMP_TYPE_FULL, 0, hdr_buf,
28DUMP_HDR_SIZE, &bufSizeNeeded);
29
30if (!NT_SUCCESS(status))
31{
32TraceEvents(TRACE_LEVEL_ERROR, DBG_ALL, "Failed to obtain header");
33return status;
34}
35
36/*
37* Original KDBG pointer was saved in header by system.
38* BugcheckParameter1 field is unused in live system and will be filled by QEMU.
39* So the pointer to decoded KDBG can be stored in this field.
40*/
41#ifdef _AMD64_
42*(PULONG64)(hdr_buf + DUMP_HDR_OFFSET_BUGCHECK_PARAM1) = (ULONG64)ctx->kdbg;
43#else
44*(PULONG32)(hdr_buf + DUMP_HDR_OFFSET_BUGCHECK_PARAM1) = (ULONG32)ctx->kdbg;
45#endif
46
47return status;
48}
49
50NTSTATUS VMCoreInfoSend(PDEVICE_CONTEXT ctx)
51{
52NTSTATUS status;
53
54TraceEvents(TRACE_LEVEL_VERBOSE, DBG_ALL, "Sending header");
55
56status = FWCfgDmaSend(ctx->ioBase, ctx->vmci_data.vmci_pa, ctx->index,
57sizeof(VMCOREINFO), ctx->dma_access, ctx->dma_access_pa);
58
59return status;
60}
61
62VOID FwCfgEvtDriverCleanup(IN WDFOBJECT DriverObject)
63{
64UNREFERENCED_PARAMETER(DriverObject);
65
66PAGED_CODE();
67
68WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
69}
70
71NTSTATUS GetKdbg(PDEVICE_CONTEXT ctx)
72{
73PUCHAR minidump;
74ULONG32 kdbg_offset;
75ULONG32 kdbg_size;
76CONTEXT context = { 0 };
77NTSTATUS status = STATUS_SUCCESS;
78
79minidump = ExAllocatePoolUninitialized(NonPagedPoolNx, MINIDUMP_BUFFER_SIZE, 'pmdm');
80if (!minidump)
81{
82return STATUS_MEMORY_NOT_ALLOCATED;
83}
84memset(minidump, 0, MINIDUMP_BUFFER_SIZE);
85
86KeCapturePersistentThreadState(&context, NULL, 0, 0, 0, 0, 0, minidump);
87
88kdbg_offset = *(PULONG32)(minidump + MINIDUMP_OFFSET_KDBG_OFFSET);
89kdbg_size = *(PULONG32)(minidump + MINIDUMP_OFFSET_KDBG_SIZE);
90
91TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
92"KdDebuggerDataBlock size = %lx, offset = 0x%lx",
93kdbg_size, kdbg_offset);
94
95/*
96* KeCapturePersistentThreadState is supposed to save Small Memory Dump to the buffer.
97* But since it is undocumented function, the driver should check actual output data.
98*/
99if (kdbg_size == 0 || (kdbg_offset + kdbg_size) > MINIDUMP_BUFFER_SIZE)
100{
101status = STATUS_INVALID_BUFFER_SIZE;
102goto out_free_minidump;
103}
104
105ctx->kdbg = ExAllocatePoolUninitialized(NonPagedPoolNx, kdbg_size, 'gbdk');
106if (!ctx->kdbg)
107{
108status = STATUS_MEMORY_NOT_ALLOCATED;
109goto out_free_minidump;
110}
111
112memcpy(ctx->kdbg, minidump + kdbg_offset, kdbg_size);
113
114out_free_minidump:
115ExFreePool(minidump);
116
117return status;
118}
119
120static VOID FwCfgContextInit(PDEVICE_CONTEXT ctx)
121{
122PCBUF_DATA pcbuf_data;
123LONGLONG pcbuf_data_pa;
124
125pcbuf_data = WdfCommonBufferGetAlignedVirtualAddress(ctx->cbuf);
126pcbuf_data_pa = WdfCommonBufferGetAlignedLogicalAddress(ctx->cbuf).QuadPart;
127
128ctx->vmci_data.pNote = &pcbuf_data->note;
129ctx->vmci_data.note_pa = pcbuf_data_pa + FIELD_OFFSET(CBUF_DATA, note);
130
131ctx->vmci_data.pVmci = &pcbuf_data->vmci;
132ctx->vmci_data.vmci_pa = pcbuf_data_pa + FIELD_OFFSET(CBUF_DATA, vmci);
133
134ctx->dma_access = &pcbuf_data->fwcfg_da;
135ctx->dma_access_pa = pcbuf_data_pa + FIELD_OFFSET(CBUF_DATA, fwcfg_da);
136}
137
138NTSTATUS FwCfgEvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit)
139{
140NTSTATUS status;
141WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
142WDF_OBJECT_ATTRIBUTES attributes;
143WDFDEVICE device;
144PDEVICE_CONTEXT ctx;
145WDF_DMA_ENABLER_CONFIG dmaEnablerConfig;
146WDF_DEVICE_STATE devState;
147
148UNREFERENCED_PARAMETER(Driver);
149
150PAGED_CODE();
151
152WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
153
154pnpPowerCallbacks.EvtDevicePrepareHardware = FwCfgEvtDevicePrepareHardware;
155pnpPowerCallbacks.EvtDeviceReleaseHardware = FwCfgEvtDeviceReleaseHardware;
156pnpPowerCallbacks.EvtDeviceD0Entry = FwCfgEvtDeviceD0Entry;
157pnpPowerCallbacks.EvtDeviceD0Exit = FwCfgEvtDeviceD0Exit;
158
159WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
160
161WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);
162
163status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
164
165if (!NT_SUCCESS(status))
166{
167TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
168"WdfDeviceCreate failed: %!STATUS!", status);
169return status;
170}
171
172ctx = GetDeviceContext(device);
173memset(ctx, 0, sizeof(*ctx));
174
175WDF_DMA_ENABLER_CONFIG_INIT(&dmaEnablerConfig, WdfDmaProfilePacket64,
176sizeof(CBUF_DATA));
177status = WdfDmaEnablerCreate(device, &dmaEnablerConfig,
178WDF_NO_OBJECT_ATTRIBUTES, &ctx->dmaEnabler);
179
180if (!NT_SUCCESS(status))
181{
182TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
183"Failed to create DMA enabler");
184return status;
185}
186
187TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
188"DMA enabler created");
189
190status = WdfCommonBufferCreate(ctx->dmaEnabler, sizeof(CBUF_DATA),
191WDF_NO_OBJECT_ATTRIBUTES, &ctx->cbuf);
192if (!NT_SUCCESS(status))
193{
194TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
195"Failed to create common buffer");
196return status;
197}
198
199FwCfgContextInit(ctx);
200
201WDF_DEVICE_STATE_INIT(&devState);
202devState.NotDisableable = WdfFalse;
203WdfDeviceSetDeviceState(device, &devState);
204
205return STATUS_SUCCESS;
206}
207
208NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
209IN PUNICODE_STRING RegistryPath)
210{
211NTSTATUS status;
212WDF_DRIVER_CONFIG config;
213WDF_OBJECT_ATTRIBUTES attributes;
214
215WPP_INIT_TRACING(DriverObject, RegistryPath);
216
217WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
218attributes.EvtCleanupCallback = FwCfgEvtDriverCleanup;
219
220WDF_DRIVER_CONFIG_INIT(&config, FwCfgEvtDeviceAdd);
221
222status = WdfDriverCreate(DriverObject, RegistryPath, &attributes,
223&config, WDF_NO_HANDLE);
224if (!NT_SUCCESS(status))
225{
226TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
227"WdfDriverCreate failed: %!STATUS!", status);
228WPP_CLEANUP(DriverObject);
229}
230
231return status;
232}
233