windows-nt/Source/XPSP1/NT/base/boot/bd/file.c
2020-09-26 16:20:57 +08:00

488 lines
13 KiB
C

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
file.c
Abstract:
This module contains kd host machine file I/O support.
Author:
Matt Holle (matth) April-2001
Revision History:
--*/
#include "bd.h"
#include "bootlib.h"
#include "kddll.h"
#define TRANSFER_LENGTH 8192
#define KD_MAX_REMOTE_FILES 16
//
// Keep track of all the remote files.
typedef struct _KD_REMOTE_FILE {
ULONG64 RemoteHandle;
} KD_REMOTE_FILE, *PKD_REMOTE_FILE;
KD_REMOTE_FILE BdRemoteFiles[KD_MAX_REMOTE_FILES];
// KD_CONTEXT KdContext;
// temporary buffer used for transferring data back and forth.
// UCHAR TransferBuffer[TRANSFER_LENGTH];
UCHAR BdFileTransferBuffer[TRANSFER_LENGTH];
ARC_STATUS
BdCreateRemoteFile(
OUT PHANDLE Handle,
OUT PULONG64 Length, OPTIONAL
IN PCHAR FileName,
IN ACCESS_MASK DesiredAccess,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions
)
{
DBGKD_FILE_IO Irp;
ULONG DownloadedFileIndex;
ULONG Index;
STRING MessageData;
STRING MessageHeader;
ULONG ReturnCode;
ULONG PacketLength;
ANSI_STRING aString;
UNICODE_STRING uString;
if( !BdDebuggerEnabled ) {
return STATUS_DEBUGGER_INACTIVE;
}
if( (!FileName) ||
(strlen(FileName) > PACKET_MAX_SIZE) ) {
DbgPrint( "BdCreateRemoteFile: Bad parameter\n" );
return STATUS_INVALID_PARAMETER;
}
if (BdDebuggerNotPresent != FALSE) {
Irp.Status = STATUS_DEBUGGER_INACTIVE;
goto Exit;
}
//
// Look for an open slot.
//
for (DownloadedFileIndex = 0; DownloadedFileIndex < KD_MAX_REMOTE_FILES; DownloadedFileIndex++) {
if (BdRemoteFiles[DownloadedFileIndex].RemoteHandle == 0) {
break;
}
}
if (DownloadedFileIndex >= KD_MAX_REMOTE_FILES) {
DbgPrint( "BdCreateRemoteFile: No more empty handles available for this file.\n" );
Irp.Status = STATUS_NO_MEMORY;
goto Exit;
}
//
// Fix up the packet that we'll send to the kernel debugger.
//
Irp.ApiNumber = DbgKdCreateFileApi;
Irp.u.CreateFile.DesiredAccess = DesiredAccess;
Irp.u.CreateFile.FileAttributes = FileAttributes;
Irp.u.CreateFile.ShareAccess = ShareAccess;
Irp.u.CreateFile.CreateDisposition = CreateDisposition;
Irp.u.CreateFile.CreateOptions = CreateOptions;
Irp.u.CreateFile.Handle = 0;
Irp.u.CreateFile.Length = 0;
MessageHeader.Length = sizeof(Irp);
MessageHeader.MaximumLength = sizeof(Irp);
MessageHeader.Buffer = (PCHAR)&Irp;
//
// Send him a unicode file name.
//
RtlInitString( &aString, FileName );
uString.Buffer = (PWCHAR)BdFileTransferBuffer;
uString.MaximumLength = sizeof(BdFileTransferBuffer);
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
MessageData.Length = (USHORT)((strlen(FileName)+1) * sizeof(WCHAR));
MessageData.Buffer = BdFileTransferBuffer;
//
// Send packet to the kernel debugger on the host machine and ask him to
// send us a handle to the file.
//
BdSendPacket(PACKET_TYPE_KD_FILE_IO,
&MessageHeader,
&MessageData);
if (BdDebuggerNotPresent != FALSE) {
Irp.Status = STATUS_DEBUGGER_INACTIVE;
goto Exit;
}
//
// We asked for the handle, now receive it.
//
MessageData.MaximumLength = sizeof(BdFileTransferBuffer);
MessageData.Buffer = (PCHAR)BdFileTransferBuffer;
ReturnCode = BD_PACKET_TIMEOUT;
Index = 0;
while( (ReturnCode == BD_PACKET_TIMEOUT) &&
(Index < 10) ) {
ReturnCode = BdReceivePacket(PACKET_TYPE_KD_FILE_IO,
&MessageHeader,
&MessageData,
&PacketLength);
Index++;
}
//
// BdReceivePacket *may* return BD_PACKET_RECEIVED eventhough the kernel
// debugger failed to actually find the file we wanted. Therefore, we
// need to check the Irp.Status value too before assuming we got the
// information we wanted.
//
// Note: don't check for Irp.u.CreateFile.Length == 0 because we don't
// want to exclude downloading zero-length files.
//
if( (ReturnCode == BD_PACKET_RECEIVED) &&
(NT_SUCCESS(Irp.Status)) ) {
Irp.Status = STATUS_SUCCESS;
} else {
Irp.Status = STATUS_INVALID_PARAMETER;
}
Exit:
if (NT_SUCCESS(Irp.Status)) {
BdRemoteFiles[DownloadedFileIndex].RemoteHandle = Irp.u.CreateFile.Handle;
// Add one so that zero is reserved for invalid-handle.
*Handle = UlongToHandle(DownloadedFileIndex + 1);
if (ARGUMENT_PRESENT(Length)) {
*Length = Irp.u.CreateFile.Length;
}
}
return Irp.Status;
}
ARC_STATUS
BdReadRemoteFile(
IN HANDLE Handle,
IN ULONG64 Offset,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG Completed
)
{
DBGKD_FILE_IO Irp;
ULONG Index;
ULONG _Completed = 0;
if( !BdDebuggerEnabled ) {
return STATUS_DEBUGGER_INACTIVE;
}
Index = HandleToUlong(Handle) - 1;
if( (Index >= KD_MAX_REMOTE_FILES) ||
(BdRemoteFiles[Index].RemoteHandle == 0) ) {
DbgPrint( "BdReadRemoteFile: Bad parameters!\n" );
Irp.Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Irp.ApiNumber = DbgKdReadFileApi;
Irp.Status = STATUS_SUCCESS;
Irp.u.ReadFile.Handle = BdRemoteFiles[Index].RemoteHandle;
Irp.u.ReadFile.Offset = Offset;
while (Length > 0) {
STRING MessageData;
STRING MessageHeader;
ULONG ReturnCode;
ULONG RecvLength;
if (Length > PACKET_MAX_SIZE - sizeof(Irp)) {
Irp.u.ReadFile.Length = PACKET_MAX_SIZE - sizeof(Irp);
} else {
Irp.u.ReadFile.Length = Length;
}
MessageHeader.Length = sizeof(Irp);
MessageHeader.MaximumLength = sizeof(Irp);
MessageHeader.Buffer = (PCHAR)&Irp;
//
// Send packet to the kernel debugger on the host machine.
//
BdSendPacket(PACKET_TYPE_KD_FILE_IO,
&MessageHeader,
NULL);
//
// Receive packet from the kernel debugger on the host machine.
//
MessageData.MaximumLength = (USHORT)Irp.u.ReadFile.Length;
MessageData.Buffer = Buffer;
do {
ReturnCode = BdReceivePacket(PACKET_TYPE_KD_FILE_IO,
&MessageHeader,
&MessageData,
&RecvLength);
} while (ReturnCode == BD_PACKET_TIMEOUT);
if (ReturnCode == BD_PACKET_RECEIVED) {
if (!NT_SUCCESS(Irp.Status)) {
break;
}
_Completed += RecvLength;
Buffer = (PVOID)((PUCHAR)Buffer + RecvLength);
Irp.u.ReadFile.Offset += RecvLength;
Length -= RecvLength;
}
}
*Completed = _Completed;
Exit:
return Irp.Status;
}
ARC_STATUS
BdCloseRemoteFile(
IN HANDLE Handle
)
{
DBGKD_FILE_IO Irp;
ULONG Index;
if( !BdDebuggerEnabled ) {
return STATUS_DEBUGGER_INACTIVE;
}
Index = HandleToUlong(Handle) - 1;
if (Index >= KD_MAX_REMOTE_FILES) {
return STATUS_INVALID_PARAMETER;
}
if (BdRemoteFiles[Index].RemoteHandle == 0) {
Irp.Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Irp.ApiNumber = DbgKdCloseFileApi;
Irp.u.CloseFile.Handle = BdRemoteFiles[Index].RemoteHandle;
for (;;) {
STRING MessageData;
STRING MessageHeader;
ULONG ReturnCode;
ULONG RecvLength;
MessageHeader.Length = sizeof(Irp);
MessageHeader.MaximumLength = sizeof(Irp);
MessageHeader.Buffer = (PCHAR)&Irp;
//
// Send packet to the kernel debugger on the host machine.
//
BdSendPacket(PACKET_TYPE_KD_FILE_IO,
&MessageHeader,
NULL);
//
// Receive packet from the kernel debugger on the host machine.
//
MessageData.MaximumLength = BD_MESSAGE_BUFFER_SIZE;
MessageData.Buffer = (PCHAR)BdMessageBuffer;
do {
ReturnCode = BdReceivePacket(PACKET_TYPE_KD_FILE_IO,
&MessageHeader,
&MessageData,
&RecvLength);
} while (ReturnCode == BD_PACKET_TIMEOUT);
if (ReturnCode == BD_PACKET_RECEIVED) {
break;
}
}
if (NT_SUCCESS(Irp.Status)) {
BdRemoteFiles[Index].RemoteHandle = 0;
}
Exit:
return Irp.Status;
}
ARC_STATUS
BdPullRemoteFile(
IN PCHAR FileName,
IN ULONG FileAttributes,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN ULONG FileId
)
{
ARC_STATUS Status = ESUCCESS;
PUCHAR BaseFilePointer = NULL;
PUCHAR WorkingMemoryPointer = NULL;
ULONG64 Length = 0;
HANDLE RemoteHandle = NULL;
ULONG64 Offset = 0;
ULONG basePage = 0;
PBL_FILE_TABLE fileTableEntry = NULL;
if( !BdDebuggerEnabled ) {
return STATUS_DEBUGGER_INACTIVE;
}
// Open the remote file for reading.
Status = BdCreateRemoteFile(&RemoteHandle, &Length, FileName,
FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN, 0);
if (!NT_SUCCESS(Status)) {
//
// File probably doesn't exist on the debugger.
//
goto Exit;
}
//
// Allocate memory for the file, then download it.
//
Status = BlAllocateAlignedDescriptor( LoaderFirmwareTemporary,
0,
(ULONG)((Length + PAGE_SIZE - 1) >> PAGE_SHIFT),
0,
&basePage );
if ( Status != ESUCCESS ) {
DbgPrint( "BdPullRemoteFile: BlAllocateAlignedDescriptor failed! (%x)\n", Status );
goto Exit;
}
//
// Keep track of our pointers.
// BaseFilePointer will point to the starting address of the block
// we're about to download the file into.
//
// Working MemoryPointer will move through memory as we download small
// chunks of the file.
//
BaseFilePointer = (PUCHAR)ULongToPtr( (basePage << PAGE_SHIFT) );
WorkingMemoryPointer = BaseFilePointer;
//
// Download the file.
//
Offset = 0;
while( Offset < Length ) {
ULONG ReqLength, ReqCompleted;
if((Length - Offset) > TRANSFER_LENGTH) {
ReqLength = TRANSFER_LENGTH;
} else {
ReqLength = (ULONG)(Length - Offset);
}
Status = BdReadRemoteFile( RemoteHandle,
Offset,
WorkingMemoryPointer,
ReqLength,
&ReqCompleted );
if (!NT_SUCCESS(Status) || ReqCompleted == 0) {
DbgPrint( "BdPullRemoteFile: BdReadRemoteFile failed! (%x)\n", Status );
goto Exit;
}
// Increment our working pointer so we copy the next chunk
// into the next spot in memory.
WorkingMemoryPointer += ReqLength;
Offset += ReqLength;
}
//
// We got the file, so setup the BL_FILE_TABLE
// entry for this file. We'll pretend that we got this file
// off the network because that's pretty close, and it allows
// us to conveniently record the memory block where we're about
// to download this file.
//
{
extern BL_DEVICE_ENTRY_TABLE NetDeviceEntryTable;
fileTableEntry = &BlFileTable[FileId];
fileTableEntry->Flags.Open = 1;
fileTableEntry->DeviceId = NET_DEVICE_ID;
fileTableEntry->u.NetFileContext.FileSize = (ULONG)Length;
fileTableEntry->u.NetFileContext.InMemoryCopy = BaseFilePointer;
fileTableEntry->Position.QuadPart = 0;
fileTableEntry->Flags.Read = 1;
fileTableEntry->DeviceEntryTable = &NetDeviceEntryTable;
RtlZeroMemory( fileTableEntry->StructureContext, sizeof(NET_STRUCTURE_CONTEXT) );
//
// If we've called NetIntialize before (like if we're really booting from
// the net, or if we've come through here before), then he returns immediately
// so the call isn't expensive.
//
// If we're not booting from the net, and we've never called NetInitialize before,
// then this will do nothing but setup his function table and return quickly.
//
NetInitialize();
}
DbgPrint( "BD: Loaded remote file %s\n", FileName );
Exit:
if (RemoteHandle != NULL) {
BdCloseRemoteFile(RemoteHandle);
}
return Status;
}