You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2125 lines
58 KiB
2125 lines
58 KiB
/*++
|
|
|
|
Copyright (c) 1990-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
porti386.c
|
|
|
|
Abstract:
|
|
|
|
This is the x86 specific part of the video port driver.
|
|
|
|
Author:
|
|
|
|
Andre Vachon (andreva) 10-Jan-1991
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
This module is a driver which implements OS dependant functions on the
|
|
behalf of the video drivers
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "videoprt.h"
|
|
#include "vdm.h"
|
|
|
|
//#include "..\..\..\nthals\x86new\xm86.h"
|
|
//#include "..\..\..\nthals\x86new\x86new.h"
|
|
|
|
VP_STATUS
|
|
SymmetryDeviceDataCallback(
|
|
PVOID HwDeviceExtension,
|
|
PVOID Context,
|
|
VIDEO_DEVICE_DATA_TYPE DeviceDataType,
|
|
PVOID Identifier,
|
|
ULONG IdentifierLength,
|
|
PVOID ConfigurationData,
|
|
ULONG ConfigurationDataLength,
|
|
PVOID ComponentInformation,
|
|
ULONG ComponentInformationLength
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,pVideoPortEnableVDM)
|
|
#pragma alloc_text(PAGE,pVideoPortInitializeInt10)
|
|
#pragma alloc_text(PAGE,VideoPortInt10)
|
|
#pragma alloc_text(PAGE,SymmetryDeviceDataCallback)
|
|
#pragma alloc_text(PAGE,pVideoPortRegisterVDM)
|
|
#pragma alloc_text(PAGE,pVideoPortSetIOPM)
|
|
#pragma alloc_text(PAGE,VideoPortSetTrappedEmulatorPorts)
|
|
#pragma alloc_text(PAGE,VpInt10AllocateBuffer)
|
|
#pragma alloc_text(PAGE,VpInt10FreeBuffer)
|
|
#pragma alloc_text(PAGE,VpInt10ReadMemory)
|
|
#pragma alloc_text(PAGE,VpInt10WriteMemory)
|
|
#pragma alloc_text(PAGE,VpInt10CallBios)
|
|
#pragma alloc_text(PAGE,pVideoPortGetVDMBiosData)
|
|
#pragma alloc_text(PAGE,pVideoPortPutVDMBiosData)
|
|
#endif
|
|
|
|
|
|
VP_STATUS
|
|
SymmetryDeviceDataCallback(
|
|
PVOID HwDeviceExtension,
|
|
PVOID Context,
|
|
VIDEO_DEVICE_DATA_TYPE DeviceDataType,
|
|
PVOID Identifier,
|
|
ULONG IdentifierLength,
|
|
PVOID ConfigurationData,
|
|
ULONG ConfigurationDataLength,
|
|
PVOID ComponentInformation,
|
|
ULONG ComponentInformationLength
|
|
)
|
|
{
|
|
|
|
if (RtlCompareMemory(L"SEQUENT Symmetry",
|
|
Identifier,
|
|
sizeof(L"SEQUENT Symmetry")) ==
|
|
sizeof(L"SEQUENT Symmetry"))
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
pVideoPortEnableVDM(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN BOOLEAN Enable,
|
|
IN PVIDEO_VDM VdmInfo,
|
|
IN ULONG VdmInfoSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allows the kernel video driver to hook out I/O ports or
|
|
specific interrupts from the V86 fault handler. Operations on the
|
|
specified ports which are intercepted by the V86 fault handler will be
|
|
forwarded to the kernel driver directly.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Pointer to the port driver's device extension.
|
|
|
|
Enable - Determines if the VDM should be enabled (TRUE) or disabled
|
|
(FALSE).
|
|
|
|
VdmInfo - Pointer to the VdmInfo passed by the caller.
|
|
|
|
VdmInfoSize - Size of the VdmInfo struct passed by the caller.
|
|
|
|
Return Value:
|
|
|
|
Return the value returned by ZwSetInformationProcess().
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PROCESS_IO_PORT_HANDLER_INFORMATION processHandlerInfo;
|
|
NTSTATUS ntStatus;
|
|
PEPROCESS process;
|
|
PVOID virtualAddress;
|
|
ULONG length;
|
|
ULONG defaultMask = 0;
|
|
ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY |
|
|
VIDEO_MEMORY_SPACE_USER_MODE;
|
|
|
|
//
|
|
// Must make sure the caller is a trusted subsystem with the
|
|
// appropriate privilege level before executing this call.
|
|
// If the calls returns FALSE we must return an error code.
|
|
//
|
|
|
|
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
|
|
SE_TCB_PRIVILEGE),
|
|
FdoExtension->CurrentIrpRequestorMode)) {
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
}
|
|
|
|
//
|
|
// Test to see if the parameter size is valid
|
|
//
|
|
|
|
if (VdmInfoSize < sizeof(VIDEO_VDM) ) {
|
|
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the enable flag in the process struct and put in the length and
|
|
// pointer to the emulator info struct.
|
|
//
|
|
|
|
if (Enable) {
|
|
|
|
processHandlerInfo.Install = TRUE;
|
|
|
|
} else {
|
|
|
|
processHandlerInfo.Install = FALSE;
|
|
|
|
}
|
|
|
|
processHandlerInfo.NumEntries =
|
|
FdoExtension->NumEmulatorAccessEntries;
|
|
processHandlerInfo.EmulatorAccessEntries =
|
|
FdoExtension->EmulatorAccessEntries;
|
|
processHandlerInfo.Context = FdoExtension->EmulatorAccessEntriesContext;
|
|
|
|
|
|
//
|
|
// Call SetInformationProcess
|
|
//
|
|
|
|
ntStatus = ZwSetInformationProcess(VdmInfo->ProcessHandle,
|
|
ProcessIoPortHandlers,
|
|
&processHandlerInfo,
|
|
sizeof(PROCESS_IO_PORT_HANDLER_INFORMATION));
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
return ntStatus;
|
|
|
|
}
|
|
|
|
//
|
|
// If we are disabling the DOS application, give it the original IOPM
|
|
// it had (which is mask zero.
|
|
// If we are enabling it, then wait for the miniport to call to set it up
|
|
// appropriately.
|
|
//
|
|
|
|
ntStatus = ObReferenceObjectByHandle(VdmInfo->ProcessHandle,
|
|
0,
|
|
*(PVOID *)PsProcessType,
|
|
FdoExtension->CurrentIrpRequestorMode,
|
|
(PVOID *)&process,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
if (Enable) {
|
|
|
|
defaultMask = 1;
|
|
|
|
//
|
|
// This will be used later while saving the hardware state
|
|
//
|
|
|
|
FdoExtension->VdmProcess = process;
|
|
|
|
} // otherwise we are disabling and the mask number is 0;
|
|
|
|
if (!Ke386IoSetAccessProcess(PEProcessToPKProcess(process),
|
|
defaultMask)) {
|
|
|
|
ntStatus = STATUS_IO_PRIVILEGE_FAILED;
|
|
|
|
}
|
|
|
|
ObDereferenceObject(process);
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
if (Enable) {
|
|
|
|
processHandlerInfo.Install = FALSE;
|
|
|
|
ZwSetInformationProcess(VdmInfo->ProcessHandle,
|
|
ProcessIoPortHandlers,
|
|
&processHandlerInfo,
|
|
sizeof(PROCESS_IO_PORT_HANDLER_INFORMATION));
|
|
|
|
}
|
|
|
|
return ntStatus;
|
|
|
|
}
|
|
|
|
//
|
|
// We can now map (or unmap) the video frame buffer into the VDM's
|
|
// address space.
|
|
//
|
|
|
|
virtualAddress = (PVOID) FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart;
|
|
|
|
//
|
|
// Override this with A0000 for the Sequent Symmetry machine.
|
|
//
|
|
|
|
if (VideoPortGetDeviceData(FdoExtension->HwDeviceExtension,
|
|
VpMachineData,
|
|
&SymmetryDeviceDataCallback,
|
|
NULL) == NO_ERROR)
|
|
{
|
|
virtualAddress = (PVOID) 0xA0000;
|
|
}
|
|
|
|
length = FdoExtension->VdmPhysicalVideoMemoryLength;
|
|
|
|
if (Enable) {
|
|
|
|
return pVideoPortMapUserPhysicalMem(FdoExtension,
|
|
VdmInfo->ProcessHandle,
|
|
FdoExtension->VdmPhysicalVideoMemoryAddress,
|
|
&length,
|
|
&inIoSpace,
|
|
(PVOID *) &virtualAddress);
|
|
|
|
} else {
|
|
|
|
return ZwUnmapViewOfSection(VdmInfo->ProcessHandle,
|
|
(PVOID)( ((ULONG)virtualAddress) & (~(PAGE_SIZE - 1))) );
|
|
|
|
}
|
|
} // pVideoPortEnableVDM()
|
|
|
|
VP_STATUS
|
|
VpInt10AllocateBuffer(
|
|
IN PVOID Context,
|
|
OUT PUSHORT Seg,
|
|
OUT PUSHORT Off,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
{
|
|
VP_STATUS Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (Int10BufferAllocated == FALSE) {
|
|
|
|
if (*Length <= 0x1000) {
|
|
|
|
*Seg = VDM_TRANSFER_SEGMENT;
|
|
*Off = VDM_TRANSFER_OFFSET;
|
|
|
|
Int10BufferAllocated = TRUE;
|
|
|
|
Status = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
*Length = VDM_TRANSFER_LENGTH;
|
|
return Status;
|
|
}
|
|
|
|
VP_STATUS
|
|
VpInt10FreeBuffer(
|
|
IN PVOID Context,
|
|
IN USHORT Seg,
|
|
IN USHORT Off
|
|
)
|
|
|
|
{
|
|
VP_STATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if ((VDM_TRANSFER_SEGMENT == Seg) && (VDM_TRANSFER_OFFSET == Off)) {
|
|
|
|
if (Int10BufferAllocated == TRUE) {
|
|
|
|
Int10BufferAllocated = FALSE;
|
|
Status = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VP_STATUS
|
|
VpInt10ReadMemory(
|
|
IN PVOID Context,
|
|
IN USHORT Seg,
|
|
IN USHORT Off,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length
|
|
)
|
|
|
|
{
|
|
BOOLEAN bAttachProcess = FALSE;
|
|
PVOID Memory = (PVOID)((Seg << 4) + Off);
|
|
VP_STATUS Status = NO_ERROR;
|
|
|
|
if(!CsrProcess) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (PsGetCurrentProcess() != CsrProcess)
|
|
{
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
}
|
|
|
|
try {
|
|
RtlCopyMemory(Buffer, Memory, Length);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VP_STATUS
|
|
VpInt10WriteMemory(
|
|
IN PVOID Context,
|
|
IN USHORT Seg,
|
|
IN USHORT Off,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length
|
|
)
|
|
|
|
{
|
|
BOOLEAN bAttachProcess = FALSE;
|
|
PVOID Memory = (PVOID)((Seg << 4) + Off);
|
|
VP_STATUS Status = NO_ERROR;
|
|
|
|
if(!CsrProcess) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (PsGetCurrentProcess() != CsrProcess)
|
|
{
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
}
|
|
|
|
try {
|
|
RtlCopyMemory(Memory, Buffer, Length);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#define BAD_BIOS_SIGNATURE 0xB105
|
|
|
|
VP_STATUS
|
|
VpInt10CallBios(
|
|
PVOID HwDeviceExtension,
|
|
PINT10_BIOS_ARGUMENTS BiosArguments
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allows a miniport driver to call the kernel to perform
|
|
an int10 operation.
|
|
This will execute natively the BIOS ROM code on the device.
|
|
|
|
THIS FUNCTION IS FOR X86 ONLY.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
|
|
BiosArguments - Pointer to a structure containing the value of the
|
|
basic x86 registers that should be set before calling the BIOS routine.
|
|
0 should be used for unused registers.
|
|
|
|
Return Value:
|
|
|
|
Restrictions:
|
|
|
|
Device uses IO ports ONLY.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS ntStatus;
|
|
CONTEXT context;
|
|
BOOLEAN bAttachProcess = FALSE;
|
|
|
|
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
|
|
|
//
|
|
// Must make sure the caller is a trusted subsystem with the
|
|
// appropriate address space set up.
|
|
//
|
|
|
|
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
|
|
SE_TCB_PRIVILEGE),
|
|
fdoExtension->CurrentIrpRequestorMode)) {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (ServerBiosAddressSpaceInitialized == 0) {
|
|
|
|
ASSERT(FALSE);
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (CsrProcess == 0) {
|
|
|
|
// This might happen if we're shutting down the system.
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (PsGetCurrentProcess() != CsrProcess)
|
|
{
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
}
|
|
|
|
//
|
|
// Zero out the context and initialize the required values with the
|
|
// miniport's requested register values.
|
|
//
|
|
|
|
RtlZeroMemory(&context, sizeof(CONTEXT));
|
|
|
|
context.Edi = BiosArguments->Edi;
|
|
context.Esi = BiosArguments->Esi;
|
|
context.Eax = BiosArguments->Eax;
|
|
context.Ebx = BiosArguments->Ebx;
|
|
context.Ecx = BiosArguments->Ecx;
|
|
context.Edx = BiosArguments->Edx;
|
|
context.Ebp = BiosArguments->Ebp;
|
|
context.SegDs = BiosArguments->SegDs;
|
|
context.SegEs = BiosArguments->SegEs;
|
|
|
|
//
|
|
// Now call the kernel to actually perform the int 10 operation.
|
|
// We wrap thiw with a try/except in case csrss is gone.
|
|
//
|
|
|
|
KeWaitForSingleObject(&VpInt10Mutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PTIME)NULL);
|
|
|
|
try {
|
|
ntStatus = Ke386CallBios(0x10, &context);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ntStatus = GetExceptionCode();
|
|
}
|
|
|
|
KeReleaseMutex(&VpInt10Mutex, FALSE);
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
//
|
|
// fill in struct with any return values from the context
|
|
//
|
|
|
|
BiosArguments->Edi = context.Edi;
|
|
BiosArguments->Esi = context.Esi;
|
|
BiosArguments->Eax = context.Eax;
|
|
BiosArguments->Ebx = context.Ebx;
|
|
BiosArguments->Ecx = context.Ecx;
|
|
BiosArguments->Edx = context.Edx;
|
|
BiosArguments->Ebp = context.Ebp;
|
|
BiosArguments->SegDs = (USHORT)context.SegDs;
|
|
BiosArguments->SegEs = (USHORT)context.SegEs;
|
|
|
|
//
|
|
// Return that status we got when calling the BIOS (writting to the
|
|
// is secondary at best).
|
|
//
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
pVideoDebugPrint ((2, "VIDEOPRT: Int10: Int 10 succeded properly\n"));
|
|
|
|
} else {
|
|
|
|
pVideoDebugPrint ((0, "VIDEOPRT: Int10 failed - status %08lx\n", ntStatus));
|
|
|
|
}
|
|
|
|
if (((BiosArguments->Eax & 0xffff) == 0x014f) &&
|
|
((BiosArguments->Ebx & 0xffff) == BAD_BIOS_SIGNATURE) ) {
|
|
|
|
pVideoDebugPrint ((0, "VIDEOPRT: Video bios error detected at CS:IP = %4x:%4x\n",
|
|
(USHORT) BiosArguments->Ecx, (USHORT) BiosArguments->Edx));
|
|
|
|
ASSERT(FALSE);
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
return ntStatus;
|
|
|
|
}
|
|
|
|
VP_STATUS
|
|
VideoPortInt10(
|
|
PVOID HwDeviceExtension,
|
|
PVIDEO_X86_BIOS_ARGUMENTS BiosArguments
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allows a miniport driver to call the kernel to perform
|
|
an int10 operation.
|
|
This will execute natively the BIOS ROM code on the device.
|
|
|
|
THIS FUNCTION IS FOR X86 ONLY.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
|
|
BiosArguments - Pointer to a structure containing the value of the
|
|
basic x86 registers that should be set before calling the BIOS routine.
|
|
0 should be used for unused registers.
|
|
|
|
Return Value:
|
|
|
|
|
|
Restrictions:
|
|
|
|
Device uses IO ports ONLY.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS ntStatus;
|
|
CONTEXT context;
|
|
BOOLEAN bAttachProcess = FALSE;
|
|
|
|
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
|
|
|
//
|
|
// Must make sure the caller is a trusted subsystem with the
|
|
// appropriate address space set up.
|
|
//
|
|
|
|
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
|
|
SE_TCB_PRIVILEGE),
|
|
fdoExtension->CurrentIrpRequestorMode)) {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (ServerBiosAddressSpaceInitialized == 0) {
|
|
|
|
pVideoDebugPrint((0, "Warning: Attempt to call VideoPortInt10 before Int10 support is initialized.\n"));
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (CsrProcess == 0) {
|
|
|
|
// This might happen if we're shutting down the system.
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (PsGetCurrentProcess() != CsrProcess)
|
|
{
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
}
|
|
|
|
//
|
|
// Zero out the context and initialize the required values with the
|
|
// miniport's requested register values.
|
|
//
|
|
|
|
RtlZeroMemory(&context, sizeof(CONTEXT));
|
|
|
|
context.Edi = BiosArguments->Edi;
|
|
context.Esi = BiosArguments->Esi;
|
|
context.Eax = BiosArguments->Eax;
|
|
context.Ebx = BiosArguments->Ebx;
|
|
context.Ecx = BiosArguments->Ecx;
|
|
context.Edx = BiosArguments->Edx;
|
|
context.Ebp = BiosArguments->Ebp;
|
|
|
|
//
|
|
// Now call the kernel to actually perform the int 10 operation.
|
|
// We wrap thiw with a try/except in case csrss is gone.
|
|
// And we need to protect Ke386CallBios from reentrance.
|
|
//
|
|
|
|
KeWaitForSingleObject(&VpInt10Mutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PTIME)NULL);
|
|
|
|
try {
|
|
ntStatus = Ke386CallBios(0x10, &context);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ntStatus = GetExceptionCode();
|
|
}
|
|
|
|
KeReleaseMutex(&VpInt10Mutex, FALSE);
|
|
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
//
|
|
// fill in struct with any return values from the context
|
|
//
|
|
|
|
BiosArguments->Edi = context.Edi;
|
|
BiosArguments->Esi = context.Esi;
|
|
BiosArguments->Eax = context.Eax;
|
|
BiosArguments->Ebx = context.Ebx;
|
|
BiosArguments->Ecx = context.Ecx;
|
|
BiosArguments->Edx = context.Edx;
|
|
BiosArguments->Ebp = context.Ebp;
|
|
|
|
//
|
|
// Return that status we got when calling the BIOS (writting to the
|
|
// is secondary at best).
|
|
//
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
pVideoDebugPrint ((2, "VIDEOPRT: Int10: Int 10 succeded properly\n"));
|
|
|
|
} else {
|
|
|
|
pVideoDebugPrint ((0, "VIDEOPRT: Int10 failed - status %08lx\n", ntStatus));
|
|
|
|
}
|
|
|
|
if (((BiosArguments->Eax & 0xffff) == 0x014f) &&
|
|
((BiosArguments->Ebx & 0xffff) == BAD_BIOS_SIGNATURE) ) {
|
|
|
|
pVideoDebugPrint ((0, "VIDEOPRT: Video bios error detected at CS:IP = %4x:%4x\n",
|
|
(USHORT) BiosArguments->Ecx, (USHORT) BiosArguments->Edx));
|
|
|
|
ASSERT(FALSE);
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// We have to return NO_ERROR even when we failed the int10,
|
|
// because some drivers expect us to always return NO_ERROR.
|
|
return NO_ERROR;
|
|
|
|
} // end VideoPortInt10()
|
|
|
|
//
|
|
// Internal definitions
|
|
//
|
|
|
|
#define KEY_VALUE_BUFFER_SIZE 1024
|
|
#define ONE_MEG 0x100000
|
|
#define ROM_BIOS_START 0xC0000
|
|
#define VIDEO_BUFFER_START 0xA0000
|
|
#define DOS_LOADED_ADDRESS 0x700
|
|
#define EBIOS_AREA_INFORMATION 0x40
|
|
#define INT00_VECTOR_ADDRESS (0x00*4)
|
|
#define INTCD_VECTOR_ADDRESS (0xCD*4)
|
|
#define INT1A_VECTOR_ADDRESS (0x1A*4)
|
|
#define ERROR_HANDLER_SEGMENT 0x3000
|
|
#define ERROR_HANDLER_OFFSET 0x0
|
|
|
|
typedef struct _EBIOS_INFORMATION {
|
|
ULONG EBiosAddress;
|
|
ULONG EBiosSize;
|
|
} EBIOS_INFORMATION, *PEBIOS_INFORMATION;
|
|
|
|
UCHAR ErrorHandler[] = {
|
|
0x89, 0xe5, // mov bp, sp
|
|
0xb8, 0x4f, 0x01, // mov ax, 0x014f
|
|
0xbb, 0x05, 0xb1, // mov bx, BAD_BIOS_SIGNATURE
|
|
0x8b, 0x56, 0x00, // mov dx,[bp]
|
|
0x8b, 0x4e, 0x02, // mov cx,[bp+0x2]
|
|
0xc4, 0xc4, 0xfe, // BOP 0xfe
|
|
0xcf // iret
|
|
};
|
|
|
|
VOID
|
|
pVideoPortInitializeInt10(
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the CSR address space so we can do an int 10.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
|
|
Return Value:
|
|
|
|
|
|
Restrictions:
|
|
|
|
THIS FUNCTION IS FOR X86 ONLY.
|
|
|
|
THIS FUNCTION MUST BE RUN IN THE CONTEXT OF CSR
|
|
|
|
This function goes thru ROM BIOS area to map in all the ROM blocks and
|
|
allocates memory for the holes inside the BIOS area. The reason we
|
|
allocate memory for the holes in BIOS area is because some int 10 BIOS
|
|
code touches the nonexisting memory. Under Nt, this triggers page fault
|
|
and the int 10 is terminated.
|
|
|
|
Note: the code is adapted from VdmpInitialize().
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS ntStatus;
|
|
|
|
ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY |
|
|
VIDEO_MEMORY_SPACE_USER_MODE;
|
|
PVOID virtualAddress;
|
|
ULONG length;
|
|
ULONG size;
|
|
PVOID baseAddress;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING SectionName;
|
|
UNICODE_STRING WorkString;
|
|
ULONG ViewSize;
|
|
LARGE_INTEGER ViewBase;
|
|
PVOID BaseAddress;
|
|
PVOID destination;
|
|
HANDLE SectionHandle, RegistryHandle;
|
|
ULONG ResultLength, EndingAddress;
|
|
ULONG Index;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueBuffer;
|
|
CM_ROM_BLOCK RomBlock;
|
|
PCM_ROM_BLOCK BiosBlock;
|
|
ULONG LastMappedAddress;
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
PHYSICAL_ADDRESS PhysicalAddressLow, PhysicalAddressHigh, BoundaryAddress;
|
|
ULONG AddressSpace = VIDEO_MEMORY_SPACE_MEMORY;
|
|
ULONG dwCrc = 0xFFFFFFFF;
|
|
PULONG ExtendedBiosLocationInfo;
|
|
ULONG ExtendedBiosAddress, ExtendedBiosSize, *IntVectorAddress;
|
|
ULONG Int1ACodeAddress;
|
|
BOOLEAN Int1AIsValid = FALSE;
|
|
|
|
//
|
|
// NOTE Due to the way compiler optimization code works, I have
|
|
// to declare EBiosInformation to be volatile. Otherwise, no
|
|
// code will be generated for the EBiosInformation.
|
|
// It should be removed once the C compiler is fixed.
|
|
//
|
|
volatile PEBIOS_INFORMATION EBiosInformation = (PEBIOS_INFORMATION)
|
|
(DOS_LOADED_ADDRESS + EBIOS_AREA_INFORMATION);
|
|
BOOLEAN EBiosInitialized = FALSE;
|
|
|
|
//
|
|
// If we have already initialized, or for some reason can not, return
|
|
// right here.
|
|
//
|
|
|
|
if ((ServerBiosAddressSpaceInitialized == 1) ||
|
|
(VpC0000Compatible == 0) ||
|
|
(FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart == 0) ||
|
|
(CsrProcess == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// It is possible that this routine will end up failing below if
|
|
// the 0xA0000 memory range isn't visible to the current display device.
|
|
// However, failing half way through the routine is bad because we've
|
|
// already done the MEM_COMMIT in csrss. So a subsequent call will
|
|
// also fail. So lets try to determine now if we are going to fail.
|
|
// This is easier than backing out changes if we do fail!
|
|
//
|
|
|
|
if (!HalTranslateBusAddress(FdoExtension->AdapterInterfaceType,
|
|
FdoExtension->SystemIoBusNumber,
|
|
FdoExtension->VdmPhysicalVideoMemoryAddress,
|
|
&AddressSpace,
|
|
&PhysicalAddress)) {
|
|
|
|
pVideoDebugPrint((1, "This device isn't the VGA.\n"));
|
|
return;
|
|
}
|
|
|
|
size = 0x00100000 - 1; // 1 MEG
|
|
|
|
//
|
|
// We pass an address of 1, so Memory Management will round it down to 0.
|
|
// if we passed in 0, memory management would think the argument was
|
|
// not present.
|
|
//
|
|
|
|
baseAddress = (PVOID) 0x00000001;
|
|
|
|
// N.B. We expect that process creation has reserved the first 16 MB
|
|
// for us already. If not, then this won't work worth a darn
|
|
|
|
ntStatus = ZwAllocateVirtualMemory( NtCurrentProcess(),
|
|
&baseAddress,
|
|
0L,
|
|
&size,
|
|
MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE );
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
pVideoDebugPrint ((1, "VIDEOPRT: Int10: Failed to allocate 1MEG of memory for the VDM\n"));
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Map in the physical memory into the caller's address space so that
|
|
// any memory references from the BIOS will work properly.
|
|
//
|
|
|
|
virtualAddress = (PVOID) FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart;
|
|
length = FdoExtension->VdmPhysicalVideoMemoryLength;
|
|
|
|
ntStatus = ZwFreeVirtualMemory(NtCurrentProcess(),
|
|
&virtualAddress,
|
|
&length,
|
|
MEM_RELEASE);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
pVideoDebugPrint ((1, "VIDEOPRT: Int10: Failed to free memory space for video memory to be mapped\n"));
|
|
return;
|
|
|
|
}
|
|
|
|
virtualAddress = (PVOID) FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart;
|
|
length = FdoExtension->VdmPhysicalVideoMemoryLength;
|
|
|
|
ntStatus = pVideoPortMapUserPhysicalMem(FdoExtension,
|
|
NtCurrentProcess(),
|
|
FdoExtension->VdmPhysicalVideoMemoryAddress,
|
|
&length,
|
|
&inIoSpace,
|
|
&virtualAddress);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
pVideoDebugPrint ((1, "VIDEOPRT: Int10: Failed to Map video memory in address space\n"));
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the default bios block which will be used if we can NOT
|
|
// find any valid bios block.
|
|
//
|
|
|
|
RomBlock.Address = ROM_BIOS_START;
|
|
RomBlock.Size = 0x40000;
|
|
BiosBlock = &RomBlock;
|
|
Index = 1;
|
|
|
|
RtlInitUnicodeString(
|
|
&SectionName,
|
|
L"\\Device\\PhysicalMemory"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&SectionName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL
|
|
);
|
|
|
|
ntStatus = ZwOpenSection(
|
|
&SectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the first unused memory with "int cd" so we will catch
|
|
// a bios that starts executing from this region by hooking up our
|
|
// own int cd code.
|
|
//
|
|
|
|
memset(0, 0xCD, 0xa0000);
|
|
|
|
//
|
|
// Copy the first page of physical memory into the CSR's address space
|
|
//
|
|
|
|
BaseAddress = 0;
|
|
destination = 0;
|
|
ViewSize = 0x1000;
|
|
ViewBase.LowPart = 0;
|
|
ViewBase.HighPart = 0;
|
|
|
|
ntStatus =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
|
|
}
|
|
|
|
#pragma prefast(suppress:11, "We ARE using a NULL pointer here (PREfast bug 531472)")
|
|
RtlMoveMemory(
|
|
destination,
|
|
BaseAddress,
|
|
ViewSize
|
|
);
|
|
|
|
//
|
|
// Copy the info from 0x700 to 0x717 into the registry.
|
|
// These correspond to the 6 font pointers needed for
|
|
// vdm support.
|
|
//
|
|
// Note: Will not return if registry calls fail. This
|
|
// function needs to continue; it would be bad if we
|
|
// could not perform an int 0x10.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&WorkString,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wow"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&WorkString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
(HANDLE)NULL,
|
|
NULL
|
|
);
|
|
|
|
ntStatus = ZwOpenKey(
|
|
&RegistryHandle,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
RtlInitUnicodeString(
|
|
&WorkString,
|
|
L"RomFontPointers"
|
|
);
|
|
|
|
destination = (PVOID) 0x700;
|
|
|
|
ntStatus = ZwSetValueKey(
|
|
RegistryHandle,
|
|
&WorkString,
|
|
0,
|
|
REG_BINARY,
|
|
destination,
|
|
24
|
|
);
|
|
|
|
//
|
|
// We won't return here if this fails. The function should
|
|
// continue in order to enable int 0x10 support.
|
|
//
|
|
|
|
ZwClose(RegistryHandle);
|
|
|
|
}
|
|
|
|
ntStatus = ZwUnmapViewOfSection(
|
|
NtCurrentProcess(),
|
|
BaseAddress
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Hook error handler to int 0
|
|
//
|
|
|
|
IntVectorAddress = (ULONG *) (INT00_VECTOR_ADDRESS);
|
|
|
|
#pragma prefast(suppress:11, "We ARE using a NULL pointer here (PREfast bug 531472)")
|
|
if(*IntVectorAddress >= 0xF0000000) {
|
|
|
|
//
|
|
// Only replace the int0 handler if it is pointing to F000 segment
|
|
// where system bios lives
|
|
//
|
|
|
|
RtlMoveMemory((PVOID)((ERROR_HANDLER_SEGMENT << 4) | ERROR_HANDLER_OFFSET),
|
|
ErrorHandler,
|
|
sizeof(ErrorHandler)
|
|
);
|
|
|
|
#pragma prefast(suppress:11, "We ARE using a NULL pointer here (PREfast bug 531472)")
|
|
*IntVectorAddress =
|
|
(ERROR_HANDLER_SEGMENT << 16) | ERROR_HANDLER_OFFSET;
|
|
}
|
|
|
|
//
|
|
// Hook error handler to int cd
|
|
//
|
|
|
|
IntVectorAddress = (ULONG *) (INTCD_VECTOR_ADDRESS);
|
|
|
|
if(*IntVectorAddress == 0) {
|
|
|
|
RtlMoveMemory((PVOID)((ERROR_HANDLER_SEGMENT << 4) | ERROR_HANDLER_OFFSET),
|
|
ErrorHandler,
|
|
sizeof(ErrorHandler)
|
|
);
|
|
|
|
*IntVectorAddress =
|
|
(ERROR_HANDLER_SEGMENT << 16) | ERROR_HANDLER_OFFSET;
|
|
}
|
|
|
|
{
|
|
USHORT seg, offset;
|
|
|
|
offset = *(USHORT *)(INT1A_VECTOR_ADDRESS);
|
|
seg = *(USHORT *)(INT1A_VECTOR_ADDRESS + 2);
|
|
|
|
Int1ACodeAddress = (seg << 4) + offset;
|
|
Int1AIsValid = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the exteneded Bios region into the CSR's address space
|
|
//
|
|
|
|
ExtendedBiosLocationInfo = (PVOID) EXTENDED_BIOS_INFO_LOCATION;
|
|
ExtendedBiosAddress = *ExtendedBiosLocationInfo++;
|
|
ExtendedBiosSize = *ExtendedBiosLocationInfo;
|
|
|
|
//
|
|
// Round to page boundary
|
|
//
|
|
|
|
ExtendedBiosSize += (ExtendedBiosAddress & (PAGE_SIZE - 1));
|
|
ExtendedBiosAddress &= ~(PAGE_SIZE - 1);
|
|
|
|
if (ExtendedBiosSize) {
|
|
|
|
BaseAddress = 0;
|
|
destination = (PVOID) ExtendedBiosAddress;
|
|
ViewSize = ExtendedBiosSize;
|
|
ViewBase.LowPart = ExtendedBiosAddress;
|
|
ViewBase.HighPart = 0;
|
|
|
|
ntStatus = ZwMapViewOfSection(SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE);
|
|
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
}
|
|
|
|
RtlMoveMemory(destination, BaseAddress, ViewSize);
|
|
|
|
ntStatus = ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
}
|
|
|
|
if(Int1ACodeAddress >= ExtendedBiosAddress &&
|
|
Int1ACodeAddress < ExtendedBiosAddress + ExtendedBiosSize) {
|
|
Int1AIsValid = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the e000:0000 segment of physical memory into the CSR's address space
|
|
// This is because some bios code can live in the e000:0000 segment.
|
|
//
|
|
// We are doing a copy instead of mapping the physical e000:0000 segment
|
|
// because we don't know how the real e000:0000 segment will be used in
|
|
// all machines.
|
|
//
|
|
// See bugbug comment in \nt\base\hals\x86new\x86bios.c. we are adding
|
|
// this to be consisten with that code. JeffHa added that code.
|
|
//
|
|
// Should we just copy the whole 640K?
|
|
//
|
|
|
|
BaseAddress = 0;
|
|
destination = (PVOID) 0xe0000;
|
|
ViewSize = 0x10000;
|
|
ViewBase.LowPart = 0xe0000;
|
|
ViewBase.HighPart = 0;
|
|
|
|
ntStatus =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
destination,
|
|
BaseAddress,
|
|
ViewSize
|
|
);
|
|
|
|
ntStatus = ZwUnmapViewOfSection(
|
|
NtCurrentProcess(),
|
|
BaseAddress
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
}
|
|
|
|
if(Int1ACodeAddress >= (ULONG)destination &&
|
|
Int1ACodeAddress < (ULONG)destination + ViewSize) {
|
|
Int1AIsValid = TRUE;
|
|
}
|
|
|
|
//
|
|
// Set up and open KeyPath
|
|
//
|
|
RtlInitUnicodeString(
|
|
&WorkString,
|
|
L"\\Registry\\Machine\\Hardware\\Description\\System"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&WorkString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
(HANDLE)NULL,
|
|
NULL
|
|
);
|
|
|
|
ntStatus = ZwOpenKey(
|
|
&RegistryHandle,
|
|
KEY_READ,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
ZwClose(SectionHandle);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the data
|
|
//
|
|
|
|
KeyValueBuffer = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
KEY_VALUE_BUFFER_SIZE,
|
|
VP_TAG
|
|
);
|
|
|
|
if (KeyValueBuffer == NULL) {
|
|
ZwClose(SectionHandle);
|
|
ZwClose(RegistryHandle);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the data for the rom information
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&WorkString,
|
|
L"Configuration Data"
|
|
);
|
|
|
|
ntStatus = ZwQueryValueKey(
|
|
RegistryHandle,
|
|
&WorkString,
|
|
KeyValueFullInformation,
|
|
KeyValueBuffer,
|
|
KEY_VALUE_BUFFER_SIZE,
|
|
&ResultLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
ZwClose(SectionHandle);
|
|
ZwClose(RegistryHandle);
|
|
ExFreePool(KeyValueBuffer);
|
|
return;
|
|
}
|
|
|
|
ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
|
((PUCHAR) KeyValueBuffer + KeyValueBuffer->DataOffset);
|
|
|
|
if ((KeyValueBuffer->DataLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) &&
|
|
(ResourceDescriptor->PartialResourceList.Count >= 2) ) {
|
|
|
|
PartialResourceDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
((PUCHAR)ResourceDescriptor +
|
|
sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
|
|
ResourceDescriptor->PartialResourceList.PartialDescriptors[0]
|
|
.u.DeviceSpecificData.DataSize);
|
|
|
|
if (KeyValueBuffer->DataLength >= ((PUCHAR)PartialResourceDescriptor -
|
|
(PUCHAR)ResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
+ sizeof(CM_ROM_BLOCK))) {
|
|
BiosBlock = (PCM_ROM_BLOCK)((PUCHAR)PartialResourceDescriptor +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
|
|
Index = PartialResourceDescriptor->u.DeviceSpecificData.DataSize /
|
|
sizeof(CM_ROM_BLOCK);
|
|
}
|
|
}
|
|
|
|
//
|
|
// First check if there is any Extended BIOS Data area. If yes, we need
|
|
// to map in the physical memory and copy the content to our virtual addr.
|
|
//
|
|
|
|
LastMappedAddress = 0;
|
|
while (Index && BiosBlock->Address < ROM_BIOS_START) {
|
|
EBiosInitialized = TRUE;
|
|
destination = (PVOID)(BiosBlock->Address & ~(PAGE_SIZE - 1));
|
|
BaseAddress = (PVOID)0;
|
|
EndingAddress = (BiosBlock->Address + BiosBlock->Size + PAGE_SIZE - 1) &
|
|
~(PAGE_SIZE - 1);
|
|
ViewSize = EndingAddress - (ULONG)destination;
|
|
|
|
if ((ULONG)destination < LastMappedAddress) {
|
|
if (ViewSize > (LastMappedAddress - (ULONG)destination)) {
|
|
ViewSize = ViewSize - (LastMappedAddress - (ULONG)destination);
|
|
destination = (PVOID)LastMappedAddress;
|
|
} else {
|
|
ViewSize = 0;
|
|
}
|
|
}
|
|
if (ViewSize > 0) {
|
|
ViewBase.LowPart = (ULONG)destination;
|
|
ViewBase.HighPart = 0;
|
|
|
|
ntStatus =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
ViewSize = EndingAddress - (ULONG)destination; // only copy what we need
|
|
LastMappedAddress = (ULONG)destination + ViewSize;
|
|
RtlMoveMemory(destination, BaseAddress, ViewSize);
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
|
|
if(Int1ACodeAddress >= (ULONG)destination &&
|
|
Int1ACodeAddress < (ULONG)destination + ViewSize) {
|
|
Int1AIsValid = TRUE;
|
|
}
|
|
}
|
|
}
|
|
BiosBlock++;
|
|
Index--;
|
|
}
|
|
|
|
//
|
|
// NOTE - The code should be removed after product 1.
|
|
// Due to some problem in VDM initialization, if we pass EBIOS data
|
|
// area information thru ROM block list, vdm init will fail and our
|
|
// subsequential int10 mode set will fail. This prevents new ntdetect
|
|
// from working with beta versions of NT. To solve this problem, the
|
|
// EBIOS information is passed to VDM with fonts information thru DOS
|
|
// loaded area.
|
|
//
|
|
// We've shipped two products (about to be 3) and this works fine,
|
|
// don't mess with it.
|
|
//
|
|
|
|
if (EBiosInitialized == FALSE &&
|
|
EBiosInformation->EBiosAddress != 0 &&
|
|
EBiosInformation->EBiosAddress <= VIDEO_BUFFER_START &&
|
|
EBiosInformation->EBiosSize != 0 &&
|
|
(EBiosInformation->EBiosSize & 0x3ff) == 0 &&
|
|
EBiosInformation->EBiosSize < 0x40000) {
|
|
EndingAddress = EBiosInformation->EBiosAddress +
|
|
EBiosInformation->EBiosSize;
|
|
if (EndingAddress <= VIDEO_BUFFER_START &&
|
|
(EndingAddress & 0x3FF) == 0) {
|
|
destination = (PVOID)(EBiosInformation->EBiosAddress & ~(PAGE_SIZE - 1));
|
|
BaseAddress = (PVOID)0;
|
|
EndingAddress = (EndingAddress + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
|
|
ViewSize = EndingAddress - (ULONG)destination;
|
|
|
|
ViewBase.LowPart = (ULONG)destination;
|
|
ViewBase.HighPart = 0;
|
|
|
|
ntStatus =ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
ViewSize = EndingAddress - (ULONG)destination; // only copy what we need
|
|
RtlMoveMemory(destination, BaseAddress, ViewSize);
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
|
|
if(Int1ACodeAddress >= (ULONG)destination &&
|
|
Int1ACodeAddress < (ULONG)destination + ViewSize) {
|
|
Int1AIsValid = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// N.B. Rom blocks begin on 2K (not necessarily page) boundaries
|
|
// They end on 512 byte boundaries. This means that we have
|
|
// to keep track of the last page mapped, and round the next
|
|
// Rom block up to the next page boundary if necessary.
|
|
//
|
|
|
|
LastMappedAddress = ROM_BIOS_START;
|
|
|
|
while (Index) {
|
|
if ((Index > 1) &&
|
|
((BiosBlock->Address + BiosBlock->Size) == BiosBlock[1].Address)) {
|
|
|
|
//
|
|
// Coalesce adjacent blocks
|
|
//
|
|
|
|
BiosBlock[1].Address = BiosBlock[0].Address;
|
|
BiosBlock[1].Size += BiosBlock[0].Size;
|
|
Index--;
|
|
BiosBlock++;
|
|
continue;
|
|
}
|
|
|
|
BaseAddress = (PVOID)(BiosBlock->Address & ~(PAGE_SIZE - 1));
|
|
EndingAddress = (BiosBlock->Address + BiosBlock->Size + PAGE_SIZE - 1) &
|
|
~(PAGE_SIZE - 1);
|
|
ViewSize = EndingAddress - (ULONG)BaseAddress;
|
|
|
|
if ((ULONG)BaseAddress < LastMappedAddress) {
|
|
if (ViewSize > (LastMappedAddress - (ULONG)BaseAddress)) {
|
|
ViewSize = ViewSize - (LastMappedAddress - (ULONG)BaseAddress);
|
|
BaseAddress = (PVOID)LastMappedAddress;
|
|
} else {
|
|
ViewSize = 0;
|
|
}
|
|
}
|
|
ViewBase.LowPart = (ULONG)BaseAddress;
|
|
|
|
if (ViewSize > 0) {
|
|
|
|
//
|
|
// Move FF to the non-ROM area to make it like nonexisting memory
|
|
//
|
|
|
|
#if 0
|
|
if ((ULONG)BaseAddress - LastMappedAddress > 0) {
|
|
RtlFillMemory((PVOID)LastMappedAddress,
|
|
(ULONG)BaseAddress - LastMappedAddress,
|
|
0xFF
|
|
);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// First unmap the reserved memory. This must be done here to prevent
|
|
// the virtual memory in question from being consumed by some other
|
|
// alloc vm call.
|
|
//
|
|
|
|
ntStatus = ZwFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&ViewSize,
|
|
MEM_RELEASE
|
|
);
|
|
|
|
// N.B. This should probably take into account the fact that there are
|
|
// a handfull of error conditions that are ok. (such as no memory to
|
|
// release.)
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ZwClose(SectionHandle);
|
|
ZwClose(RegistryHandle);
|
|
ExFreePool(KeyValueBuffer);
|
|
return;
|
|
|
|
}
|
|
|
|
ntStatus = ZwMapViewOfSection(
|
|
SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&ViewBase,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
break;
|
|
}
|
|
|
|
if(Int1ACodeAddress >= (ULONG)ViewBase.LowPart &&
|
|
Int1ACodeAddress < (ULONG)ViewBase.LowPart + ViewSize) {
|
|
|
|
Int1AIsValid = TRUE;
|
|
}
|
|
|
|
LastMappedAddress = (ULONG)BaseAddress + ViewSize;
|
|
}
|
|
|
|
Index--;
|
|
BiosBlock++;
|
|
}
|
|
|
|
//
|
|
// If some one hooked int1a but didn't report the hooked code as
|
|
// extended bios, we have to set int1a vector to its original value.
|
|
// We've seen many instance of this problem in RIS setup.
|
|
//
|
|
|
|
if(!Int1AIsValid) {
|
|
IntVectorAddress = (ULONG *) INT1A_VECTOR_ADDRESS;
|
|
*IntVectorAddress = 0xF000FE6E;
|
|
}
|
|
|
|
#if 0
|
|
if (LastMappedAddress < ONE_MEG) {
|
|
RtlFillMemory((PVOID)LastMappedAddress,
|
|
(ULONG)ONE_MEG - LastMappedAddress,
|
|
0xFF
|
|
);
|
|
}
|
|
#endif
|
|
|
|
//#if DBG
|
|
// BaseAddress = 0;
|
|
// RegionSize = 0x1000;
|
|
// ZwProtectVirtualMemory ( NtCurrentProcess(),
|
|
// &BaseAddress,
|
|
// &RegionSize,
|
|
// PAGE_NOACCESS,
|
|
// &OldProtect
|
|
// );
|
|
//#endif
|
|
|
|
//
|
|
// Free up the handles
|
|
//
|
|
|
|
ZwClose(SectionHandle);
|
|
ZwClose(RegistryHandle);
|
|
ExFreePool(KeyValueBuffer);
|
|
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
|
|
// Crc324 - Calculate the Crc32 value of a string in 4 bit nibbles.
|
|
//
|
|
// dwCrc - initial value of CRC
|
|
// cbBuffer - count in bytes of length of buffer
|
|
// pbBuffer - pointer to buffer to checksum
|
|
//
|
|
// returns: value of crc32
|
|
//
|
|
// this table is derived from the 256 element CRCTable in
|
|
// \\orville\razzle\src\net\svcdlls\ntlmssp\client\crc32.c
|
|
// This table contains every 16th element since we do 4 bits
|
|
// at a time, not 8
|
|
//
|
|
|
|
{
|
|
ULONG CRCTable4[16] = {
|
|
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
|
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
|
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
|
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
|
};
|
|
|
|
UCHAR byte;
|
|
UCHAR index;
|
|
ULONG cBuffer = 0x1000;
|
|
PUCHAR pBuffer = (PUCHAR) 0x000C0000;
|
|
|
|
while (cBuffer-- != 0)
|
|
{
|
|
byte = *pBuffer++;
|
|
|
|
index = (byte ^ (UCHAR)(dwCrc) ) & 0xf;
|
|
dwCrc = (dwCrc >> 4) ^ CRCTable4[index];
|
|
|
|
byte = byte >> 4;
|
|
index = (byte ^ (UCHAR)(dwCrc) ) & 0xf;
|
|
dwCrc = (dwCrc >> 4) ^ CRCTable4[index];
|
|
}
|
|
|
|
dwCrc ^= 0xFFFFFFFF;
|
|
}
|
|
|
|
KeDetachProcess();
|
|
|
|
//
|
|
// Write the Crc value into the registry.
|
|
//
|
|
|
|
VideoPortSetRegistryParameters(FdoExtension->HwDeviceExtension,
|
|
L"HardwareInformation.Crc32",
|
|
&dwCrc,
|
|
sizeof(ULONG));
|
|
|
|
//
|
|
// Everything worked !
|
|
//
|
|
|
|
ServerBiosAddressSpaceInitialized = 1;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
pVideoPortRegisterVDM(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PVIDEO_VDM VdmInfo,
|
|
IN ULONG VdmInfoSize,
|
|
OUT PVIDEO_REGISTER_VDM RegisterVdm,
|
|
IN ULONG RegisterVdmSize,
|
|
OUT PULONG_PTR OutputSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to register a VDM when it is started up.
|
|
|
|
What this routine does is map the VIDEO BIOS into the VDM address space
|
|
so that DOS apps can use it directly. Since the BIOS is READ_ONLY, we
|
|
have no problem in mapping it as many times as we want.
|
|
|
|
It returns the size of the save state buffer that must be allocated by
|
|
the caller.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Pointer to the port driver's device extension.
|
|
|
|
VdmInfo - Pointer to the VDM information necessary to perform the
|
|
operation.
|
|
|
|
VdmInfoSize - Length of the information buffer.
|
|
|
|
RegisterVdm - Pointer to the output buffer into which the save state
|
|
size is stored.
|
|
|
|
RegisterVdmSize - Length of the passed in output buffer.
|
|
|
|
OutputSize - Pointer to the size of the data stored in the output buffer.
|
|
Can also be the minimum required size of the output buffer is the
|
|
passed in buffer was too small.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the call completed successfully.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Must make sure the caller is a trusted subsystem with the
|
|
// appropriate privilege level before executing this call.
|
|
// If the calls returns FALSE we must return an error code.
|
|
//
|
|
|
|
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
|
|
SE_TCB_PRIVILEGE),
|
|
FdoExtension->CurrentIrpRequestorMode)) {
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
}
|
|
|
|
//
|
|
// Check the size of the output buffer.
|
|
//
|
|
|
|
if (RegisterVdmSize < sizeof(VIDEO_REGISTER_VDM)) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Return the size required for the save/restore state call.
|
|
//
|
|
|
|
*OutputSize = sizeof(VIDEO_REGISTER_VDM);
|
|
RegisterVdm->MinimumStateSize = FdoExtension->HardwareStateSize;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // end pVideoPortRegisterVDM()
|
|
|
|
NTSTATUS
|
|
pVideoPortSetIOPM(
|
|
IN ULONG NumAccessRanges,
|
|
IN PVIDEO_ACCESS_RANGE AccessRange,
|
|
IN BOOLEAN Enable,
|
|
IN ULONG IOPMNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to change the IOPM. It modifies the IOPM based on
|
|
the valid IO ports for the particular device.
|
|
It retrieves the video IOPM mask, changes the access to the I/O ports of
|
|
the specified device and stores the updated mask.
|
|
|
|
-- This call can only be performed if the requesting process has the
|
|
appropriate privileges, as determined by the security subsystem. --
|
|
|
|
Arguments:
|
|
|
|
NumAccessRanges - Number of entries in the array of access ranges.
|
|
|
|
AccessRange - Pointer to the array of access ranges.
|
|
|
|
Enable - Determine if the port listed must be enabled or disabled in the
|
|
mask.
|
|
|
|
IOPMNumber - Number of the mask being manipulated.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the call completed successfully.
|
|
The status from the VideoPortQueryIOPM call if it failed.
|
|
...
|
|
|
|
The return value is also stored in the StatusBlock.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS ntStatus;
|
|
PKIO_ACCESS_MAP accessMap;
|
|
ULONG port;
|
|
ULONG entries;
|
|
|
|
//
|
|
// Retrieve the existing permission mask. If this fails, return
|
|
// immediately.
|
|
//
|
|
|
|
if ((accessMap = (PKIO_ACCESS_MAP)ExAllocatePoolWithTag(NonPagedPool,
|
|
IOPM_SIZE,
|
|
VP_TAG)) == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the kernel map copied into our buffer.
|
|
//
|
|
|
|
if (!Ke386QueryIoAccessMap(IOPMNumber,
|
|
accessMap)) {
|
|
|
|
//
|
|
// An error occured while *accessing* the map in the
|
|
// kernel. Return an error and exit normally.
|
|
//
|
|
|
|
ExFreePool(accessMap);
|
|
|
|
return STATUS_IO_PRIVILEGE_FAILED;
|
|
|
|
}
|
|
|
|
//
|
|
// Give the calling process access to all the IO ports enabled by the
|
|
// miniport driver in the access range.
|
|
//
|
|
|
|
for (entries = 0; entries < NumAccessRanges; entries++) {
|
|
|
|
for (port = AccessRange[entries].RangeStart.LowPart;
|
|
(AccessRange[entries].RangeInIoSpace) &&
|
|
(port < AccessRange[entries].RangeStart.LowPart +
|
|
AccessRange[entries].RangeLength);
|
|
port++) {
|
|
|
|
//
|
|
// Change the port access in the mask:
|
|
// Shift the port address by three to get the index in bytes into
|
|
// the mask. Then take the bottom three bits of the port address
|
|
// and shift 0x01 by that amount to get the right bit in that
|
|
// byte. the bit values are:
|
|
// 0 - access to the port
|
|
// 1 - no access to the port
|
|
//
|
|
|
|
if (Enable && AccessRange[entries].RangeVisible) {
|
|
|
|
//
|
|
// To give access to a port, NAND 1 with the original port.
|
|
// ex: 11111111 ~& 00001000 = 11110111
|
|
// which gives you access to the port who's bit was 1.
|
|
// If the port we are enabling is in the current IOPM mask,
|
|
// return an error instead.
|
|
//
|
|
|
|
(*accessMap)[port >> 3] &= ~(0x01 << (port & 0x07));
|
|
|
|
} else { // disable mask
|
|
|
|
//
|
|
// To remove access to a port, OR 1 with the original port.
|
|
// ex: 11110100 | 00001000 = 11111100
|
|
// which removes access to the port who's bit was 1.
|
|
// If the port we are disabling is not in the current IOPM mask,
|
|
// return an error instead.
|
|
//
|
|
|
|
(*accessMap)[port >> 3] |= (0x01 << (port &0x07));
|
|
|
|
} // if (Enable) ... else
|
|
|
|
} // for (port == ...
|
|
|
|
} // for (entries = 0; ...
|
|
|
|
//
|
|
// If the mask was updated properly, with no errors, set the new mask.
|
|
// Otherwise, leave the existing one.
|
|
//
|
|
|
|
if (Ke386SetIoAccessMap(IOPMNumber,
|
|
accessMap)) {
|
|
|
|
//
|
|
// If the map was created correctly, associate the map to the
|
|
// requesting process. We only need to do this once when the
|
|
// IOPM is first assigned. But we don't know when the first time
|
|
// is.
|
|
//
|
|
|
|
if (Ke386IoSetAccessProcess(PEProcessToPKProcess(PsGetCurrentProcess()),
|
|
IOPMNumber)) {
|
|
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// An error occured while *assigning* the map to
|
|
// the process. Return an error and exit normally.
|
|
//
|
|
|
|
ntStatus = STATUS_IO_PRIVILEGE_FAILED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// An error occured while *creating* the map in the
|
|
// kernel. Return an error and exit normally.
|
|
//
|
|
|
|
ntStatus = STATUS_IO_PRIVILEGE_FAILED;
|
|
|
|
} // if (Ke386Set ...) ... else
|
|
|
|
//
|
|
// Free the memory allocated for the map by the VideoPortQueryIOPM call
|
|
// since the mask has been copied in the kernel TSS.
|
|
//
|
|
|
|
ExFreePool(accessMap);
|
|
|
|
return ntStatus;
|
|
|
|
} // end pVideoPortSetIOPM();
|
|
|
|
VP_STATUS
|
|
VideoPortSetTrappedEmulatorPorts(
|
|
PVOID HwDeviceExtension,
|
|
ULONG NumAccessRanges,
|
|
PVIDEO_ACCESS_RANGE AccessRange
|
|
)
|
|
|
|
/*++
|
|
|
|
VideoPortSetTrappedEmulatorPorts (x86 machines only) allows a miniport
|
|
driver to dynamically change the list of I/O ports that are trapped when
|
|
a VDM is running in full-screen mode. The default set of ports being
|
|
trapped by the miniport driver is defined to be all ports in the
|
|
EMULATOR_ACCESS_ENTRY structure of the miniport driver.
|
|
I/O ports not listed in the EMULATOR_ACCESS_ENTRY structure are
|
|
unavailable to the MS-DOS application. Accessing those ports causes a
|
|
trap to occur in the system, and the I/O operation to be reflected to a
|
|
user-mode virtual device driver.
|
|
|
|
The ports listed in the specified VIDEO_ACCESS_RANGE structure will be
|
|
enabled in the I/O Permission Mask (IOPM) associated with the MS-DOS
|
|
application. This will enable the MS-DOS application to access those I/O
|
|
ports directly, without having the IO instruction trap and be passed down
|
|
to the miniport trap handling functions (for example EmulatorAccessEntry
|
|
functions) for validation. However, the subset of critical IO ports must
|
|
always remain trapped for robustness.
|
|
|
|
All MS-DOS applications use the same IOPM, and therefore the same set of
|
|
enabled/disabled I/O ports. Thus, on each switch of application, the
|
|
set of trapped I/O ports is reinitialized to be the default set of ports
|
|
(all ports in the EMULATOR_ACCESS_ENTRY structure).
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Points to the miniport driver's device extension.
|
|
|
|
NumAccessRanges - Specifies the number of entries in the VIDEO_ACCESS_RANGE
|
|
structure specified in AccessRange.
|
|
|
|
AccessRange - Points to an array of access ranges (VIDEO_ACCESS_RANGE)
|
|
defining the ports that can be untrapped and accessed directly by
|
|
the MS-DOS application.
|
|
|
|
Return Value:
|
|
|
|
This function returns the final status of the operation.
|
|
|
|
Environment:
|
|
|
|
This routine cannot be called from a miniport routine synchronized with
|
|
VideoPortSynchronizeRoutine or from an ISR.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (NT_SUCCESS(pVideoPortSetIOPM(NumAccessRanges,
|
|
AccessRange,
|
|
TRUE,
|
|
1))) {
|
|
|
|
return NO_ERROR;
|
|
|
|
} else {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
} // end VideoPortSetTrappedEmulatorPorts()
|
|
|
|
NTSTATUS
|
|
pVideoPortGetVDMBiosData(
|
|
PFDO_EXTENSION FdoExtension,
|
|
PCHAR Buffer,
|
|
ULONG Length
|
|
)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
BOOLEAN bAttachProcess = FALSE;
|
|
PCHAR Memory;
|
|
ULONG i;
|
|
UCHAR uchar;
|
|
|
|
if(!CsrProcess) return STATUS_INVALID_PARAMETER;
|
|
|
|
ObReferenceObject(FdoExtension->VdmProcess);
|
|
|
|
if (PsGetCurrentProcess() != FdoExtension->VdmProcess) {
|
|
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(FdoExtension->VdmProcess));
|
|
}
|
|
|
|
//
|
|
// Copy over Length bytes from VDM's Bios data area
|
|
//
|
|
|
|
Memory = (PCHAR) 0x400;
|
|
|
|
try {
|
|
RtlCopyMemory(Buffer, Memory, Length);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
NtStatus = GetExceptionCode();
|
|
}
|
|
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
ObDereferenceObject(FdoExtension->VdmProcess);
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
return NtStatus;
|
|
|
|
if (PsGetCurrentProcess() != CsrProcess)
|
|
{
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
}
|
|
|
|
//
|
|
// Replace the Bios data area in CSRSS with that from VDM. At the
|
|
// same time we save the original bios data in CSRSS. The
|
|
// subsequent int10 calls from the driver could get the status
|
|
// of the hardware in VDM environment.
|
|
//
|
|
// We'll improve this when we have a better approach
|
|
//
|
|
|
|
try {
|
|
|
|
for (i = 0; i < Length; i++) {
|
|
uchar = *Memory;
|
|
*Memory++ = Buffer[i];
|
|
Buffer[i] = uchar;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
NtStatus = GetExceptionCode();
|
|
}
|
|
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
pVideoPortPutVDMBiosData(
|
|
PFDO_EXTENSION FdoExtension,
|
|
PCHAR Buffer,
|
|
ULONG Length
|
|
)
|
|
{
|
|
|
|
BOOLEAN bAttachProcess = FALSE;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PCHAR Memory;
|
|
|
|
if(!CsrProcess) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (PsGetCurrentProcess() != CsrProcess) {
|
|
|
|
bAttachProcess = TRUE;
|
|
KeAttachProcess(PEProcessToPKProcess(CsrProcess));
|
|
}
|
|
|
|
//
|
|
// Copy over Length bytes from VDM's Bios data area
|
|
//
|
|
|
|
Memory = (PCHAR) 0x400;
|
|
|
|
try {
|
|
RtlCopyMemory(Memory, Buffer, Length);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
NtStatus = GetExceptionCode();
|
|
}
|
|
|
|
if (bAttachProcess) {
|
|
KeDetachProcess();
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|