mirror of
https://github.com/reactos/reactos.git
synced 2024-07-04 03:34:16 +00:00
- Complete and utter reimplementation of V86 Mode for Ke386CallBios. Details below. Tested on QEMU/VMWARE. May give you a breakpoint/crash on real hardware - please let me know the V86 opcode displayed on the debug log/screen if this is the case *if you see such a message*.
- Got rid of all the previous related assembly code and implemented Ki386SetupAndExitToV86Mode and Ki386BiosCallREturnAddress. - Implemented GPF (Trap 13) code for V86 faults (which will happen in V86 mode). Implement a generic Ki386HandleOpcodeV86 handler that increments counts and calls the right opcode handler. - Implemented an Opcode Table Entry Index and Opcode Table array for mapping opcodes that caused a GPF to their V86 handlers/emulators. - Implemented handlers for PUSHF, POPF, CLI, STI, IRETD and INTnn, which is what QEMU/VMWare and *most* VIDEO ROM BIOS code should use. - Created a /vdm tree and moved all NTVDM/VDM specific code there. - Halfplemented VdmStart/EndExecution APIs which the BIOS ROM V86 implementation is built upon. Currently don't handle VDM at all, only this V86 mode. - Also added code for NtVdmControl and fixed up CSRSS and ACPI's calls to this API. - Added detection and FIXMEs for support of VMEs in VMWare, Bochs and real hardware (VME is not yet supported). - Move exp.c fixmes to krnlfun and remove kernel fun entries that this patch fixes. svn path=/trunk/; revision=23763
This commit is contained in:
parent
9d1c606794
commit
28122cd8d9
|
@ -441,6 +441,9 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems","Required",0x
|
|||
HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems","Vms",0x00020000,"%SystemRoot%\system32\csr.exe ObjectDirectory=\VMS SharedSection=128 Windows=Off SubSystemType=Text ServerDll=vmssrv,1 ProfileControl=Off RequestThreads=2 MaxRequestThreads=2 Sessions=Off"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems","Windows",0x00020000,"%SystemRoot%\system32\csrss.exe"
|
||||
|
||||
; WOW Support
|
||||
HKLM,"SYSTEM\CurrentControlSet\Control\Wow","",0x00000000,""
|
||||
|
||||
; PNP Root device
|
||||
HKLM,"SYSTEM\CurrentControlSet\Enum\HTREE\ROOT\0","",0x00000000,""
|
||||
|
||||
|
|
|
@ -27,11 +27,6 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* NDK FIXME */
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtVdmControl (ULONG ControlCode, PVOID ControlData);
|
||||
|
||||
static PKINTERRUPT AcpiInterrupt;
|
||||
static BOOLEAN AcpiInterruptHandlerRegistered = FALSE;
|
||||
static OSD_HANDLER AcpiIrqHandler = NULL;
|
||||
|
@ -143,13 +138,9 @@ acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt)
|
|||
if (phys == 0x0) {
|
||||
/* Real mode Interrupt Vector Table */
|
||||
Virtual = ExAllocatePool(NonPagedPool, size);
|
||||
if (NT_SUCCESS(NtVdmControl(0, Virtual))) {
|
||||
IVTVirtualAddress = Virtual;
|
||||
*virt = Virtual;
|
||||
return AE_OK;
|
||||
} else {
|
||||
return AE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Address.QuadPart = (ULONG)phys;
|
||||
|
|
|
@ -145,53 +145,51 @@ IntInt10WriteMemory(
|
|||
return NO_ERROR;
|
||||
}
|
||||
|
||||
VP_STATUS NTAPI
|
||||
VP_STATUS
|
||||
NTAPI
|
||||
IntInt10CallBios(
|
||||
IN PVOID Context,
|
||||
IN OUT PINT10_BIOS_ARGUMENTS BiosArguments)
|
||||
IN PVOID Context,
|
||||
IN OUT PINT10_BIOS_ARGUMENTS BiosArguments)
|
||||
{
|
||||
KV86M_REGISTERS Regs;
|
||||
NTSTATUS Status;
|
||||
PKPROCESS CallingProcess;
|
||||
KAPC_STATE ApcState;
|
||||
CONTEXT BiosContext;
|
||||
NTSTATUS Status;
|
||||
PKPROCESS CallingProcess;
|
||||
KAPC_STATE ApcState;
|
||||
|
||||
DPRINT("IntInt10CallBios\n");
|
||||
/* Attach to CSRSS */
|
||||
IntAttachToCSRSS(&CallingProcess, &ApcState);
|
||||
|
||||
IntAttachToCSRSS(&CallingProcess, &ApcState);
|
||||
/* Clear the context */
|
||||
RtlZeroMemory(&BiosContext, sizeof(CONTEXT));
|
||||
|
||||
memset(&Regs, 0, sizeof(Regs));
|
||||
DPRINT("- Input register Eax: %x\n", BiosArguments->Eax);
|
||||
Regs.Eax = BiosArguments->Eax;
|
||||
DPRINT("- Input register Ebx: %x\n", BiosArguments->Ebx);
|
||||
Regs.Ebx = BiosArguments->Ebx;
|
||||
DPRINT("- Input register Ecx: %x\n", BiosArguments->Ecx);
|
||||
Regs.Ecx = BiosArguments->Ecx;
|
||||
DPRINT("- Input register Edx: %x\n", BiosArguments->Edx);
|
||||
Regs.Edx = BiosArguments->Edx;
|
||||
DPRINT("- Input register Esi: %x\n", BiosArguments->Esi);
|
||||
Regs.Esi = BiosArguments->Esi;
|
||||
DPRINT("- Input register Edi: %x\n", BiosArguments->Edi);
|
||||
Regs.Edi = BiosArguments->Edi;
|
||||
DPRINT("- Input register Ebp: %x\n", BiosArguments->Ebp);
|
||||
Regs.Ebp = BiosArguments->Ebp;
|
||||
DPRINT("- Input register SegDs: %x\n", BiosArguments->SegDs);
|
||||
Regs.Ds = BiosArguments->SegDs;
|
||||
DPRINT("- Input register SegEs: %x\n", BiosArguments->SegEs);
|
||||
Regs.Es = BiosArguments->SegEs;
|
||||
Status = Ke386CallBios(0x10, (PCONTEXT)&Regs);
|
||||
BiosArguments->Eax = Regs.Eax;
|
||||
BiosArguments->Ebx = Regs.Ebx;
|
||||
BiosArguments->Ecx = Regs.Ecx;
|
||||
BiosArguments->Edx = Regs.Edx;
|
||||
BiosArguments->Esi = Regs.Esi;
|
||||
BiosArguments->Edi = Regs.Edi;
|
||||
BiosArguments->Ebp = Regs.Ebp;
|
||||
BiosArguments->SegDs = Regs.Ds;
|
||||
BiosArguments->SegEs = Regs.Es;
|
||||
/* Fil out the bios arguments */
|
||||
BiosContext.Eax = BiosArguments->Eax;
|
||||
BiosContext.Ebx = BiosArguments->Ebx;
|
||||
BiosContext.Ecx = BiosArguments->Ecx;
|
||||
BiosContext.Edx = BiosArguments->Edx;
|
||||
BiosContext.Esi = BiosArguments->Esi;
|
||||
BiosContext.Edi = BiosArguments->Edi;
|
||||
BiosContext.Ebp = BiosArguments->Ebp;
|
||||
BiosContext.SegDs = BiosArguments->SegDs;
|
||||
BiosContext.SegEs = BiosArguments->SegEs;
|
||||
|
||||
IntDetachFromCSRSS(&CallingProcess, &ApcState);
|
||||
/* Do the ROM BIOS call */
|
||||
Status = Ke386CallBios(0x10, &BiosContext);
|
||||
|
||||
return Status;
|
||||
/* Return the arguments */
|
||||
BiosArguments->Eax = BiosContext.Eax;
|
||||
BiosArguments->Ebx = BiosContext.Ebx;
|
||||
BiosArguments->Ecx = BiosContext.Ecx;
|
||||
BiosArguments->Edx = BiosContext.Edx;
|
||||
BiosArguments->Esi = BiosContext.Esi;
|
||||
BiosArguments->Edi = BiosContext.Edi;
|
||||
BiosArguments->Ebp = BiosContext.Ebp;
|
||||
BiosArguments->SegDs = BiosContext.SegDs;
|
||||
BiosArguments->SegEs = BiosContext.SegEs;
|
||||
|
||||
/* Detach and return status */
|
||||
IntDetachFromCSRSS(&CallingProcess, &ApcState);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
|
|
@ -471,6 +471,11 @@ Author:
|
|||
#define SERVICE_DESCRIPTOR_NUMBER 0x000C
|
||||
#define SERVICE_DESCRIPTOR_LENGTH 0x0010
|
||||
|
||||
//
|
||||
// VDM State Pointer
|
||||
//
|
||||
#define FIXED_NTVDMSTATE_LINEAR_PC_AT 0x714
|
||||
|
||||
//
|
||||
// Machine types
|
||||
//
|
||||
|
|
|
@ -83,6 +83,7 @@ Author:
|
|||
#define EFLAGS_ALIGN_CHECK 0x40000
|
||||
#define EFLAGS_VIF 0x80000
|
||||
#define EFLAGS_VIP 0x100000
|
||||
#define EFLAGS_USER_SANITIZE 0x3F4DD7
|
||||
#define EFLAG_SIGN 0x8000
|
||||
#define EFLAG_ZERO 0x4000
|
||||
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
// - Use Object Type Mutex/Lock.
|
||||
//
|
||||
// Ke:
|
||||
// - Reimplement the V86 support using a mode that will be compatible with
|
||||
// VDM and the future and use ABIOS gates.
|
||||
// - Implement Invalid Opcode and GPD handlers for V86-mode.
|
||||
// - Clean up exp.c (remove all stack functions and use RtlWalkFrameChain/RtlCaptureStackBacktrace)
|
||||
// - Sanitize some context fields during conversions
|
||||
// - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
|
||||
// - Forward exceptions to user-mode debugger.
|
||||
// - Implement stack fault and segment fault handlers.
|
||||
// - Implement kernel-mode GPF handler, possibly fixing below:
|
||||
// - Figure out why ES/DS gets messed up in VMWare, when doing KiServiceExit only,
|
||||
|
@ -36,7 +37,6 @@
|
|||
// - Add DR macro/save and VM macro/save.
|
||||
// - Implement KiCallbackReturn, KiGetTickCount, KiRaiseAssertion.
|
||||
//
|
||||
//
|
||||
// Ex:
|
||||
// - Use pushlocks for handle implementation.
|
||||
//
|
||||
|
|
|
@ -560,7 +560,7 @@ ExpInitializeExecutive(VOID)
|
|||
|
||||
/* Initalize the Process Manager */
|
||||
PiInitProcessManager();
|
||||
|
||||
|
||||
/* Break into the Debugger if requested */
|
||||
if (KdPollBreakIn()) DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
|
||||
|
||||
|
@ -638,6 +638,9 @@ ExpInitializeExecutive(VOID)
|
|||
/* Import and Load Registry Hives */
|
||||
CmInitHives(SetupMode);
|
||||
|
||||
/* Initialize VDM support */
|
||||
KeI386VdmInitialize();
|
||||
|
||||
/* Initialize the time zone information from the registry */
|
||||
ExpInitTimeZoneInfo();
|
||||
|
||||
|
|
|
@ -150,6 +150,42 @@ _KiUnexpectedInterrupt&Number:
|
|||
.endr
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name INVALID_V86_OPCODE
|
||||
//
|
||||
// This macro creates one or more entries for unhandled V86 Opcodes
|
||||
// in the V86 Opcode Table.
|
||||
//
|
||||
// @param count.
|
||||
// Number of entries to generate.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro INVALID_V86_OPCODE count
|
||||
.rept \count
|
||||
.byte 0
|
||||
.endr
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name INVALID_V86_OPCODE
|
||||
//
|
||||
// This macro prints out visible message and hangs the computer.
|
||||
//
|
||||
// @param None.
|
||||
//
|
||||
// @remark Temporary debugging use.
|
||||
//
|
||||
.macro UNHANDLED_V86_OPCODE
|
||||
/* Print debug message, breakpoint and freeze */
|
||||
push ecx
|
||||
push offset V86DebugMsg
|
||||
call _DbgPrint
|
||||
add esp, 8
|
||||
int 3
|
||||
jmp $
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name SET_TF_DEBUG_HEADER
|
||||
//
|
||||
|
@ -512,6 +548,134 @@ _KiUnexpectedInterrupt&Number:
|
|||
sti
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name V86_TRAP_PROLOG
|
||||
//
|
||||
// This macro creates a V86 Trap entry prologue.
|
||||
// It should be used for entry into any fast-system call (KiGetTickCount,
|
||||
// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
|
||||
// (KiSystemService)
|
||||
//
|
||||
// @param Label
|
||||
// Unique label identifying the name of the caller function; will be
|
||||
// used to append to the name of the DR helper function, which must
|
||||
// already exist.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro V86_TRAP_PROLOG Label
|
||||
|
||||
/* Skip everything to the error code */
|
||||
sub esp, KTRAP_FRAME_ERROR_CODE
|
||||
|
||||
/* Clear the error code */
|
||||
mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
|
||||
|
||||
/* Save the registers we'll trample */
|
||||
mov [esp+KTRAP_FRAME_EBX], ebx
|
||||
mov [esp+KTRAP_FRAME_EAX], eax
|
||||
mov [esp+KTRAP_FRAME_EBP], ebp
|
||||
mov [esp+KTRAP_FRAME_ESI], esi
|
||||
mov [esp+KTRAP_FRAME_EDI], edi
|
||||
|
||||
/* Save PCR and Ring 3 segments */
|
||||
mov ebx, KGDT_R0_PCR
|
||||
mov eax, KGDT_R3_DATA + RPL_MASK
|
||||
|
||||
/* Save ECX and EDX too */
|
||||
mov [esp+KTRAP_FRAME_ECX], ecx
|
||||
mov [esp+KTRAP_FRAME_EDX], edx
|
||||
|
||||
/* Set debugging markers */
|
||||
mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
|
||||
mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
|
||||
|
||||
/* Now set segments (use OVERRIDE, 0x66) */
|
||||
.byte 0x66
|
||||
mov fs, bx
|
||||
.byte 0x66
|
||||
mov ds, ax
|
||||
.byte 0x66
|
||||
mov es, ax
|
||||
|
||||
/* Set the trap frame in the stack and clear the direction flag */
|
||||
mov ebp, esp
|
||||
cld
|
||||
|
||||
/* Save the exception list */
|
||||
mov eax, [fs:KPCR_EXCEPTION_LIST]
|
||||
mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
|
||||
|
||||
/* Check if we need debugging */
|
||||
mov eax, dr7
|
||||
test eax, ~DR7_RESERVED_MASK
|
||||
mov [esp+KTRAP_FRAME_DR7], eax
|
||||
// jnz Dr_&Label
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name V86_TRAP_EPILOG
|
||||
//
|
||||
// This macro creates an epilogue for leaving V86 traps
|
||||
//
|
||||
// @param None.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro V86_TRAP_EPILOG
|
||||
|
||||
/* Get the current thread and make it unalerted */
|
||||
ExitBegin:
|
||||
mov ebx, [fs:KPCR_CURRENT_THREAD]
|
||||
mov byte ptr [ebx+KTHREAD_ALERTED], 0
|
||||
|
||||
/* Check if it has User-mode APCs pending */
|
||||
cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
|
||||
jne PendingUserApc
|
||||
|
||||
/* It doesn't, pop the frame */
|
||||
add esp, KTRAP_FRAME_EDX
|
||||
pop edx
|
||||
pop ecx
|
||||
pop eax
|
||||
|
||||
/* Check if DR registers should be restored */
|
||||
test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
|
||||
//jnz V86DebugRestore
|
||||
|
||||
/* Finish popping the rest of the frame, and return to P-mode */
|
||||
add esp, 12
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
add esp, 4
|
||||
iretd
|
||||
|
||||
PendingUserApc:
|
||||
|
||||
/* Raise to APC level */
|
||||
mov ecx, APC_LEVEL
|
||||
call @KfRaiseIrql@4
|
||||
|
||||
/* Save KIRQL and deliver APCs */
|
||||
push eax
|
||||
sti
|
||||
push ebp
|
||||
push 0
|
||||
push UserMode
|
||||
call _KiDeliverApc@12
|
||||
|
||||
/* Restore IRQL */
|
||||
pop ecx
|
||||
call @KfLowerIrql@4
|
||||
cli
|
||||
|
||||
/* Check if we're not in V86 anymore */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jnz ExitBegin
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name TRAP_EPILOG
|
||||
//
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
#define X86_CR4_OSFXSR 0x00000200 /* enable FXSAVE/FXRSTOR instructions */
|
||||
#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable #XF exception */
|
||||
|
||||
#define KF_RDTSC 0x00000002 /* time stamp counters are present */
|
||||
#define X86_FEATURE_VME 0x00000002 /* Virtual 8086 Extensions are present */
|
||||
#define X86_FEATURE_TSC 0x00000010 /* time stamp counters are present */
|
||||
#define X86_FEATURE_PAE 0x00000040 /* physical address extension is present */
|
||||
#define X86_FEATURE_CX8 0x00000100 /* CMPXCHG8B instruction present */
|
||||
#define X86_FEATURE_SYSCALL 0x00000800 /* SYSCALL/SYSRET support present */
|
||||
|
|
|
@ -71,6 +71,10 @@ extern PULONG KiInterruptTemplateObject;
|
|||
extern PULONG KiInterruptTemplateDispatch;
|
||||
extern PULONG KiInterruptTemplate2ndDispatch;
|
||||
extern ULONG KiUnexpectedEntrySize;
|
||||
extern PVOID Ki386IopmSaveArea;
|
||||
extern ULONG KeI386EFlagsAndMaskV86;
|
||||
extern ULONG KeI386EFlagsOrMaskV86;
|
||||
extern BOOLEAN KeI386VirtualIntExtensions;
|
||||
|
||||
/* MACROS *************************************************************************/
|
||||
|
||||
|
@ -139,6 +143,8 @@ extern KSPIN_LOCK DispatcherDatabaseLock;
|
|||
/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */
|
||||
#define TIMER_WAIT_BLOCK 0x3L
|
||||
|
||||
#define IOPM_OFFSET FIELD_OFFSET(KTSS, IoMaps[0].IoMap)
|
||||
|
||||
/* INTERNAL KERNEL FUNCTIONS ************************************************/
|
||||
|
||||
/* threadsch.c ********************************************************************/
|
||||
|
@ -733,6 +739,24 @@ KiChainedDispatch(
|
|||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386AdjustEsp0(
|
||||
IN PKTRAP_FRAME TrapFrame
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386SetupAndExitToV86Mode(
|
||||
OUT PTEB VdmTeb
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KeI386VdmInitialize(
|
||||
VOID
|
||||
);
|
||||
|
||||
#include "ke_x.h"
|
||||
|
||||
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_KE_H */
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "tag.h"
|
||||
#include "test.h"
|
||||
#include "inbv.h"
|
||||
#include "vdm.h"
|
||||
|
||||
#include <pshpack1.h>
|
||||
/*
|
||||
|
|
194
reactos/ntoskrnl/include/internal/vdm.h
Normal file
194
reactos/ntoskrnl/include/internal/vdm.h
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/include/vdm.h
|
||||
* PURPOSE: Internal header for V86 and VDM Support
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
//
|
||||
// Define this if you want debugging support
|
||||
//
|
||||
#define _VM_DEBUG_ 0x00
|
||||
|
||||
//
|
||||
// These define the Debug Masks Supported
|
||||
//
|
||||
#define VM_EXEC_DEBUG 0x01
|
||||
|
||||
//
|
||||
// Debug/Tracing support
|
||||
//
|
||||
#if _VM_DEBUG_
|
||||
#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
|
||||
#define VMTRACE DbgPrintEx
|
||||
#else
|
||||
#define VMTRACE(x, ...) \
|
||||
if (x & VdmpTraceLevel) DbgPrint(__VA_ARGS__)
|
||||
#endif
|
||||
#else
|
||||
#define VMTRACE(x, ...) DPRINT(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Memory addresses inside CSRSS for V86 Support
|
||||
//
|
||||
#define TRAMPOLINE_BASE 0x10000
|
||||
#define TRAMPOLINE_TIB 0x12000
|
||||
#define TRAMPOLINE_TEB 0x13000
|
||||
|
||||
//
|
||||
// BOP (Magic Opcode) to exit V86 Mode
|
||||
//
|
||||
#define TRAMPOLINE_BOP 0xFEC4C4
|
||||
|
||||
//
|
||||
// VDM State Pointer
|
||||
//
|
||||
#define VdmState \
|
||||
(PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT
|
||||
|
||||
//
|
||||
// VDM Event Types
|
||||
//
|
||||
typedef enum _VdmEventClass
|
||||
{
|
||||
VdmIO,
|
||||
VdmStringIO,
|
||||
VdmMemAccess,
|
||||
VdmIntAck,
|
||||
VdmBop,
|
||||
VdmError,
|
||||
VdmIrq13
|
||||
} VDMEVENTCLASS, *PVDMEVENTCLASS;
|
||||
|
||||
//
|
||||
// VDM Interrupt and Fault Handler Definitions
|
||||
//
|
||||
typedef struct _Vdm_InterruptHandler
|
||||
{
|
||||
USHORT CsSelector;
|
||||
USHORT Flags;
|
||||
ULONG Eip;
|
||||
} VDM_INTERRUPTHANDLER, *PVDM_INTERRUPTHANDLER;
|
||||
|
||||
typedef struct _Vdm_FaultHandler
|
||||
{
|
||||
USHORT CsSelector;
|
||||
USHORT SsSelector;
|
||||
ULONG Eip;
|
||||
ULONG Esp;
|
||||
ULONG Flags;
|
||||
} VDM_FAULTHANDLER, *PVDM_FAULTHANDLER;
|
||||
|
||||
//
|
||||
// VDM Event Information
|
||||
//
|
||||
typedef struct _VdmEventInfo
|
||||
{
|
||||
ULONG Size;
|
||||
VDMEVENTCLASS Event;
|
||||
ULONG InstructionSize;
|
||||
union
|
||||
{
|
||||
//VDMIOINFO IoInfo;
|
||||
//VDMSTRINGIOINFO StringIoInfo;
|
||||
ULONG BopNumber;
|
||||
//VDMFAULTINFO FaultInfo;
|
||||
LONG ErrorStatus;
|
||||
ULONG IntAckInfo;
|
||||
};
|
||||
} VDMEVENTINFO, *PVDMEVENTINFO;
|
||||
|
||||
//
|
||||
// VDM Printer Information
|
||||
//
|
||||
typedef struct _Vdm_Printer_Info
|
||||
{
|
||||
PUCHAR prt_state;
|
||||
// TODO
|
||||
} VDM_PRINTER_INFO, *PVDM_PRINTER_INFO;
|
||||
|
||||
//
|
||||
// VDM Trace Information
|
||||
//
|
||||
typedef struct _VdmTraceInfo
|
||||
{
|
||||
// TODO
|
||||
UCHAR Flags;
|
||||
// TODO
|
||||
} VDMTRACEINFO, *PVDMTRACEINFO;
|
||||
|
||||
//
|
||||
// VDM Family Table
|
||||
//
|
||||
typedef struct _tagFAMILY_TABLE
|
||||
{
|
||||
INT numHookedAPIs;
|
||||
// TODO
|
||||
} FAMILY_TABLE, *PFAMILY_TABLE;
|
||||
|
||||
//
|
||||
// Thread Information Block for VDM Threads
|
||||
//
|
||||
typedef struct _Vdm_Tib
|
||||
{
|
||||
ULONG Size;
|
||||
PVDM_INTERRUPTHANDLER VdmInterruptTable;
|
||||
PVDM_FAULTHANDLER VdmFaultTable;
|
||||
CONTEXT MonitorContext;
|
||||
CONTEXT VdmContext;
|
||||
VDMEVENTINFO EventInfo;
|
||||
VDM_PRINTER_INFO PrinterInfo;
|
||||
ULONG TempArea1[2];
|
||||
ULONG TempArea2[2];
|
||||
VDMTRACEINFO TraceInfo;
|
||||
ULONG IntelMSW;
|
||||
LONG NumTasks;
|
||||
PFAMILY_TABLE *pDpmFamTbls;
|
||||
BOOLEAN ContinueExecution;
|
||||
} VDM_TIB, *PVDM_TIB;
|
||||
|
||||
//
|
||||
// Process Information Block for VDM Processes
|
||||
//
|
||||
typedef struct _VDM_PROCESS_OBJECTS
|
||||
{
|
||||
PVOID VdmIoListHead; // PVDM_IO_LISTHEAD
|
||||
KAPC QueuedIntApc;
|
||||
KAPC QueuedIntUserApc;
|
||||
FAST_MUTEX DelayIntFastMutex;
|
||||
KSPIN_LOCK DelayIntSpinLock;
|
||||
LIST_ENTRY DelayIntListHead;
|
||||
PVOID pIcaUserData; // VDMICAUSERDATA
|
||||
PETHREAD MainThread;
|
||||
PVDM_TIB VdmTib;
|
||||
UCHAR PrinterState;
|
||||
UCHAR PrinterControl;
|
||||
UCHAR PrinterStatus;
|
||||
UCHAR PrinterHostState;
|
||||
USHORT AdlibStatus;
|
||||
USHORT AdlibIndexRegister;
|
||||
USHORT AdlibPhysPortStart;
|
||||
USHORT AdlibPhysPortEnd;
|
||||
USHORT AdlibVirtPortStart;
|
||||
USHORT AdlibVirtPortEnd;
|
||||
USHORT AdlibAction;
|
||||
USHORT VdmControl;
|
||||
ULONG PMCliTimeStamp;
|
||||
} VDM_PROCESS_OBJECTS, *PVDM_PROCESS_OBJECTS;
|
||||
|
||||
//
|
||||
// Functions
|
||||
//
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
VdmpStartExecution(
|
||||
VOID
|
||||
);
|
||||
|
||||
//
|
||||
// Global data inside the VDM
|
||||
//
|
||||
|
||||
|
|
@ -9,14 +9,6 @@
|
|||
* Skywing (skywing@valhallalegends.com)
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIXMES:
|
||||
* - Clean up file (remove all stack functions and use RtlWalkFrameChain/RtlCaptureStackBacktrace)
|
||||
* - Sanitize some context fields.
|
||||
* - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
|
||||
* - Forward exceptions to user-mode debugger.
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
|
@ -219,33 +211,6 @@ KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
|
|||
KeDumpStackFrames((PULONG)Tf->Ebp);
|
||||
}
|
||||
|
||||
ULONG
|
||||
KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
|
||||
/*
|
||||
* FUNCTION: Called by the lowlevel execption handlers to print an amusing
|
||||
* message and halt the computer
|
||||
* ARGUMENTS:
|
||||
* Complete CPU context
|
||||
*/
|
||||
{
|
||||
ULONG_PTR cr2;
|
||||
ASSERT(ExceptionNr == 13 || ExceptionNr == 6);
|
||||
|
||||
/* Get CR2 */
|
||||
cr2 = Ke386GetCr2();
|
||||
Tf->DbgArgPointer = cr2;
|
||||
|
||||
/*
|
||||
* If this was a V86 mode exception then handle it specially
|
||||
*/
|
||||
if (Tf->EFlags & (1 << 17))
|
||||
{
|
||||
DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->EFlags, Tf->Eip, ExceptionNr);
|
||||
return(KeV86Exception(ExceptionNr, Tf, cr2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
|
||||
|
@ -969,7 +934,6 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
|
|||
ULONG_PTR Stack, NewStack;
|
||||
ULONG Size;
|
||||
BOOLEAN UserDispatch = FALSE;
|
||||
DPRINT("KiDispatchException() called\n");
|
||||
|
||||
/* Increase number of Exception Dispatches */
|
||||
KeGetCurrentPrcb()->KeExceptionDispatchCount++;
|
||||
|
|
|
@ -587,7 +587,7 @@ Ki386SetProcessorFeatures(VOID)
|
|||
SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
|
||||
(Ke386CpuidExFlags & X86_EXT_FEATURE_3DNOW) ? TRUE : FALSE;
|
||||
SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
|
||||
(Pcr->PrcbData.FeatureBits & KF_RDTSC) ? TRUE : FALSE;
|
||||
(Pcr->PrcbData.FeatureBits & X86_FEATURE_TSC) ? TRUE : FALSE;
|
||||
SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = Ke386Pae;
|
||||
SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
|
||||
(Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? TRUE : FALSE;
|
||||
|
|
|
@ -565,7 +565,7 @@ NotUserMode:
|
|||
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
||||
|
||||
/* Check if this is a VDM Process */
|
||||
//cmp dword ptr [ebx+KPROCESS_VDM_OBJECTS], 0
|
||||
//cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
||||
//jz VdmProc
|
||||
|
||||
/* Exit through common routine */
|
||||
|
@ -980,18 +980,12 @@ _KiTrap6:
|
|||
/* Enter trap */
|
||||
TRAP_PROLOG(6)
|
||||
|
||||
/* Call the C exception handler */
|
||||
push 6
|
||||
push ebp
|
||||
call _KiTrapHandler
|
||||
add esp, 8
|
||||
|
||||
/* Check for v86 recovery */
|
||||
cmp eax, 1
|
||||
/* Not yet supported */
|
||||
int 3
|
||||
jmp $
|
||||
|
||||
/* Return to caller */
|
||||
jne _Kei386EoiHelper@0
|
||||
jmp _KiV86Complete
|
||||
jmp _Kei386EoiHelper@0
|
||||
.endfunc
|
||||
|
||||
.func KiTrap7
|
||||
|
@ -1205,21 +1199,157 @@ _KiTrap12:
|
|||
|
||||
.func KiTrap13
|
||||
_KiTrap13:
|
||||
|
||||
/* It this a V86 GPF? */
|
||||
test dword ptr [esp+12], EFLAGS_V86_MASK
|
||||
jz NotV86
|
||||
|
||||
/* Enter V86 Trap */
|
||||
V86_TRAP_PROLOG kitd
|
||||
|
||||
/* Make sure that this is a V86 process */
|
||||
mov ecx, [fs:KPCR_CURRENT_THREAD]
|
||||
mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
|
||||
cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
|
||||
jnz RaiseIrql
|
||||
|
||||
/* Otherwise, something is very wrong, raise an exception */
|
||||
sti
|
||||
jmp $
|
||||
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
||||
mov esi, -1
|
||||
mov eax, STATUS_ACCESS_VIOLATION
|
||||
jmp _DispatchTwoParam
|
||||
|
||||
RaiseIrql:
|
||||
|
||||
/* Go to APC level */
|
||||
mov ecx, APC_LEVEL
|
||||
call @KfRaiseIrql@4
|
||||
|
||||
/* Save old IRQL and enable interrupts */
|
||||
push eax
|
||||
sti
|
||||
|
||||
/* Handle the opcode */
|
||||
call _Ki386HandleOpcodeV86@0
|
||||
|
||||
/* Check if this was VDM */
|
||||
test al, 0xFF
|
||||
jnz NoReflect
|
||||
|
||||
/* FIXME: TODO */
|
||||
int 3
|
||||
|
||||
NoReflect:
|
||||
|
||||
/* Lower IRQL and disable interrupts */
|
||||
pop ecx
|
||||
call @KfLowerIrql@4
|
||||
cli
|
||||
|
||||
/* Check if this was a V86 trap */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jz NotV86Trap
|
||||
|
||||
/* Exit the V86 Trap */
|
||||
V86_TRAP_EPILOG
|
||||
|
||||
NotV86Trap:
|
||||
|
||||
/* Either this wasn't V86, or it was, but an APC interrupted us */
|
||||
jmp _Kei386EoiHelper@0
|
||||
|
||||
NotV86:
|
||||
/* Enter trap */
|
||||
TRAP_PROLOG(13)
|
||||
|
||||
/* Call the C exception handler */
|
||||
push 13
|
||||
push ebp
|
||||
call _KiTrapHandler
|
||||
add esp, 8
|
||||
|
||||
/* Check for v86 recovery */
|
||||
cmp eax, 1
|
||||
/* Check if this was from kernel-mode */
|
||||
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
||||
jnz UserModeGpf
|
||||
|
||||
/* Return to caller */
|
||||
jne _Kei386EoiHelper@0
|
||||
jmp _KiV86Complete
|
||||
/* FIXME: Check for GPF during GPF */
|
||||
|
||||
/* Get the opcode and trap frame */
|
||||
mov eax, [ebp+KTRAP_FRAME_EIP]
|
||||
mov eax, [eax]
|
||||
mov edx, [ebp+KTRAP_FRAME_EBP]
|
||||
|
||||
/* We want to check if this was POP [DS/ES/FS/GS] */
|
||||
add edx, KTRAP_FRAME_DS
|
||||
cmp al, 0x1F
|
||||
jz SegPopGpf
|
||||
add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
|
||||
cmp al, 7
|
||||
jz SegPopGpf
|
||||
add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
|
||||
cmp ax, 0xA10F
|
||||
jz SegPopGpf
|
||||
add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
|
||||
cmp ax, 0xA90F
|
||||
jz SegPopGpf
|
||||
|
||||
/* It isn't, was it IRETD? */
|
||||
cmp al, 0xCF
|
||||
jne NotIretGpf
|
||||
|
||||
/* Get error code */
|
||||
lea edx, [ebp+KTRAP_FRAME_ESP]
|
||||
mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
|
||||
and ax, ~RPL_MASK
|
||||
|
||||
/* Get CS */
|
||||
mov cx, word ptr [edx+4]
|
||||
and cx, ~RPL_MASK
|
||||
cmp cx, ax
|
||||
jnz NotCsGpf
|
||||
|
||||
/* This should be a Ki386CallBios return */
|
||||
mov eax, offset _Ki386BiosCallReturnAddress
|
||||
cmp eax, [edx]
|
||||
jne NotBiosGpf
|
||||
mov eax, [edx+4]
|
||||
cmp ax, KGDT_R0_CODE + RPL_MASK
|
||||
jne NotBiosGpf
|
||||
|
||||
/* Jump to return address */
|
||||
jmp _Ki386BiosCallReturnAddress
|
||||
|
||||
NotBiosGpf:
|
||||
/* Check if the thread was in kernel mode */
|
||||
mov ebx, [fs:KPCR_CURRENT_THREAD]
|
||||
test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
|
||||
jz UserModeGpf
|
||||
|
||||
/* Set RPL_MASK for check below */
|
||||
or word ptr [edx+4], RPL_MASK
|
||||
|
||||
NotCsGpf:
|
||||
/* Check if the IRET goes to user-mode */
|
||||
test dword ptr [edx+4], RPL_MASK
|
||||
jz UserModeGpf
|
||||
|
||||
/* FIXME: Handle IRET back to user-mode */
|
||||
int 3
|
||||
jmp $
|
||||
|
||||
NotIretGpf:
|
||||
|
||||
/* FIXME: Handle RDMSR/WRMSR and lazy load */
|
||||
int 3
|
||||
jmp $
|
||||
|
||||
SegPopGpf:
|
||||
|
||||
/* Handle segment POP fault */
|
||||
int 3
|
||||
jmp $
|
||||
|
||||
UserModeGpf:
|
||||
|
||||
/* FIXME: Unhandled */
|
||||
int 3
|
||||
jmp $
|
||||
.endfunc
|
||||
|
||||
.func KiTrap14
|
||||
|
|
|
@ -1,762 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ke/i386/v86m.c
|
||||
* PURPOSE: Support for v86 mode
|
||||
*
|
||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
#define IOPL_FLAG ((1 << 12) | (1 << 13))
|
||||
#define INTERRUPT_FLAG (1 << 9)
|
||||
#define TRAP_FLAG (1 << 8)
|
||||
#define DIRECTION_FLAG (1 << 10)
|
||||
|
||||
#define VALID_FLAGS (0xDFF)
|
||||
|
||||
#define TRAMPOLINE_BASE (0x10000)
|
||||
|
||||
VOID Ki386RetToV86Mode(KV86M_REGISTERS* InRegs,
|
||||
KV86M_REGISTERS* OutRegs);
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
ULONG
|
||||
KeV86GPF(PKV86M_TRAP_FRAME VTf, PKTRAP_FRAME Tf)
|
||||
{
|
||||
PUCHAR ip;
|
||||
PUSHORT sp;
|
||||
PULONG dsp;
|
||||
BOOL BigDataPrefix = FALSE;
|
||||
BOOL BigAddressPrefix = FALSE;
|
||||
BOOL RepPrefix = FALSE;
|
||||
ULONG i = 0;
|
||||
BOOL Exit = FALSE;
|
||||
|
||||
ip = (PUCHAR)((Tf->SegCs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
|
||||
sp = (PUSHORT)((Tf->HardwareSegSs & 0xFFFF) * 16 + (Tf->HardwareEsp & 0xFFFF));
|
||||
dsp = (PULONG)sp;
|
||||
|
||||
DPRINT("KeV86GPF handling %x at %x:%x ss:sp %x:%x Flags %x\n",
|
||||
ip[0], Tf->SegCs, Tf->Eip, Tf->Ss, Tf->HardwareEsp, VTf->regs->Flags);
|
||||
|
||||
while (!Exit)
|
||||
{
|
||||
//DPRINT1("ip: %lx\n", ip[i]);
|
||||
switch (ip[i])
|
||||
{
|
||||
/* 32-bit data prefix */
|
||||
case 0x66:
|
||||
BigDataPrefix = TRUE;
|
||||
i++;
|
||||
Tf->Eip++;
|
||||
break;
|
||||
|
||||
/* 32-bit address prefix */
|
||||
case 0x67:
|
||||
BigAddressPrefix = TRUE;
|
||||
i++;
|
||||
Tf->Eip++;
|
||||
break;
|
||||
|
||||
/* rep prefix */
|
||||
case 0xFC:
|
||||
RepPrefix = TRUE;
|
||||
i++;
|
||||
Tf->Eip++;
|
||||
break;
|
||||
|
||||
/* sti */
|
||||
case 0xFB:
|
||||
if (BigDataPrefix || BigAddressPrefix || RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
|
||||
{
|
||||
Tf->Eip++;
|
||||
VTf->regs->Vif = 1;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* cli */
|
||||
case 0xFA:
|
||||
if (BigDataPrefix || BigAddressPrefix || RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
|
||||
{
|
||||
Tf->Eip++;
|
||||
VTf->regs->Vif = 0;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* pushf */
|
||||
case 0x9C:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
|
||||
{
|
||||
Tf->Eip++;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Tf->HardwareEsp = Tf->HardwareEsp - 2;
|
||||
sp = sp - 1;
|
||||
sp[0] = (USHORT)(Tf->EFlags & 0xFFFF);
|
||||
if (VTf->regs->Vif == 1)
|
||||
{
|
||||
sp[0] = (USHORT)(sp[0] | INTERRUPT_FLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
sp[0] = (USHORT)(sp[0] & (~INTERRUPT_FLAG));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Tf->HardwareEsp = Tf->HardwareEsp - 4;
|
||||
dsp = dsp - 1;
|
||||
dsp[0] = Tf->EFlags;
|
||||
dsp[0] = dsp[0] & VALID_FLAGS;
|
||||
if (VTf->regs->Vif == 1)
|
||||
{
|
||||
dsp[0] = dsp[0] | INTERRUPT_FLAG;
|
||||
}
|
||||
else
|
||||
{
|
||||
dsp[0] = dsp[0] & (~INTERRUPT_FLAG);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* popf */
|
||||
case 0x9D:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
|
||||
{
|
||||
Tf->Eip++;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Tf->EFlags = Tf->EFlags & (~0xFFFF);
|
||||
Tf->EFlags = Tf->EFlags | (sp[0] & VALID_FLAGS);
|
||||
if (Tf->EFlags & INTERRUPT_FLAG)
|
||||
{
|
||||
VTf->regs->Vif = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
VTf->regs->Vif = 0;
|
||||
}
|
||||
Tf->EFlags = Tf->EFlags | INTERRUPT_FLAG;
|
||||
Tf->HardwareEsp = Tf->HardwareEsp + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Tf->EFlags = Tf->EFlags | (dsp[0] & VALID_FLAGS);
|
||||
if (dsp[0] & INTERRUPT_FLAG)
|
||||
{
|
||||
VTf->regs->Vif = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
VTf->regs->Vif = 0;
|
||||
}
|
||||
Tf->EFlags = Tf->EFlags | INTERRUPT_FLAG;
|
||||
Tf->HardwareEsp = Tf->HardwareEsp + 2;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* iret */
|
||||
case 0xCF:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_EMULATE_CLI_STI)
|
||||
{
|
||||
Tf->Eip = sp[0];
|
||||
Tf->SegCs = sp[1];
|
||||
Tf->EFlags = Tf->EFlags & (~0xFFFF);
|
||||
Tf->EFlags = Tf->EFlags | sp[2];
|
||||
if (Tf->EFlags & INTERRUPT_FLAG)
|
||||
{
|
||||
VTf->regs->Vif = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
VTf->regs->Vif = 0;
|
||||
}
|
||||
Tf->EFlags = Tf->EFlags & (~INTERRUPT_FLAG);
|
||||
Tf->HardwareEsp = Tf->HardwareEsp + 6;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* out imm8, al */
|
||||
case 0xE6:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
DPRINT("outb %d, %x\n", (ULONG)ip[i + 1], Tf->Eax & 0xFF);
|
||||
WRITE_PORT_UCHAR((PUCHAR)(ULONG)ip[i + 1],
|
||||
(UCHAR)(Tf->Eax & 0xFF));
|
||||
Tf->Eip = Tf->Eip + 2;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* out imm8, ax */
|
||||
case 0xE7:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
if (!BigDataPrefix)
|
||||
{
|
||||
DPRINT("outw %d, %x\n", (ULONG)ip[i + 1], Tf->Eax & 0xFFFF);
|
||||
WRITE_PORT_USHORT((PUSHORT)(ULONG)ip[1], (USHORT)(Tf->Eax & 0xFFFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("outl %d, %x\n", (ULONG)ip[i + 1], Tf->Eax);
|
||||
WRITE_PORT_ULONG((PULONG)(ULONG)ip[1], Tf->Eax);
|
||||
}
|
||||
Tf->Eip = Tf->Eip + 2;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* out dx, al */
|
||||
case 0xEE:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
DPRINT("outb %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax & 0xFF);
|
||||
WRITE_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF), (UCHAR)(Tf->Eax & 0xFF));
|
||||
Tf->Eip = Tf->Eip + 1;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* out dx, ax */
|
||||
case 0xEF:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
if (!BigDataPrefix)
|
||||
{
|
||||
DPRINT("outw %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax & 0xFFFF);
|
||||
WRITE_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF),
|
||||
(USHORT)(Tf->Eax & 0xFFFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("outl %d, %x\n", Tf->Edx & 0xFFFF, Tf->Eax);
|
||||
WRITE_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF),
|
||||
Tf->Eax);
|
||||
}
|
||||
Tf->Eip = Tf->Eip + 1;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* in al, imm8 */
|
||||
case 0xE4:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
UCHAR v;
|
||||
|
||||
v = READ_PORT_UCHAR((PUCHAR)(ULONG)ip[1]);
|
||||
DPRINT("inb %d\t%X\n", (ULONG)ip[1], v);
|
||||
Tf->Eax = Tf->Eax & (~0xFF);
|
||||
Tf->Eax = Tf->Eax | v;
|
||||
Tf->Eip = Tf->Eip + 2;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* in ax, imm8 */
|
||||
case 0xE5:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
if (!BigDataPrefix)
|
||||
{
|
||||
USHORT v;
|
||||
v = READ_PORT_USHORT((PUSHORT)(ULONG)ip[1]);
|
||||
DPRINT("inw %d\t%X\n", (ULONG)ip[1], v);
|
||||
Tf->Eax = Tf->Eax & (~0xFFFF);
|
||||
Tf->Eax = Tf->Eax | v;
|
||||
}
|
||||
else
|
||||
{
|
||||
ULONG v;
|
||||
v = READ_PORT_ULONG((PULONG)(ULONG)ip[1]);
|
||||
DPRINT("inl %d\t%X\n", (ULONG)ip[1], v);
|
||||
Tf->Eax = v;
|
||||
}
|
||||
Tf->Eip = Tf->Eip + 2;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* in al, dx */
|
||||
case 0xEC:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
UCHAR v;
|
||||
|
||||
v = READ_PORT_UCHAR((PUCHAR)(Tf->Edx & 0xFFFF));
|
||||
DPRINT("inb %d\t%X\n", Tf->Edx & 0xFFFF, v);
|
||||
Tf->Eax = Tf->Eax & (~0xFF);
|
||||
Tf->Eax = Tf->Eax | v;
|
||||
Tf->Eip = Tf->Eip + 1;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* in ax, dx */
|
||||
case 0xED:
|
||||
if (RepPrefix)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
if (!BigDataPrefix)
|
||||
{
|
||||
USHORT v;
|
||||
|
||||
v = READ_PORT_USHORT((PUSHORT)(Tf->Edx & 0xFFFF));
|
||||
DPRINT("inw %d\t%X\n", Tf->Edx & 0xFFFF, v);
|
||||
Tf->Eax = Tf->Eax & (~0xFFFF);
|
||||
Tf->Eax = Tf->Eax | v;
|
||||
}
|
||||
else
|
||||
{
|
||||
ULONG v;
|
||||
|
||||
v = READ_PORT_ULONG((PULONG)(Tf->Edx & 0xFFFF));
|
||||
DPRINT("inl %d\t%X\n", Tf->Edx & 0xFFFF, v);
|
||||
Tf->Eax = v;
|
||||
}
|
||||
Tf->Eip = Tf->Eip + 1;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* outsb */
|
||||
case 0x6E:
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
ULONG Count;
|
||||
PUCHAR Port;
|
||||
PUCHAR Buffer;
|
||||
ULONG Offset;
|
||||
|
||||
Count = 1;
|
||||
if (RepPrefix)
|
||||
{
|
||||
Count = Tf->Ecx;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Count = Count & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
Port = (PUCHAR)(Tf->Edx & 0xFFFF);
|
||||
Offset = Tf->Edi;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Offset = Offset & 0xFFFF;
|
||||
}
|
||||
Buffer = (PUCHAR)((Tf->SegEs * 16) + Offset);
|
||||
for (; Count > 0; Count--)
|
||||
{
|
||||
WRITE_PORT_UCHAR(Port, *Buffer);
|
||||
if (Tf->EFlags & DIRECTION_FLAG)
|
||||
{
|
||||
Buffer++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer--;
|
||||
}
|
||||
}
|
||||
Tf->Eip++;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* insw/insd */
|
||||
case 0x6F:
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
ULONG Count;
|
||||
PUCHAR Port;
|
||||
PUSHORT BufferS = NULL;
|
||||
PULONG BufferL = NULL;
|
||||
ULONG Offset;
|
||||
|
||||
Count = 1;
|
||||
if (RepPrefix)
|
||||
{
|
||||
Count = Tf->Ecx;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Count = Count & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
Port = (PUCHAR)(Tf->Edx & 0xFFFF);
|
||||
Offset = Tf->Edi;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Offset = Offset & 0xFFFF;
|
||||
}
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
BufferL = (PULONG)((Tf->SegEs * 16) + Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferS = (PUSHORT)((Tf->SegEs * 16) + Offset);
|
||||
}
|
||||
for (; Count > 0; Count--)
|
||||
{
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
WRITE_PORT_ULONG((PULONG)Port, *BufferL);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE_PORT_USHORT((PUSHORT)Port, *BufferS);
|
||||
}
|
||||
if (Tf->EFlags & DIRECTION_FLAG)
|
||||
{
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
BufferL++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferS++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
BufferL--;
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferS--;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tf->Eip++;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* insb */
|
||||
case 0x6C:
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
ULONG Count;
|
||||
PUCHAR Port;
|
||||
PUCHAR Buffer;
|
||||
ULONG Offset;
|
||||
|
||||
Count = 1;
|
||||
if (RepPrefix)
|
||||
{
|
||||
Count = Tf->Ecx;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Count = Count & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
Port = (PUCHAR)(Tf->Edx & 0xFFFF);
|
||||
Offset = Tf->Edi;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Offset = Offset & 0xFFFF;
|
||||
}
|
||||
Buffer = (PUCHAR)((Tf->SegEs * 16) + Offset);
|
||||
for (; Count > 0; Count--)
|
||||
{
|
||||
*Buffer = READ_PORT_UCHAR(Port);
|
||||
if (Tf->EFlags & DIRECTION_FLAG)
|
||||
{
|
||||
Buffer++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer--;
|
||||
}
|
||||
}
|
||||
Tf->Eip++;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* insw/insd */
|
||||
case 0x6D:
|
||||
if (VTf->regs->Flags & KV86M_ALLOW_IO_PORT_ACCESS)
|
||||
{
|
||||
ULONG Count;
|
||||
PUCHAR Port;
|
||||
PUSHORT BufferS = NULL;
|
||||
PULONG BufferL = NULL;
|
||||
ULONG Offset;
|
||||
|
||||
Count = 1;
|
||||
if (RepPrefix)
|
||||
{
|
||||
Count = Tf->Ecx;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Count = Count & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
Port = (PUCHAR)(Tf->Edx & 0xFFFF);
|
||||
Offset = Tf->Edi;
|
||||
if (!BigAddressPrefix)
|
||||
{
|
||||
Offset = Offset & 0xFFFF;
|
||||
}
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
BufferL = (PULONG)((Tf->SegEs * 16) + Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferS = (PUSHORT)((Tf->SegEs * 16) + Offset);
|
||||
}
|
||||
for (; Count > 0; Count--)
|
||||
{
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
*BufferL = READ_PORT_ULONG((PULONG)Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
*BufferS = READ_PORT_USHORT((PUSHORT)Port);
|
||||
}
|
||||
if (Tf->EFlags & DIRECTION_FLAG)
|
||||
{
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
BufferL++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferS++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BigDataPrefix)
|
||||
{
|
||||
BufferL--;
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferS--;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tf->Eip++;
|
||||
return(0);
|
||||
}
|
||||
Exit = TRUE;
|
||||
break;
|
||||
|
||||
/* Int nn */
|
||||
case 0xCD:
|
||||
{
|
||||
unsigned int inum;
|
||||
unsigned int entry;
|
||||
|
||||
inum = ip[1];
|
||||
entry = ((unsigned int *)0)[inum];
|
||||
|
||||
Tf->HardwareEsp = Tf->HardwareEsp - 6;
|
||||
sp = sp - 3;
|
||||
|
||||
sp[0] = (USHORT)((Tf->Eip & 0xFFFF) + 2);
|
||||
sp[1] = (USHORT)(Tf->SegCs & 0xFFFF);
|
||||
sp[2] = (USHORT)(Tf->EFlags & 0xFFFF);
|
||||
if (VTf->regs->Vif == 1)
|
||||
{
|
||||
sp[2] = (USHORT)(sp[2] | INTERRUPT_FLAG);
|
||||
}
|
||||
DPRINT("sp[0] %x sp[1] %x sp[2] %x\n", sp[0], sp[1], sp[2]);
|
||||
Tf->Eip = entry & 0xFFFF;
|
||||
Tf->SegCs = entry >> 16;
|
||||
Tf->EFlags = Tf->EFlags & (~TRAP_FLAG);
|
||||
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: Also emulate ins and outs */
|
||||
/* FIXME: Handle opcode prefixes */
|
||||
/* FIXME: Don't allow the BIOS to write to sensitive I/O ports */
|
||||
}
|
||||
|
||||
DPRINT1("V86GPF unhandled (was %x)\n", ip[i]);
|
||||
*VTf->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
return(1);
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
KeV86Exception(ULONG ExceptionNr, PKTRAP_FRAME Tf, ULONG address)
|
||||
{
|
||||
PUCHAR Ip;
|
||||
PKV86M_TRAP_FRAME VTf;
|
||||
|
||||
VTf = (PKV86M_TRAP_FRAME)Tf;
|
||||
|
||||
/*
|
||||
* Check if we have reached the recovery instruction
|
||||
*/
|
||||
Ip = (PUCHAR)((Tf->SegCs & 0xFFFF) * 16 + (Tf->Eip & 0xFFFF));
|
||||
|
||||
if (ExceptionNr == 6 &&
|
||||
memcmp(Ip, VTf->regs->RecoveryInstruction, 4) == 0 &&
|
||||
(Tf->SegCs * 16 + Tf->Eip) == VTf->regs->RecoveryAddress)
|
||||
{
|
||||
*VTf->regs->PStatus = STATUS_SUCCESS;
|
||||
return(1);
|
||||
}
|
||||
|
||||
ASSERT(ExceptionNr == 13);
|
||||
return(KeV86GPF(VTf, Tf));
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
Ke386CallBios(ULONG Int, PCONTEXT regs)
|
||||
{
|
||||
PUCHAR Ip;
|
||||
KV86M_REGISTERS ORegs;
|
||||
NTSTATUS Status;
|
||||
PKV86M_REGISTERS Regs = (PKV86M_REGISTERS)regs;
|
||||
|
||||
/*
|
||||
* Set up a trampoline for executing the BIOS interrupt
|
||||
*/
|
||||
Ip = (PUCHAR)TRAMPOLINE_BASE;
|
||||
Ip[0] = 0xCD; /* int XX */
|
||||
Ip[1] = Int;
|
||||
Ip[2] = 0x63; /* arpl ax, ax */
|
||||
Ip[3] = 0xC0;
|
||||
Ip[4] = 0x90; /* nop */
|
||||
Ip[5] = 0x90; /* nop */
|
||||
|
||||
/*
|
||||
* Munge the registers
|
||||
*/
|
||||
Regs->Eip = 0;
|
||||
Regs->Cs = TRAMPOLINE_BASE / 16;
|
||||
Regs->Esp = 0xFFFF;
|
||||
Regs->Ss = TRAMPOLINE_BASE / 16;
|
||||
Regs->Eflags = (1 << 1) | (1 << 17) | (1 << 9); /* VM, IF */
|
||||
Regs->RecoveryAddress = TRAMPOLINE_BASE + 2;
|
||||
Regs->RecoveryInstruction[0] = 0x63; /* arpl ax, ax */
|
||||
Regs->RecoveryInstruction[1] = 0xC0;
|
||||
Regs->RecoveryInstruction[2] = 0x90; /* nop */
|
||||
Regs->RecoveryInstruction[3] = 0x90; /* nop */
|
||||
Regs->Flags = KV86M_EMULATE_CLI_STI | KV86M_ALLOW_IO_PORT_ACCESS;
|
||||
Regs->Vif = 1;
|
||||
Regs->PStatus = &Status;
|
||||
|
||||
/*
|
||||
* Execute the BIOS interrupt
|
||||
*/
|
||||
Ki386RetToV86Mode(Regs, &ORegs);
|
||||
|
||||
/*
|
||||
* Copy the return values back to the caller
|
||||
*/
|
||||
memcpy(Regs, &ORegs, sizeof(KV86M_REGISTERS));
|
||||
|
||||
return(Status);
|
||||
}
|
||||
|
|
@ -1,175 +1,844 @@
|
|||
/*
|
||||
* FILE: ntoskrnl/ke/i386/vm86_sup.S
|
||||
* PURPOSE: V86 mode support
|
||||
* PROGRAMMER: David Welch (welch@cwcom.net)
|
||||
* UPDATE HISTORY:
|
||||
* Created 09/10/00
|
||||
* FILE: ntoskrnl/ke/i386/v86m_sup.S
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PURPOSE: Virtual 8086 (V86) Mode Support
|
||||
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
||||
* NOTE: See asmmacro.S for the V86 trap code.
|
||||
*/
|
||||
|
||||
#include <ndk/asm.h>
|
||||
|
||||
.globl _Ki386RetToV86Mode
|
||||
.globl _KiV86Complete
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
/*
|
||||
* VOID Ki386RetToV86Mode(KV86M_REGISTERS* InRegs,
|
||||
* KV86M_REGISTERS* OutRegs);
|
||||
*
|
||||
* Starts in v86 mode with the registers set to the
|
||||
* specified values.
|
||||
*/
|
||||
_Ki386RetToV86Mode:
|
||||
/*
|
||||
* Setup a stack frame
|
||||
*/
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
#include <asm.h>
|
||||
#include <internal/i386/asmmacro.S>
|
||||
.intel_syntax noprefix
|
||||
|
||||
/*
|
||||
* Save registers
|
||||
*/
|
||||
pusha
|
||||
/* FIXME: Can we make a nice macro to generate V86 Opcode handlers? */
|
||||
|
||||
/*
|
||||
* Get a pointer to IN_REGS
|
||||
*/
|
||||
movl 8(%ebp), %ebx
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
/*
|
||||
* Save ebp
|
||||
*/
|
||||
pushl %ebp
|
||||
//
|
||||
// This table contains indexes into the OpcodeDispatchV86 Table for opcodes in
|
||||
// Virtual-8086 Mode.
|
||||
// There are 256 entries.
|
||||
//
|
||||
OpcodeIndex:
|
||||
INVALID_V86_OPCODE 15 /* OP 00-14: UNHANDLED */
|
||||
.byte 1 /* OP 0F: 0F */
|
||||
INVALID_V86_OPCODE 22 /* OP 10-25: UNHANDLED */
|
||||
.byte 2 /* OP 26: ES Prefix */
|
||||
INVALID_V86_OPCODE 7 /* OP 27-2D: UNHANDLED */
|
||||
.byte 3 /* OP 2E: CS Prefix */
|
||||
INVALID_V86_OPCODE 7 /* OP 2F-35: UNHANDLED */
|
||||
.byte 4 /* OP 36: SS Prefix */
|
||||
INVALID_V86_OPCODE 7 /* OP 37-3D: UNHANDLED */
|
||||
.byte 5 /* OP 3E: DS Prefix */
|
||||
INVALID_V86_OPCODE 37 /* OP 3F-63: UNHANDLED */
|
||||
.byte 6 /* OP 64: FS Prefix */
|
||||
.byte 7 /* OP 65: GS Prefix */
|
||||
.byte 8 /* OP 66: OPER32 Prefix */
|
||||
.byte 9 /* OP 67: ADDR32 Prefix */
|
||||
INVALID_V86_OPCODE 4 /* OP 68-6B: UNHANDLED */
|
||||
.byte 10 /* OP 6C: INSB */
|
||||
.byte 11 /* OP 6D: INSW */
|
||||
.byte 12 /* OP 6E: OUTSB */
|
||||
.byte 13 /* OP 6F: OUTSW */
|
||||
INVALID_V86_OPCODE 43 /* OP 70-9A: UNHANDLED */
|
||||
.byte 19 /* OP 9B: NPX */
|
||||
.byte 14 /* OP 9C: PUSHF */
|
||||
.byte 15 /* OP 9D: POPF */
|
||||
INVALID_V86_OPCODE 47 /* OP 9E-CC: UNHANDLED */
|
||||
.byte 16 /* OP CD: INTnn */
|
||||
.byte 17 /* OP CE: INTO */
|
||||
.byte 18 /* OP CF: IRETD */
|
||||
INVALID_V86_OPCODE 8 /* OP D0-D7: UNHANDLED */
|
||||
.byte 19 /* OP D8: NPX */
|
||||
.byte 19 /* OP D9: NPX */
|
||||
.byte 19 /* OP DA: NPX */
|
||||
.byte 19 /* OP DB: NPX */
|
||||
.byte 19 /* OP DC: NPX */
|
||||
.byte 19 /* OP DD: NPX */
|
||||
.byte 19 /* OP DE: NPX */
|
||||
.byte 19 /* OP DF: NPX */
|
||||
INVALID_V86_OPCODE 4 /* OP DE-E3: UNHANDLED */
|
||||
.byte 20 /* OP E4: INBimm */
|
||||
.byte 21 /* OP E5: INWimm */
|
||||
.byte 22 /* OP E6: OUTBimm */
|
||||
.byte 23 /* OP E7: OUTWimm */
|
||||
INVALID_V86_OPCODE 4 /* OP E8-EB: UNHANDLED */
|
||||
.byte 24 /* OP EC: INB */
|
||||
.byte 25 /* OP EF: INW */
|
||||
.byte 26 /* OP EE: OUTB */
|
||||
.byte 27 /* OP EF: OUTW */
|
||||
.byte 28 /* OP F0: LOCK Prefix */
|
||||
.byte 0 /* OP F1: UNHANDLED */
|
||||
.byte 29 /* OP F2: REPNE Prefix */
|
||||
.byte 30 /* OP F3: REP Prefix */
|
||||
.byte 33 /* OP F4: HLT */
|
||||
INVALID_V86_OPCODE 5 /* OP F5-F9: UNHANDLED */
|
||||
.byte 31 /* OP FA: CLI */
|
||||
.byte 32 /* OP FB: STI */
|
||||
INVALID_V86_OPCODE 4 /* OP FC-FF: UNHANDLED */
|
||||
|
||||
/*
|
||||
* Save a pointer to IN_REGS which the v86m exception handler will
|
||||
* use to handle exceptions
|
||||
*/
|
||||
pushl %ebx
|
||||
//
|
||||
// This table contains the emulation routines for
|
||||
// Virtual-8086 Mode. There are 34 entries.
|
||||
//
|
||||
OpcodeDispatchV86:
|
||||
.long _OpcodeInvalidV86
|
||||
.long _Opcode0FV86
|
||||
.long _OpcodeESPrefixV86
|
||||
.long _OpcodeCSPrefixV86
|
||||
.long _OpcodeSSPrefixV86
|
||||
.long _OpcodeDSPrefixV86
|
||||
.long _OpcodeFSPrefixV86
|
||||
.long _OpcodeGSPrefixV86
|
||||
.long _OpcodeOPER32PrefixV86
|
||||
.long _OpcodeADDR32PrefixV86
|
||||
.long _OpcodeINSBV86
|
||||
.long _OpcodeINSWV86
|
||||
.long _OpcodeOUTSBV86
|
||||
.long _OpcodeOUTSWV86
|
||||
.long _OpcodePUSHFV86
|
||||
.long _OpcodePOPFV86
|
||||
.long _OpcodeINTnnV86
|
||||
.long _OpcodeINTOV86
|
||||
.long _OpcodeIRETV86
|
||||
.long _OpcodeNPXV86
|
||||
.long _OpcodeINBimmV86
|
||||
.long _OpcodeINWimmV86
|
||||
.long _OpcodeOUTBimmV86
|
||||
.long _OpcodeOUTWimmV86
|
||||
.long _OpcodeINBV86
|
||||
.long _OpcodeINWV86
|
||||
.long _OpcodeOUTBV86
|
||||
.long _OpcodeOUTWV86
|
||||
.long _OpcodeLOCKPrefixV86
|
||||
.long _OpcodeREPNEPrefixV86
|
||||
.long _OpcodeREPPrefixV86
|
||||
.long _OpcodeCLIV86
|
||||
.long _OpcodeSTIV86
|
||||
.long _OpcodeHLTV86
|
||||
|
||||
/*
|
||||
* Since we are going to fiddle with the stack pointer this must be
|
||||
* a critical section for this processor
|
||||
*/
|
||||
cli
|
||||
|
||||
/*
|
||||
* Save the exception handler stack from the TSS
|
||||
*/
|
||||
movl %fs:KPCR_TSS, %esi
|
||||
pushl KTSS_ESP0(%esi)
|
||||
_ExVdmOpcodeDispatchCounts:
|
||||
.rept 34
|
||||
.long 0
|
||||
.endr
|
||||
|
||||
/*
|
||||
* The stack used for handling exceptions from v86 mode in this thread
|
||||
* will be the current stack adjusted so we don't overwrite the
|
||||
* existing stack frames
|
||||
*/
|
||||
movl %esp, KTSS_ESP0(%esi)
|
||||
V86DebugMsg:
|
||||
.asciz "Received V86 Emulation Opcode: %lx\n"
|
||||
|
||||
/*
|
||||
* Create the stack frame for an iret to v86 mode
|
||||
*/
|
||||
pushl KV86M_REGISTERS_GS(%ebx)
|
||||
pushl KV86M_REGISTERS_FS(%ebx)
|
||||
pushl KV86M_REGISTERS_DS(%ebx)
|
||||
pushl KV86M_REGISTERS_ES(%ebx)
|
||||
pushl KV86M_REGISTERS_SS(%ebx)
|
||||
pushl KV86M_REGISTERS_ESP(%ebx)
|
||||
pushl KV86M_REGISTERS_EFLAGS(%ebx)
|
||||
pushl KV86M_REGISTERS_CS(%ebx)
|
||||
pushl KV86M_REGISTERS_EIP(%ebx)
|
||||
/* VIRTUAL-8086 MODE OPCODER HANDLERS ****************************************/
|
||||
|
||||
/*
|
||||
* Setup the CPU registers
|
||||
*/
|
||||
movl KV86M_REGISTERS_EAX(%ebx), %eax
|
||||
movl KV86M_REGISTERS_ECX(%ebx), %ecx
|
||||
movl KV86M_REGISTERS_EDX(%ebx), %edx
|
||||
movl KV86M_REGISTERS_ESI(%ebx), %esi
|
||||
movl KV86M_REGISTERS_EDI(%ebx), %edi
|
||||
movl KV86M_REGISTERS_EBP(%ebx), %ebp
|
||||
movl KV86M_REGISTERS_EBX(%ebx), %ebx
|
||||
.func OpcodeInvalidV86
|
||||
_OpcodeInvalidV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/*
|
||||
* Go to v86 mode
|
||||
*/
|
||||
iret
|
||||
.func Opcode0FV86
|
||||
_Opcode0FV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/*
|
||||
* Handle the completion of a vm86 routine. We are called from
|
||||
* an exception handler with the registers at the point of the
|
||||
* exception on the stack.
|
||||
*/
|
||||
_KiV86Complete:
|
||||
/* Restore the original ebp */
|
||||
movl TF_ORIG_EBP(%esp), %ebp
|
||||
.func OpcodeESPrefixV86
|
||||
_OpcodeESPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Get a pointer to the OUT_REGS structure */
|
||||
movl 12(%ebp), %ebx
|
||||
.func OpcodeCSPrefixV86
|
||||
_OpcodeCSPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Skip debug information and unsaved registers */
|
||||
addl $0x30, %esp
|
||||
.func OpcodeSSPrefixV86
|
||||
_OpcodeSSPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Ignore 32-bit segment registers */
|
||||
addl $12, %esp
|
||||
.func OpcodeDSPrefixV86
|
||||
_OpcodeDSPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Save the vm86 registers into the OUT_REGS structure */
|
||||
popl KV86M_REGISTERS_EDX(%ebx)
|
||||
popl KV86M_REGISTERS_ECX(%ebx)
|
||||
popl KV86M_REGISTERS_EAX(%ebx)
|
||||
.func OpcodeFSPrefixV86
|
||||
_OpcodeFSPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Restore the old previous mode */
|
||||
popl %eax
|
||||
movb %al, %ss:KTHREAD_PREVIOUS_MODE(%esi)
|
||||
.func OpcodeGSPrefixV86
|
||||
_OpcodeGSPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Restore the old exception handler list */
|
||||
popl %eax
|
||||
movl %eax, %fs:KPCR_EXCEPTION_LIST
|
||||
|
||||
/* Ignore the 32-bit fs register */
|
||||
addl $4, %esp
|
||||
.func OpcodeOPER32PrefixV86
|
||||
_OpcodeOPER32PrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
popl KV86M_REGISTERS_EDI(%ebx)
|
||||
popl KV86M_REGISTERS_ESI(%ebx)
|
||||
popl KV86M_REGISTERS_EBX(%ebx)
|
||||
popl KV86M_REGISTERS_EBP(%ebx)
|
||||
.func OpcodeADDR32PrefixV86
|
||||
_OpcodeADDR32PrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Ignore error code */
|
||||
addl $4, %esp
|
||||
.func OpcodeINSBV86
|
||||
_OpcodeINSBV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
popl KV86M_REGISTERS_EIP(%ebx)
|
||||
popl KV86M_REGISTERS_CS(%ebx)
|
||||
popl KV86M_REGISTERS_EFLAGS(%ebx)
|
||||
popl KV86M_REGISTERS_ESP(%ebx)
|
||||
popl KV86M_REGISTERS_SS(%ebx)
|
||||
popl KV86M_REGISTERS_ES(%ebx)
|
||||
popl KV86M_REGISTERS_DS(%ebx)
|
||||
popl KV86M_REGISTERS_FS(%ebx)
|
||||
popl KV86M_REGISTERS_GS(%ebx)
|
||||
.func OpcodeINSWV86
|
||||
_OpcodeINSWV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/*
|
||||
* We are going to fiddle with the stack so this must be a critical
|
||||
* section for this process
|
||||
*/
|
||||
cli
|
||||
.func OpcodeOUTSBV86
|
||||
_OpcodeOUTSBV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/*
|
||||
* Restore the exception handler stack in the TSS
|
||||
*/
|
||||
movl %fs:KPCR_TSS, %esi
|
||||
popl KTSS_ESP0(%esi)
|
||||
.func OpcodeOUTSWV86
|
||||
_OpcodeOUTSWV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* Exit the critical section */
|
||||
sti
|
||||
.func OpcodePUSHFV86
|
||||
_OpcodePUSHFV86:
|
||||
|
||||
/* Ignore IN_REGS pointer */
|
||||
addl $4, %esp
|
||||
/* Get VDM state */
|
||||
mov eax, 0x714
|
||||
mov eax, [eax]
|
||||
|
||||
/* Ignore ebp restored above */
|
||||
addl $4, %esp
|
||||
/* Get EFLAGS and mask out IF */
|
||||
mov edx, [ebp+KTRAP_FRAME_EFLAGS]
|
||||
and eax, ~EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Return to caller */
|
||||
popa
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret
|
||||
/* Mask align check and interrupt mask */
|
||||
and eax, EFLAGS_ALIGN_CHECK + 0x4000 + EFLAGS_INTERRUPT_MASK
|
||||
or eax, edx
|
||||
|
||||
/* Add IOPL Mask */
|
||||
or eax, 0x3000
|
||||
|
||||
/* Get flat ESP */
|
||||
movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
|
||||
shl ecx, 4
|
||||
movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
|
||||
sub dx, 2
|
||||
|
||||
/* Check if there is an OPER32 prefix */
|
||||
test ebx, 0x4000
|
||||
jnz SkipPrefix
|
||||
|
||||
/* Push EFLAGS */
|
||||
mov [ecx+edx], ax
|
||||
|
||||
UpdateFrame:
|
||||
|
||||
/* Update ESP and EIP */
|
||||
mov [ebp+KTRAP_FRAME_ESP], dx
|
||||
add [ebp+KTRAP_FRAME_EIP], edi
|
||||
|
||||
/* Return success */
|
||||
mov eax, 1
|
||||
ret
|
||||
|
||||
SkipPrefix:
|
||||
|
||||
/* Skip the prefix, push EFLAGS and jump back */
|
||||
sub dx, 2
|
||||
mov [edx+ecx], eax
|
||||
jmp UpdateFrame
|
||||
.endfunc
|
||||
|
||||
.func OpcodePOPFV86
|
||||
_OpcodePOPFV86:
|
||||
|
||||
/* Get VDM state */
|
||||
mov eax, 0x714
|
||||
|
||||
/* Get flat ESP */
|
||||
mov ecx, [ebp+KTRAP_FRAME_SS]
|
||||
shl ecx, 4
|
||||
movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
|
||||
|
||||
/* Pop EFLAGS */
|
||||
mov ecx, [ecx+edx]
|
||||
add edx, 4
|
||||
|
||||
/* Check for OPER32 prefix */
|
||||
test ebx, 0x4000
|
||||
jnz NoPrefix
|
||||
|
||||
/* Skip 2 bytes */
|
||||
and ecx, 0xFFFF
|
||||
sub edx, 2
|
||||
|
||||
NoPrefix:
|
||||
|
||||
/* Set new ESP */
|
||||
mov [ebp+KTRAP_FRAME_ESP], edx
|
||||
|
||||
/* Mask out EFLAGS */
|
||||
and eax, ~0x3000
|
||||
mov ebx, ebx
|
||||
and ebx, ~0x4000
|
||||
and ecx, EFLAGS_ALIGN_CHECK + 0x4000 + EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* FIXME: Support VME */
|
||||
|
||||
/* Save VDM State pointer */
|
||||
push eax
|
||||
|
||||
/* Set new EFLAGS, make sure to add IF and V86 */
|
||||
or ebx, EFLAGS_INTERRUPT_MASK + EFLAGS_V86_MASK
|
||||
push [ebp+KTRAP_FRAME_EFLAGS]
|
||||
mov [ebp+KTRAP_FRAME_EFLAGS], ebx
|
||||
|
||||
/* Make sure we were in V86 mode */
|
||||
test ebx, EFLAGS_V86_MASK
|
||||
jnz CheckEspAdjust
|
||||
int 3
|
||||
|
||||
CheckEspAdjust:
|
||||
|
||||
/* Check if we have to update ESP0 and fixup the stack from our push */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
lea esp, [esp+4]
|
||||
jnz NoAdjustEsp0
|
||||
|
||||
/* Adjust it */
|
||||
push ebp
|
||||
call _Ki386AdjustEsp0@4
|
||||
|
||||
NoAdjustEsp0:
|
||||
|
||||
/* Restore VDM state */
|
||||
pop eax
|
||||
|
||||
/* Update the flags in the VDM State */
|
||||
LOCK and dword ptr [eax], ~(EFLAGS_ALIGN_CHECK + 0x4000 + EFLAGS_INTERRUPT_MASK)
|
||||
LOCK or [eax], ecx
|
||||
|
||||
/* Update EIP */
|
||||
add [ebp+KTRAP_FRAME_EIP], edi
|
||||
|
||||
/* FIXME: Check for VDM Pending interrupts */
|
||||
|
||||
/* Return success */
|
||||
mov eax, 1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.func OpcodeINTnnV86
|
||||
_OpcodeINTnnV86:
|
||||
|
||||
/* Get EFlags */
|
||||
mov edx, [ebp+KTRAP_FRAME_EFLAGS]
|
||||
|
||||
/* Remove the flag in the VDM State */
|
||||
mov eax, 0x714
|
||||
mov ecx, [eax]
|
||||
LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Mask it out from EFLAGS too */
|
||||
mov eax, edx
|
||||
and eax, ~EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Mask out the alignment check and IF flag from the VDM state */
|
||||
and ecx, EFLAGS_ALIGN_CHECK + EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* FIXME: Support VME */
|
||||
|
||||
/* Now mask out VIF and TF */
|
||||
or eax, ecx
|
||||
and edx, ~(EFLAGS_VIF + 0x4000 + EFLAGS_TF)
|
||||
mov [ebp+KTRAP_FRAME_EFLAGS], edx
|
||||
|
||||
/* Set the IOPL Mask */
|
||||
or eax, 0x3000
|
||||
|
||||
/* Get stack flat address */
|
||||
movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
|
||||
shl ecx, 4
|
||||
movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
|
||||
|
||||
/* Push EFLAGS */
|
||||
sub dx, 2
|
||||
mov word ptr [ecx+edx], ax
|
||||
|
||||
/* Push CS */
|
||||
mov ax, word ptr [ebp+KTRAP_FRAME_CS]
|
||||
sub dx, 2
|
||||
mov word ptr [ecx+edx], ax
|
||||
|
||||
/* Push IP */
|
||||
movzx eax, word ptr [ebp+KTRAP_FRAME_EIP]
|
||||
add eax, edi
|
||||
inc eax
|
||||
sub dx, 2
|
||||
mov word ptr [ecx+edx], ax
|
||||
|
||||
/* Update ESP */
|
||||
mov [ebp+KTRAP_FRAME_ESP], dx
|
||||
|
||||
/* Get the interrupt */
|
||||
inc esi
|
||||
movzx ecx, byte ptr [esi]
|
||||
/* FIXME: Analyze and see if this is a hooked VDM (PM) Interrupt */
|
||||
|
||||
/* Get the entry in the IVT */
|
||||
mov ebx, [ecx*4]
|
||||
mov eax, ebx
|
||||
shr eax, 16
|
||||
|
||||
/* Update EIP */
|
||||
mov word ptr [ebp+KTRAP_FRAME_EIP], bx
|
||||
|
||||
/* Check if this was V86 mode */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jnz SetCs
|
||||
|
||||
/* Check if it was a kernel CS */
|
||||
or ax, RPL_MASK
|
||||
cmp ax, KGDT_R0_CODE
|
||||
jnb SetCs
|
||||
|
||||
/* Set user-mode CS */
|
||||
mov ax, KGDT_R3_CODE + RPL_MASK
|
||||
|
||||
SetCs:
|
||||
/* Set new CS */
|
||||
mov [ebp+KTRAP_FRAME_CS], ax
|
||||
|
||||
/* Return success */
|
||||
mov eax, 1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.func OpcodeINTOV86
|
||||
_OpcodeINTOV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeIRETV86
|
||||
_OpcodeIRETV86:
|
||||
|
||||
/* Get the VDM State */
|
||||
mov eax, 0x714
|
||||
|
||||
/* Get flat ESP */
|
||||
movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
|
||||
shl ecx, 4
|
||||
movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
|
||||
add ecx, edx
|
||||
|
||||
/* Check for OPER32 prefix */
|
||||
test ebx, 0x4000
|
||||
jnz Iret32
|
||||
|
||||
/* Get flat IP */
|
||||
movzx edi, word ptr [ecx]
|
||||
mov [ebp+KTRAP_FRAME_EIP], edi
|
||||
movzx esi, word ptr [ecx+2]
|
||||
mov [ebp+KTRAP_FRAME_CS], esi
|
||||
|
||||
/* Update ESP */
|
||||
add edx, 6
|
||||
mov [ebp+KTRAP_FRAME_ESP], edx
|
||||
|
||||
/* Get EFLAGS */
|
||||
movzx ebx, word ptr [ecx+4]
|
||||
|
||||
MaskEFlags:
|
||||
|
||||
/* Mask out EFLAGS */
|
||||
and ebx, ~(0x3000 + EFLAGS_VIF + 0x4000 + EFLAGS_VIP)
|
||||
mov ecx, ebx
|
||||
|
||||
/* FIXME: Check for VME support */
|
||||
|
||||
/* Save VDM state */
|
||||
push eax
|
||||
|
||||
/* Enable V86 and Interrupts */
|
||||
or ebx, EFLAGS_V86_MASK + EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Save old flags */
|
||||
mov eax, [ebp+KTRAP_FRAME_EFLAGS]
|
||||
push eax
|
||||
|
||||
/* Mask out VIP and set new eflags */
|
||||
and eax, EFLAGS_VIP
|
||||
or eax, ebx
|
||||
mov [ebp+KTRAP_FRAME_EFLAGS], eax
|
||||
|
||||
/* Check if we have to update ESP0 */
|
||||
pop ebx
|
||||
test ebx, EFLAGS_V86_MASK
|
||||
jnz NoEsp0Update
|
||||
|
||||
/* Save ECX and ECX */
|
||||
push ecx
|
||||
push edx
|
||||
|
||||
/* Update esp0 and restore registers */
|
||||
push ebp
|
||||
call _Ki386AdjustEsp0@4
|
||||
pop edx
|
||||
pop ecx
|
||||
|
||||
NoEsp0Update:
|
||||
|
||||
/* Put VDM state in EAX and update VDM EFlags */
|
||||
pop eax
|
||||
and ecx, EFLAGS_INTERRUPT_MASK
|
||||
LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
|
||||
LOCK or [eax], ecx
|
||||
|
||||
/* Get flat EIP and check if this is the BOP */
|
||||
shl esi, 4
|
||||
add esi, edi
|
||||
mov ax, [esi]
|
||||
cmp ax, 0xC4C4
|
||||
jz IsBop
|
||||
|
||||
/* FIXME: Check for VDM interrupts */
|
||||
|
||||
/* Return success */
|
||||
RetIret:
|
||||
mov eax, 1
|
||||
ret
|
||||
|
||||
IsBop:
|
||||
|
||||
/* Call the BOP handler */
|
||||
push ebp
|
||||
call _VdmDispatchBop@4
|
||||
jmp RetIret
|
||||
|
||||
Iret32:
|
||||
|
||||
/* Get 32-bit flat EIP */
|
||||
mov edi, [ecx]
|
||||
mov [ebp+KTRAP_FRAME_EIP], edi
|
||||
movzx esi, word ptr [ecx+4]
|
||||
mov [ebp+KTRAP_FRAME_CS], esi
|
||||
|
||||
/* Set new ESP */
|
||||
add edx, 12
|
||||
mov [ebp+KTRAP_FRAME_ESP], edx
|
||||
|
||||
/* Get EFLAGS and continue */
|
||||
mov ebx, [ecx+8]
|
||||
jmp MaskEFlags
|
||||
.endfunc
|
||||
|
||||
.func OpcodeNPXV86
|
||||
_OpcodeNPXV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeINBimmV86
|
||||
_OpcodeINBimmV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeINWimmV86
|
||||
_OpcodeINWimmV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeOUTBimmV86
|
||||
_OpcodeOUTBimmV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeOUTWimmV86
|
||||
_OpcodeOUTWimmV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeINBV86
|
||||
_OpcodeINBV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeINWV86
|
||||
_OpcodeINWV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeOUTBV86
|
||||
_OpcodeOUTBV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeOUTWV86
|
||||
_OpcodeOUTWV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeLOCKPrefixV86
|
||||
_OpcodeLOCKPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeREPNEPrefixV86
|
||||
_OpcodeREPNEPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeREPPrefixV86
|
||||
_OpcodeREPPrefixV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
.func OpcodeCLIV86
|
||||
_OpcodeCLIV86:
|
||||
|
||||
/* Get VDM State */
|
||||
mov eax, 0x714
|
||||
|
||||
/* FIXME: Support VME */
|
||||
|
||||
/* FIXME: Support VDM Interrupts */
|
||||
|
||||
/* Disable interrupts */
|
||||
LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Update EIP (remember EDI == instruction size) */
|
||||
add [ebp+KTRAP_FRAME_EIP], edi
|
||||
|
||||
/* Return success */
|
||||
mov eax, 1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.func OpcodeSTIV86
|
||||
_OpcodeSTIV86:
|
||||
|
||||
/* Get VDM State */
|
||||
mov eax, 0x714
|
||||
|
||||
/* FIXME: Support VME */
|
||||
|
||||
/* Enable interrupts */
|
||||
LOCK or dword ptr [eax], EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Update EIP (remember EDI == instruction size) */
|
||||
add [ebp+KTRAP_FRAME_EIP], edi
|
||||
|
||||
/* FIXME: Support VDM Interrupts */
|
||||
|
||||
/* Return success */
|
||||
mov eax, 1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.func OpcodeHLTV86
|
||||
_OpcodeHLTV86:
|
||||
UNHANDLED_V86_OPCODE
|
||||
.endfunc
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
.globl _Ki386SetupAndExitToV86Mode@4
|
||||
.func Ki386SetupAndExitToV86Mode@4
|
||||
_Ki386SetupAndExitToV86Mode@4:
|
||||
|
||||
/* Save nonvolatiles */
|
||||
push ebp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
/* Give us a little stack */
|
||||
sub esp, 12
|
||||
mov ecx, esp
|
||||
|
||||
/* Go past the KTRAP_FRAME and NPX Frame and set a new frame in EAX */
|
||||
sub esp, NPX_FRAME_LENGTH
|
||||
and esp, ~15
|
||||
sub esp, KTRAP_FRAME_LENGTH
|
||||
mov eax, esp
|
||||
|
||||
/* Create a fake user-mode frame */
|
||||
mov dword ptr [eax+KTRAP_FRAME_CS], KGDT_R0_CODE + RPL_MASK
|
||||
mov dword ptr [eax+KTRAP_FRAME_ES], 0
|
||||
mov dword ptr [eax+KTRAP_FRAME_DS], 0
|
||||
mov dword ptr [eax+KTRAP_FRAME_FS], 0
|
||||
mov dword ptr [eax+KTRAP_FRAME_GS], 0
|
||||
mov dword ptr [eax+KTRAP_FRAME_ERROR_CODE], 0
|
||||
|
||||
/* Get the current thread's initial stack */
|
||||
mov ebx, [fs:KPCR_SELF]
|
||||
mov edi, [ebx+KPCR_CURRENT_THREAD]
|
||||
mov edx, [edi+KTHREAD_INITIAL_STACK]
|
||||
sub edx, NPX_FRAME_LENGTH
|
||||
|
||||
/* Save it on our stack, as well as the real TEB addresses */
|
||||
mov [ecx], edx
|
||||
mov edx, [edi+KTHREAD_TEB]
|
||||
mov [ecx+4], edx
|
||||
mov edx, [fs:KPCR_TEB]
|
||||
mov [ecx+8] , edx
|
||||
|
||||
/* Set our ESP in ESI, and the return function in EIP */
|
||||
mov edi, offset _Ki386BiosCallReturnAddress
|
||||
mov [eax+KTRAP_FRAME_ESI], ecx
|
||||
mov [eax+KTRAP_FRAME_EIP], edi
|
||||
|
||||
/* Push the flags and sanitize them */
|
||||
pushfd
|
||||
pop edi
|
||||
and edi, 0x60DD7
|
||||
or edi, EFLAGS_INTERRUPT_MASK
|
||||
|
||||
/* Set SS and ESP, and fill out the rest of the frame */
|
||||
mov dword ptr [eax+KTRAP_FRAME_SS], KGDT_R3_DATA + RPL_MASK;
|
||||
mov dword ptr [eax+KTRAP_FRAME_ESP], 0x11FFE;
|
||||
mov dword ptr [eax+KTRAP_FRAME_EFLAGS], edi
|
||||
mov dword ptr [eax+KTRAP_FRAME_EXCEPTION_LIST], -1
|
||||
mov dword ptr [eax+KTRAP_FRAME_PREVIOUS_MODE], -1
|
||||
mov dword ptr [eax+KTRAP_FRAME_DR7], 0
|
||||
mov dword ptr [eax+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
|
||||
|
||||
/* Jump past the frame now */
|
||||
add eax, KTRAP_FRAME_LENGTH
|
||||
cli
|
||||
|
||||
/* Save the current stack */
|
||||
push ecx
|
||||
|
||||
/* Get the current thread's intial stack again */
|
||||
mov edi, [ebx+KPCR_CURRENT_THREAD]
|
||||
mov esi, [edi+KTHREAD_INITIAL_STACK]
|
||||
sub esi, NPX_FRAME_LENGTH
|
||||
|
||||
/* Set the size of the copy, and the destination, and copy the NPX frame */
|
||||
mov ecx, NPX_FRAME_LENGTH / 4
|
||||
mov edi, eax
|
||||
rep movsd
|
||||
|
||||
/* Restore stack */
|
||||
pop ecx
|
||||
|
||||
/* Get the current thread and TSS */
|
||||
mov edi, [ebx+KPCR_CURRENT_THREAD]
|
||||
mov esi, [ebx+KPCR_TSS]
|
||||
|
||||
/* Bias the V86 vrame */
|
||||
sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
|
||||
|
||||
/* Set exception list and new ESP */
|
||||
mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
|
||||
mov [esi+KTSS_ESP0], eax
|
||||
|
||||
/* Now skip past the NPX frame and V86 fields and set this as the intial stack */
|
||||
add eax, NPX_FRAME_LENGTH + (KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS)
|
||||
mov [edi+KTHREAD_INITIAL_STACK], eax
|
||||
|
||||
/* Setup our fake TEB pointer */
|
||||
mov eax, [ecx+0x20]
|
||||
mov [fs:KPCR_TEB], eax
|
||||
mov [edi+KTHREAD_TEB], eax
|
||||
|
||||
/* Setup the descriptors for the fake TEB */
|
||||
mov ebx, [fs:KPCR_GDT]
|
||||
mov [ebx+0x3A], ax
|
||||
shr eax, 16
|
||||
mov [ebx+0x3C], al
|
||||
mov [ebx+0x3F], ah
|
||||
sti
|
||||
|
||||
/*
|
||||
* Start VDM execution. This will save this fake 32-bit KTRAP_FRAME and
|
||||
* initialize a real 16-bit VDM context frame
|
||||
*/
|
||||
push 0
|
||||
push 0 // VdmStartExecution
|
||||
call _NtVdmControl@8
|
||||
|
||||
/* Exit to V86 mode */
|
||||
mov ebp, esp
|
||||
jmp _Kei386EoiHelper@0
|
||||
.endfunc
|
||||
|
||||
.globl _Ki386BiosCallReturnAddress
|
||||
.func Ki386BiosCallReturnAddress
|
||||
_Ki386BiosCallReturnAddress:
|
||||
|
||||
/* Get the PCR */
|
||||
mov eax, [fs:KPCR_SELF]
|
||||
|
||||
/* Get NPX destination */
|
||||
mov edi, [ebp+KTRAP_FRAME_ESI]
|
||||
mov edi, [edi]
|
||||
|
||||
/* Get initial stack */
|
||||
mov ecx, [eax+KPCR_CURRENT_THREAD]
|
||||
mov esi, [ecx+KTHREAD_INITIAL_STACK]
|
||||
sub esi, NPX_FRAME_LENGTH
|
||||
|
||||
/* Set length and copy the NPX frame */
|
||||
mov ecx, NPX_FRAME_LENGTH / 4
|
||||
rep movsd
|
||||
|
||||
/* Restore stack */
|
||||
mov esp, [ebp+KTRAP_FRAME_ESI]
|
||||
add esp, 4
|
||||
|
||||
/* Set initial stack */
|
||||
mov ecx, [eax+KPCR_CURRENT_THREAD]
|
||||
mov [ecx+KTHREAD_INITIAL_STACK], edi
|
||||
|
||||
/* Get TSS and set the ESP 0 */
|
||||
mov eax, [eax+KPCR_TSS]
|
||||
sub edi, NPX_FRAME_LENGTH + (KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS)
|
||||
mov [eax+KTSS_ESP0], edi
|
||||
|
||||
/* Restore KTHREAD TEB in EDX */
|
||||
pop edx
|
||||
mov [ecx+KTHREAD_TEB], edx
|
||||
|
||||
/* Restore PCR TEB in EDX */
|
||||
pop edx
|
||||
mov [fs:KPCR_TEB], edx
|
||||
|
||||
/* Setup the descriptors for the real TEB */
|
||||
mov ebx, [fs:KPCR_GDT]
|
||||
mov [ebx+0x3A], dx
|
||||
shr edx, 16
|
||||
mov [ebx+0x3C], dl
|
||||
mov [ebx+0x3F], dh
|
||||
|
||||
/* Enable interrupts and pop back non-volatiles */
|
||||
sti
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret 4
|
||||
.endfunc
|
||||
|
||||
.globl _Ki386HandleOpcodeV86@0
|
||||
.func Ki386HandleOpcodeV86@0
|
||||
_Ki386HandleOpcodeV86@0:
|
||||
|
||||
/* Get flat EIP */
|
||||
mov esi, [ebp+KTRAP_FRAME_CS]
|
||||
shl esi, 4
|
||||
add esi, [ebp+KTRAP_FRAME_EIP]
|
||||
|
||||
/* Get the opcode entry in the table */
|
||||
movzx ecx, byte ptr [esi]
|
||||
movzx edx, byte ptr OpcodeIndex[ecx]
|
||||
|
||||
/* Set instruction length and prefix flags */
|
||||
mov edi, 1
|
||||
xor ebx, ebx
|
||||
|
||||
/* Accounting statistics */
|
||||
// inc dword ptr _ExVdmOpcodeDispatchCounts[edx*4] // FIXME: Generates protection fault
|
||||
|
||||
/* Handle the opcode */
|
||||
jmp OpcodeDispatchV86[edx*4]
|
||||
.endfunc
|
||||
|
|
122
reactos/ntoskrnl/ke/i386/v86vdm.c
Normal file
122
reactos/ntoskrnl/ke/i386/v86vdm.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/ke/i386/v86vdm.c
|
||||
* PURPOSE: Manages the Kernel's support for Virtual-8086 Mode (V86)
|
||||
* used by Video Drivers to access ROM BIOS functions, as well
|
||||
* as the kernel architecture part of generic VDM support.
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
|
||||
ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
|
||||
PVOID Ki386IopmSaveArea;
|
||||
BOOLEAN KeI386VirtualIntExtensions = FALSE;
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
Ke386CallBios(IN ULONG Int,
|
||||
OUT PCONTEXT Context)
|
||||
{
|
||||
PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE;
|
||||
PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB;
|
||||
PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB;
|
||||
ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
|
||||
PKTHREAD Thread = KeGetCurrentThread();
|
||||
PKTSS Tss = KeGetPcr()->TSS;
|
||||
PKPROCESS Process = Thread->ApcState.Process;
|
||||
PVDM_PROCESS_OBJECTS VdmProcessObjects;
|
||||
USHORT OldOffset, OldBase;
|
||||
|
||||
/* Start with a clean TEB */
|
||||
RtlZeroMemory(VdmTeb, sizeof(TEB));
|
||||
|
||||
/* Write the interrupt and bop */
|
||||
*Trampoline++ = 0xCD;
|
||||
*Trampoline++ = (UCHAR)Int;
|
||||
*(PULONG)Trampoline = TRAMPOLINE_BOP;
|
||||
|
||||
/* Setup the VDM TEB and TIB */
|
||||
VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB;
|
||||
RtlZeroMemory(VdmTib, sizeof(VDM_TIB));
|
||||
VdmTib->Size = sizeof(VDM_TIB);
|
||||
|
||||
/* Set a blank VDM state */
|
||||
*VdmState = 0;
|
||||
|
||||
/* Copy the context */
|
||||
RtlMoveMemory(&VdmTib->VdmContext, Context, ContextSize);
|
||||
VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4;
|
||||
VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4;
|
||||
VdmTib->VdmContext.Eip = 0;
|
||||
VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR);
|
||||
VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
|
||||
VdmTib->VdmContext.ContextFlags = CONTEXT_FULL;
|
||||
|
||||
/* This can't be a real VDM process */
|
||||
ASSERT(PsGetCurrentProcess()->VdmObjects == NULL);
|
||||
|
||||
/* Allocate VDM structure */
|
||||
VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(VDM_PROCESS_OBJECTS),
|
||||
TAG('K', 'e', ' ', ' '));
|
||||
if (!VdmProcessObjects) return STATUS_NO_MEMORY;
|
||||
|
||||
/* Set it up */
|
||||
RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS));
|
||||
VdmProcessObjects->VdmTib = VdmTib;
|
||||
PsGetCurrentProcess()->VdmObjects = VdmProcessObjects;
|
||||
|
||||
/* Set the system affinity for the current thread */
|
||||
KeSetSystemAffinityThread(1);
|
||||
|
||||
/* Make sure there's space for two IOPMs, then copy & clear the current */
|
||||
//ASSERT(((PKGDTENTRY)&KeGetPcr()->GDT[KGDT_TSS / 8])->LimitLow >= (0x2000 + IOPM_OFFSET - 1));
|
||||
RtlMoveMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
|
||||
RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
|
||||
|
||||
/* Save the old offset and base, and set the new ones */
|
||||
OldOffset = Process->IopmOffset;
|
||||
OldBase = Tss->IoMapBase;
|
||||
Process->IopmOffset = IOPM_OFFSET;
|
||||
Tss->IoMapBase = IOPM_OFFSET;
|
||||
|
||||
/* Switch stacks and work the magic */
|
||||
Ki386SetupAndExitToV86Mode(VdmTeb);
|
||||
|
||||
/* Restore IOPM */
|
||||
RtlMoveMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2);
|
||||
Process->IopmOffset = OldOffset;
|
||||
Tss->IoMapBase = OldBase;
|
||||
|
||||
/* Restore affinity */
|
||||
KeRevertToUserAffinityThread();
|
||||
|
||||
/* Restore context */
|
||||
RtlMoveMemory(Context, &VdmTib->VdmContext, ContextSize);
|
||||
Context->ContextFlags = CONTEXT_FULL;
|
||||
|
||||
/* Free VDM objects */
|
||||
ExFreePool(PsGetCurrentProcess()->VdmObjects);
|
||||
PsGetCurrentProcess()->VdmObjects = NULL;
|
||||
|
||||
/* Return status */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -1,112 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ke/i386/vdm.c
|
||||
* PURPOSE: Virtual DOS machine support
|
||||
*
|
||||
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include <internal/debug.h>
|
||||
|
||||
#if defined (ALLOC_PRAGMA)
|
||||
#pragma alloc_text(INIT, NtEarlyInitVdm)
|
||||
#endif
|
||||
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
static UCHAR OrigIVT[1024];
|
||||
static UCHAR OrigBDA[256];
|
||||
/* static UCHAR OrigEBDA[]; */
|
||||
|
||||
extern VOID Ki386RetToV86Mode(PKV86M_REGISTERS InRegs,
|
||||
PKV86M_REGISTERS OutRegs);
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
NtEarlyInitVdm(VOID)
|
||||
{
|
||||
/* GCC 3.4 warns if NULL is passed in parameter 2 to the standard function memcpy */
|
||||
PVOID start = (PVOID)0x0;
|
||||
|
||||
/*
|
||||
* Save various BIOS data tables. At this point the lower 4MB memory
|
||||
* map is still active so we can just copy the data from low memory.
|
||||
*/
|
||||
memcpy(OrigIVT, start, 1024);
|
||||
memcpy(OrigBDA, (PVOID)0x400, 256);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS STDCALL NtVdmControl(ULONG ControlCode,
|
||||
PVOID ControlData)
|
||||
{
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
|
||||
if (PreviousMode != KernelMode)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
switch (ControlCode)
|
||||
{
|
||||
case 0:
|
||||
ProbeForWrite(ControlData,
|
||||
1024,
|
||||
1);
|
||||
memcpy(ControlData, OrigIVT, 1024);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ProbeForWrite(ControlData,
|
||||
256,
|
||||
1);
|
||||
memcpy(ControlData, OrigBDA, 256);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
KV86M_REGISTERS V86Registers;
|
||||
|
||||
ProbeForWrite(ControlData,
|
||||
sizeof(KV86M_REGISTERS),
|
||||
1);
|
||||
memcpy(&V86Registers,
|
||||
ControlData,
|
||||
sizeof(KV86M_REGISTERS));
|
||||
|
||||
/* FIXME: This should use ->VdmObjects */
|
||||
KeGetCurrentProcess()->Unused = 1;
|
||||
Ki386RetToV86Mode(&V86Registers, &V86Registers);
|
||||
|
||||
/* FIXME: This should use ->VdmObjects */
|
||||
KeGetCurrentProcess()->Unused = 0;
|
||||
|
||||
memcpy(ControlData,
|
||||
&V86Registers,
|
||||
sizeof(KV86M_REGISTERS));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -104,6 +104,11 @@ KiSystemStartup(BOOLEAN BootProcessor)
|
|||
/* Initialize the Kernel Executive */
|
||||
ExpInitializeExecutive();
|
||||
|
||||
/* Create the IOPM Save Area */
|
||||
Ki386IopmSaveArea = ExAllocatePoolWithTag(NonPagedPool,
|
||||
PAGE_SIZE * 2,
|
||||
TAG('K', 'e', ' ', ' '));
|
||||
|
||||
/* Free Initial Memory */
|
||||
MiFreeInitMemory();
|
||||
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mkconfig.c
|
||||
* PURPOSE: No purpose listed.
|
||||
*
|
||||
* PROGRAMMERS: No programmer listed.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
int
|
||||
write_if_change(char* outbuf, char* filename)
|
||||
{
|
||||
FILE* out;
|
||||
unsigned int end;
|
||||
char* cmpbuf;
|
||||
unsigned int stat;
|
||||
|
||||
out = fopen(filename, "rb");
|
||||
if (out == NULL)
|
||||
{
|
||||
out = fopen(filename, "wb");
|
||||
if (out == NULL)
|
||||
{
|
||||
fprintf(stderr, "Unable to create output file\n");
|
||||
return(1);
|
||||
}
|
||||
fputs(outbuf, out);
|
||||
fclose(out);
|
||||
return(0);
|
||||
}
|
||||
|
||||
fseek(out, 0, SEEK_END);
|
||||
end = ftell(out);
|
||||
cmpbuf = malloc(end);
|
||||
if (cmpbuf == NULL)
|
||||
{
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
fclose(out);
|
||||
return(1);
|
||||
}
|
||||
|
||||
fseek(out, 0, SEEK_SET);
|
||||
stat = fread(cmpbuf, 1, end, out);
|
||||
if (stat != end)
|
||||
{
|
||||
fprintf(stderr, "Failed to read data\n");
|
||||
fclose(out);
|
||||
return(1);
|
||||
}
|
||||
if (end == strlen(outbuf) && memcmp(cmpbuf, outbuf, end) == 0)
|
||||
{
|
||||
fclose(out);
|
||||
return(0);
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
out = fopen(filename, "wb");
|
||||
if (out == NULL)
|
||||
{
|
||||
fprintf(stderr, "Unable to create output file\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
stat = fwrite(outbuf, 1, strlen(outbuf), out);
|
||||
if (strlen(outbuf) != stat)
|
||||
{
|
||||
fprintf(stderr, "Unable to write output file\n");
|
||||
fclose(out);
|
||||
return(1);
|
||||
}
|
||||
fclose(out);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
unsigned int i;
|
||||
char* outbuf;
|
||||
char* s;
|
||||
char config[512];
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
fprintf(stderr, "Not enough arguments\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
outbuf = malloc(256 * 1024);
|
||||
if (outbuf == NULL)
|
||||
{
|
||||
fprintf(stderr, "Out of memory 1\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
s = outbuf;
|
||||
s = s + sprintf(s, "/* Automatically generated, ");
|
||||
s = s + sprintf(s, "Edit the Makefile to change configuration */\n");
|
||||
s = s + sprintf(s, "#ifndef __NTOSKRNL_INCLUDE_INTERNAL_CONFIG_H\n");
|
||||
s = s + sprintf(s, "#define __NTOSKRNL_INCLUDE_INTERNAL_CONFIG_H\n");
|
||||
strcpy(config, "");
|
||||
for (i = 2; i < argc; i++)
|
||||
{
|
||||
s = s + sprintf(s, "#define %s\n", argv[i]);
|
||||
strcat(config, argv[i]);
|
||||
if (i != (argc - 1))
|
||||
{
|
||||
strcat(config, " ");
|
||||
}
|
||||
}
|
||||
s = s + sprintf(s, "#define CONFIG \"%s\"\n", config);
|
||||
s = s + sprintf(s, "#endif /* __NTOSKRNL_INCLUDE_INTERNAL_CONFIG_H */\n");
|
||||
|
||||
return(write_if_change(outbuf, argv[1]));
|
||||
}
|
|
@ -110,6 +110,7 @@ MmAccessFault(KPROCESSOR_MODE Mode,
|
|||
*/
|
||||
if (Mode != KernelMode)
|
||||
{
|
||||
DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
|
||||
DbgPrint("%s:%d\n",__FILE__,__LINE__);
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
|
|
@ -40,9 +40,8 @@
|
|||
<file>trap.s</file>
|
||||
<file>tss.c</file>
|
||||
<file>usercall_asm.S</file>
|
||||
<file>v86m.c</file>
|
||||
<file>v86vdm.c</file>
|
||||
<file>v86m_sup.S</file>
|
||||
<file>vdm.c</file>
|
||||
</directory>
|
||||
</if>
|
||||
<file>apc.c</file>
|
||||
|
@ -328,6 +327,12 @@
|
|||
<file>sid.c</file>
|
||||
<file>token.c</file>
|
||||
</directory>
|
||||
<directory name="vdm">
|
||||
<if property="ARCH" value="i386">
|
||||
<file>vdmmain.c</file>
|
||||
<file>vdmexec.c</file>
|
||||
</if>
|
||||
</directory>
|
||||
<directory name="wmi">
|
||||
<file>wmi.c</file>
|
||||
</directory>
|
||||
|
|
File diff suppressed because it is too large
Load diff
323
reactos/ntoskrnl/vdm/vdmexec.c
Normal file
323
reactos/ntoskrnl/vdm/vdmexec.c
Normal file
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/vdm/vdmexec.c
|
||||
* PURPOSE: Support for executing VDM code and context swapping.
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
ULONG VdmBopCount;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
VdmpGetVdmTib(OUT PVDM_TIB *VdmTib)
|
||||
{
|
||||
PAGED_CODE();
|
||||
PVDM_TIB Tib;
|
||||
|
||||
/* Assume vailure */
|
||||
*VdmTib = NULL;
|
||||
|
||||
/* Get the current TIB */
|
||||
Tib = NtCurrentTeb()->Vdm;
|
||||
if (!Tib) return STATUS_INVALID_SYSTEM_SERVICE;
|
||||
|
||||
/* Validate the size */
|
||||
if (Tib->Size != sizeof(VDM_TIB)) return STATUS_INVALID_SYSTEM_SERVICE;
|
||||
|
||||
/* Return it */
|
||||
*VdmTib = Tib;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
VdmSwapContext(IN PKTRAP_FRAME TrapFrame,
|
||||
IN PCONTEXT OutContext,
|
||||
IN PCONTEXT InContext)
|
||||
{
|
||||
ULONG EFlags, OldEFlags;
|
||||
|
||||
/* Make sure that we're at APC_LEVEL and that this is a valid frame */
|
||||
ASSERT_IRQL(APC_LEVEL);
|
||||
ASSERT(TrapFrame->DbgArgMark = 0xBADB0D00);
|
||||
|
||||
/* Check if this is a V86 frame */
|
||||
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
|
||||
{
|
||||
/* Copy segment registers */
|
||||
OutContext->SegGs = TrapFrame->V86Gs;
|
||||
OutContext->SegFs = TrapFrame->V86Fs;
|
||||
OutContext->SegEs = TrapFrame->V86Es;
|
||||
OutContext->SegDs = TrapFrame->V86Ds;
|
||||
}
|
||||
else if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
|
||||
{
|
||||
/* This was user mode, copy segment registers */
|
||||
OutContext->SegGs = TrapFrame->SegGs;
|
||||
OutContext->SegFs = TrapFrame->SegFs;
|
||||
OutContext->SegEs = TrapFrame->SegEs;
|
||||
OutContext->SegDs = TrapFrame->SegDs;
|
||||
}
|
||||
|
||||
/* Copy CS and SS */
|
||||
OutContext->SegCs = TrapFrame->SegCs;
|
||||
OutContext->SegSs = TrapFrame->HardwareSegSs;
|
||||
|
||||
/* Copy general purpose registers */
|
||||
OutContext->Eax = TrapFrame->Eax;
|
||||
OutContext->Ebx = TrapFrame->Ebx;
|
||||
OutContext->Ecx = TrapFrame->Ecx;
|
||||
OutContext->Edx = TrapFrame->Edx;
|
||||
OutContext->Esi = TrapFrame->Esi;
|
||||
OutContext->Edi = TrapFrame->Edi;
|
||||
|
||||
/* Copy stack and counter */
|
||||
OutContext->Ebp = TrapFrame->Ebp;
|
||||
OutContext->Esp = TrapFrame->HardwareEsp;
|
||||
OutContext->Eip = TrapFrame->Eip;
|
||||
|
||||
/* Finally the flags */
|
||||
OutContext->EFlags = TrapFrame->EFlags;
|
||||
|
||||
/* Now copy from the in frame to the trap frame */
|
||||
TrapFrame->SegCs = InContext->SegCs;
|
||||
TrapFrame->HardwareSegSs = InContext->SegSs;
|
||||
|
||||
/* Copy the general purpose registers */
|
||||
TrapFrame->Eax = InContext->Eax;
|
||||
TrapFrame->Ebx = InContext->Ebx;
|
||||
TrapFrame->Ecx = InContext->Ecx;
|
||||
TrapFrame->Edx = InContext->Edx;
|
||||
TrapFrame->Esi = InContext->Esi;
|
||||
TrapFrame->Edi = InContext->Edi;
|
||||
|
||||
/* Copy the stack and counter */
|
||||
TrapFrame->Ebp = InContext->Ebp;
|
||||
TrapFrame->HardwareEsp = InContext->Esp;
|
||||
TrapFrame->Eip = InContext->Eip;
|
||||
|
||||
/* Check if the context is from V86 */
|
||||
EFlags = InContext->EFlags;
|
||||
if (EFlags & EFLAGS_V86_MASK)
|
||||
{
|
||||
/* Sanitize the flags for V86 */
|
||||
EFlags &= KeI386EFlagsAndMaskV86;
|
||||
EFlags |= KeI386EFlagsOrMaskV86;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add RPL_MASK to segments */
|
||||
TrapFrame->SegCs |= RPL_MASK;
|
||||
TrapFrame->HardwareSegSs |= RPL_MASK;
|
||||
|
||||
/* Check for bogus CS */
|
||||
if (TrapFrame->SegCs < KGDT_R0_CODE)
|
||||
{
|
||||
/* Set user-mode */
|
||||
TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
|
||||
}
|
||||
|
||||
/* Sanitize flags and add interrupt mask */
|
||||
EFlags &= EFLAGS_USER_SANITIZE;
|
||||
EFlags |=EFLAGS_INTERRUPT_MASK;
|
||||
}
|
||||
|
||||
/* Save the new eflags */
|
||||
OldEFlags = TrapFrame->EFlags;
|
||||
TrapFrame->EFlags = EFlags;
|
||||
|
||||
/* Check if we need to fixup ESP0 */
|
||||
if ((OldEFlags ^ EFlags) & EFLAGS_V86_MASK)
|
||||
{
|
||||
/* Fix it up */
|
||||
Ki386AdjustEsp0(TrapFrame);
|
||||
}
|
||||
|
||||
/* Check if this is a V86 context */
|
||||
if (InContext->EFlags & EFLAGS_V86_MASK)
|
||||
{
|
||||
/* Copy VDM segments */
|
||||
TrapFrame->V86Gs = InContext->SegGs;
|
||||
TrapFrame->V86Fs = InContext->SegFs;
|
||||
TrapFrame->V86Es = InContext->SegEs;
|
||||
TrapFrame->V86Ds = InContext->SegDs;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy monitor segments */
|
||||
TrapFrame->SegGs = InContext->SegGs;
|
||||
TrapFrame->SegFs = InContext->SegFs;
|
||||
TrapFrame->SegEs = InContext->SegEs;
|
||||
TrapFrame->SegDs = InContext->SegDs;
|
||||
}
|
||||
|
||||
/* Clear the exception list and return */
|
||||
TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
VdmpStartExecution(VOID)
|
||||
{
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
PKTRAP_FRAME VdmFrame;
|
||||
NTSTATUS Status;
|
||||
PVDM_TIB VdmTib;
|
||||
BOOLEAN Interrupts;
|
||||
KIRQL OldIrql;
|
||||
CONTEXT VdmContext;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Get the thread's VDM frame and TIB */
|
||||
VdmFrame = (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
|
||||
sizeof(FX_SAVE_AREA) -
|
||||
sizeof(KTRAP_FRAME));
|
||||
Status = VdmpGetVdmTib(&VdmTib);
|
||||
if (!NT_SUCCESS(Status)) return STATUS_INVALID_SYSTEM_SERVICE;
|
||||
|
||||
/* Go to APC level */
|
||||
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
||||
|
||||
/* Check if interrupts are enabled */
|
||||
Interrupts = (BOOLEAN)(VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK);
|
||||
|
||||
/* We don't support full VDM yet, this shouldn't happen */
|
||||
ASSERT(*VdmState == 0);
|
||||
ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);
|
||||
|
||||
/* Get the VDM context and make sure it's an edited frame */
|
||||
VdmContext = VdmTib->VdmContext;
|
||||
if (!(VdmContext.SegCs & FRAME_EDITED))
|
||||
{
|
||||
/* Fail */
|
||||
KeLowerIrql(OldIrql);
|
||||
return STATUS_INVALID_SYSTEM_SERVICE;
|
||||
}
|
||||
|
||||
/* FIXME: Support VME */
|
||||
ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);
|
||||
|
||||
/* Set interrupt state in the VDM State */
|
||||
if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK)
|
||||
{
|
||||
/* Enable them as well */
|
||||
InterlockedOr(VdmState, EFLAGS_INTERRUPT_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable them */
|
||||
InterlockedAnd(VdmState, ~EFLAGS_INTERRUPT_MASK);
|
||||
}
|
||||
|
||||
/* Enable the interrupt flag */
|
||||
VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
|
||||
|
||||
/* Now do the VDM Swap */
|
||||
VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);
|
||||
|
||||
/* Lower the IRQL and return EAX */
|
||||
KeLowerIrql(OldIrql);
|
||||
return VdmFrame->Eax;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
VdmEndExecution(IN PKTRAP_FRAME TrapFrame,
|
||||
IN PVDM_TIB VdmTib)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
CONTEXT Context;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Sanity check */
|
||||
ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
|
||||
(TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)));
|
||||
|
||||
/* Raise to APC_LEVEL */
|
||||
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
||||
|
||||
/* Set success */
|
||||
VdmTib->MonitorContext.Eax = STATUS_SUCCESS;
|
||||
|
||||
/* Make a copy of the monitor context */
|
||||
RtlMoveMemory(&Context, &VdmTib->MonitorContext, sizeof(CONTEXT));
|
||||
|
||||
/* Switch contexts */
|
||||
VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);
|
||||
|
||||
/* FIXME: Support VME */
|
||||
|
||||
/* Set the EFLAGS */
|
||||
VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags &
|
||||
~EFLAGS_INTERRUPT_MASK) |
|
||||
(*VdmState & EFLAGS_INTERRUPT_MASK);
|
||||
|
||||
/* Lower IRQL and reutrn */
|
||||
KeLowerIrql(OldIrql);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)
|
||||
{
|
||||
PUCHAR Eip;
|
||||
PVDM_TIB VdmTib;
|
||||
|
||||
/* Check if this is from V86 mode */
|
||||
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
|
||||
{
|
||||
/* Calculate flat EIP */
|
||||
Eip = (PUCHAR)((TrapFrame->Eip & 0xFFFF) +
|
||||
((TrapFrame->SegCs & 0xFFFF) << 4));
|
||||
|
||||
/* Check if this is a BOP */
|
||||
if (*(PUSHORT)Eip == 0xC4C4)
|
||||
{
|
||||
/* Check sure its the DOS Bop */
|
||||
if (Eip[2] == 0x50)
|
||||
{
|
||||
/* FIXME: No VDM Support */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* Increase the number of BOP operations */
|
||||
VdmBopCount++;
|
||||
|
||||
/* Get the TIB */
|
||||
VdmTib = NtCurrentTeb()->Vdm;
|
||||
|
||||
/* Fill out a VDM Event */
|
||||
VdmTib->EventInfo.InstructionSize = 3;
|
||||
VdmTib->EventInfo.BopNumber = Eip[2];
|
||||
VdmTib->EventInfo.Event = VdmBop;
|
||||
|
||||
/* End VDM Execution */
|
||||
VdmEndExecution(TrapFrame, VdmTib);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not a BOP */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Shouldn't happen on ROS */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
|
131
reactos/ntoskrnl/vdm/vdmmain.c
Normal file
131
reactos/ntoskrnl/vdm/vdmmain.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
static UCHAR OrigIVT[1024];
|
||||
static UCHAR OrigBDA[256];
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
INIT_FUNCTION
|
||||
NtEarlyInitVdm(VOID)
|
||||
{
|
||||
/* GCC 3.4 hack */
|
||||
PVOID start = (PVOID)0x0;
|
||||
|
||||
/*
|
||||
* Save various BIOS data tables. At this point the lower 4MB memory
|
||||
* map is still active so we can just copy the data from low memory.
|
||||
* HACK HACK HACK: We should just map Physical Memory!!!
|
||||
*/
|
||||
memcpy(OrigIVT, start, 1024);
|
||||
memcpy(OrigBDA, (PVOID)0x400, 256);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Ki386VdmEnablePentiumExtentions(VOID)
|
||||
{
|
||||
DPRINT1("VME detected but not yet supported\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
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\\"
|
||||
"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 & X86_FEATURE_VME)
|
||||
{
|
||||
/* Enable them. FIXME: Use IPI */
|
||||
Ki386VdmEnablePentiumExtentions();
|
||||
KeI386VirtualIntExtensions = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the key */
|
||||
ZwClose(RegHandle);
|
||||
}
|
||||
|
||||
/* 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:
|
||||
|
||||
/* Pretty much a hack, since a lot more needs to happen */
|
||||
memcpy(ControlData, OrigIVT, 1024);
|
||||
memcpy((PVOID)((ULONG_PTR)ControlData + 1024), OrigBDA, 256);
|
||||
Status = STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Unsupported */
|
||||
DPRINT1("Unknown VDM call: %lx\n", ControlCode);
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Return the status */
|
||||
return Status;
|
||||
}
|
|
@ -19,8 +19,7 @@ InitializeVideoAddressSpace(VOID)
|
|||
PVOID NullAddress;
|
||||
LARGE_INTEGER Offset;
|
||||
ULONG ViewSize;
|
||||
CHAR IVT[1024];
|
||||
CHAR BDA[256];
|
||||
CHAR IVTAndBda[1024+256];
|
||||
|
||||
/*
|
||||
* Open the physical memory section
|
||||
|
@ -93,35 +92,21 @@ InitializeVideoAddressSpace(VOID)
|
|||
}
|
||||
|
||||
/*
|
||||
* Get the real mode IVT from the kernel
|
||||
* Get the real mode IVT and BDA from the kernel
|
||||
*/
|
||||
Status = NtVdmControl(0, IVT);
|
||||
if (!NT_SUCCESS(Status))
|
||||
Status = NtVdmControl(VdmInitialize, IVTAndBda);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DbgPrint("NtVdmControl failed (status %x)\n", Status);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the real mode IVT into the right place
|
||||
* Copy the IVT and BDA into the right place
|
||||
*/
|
||||
NullAddress = (PVOID)0x0; /* Workaround for GCC 3.4 */
|
||||
memcpy(NullAddress, IVT, 1024);
|
||||
|
||||
/*
|
||||
* Get the BDA from the kernel
|
||||
*/
|
||||
Status = NtVdmControl(1, BDA);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DbgPrint("NtVdmControl failed (status %x)\n", Status);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the BDA into the right place
|
||||
*/
|
||||
memcpy((PVOID)0x400, BDA, 256);
|
||||
memcpy(NullAddress, IVTAndBda, 1024);
|
||||
memcpy((PVOID)0x400, &IVTAndBda[1024], 256);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue