- 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:
Alex Ionescu 2006-08-28 23:56:35 +00:00
parent 9d1c606794
commit 28122cd8d9
27 changed files with 2003 additions and 2363 deletions

View file

@ -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,""

View file

@ -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;

View file

@ -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 ***********************************************************/

View file

@ -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
//

View file

@ -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

View file

@ -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.
//

View file

@ -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();

View file

@ -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
//

View file

@ -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 */

View file

@ -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 */

View file

@ -35,6 +35,7 @@
#include "tag.h"
#include "test.h"
#include "inbv.h"
#include "vdm.h"
#include <pshpack1.h>
/*

View 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
//

View file

@ -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++;

View file

@ -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;

View file

@ -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

View file

@ -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);
}

View file

@ -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

View 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 */

View file

@ -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 */

View file

@ -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();

View file

@ -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]));
}

View file

@ -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);
}

View file

@ -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

View 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;
}

View 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;
}

View file

@ -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);
}