windows-nt/Source/XPSP1/NT/base/ntos/ex/xipdisp.c
2020-09-26 16:20:57 +08:00

471 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990-1998 Microsoft Corporation
Module Name:
xipdisp.c
Abstract:
This file implements functions for communicating with the XIP Disk Driver.
Most importantly this routine is used by the kernel to communicate
information about the location of the memory set aside for XIP.
Author:
Dave Probert (davepr) 2000/10/10
Environment:
kernel mode
Revision History:
--*/
#include "exp.h"
#pragma hdrstop
#include "cpyuchr.h"
#include "fat.h"
#include "xip.h"
#if defined(_X86_)
typedef struct _XIP_CONFIGURATION {
XIP_BOOT_PARAMETERS BootParameters;
BIOS_PARAMETER_BLOCK BiosParameterBlock;
ULONG ClusterZeroPage;
} XIP_CONFIGURATION, *PXIP_CONFIGURATION;
PXIP_CONFIGURATION XIPConfiguration;
BOOLEAN XIPConfigured;
VOID
XIPInit(
PLOADER_PARAMETER_BLOCK LoaderBlock
);
PMEMORY_ALLOCATION_DESCRIPTOR
XIPpFindMemoryDescriptor(
PLOADER_PARAMETER_BLOCK LoaderBlock
);
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(INIT, XIPInit)
#pragma alloc_text(INIT, XIPpFindMemoryDescriptor)
#pragma alloc_text(PAGE, XIPLocatePages)
#endif
VOID
XIPInit(
PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine sets up the boot parameter information for XIP Rom.
Arguments:
Environment:
Called only at INIT.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR XIPMemoryDescriptor;
PPACKED_BOOT_SECTOR pboot;
BIOS_PARAMETER_BLOCK bios;
PHYSICAL_ADDRESS physicalAddress;
PCHAR Options;
PCHAR XIPBoot, XIPRom, XIPRam, XIPSize, XIPVerbose;
PCHAR sizestr;
ULONG nmegs = 0;
//
// Process the boot options. Really only need to know whether or not we are the boot device, and RAM or ROM.
// But the other checking is done for diagnostic purposes (at least in checked builds).
//
Options = LoaderBlock->LoadOptions;
if (!Options) {
return;
}
XIPBoot = strstr(Options, "XIPBOOT");
XIPRom = strstr(Options, "XIPROM=");
XIPRam = strstr(Options, "XIPRAM=");
XIPSize = strstr(Options, "XIPMEGS=");
XIPVerbose = strstr(Options, "XIPVERBOSE");
if (XIPVerbose) {
DbgPrint("\n\nXIP: debug timestamp at line %d in %s: <<<%s %s>>>\n\n\n", __LINE__, __FILE__, __DATE__, __TIME__);
}
XIPMemoryDescriptor = XIPpFindMemoryDescriptor(LoaderBlock);
if (!XIPMemoryDescriptor) {
return;
}
if (XIPVerbose) {
DbgPrint("XIP: Base %x Count %x\n", XIPMemoryDescriptor->BasePage, XIPMemoryDescriptor->PageCount);
}
if (XIPRom && XIPRam) {
return;
}
if (!XIPRom && !XIPRam) {
return;
}
sizestr = XIPSize? strchr(XIPSize, '=') : NULL;
if (sizestr) {
nmegs = (ULONG) atol(sizestr+1);
}
if (nmegs == 0) {
return;
}
if (XIPVerbose && XIPMemoryDescriptor->PageCount != nmegs * 1024*1024 / PAGE_SIZE) {
DbgPrint("XIPMEGS=%d in boot options is %d pages, but only %d pages were allocated by NTLDR\n",
nmegs * 1024*1024 / PAGE_SIZE,
XIPMemoryDescriptor->PageCount * PAGE_SIZE);
return;
}
//
// Get info from FAT16 boot sector.
// We only need to map one page, so we've allocated an MDL on the stack.
//
//
// Temporarily map the page with the boot sector so we can unpack it.
//
physicalAddress.QuadPart = XIPMemoryDescriptor->BasePage * PAGE_SIZE;
pboot = (PPACKED_BOOT_SECTOR) MmMapIoSpace(physicalAddress, PAGE_SIZE, MmCached);
if (!pboot) {
return;
}
FatUnpackBios(&bios, &pboot->PackedBpb);
MmUnmapIoSpace (pboot, PAGE_SIZE);
//
// Check Bios parameters
//
if (bios.BytesPerSector != 512
|| FatBytesPerCluster(&bios) != PAGE_SIZE
|| FatFileAreaLbo(&bios) & (PAGE_SIZE-1)) {
if (XIPVerbose) {
DbgPrint("XIP: Malformed FAT Filesystem: BytesPerSector=%x BytesPerCluster=%x ClusterZeroOffset=%x\n",
bios.BytesPerSector, FatBytesPerCluster(&bios), FatFileAreaLbo(&bios));
}
return;
}
//
// Boot.ini parameters and Bios parameters were ok, so initialize the XIP configuration.
//
XIPConfiguration = ExAllocatePoolWithTag (NonPagedPool, sizeof(*XIPConfiguration), XIP_POOLTAG);
if (!XIPConfiguration) {
return;
}
XIPConfigured = TRUE;
XIPConfiguration->BiosParameterBlock = bios;
XIPConfiguration->BootParameters.SystemDrive = XIPBoot? TRUE : FALSE;
XIPConfiguration->BootParameters.ReadOnly = XIPRom? TRUE : FALSE;
XIPConfiguration->BootParameters.BasePage = XIPMemoryDescriptor->BasePage;
XIPConfiguration->BootParameters.PageCount = XIPMemoryDescriptor->PageCount;
XIPConfiguration->ClusterZeroPage = FatFileAreaLbo(&bios) >> PAGE_SHIFT;
return;
}
NTSTATUS
XIPDispatch(
IN XIPCMD Command,
IN OUT PVOID ParameterBuffer OPTIONAL,
IN ULONG BufferSize
)
/*++
Routine Description:
This routine sets up the boot parameter information for XIP Rom.
Arguments:
Environment:
Only to be called at INIT time.
--*/
{
ULONG sz;
if (!XIPConfiguration) {
return STATUS_NO_SUCH_DEVICE;
}
switch (Command) {
case XIPCMD_GETBOOTPARAMETERS:
sz = sizeof(XIPConfiguration->BootParameters);
if (sz != BufferSize) {
break;
}
RtlCopyMemory(ParameterBuffer, &XIPConfiguration->BootParameters, sz);
return STATUS_SUCCESS;
case XIPCMD_GETBIOSPARAMETERS:
sz = sizeof(XIPConfiguration->BiosParameterBlock);
if (sz != BufferSize) {
break;
}
RtlCopyMemory(ParameterBuffer, &XIPConfiguration->BiosParameterBlock, sz);
return STATUS_SUCCESS;
case XIPCMD_NOOP:
if (BufferSize) {
break;
}
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
////////////////////////////
// DEBUG
int XIPlocate_noisy = 0;
int XIPlocate_breakin = 0;
int XIPlocate_disable = 0;
struct {
int attempted;
int bounced;
int succeeded;
int no_irp;
int no_devobj;
int no_contig;
int no_endofdisk;
} XIPlocatecnt;
////////////////////////////
NTSTATUS
XIPLocatePages(
IN PFILE_OBJECT FileObject,
OUT PPHYSICAL_ADDRESS PhysicalAddress
)
/*++
Routine Description:
Return the requested XIP physical address. If the requested page range
is not contiguous in the file, or there is any other problem, the routine fails.
Arguments:
FileObject - the file of interest
PhysicalAddress - used to return the physical address of the start of the file in ROM.
Environment:
Kernel
--*/
{
STARTING_VCN_INPUT_BUFFER startingvcn;
RETRIEVAL_POINTERS_BUFFER retrbuf;
IO_STATUS_BLOCK iostatus;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpSp;
NTSTATUS status;
KEVENT event;
PIRP irp;
PFN_NUMBER firstPage, numberOfPages;
PDEVICE_OBJECT xipDeviceObject;
xipDeviceObject = FileObject->DeviceObject;
if (!XIPConfiguration) {
return STATUS_NO_SUCH_DEVICE;
}
if (!xipDeviceObject || !(xipDeviceObject->Flags & DO_XIP)) {
return STATUS_INVALID_DEVICE_REQUEST;
}
////////////////
XIPlocatecnt.attempted++;
////////////////
startingvcn.StartingVcn.QuadPart = 0;
deviceObject = IoGetRelatedDeviceObject(FileObject);
if (!deviceObject) {
////////////////
XIPlocatecnt.no_devobj++;
////////////////
return STATUS_INVALID_DEVICE_REQUEST;
}
//
// Ask fat for the retrieval pointers (relative to cluster 0).
//
irp = IoBuildDeviceIoControlRequest(
FSCTL_GET_RETRIEVAL_POINTERS,
deviceObject,
&startingvcn,
sizeof(startingvcn),
&retrbuf,
sizeof(retrbuf),
FALSE,
&event,
&iostatus);
if (!irp) {
////////////////
XIPlocatecnt.no_irp++;
////////////////
return STATUS_INSUFFICIENT_RESOURCES;
}
irp->Flags |= IRP_SYNCHRONOUS_API;
irp->Tail.Overlay.OriginalFileObject = FileObject;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
irpSp->MinorFunction = IRP_MN_USER_FS_REQUEST;
irpSp->FileObject = FileObject;
//
// Take out another reference to the file object to match I/O completion will deref.
//
ObReferenceObject( FileObject );
//
// Do the FSCTL
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
status = IoCallDriver( deviceObject, irp );
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL );
status = iostatus.Status;
}
if (!NT_SUCCESS(iostatus.Status)
|| retrbuf.ExtentCount != 1
|| retrbuf.Extents[0].Lcn.HighPart
|| retrbuf.Extents[0].NextVcn.HighPart
|| retrbuf.StartingVcn.QuadPart != 0L) {
////////////////
XIPlocatecnt.no_contig++;
////////////////
return STATUS_UNSUCCESSFUL;
}
firstPage = XIPConfiguration->BootParameters.BasePage
+ XIPConfiguration->ClusterZeroPage
+ retrbuf.Extents[0].Lcn.LowPart;
numberOfPages = retrbuf.Extents[0].NextVcn.LowPart;
if (firstPage + numberOfPages > XIPConfiguration->BootParameters.BasePage
+ XIPConfiguration->BootParameters.PageCount) {
XIPlocatecnt.no_endofdisk++;
return STATUS_DISK_CORRUPT_ERROR;
}
////////////////
////////////////
if (XIPlocate_noisy || XIPlocate_breakin) {
DbgPrint("Break top of XIPLocatePages. bounced=%x attempted=%x succeeded=%x\n"
" %x nt!XIPlocate_disable %s\n"
" %x nt!XIPlocate_breakin %s\n"
" %x nt!XIPConfiguration\n"
" Would have returned address %x (npages was %x)\n",
XIPlocatecnt.bounced, XIPlocatecnt.attempted, XIPlocatecnt.succeeded,
&XIPlocate_disable, XIPlocate_disable? "DISABLED" : "enabled",
&XIPlocate_breakin, XIPlocate_breakin? "WILL BREAK" : "no break",
XIPConfiguration, firstPage, numberOfPages);
if (XIPlocate_breakin) {
DbgBreakPoint();
}
}
if (XIPlocate_disable) {
XIPlocatecnt.bounced++;
return STATUS_DEVICE_OFF_LINE;
}
XIPlocatecnt.succeeded++;
////////////////
////////////////
PhysicalAddress->QuadPart = firstPage << PAGE_SHIFT;
return STATUS_SUCCESS;
}
//
// Local support routine
//
//
// Find the XIP memory descriptor
// Called only at INIT.
//
PMEMORY_ALLOCATION_DESCRIPTOR
XIPpFindMemoryDescriptor(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PLIST_ENTRY NextMd;
for (NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
NextMd != &LoaderBlock->MemoryDescriptorListHead;
NextMd = MemoryDescriptor->ListEntry.Flink
)
{
MemoryDescriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (MemoryDescriptor->MemoryType == LoaderXIPRom) {
return MemoryDescriptor;
}
}
return NULL;
}
#endif //__X86__