NT4/private/ntos/vdm/i386/vdminit.c
2020-09-30 17:12:29 +02:00

491 lines
12 KiB
C

#include <ntos.h>
#include <zwapi.h>
#include <ntconfig.h>
#include "vdmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VdmpInitialize)
#endif
#define KEY_VALUE_BUFFER_SIZE 1024
#if DEVL
ULONG VdmBopCount;
#endif
NTSTATUS
VdmpInitialize(
PVDMICAUSERDATA pIcaUserData
)
/*++
Routine Description:
Initialize the address space of a VDM.
Arguments:
None,
Return Value:
NTSTATUS.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING SectionName;
UNICODE_STRING WorkString;
ULONG ViewSize;
LARGE_INTEGER ViewBase;
PVOID BaseAddress;
PVOID destination;
HANDLE SectionHandle, RegistryHandle;
PEPROCESS Process;
ULONG ResultLength;
ULONG Index;
PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
PKEY_VALUE_FULL_INFORMATION KeyValueBuffer;
PCM_ROM_BLOCK BiosBlock;
ULONG LastMappedAddress;
PVDM_PROCESS_OBJECTS pVdmObjects;
USHORT PagedQuotaCharged = 0;
USHORT NonPagedQuotaCharged = 0;
PAGED_CODE();
if ((KeI386MachineType & MACHINE_TYPE_PC_9800_COMPATIBLE) == 0) {
//
// This is PC/AT (and FMR in Japan) VDM.
//
RtlInitUnicodeString(
&SectionName,
L"\\Device\\PhysicalMemory"
);
InitializeObjectAttributes(
&ObjectAttributes,
&SectionName,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL
);
Status = ZwOpenSection(
&SectionHandle,
SECTION_ALL_ACCESS,
&ObjectAttributes
);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Copy the first page of memory into the VDM's address space
//
BaseAddress = 0;
destination = 0;
ViewSize = 0x1000;
ViewBase.LowPart = 0;
ViewBase.HighPart = 0;
Status = ZwMapViewOfSection(
SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0,
ViewSize,
&ViewBase,
&ViewSize,
ViewUnmap,
0,
PAGE_READWRITE
);
if (!NT_SUCCESS(Status)) {
return Status;
}
RtlMoveMemory(
destination,
BaseAddress,
ViewSize
);
Status = ZwUnmapViewOfSection(
NtCurrentProcess(),
BaseAddress
);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Map Rom into address space
//
BaseAddress = (PVOID) 0x000C0000;
ViewSize = 0x40000;
ViewBase.LowPart = 0x000C0000;
ViewBase.HighPart = 0;
//
// 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.
//
Status = 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(Status)) {
return Status;
}
//
// Set up and open KeyPath
//
InitializeObjectAttributes(
&ObjectAttributes,
&CmRegistryMachineHardwareDescriptionSystemName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL
);
Status = ZwOpenKey(
&RegistryHandle,
KEY_READ,
&ObjectAttributes
);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Allocate space for the data
//
KeyValueBuffer = ExAllocatePool(PagedPool, KEY_VALUE_BUFFER_SIZE);
if (KeyValueBuffer == NULL) {
ZwClose(RegistryHandle);
return STATUS_NO_MEMORY;
}
//
// Get the data for the rom information
//
RtlInitUnicodeString(
&WorkString,
L"Configuration Data"
);
Status = ZwQueryValueKey(
RegistryHandle,
&WorkString,
KeyValueFullInformation,
KeyValueBuffer,
KEY_VALUE_BUFFER_SIZE,
&ResultLength
);
if (!NT_SUCCESS(Status)) {
ZwClose(RegistryHandle);
ExFreePool(KeyValueBuffer);
return Status;
}
ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
((PUCHAR) KeyValueBuffer + KeyValueBuffer->DataOffset);
if ((KeyValueBuffer->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) ||
(ResourceDescriptor->PartialResourceList.Count < 2)
) {
ZwClose(RegistryHandle);
ExFreePool(KeyValueBuffer);
// No rom blocks.
return STATUS_SUCCESS;
}
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))
) {
ZwClose(RegistryHandle);
ExFreePool(KeyValueBuffer);
return STATUS_ILL_FORMED_SERVICE_ENTRY;
}
BiosBlock = (PCM_ROM_BLOCK)((PUCHAR)PartialResourceDescriptor +
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
Index = PartialResourceDescriptor->u.DeviceSpecificData.DataSize /
sizeof(CM_ROM_BLOCK);
//
// 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 = 0xC0000;
while (Index) {
#if 0
DbgPrint(
"Bios Block, PhysAddr = %lx, size = %lx\n",
BiosBlock->Address,
BiosBlock->Size
);
#endif
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);
ViewSize = BiosBlock->Size;
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) {
Status = ZwMapViewOfSection(
SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0,
ViewSize,
&ViewBase,
&ViewSize,
ViewUnmap,
MEM_DOS_LIM,
PAGE_READWRITE
);
if (!NT_SUCCESS(Status)) {
break;
}
LastMappedAddress = (ULONG)BaseAddress + ViewSize;
}
Index--;
BiosBlock++;
}
//
// Free up the handles
//
ZwClose(SectionHandle);
ZwClose(RegistryHandle);
ExFreePool(KeyValueBuffer);
} else {
//
// This is PC-9800 Series VDM.
//
Status = STATUS_SUCCESS;
}
//
// Mark the process as a vdm
//
Process = PsGetCurrentProcess();
Process->Pcb.VdmFlag = TRUE;
//
// Create VdmObjects structure
//
// N.B. We don't use ExAllocatePoolWithQuota because it
// takes a reference to the process (which ExFreePool
// dereferences). Since we expect to clean up on
// process deletion, we don't need or want the reference
// (which will prevent the process from being deleted)
//
try {
Process->VdmObjects = ExAllocatePool(
NonPagedPool,
sizeof(VDM_PROCESS_OBJECTS)
);
if (Process->VdmObjects == NULL) {
return STATUS_NO_MEMORY;
}
//
// We use NonPagedQuotaCharged to keep track of the quota to return
// if this function fails
//
PsChargePoolQuota(Process, NonPagedPool, sizeof(VDM_PROCESS_OBJECTS));
NonPagedQuotaCharged = sizeof(VDM_PROCESS_OBJECTS);
pVdmObjects = Process->VdmObjects;
RtlZeroMemory( Process->VdmObjects, sizeof(VDM_PROCESS_OBJECTS));
ExInitializeFastMutex(&pVdmObjects->DelayIntFastMutex);
KeInitializeSpinLock(&pVdmObjects->DelayIntSpinLock);
InitializeListHead(&pVdmObjects->DelayIntListHead);
pVdmObjects->pIcaUserData = ExAllocatePool(
PagedPool,
sizeof(VDMICAUSERDATA)
);
if (pVdmObjects->pIcaUserData == NULL) {
Status = STATUS_NO_MEMORY;
} else {
//
// We use NonPagedQuotaCharged to keep track of the quota to return
// if this function fails
//
PsChargePoolQuota(
Process,
PagedPool,
sizeof(VDMICAUSERDATA)
);
PagedQuotaCharged = sizeof(VDMICAUSERDATA);
RtlZeroMemory( pVdmObjects->pIcaUserData, sizeof(VDMICAUSERDATA));
//
// Copy Ica addresses from service data (in user space) into
// pVdmObjects->pIcaUserData
//
ProbeForRead(pIcaUserData, sizeof(VDMICAUSERDATA), sizeof(UCHAR));
*pVdmObjects->pIcaUserData = *pIcaUserData;
//
// Probe static addresses in IcaUserData.
//
ProbeForWriteHandle(pIcaUserData->phWowIdleEvent);
ProbeForWrite(
pIcaUserData->pIcaLock,
sizeof(RTL_CRITICAL_SECTION),
sizeof(UCHAR)
);
ProbeForWrite(
pIcaUserData->pIcaMaster,
sizeof(VDMVIRTUALICA),
sizeof(UCHAR)
);
ProbeForWrite(
pIcaUserData->pIcaSlave,
sizeof(VDMVIRTUALICA),
sizeof(UCHAR)
);
ProbeForWriteUlong(pIcaUserData->pIretHooked);
ProbeForWriteUlong(pIcaUserData->pDelayIrq);
ProbeForWriteUlong(pIcaUserData->pUndelayIrq);
ProbeForWriteUlong(pIcaUserData->pDelayIret);
}
} except(ExSystemExceptionFilter()) {
Status = GetExceptionCode();
}
if (!NT_SUCCESS(Status)) {
if (pVdmObjects->pIcaUserData)
ExFreePool(pVdmObjects->pIcaUserData);
ExFreePool(pVdmObjects);
Process->VdmObjects = NULL;
//
// Return Quota charged
//
PsReturnPoolQuota(Process, NonPagedPool, NonPagedQuotaCharged);
PsReturnPoolQuota(Process, PagedPool, PagedQuotaCharged);
}
//
// following codepath only for PC/AT (and FMR in Japan) vdm
//
if (KeI386MachineType & MACHINE_TYPE_PC_9800_COMPATIBLE == 0) {
#ifdef WHEN_IO_DISPATCHING_IMPROVED
// Sudeepb - Once we improve the IO dispatching we should use this
// routine. Currently we are dispatching the printer ports directly
// from emv86.asm and instemul.asm
VdmInitializePrinter ();
#endif
}
return Status;
} // end InitializeVDM()