2006-11-08 11:47:44 +00:00
|
|
|
/*
|
|
|
|
* 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 */
|
|
|
|
RtlCopyMemory(&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),
|
2009-08-24 18:19:53 +00:00
|
|
|
' eK');
|
2006-11-08 11:47:44 +00:00
|
|
|
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 */
|
2008-10-22 13:24:01 +00:00
|
|
|
ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >=
|
|
|
|
(0x2000 + IOPM_OFFSET - 1));
|
2006-11-08 11:47:44 +00:00
|
|
|
RtlCopyMemory(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 = (USHORT)IOPM_OFFSET;
|
|
|
|
Tss->IoMapBase = (USHORT)IOPM_OFFSET;
|
|
|
|
|
|
|
|
/* Switch stacks and work the magic */
|
|
|
|
Ki386SetupAndExitToV86Mode(VdmTeb);
|
|
|
|
|
|
|
|
/* Restore IOPM */
|
|
|
|
RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2);
|
|
|
|
Process->IopmOffset = OldOffset;
|
|
|
|
Tss->IoMapBase = OldBase;
|
|
|
|
|
|
|
|
/* Restore affinity */
|
|
|
|
KeRevertToUserAffinityThread();
|
|
|
|
|
|
|
|
/* Restore context */
|
|
|
|
RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize);
|
|
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
|
|
|
|
/* Free VDM objects */
|
|
|
|
ExFreePool(PsGetCurrentProcess()->VdmObjects);
|
|
|
|
PsGetCurrentProcess()->VdmObjects = NULL;
|
|
|
|
|
|
|
|
/* Return status */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-11-02 11:48:24 +00:00
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
Ke386IoSetAccessProcess(IN PKPROCESS Process,
|
|
|
|
IN ULONG Flag)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
Ke386SetIoAccessMap(IN ULONG Flag,
|
|
|
|
IN PVOID IopmBuffer)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
Ke386QueryIoAccessMap(IN ULONG Flag,
|
|
|
|
IN PVOID IopmBuffer)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return FALSE;
|
|
|
|
}
|