xref: /reactos/ntoskrnl/vdm/vdmmain.c (revision 53221834)
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 CODE_SEG("INIT")
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 CODE_SEG("INIT")
40 VOID
41 NTAPI
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 | OBJ_KERNEL_HANDLE,
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 VdmpInitialize(PVOID ControlData)
89 {
90     OBJECT_ATTRIBUTES ObjectAttributes;
91     UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
92     NTSTATUS Status;
93     HANDLE PhysMemHandle;
94     PVOID BaseAddress;
95     volatile PVOID NullAddress = NULL;
96     LARGE_INTEGER Offset;
97     ULONG ViewSize;
98 
99     /* Open the physical memory section */
100     InitializeObjectAttributes(&ObjectAttributes,
101                                &PhysMemName,
102                                OBJ_KERNEL_HANDLE,
103                                NULL,
104                                NULL);
105     Status = ZwOpenSection(&PhysMemHandle,
106                            SECTION_ALL_ACCESS,
107                            &ObjectAttributes);
108     if (!NT_SUCCESS(Status))
109     {
110         DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
111         return Status;
112     }
113 
114     /* Map the BIOS and device registers into the address space */
115     Offset.QuadPart = 0;
116     ViewSize = PAGE_SIZE;
117     BaseAddress = 0;
118     Status = ZwMapViewOfSection(PhysMemHandle,
119                                 NtCurrentProcess(),
120                                 &BaseAddress,
121                                 0,
122                                 ViewSize,
123                                 &Offset,
124                                 &ViewSize,
125                                 ViewUnmap,
126                                 0,
127                                 PAGE_READWRITE);
128     if (!NT_SUCCESS(Status))
129     {
130         DPRINT1("Couldn't map physical memory (%x)\n", Status);
131         ZwClose(PhysMemHandle);
132         return Status;
133     }
134 
135     /* Enter SEH */
136     _SEH2_TRY
137     {
138         /* Copy the first physical page into the first virtual page */
139         RtlMoveMemory(NullAddress, BaseAddress, ViewSize);
140     }
141     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
142     {
143         /* Fail */
144         DPRINT1("Couldn't copy first page (%x)\n", Status);
145         ZwClose(PhysMemHandle);
146         ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
147         _SEH2_YIELD(return _SEH2_GetExceptionCode());
148     }
149     _SEH2_END;
150 
151     /* Close physical memory section handle */
152     ZwClose(PhysMemHandle);
153 
154     /* Unmap the section */
155     Status = ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
156 
157     if (!NT_SUCCESS(Status))
158     {
159         DPRINT1("Couldn't unmap the section (%x)\n", Status);
160         return Status;
161     }
162 
163     return STATUS_SUCCESS;
164 }
165 
166 /* PUBLIC FUNCTIONS **********************************************************/
167 
168 /*
169  * @implemented
170  */
171 NTSTATUS
172 NTAPI
173 NtVdmControl(IN ULONG ControlCode,
174              IN PVOID ControlData)
175 {
176     NTSTATUS Status;
177     PAGED_CODE();
178 
179     /* Check which control code this is */
180     switch (ControlCode)
181     {
182         /* VDM Execution start */
183         case VdmStartExecution:
184 
185             /* Call the sub-function */
186             Status = VdmpStartExecution();
187             break;
188 
189         case VdmInitialize:
190 
191             /* Call the init sub-function */
192             Status = VdmpInitialize(ControlData);
193             break;
194 
195         default:
196 
197             /* Unsupported */
198             DPRINT1("Unknown VDM call: %lx\n", ControlCode);
199             Status = STATUS_INVALID_PARAMETER;
200     }
201 
202     /* Return the status */
203     return Status;
204 }
205