forked from ionescu007/SimpleVisor
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathshv.c
130 lines (107 loc) · 3.45 KB
/
shv.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*++
Copyright (c) Alex Ionescu. All rights reserved.
Module Name:
shv.c
Abstract:
This module implements the Driver Entry/Unload for the Simple Hyper Visor.
Author:
Alex Ionescu (@aionescu) 16-Mar-2016 - Initial version
Environment:
Kernel mode only.
--*/
#include "shv.h"
PSHV_GLOBAL_DATA ShvGlobalData;
VOID
ShvUnload (
_In_ PDRIVER_OBJECT DriverObject
)
{
UNREFERENCED_PARAMETER(DriverObject);
//
// Attempt to exit VMX root mode on all logical processors. This will
// broadcast a DPC interrupt which will execute the callback routine in
// parallel on the LPs. Send the callback routine a NULL context in order
// to indicate that this is the unload, not load, path.
//
// Note that if SHV is not loaded on any of the LPs, this routine will not
// perform any work, but will not fail in any way.
//
KeGenericCallDpc(ShvVpCallbackDpc, NULL);
//
// If the SHV was not fully/correctly loaded, we may not have global data
// allocated yet. Check for that before freeing it.
//
// Note that KeGenericCallDpc is guaranteed to return only after all LPs
// have succesfully executed the DPC and synchronized. This means that SHV
// is fully unloaded, and no further VMEXITs can return. It is safe to free
// this data.
//
if (ShvGlobalData != NULL)
{
MmFreeContiguousMemory(ShvGlobalData);
}
//
// Indicate unload
//
DbgPrintEx(77, 0, "The SHV has been uninstalled.\n");
}
NTSTATUS
ShvInitialize (
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
UNREFERENCED_PARAMETER(RegistryPath);
//
// Detect if a hypervisor is already loaded, using the standard high bit in
// the ECX features register. Hypervisors may choose to hide from this, at
// which point entering VMX root mode will fail (unless a shadows VMCS is
// used).
//
#ifndef VMWARE_COMPAT_MODE
if (HviIsAnyHypervisorPresent())
{
return STATUS_HV_OBJECT_IN_USE;
}
#endif
//
// Next, detect if the hardware appears to support VMX root mode to start.
// No attempts are made to enable this if it is lacking or disabled.
//
if (!ShvVmxProbe())
{
return STATUS_HV_FEATURE_UNAVAILABLE;
}
//
// Allocate the global shared data which all virtual processors will share.
//
ShvGlobalData = ShvVpAllocateGlobalData();
if (!ShvGlobalData)
{
return STATUS_HV_INSUFFICIENT_BUFFER;
}
//
// Attempt to enter VMX root mode on all logical processors. This will
// broadcast a DPC interrupt which will execute the callback routine in
// parallel on the LPs. Send the callback routine the physical address of
// the PML4 of the system process, which is what this driver entrypoint
// should be executing in.
//
NT_ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
KeGenericCallDpc(ShvVpCallbackDpc, (PVOID)__readcr3());
//
// A hypervisor should now be seen as present on this (and all other) LP,
// as the SHV correctly handles CPUID ECX features register.
//
if (HviIsAnyHypervisorPresent() == FALSE)
{
MmFreeContiguousMemory(ShvGlobalData);
return STATUS_HV_NOT_PRESENT;
}
//
// Make the driver (and SHV itself) unloadable, and indicate success.
//
DriverObject->DriverUnload = ShvUnload;
DbgPrintEx(77, 0, "The SHV has been installed.\n");
return STATUS_SUCCESS;
}