[VIDEOPRT] Implement support for dynamically choosing V86 vs. X86 emulator on x86 32-bit builds (#8451)

The choice is done by looking for the presence or absence of the
`HKLM\System\CurrentControlSet\Control\GraphicsDrivers\DisableEmulator`
registry key. For more details, see:
https://www.geoffchappell.com/studies/windows/km/hal/api/x86bios/call.htm

By default, use V86 in 32-bit Win2k3-compatible builds, otherwise
(Vista+) check the presence of the registry key.

The X86 emulator routines are exported by the HAL.DLL. They are always
exported by the non-x86 HAL. However, they may or may not be exported by
the x86 (32-bit) HAL: on NT 5.2 and below they are not exported, while
on NT 6.x (Vista+) they are.

Therefore:

- in our NT <= 5.2 x86 builds, we load the routines at runtime. If they
  aren't found, we fail emulator support initialization and fall back to
  VDM V86 support.

- in our NT 6.x (x86 or not) builds, we always directly link with the HAL
  routines, since they are guaranteed to be present there.
This commit is contained in:
Hermès Bélusca-Maïto
2025-11-18 17:01:26 +01:00
parent 6313ef9d69
commit 89d5a3dbb8
4 changed files with 473 additions and 144 deletions
+2 -2
View File
@@ -385,10 +385,10 @@ IntVideoPortDispatchOpen(
ObReferenceObject(CsrProcess); ObReferenceObject(CsrProcess);
INFO_(VIDEOPRT, "CsrProcess 0x%p\n", CsrProcess); INFO_(VIDEOPRT, "CsrProcess 0x%p\n", CsrProcess);
Status = IntInitializeVideoAddressSpace(); Status = IntInitializeInt10();
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ERR_(VIDEOPRT, "IntInitializeVideoAddressSpace() failed: 0x%lx\n", Status); ERR_(VIDEOPRT, "IntInitializeInt10() failed: 0x%lx\n", Status);
ObDereferenceObject(CsrProcess); ObDereferenceObject(CsrProcess);
CsrProcess = NULL; CsrProcess = NULL;
return Status; return Status;
+402 -100
View File
@@ -22,20 +22,96 @@
#include "videoprt.h" #include "videoprt.h"
#include <ndk/kefuncs.h> #include <ndk/kefuncs.h>
#include <ndk/halfuncs.h>
#include <ndk/mmfuncs.h> #include <ndk/mmfuncs.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/ /* GLOBAL VARIABLES ***********************************************************/
#ifdef _M_IX86
/* Use the 32-bit x86 emulator by default, on NT 6.x (Vista+), or on NT 5.x
* if the HAL has the necessary exports. Otherwise fall back to V86 mode. */
BOOLEAN VideoPortDisableX86Emulator = FALSE;
#endif
KMUTEX VideoPortInt10Mutex;
/* X86 EMULATOR & V86 MODE INITIALIZATION *************************************/
#if (NTDDI_VERSION < NTDDI_VISTA) && (DLL_EXPORT_VERSION < _WIN32_WINNT_VISTA)
/*
* x86 Emulator callbacks
*/
#include <ndk/haltypes.h> // For X86_BIOS_REGISTERS
static BOOLEAN
(NTAPI *x86BiosCall)(
_In_ ULONG InterruptNumber,
_Inout_ PX86_BIOS_REGISTERS Registers);
static NTSTATUS
(NTAPI *x86BiosAllocateBuffer)(
_Inout_ PULONG Size,
_Out_ PUSHORT Segment,
_Out_ PUSHORT Offset);
static NTSTATUS
(NTAPI *x86BiosFreeBuffer)(
_In_ USHORT Segment,
_In_ USHORT Offset);
static NTSTATUS
(NTAPI *x86BiosReadMemory)(
_In_ USHORT Segment,
_In_ USHORT Offset,
_Out_writes_bytes_(Size) PVOID Buffer,
_In_ ULONG Size);
static NTSTATUS
(NTAPI *x86BiosWriteMemory)(
_In_ USHORT Segment,
_In_ USHORT Offset,
_In_reads_bytes_(Size) PVOID Buffer,
_In_ ULONG Size);
#else // (NTDDI_VERSION >= NTDDI_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
#include <ndk/halfuncs.h> // For x86Bios*()
#endif
static BOOLEAN
IntInitializeX86Emu(VOID)
{
#if (NTDDI_VERSION < NTDDI_VISTA) && (DLL_EXPORT_VERSION < _WIN32_WINNT_VISTA)
UNICODE_STRING ImportName;
#define LOAD_IMPORT(func) \
(RtlInitUnicodeString(&ImportName, L ## #func), \
(func) = MmGetSystemRoutineAddress(&ImportName))
if (!LOAD_IMPORT(x86BiosCall)) // Check also HalInitializeBios ?
return FALSE; /* No emulator available */
if (!LOAD_IMPORT(x86BiosAllocateBuffer))
return FALSE;
if (!LOAD_IMPORT(x86BiosFreeBuffer))
return FALSE;
if (!LOAD_IMPORT(x86BiosReadMemory))
return FALSE;
if (!LOAD_IMPORT(x86BiosWriteMemory))
return FALSE;
#undef LOAD_IMPORT
#endif
return TRUE;
}
#ifdef _M_IX86
#define IsLowV86Mem(_Seg, _Off) ((((_Seg) << 4) + (_Off)) < (0xa0000)) #define IsLowV86Mem(_Seg, _Off) ((((_Seg) << 4) + (_Off)) < (0xa0000))
/* Those two functions below are there so that CSRSS can't access low mem. /* Those two functions below are there so that CSRSS can't access low mem.
* Especially, MAKE IT CRASH ON NULL ACCESS */ * Especially, MAKE IT CRASH ON NULL ACCESS */
static static VOID
VOID
ProtectLowV86Mem(VOID) ProtectLowV86Mem(VOID)
{ {
/* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it /* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it
@@ -57,8 +133,7 @@ ProtectLowV86Mem(VOID)
ASSERT(NT_SUCCESS(Status)); ASSERT(NT_SUCCESS(Status));
} }
static static VOID
VOID
UnprotectLowV86Mem(VOID) UnprotectLowV86Mem(VOID)
{ {
/* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it /* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it
@@ -80,9 +155,8 @@ UnprotectLowV86Mem(VOID)
ASSERT(NT_SUCCESS(Status)); ASSERT(NT_SUCCESS(Status));
} }
#if defined(_M_IX86) || defined(_M_AMD64) static inline
NTSTATUS NTSTATUS
NTAPI
IntInitializeVideoAddressSpace(VOID) IntInitializeVideoAddressSpace(VOID)
{ {
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
@@ -92,9 +166,7 @@ IntInitializeVideoAddressSpace(VOID)
PVOID BaseAddress; PVOID BaseAddress;
LARGE_INTEGER Offset; LARGE_INTEGER Offset;
SIZE_T ViewSize; SIZE_T ViewSize;
#ifdef _M_IX86
CHAR IVTAndBda[1024 + 256]; CHAR IVTAndBda[1024 + 256];
#endif // _M_IX86
/* We should only do that for CSRSS */ /* We should only do that for CSRSS */
ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess); ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess);
@@ -181,7 +253,6 @@ IntInitializeVideoAddressSpace(VOID)
return 0; return 0;
} }
#ifdef _M_IX86
/* Get the real mode IVT and BDA from the kernel */ /* Get the real mode IVT and BDA from the kernel */
Status = NtVdmControl(VdmInitialize, IVTAndBda); Status = NtVdmControl(VdmInitialize, IVTAndBda);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
@@ -189,7 +260,6 @@ IntInitializeVideoAddressSpace(VOID)
DPRINT1("NtVdmControl failed (status %x)\n", Status); DPRINT1("NtVdmControl failed (status %x)\n", Status);
return Status; return Status;
} }
#endif // _M_IX86
/* Protect the V86 address space after this */ /* Protect the V86 address space after this */
ProtectLowV86Mem(); ProtectLowV86Mem();
@@ -197,33 +267,62 @@ IntInitializeVideoAddressSpace(VOID)
/* Return success */ /* Return success */
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
#else
NTSTATUS
NTAPI
IntInitializeVideoAddressSpace(VOID)
{
UNIMPLEMENTED;
NT_ASSERT(FALSE);
return STATUS_NOT_IMPLEMENTED;
}
#endif
VP_STATUS #endif // _M_IX86
/* VideoPortServicesInt10 CALLBACKS *******************************************/
#ifdef _M_IX86
typedef struct _INT10_INTERFACE
{
PINT10_ALLOCATE_BUFFER Int10AllocateBuffer;
PINT10_FREE_BUFFER Int10FreeBuffer;
PINT10_READ_MEMORY Int10ReadMemory;
PINT10_WRITE_MEMORY Int10WriteMemory;
PINT10_CALL_BIOS Int10CallBios;
} INT10_INTERFACE;
// Remark: Instead of `Int10Vtbl->`, one could use: `Int10IFace[VideoPortDisableX86Emulator].`
static const INT10_INTERFACE *Int10Vtbl; // Int10IFace[2];
#define INT10(func) Int10Vtbl->Int10##func
#else
#define INT10(func) IntInt10##func##Emu
#endif // _M_IX86
static VP_STATUS
NTAPI NTAPI
IntInt10AllocateBuffer( IntInt10AllocateBufferEmu(
IN PVOID Context, _In_ PVOID Context,
OUT PUSHORT Seg, _Out_ PUSHORT Seg,
OUT PUSHORT Off, _Out_ PUSHORT Off,
IN OUT PULONG Length) _Inout_ PULONG Length)
{ {
NTSTATUS Status; NTSTATUS Status;
UNREFERENCED_PARAMETER(Context);
Status = x86BiosAllocateBuffer(Length, Seg, Off);
return (NT_SUCCESS(Status) ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY);
}
#ifdef _M_IX86 #ifdef _M_IX86
static VP_STATUS
NTAPI
IntInt10AllocateBufferV86(
_In_ PVOID Context,
_Out_ PUSHORT Seg,
_Out_ PUSHORT Off,
_Inout_ PULONG Length)
{
NTSTATUS Status;
PVOID MemoryAddress; PVOID MemoryAddress;
PKPROCESS CallingProcess; PKPROCESS CallingProcess;
KAPC_STATE ApcState; KAPC_STATE ApcState;
SIZE_T Size; SIZE_T Size;
TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n"); UNREFERENCED_PARAMETER(Context);
/* Perform the call in the CSRSS context */ /* Perform the call in the CSRSS context */
if (!IntAttachToCSRSS(&CallingProcess, &ApcState)) if (!IntAttachToCSRSS(&CallingProcess, &ApcState))
@@ -262,34 +361,63 @@ IntInt10AllocateBuffer(
*Seg = (USHORT)((ULONG_PTR)MemoryAddress >> 4); *Seg = (USHORT)((ULONG_PTR)MemoryAddress >> 4);
*Off = (USHORT)((ULONG_PTR)MemoryAddress & 0xF); *Off = (USHORT)((ULONG_PTR)MemoryAddress & 0xF);
INFO_(VIDEOPRT, "- Segment: %x\n", *Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", *Off);
INFO_(VIDEOPRT, "- Length: %x\n", *Length);
return NO_ERROR; return NO_ERROR;
#else
Status = x86BiosAllocateBuffer(Length, Seg, Off);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY;
#endif
} }
#endif // _M_IX86
VP_STATUS VP_STATUS
NTAPI NTAPI
IntInt10FreeBuffer( IntInt10AllocateBuffer(
IN PVOID Context, _In_ PVOID Context,
IN USHORT Seg, _Out_ PUSHORT Seg,
IN USHORT Off) _Out_ PUSHORT Off,
_Inout_ PULONG Length)
{
VP_STATUS Status;
TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n");
Status = INT10(AllocateBuffer)(Context, Seg, Off, Length);
if (Status == NO_ERROR)
{
INFO_(VIDEOPRT, "- Segment: 0x%x\n", *Seg);
INFO_(VIDEOPRT, "- Offset : 0x%x\n", *Off);
INFO_(VIDEOPRT, "- Length : 0x%x\n", *Length);
}
return Status;
}
static VP_STATUS
NTAPI
IntInt10FreeBufferEmu(
_In_ PVOID Context,
_In_ USHORT Seg,
_In_ USHORT Off)
{ {
NTSTATUS Status; NTSTATUS Status;
UNREFERENCED_PARAMETER(Context);
Status = x86BiosFreeBuffer(Seg, Off);
return (NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER);
}
#ifdef _M_IX86 #ifdef _M_IX86
static VP_STATUS
NTAPI
IntInt10FreeBufferV86(
_In_ PVOID Context,
_In_ USHORT Seg,
_In_ USHORT Off)
{
NTSTATUS Status;
PVOID MemoryAddress = (PVOID)((ULONG_PTR)(Seg << 4) | Off); PVOID MemoryAddress = (PVOID)((ULONG_PTR)(Seg << 4) | Off);
PKPROCESS CallingProcess; PKPROCESS CallingProcess;
KAPC_STATE ApcState; KAPC_STATE ApcState;
SIZE_T Size = 0; SIZE_T Size = 0;
TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n"); UNREFERENCED_PARAMETER(Context);
INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", Off);
/* Perform the call in the CSRSS context */ /* Perform the call in the CSRSS context */
if (!IntAttachToCSRSS(&CallingProcess, &ApcState)) if (!IntAttachToCSRSS(&CallingProcess, &ApcState))
@@ -303,30 +431,55 @@ IntInt10FreeBuffer(
IntDetachFromCSRSS(CallingProcess, &ApcState); IntDetachFromCSRSS(CallingProcess, &ApcState);
return Status; return Status;
#else
Status = x86BiosFreeBuffer(Seg, Off);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER;
#endif
} }
#endif // _M_IX86
VP_STATUS VP_STATUS
NTAPI NTAPI
IntInt10ReadMemory( IntInt10FreeBuffer(
IN PVOID Context, _In_ PVOID Context,
IN USHORT Seg, _In_ USHORT Seg,
IN USHORT Off, _In_ USHORT Off)
OUT PVOID Buffer,
IN ULONG Length)
{ {
TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n");
INFO_(VIDEOPRT, "- Segment: 0x%x\n", Seg);
INFO_(VIDEOPRT, "- Offset : 0x%x\n", Off);
return INT10(FreeBuffer)(Context, Seg, Off);
}
static VP_STATUS
NTAPI
IntInt10ReadMemoryEmu(
_In_ PVOID Context,
_In_ USHORT Seg,
_In_ USHORT Off,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length)
{
NTSTATUS Status;
UNREFERENCED_PARAMETER(Context);
Status = x86BiosReadMemory(Seg, Off, Buffer, Length);
return (NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER);
}
#ifdef _M_IX86 #ifdef _M_IX86
static VP_STATUS
NTAPI
IntInt10ReadMemoryV86(
_In_ PVOID Context,
_In_ USHORT Seg,
_In_ USHORT Off,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length)
{
PKPROCESS CallingProcess; PKPROCESS CallingProcess;
KAPC_STATE ApcState; KAPC_STATE ApcState;
TRACE_(VIDEOPRT, "IntInt10ReadMemory\n"); UNREFERENCED_PARAMETER(Context);
INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", Off);
INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer);
INFO_(VIDEOPRT, "- Length: %x\n", Length);
/* Perform the call in the CSRSS context */ /* Perform the call in the CSRSS context */
if (!IntAttachToCSRSS(&CallingProcess, &ApcState)) if (!IntAttachToCSRSS(&CallingProcess, &ApcState))
@@ -341,32 +494,59 @@ IntInt10ReadMemory(
IntDetachFromCSRSS(CallingProcess, &ApcState); IntDetachFromCSRSS(CallingProcess, &ApcState);
return NO_ERROR; return NO_ERROR;
#else
NTSTATUS Status;
Status = x86BiosReadMemory(Seg, Off, Buffer, Length);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER;
#endif
} }
#endif // _M_IX86
VP_STATUS VP_STATUS
NTAPI NTAPI
IntInt10WriteMemory( IntInt10ReadMemory(
IN PVOID Context, _In_ PVOID Context,
IN USHORT Seg, _In_ USHORT Seg,
IN USHORT Off, _In_ USHORT Off,
IN PVOID Buffer, _Out_writes_bytes_(Length) PVOID Buffer,
IN ULONG Length) _In_ ULONG Length)
{ {
TRACE_(VIDEOPRT, "IntInt10ReadMemory\n");
INFO_(VIDEOPRT, "- Segment: 0x%x\n", Seg);
INFO_(VIDEOPRT, "- Offset : 0x%x\n", Off);
INFO_(VIDEOPRT, "- Buffer : 0x%x\n", Buffer);
INFO_(VIDEOPRT, "- Length : 0x%x\n", Length);
return INT10(ReadMemory)(Context, Seg, Off, Buffer, Length);
}
static VP_STATUS
NTAPI
IntInt10WriteMemoryEmu(
_In_ PVOID Context,
_In_ USHORT Seg,
_In_ USHORT Off,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length)
{
NTSTATUS Status;
UNREFERENCED_PARAMETER(Context);
Status = x86BiosWriteMemory(Seg, Off, Buffer, Length);
return (NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER);
}
#ifdef _M_IX86 #ifdef _M_IX86
static VP_STATUS
NTAPI
IntInt10WriteMemoryV86(
_In_ PVOID Context,
_In_ USHORT Seg,
_In_ USHORT Off,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length)
{
PKPROCESS CallingProcess; PKPROCESS CallingProcess;
KAPC_STATE ApcState; KAPC_STATE ApcState;
TRACE_(VIDEOPRT, "IntInt10WriteMemory\n"); UNREFERENCED_PARAMETER(Context);
INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", Off);
INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer);
INFO_(VIDEOPRT, "- Length: %x\n", Length);
/* Perform the call in the CSRSS context */ /* Perform the call in the CSRSS context */
if (!IntAttachToCSRSS(&CallingProcess, &ApcState)) if (!IntAttachToCSRSS(&CallingProcess, &ApcState))
@@ -381,29 +561,90 @@ IntInt10WriteMemory(
IntDetachFromCSRSS(CallingProcess, &ApcState); IntDetachFromCSRSS(CallingProcess, &ApcState);
return NO_ERROR; return NO_ERROR;
#else
NTSTATUS Status;
Status = x86BiosWriteMemory(Seg, Off, Buffer, Length);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER;
#endif
} }
#endif // _M_IX86
VP_STATUS VP_STATUS
NTAPI NTAPI
IntInt10CallBios( IntInt10WriteMemory(
IN PVOID Context, _In_ PVOID Context,
IN OUT PINT10_BIOS_ARGUMENTS BiosArguments) _In_ USHORT Seg,
_In_ USHORT Off,
_In_reads_bytes_(Length) PVOID Buffer,
_In_ ULONG Length)
{
TRACE_(VIDEOPRT, "IntInt10WriteMemory\n");
INFO_(VIDEOPRT, "- Segment: 0x%x\n", Seg);
INFO_(VIDEOPRT, "- Offset : 0x%x\n", Off);
INFO_(VIDEOPRT, "- Buffer : 0x%x\n", Buffer);
INFO_(VIDEOPRT, "- Length : 0x%x\n", Length);
return INT10(WriteMemory)(Context, Seg, Off, Buffer, Length);
}
static VP_STATUS
NTAPI
IntInt10CallBiosEmu(
_In_ PVOID Context,
_Inout_ PINT10_BIOS_ARGUMENTS BiosArguments)
{ {
#ifdef _M_AMD64
X86_BIOS_REGISTERS BiosContext; X86_BIOS_REGISTERS BiosContext;
#else BOOLEAN Success;
UNREFERENCED_PARAMETER(Context);
/* Clear the context and fill out the BIOS arguments */
RtlZeroMemory(&BiosContext, sizeof(BiosContext));
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;
/* Do the ROM BIOS call */
(void)KeWaitForMutexObject(&VideoPortInt10Mutex,
Executive,
KernelMode,
FALSE,
NULL);
Success = x86BiosCall(0x10, &BiosContext);
KeReleaseMutex(&VideoPortInt10Mutex, FALSE);
/* 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 = (USHORT)BiosContext.SegDs;
BiosArguments->SegEs = (USHORT)BiosContext.SegEs;
return (Success ? NO_ERROR : ERROR_INVALID_PARAMETER);
}
#ifdef _M_IX86
static VP_STATUS
NTAPI
IntInt10CallBiosV86(
_In_ PVOID Context,
_Inout_ PINT10_BIOS_ARGUMENTS BiosArguments)
{
CONTEXT BiosContext; CONTEXT BiosContext;
#endif
NTSTATUS Status; NTSTATUS Status;
PKPROCESS CallingProcess; PKPROCESS CallingProcess;
KAPC_STATE ApcState; KAPC_STATE ApcState;
UNREFERENCED_PARAMETER(Context);
/* Clear the context and fill out the BIOS arguments */ /* Clear the context and fill out the BIOS arguments */
RtlZeroMemory(&BiosContext, sizeof(BiosContext)); RtlZeroMemory(&BiosContext, sizeof(BiosContext));
BiosContext.Eax = BiosArguments->Eax; BiosContext.Eax = BiosArguments->Eax;
@@ -429,11 +670,18 @@ IntInt10CallBios(
/* The kernel needs access here */ /* The kernel needs access here */
UnprotectLowV86Mem(); UnprotectLowV86Mem();
#ifdef _M_AMD64
Status = x86BiosCall(0x10, &BiosContext) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; /* Invoke the V86 monitor under SEH, as it can raise exceptions */
#else _SEH2_TRY
Status = Ke386CallBios(0x10, &BiosContext); {
#endif Status = Ke386CallBios(0x10, &BiosContext);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
ProtectLowV86Mem(); ProtectLowV86Mem();
KeReleaseMutex(&VideoPortInt10Mutex, FALSE); KeReleaseMutex(&VideoPortInt10Mutex, FALSE);
@@ -451,8 +699,67 @@ IntInt10CallBios(
BiosArguments->SegDs = (USHORT)BiosContext.SegDs; BiosArguments->SegDs = (USHORT)BiosContext.SegDs;
BiosArguments->SegEs = (USHORT)BiosContext.SegEs; BiosArguments->SegEs = (USHORT)BiosContext.SegEs;
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; return (NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER);
} }
#endif // _M_IX86
VP_STATUS
NTAPI
IntInt10CallBios(
_In_ PVOID Context,
_Inout_ PINT10_BIOS_ARGUMENTS BiosArguments)
{
return INT10(CallBios)(Context, BiosArguments);
}
#ifdef _M_IX86
static const INT10_INTERFACE Int10IFace[2] =
{ { IntInt10AllocateBufferEmu,
IntInt10FreeBufferEmu,
IntInt10ReadMemoryEmu,
IntInt10WriteMemoryEmu,
IntInt10CallBiosEmu }
,
{ IntInt10AllocateBufferV86,
IntInt10FreeBufferV86,
IntInt10ReadMemoryV86,
IntInt10WriteMemoryV86,
IntInt10CallBiosV86 }
};
static const INT10_INTERFACE *Int10Vtbl = &Int10IFace[0];
#endif
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS
IntInitializeInt10(VOID)
{
#ifdef _M_IX86
/* We should only do that for CSRSS */
ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess);
/* Initialize the x86 emulator if necessary, otherwise fall back to V86 mode */
if (!VideoPortDisableX86Emulator)
{
/* Use the emulation routines */
//Int10Vtbl = &Int10IFace[0];
if (IntInitializeX86Emu())
return STATUS_SUCCESS;
DPRINT1("Could not initialize the x86 emulator; falling back to V86 mode\n");
VideoPortDisableX86Emulator = TRUE;
}
/* Fall back to the V86 routines */
Int10Vtbl = &Int10IFace[1];
return IntInitializeVideoAddressSpace();
#else
/* Initialize the x86 emulator */
return (IntInitializeX86Emu() ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED);
#endif
}
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
@@ -465,13 +772,8 @@ VideoPortInt10(
IN PVOID HwDeviceExtension, IN PVOID HwDeviceExtension,
IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments) IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments)
{ {
INT10_BIOS_ARGUMENTS Int10BiosArguments;
VP_STATUS Status; VP_STATUS Status;
INT10_BIOS_ARGUMENTS Int10BiosArguments;
if (!CsrProcess)
{
return ERROR_INVALID_PARAMETER;
}
/* Copy arguments to other format */ /* Copy arguments to other format */
RtlCopyMemory(&Int10BiosArguments, BiosArguments, sizeof(*BiosArguments)); RtlCopyMemory(&Int10BiosArguments, BiosArguments, sizeof(*BiosArguments));
+33 -14
View File
@@ -39,7 +39,7 @@ BOOLEAN VpNoVesa = FALSE;
PKPROCESS CsrProcess = NULL; PKPROCESS CsrProcess = NULL;
static ULONG VideoPortMaxObjectNumber = -1; static ULONG VideoPortMaxObjectNumber = -1;
BOOLEAN VideoPortUseNewKey = FALSE; BOOLEAN VideoPortUseNewKey = FALSE;
KMUTEX VideoPortInt10Mutex;
KSPIN_LOCK HwResetAdaptersLock; KSPIN_LOCK HwResetAdaptersLock;
RTL_STATIC_LIST_HEAD(HwResetAdaptersList); RTL_STATIC_LIST_HEAD(HwResetAdaptersList);
@@ -628,21 +628,21 @@ IntLoadRegistryParameters(VOID)
{ {
NTSTATUS Status; NTSTATUS Status;
HANDLE KeyHandle; HANDLE KeyHandle;
UNICODE_STRING UseNewKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\UseNewKey"); UNICODE_STRING KeyPath;
UNICODE_STRING Path = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions"); UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SystemStartOptions");
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo; PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
ULONG Length, NewLength; ULONG Length, NewLength;
/* Check if we need to use new registry */ /* Check if we need to use new registry */
RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\UseNewKey");
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
&UseNewKeyPath, &KeyPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL, NULL,
NULL); NULL);
Status = ZwOpenKey(&KeyHandle, Status = ZwOpenKey(&KeyHandle,
GENERIC_READ | GENERIC_WRITE, KEY_QUERY_VALUE,
&ObjectAttributes); &ObjectAttributes);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
@@ -650,9 +650,29 @@ IntLoadRegistryParameters(VOID)
ZwClose(KeyHandle); ZwClose(KeyHandle);
} }
/* Initialize object attributes with the path we want */ #ifdef _M_IX86
/* Check whether we need to use the 32-bit x86 emulator instead of V86 mode */
RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\DisableEmulator");
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
&Path, &KeyPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwOpenKey(&KeyHandle,
KEY_QUERY_VALUE,
&ObjectAttributes);
if (NT_SUCCESS(Status))
{
VideoPortDisableX86Emulator = TRUE;
ZwClose(KeyHandle);
}
DPRINT1("Using %s\n", VideoPortDisableX86Emulator ? "V86 mode" : "x86 emulator");
#endif // _M_IX86
/* Initialize object attributes with the path we want */
RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
InitializeObjectAttributes(&ObjectAttributes,
&KeyPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL, NULL,
NULL); NULL);
@@ -677,7 +697,7 @@ IntLoadRegistryParameters(VOID)
if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
{ {
VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status); VideoPortDebugPrint(Error, "ZwQueryValueKey failed (0x%x)\n", Status);
ObCloseHandle(KeyHandle, KernelMode); ZwClose(KeyHandle);
return; return;
} }
@@ -686,7 +706,7 @@ IntLoadRegistryParameters(VOID)
if (!KeyInfo) if (!KeyInfo)
{ {
VideoPortDebugPrint(Error, "Out of memory\n"); VideoPortDebugPrint(Error, "Out of memory\n");
ObCloseHandle(KeyHandle, KernelMode); ZwClose(KeyHandle);
return; return;
} }
@@ -697,7 +717,7 @@ IntLoadRegistryParameters(VOID)
KeyInfo, KeyInfo,
Length, Length,
&NewLength); &NewLength);
ObCloseHandle(KeyHandle, KernelMode); ZwClose(KeyHandle);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
@@ -733,10 +753,9 @@ IntLoadRegistryParameters(VOID)
/* If we are in BASEVIDEO, create the volatile registry key for Win32k */ /* If we are in BASEVIDEO, create the volatile registry key for Win32k */
if (VpBaseVideo) if (VpBaseVideo)
{ {
RtlInitUnicodeString(&Path, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo"); RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo");
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
&Path, &KeyPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL, NULL,
NULL); NULL);
@@ -749,7 +768,7 @@ IntLoadRegistryParameters(VOID)
REG_OPTION_VOLATILE, REG_OPTION_VOLATILE,
NULL); NULL);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
ObCloseHandle(KeyHandle, KernelMode); ZwClose(KeyHandle);
else else
ERR_(VIDEOPRT, "Failed to create the BaseVideo key (0x%x)\n", Status); ERR_(VIDEOPRT, "Failed to create the BaseVideo key (0x%x)\n", Status);
} }
+36 -28
View File
@@ -254,7 +254,7 @@ IntVideoPortMapPhysicalMemory(
extern PKPROCESS CsrProcess; extern PKPROCESS CsrProcess;
extern ULONG VideoPortDeviceNumber; extern ULONG VideoPortDeviceNumber;
extern BOOLEAN VideoPortUseNewKey; extern BOOLEAN VideoPortUseNewKey;
extern KMUTEX VideoPortInt10Mutex;
extern KSPIN_LOCK HwResetAdaptersLock; extern KSPIN_LOCK HwResetAdaptersLock;
extern LIST_ENTRY HwResetAdaptersList; extern LIST_ENTRY HwResetAdaptersList;
@@ -298,43 +298,52 @@ IntVideoPortEnumerateChildren(
/* int10.c */ /* int10.c */
#ifdef _M_IX86
extern BOOLEAN VideoPortDisableX86Emulator;
#endif
extern KMUTEX VideoPortInt10Mutex;
NTSTATUS NTSTATUS
IntInitializeInt10(VOID);
VP_STATUS
NTAPI NTAPI
IntInitializeVideoAddressSpace(VOID);
VP_STATUS NTAPI
IntInt10AllocateBuffer( IntInt10AllocateBuffer(
IN PVOID Context, _In_ PVOID Context,
OUT PUSHORT Seg, _Out_ PUSHORT Seg,
OUT PUSHORT Off, _Out_ PUSHORT Off,
IN OUT PULONG Length); _Inout_ PULONG Length);
VP_STATUS NTAPI VP_STATUS
NTAPI
IntInt10FreeBuffer( IntInt10FreeBuffer(
IN PVOID Context, _In_ PVOID Context,
IN USHORT Seg, _In_ USHORT Seg,
IN USHORT Off); _In_ USHORT Off);
VP_STATUS NTAPI VP_STATUS
NTAPI
IntInt10ReadMemory( IntInt10ReadMemory(
IN PVOID Context, _In_ PVOID Context,
IN USHORT Seg, _In_ USHORT Seg,
IN USHORT Off, _In_ USHORT Off,
OUT PVOID Buffer, _Out_writes_bytes_(Length) PVOID Buffer,
IN ULONG Length); _In_ ULONG Length);
VP_STATUS NTAPI VP_STATUS
NTAPI
IntInt10WriteMemory( IntInt10WriteMemory(
IN PVOID Context, _In_ PVOID Context,
IN USHORT Seg, _In_ USHORT Seg,
IN USHORT Off, _In_ USHORT Off,
IN PVOID Buffer, _In_reads_bytes_(Length) PVOID Buffer,
IN ULONG Length); _In_ ULONG Length);
VP_STATUS NTAPI VP_STATUS
NTAPI
IntInt10CallBios( IntInt10CallBios(
IN PVOID Context, _In_ PVOID Context,
IN OUT PINT10_BIOS_ARGUMENTS BiosArguments); _Inout_ PINT10_BIOS_ARGUMENTS BiosArguments);
/* registry.c */ /* registry.c */
@@ -368,5 +377,4 @@ IntCreateRegistryPath(
IN ULONG DeviceNumber, IN ULONG DeviceNumber,
OUT PUNICODE_STRING DeviceRegistryPath); OUT PUNICODE_STRING DeviceRegistryPath);
#endif /* VIDEOPRT_H */ #endif /* VIDEOPRT_H */