2006-11-08 11:47:44 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: ntoskrnl/vdm/vdmmain.c
|
|
|
|
* PURPOSE: VDM Support Services
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
2008-09-24 10:06:08 +00:00
|
|
|
* Aleksey Bragin (aleksey@reactos.org)
|
2006-11-08 11:47:44 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include <ntoskrnl.h>
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
Ki386VdmEnablePentiumExtentions(IN BOOLEAN Enable)
|
2006-11-08 11:47:44 +00:00
|
|
|
{
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
ULONG EFlags, Cr4;
|
|
|
|
|
|
|
|
/* Save interrupt state and disable them */
|
|
|
|
EFlags = __readeflags();
|
|
|
|
_disable();
|
|
|
|
|
|
|
|
/* Enable or disable VME as required */
|
|
|
|
Cr4 = __readcr4();
|
|
|
|
__writecr4(Enable ? Cr4 | CR4_VME : Cr4 & ~CR4_VME);
|
|
|
|
|
|
|
|
/* Restore interrupt state */
|
|
|
|
__writeeflags(EFlags);
|
2006-11-08 11:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
2006-11-08 11:47:44 +00:00
|
|
|
KeI386VdmInitialize(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
HANDLE RegHandle;
|
|
|
|
UNICODE_STRING Name;
|
|
|
|
UCHAR KeyValueInfo[sizeof(KEY_VALUE_BASIC_INFORMATION) + 30];
|
|
|
|
ULONG ReturnLength;
|
|
|
|
|
|
|
|
/* Make sure that there is a WOW key */
|
|
|
|
RtlInitUnicodeString(&Name,
|
|
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
|
|
|
L"Control\\Wow");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&Name,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(&RegHandle, KEY_READ, &ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
|
|
|
|
/* Check if VME is enabled */
|
|
|
|
RtlInitUnicodeString(&Name, L"DisableVme");
|
|
|
|
Status = ZwQueryValueKey(RegHandle,
|
|
|
|
&Name,
|
|
|
|
KeyValueBasicInformation,
|
|
|
|
&KeyValueInfo,
|
|
|
|
sizeof(KeyValueInfo),
|
|
|
|
&ReturnLength);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Not present, so check if the CPU supports VME */
|
|
|
|
if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
|
|
|
|
{
|
|
|
|
/* Enable them. FIXME: Use IPI */
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
Ki386VdmEnablePentiumExtentions(TRUE);
|
2006-11-08 11:47:44 +00:00
|
|
|
KeI386VirtualIntExtensions = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the key */
|
|
|
|
ZwClose(RegHandle);
|
|
|
|
}
|
|
|
|
|
2008-09-24 10:06:08 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
2008-09-24 10:06:08 +00:00
|
|
|
VdmpInitialize(PVOID ControlData)
|
|
|
|
{
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
|
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE PhysMemHandle;
|
|
|
|
PVOID BaseAddress;
|
|
|
|
PVOID NullAddress = NULL;
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
ULONG ViewSize;
|
|
|
|
|
|
|
|
/* Open the physical memory section */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&PhysMemName,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = ZwOpenSection(&PhysMemHandle,
|
|
|
|
SECTION_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Map the BIOS and device registers into the address space */
|
|
|
|
Offset.QuadPart = 0;
|
|
|
|
ViewSize = PAGE_SIZE;
|
|
|
|
BaseAddress = 0;
|
|
|
|
Status = ZwMapViewOfSection(PhysMemHandle,
|
|
|
|
NtCurrentProcess(),
|
|
|
|
&BaseAddress,
|
|
|
|
0,
|
|
|
|
ViewSize,
|
|
|
|
&Offset,
|
|
|
|
&ViewSize,
|
|
|
|
ViewUnmap,
|
|
|
|
0,
|
|
|
|
PAGE_READWRITE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Couldn't map physical memory (%x)\n", Status);
|
|
|
|
ZwClose(PhysMemHandle);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2009-08-24 19:58:15 +00:00
|
|
|
/* Enter SEH */
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2008-09-24 10:06:08 +00:00
|
|
|
{
|
2009-08-24 19:58:15 +00:00
|
|
|
/* Copy the first physical page into the first virtual page */
|
2008-09-24 10:06:08 +00:00
|
|
|
RtlMoveMemory(NullAddress, BaseAddress, ViewSize);
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2008-09-24 10:06:08 +00:00
|
|
|
{
|
2009-08-24 19:58:15 +00:00
|
|
|
/* Fail */
|
2008-09-24 10:06:08 +00:00
|
|
|
DPRINT1("Couldn't copy first page (%x)\n", Status);
|
|
|
|
ZwClose(PhysMemHandle);
|
|
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
2009-08-24 19:58:15 +00:00
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2008-09-24 10:06:08 +00:00
|
|
|
}
|
2009-08-24 19:58:15 +00:00
|
|
|
_SEH2_END;
|
2008-09-24 10:06:08 +00:00
|
|
|
|
|
|
|
/* Close physical memory section handle */
|
|
|
|
ZwClose(PhysMemHandle);
|
|
|
|
|
|
|
|
/* Unmap the section */
|
|
|
|
Status = ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Couldn't unmap the section (%x)\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-11-08 11:47:44 +00:00
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtVdmControl(IN ULONG ControlCode,
|
|
|
|
IN PVOID ControlData)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Check which control code this is */
|
|
|
|
switch (ControlCode)
|
|
|
|
{
|
|
|
|
/* VDM Execution start */
|
|
|
|
case VdmStartExecution:
|
|
|
|
|
|
|
|
/* Call the sub-function */
|
|
|
|
Status = VdmpStartExecution();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VdmInitialize:
|
|
|
|
|
2008-09-24 10:06:08 +00:00
|
|
|
/* Call the init sub-function */
|
|
|
|
Status = VdmpInitialize(ControlData);
|
2006-11-08 11:47:44 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
/* Unsupported */
|
|
|
|
DPRINT1("Unknown VDM call: %lx\n", ControlCode);
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the status */
|
|
|
|
return Status;
|
|
|
|
}
|