mirror of https://github.com/lianthony/NT4.0
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.
2177 lines
56 KiB
2177 lines
56 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
biosdrv.c
|
|
|
|
Abstract:
|
|
|
|
Provides the ARC emulation routines for I/O to a device supported by
|
|
real-mode INT 13h BIOS calls.
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 7-Aug-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "arccodes.h"
|
|
#include "bootx86.h"
|
|
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
|
|
#include "flop.h"
|
|
|
|
//
|
|
// defines for doing console I/O
|
|
//
|
|
#define CSI 0x95
|
|
#define SGR_INVERSE 7
|
|
#define SGR_NORMAL 0
|
|
|
|
//
|
|
// static data for console I/O
|
|
//
|
|
BOOLEAN ControlSequence=FALSE;
|
|
BOOLEAN EscapeSequence=FALSE;
|
|
BOOLEAN FontSelection=FALSE;
|
|
ULONG PCount=0;
|
|
|
|
#define CONTROL_SEQUENCE_MAX_PARAMETER 10
|
|
ULONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER];
|
|
|
|
#define KEY_INPUT_BUFFER_SIZE 16
|
|
UCHAR KeyBuffer[KEY_INPUT_BUFFER_SIZE];
|
|
ULONG KeyBufferEnd=0;
|
|
ULONG KeyBufferStart=0;
|
|
|
|
//
|
|
// array for translating between ANSI colors and the VGA standard
|
|
//
|
|
UCHAR TranslateColor[] = {0,4,2,6,1,5,3,7};
|
|
|
|
ARC_STATUS
|
|
BiosDiskClose(
|
|
IN ULONG FileId
|
|
);
|
|
|
|
VOID
|
|
BiosConsoleFillBuffer(
|
|
IN ULONG Key
|
|
);
|
|
|
|
//
|
|
// Buffer for temporary storage of data read from the disk that needs
|
|
// to end up in a location above the 1MB boundary.
|
|
//
|
|
// NOTE: it is very important that this buffer not cross a 64k boundary.
|
|
//
|
|
PUCHAR LocalBuffer=NULL;
|
|
|
|
//
|
|
// There are two sorts of things we can open in this module, disk partitions,
|
|
// and raw disk devices. The following device entry tables are
|
|
// used for these things.
|
|
//
|
|
|
|
BL_DEVICE_ENTRY_TABLE BiosPartitionEntryTable =
|
|
{
|
|
(PARC_CLOSE_ROUTINE)BiosPartitionClose,
|
|
(PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_OPEN_ROUTINE)BiosPartitionOpen,
|
|
(PARC_READ_ROUTINE)BiosPartitionRead,
|
|
(PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_SEEK_ROUTINE)BiosPartitionSeek,
|
|
(PARC_WRITE_ROUTINE)BiosPartitionWrite,
|
|
(PARC_GET_FILE_INFO_ROUTINE)BiosGetFileInfo,
|
|
(PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
|
|
(PRENAME_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
|
|
(PBOOTFS_INFO)BlArcNotYetImplemented
|
|
};
|
|
|
|
BL_DEVICE_ENTRY_TABLE BiosDiskEntryTable =
|
|
{
|
|
(PARC_CLOSE_ROUTINE)BiosDiskClose,
|
|
(PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_OPEN_ROUTINE)BiosDiskOpen,
|
|
(PARC_READ_ROUTINE)BiosDiskRead,
|
|
(PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_SEEK_ROUTINE)BiosPartitionSeek,
|
|
(PARC_WRITE_ROUTINE)BiosDiskWrite,
|
|
(PARC_GET_FILE_INFO_ROUTINE)BiosGetFileInfo,
|
|
(PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
|
|
(PRENAME_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
|
|
(PBOOTFS_INFO)BlArcNotYetImplemented
|
|
};
|
|
|
|
#if defined(ELTORITO)
|
|
BL_DEVICE_ENTRY_TABLE BiosEDDSEntryTable =
|
|
{
|
|
(PARC_CLOSE_ROUTINE)BiosDiskClose,
|
|
(PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_OPEN_ROUTINE)BiosDiskOpen,
|
|
(PARC_READ_ROUTINE)BiosEDDSDiskRead,
|
|
(PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_SEEK_ROUTINE)BiosPartitionSeek,
|
|
(PARC_WRITE_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_FILE_INFO_ROUTINE)BiosGetFileInfo,
|
|
(PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
|
|
(PRENAME_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
|
|
(PBOOTFS_INFO)BlArcNotYetImplemented
|
|
};
|
|
#endif
|
|
|
|
ARC_STATUS
|
|
BiosDiskClose(
|
|
IN ULONG FileId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes the specified device
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies file id of the device to be closed
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Device closed successfully
|
|
|
|
!ESUCCESS - Device was not closed.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (BlFileTable[FileId].Flags.Open == 0) {
|
|
BlPrint("ERROR - Unopened fileid %lx closed\n",FileId);
|
|
}
|
|
BlFileTable[FileId].Flags.Open = 0;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
ARC_STATUS
|
|
BiosPartitionClose(
|
|
IN ULONG FileId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes the specified device
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies file id of the device to be closed
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Device closed successfully
|
|
|
|
!ESUCCESS - Device was not closed.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (BlFileTable[FileId].Flags.Open == 0) {
|
|
BlPrint("ERROR - Unopened fileid %lx closed\n",FileId);
|
|
}
|
|
BlFileTable[FileId].Flags.Open = 0;
|
|
|
|
return(BiosDiskClose((ULONG)BlFileTable[FileId].u.PartitionContext.DiskId));
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosPartitionOpen(
|
|
IN PCHAR OpenPath,
|
|
IN OPEN_MODE OpenMode,
|
|
OUT PULONG FileId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens the disk partition specified by OpenPath. This routine will open
|
|
floppy drives 0 and 1, and any partition on hard drive 0 or 1.
|
|
|
|
Arguments:
|
|
|
|
OpenPath - Supplies a pointer to the name of the partition. If OpenPath
|
|
is "A:" or "B:" the corresponding floppy drive will be opened.
|
|
If it is "C:" or above, this routine will find the corresponding
|
|
partition on hard drive 0 or 1 and open it.
|
|
|
|
OpenMode - Supplies the mode to open the file.
|
|
0 - Read Only
|
|
1 - Write Only
|
|
2 - Read/Write
|
|
|
|
FileId - Returns the file descriptor for use with the Close, Read, Write,
|
|
and Seek routines
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - File successfully opened.
|
|
|
|
--*/
|
|
|
|
{
|
|
ARC_STATUS Status;
|
|
ULONG DiskFileId;
|
|
UCHAR PartitionNumber;
|
|
ULONG Controller;
|
|
ULONG Key;
|
|
BOOLEAN IsEisa = FALSE;
|
|
|
|
//
|
|
// BIOS devices are always "multi(0)" (except for EISA flakiness
|
|
// where we treat "eisa(0)..." like "multi(0)..." in floppy cases.
|
|
//
|
|
if(FwGetPathMnemonicKey(OpenPath,"multi",&Key)) {
|
|
|
|
if(FwGetPathMnemonicKey(OpenPath,"eisa", &Key)) {
|
|
return(EBADF);
|
|
} else {
|
|
IsEisa = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Key!=0) {
|
|
return(EBADF);
|
|
}
|
|
|
|
//
|
|
// If we're opening a floppy drive, there are no partitions
|
|
// so we can just return the physical device.
|
|
//
|
|
|
|
if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)partition(0)") == 0) ||
|
|
(_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)partition(0)" ) == 0))
|
|
{
|
|
return(BiosDiskOpen( 0, 0, FileId));
|
|
}
|
|
if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)partition(0)") == 0) ||
|
|
(_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)partition(0)" ) == 0))
|
|
{
|
|
return(BiosDiskOpen( 1, 0, FileId));
|
|
}
|
|
|
|
if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)") == 0) ||
|
|
(_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)" ) == 0))
|
|
{
|
|
return(BiosDiskOpen( 0, 0, FileId));
|
|
}
|
|
if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)") == 0) ||
|
|
(_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)" ) == 0))
|
|
{
|
|
return(BiosDiskOpen( 1, 0, FileId));
|
|
}
|
|
|
|
//
|
|
// We can't handle eisa(0) cases for hard disks.
|
|
//
|
|
if(IsEisa) {
|
|
return(EBADF);
|
|
}
|
|
|
|
//
|
|
// We can only deal with disk controller 0
|
|
//
|
|
|
|
if (FwGetPathMnemonicKey(OpenPath,"disk",&Controller)) {
|
|
return(EBADF);
|
|
}
|
|
if ( Controller!=0 ) {
|
|
return(EBADF);
|
|
}
|
|
|
|
#if defined(ELTORITO)
|
|
if (!FwGetPathMnemonicKey(OpenPath,"cdrom",&Key)) {
|
|
//
|
|
// Now we have a CD-ROM disk number, so we open that for raw access.
|
|
// Use a special bit to indicate CD-ROM, because otherwise
|
|
// the BiosDiskOpen routine thinks a third or greater disk is
|
|
// a CD-ROM.
|
|
//
|
|
return(BiosDiskOpen( Key | 0x80000000, 0, FileId ) );
|
|
}
|
|
#endif
|
|
|
|
if (FwGetPathMnemonicKey(OpenPath,"rdisk",&Key)) {
|
|
return(EBADF);
|
|
}
|
|
|
|
//
|
|
// Now we have a disk number, so we open that for raw access.
|
|
// We need to add 0x80 to translate it to a BIOS number.
|
|
//
|
|
|
|
Status = BiosDiskOpen( 0x80 + Key,
|
|
0,
|
|
&DiskFileId );
|
|
|
|
if (Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Find the partition number to open
|
|
//
|
|
|
|
if (FwGetPathMnemonicKey(OpenPath,"partition",&Key)) {
|
|
BiosPartitionClose(DiskFileId);
|
|
return(EBADF);
|
|
}
|
|
|
|
//
|
|
// If the partition number was 0, then we are opening the device
|
|
// for raw access, so we are already done.
|
|
//
|
|
if (Key == 0) {
|
|
*FileId = DiskFileId;
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
//
|
|
// Before we open the partition, we need to find an available
|
|
// file descriptor.
|
|
//
|
|
|
|
*FileId=2;
|
|
|
|
while (BlFileTable[*FileId].Flags.Open != 0) {
|
|
*FileId += 1;
|
|
if (*FileId == BL_FILE_TABLE_SIZE) {
|
|
return(ENOENT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We found an entry we can use, so mark it as open.
|
|
//
|
|
BlFileTable[*FileId].Flags.Open = 1;
|
|
|
|
BlFileTable[*FileId].DeviceEntryTable=&BiosPartitionEntryTable;
|
|
|
|
|
|
//
|
|
// Convert to zero-based partition number
|
|
//
|
|
PartitionNumber = (UCHAR)(Key - 1);
|
|
|
|
return (HardDiskPartitionOpen( *FileId,
|
|
DiskFileId,
|
|
PartitionNumber) );
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosPartitionRead (
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads from the specified file
|
|
|
|
NOTE John Vert (jvert) 18-Jun-1991
|
|
This only supports block sector reads. Thus, everything
|
|
is assumed to start on a sector boundary, and every offset
|
|
is considered an offset from the logical beginning of the disk
|
|
partition.
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the file to read from
|
|
|
|
Buffer - Supplies buffer to hold the data that is read
|
|
|
|
Length - Supplies maximum number of bytes to read
|
|
|
|
Count - Returns actual bytes read.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Read completed successfully
|
|
|
|
!ESUCCESS - Read failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
ARC_STATUS Status;
|
|
LARGE_INTEGER PhysicalOffset;
|
|
ULONG DiskId;
|
|
|
|
PhysicalOffset.QuadPart = BlFileTable[FileId].Position.QuadPart +
|
|
SECTOR_SIZE * BlFileTable[FileId].u.PartitionContext.StartingSector;
|
|
|
|
DiskId = BlFileTable[FileId].u.PartitionContext.DiskId;
|
|
|
|
Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
|
|
&PhysicalOffset,
|
|
SeekAbsolute );
|
|
|
|
if (Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
|
|
Buffer,
|
|
Length,
|
|
Count );
|
|
|
|
BlFileTable[FileId].Position.QuadPart += *Count;
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
BiosPartitionSeek (
|
|
IN ULONG FileId,
|
|
IN PLARGE_INTEGER Offset,
|
|
IN SEEK_MODE SeekMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Changes the current offset of the file specified by FileId
|
|
|
|
Arguments:
|
|
|
|
FileId - specifies the file on which the current offset is to
|
|
be changed.
|
|
|
|
Offset - New offset into file.
|
|
|
|
SeekMode - Either SeekAbsolute or SeekRelative
|
|
SeekEndRelative is not supported
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Operation completed succesfully
|
|
|
|
EBADF - Operation did not complete successfully.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (SeekMode) {
|
|
case SeekAbsolute:
|
|
BlFileTable[FileId].Position = *Offset;
|
|
break;
|
|
case SeekRelative:
|
|
BlFileTable[FileId].Position.QuadPart += Offset->QuadPart;
|
|
break;
|
|
default:
|
|
BlPrint("SeekMode %lx not supported\n",SeekMode);
|
|
return(EACCES);
|
|
|
|
}
|
|
return(ESUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
BiosPartitionWrite(
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes to the specified file
|
|
|
|
NOTE John Vert (jvert) 18-Jun-1991
|
|
This only supports block sector reads. Thus, everything
|
|
is assumed to start on a sector boundary, and every offset
|
|
is considered an offset from the logical beginning of the disk
|
|
partition.
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the file to write to
|
|
|
|
Buffer - Supplies buffer with data to write
|
|
|
|
Length - Supplies number of bytes to write
|
|
|
|
Count - Returns actual bytes written.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - write completed successfully
|
|
|
|
!ESUCCESS - write failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
ARC_STATUS Status;
|
|
LARGE_INTEGER PhysicalOffset;
|
|
ULONG DiskId;
|
|
|
|
PhysicalOffset.QuadPart = BlFileTable[FileId].Position.QuadPart +
|
|
SECTOR_SIZE * BlFileTable[FileId].u.PartitionContext.StartingSector;
|
|
|
|
DiskId = BlFileTable[FileId].u.PartitionContext.DiskId;
|
|
|
|
Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
|
|
&PhysicalOffset,
|
|
SeekAbsolute );
|
|
|
|
if (Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
Status = (BlFileTable[DiskId].DeviceEntryTable->Write)(DiskId,
|
|
Buffer,
|
|
Length,
|
|
Count );
|
|
|
|
if(Status == ESUCCESS) {
|
|
BlFileTable[FileId].Position.QuadPart += *Count;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
BiosConsoleOpen(
|
|
IN PCHAR OpenPath,
|
|
IN OPEN_MODE OpenMode,
|
|
OUT PULONG FileId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempts to open either the console input or output
|
|
|
|
Arguments:
|
|
|
|
OpenPath - Supplies a pointer to the name of the device to open. If
|
|
this is either CONSOLE_INPUT_NAME or CONSOLE_OUTPUT_NAME,
|
|
a file descriptor is allocated and filled in.
|
|
|
|
OpenMode - Supplies the mode to open the file.
|
|
0 - Read Only (CONSOLE_INPUT_NAME)
|
|
1 - Write Only (CONSOLE_OUTPUT_NAME)
|
|
|
|
FileId - Returns the file descriptor for use with the Close, Read and
|
|
Write routines
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Console successfully opened.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (_stricmp(OpenPath, CONSOLE_INPUT_NAME)==0) {
|
|
|
|
//
|
|
// Open the keyboard for input
|
|
//
|
|
|
|
if (OpenMode != ArcOpenReadOnly) {
|
|
return(EACCES);
|
|
}
|
|
|
|
*FileId = 0;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
if (_stricmp(OpenPath, CONSOLE_OUTPUT_NAME)==0) {
|
|
|
|
//
|
|
// Open the display for output
|
|
//
|
|
|
|
if (OpenMode != ArcOpenWriteOnly) {
|
|
return(EACCES);
|
|
}
|
|
*FileId = 1;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
return(ENOENT);
|
|
|
|
}
|
|
|
|
ARC_STATUS
|
|
BiosConsoleReadStatus(
|
|
IN ULONG FileId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if there is a keypress pending
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the FileId to be read. (should always be 0 for this
|
|
function)
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - There is a key pending
|
|
|
|
EAGAIN - There is not a key pending
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Key;
|
|
|
|
Key = GET_KEY();
|
|
if (Key != 0) {
|
|
//
|
|
// We got a key, so we have to stick it back into our buffer
|
|
// and return ESUCCESS.
|
|
//
|
|
BiosConsoleFillBuffer(Key);
|
|
return(ESUCCESS);
|
|
|
|
} else {
|
|
//
|
|
// no key pending
|
|
//
|
|
return(EAGAIN);
|
|
}
|
|
|
|
}
|
|
|
|
ARC_STATUS
|
|
BiosConsoleRead(
|
|
IN ULONG FileId,
|
|
OUT PUCHAR Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets input from the keyboard.
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the FileId to be read (should always be 0 for this
|
|
function)
|
|
|
|
Buffer - Returns the keyboard input.
|
|
|
|
Length - Supplies the length of the buffer (in bytes)
|
|
|
|
Count - Returns the actual number of bytes read
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Keyboard read completed succesfully.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Key;
|
|
|
|
*Count = 0;
|
|
|
|
while (*Count < Length) {
|
|
if (KeyBufferEnd == KeyBufferStart) { // then buffer is presently empty
|
|
do {
|
|
|
|
//
|
|
// Poll the keyboard until input is available
|
|
//
|
|
|
|
Key = GET_KEY();
|
|
} while ( Key==0 );
|
|
|
|
BiosConsoleFillBuffer(Key);
|
|
}
|
|
|
|
Buffer[*Count] = KeyBuffer[KeyBufferStart];
|
|
KeyBufferStart = (KeyBufferStart+1) % KEY_INPUT_BUFFER_SIZE;
|
|
|
|
*Count = *Count + 1;
|
|
}
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
BiosConsoleFillBuffer(
|
|
IN ULONG Key
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Places input from the keyboard into the keyboard buffer, expanding the
|
|
special keys as appropriate.
|
|
|
|
Arguments:
|
|
|
|
Key - Raw keypress value as returned by GET_KEY().
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch(Key) {
|
|
case UP_ARROW:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'A';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case DOWN_ARROW:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'B';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case F1_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'O';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'P';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case F3_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'O';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'w';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case F5_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'O';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 't';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case F6_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'O';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'u';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// The ASCII code is the low byte of Key
|
|
//
|
|
KeyBuffer[KeyBufferEnd] = (UCHAR)(Key & 0xff);
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
BiosConsoleWrite(
|
|
IN ULONG FileId,
|
|
OUT PUCHAR Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs to the console. (In this case, the VGA display)
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the FileId to be written (should always be 1 for this
|
|
function)
|
|
|
|
Buffer - Supplies characters to be output
|
|
|
|
Length - Supplies the length of the buffer (in bytes)
|
|
|
|
Count - Returns the actual number of bytes written
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Console write completed succesfully.
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status;
|
|
PUCHAR String;
|
|
ULONG Index;
|
|
UCHAR a;
|
|
PUCHAR p;
|
|
|
|
//
|
|
// Process each character in turn.
|
|
//
|
|
|
|
Status = ESUCCESS;
|
|
String = (PUCHAR)Buffer;
|
|
|
|
for ( *Count = 0 ;
|
|
*Count < Length ;
|
|
(*Count)++, String++ ) {
|
|
|
|
//
|
|
// If we're in the middle of a control sequence, continue scanning,
|
|
// otherwise process character.
|
|
//
|
|
|
|
if (ControlSequence) {
|
|
|
|
//
|
|
// If the character is a digit, update parameter value.
|
|
//
|
|
|
|
if ((*String >= '0') && (*String <= '9')) {
|
|
Parameter[PCount] = Parameter[PCount] * 10 + *String - '0';
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If we are in the middle of a font selection sequence, this
|
|
// character must be a 'D', otherwise reset control sequence.
|
|
//
|
|
|
|
if (FontSelection) {
|
|
|
|
//if (*String == 'D') {
|
|
//
|
|
// //
|
|
// // Other fonts not implemented yet.
|
|
// //
|
|
//
|
|
//} else {
|
|
//}
|
|
|
|
ControlSequence = FALSE;
|
|
FontSelection = FALSE;
|
|
continue;
|
|
}
|
|
|
|
switch (*String) {
|
|
|
|
//
|
|
// If a semicolon, move to the next parameter.
|
|
//
|
|
|
|
case ';':
|
|
|
|
PCount++;
|
|
if (PCount > CONTROL_SEQUENCE_MAX_PARAMETER) {
|
|
PCount = CONTROL_SEQUENCE_MAX_PARAMETER;
|
|
}
|
|
Parameter[PCount] = 0;
|
|
break;
|
|
|
|
//
|
|
// If a 'J', erase part or all of the screen.
|
|
//
|
|
|
|
case 'J':
|
|
|
|
switch (Parameter[0]) {
|
|
case 0:
|
|
//
|
|
// Erase to end of the screen
|
|
//
|
|
TextClearToEndOfDisplay();
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// Erase from the beginning of the screen
|
|
//
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Erase entire screen
|
|
//
|
|
TextClearDisplay();
|
|
break;
|
|
}
|
|
|
|
ControlSequence = FALSE;
|
|
break;
|
|
|
|
//
|
|
// If a 'K', erase part or all of the line.
|
|
//
|
|
|
|
case 'K':
|
|
|
|
switch (Parameter[0]) {
|
|
|
|
//
|
|
// Erase to end of the line.
|
|
//
|
|
|
|
case 0:
|
|
TextClearToEndOfLine();
|
|
break;
|
|
|
|
//
|
|
// Erase from the beginning of the line.
|
|
//
|
|
|
|
case 1:
|
|
TextClearFromStartOfLine();
|
|
break;
|
|
|
|
//
|
|
// Erase entire line.
|
|
//
|
|
|
|
default :
|
|
TextClearFromStartOfLine();
|
|
TextClearToEndOfLine();
|
|
break;
|
|
}
|
|
|
|
ControlSequence = FALSE;
|
|
break;
|
|
|
|
//
|
|
// If a 'H', move cursor to position.
|
|
//
|
|
|
|
case 'H':
|
|
TextSetCursorPosition(Parameter[1]-1, Parameter[0]-1);
|
|
ControlSequence = FALSE;
|
|
break;
|
|
|
|
//
|
|
// If a ' ', could be a FNT selection command.
|
|
//
|
|
|
|
case ' ':
|
|
FontSelection = TRUE;
|
|
break;
|
|
|
|
case 'm':
|
|
//
|
|
// Select action based on each parameter.
|
|
//
|
|
|
|
for ( Index = 0 ; Index <= PCount ; Index++ ) {
|
|
switch (Parameter[Index]) {
|
|
|
|
//
|
|
// Attributes off.
|
|
//
|
|
|
|
case 0:
|
|
TextSetCurrentAttribute(7);
|
|
break;
|
|
|
|
//
|
|
// High Intensity.
|
|
//
|
|
|
|
case 1:
|
|
break;
|
|
|
|
//
|
|
// Underscored.
|
|
//
|
|
|
|
case 4:
|
|
break;
|
|
|
|
//
|
|
// Reverse Video.
|
|
//
|
|
|
|
case 7:
|
|
TextSetCurrentAttribute(0x70);
|
|
break;
|
|
|
|
//
|
|
// Font selection, not implemented yet.
|
|
//
|
|
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
break;
|
|
|
|
//
|
|
// Foreground Color
|
|
//
|
|
|
|
case 30:
|
|
case 31:
|
|
case 32:
|
|
case 33:
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37:
|
|
a = TextGetCurrentAttribute();
|
|
a &= 0xf0;
|
|
a |= TranslateColor[Parameter[Index]-30];
|
|
TextSetCurrentAttribute(a);
|
|
break;
|
|
|
|
//
|
|
// Background Color
|
|
//
|
|
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
a = TextGetCurrentAttribute();
|
|
a &= 0x0f;
|
|
a |= TranslateColor[Parameter[Index]-40] << 4;
|
|
TextSetCurrentAttribute(a);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
default:
|
|
ControlSequence = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This is not a control sequence, check for escape sequence.
|
|
//
|
|
|
|
} else {
|
|
|
|
//
|
|
// If escape sequence, check for control sequence, otherwise
|
|
// process single character.
|
|
//
|
|
|
|
if (EscapeSequence) {
|
|
|
|
//
|
|
// Check for '[', means control sequence, any other following
|
|
// character is ignored.
|
|
//
|
|
|
|
if (*String == '[') {
|
|
|
|
ControlSequence = TRUE;
|
|
|
|
//
|
|
// Initialize first parameter.
|
|
//
|
|
|
|
PCount = 0;
|
|
Parameter[0] = 0;
|
|
}
|
|
EscapeSequence = FALSE;
|
|
|
|
//
|
|
// This is not a control or escape sequence, process single character.
|
|
//
|
|
|
|
} else {
|
|
|
|
switch (*String) {
|
|
//
|
|
// Check for escape sequence.
|
|
//
|
|
|
|
case ASCI_ESC:
|
|
EscapeSequence = TRUE;
|
|
break;
|
|
|
|
default:
|
|
p = TextCharOut(String);
|
|
//
|
|
// Each pass through the loop increments String by 1.
|
|
// If we output a dbcs char we need to increment by
|
|
// one more.
|
|
//
|
|
(*Count) += (p - String) - 1;
|
|
String += (p - String) - 1;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosDiskOpen(
|
|
IN ULONG DriveId,
|
|
IN OPEN_MODE OpenMode,
|
|
OUT PULONG FileId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a BIOS-accessible disk for raw sector access.
|
|
|
|
Arguments:
|
|
|
|
DriveId - Supplies the BIOS DriveId of the drive to open
|
|
0 - Floppy 0
|
|
1 - Floppy 1
|
|
0x80 - Hard Drive 0
|
|
0x81 - Hard Drive 1
|
|
0x82 - Hard Drive 2
|
|
etc
|
|
#if defined(ELTORITO)
|
|
High bit set and ID > 0x81 means the device is expected to be
|
|
a CD-ROM drive.
|
|
#endif
|
|
|
|
OpenMode - Supplies the mode of the open
|
|
|
|
FileId - Supplies a pointer to a variable that specifies the file
|
|
table entry that is filled in if the open is successful.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS is returned if the open operation is successful. Otherwise,
|
|
an unsuccessful status is returned that describes the reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG NumberHeads;
|
|
ULONG NumberSectors;
|
|
ULONG NumberCylinders;
|
|
ULONG NumberDrives;
|
|
ULONG Result;
|
|
ULONG Return;
|
|
PDRIVE_CONTEXT Context;
|
|
ULONG Retries;
|
|
|
|
#if defined(ELTORITO)
|
|
BOOLEAN IsCd;
|
|
|
|
if(DriveId > 0x80000081) {
|
|
IsCd = TRUE;
|
|
DriveId &= 0x7fffffff;
|
|
} else {
|
|
IsCd = FALSE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If we are opening Floppy 0 or Floppy 1, we want to read the BPB off
|
|
// the disk so we can deal with all the odd disk formats.
|
|
//
|
|
// If we are opening a hard drive, we can just call the BIOS to find out
|
|
// its characteristics
|
|
//
|
|
if ((DriveId==0) || (DriveId==1)) {
|
|
UCHAR Buffer[512];
|
|
PPACKED_BOOT_SECTOR BootSector;
|
|
BIOS_PARAMETER_BLOCK Bpb;
|
|
|
|
//
|
|
// Read the boot sector off the floppy and extract the cylinder,
|
|
// sector, and head information.
|
|
//
|
|
|
|
Return = MdGetPhysicalSectors( (USHORT)DriveId,
|
|
0, 0, 1,
|
|
1,
|
|
Buffer );
|
|
if (Return != ESUCCESS) {
|
|
#ifdef LOADER_DEBUG
|
|
BlPrint("Couldn't read first sector from drive %i\n",DriveId);
|
|
while (!GET_KEY()) {
|
|
}
|
|
#endif
|
|
return(EIO);
|
|
}
|
|
BootSector = (PPACKED_BOOT_SECTOR)Buffer;
|
|
|
|
FatUnpackBios(&Bpb, &(BootSector->PackedBpb));
|
|
|
|
NumberHeads = Bpb.Heads;
|
|
NumberSectors = Bpb.SectorsPerTrack;
|
|
NumberCylinders = Bpb.Sectors / (NumberSectors * NumberHeads);
|
|
|
|
#ifdef FLOPPY_CACHE
|
|
//
|
|
// Cache floppy 0 if not already cached.
|
|
//
|
|
if((DriveId == 0) && !FcIsThisFloppyCached(Buffer)) {
|
|
FcCacheFloppyDisk(&Bpb);
|
|
}
|
|
#endif
|
|
#if defined(ELTORITO)
|
|
} else if (IsCd) {
|
|
// This is an El Torito drive
|
|
// Just use bogus values since CHS values are meaningless for no-emulation El Torito boot
|
|
|
|
NumberCylinders = 1;
|
|
NumberHeads = 1;
|
|
NumberSectors = 1;
|
|
#endif
|
|
} else {
|
|
Retries=0;
|
|
do {
|
|
Return=BIOS_IO( 0x08, // BIOS Get Drive Parameters
|
|
(USHORT)DriveId,
|
|
0,0,0,0,0 ); // Not used
|
|
//
|
|
// At this point, AH should hold our return code, and ECX should look
|
|
// like this:
|
|
// bits 31..22 - Maximum cylinder
|
|
// bits 21..16 - Maximum sector
|
|
// bits 15..8 - Maximum head
|
|
// bits 7..0 - Number of drives
|
|
//
|
|
_asm {
|
|
mov Result, ecx
|
|
}
|
|
|
|
//
|
|
// Unpack the information from ecx
|
|
//
|
|
|
|
NumberDrives = Result & 0xff;
|
|
NumberHeads = ((Result >> 8) & 0xff) + 1;
|
|
NumberSectors = (Result >> 16) & 0x3f;
|
|
NumberCylinders = ((Result >> 24) + ((Result >> 14) &0x300)) + 1;
|
|
|
|
++Retries;
|
|
|
|
} while ( ((NumberHeads==0) || (NumberSectors==0) || (NumberCylinders==0))
|
|
&& (Retries < 5) );
|
|
|
|
|
|
if ((DriveId & 0x7f) >= NumberDrives) {
|
|
//
|
|
// The requested DriveId does not exist
|
|
//
|
|
return(EIO);
|
|
}
|
|
|
|
if (Retries == 5) {
|
|
#ifdef LOADER_DEBUG
|
|
BlPrint("Couldn't get BIOS configuration info\n");
|
|
#endif
|
|
return(EIO);
|
|
}
|
|
}
|
|
|
|
#ifdef LOADER_DEBUG
|
|
BlPrint("Bios info: D %lx H %lx S %lx C %lx\n",
|
|
DriveId,
|
|
NumberHeads,
|
|
NumberSectors,
|
|
NumberCylinders );
|
|
|
|
while (!GET_KEY()) {
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Find an available FileId descriptor to open the device with
|
|
//
|
|
*FileId=2;
|
|
|
|
while (BlFileTable[*FileId].Flags.Open != 0) {
|
|
*FileId += 1;
|
|
if (*FileId == BL_FILE_TABLE_SIZE) {
|
|
return(ENOENT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We found an entry we can use, so mark it as open.
|
|
//
|
|
BlFileTable[*FileId].Flags.Open = 1;
|
|
|
|
#if defined(ELTORITO)
|
|
if(IsCd) {
|
|
// We're using the Phoenix Enhanced Disk Drive Spec
|
|
BlFileTable[*FileId].DeviceEntryTable = &BiosEDDSEntryTable;
|
|
} else {
|
|
#endif
|
|
BlFileTable[*FileId].DeviceEntryTable = &BiosDiskEntryTable;
|
|
#if defined(ELTORITO)
|
|
}
|
|
#endif
|
|
|
|
Context = &(BlFileTable[*FileId].u.DriveContext);
|
|
|
|
Context->Drive = DriveId;
|
|
Context->Cylinders = NumberCylinders;
|
|
Context->Heads = NumberHeads;
|
|
Context->Sectors = NumberSectors;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiospWritePartialSector(
|
|
IN ULONGLONG Sector,
|
|
IN PUCHAR Buffer,
|
|
IN BOOLEAN IsHead,
|
|
IN ULONG Bytes,
|
|
IN PDRIVE_CONTEXT DriveContext
|
|
)
|
|
{
|
|
ULONG head,sector,cylinder;
|
|
ULONG SectorsPerCylinder,r;
|
|
ARC_STATUS Status;
|
|
|
|
//
|
|
// figure out CHS values to address the given sector
|
|
//
|
|
|
|
SectorsPerCylinder = DriveContext->Heads * DriveContext->Sectors;
|
|
cylinder = (ULONG)(Sector / SectorsPerCylinder);
|
|
r = (ULONG)(Sector % SectorsPerCylinder);
|
|
head = r / DriveContext->Sectors;
|
|
sector = (r % DriveContext->Sectors) + 1;
|
|
|
|
//
|
|
// read sector into the write buffer
|
|
//
|
|
|
|
Status = MdGetPhysicalSectors((USHORT)DriveContext->Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// xfer the appropriate bytes from the user buffer to the write buffer
|
|
//
|
|
|
|
RtlMoveMemory(IsHead ? LocalBuffer + Bytes : LocalBuffer,
|
|
Buffer,
|
|
IsHead ? SECTOR_SIZE - Bytes : Bytes
|
|
);
|
|
|
|
//
|
|
// write the sector out
|
|
//
|
|
|
|
Status = MdPutPhysicalSectors((USHORT)DriveContext->Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosDiskWrite(
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes sectors directly to an open physical disk.
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the file to write to
|
|
|
|
Buffer - Supplies buffer with data to write
|
|
|
|
Length - Supplies number of bytes to write
|
|
|
|
Count - Returns actual bytes written
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - write completed successfully
|
|
|
|
!ESUCCESS - write failed
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG HeadSector,TailSector,CurrentSector;
|
|
ULONG HeadOffset,TailByteCount;
|
|
ARC_STATUS Status;
|
|
ULONG BytesLeftToTransfer = Length;
|
|
PUCHAR UserBuffer = Buffer;
|
|
ULONG SectorsPerCylinder,SectorsPerTrack;
|
|
ULONG cylinder,head,sector,r;
|
|
ULONG SectorsToTransfer;
|
|
BOOLEAN Under1MegLine = FALSE;
|
|
PVOID TransferBuffer;
|
|
|
|
if (LocalBuffer==NULL) {
|
|
LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
|
|
if (LocalBuffer==NULL) {
|
|
return(ENOMEM);
|
|
}
|
|
}
|
|
|
|
HeadSector = BlFileTable[FileId].Position.QuadPart / SECTOR_SIZE;
|
|
HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % SECTOR_SIZE);
|
|
|
|
TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / SECTOR_SIZE;
|
|
TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % SECTOR_SIZE);
|
|
|
|
CurrentSector = HeadSector;
|
|
|
|
SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
|
|
SectorsPerCylinder = BlFileTable[FileId].u.DriveContext.Heads
|
|
* SectorsPerTrack;
|
|
|
|
//
|
|
// special case of transfer occuring entirely within one sector
|
|
//
|
|
|
|
if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
|
|
|
|
cylinder = (ULONG)(CurrentSector / SectorsPerCylinder);
|
|
r = (ULONG)(CurrentSector % SectorsPerCylinder);
|
|
head = r / SectorsPerTrack;
|
|
sector = (r % SectorsPerTrack) + 1;
|
|
|
|
Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
RtlMoveMemory((PUCHAR)LocalBuffer + HeadOffset,
|
|
Buffer,
|
|
Length
|
|
);
|
|
|
|
Status = MdPutPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
goto BiosWriteDone;
|
|
}
|
|
|
|
if(HeadOffset) {
|
|
|
|
Status = BiospWritePartialSector(HeadSector,
|
|
Buffer,
|
|
TRUE, // head, not tail
|
|
HeadOffset,
|
|
&BlFileTable[FileId].u.DriveContext
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
BytesLeftToTransfer -= SECTOR_SIZE - HeadOffset;
|
|
UserBuffer += SECTOR_SIZE - HeadOffset;
|
|
CurrentSector += 1;
|
|
}
|
|
|
|
if(TailByteCount) {
|
|
|
|
Status = BiospWritePartialSector(TailSector,
|
|
(PUCHAR)Buffer + Length - TailByteCount,
|
|
FALSE,
|
|
TailByteCount,
|
|
&BlFileTable[FileId].u.DriveContext
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
BytesLeftToTransfer -= TailByteCount;
|
|
}
|
|
|
|
|
|
//
|
|
// The following calculation is not inside the transfer loop because
|
|
// it is unlikely that a caller's buffer will *cross* the 1 meg line
|
|
// due to the PC memory map.
|
|
//
|
|
|
|
if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
|
|
Under1MegLine = TRUE;
|
|
}
|
|
|
|
//
|
|
// now handle the middle part. This is some number of whole sectors.
|
|
//
|
|
|
|
while(BytesLeftToTransfer) {
|
|
|
|
//
|
|
// Get CHS address of current sector
|
|
//
|
|
|
|
cylinder = (ULONG)(CurrentSector / SectorsPerCylinder);
|
|
r = (ULONG)(CurrentSector % SectorsPerCylinder);
|
|
|
|
head = r / SectorsPerTrack;
|
|
sector = (r % SectorsPerTrack) + 1;
|
|
|
|
//
|
|
// The number of sectors to transfer is the minimum of:
|
|
// - the number of sectors left in the current track
|
|
// - BytesLeftToTransfer / SECTOR_SIZE
|
|
//
|
|
|
|
SectorsToTransfer = min(SectorsPerTrack - sector + 1,BytesLeftToTransfer / SECTOR_SIZE);
|
|
|
|
//
|
|
// Now we'll figure out where to transfer the data from. If the
|
|
// caller's buffer is under the 1 meg line, we can transfer the
|
|
// data directly from the caller's buffer. Otherwise we'll copy the
|
|
// user's buffer to our local buffer and transfer from there.
|
|
// In the latter case we can only transfer in chunks of
|
|
// SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
|
|
//
|
|
// Also make sure the transfer won't cross a 64k boundary.
|
|
//
|
|
|
|
if(Under1MegLine) {
|
|
|
|
//
|
|
// Check if the transfer would cross a 64k boundary. If so,
|
|
// use the local buffer. Otherwise use the user's buffer.
|
|
//
|
|
|
|
if(((ULONG)UserBuffer & 0xffff0000)
|
|
!= (((ULONG)UserBuffer + (SectorsToTransfer * SECTOR_SIZE) - 1) & 0xffff0000))
|
|
{
|
|
TransferBuffer = LocalBuffer;
|
|
SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
|
|
|
|
} else {
|
|
|
|
TransferBuffer = UserBuffer;
|
|
}
|
|
} else {
|
|
TransferBuffer = LocalBuffer;
|
|
SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
|
|
}
|
|
|
|
if(TransferBuffer == LocalBuffer) {
|
|
RtlMoveMemory(LocalBuffer,UserBuffer,SectorsToTransfer*SECTOR_SIZE);
|
|
}
|
|
|
|
Status = MdPutPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
(USHORT)SectorsToTransfer,
|
|
TransferBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
CurrentSector += SectorsToTransfer;
|
|
BytesLeftToTransfer -= SectorsToTransfer * SECTOR_SIZE;
|
|
UserBuffer += SectorsToTransfer * SECTOR_SIZE;
|
|
}
|
|
|
|
BiosWriteDone:
|
|
|
|
*Count = Length;
|
|
BlFileTable[FileId].Position.QuadPart += Length;
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosDiskRead (
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads sectors directly from an open physical disk.
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the file to read from
|
|
|
|
Buffer - Supplies buffer to hold the data that is read
|
|
|
|
Length - Supplies maximum number of bytes to read
|
|
|
|
Count - Returns actual bytes read
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Read completed successfully
|
|
|
|
!ESUCCESS - Read failed
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG HeadSector,TailSector,CurrentSector;
|
|
ULONG HeadOffset,TailByteCount;
|
|
ULONG BytesLeftToTransfer = Length;
|
|
ULONG SectorsPerTrack,SectorsPerCylinder;
|
|
ARC_STATUS Status;
|
|
PUCHAR UserBuffer = Buffer;
|
|
ULONG cylinder,head,sector,r;
|
|
ULONG SectorsToTransfer;
|
|
BOOLEAN Under1MegLine = FALSE;
|
|
PVOID TransferBuffer;
|
|
|
|
|
|
#ifdef FLOPPY_CACHE
|
|
//
|
|
// For A:, try to satisfy the read from the cache.
|
|
//
|
|
if(!BlFileTable[FileId].u.DriveContext.Drive) {
|
|
|
|
Status = FcReadFromCache(
|
|
BlFileTable[FileId].Position.LowPart,
|
|
Length,
|
|
Buffer
|
|
);
|
|
|
|
if(Status == ESUCCESS) {
|
|
|
|
BlFileTable[FileId].Position.QuadPart += Length;
|
|
*Count = Length;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
//
|
|
// EINVAL means the read could not be satisfied from the cache.
|
|
//
|
|
if(Status != EINVAL) {
|
|
return(Status);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (LocalBuffer==NULL) {
|
|
LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
|
|
if (LocalBuffer==NULL) {
|
|
return(ENOMEM);
|
|
}
|
|
}
|
|
|
|
SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
|
|
SectorsPerCylinder = BlFileTable[FileId].u.DriveContext.Heads
|
|
* SectorsPerTrack;
|
|
|
|
HeadSector = BlFileTable[FileId].Position.QuadPart / SECTOR_SIZE;
|
|
HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % SECTOR_SIZE);
|
|
|
|
TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / SECTOR_SIZE;
|
|
TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % SECTOR_SIZE);
|
|
|
|
CurrentSector = HeadSector;
|
|
if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
|
|
|
|
cylinder = (ULONG)(HeadSector / SectorsPerCylinder);
|
|
r = (ULONG)(HeadSector % SectorsPerCylinder);
|
|
head = r / SectorsPerTrack;
|
|
sector = (r % SectorsPerTrack) + 1;
|
|
|
|
Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
RtlMoveMemory(Buffer,LocalBuffer + HeadOffset,Length);
|
|
goto BiosDiskReadDone;
|
|
}
|
|
|
|
if(HeadOffset) {
|
|
|
|
cylinder = (ULONG)(HeadSector / SectorsPerCylinder);
|
|
r = (ULONG)(HeadSector % SectorsPerCylinder);
|
|
head = r / SectorsPerTrack;
|
|
sector = (r % SectorsPerTrack) + 1;
|
|
|
|
Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
RtlMoveMemory(Buffer,LocalBuffer + HeadOffset,SECTOR_SIZE - HeadOffset);
|
|
|
|
BytesLeftToTransfer -= SECTOR_SIZE - HeadOffset;
|
|
UserBuffer += SECTOR_SIZE - HeadOffset;
|
|
CurrentSector = HeadSector + 1;
|
|
}
|
|
|
|
if(TailByteCount) {
|
|
|
|
cylinder = (ULONG)(TailSector / SectorsPerCylinder);
|
|
r = (ULONG)(TailSector % SectorsPerCylinder);
|
|
head = r / SectorsPerTrack;
|
|
sector = (r % SectorsPerTrack) + 1;
|
|
|
|
Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
RtlMoveMemory((PUCHAR)Buffer+Length-TailByteCount,LocalBuffer,TailByteCount);
|
|
|
|
BytesLeftToTransfer -= TailByteCount;
|
|
}
|
|
|
|
//
|
|
// The following calculation is not inside the transfer loop because
|
|
// it is unlikely that a caller's buffer will *cross* the 1 meg line
|
|
// due to the PC memory map.
|
|
//
|
|
|
|
if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
|
|
Under1MegLine = TRUE;
|
|
}
|
|
|
|
//
|
|
// Now BytesLeftToTransfer is an integral multiple of sector size.
|
|
//
|
|
|
|
while(BytesLeftToTransfer) {
|
|
|
|
cylinder = (ULONG)(CurrentSector / SectorsPerCylinder);
|
|
r = (ULONG)(CurrentSector % SectorsPerCylinder);
|
|
head = r / SectorsPerTrack;
|
|
sector = (r % SectorsPerTrack) + 1;
|
|
|
|
//
|
|
// The number of sectors to transfer is the minimum of:
|
|
// - the number of sectors left in the current track
|
|
// - BytesLeftToTransfer / SECTOR_SIZE
|
|
//
|
|
|
|
SectorsToTransfer = min(SectorsPerTrack - sector + 1,BytesLeftToTransfer / SECTOR_SIZE);
|
|
|
|
//
|
|
// Now we'll figure out where to transfer the data to. If the
|
|
// caller's buffer is under the 1 meg line, we can transfer the
|
|
// data directly to the caller's buffer. Otherwise we'll transfer
|
|
// the data to our local buffer and copy it to the caller's buffer.
|
|
// In the latter case we can only transfer in chunks of
|
|
// SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
|
|
//
|
|
// Also make sure the transfer won't cross a 64k boundary.
|
|
//
|
|
|
|
if(Under1MegLine) {
|
|
|
|
//
|
|
// Check if the transfer would cross a 64k boundary. If so,
|
|
// use the local buffer. Otherwise use the user's buffer.
|
|
//
|
|
|
|
if(((ULONG)UserBuffer & 0xffff0000)
|
|
!= (((ULONG)UserBuffer + (SectorsToTransfer * SECTOR_SIZE) - 1) & 0xffff0000))
|
|
{
|
|
TransferBuffer = LocalBuffer;
|
|
SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
|
|
|
|
} else {
|
|
|
|
TransferBuffer = UserBuffer;
|
|
}
|
|
} else {
|
|
TransferBuffer = LocalBuffer;
|
|
SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
|
|
}
|
|
|
|
Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(USHORT)head,
|
|
(USHORT)cylinder,
|
|
(USHORT)sector,
|
|
(USHORT)SectorsToTransfer,
|
|
TransferBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
if(TransferBuffer == LocalBuffer) {
|
|
|
|
RtlMoveMemory(UserBuffer,LocalBuffer,SectorsToTransfer * SECTOR_SIZE);
|
|
}
|
|
UserBuffer += SectorsToTransfer * SECTOR_SIZE;
|
|
CurrentSector += SectorsToTransfer;
|
|
BytesLeftToTransfer -= SectorsToTransfer*SECTOR_SIZE;
|
|
}
|
|
|
|
BiosDiskReadDone:
|
|
|
|
*Count = Length;
|
|
BlFileTable[FileId].Position.QuadPart += Length;
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
#if defined(ELTORITO)
|
|
ARC_STATUS
|
|
BiosEDDSDiskRead (
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads sectors directly from an open physical disk using Phoenix Enhanced Disk Drive Spec. interface.
|
|
|
|
BUGBUG - sector size of 2048 shouldn't be used here - instead to sector size should be obtained
|
|
from drive context.
|
|
|
|
Arguments:
|
|
|
|
FileId - Supplies the file to read from
|
|
|
|
Buffer - Supplies buffer to hold the data that is read
|
|
|
|
Length - Supplies maximum number of bytes to read
|
|
|
|
Count - Returns actual bytes read
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Read completed successfully
|
|
|
|
!ESUCCESS - Read failed
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONGLONG StartLBA, EndLBA, CurrentLBA;
|
|
ULONG CurrentLBAHigh, CurrentLBALow;
|
|
ULONG StartOffset,EndOffset;
|
|
ULONG BytesLeftToTransfer = Length;
|
|
ARC_STATUS Status;
|
|
ULONG LBsToTransfer;
|
|
PUCHAR UserBuffer = Buffer;
|
|
BOOLEAN Under1MegLine = FALSE;
|
|
PVOID TransferBuffer;
|
|
|
|
if (LocalBuffer==NULL) {
|
|
LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
|
|
if (LocalBuffer==NULL) {
|
|
return(ENOMEM);
|
|
}
|
|
}
|
|
|
|
StartLBA = BlFileTable[FileId].Position.QuadPart / 2048;
|
|
StartOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % 2048);
|
|
|
|
EndLBA = (BlFileTable[FileId].Position.QuadPart + Length) / 2048;
|
|
EndOffset = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % 2048);
|
|
|
|
CurrentLBA = StartLBA;
|
|
|
|
if(StartOffset && EndOffset && (StartLBA == EndLBA)) {
|
|
//
|
|
// We're starting and ending in the middle of a Logical Block - this transfers the whole thing
|
|
//
|
|
|
|
CurrentLBALow = (ULONG)(CurrentLBA & 0x00000000ffffffff);
|
|
CurrentLBAHigh = (ULONG)(CurrentLBA >> 32 & 0x00000000ffffffff);
|
|
|
|
Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(ULONG)CurrentLBALow,
|
|
(ULONG)CurrentLBAHigh,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
RtlMoveMemory(Buffer,LocalBuffer + StartOffset,Length);
|
|
goto BiosEDDSDiskReadDone;
|
|
}
|
|
|
|
if(StartOffset) {
|
|
//
|
|
// We're starting in the middle of a Logical Block, but ending in another - this transfers the first piece
|
|
//
|
|
|
|
CurrentLBALow = (ULONG)(CurrentLBA & 0x00000000ffffffff);
|
|
CurrentLBAHigh = (ULONG)(CurrentLBA >> 32 & 0x00000000ffffffff);
|
|
|
|
Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(ULONG)CurrentLBALow,
|
|
(ULONG)CurrentLBAHigh,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
RtlMoveMemory(Buffer, LocalBuffer + StartOffset, 2048 - StartOffset);
|
|
|
|
BytesLeftToTransfer -= (2048 - StartOffset);
|
|
UserBuffer += (2048 - StartOffset);
|
|
CurrentLBA = StartLBA + 1;
|
|
}
|
|
|
|
if(EndOffset) {
|
|
//
|
|
// We're ending in the middle of a Logical Block - this just transfers the end piece
|
|
//
|
|
|
|
CurrentLBALow = (ULONG)(EndLBA & 0x00000000ffffffff);
|
|
CurrentLBAHigh = (ULONG)(EndLBA >> 32 & 0x00000000ffffffff);
|
|
|
|
Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(ULONG)CurrentLBALow,
|
|
(ULONG)CurrentLBAHigh,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
RtlMoveMemory((PUCHAR)Buffer+Length-EndOffset, LocalBuffer, EndOffset);
|
|
|
|
BytesLeftToTransfer -= EndOffset;
|
|
}
|
|
|
|
//
|
|
// The following calculation is not inside the transfer loop because
|
|
// it is unlikely that a caller's buffer will *cross* the 1 meg line
|
|
// due to the PC memory map.
|
|
//
|
|
|
|
if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
|
|
Under1MegLine = TRUE;
|
|
}
|
|
|
|
//
|
|
// Now BytesLeftToTransfer is an integral multiple of logical blocks.
|
|
//
|
|
while(BytesLeftToTransfer) {
|
|
|
|
LBsToTransfer = BytesLeftToTransfer / 2048;
|
|
|
|
//
|
|
// Now we'll figure out where to transfer the data to. If the
|
|
// caller's buffer is under the 1 meg line, we can transfer the
|
|
// data directly to the caller's buffer. Otherwise we'll transfer
|
|
// the data to our local buffer and copy it to the caller's buffer.
|
|
// In the latter case we can only transfer in chunks of
|
|
// SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
|
|
//
|
|
// Also make sure the transfer won't cross a 64k boundary.
|
|
//
|
|
|
|
if(Under1MegLine) {
|
|
//
|
|
// Check if the transfer would cross a 64k boundary. If so,
|
|
// use the local buffer. Otherwise use the user's buffer.
|
|
//
|
|
|
|
if(((ULONG)UserBuffer & 0xffff0000)
|
|
!= (((ULONG)UserBuffer + (LBsToTransfer * 2048) - 1) & 0xffff0000))
|
|
{
|
|
TransferBuffer = LocalBuffer;
|
|
LBsToTransfer = min(LBsToTransfer, SCRATCH_BUFFER_SIZE / 2048);
|
|
} else {
|
|
TransferBuffer = UserBuffer;
|
|
}
|
|
} else {
|
|
TransferBuffer = LocalBuffer;
|
|
LBsToTransfer = min(LBsToTransfer, SCRATCH_BUFFER_SIZE / 2048);
|
|
}
|
|
|
|
CurrentLBALow = (ULONG)(CurrentLBA & 0x00000000ffffffff);
|
|
CurrentLBAHigh = (ULONG)(CurrentLBA >> 32 & 0x00000000ffffffff);
|
|
|
|
Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
|
|
(ULONG)CurrentLBALow,
|
|
(ULONG)CurrentLBAHigh,
|
|
(USHORT)LBsToTransfer,
|
|
TransferBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
if(TransferBuffer == LocalBuffer) {
|
|
|
|
RtlMoveMemory(UserBuffer, LocalBuffer, LBsToTransfer * 2048);
|
|
|
|
}
|
|
UserBuffer += LBsToTransfer * 2048;
|
|
CurrentLBA += LBsToTransfer;
|
|
BytesLeftToTransfer -= (LBsToTransfer * 2048);
|
|
}
|
|
|
|
BiosEDDSDiskReadDone:
|
|
|
|
*Count = Length;
|
|
BlFileTable[FileId].Position.QuadPart += Length;
|
|
return(ESUCCESS);
|
|
}
|
|
#endif
|
|
|
|
|
|
ARC_STATUS
|
|
BiosGetFileInfo(
|
|
IN ULONG FileId,
|
|
OUT PFILE_INFORMATION Finfo
|
|
)
|
|
{
|
|
//
|
|
// THIS ROUTINE DOES NOT WORK FOR PARTITION 0.
|
|
//
|
|
|
|
PPARTITION_CONTEXT Context;
|
|
|
|
RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
|
|
|
|
Context = &BlFileTable[FileId].u.PartitionContext;
|
|
|
|
Finfo->StartingAddress.QuadPart = Context->StartingSector;
|
|
Finfo->StartingAddress.QuadPart = Finfo->StartingAddress.QuadPart << (CCHAR)Context->SectorShift;
|
|
|
|
Finfo->EndingAddress.QuadPart = Finfo->StartingAddress.QuadPart + Context->PartitionLength.QuadPart;
|
|
|
|
Finfo->Type = DiskPeripheral;
|
|
|
|
return ESUCCESS;
|
|
}
|