* Sync up to trunk head (r65095).
[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 /* PRIVATE FUNCTIONS *********************************************************/
19
20 VOID
21 NTAPI
22 INIT_FUNCTION
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 INIT_FUNCTION
42 KeI386VdmInitialize(VOID)
43 {
44 NTSTATUS Status;
45 OBJECT_ATTRIBUTES ObjectAttributes;
46 HANDLE RegHandle;
47 UNICODE_STRING Name;
48 UCHAR KeyValueInfo[sizeof(KEY_VALUE_BASIC_INFORMATION) + 30];
49 ULONG ReturnLength;
50
51 /* Make sure that there is a WOW key */
52 RtlInitUnicodeString(&Name,
53 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
54 L"Control\\Wow");
55 InitializeObjectAttributes(&ObjectAttributes,
56 &Name,
57 OBJ_CASE_INSENSITIVE,
58 NULL,
59 NULL);
60 Status = ZwOpenKey(&RegHandle, KEY_READ, &ObjectAttributes);
61 if (!NT_SUCCESS(Status)) return;
62
63 /* Check if VME is enabled */
64 RtlInitUnicodeString(&Name, L"DisableVme");
65 Status = ZwQueryValueKey(RegHandle,
66 &Name,
67 KeyValueBasicInformation,
68 &KeyValueInfo,
69 sizeof(KeyValueInfo),
70 &ReturnLength);
71 if (!NT_SUCCESS(Status))
72 {
73 /* Not present, so check if the CPU supports VME */
74 if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
75 {
76 /* Enable them. FIXME: Use IPI */
77 Ki386VdmEnablePentiumExtentions(TRUE);
78 KeI386VirtualIntExtensions = TRUE;
79 }
80 }
81
82 /* Close the key */
83 ZwClose(RegHandle);
84 }
85
86 NTSTATUS
87 NTAPI
88 INIT_FUNCTION
89 VdmpInitialize(PVOID ControlData)
90 {
91 OBJECT_ATTRIBUTES ObjectAttributes;
92 UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
93 NTSTATUS Status;
94 HANDLE PhysMemHandle;
95 PVOID BaseAddress;
96 volatile PVOID NullAddress = NULL;
97 LARGE_INTEGER Offset;
98 ULONG ViewSize;
99
100 /* Open the physical memory section */
101 InitializeObjectAttributes(&ObjectAttributes,
102 &PhysMemName,
103 0,
104 NULL,
105 NULL);
106 Status = ZwOpenSection(&PhysMemHandle,
107 SECTION_ALL_ACCESS,
108 &ObjectAttributes);
109 if (!NT_SUCCESS(Status))
110 {
111 DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
112 return Status;
113 }
114
115 /* Map the BIOS and device registers into the address space */
116 Offset.QuadPart = 0;
117 ViewSize = PAGE_SIZE;
118 BaseAddress = 0;
119 Status = ZwMapViewOfSection(PhysMemHandle,
120 NtCurrentProcess(),
121 &BaseAddress,
122 0,
123 ViewSize,
124 &Offset,
125 &ViewSize,
126 ViewUnmap,
127 0,
128 PAGE_READWRITE);
129 if (!NT_SUCCESS(Status))
130 {
131 DPRINT1("Couldn't map physical memory (%x)\n", Status);
132 ZwClose(PhysMemHandle);
133 return Status;
134 }
135
136 /* Enter SEH */
137 _SEH2_TRY
138 {
139 /* Copy the first physical page into the first virtual page */
140 RtlMoveMemory(NullAddress, BaseAddress, ViewSize);
141 }
142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
143 {
144 /* Fail */
145 DPRINT1("Couldn't copy first page (%x)\n", Status);
146 ZwClose(PhysMemHandle);
147 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
148 _SEH2_YIELD(return _SEH2_GetExceptionCode());
149 }
150 _SEH2_END;
151
152 /* Close physical memory section handle */
153 ZwClose(PhysMemHandle);
154
155 /* Unmap the section */
156 Status = ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
157
158 if (!NT_SUCCESS(Status))
159 {
160 DPRINT1("Couldn't unmap the section (%x)\n", Status);
161 return Status;
162 }
163
164 return STATUS_SUCCESS;
165 }
166
167 /* PUBLIC FUNCTIONS **********************************************************/
168
169 /*
170 * @implemented
171 */
172 NTSTATUS
173 NTAPI
174 NtVdmControl(IN ULONG ControlCode,
175 IN PVOID ControlData)
176 {
177 NTSTATUS Status;
178 PAGED_CODE();
179
180 /* Check which control code this is */
181 switch (ControlCode)
182 {
183 /* VDM Execution start */
184 case VdmStartExecution:
185
186 /* Call the sub-function */
187 Status = VdmpStartExecution();
188 break;
189
190 case VdmInitialize:
191
192 /* Call the init sub-function */
193 Status = VdmpInitialize(ControlData);
194 break;
195
196 default:
197
198 /* Unsupported */
199 DPRINT1("Unknown VDM call: %lx\n", ControlCode);
200 Status = STATUS_INVALID_PARAMETER;
201 }
202
203 /* Return the status */
204 return Status;
205 }