[CMAKE]
[reactos.git] / ntoskrnl / vdm / vdmmain.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/vdm/vdmmain.c
5 * PURPOSE: VDM Support Services
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 VOID
22 NTAPI
23 Ki386VdmEnablePentiumExtentions(IN BOOLEAN Enable)
24 {
25 ULONG EFlags, Cr4;
26
27 /* Save interrupt state and disable them */
28 EFlags = __readeflags();
29 _disable();
30
31 /* Enable or disable VME as required */
32 Cr4 = __readcr4();
33 __writecr4(Enable ? Cr4 | CR4_VME : Cr4 & ~CR4_VME);
34
35 /* Restore interrupt state */
36 __writeeflags(EFlags);
37 }
38
39 VOID
40 NTAPI
41 KeI386VdmInitialize(VOID)
42 {
43 NTSTATUS Status;
44 OBJECT_ATTRIBUTES ObjectAttributes;
45 HANDLE RegHandle;
46 UNICODE_STRING Name;
47 UCHAR KeyValueInfo[sizeof(KEY_VALUE_BASIC_INFORMATION) + 30];
48 ULONG ReturnLength;
49
50 /* Make sure that there is a WOW key */
51 RtlInitUnicodeString(&Name,
52 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
53 L"Control\\Wow");
54 InitializeObjectAttributes(&ObjectAttributes,
55 &Name,
56 OBJ_CASE_INSENSITIVE,
57 NULL,
58 NULL);
59 Status = ZwOpenKey(&RegHandle, KEY_READ, &ObjectAttributes);
60 if (!NT_SUCCESS(Status)) return;
61
62 /* Check if VME is enabled */
63 RtlInitUnicodeString(&Name, L"DisableVme");
64 Status = ZwQueryValueKey(RegHandle,
65 &Name,
66 KeyValueBasicInformation,
67 &KeyValueInfo,
68 sizeof(KeyValueInfo),
69 &ReturnLength);
70 if (!NT_SUCCESS(Status))
71 {
72 /* Not present, so check if the CPU supports VME */
73 if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
74 {
75 /* Enable them. FIXME: Use IPI */
76 Ki386VdmEnablePentiumExtentions(TRUE);
77 KeI386VirtualIntExtensions = TRUE;
78 }
79 }
80
81 /* Close the key */
82 ZwClose(RegHandle);
83 }
84
85 NTSTATUS
86 NTAPI
87 VdmpInitialize(PVOID ControlData)
88 {
89 OBJECT_ATTRIBUTES ObjectAttributes;
90 UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
91 NTSTATUS Status;
92 HANDLE PhysMemHandle;
93 PVOID BaseAddress;
94 PVOID NullAddress = NULL;
95 LARGE_INTEGER Offset;
96 ULONG ViewSize;
97
98 /* Open the physical memory section */
99 InitializeObjectAttributes(&ObjectAttributes,
100 &PhysMemName,
101 0,
102 NULL,
103 NULL);
104 Status = ZwOpenSection(&PhysMemHandle,
105 SECTION_ALL_ACCESS,
106 &ObjectAttributes);
107 if (!NT_SUCCESS(Status))
108 {
109 DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
110 return Status;
111 }
112
113 /* Map the BIOS and device registers into the address space */
114 Offset.QuadPart = 0;
115 ViewSize = PAGE_SIZE;
116 BaseAddress = 0;
117 Status = ZwMapViewOfSection(PhysMemHandle,
118 NtCurrentProcess(),
119 &BaseAddress,
120 0,
121 ViewSize,
122 &Offset,
123 &ViewSize,
124 ViewUnmap,
125 0,
126 PAGE_READWRITE);
127 if (!NT_SUCCESS(Status))
128 {
129 DPRINT1("Couldn't map physical memory (%x)\n", Status);
130 ZwClose(PhysMemHandle);
131 return Status;
132 }
133
134 /* Enter SEH */
135 _SEH2_TRY
136 {
137 /* Copy the first physical page into the first virtual page */
138 RtlMoveMemory(NullAddress, BaseAddress, ViewSize);
139 }
140 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
141 {
142 /* Fail */
143 DPRINT1("Couldn't copy first page (%x)\n", Status);
144 ZwClose(PhysMemHandle);
145 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
146 _SEH2_YIELD(return _SEH2_GetExceptionCode());
147 }
148 _SEH2_END;
149
150 /* Close physical memory section handle */
151 ZwClose(PhysMemHandle);
152
153 /* Unmap the section */
154 Status = ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
155
156 if (!NT_SUCCESS(Status))
157 {
158 DPRINT1("Couldn't unmap the section (%x)\n", Status);
159 return Status;
160 }
161
162 return STATUS_SUCCESS;
163 }
164
165 /* PUBLIC FUNCTIONS **********************************************************/
166
167 /*
168 * @implemented
169 */
170 NTSTATUS
171 NTAPI
172 NtVdmControl(IN ULONG ControlCode,
173 IN PVOID ControlData)
174 {
175 NTSTATUS Status;
176 PAGED_CODE();
177
178 /* Check which control code this is */
179 switch (ControlCode)
180 {
181 /* VDM Execution start */
182 case VdmStartExecution:
183
184 /* Call the sub-function */
185 Status = VdmpStartExecution();
186 break;
187
188 case VdmInitialize:
189
190 /* Call the init sub-function */
191 Status = VdmpInitialize(ControlData);
192 break;
193
194 default:
195
196 /* Unsupported */
197 DPRINT1("Unknown VDM call: %lx\n", ControlCode);
198 Status = STATUS_INVALID_PARAMETER;
199 }
200
201 /* Return the status */
202 return Status;
203 }