reactos/win32ss/drivers/videoprt/int10.c
Jérôme Gardou e46c2dd1b3 [VIDEOPRT] Mark low memory range as NOACCESS when we don't need to access it.
This allows to accomplish great things, such as crashing when dereferencing NULL pointer.
2021-02-10 17:48:30 +01:00

481 lines
14 KiB
C

/*
* VideoPort driver
*
* Copyright (C) 2002, 2003, 2004 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "videoprt.h"
#include <ndk/kefuncs.h>
#include <ndk/halfuncs.h>
#include <ndk/mmfuncs.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
#define IsLowV86Mem(_Seg, _Off) ((((_Seg) << 4) + (_Off)) < (0xa0000))
/* Those two functions below are there so that CSRSS can't access low mem.
* Expecially, MAKE IT CRASH ON NULL ACCESS */
static
VOID
ProtectLowV86Mem(VOID)
{
/* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it
* And we truncate one page to get the right range spanned. */
PVOID BaseAddress = (PVOID)1;
NTSTATUS Status;
SIZE_T ViewSize = 0xa0000 - PAGE_SIZE;
/* We should only do that for CSRSS. */
ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess);
/* Commit (again) the pages, but with PAGE_NOACCESS protection */
Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
&BaseAddress,
0,
&ViewSize,
MEM_COMMIT,
PAGE_NOACCESS);
ASSERT(NT_SUCCESS(Status));
}
static
VOID
UnprotectLowV86Mem(VOID)
{
/* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it
* And we truncate one page to get the right range spanned. */
PVOID BaseAddress = (PVOID)1;
NTSTATUS Status;
SIZE_T ViewSize = 0xa0000 - PAGE_SIZE;
/* We should only do that for CSRSS, for the v86 address space */
ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess);
/* Commit (again) the pages, but with PAGE_READWRITE protection */
Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
&BaseAddress,
0,
&ViewSize,
MEM_COMMIT,
PAGE_READWRITE);
ASSERT(NT_SUCCESS(Status));
}
#if defined(_M_IX86) || defined(_M_AMD64)
NTSTATUS
NTAPI
IntInitializeVideoAddressSpace(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory");
NTSTATUS Status;
HANDLE PhysMemHandle;
PVOID BaseAddress;
LARGE_INTEGER Offset;
SIZE_T ViewSize;
#ifdef _M_IX86
CHAR IVTAndBda[1024 + 256];
#endif // _M_IX86
/* Free the 1MB pre-reserved region. In reality, ReactOS should simply support us mapping the view into the reserved area, but it doesn't. */
BaseAddress = 0;
ViewSize = 1024 * 1024;
Status = ZwFreeVirtualMemory(NtCurrentProcess(),
&BaseAddress,
&ViewSize,
MEM_RELEASE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Couldn't unmap reserved memory (%x)\n", Status);
return 0;
}
/* Open the physical memory section */
InitializeObjectAttributes(&ObjectAttributes,
&PhysMemName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwOpenSection(&PhysMemHandle,
SECTION_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("Couldn't open \\Device\\PhysicalMemory\n");
return Status;
}
/* Map the BIOS and device registers into the address space */
Offset.QuadPart = 0xa0000;
ViewSize = 0x100000 - 0xa0000;
BaseAddress = (PVOID)0xa0000;
Status = ZwMapViewOfSection(PhysMemHandle,
NtCurrentProcess(),
&BaseAddress,
0,
ViewSize,
&Offset,
&ViewSize,
ViewUnmap,
0,
PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Couldn't map physical memory (%x)\n", Status);
ZwClose(PhysMemHandle);
return Status;
}
/* Close physical memory section handle */
ZwClose(PhysMemHandle);
if (BaseAddress != (PVOID)0xa0000)
{
DPRINT1("Couldn't map physical memory at the right address (was %x)\n",
BaseAddress);
return STATUS_UNSUCCESSFUL;
}
/* Allocate some low memory to use for the non-BIOS
* parts of the v86 mode address space
*/
BaseAddress = (PVOID)0x1;
ViewSize = 0xa0000 - 0x1000;
Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
&BaseAddress,
0,
&ViewSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status);
return Status;
}
if (BaseAddress != (PVOID)0x0)
{
DPRINT1("Failed to allocate virtual memory at right address (was %x)\n",
BaseAddress);
return 0;
}
#ifdef _M_IX86
/* Get the real mode IVT and BDA from the kernel */
Status = NtVdmControl(VdmInitialize, IVTAndBda);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtVdmControl failed (status %x)\n", Status);
return Status;
}
#endif // _M_IX86
/* Protect the V86 address space after this */
ProtectLowV86Mem();
/* Return success */
return STATUS_SUCCESS;
}
#else
NTSTATUS
NTAPI
IntInitializeVideoAddressSpace(VOID)
{
UNIMPLEMENTED;
NT_ASSERT(FALSE);
return STATUS_NOT_IMPLEMENTED;
}
#endif
VP_STATUS
NTAPI
IntInt10AllocateBuffer(
IN PVOID Context,
OUT PUSHORT Seg,
OUT PUSHORT Off,
IN OUT PULONG Length)
{
NTSTATUS Status;
#ifdef _M_IX86
PVOID MemoryAddress;
PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
KAPC_STATE ApcState;
SIZE_T Size;
TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n");
IntAttachToCSRSS(&CallingProcess, &ApcState);
Size = *Length;
MemoryAddress = (PVOID)0x20000;
Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
&MemoryAddress,
0,
&Size,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(Status))
{
WARN_(VIDEOPRT, "- ZwAllocateVirtualMemory failed\n");
IntDetachFromCSRSS(&CallingProcess, &ApcState);
return ERROR_NOT_ENOUGH_MEMORY;
}
if (MemoryAddress > (PVOID)(0x100000 - Size))
{
ZwFreeVirtualMemory(NtCurrentProcess(),
&MemoryAddress,
&Size,
MEM_RELEASE);
WARN_(VIDEOPRT, "- Unacceptable memory allocated\n");
IntDetachFromCSRSS(&CallingProcess, &ApcState);
return ERROR_NOT_ENOUGH_MEMORY;
}
*Length = (ULONG)Size;
*Seg = (USHORT)((ULONG_PTR)MemoryAddress >> 4);
*Off = (USHORT)((ULONG_PTR)MemoryAddress & 0xF);
INFO_(VIDEOPRT, "- Segment: %x\n", (ULONG_PTR)MemoryAddress >> 4);
INFO_(VIDEOPRT, "- Offset: %x\n", (ULONG_PTR)MemoryAddress & 0xF);
INFO_(VIDEOPRT, "- Length: %x\n", *Length);
IntDetachFromCSRSS(&CallingProcess, &ApcState);
return NO_ERROR;
#else
Status = x86BiosAllocateBuffer(Length, Seg, Off);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY;
#endif
}
VP_STATUS
NTAPI
IntInt10FreeBuffer(
IN PVOID Context,
IN USHORT Seg,
IN USHORT Off)
{
NTSTATUS Status;
#ifdef _M_IX86
PVOID MemoryAddress = (PVOID)((ULONG_PTR)(Seg << 4) | Off);
PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
KAPC_STATE ApcState;
SIZE_T Size = 0;
TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n");
INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", Off);
IntAttachToCSRSS(&CallingProcess, &ApcState);
Status = ZwFreeVirtualMemory(NtCurrentProcess(),
&MemoryAddress,
&Size,
MEM_RELEASE);
IntDetachFromCSRSS(&CallingProcess, &ApcState);
return Status;
#else
Status = x86BiosFreeBuffer(Seg, Off);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER;
#endif
}
VP_STATUS
NTAPI
IntInt10ReadMemory(
IN PVOID Context,
IN USHORT Seg,
IN USHORT Off,
OUT PVOID Buffer,
IN ULONG Length)
{
#ifdef _M_IX86
PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
KAPC_STATE ApcState;
TRACE_(VIDEOPRT, "IntInt10ReadMemory\n");
INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", Off);
INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer);
INFO_(VIDEOPRT, "- Length: %x\n", Length);
IntAttachToCSRSS(&CallingProcess, &ApcState);
if (IsLowV86Mem(Seg, Off))
UnprotectLowV86Mem();
RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)(Seg << 4) | Off), Length);
if (IsLowV86Mem(Seg, Off))
ProtectLowV86Mem();
IntDetachFromCSRSS(&CallingProcess, &ApcState);
return NO_ERROR;
#else
NTSTATUS Status;
Status = x86BiosReadMemory(Seg, Off, Buffer, Length);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER;
#endif
}
VP_STATUS
NTAPI
IntInt10WriteMemory(
IN PVOID Context,
IN USHORT Seg,
IN USHORT Off,
IN PVOID Buffer,
IN ULONG Length)
{
#ifdef _M_IX86
PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
KAPC_STATE ApcState;
TRACE_(VIDEOPRT, "IntInt10WriteMemory\n");
INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
INFO_(VIDEOPRT, "- Offset: %x\n", Off);
INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer);
INFO_(VIDEOPRT, "- Length: %x\n", Length);
IntAttachToCSRSS(&CallingProcess, &ApcState);
if (IsLowV86Mem(Seg, Off))
UnprotectLowV86Mem();
RtlCopyMemory((PVOID)((ULONG_PTR)(Seg << 4) | Off), Buffer, Length);
if (IsLowV86Mem(Seg, Off))
ProtectLowV86Mem();
IntDetachFromCSRSS(&CallingProcess, &ApcState);
return NO_ERROR;
#else
NTSTATUS Status;
Status = x86BiosWriteMemory(Seg, Off, Buffer, Length);
return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER;
#endif
}
VP_STATUS
NTAPI
IntInt10CallBios(
IN PVOID Context,
IN OUT PINT10_BIOS_ARGUMENTS BiosArguments)
{
#ifdef _M_AMD64
X86_BIOS_REGISTERS BiosContext;
#else
CONTEXT BiosContext;
#endif
NTSTATUS Status;
PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
KAPC_STATE ApcState;
/* Attach to CSRSS */
IntAttachToCSRSS(&CallingProcess, &ApcState);
/* Clear the context */
RtlZeroMemory(&BiosContext, sizeof(BiosContext));
/* Fill 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;
/* Do the ROM BIOS call */
(void)KeWaitForMutexObject(&VideoPortInt10Mutex,
Executive,
KernelMode,
FALSE,
NULL);
/* The kernel needs access here */
UnprotectLowV86Mem();
#ifdef _M_AMD64
Status = x86BiosCall(0x10, &BiosContext) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
#else
Status = Ke386CallBios(0x10, &BiosContext);
#endif
ProtectLowV86Mem();
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;
/* Detach and return status */
IntDetachFromCSRSS(&CallingProcess, &ApcState);
if (NT_SUCCESS(Status))
{
return NO_ERROR;
}
return ERROR_INVALID_PARAMETER;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
*/
VP_STATUS
NTAPI
VideoPortInt10(
IN PVOID HwDeviceExtension,
IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments)
{
INT10_BIOS_ARGUMENTS Int10BiosArguments;
VP_STATUS Status;
if (!CsrProcess)
{
return ERROR_INVALID_PARAMETER;
}
/* Copy arguments to other format */
RtlCopyMemory(&Int10BiosArguments, BiosArguments, sizeof(*BiosArguments));
Int10BiosArguments.SegDs = 0;
Int10BiosArguments.SegEs = 0;
/* Do the BIOS call */
Status = IntInt10CallBios(NULL, &Int10BiosArguments);
/* Copy results back */
RtlCopyMemory(BiosArguments, &Int10BiosArguments, sizeof(*BiosArguments));
return Status;
}