mirror of https://github.com/tongzx/nt5src
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.
4104 lines
114 KiB
4104 lines
114 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:
|
|
|
|
Allen Kay (akay) 19-May-1999
|
|
|
|
--*/
|
|
|
|
#include "arccodes.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
|
|
#if defined(_IA64_)
|
|
#include "bootia64.h"
|
|
#endif
|
|
|
|
#if defined(_X86_)
|
|
#include "bootx86.h"
|
|
#endif
|
|
|
|
#include "bootefi.h"
|
|
#include "biosdrv.h"
|
|
|
|
#include "efi.h"
|
|
#include "efip.h"
|
|
#include "flop.h"
|
|
|
|
//
|
|
// Externals
|
|
//
|
|
|
|
extern VOID FlipToVirtual();
|
|
extern VOID FlipToPhysical();
|
|
extern ULONGLONG CompareGuid();
|
|
|
|
extern BOOT_CONTEXT BootContext;
|
|
extern EFI_HANDLE EfiImageHandle;
|
|
extern EFI_SYSTEM_TABLE *EfiST;
|
|
extern EFI_BOOT_SERVICES *EfiBS;
|
|
extern EFI_RUNTIME_SERVICES *EfiRS;
|
|
extern EFI_GUID EfiDevicePathProtocol;
|
|
extern EFI_GUID EfiBlockIoProtocol;
|
|
extern EFI_GUID EfiDiskIoProtocol;
|
|
extern EFI_GUID EfiLoadedImageProtocol;
|
|
extern EFI_GUID EfiFilesystemProtocol;
|
|
|
|
extern
|
|
ULONG GetDevPathSize(
|
|
IN EFI_DEVICE_PATH *DevPath
|
|
);
|
|
|
|
#if 0
|
|
#define DBGOUT(x) BlPrint x
|
|
#define DBGPAUSE while(!GET_KEY());
|
|
#else
|
|
#define DBGOUT(x)
|
|
#define DBGPAUSE
|
|
#endif
|
|
|
|
|
|
//
|
|
// defines for doing console I/O
|
|
//
|
|
#define CSI 0x95
|
|
#define SGR_INVERSE 7
|
|
#define SGR_NORMAL 0
|
|
|
|
//
|
|
// define for FloppyOpenMode
|
|
//
|
|
#define FloppyOpenMode 0xCDEFABCD
|
|
|
|
//
|
|
// static data for console I/O
|
|
//
|
|
BOOLEAN ControlSequence=FALSE;
|
|
BOOLEAN EscapeSequence=FALSE;
|
|
BOOLEAN FontSelection=FALSE;
|
|
BOOLEAN HighIntensity=FALSE;
|
|
BOOLEAN Blink=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
|
|
);
|
|
|
|
#define DEVICE_NOT_FOUND 0xFEEBEE
|
|
|
|
#ifdef FORCE_CD_BOOT
|
|
|
|
EFI_HANDLE
|
|
GetCdTest(
|
|
VOID
|
|
);
|
|
|
|
#endif
|
|
|
|
ULONG
|
|
FindAtapiDevice(
|
|
ULONGLONG *pDevicePaths,
|
|
ULONG nDevicePaths,
|
|
ULONG PrimarySecondary,
|
|
ULONG SlaveMaster,
|
|
ULONG Lun
|
|
);
|
|
|
|
ULONG
|
|
FindScsiDevice(
|
|
ULONGLONG *pDevicePaths,
|
|
ULONG nDevicePaths,
|
|
ULONG Pun,
|
|
ULONG Lun
|
|
);
|
|
|
|
//
|
|
// 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)BiosPartitionGetFileInfo,
|
|
(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)BiosDiskGetFileInfo,
|
|
(PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
|
|
(PRENAME_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
|
|
(PBOOTFS_INFO)BlArcNotYetImplemented
|
|
};
|
|
|
|
BL_DEVICE_ENTRY_TABLE BiosEDDSEntryTable =
|
|
{
|
|
(PARC_CLOSE_ROUTINE)BiosDiskClose,
|
|
(PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_OPEN_ROUTINE)BiosDiskOpen,
|
|
(PARC_READ_ROUTINE)BiosElToritoDiskRead,
|
|
(PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_SEEK_ROUTINE)BiosPartitionSeek,
|
|
(PARC_WRITE_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_FILE_INFO_ROUTINE)BiosDiskGetFileInfo,
|
|
(PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
|
|
(PRENAME_ROUTINE)BlArcNotYetImplemented,
|
|
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
|
|
(PBOOTFS_INFO)BlArcNotYetImplemented
|
|
};
|
|
|
|
|
|
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(TEXT("ERROR - Unopened fileid %lx closed\r\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(TEXT("ERROR - Unopened fileid %lx closed\r\n"),FileId);
|
|
}
|
|
BlFileTable[FileId].Flags.Open = 0;
|
|
|
|
return(BiosDiskClose((ULONG)BlFileTable[FileId].u.PartitionContext.DiskId));
|
|
}
|
|
|
|
|
|
#define STR_PREFIX
|
|
#define DBG_PRINT(x)
|
|
|
|
|
|
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, FloppyOpenMode, 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, FloppyOpenMode, FileId));
|
|
}
|
|
|
|
if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)") == 0) ||
|
|
(_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)" ) == 0))
|
|
{
|
|
return(BiosDiskOpen( 0, FloppyOpenMode, FileId));
|
|
}
|
|
if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)") == 0) ||
|
|
(_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)" ) == 0))
|
|
{
|
|
return(BiosDiskOpen( 1, FloppyOpenMode, 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 (!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 ) );
|
|
}
|
|
|
|
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( Key,
|
|
0,
|
|
&DiskFileId );
|
|
|
|
if (Status != ESUCCESS) {
|
|
DBG_PRINT(STR_PREFIX"BiosDiskOpen Failed\r\n");
|
|
|
|
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);
|
|
|
|
DBG_PRINT(STR_PREFIX"Trying HardDiskPartitionOpen(...)\r\n");
|
|
|
|
//
|
|
// Try to open the MBR partition
|
|
//
|
|
Status = HardDiskPartitionOpen( *FileId,
|
|
DiskFileId,
|
|
PartitionNumber);
|
|
|
|
|
|
#ifdef EFI_PARTITION_SUPPORT
|
|
|
|
if (Status != ESUCCESS) {
|
|
//
|
|
// Try to open the GPT partition
|
|
//
|
|
DBG_PRINT(STR_PREFIX"Trying BlOpenGPTDiskPartition(...)\r\n");
|
|
|
|
Status = BlOpenGPTDiskPartition(*FileId,
|
|
DiskFileId,
|
|
PartitionNumber);
|
|
}
|
|
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
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 +
|
|
(ULONGLONG)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(TEXT("SeekMode %lx not supported\r\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 +
|
|
(ULONGLONG)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 = ARC_CONSOLE_INPUT;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
if (_stricmp(OpenPath, CONSOLE_OUTPUT_NAME)==0) {
|
|
|
|
//
|
|
// Open the display for output
|
|
//
|
|
|
|
if (OpenMode != ArcOpenWriteOnly) {
|
|
return(EACCES);
|
|
}
|
|
*FileId = ARC_CONSOLE_OUTPUT;
|
|
|
|
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;
|
|
|
|
//
|
|
// If we have buffered input...
|
|
//
|
|
if (KeyBufferEnd != KeyBufferStart) {
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
//
|
|
// Check for a 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.
|
|
|
|
All keys translated here use the ARC translation table, as defined in the
|
|
ARC specification, with one exception -- the BACKTAB_KEY, for which the
|
|
ARC spec is lacking. I have decided that BACKTAB_KEY is ESC+TAB.
|
|
|
|
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 RIGHT_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'C';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case LEFT_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'D';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case INS_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = '@';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case DEL_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'P';
|
|
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 F2_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] = 'Q';
|
|
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;
|
|
|
|
case F8_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] = 'r';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case F10_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] = 'M';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case HOME_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'H';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case END_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = 'K';
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case ESCAPE_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
break;
|
|
|
|
case BACKTAB_KEY:
|
|
KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
|
|
KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
|
|
KeyBuffer[KeyBufferEnd] = (UCHAR)(TAB_KEY & 0xFF);
|
|
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 PWCHAR 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;
|
|
PWCHAR String;
|
|
ULONG Index;
|
|
WCHAR a;
|
|
PWCHAR p;
|
|
ULONG y;
|
|
|
|
//
|
|
// Process each character in turn.
|
|
//
|
|
|
|
Status = ESUCCESS;
|
|
String = Buffer;
|
|
|
|
for ( *Count = 0 ;
|
|
*Count < Length ;
|
|
String++,*Count = *Count+sizeof(WCHAR) ) {
|
|
|
|
//
|
|
// 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 >= L'0') && (*String <= L'9')) {
|
|
Parameter[PCount] = Parameter[PCount] * 10 + *String - L'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 L';':
|
|
|
|
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 L'J':
|
|
|
|
switch (Parameter[0]) {
|
|
case 0:
|
|
//
|
|
// Erase to end of the screen
|
|
//
|
|
BlEfiClearToEndOfDisplay();
|
|
//TextClearToEndOfDisplay();
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// Erase from the beginning of the screen
|
|
//
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Erase entire screen
|
|
//
|
|
//TextClearDisplay();
|
|
BlEfiClearDisplay();
|
|
break;
|
|
}
|
|
|
|
ControlSequence = FALSE;
|
|
break;
|
|
|
|
//
|
|
// If a 'K', erase part or all of the line.
|
|
//
|
|
|
|
case L'K':
|
|
|
|
switch (Parameter[0]) {
|
|
|
|
//
|
|
// Erase to end of the line.
|
|
//
|
|
|
|
case 0:
|
|
//TextClearToEndOfLine();
|
|
BlEfiClearToEndOfDisplay();
|
|
break;
|
|
|
|
//
|
|
// Erase from the beginning of the line.
|
|
//
|
|
|
|
case 1:
|
|
//TextClearFromStartOfLine();
|
|
BlEfiClearToEndOfLine();
|
|
break;
|
|
|
|
//
|
|
// Erase entire line.
|
|
//
|
|
|
|
default :
|
|
BlEfiGetCursorPosition( NULL, &y );
|
|
BlEfiPositionCursor( 0, y );
|
|
BlEfiClearToEndOfLine();
|
|
//TextClearFromStartOfLine();
|
|
//TextClearToEndOfLine();
|
|
break;
|
|
}
|
|
|
|
ControlSequence = FALSE;
|
|
break;
|
|
|
|
//
|
|
// If a 'H', move cursor to position.
|
|
//
|
|
|
|
case 'H':
|
|
//TextSetCursorPosition(Parameter[1]-1, Parameter[0]-1);
|
|
BlEfiPositionCursor( Parameter[1]-1, Parameter[0]-1 );
|
|
ControlSequence = FALSE;
|
|
break;
|
|
|
|
//
|
|
// If a ' ', could be a FNT selection command.
|
|
//
|
|
|
|
case L' ':
|
|
FontSelection = TRUE;
|
|
break;
|
|
|
|
case L'm':
|
|
//
|
|
// Select action based on each parameter.
|
|
//
|
|
// Blink and HighIntensity are by default disabled
|
|
// each time a new SGR is specified, unless they are
|
|
// explicitly specified again, in which case these
|
|
// will be set to TRUE at that time.
|
|
//
|
|
|
|
HighIntensity = FALSE;
|
|
Blink = FALSE;
|
|
|
|
for ( Index = 0 ; Index <= PCount ; Index++ ) {
|
|
switch (Parameter[Index]) {
|
|
|
|
//
|
|
// Attributes off.
|
|
//
|
|
|
|
case 0:
|
|
// bugbug blink???
|
|
BlEfiSetAttribute( ATT_FG_WHITE );
|
|
//TextSetCurrentAttribute(7);
|
|
//
|
|
HighIntensity = FALSE;
|
|
Blink = FALSE;
|
|
break;
|
|
|
|
//
|
|
// High Intensity.
|
|
//
|
|
|
|
case 1:
|
|
BlEfiSetAttribute( ATT_FG_INTENSE );
|
|
//TextSetCurrentAttribute(0xf);
|
|
HighIntensity = TRUE;
|
|
break;
|
|
|
|
//
|
|
// Underscored.
|
|
//
|
|
|
|
case 4:
|
|
break;
|
|
|
|
//
|
|
// Blink.
|
|
//
|
|
|
|
case 5:
|
|
//bugbug no blink in EFI
|
|
//TextSetCurrentAttribute(0x87);
|
|
Blink = TRUE;
|
|
break;
|
|
|
|
//
|
|
// Reverse Video.
|
|
//
|
|
|
|
case 7:
|
|
BlEfiSetInverseMode( TRUE );
|
|
//TextSetCurrentAttribute(0x70);
|
|
HighIntensity = FALSE;
|
|
Blink = FALSE;
|
|
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:
|
|
//bugbug EFI
|
|
#if 0
|
|
a = TextGetCurrentAttribute();
|
|
a &= 0x70;
|
|
a |= TranslateColor[Parameter[Index]-30];
|
|
if (HighIntensity) {
|
|
a |= 0x08;
|
|
}
|
|
if (Blink) {
|
|
a |= 0x80;
|
|
}
|
|
TextSetCurrentAttribute(a);
|
|
break;
|
|
|
|
//
|
|
// Background Color
|
|
//
|
|
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47:
|
|
a = TextGetCurrentAttribute();
|
|
a &= 0x8f;
|
|
a |= TranslateColor[Parameter[Index]-40] << 4;
|
|
TextSetCurrentAttribute(a);
|
|
break;
|
|
#endif
|
|
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:
|
|
TextCharOut(String);
|
|
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
|
|
|
|
High bit set and ID > 0x81 means the device is expected to be
|
|
a CD-ROM drive.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
EFI_HANDLE DeviceHandle;
|
|
PDRIVE_CONTEXT Context;
|
|
BOOLEAN IsCd;
|
|
|
|
DBGOUT((TEXT("BiosDiskOpen: enter, id = 0x%x\r\n"),DriveId));
|
|
|
|
//
|
|
// Check special drive number encoding for CD-ROM case
|
|
//
|
|
if(DriveId >= 0x80000000) {
|
|
IsCd = TRUE;
|
|
DriveId &= 0x7fffffff;
|
|
} else {
|
|
IsCd = FALSE;
|
|
}
|
|
|
|
if( OpenMode == FloppyOpenMode ) {
|
|
|
|
//
|
|
// Must be floppy.
|
|
//
|
|
DeviceHandle = GetFloppyDrive( DriveId );
|
|
|
|
if (DeviceHandle == (EFI_HANDLE) DEVICE_NOT_FOUND) {
|
|
return EBADF;
|
|
}
|
|
|
|
} else {
|
|
if( IsCd ) {
|
|
|
|
//
|
|
// For cd, we get the device we booted from.
|
|
//
|
|
#ifndef FORCE_CD_BOOT
|
|
DeviceHandle = GetCd();
|
|
|
|
if (DeviceHandle == (EFI_HANDLE) DEVICE_NOT_FOUND) {
|
|
return EBADF;
|
|
}
|
|
|
|
#else
|
|
DeviceHandle = GetCdTest();
|
|
|
|
if (DeviceHandle == (EFI_HANDLE)0)
|
|
return EBADF;
|
|
#endif // for FORCE_CD_BOOT
|
|
|
|
} else {
|
|
|
|
//
|
|
// For harddrive, we get the harddrive associated
|
|
// with the passed-in rdisk (DriveId) value.
|
|
//
|
|
DeviceHandle = GetHardDrive( DriveId );
|
|
if (DeviceHandle == (EFI_HANDLE) DEVICE_NOT_FOUND) {
|
|
DBGOUT((TEXT("GetHardDrive returns DEVICE_NOT_FOUND %x\r\n"),DriveId));
|
|
return EBADF;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// 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) {
|
|
DBGOUT((TEXT("BiosDiskOpen: no file table entry available\r\n")));
|
|
DBGPAUSE
|
|
return(ENOENT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We found an entry we can use, so mark it as open.
|
|
//
|
|
BlFileTable[*FileId].Flags.Open = 1;
|
|
BlFileTable[*FileId].DeviceEntryTable = IsCd
|
|
? &BiosEDDSEntryTable
|
|
: &BiosDiskEntryTable;
|
|
|
|
|
|
Context = &(BlFileTable[*FileId].u.DriveContext);
|
|
Context->DeviceHandle = (ULONGLONG) DeviceHandle;
|
|
Context->xInt13 = TRUE;
|
|
|
|
|
|
DBGOUT((TEXT("BiosDiskOpen: exit success\r\n")));
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
ARC_STATUS
|
|
BiospWritePartialSector(
|
|
IN UCHAR Int13Unit,
|
|
IN ULONGLONG Sector,
|
|
IN PUCHAR Buffer,
|
|
IN BOOLEAN IsHead,
|
|
IN ULONG Bytes,
|
|
IN UCHAR SectorsPerTrack,
|
|
IN USHORT Heads,
|
|
IN USHORT Cylinders,
|
|
IN BOOLEAN AllowXInt13,
|
|
IN ULONGLONG DeviceHandle
|
|
)
|
|
{
|
|
ARC_STATUS Status;
|
|
|
|
//
|
|
// Read sector into the write buffer
|
|
//
|
|
Status = ReadExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
Sector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Transfer 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 = WriteExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
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;
|
|
ULONGLONG DeviceHandle;
|
|
UCHAR Int13Unit;
|
|
ULONG HeadOffset,TailByteCount;
|
|
UCHAR SectorsPerTrack;
|
|
USHORT Heads,Cylinders;
|
|
BOOLEAN AllowXInt13;
|
|
ARC_STATUS Status;
|
|
ULONG BytesLeftToTransfer;
|
|
UCHAR SectorsToTransfer;
|
|
BOOLEAN Under1MegLine;
|
|
PVOID TransferBuffer;
|
|
PUCHAR UserBuffer;
|
|
ULONG PhysicalSectors;
|
|
|
|
BytesLeftToTransfer = Length;
|
|
PhysicalSectors = SECTOR_SIZE;
|
|
|
|
if(!LocalBuffer) {
|
|
LocalBuffer = BlAllocateHeap(SCRATCH_BUFFER_SIZE);
|
|
if(!LocalBuffer) {
|
|
Status = ENOMEM;
|
|
goto BiosDiskWriteDone;
|
|
}
|
|
}
|
|
|
|
HeadSector = BlFileTable[FileId].Position.QuadPart / PhysicalSectors;
|
|
HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % PhysicalSectors);
|
|
|
|
TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / PhysicalSectors;
|
|
TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % PhysicalSectors);
|
|
|
|
Int13Unit = BlFileTable[FileId].u.DriveContext.Drive;
|
|
DeviceHandle = BlFileTable[FileId].u.DriveContext.DeviceHandle;
|
|
|
|
SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
|
|
Heads = BlFileTable[FileId].u.DriveContext.Heads;
|
|
Cylinders = BlFileTable[FileId].u.DriveContext.Cylinders;
|
|
AllowXInt13 = BlFileTable[FileId].u.DriveContext.xInt13;
|
|
|
|
UserBuffer = Buffer;
|
|
|
|
//
|
|
// Special case of transfer occuring entirely within one sector
|
|
//
|
|
CurrentSector = HeadSector;
|
|
|
|
if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
|
|
|
|
Status = ReadExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
HeadSector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
goto BiosDiskWriteDone;
|
|
}
|
|
|
|
RtlMoveMemory(LocalBuffer+HeadOffset,Buffer,Length);
|
|
|
|
Status = WriteExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
CurrentSector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
goto BiosDiskWriteDone;
|
|
}
|
|
|
|
BytesLeftToTransfer = 0;
|
|
goto BiosDiskWriteDone;
|
|
}
|
|
|
|
if(HeadOffset) {
|
|
|
|
Status = BiospWritePartialSector(
|
|
Int13Unit,
|
|
HeadSector,
|
|
Buffer,
|
|
TRUE,
|
|
HeadOffset,
|
|
SectorsPerTrack,
|
|
Heads,
|
|
Cylinders,
|
|
AllowXInt13,
|
|
DeviceHandle
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
BytesLeftToTransfer -= PhysicalSectors - HeadOffset;
|
|
UserBuffer += PhysicalSectors - HeadOffset;
|
|
CurrentSector += 1;
|
|
}
|
|
|
|
if(TailByteCount) {
|
|
|
|
Status = BiospWritePartialSector(
|
|
Int13Unit,
|
|
TailSector,
|
|
(PUCHAR)Buffer + Length - TailByteCount,
|
|
FALSE,
|
|
TailByteCount,
|
|
SectorsPerTrack,
|
|
Heads,
|
|
Cylinders,
|
|
AllowXInt13,
|
|
DeviceHandle
|
|
);
|
|
|
|
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_PTR) UserBuffer + BytesLeftToTransfer <= 0x100000) {
|
|
Under1MegLine = TRUE;
|
|
} else {
|
|
Under1MegLine = FALSE;
|
|
}
|
|
|
|
//
|
|
// Now handle the middle part. This is some number of whole sectors.
|
|
//
|
|
while(BytesLeftToTransfer) {
|
|
|
|
//
|
|
// The number of sectors to transfer is the minimum of:
|
|
// - the number of sectors left in the current track
|
|
// - BytesLeftToTransfer / SECTOR_SIZE
|
|
//
|
|
// Because sectors per track is 1-63 we know this will fit in a UCHAR
|
|
//
|
|
if (AllowXInt13) {
|
|
//
|
|
// Ignore cylinders & heads & track information for XINT13 cases
|
|
//
|
|
SectorsToTransfer = (UCHAR)(BytesLeftToTransfer / PhysicalSectors);
|
|
} else {
|
|
SectorsToTransfer = (UCHAR)min(
|
|
SectorsPerTrack - (CurrentSector % SectorsPerTrack),
|
|
BytesLeftToTransfer / PhysicalSectors
|
|
);
|
|
}
|
|
|
|
//
|
|
// 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_PTR)UserBuffer & 0xffffffffffff0000) !=
|
|
(((ULONG_PTR)UserBuffer + (SectorsToTransfer * PhysicalSectors) - 1) & 0xffffffffffff0000))
|
|
{
|
|
TransferBuffer = LocalBuffer;
|
|
SectorsToTransfer = min(SectorsToTransfer, SCRATCH_BUFFER_SIZE / (USHORT)PhysicalSectors);
|
|
|
|
} else {
|
|
|
|
TransferBuffer = UserBuffer;
|
|
}
|
|
} else {
|
|
TransferBuffer = LocalBuffer;
|
|
SectorsToTransfer = min(SectorsToTransfer, SCRATCH_BUFFER_SIZE / (USHORT)PhysicalSectors);
|
|
}
|
|
|
|
if(TransferBuffer == LocalBuffer) {
|
|
RtlMoveMemory(LocalBuffer,UserBuffer,SectorsToTransfer*PhysicalSectors);
|
|
}
|
|
|
|
Status = WriteExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
CurrentSector,
|
|
SectorsToTransfer,
|
|
TransferBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
//
|
|
// Tail part isn't contiguous with middle part
|
|
//
|
|
BytesLeftToTransfer += TailByteCount;
|
|
return(Status);
|
|
}
|
|
|
|
CurrentSector += SectorsToTransfer;
|
|
BytesLeftToTransfer -= SectorsToTransfer * PhysicalSectors;
|
|
UserBuffer += SectorsToTransfer * PhysicalSectors;
|
|
}
|
|
|
|
Status = ESUCCESS;
|
|
|
|
BiosDiskWriteDone:
|
|
|
|
*Count = Length - BytesLeftToTransfer;
|
|
BlFileTable[FileId].Position.QuadPart += *Count;
|
|
return(Status);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
pBiosDiskReadWorker(
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count,
|
|
IN USHORT SectorSize,
|
|
IN BOOLEAN xInt13
|
|
)
|
|
|
|
/*++
|
|
|
|
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;
|
|
USHORT Heads,Cylinders;
|
|
UCHAR SectorsPerTrack;
|
|
UCHAR Int13Unit;
|
|
ULONGLONG DeviceHandle;
|
|
ARC_STATUS Status;
|
|
PUCHAR UserBuffer;
|
|
UCHAR SectorsToTransfer;
|
|
BOOLEAN Under1MegLine;
|
|
PVOID TransferBuffer;
|
|
BOOLEAN AllowXInt13;
|
|
|
|
DBGOUT((TEXT("BiosDiskRead: enter; length=0x%lx, sector size=%u, xint13=%u\r\n"),Length,SectorSize,xInt13));
|
|
|
|
BytesLeftToTransfer = Length;
|
|
|
|
if(!LocalBuffer) {
|
|
LocalBuffer = BlAllocateHeap(SCRATCH_BUFFER_SIZE);
|
|
if(!LocalBuffer) {
|
|
Status = ENOMEM;
|
|
DBGOUT((TEXT("BiosDiskRead: out of memory\r\n")));
|
|
goto BiosDiskReadDone;
|
|
}
|
|
}
|
|
|
|
SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
|
|
Heads = BlFileTable[FileId].u.DriveContext.Heads;
|
|
Cylinders = BlFileTable[FileId].u.DriveContext.Cylinders;
|
|
AllowXInt13 = BlFileTable[FileId].u.DriveContext.xInt13;
|
|
Int13Unit = BlFileTable[FileId].u.DriveContext.Drive;
|
|
DeviceHandle = BlFileTable[FileId].u.DriveContext.DeviceHandle;
|
|
|
|
HeadSector = BlFileTable[FileId].Position.QuadPart / SectorSize;
|
|
HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % SectorSize);
|
|
|
|
TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / SectorSize;
|
|
TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % SectorSize);
|
|
|
|
UserBuffer = Buffer;
|
|
|
|
DBGOUT((
|
|
TEXT("BiosDiskRead: unit 0x%x CHS=%lu %lu %lu\r\n"),
|
|
Int13Unit,
|
|
Cylinders,
|
|
Heads,
|
|
SectorsPerTrack
|
|
));
|
|
|
|
DBGOUT((
|
|
TEXT("BiosDiskRead: head=0x%lx%lx tail=0x%lx%lx\r\n"),
|
|
(ULONG)(HeadSector >> 32),
|
|
(ULONG)HeadSector,
|
|
(ULONG)(TailSector >> 32),
|
|
(ULONG)TailSector
|
|
));
|
|
|
|
CurrentSector = HeadSector;
|
|
if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
|
|
//
|
|
// Read contained entirely within one sector, and does not start or
|
|
// end on the sector boundary.
|
|
//
|
|
DBGOUT((TEXT("BiosDiskRead: read entirely within one sector\r\n")));
|
|
Status = ReadExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
HeadSector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
DBGOUT((TEXT("BiosDiskRead: read failed with %u\r\n"),Status));
|
|
goto BiosDiskReadDone;
|
|
}
|
|
|
|
RtlMoveMemory(Buffer,LocalBuffer + HeadOffset,Length);
|
|
BytesLeftToTransfer = 0;
|
|
goto BiosDiskReadDone;
|
|
}
|
|
|
|
if(HeadOffset) {
|
|
//
|
|
// The leading part of the read is not aligned on a sector boundary.
|
|
// Fetch the partial sector and transfer it into the caller's buffer.
|
|
//
|
|
DBGOUT((TEXT("BiosDiskRead: reading partial head sector\r\n")));
|
|
Status = ReadExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
HeadSector,
|
|
1,
|
|
LocalBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
DBGOUT((TEXT("BiosDiskRead: read failed with %u\r\n"),Status));
|
|
goto BiosDiskReadDone;
|
|
}
|
|
|
|
RtlMoveMemory(Buffer,LocalBuffer + HeadOffset,SectorSize - HeadOffset);
|
|
|
|
BytesLeftToTransfer -= SectorSize - HeadOffset;
|
|
UserBuffer += SectorSize - HeadOffset;
|
|
CurrentSector = HeadSector + 1;
|
|
}
|
|
|
|
if(TailByteCount) {
|
|
//
|
|
// The trailing part of the read is not a full sector.
|
|
// Fetch the partial sector and transfer it into the caller's buffer.
|
|
//
|
|
DBGOUT((TEXT("BiosDiskRead: reading partial tail sector\r\n")));
|
|
Status = ReadExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
TailSector,
|
|
1,
|
|
LocalBuffer,
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
DBGOUT((TEXT("BiosDiskRead: read failed with %u\r\n"),Status));
|
|
goto BiosDiskReadDone;
|
|
}
|
|
|
|
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_PTR) UserBuffer + BytesLeftToTransfer <= 0x100000) {
|
|
Under1MegLine = TRUE;
|
|
} else {
|
|
Under1MegLine = FALSE;
|
|
}
|
|
|
|
//
|
|
// Now BytesLeftToTransfer is an integral multiple of sector size.
|
|
//
|
|
while(BytesLeftToTransfer) {
|
|
|
|
//
|
|
// The number of sectors to transfer is the minimum of:
|
|
// - the number of sectors left in the current track
|
|
// - BytesLeftToTransfer / SectorSize
|
|
//
|
|
//
|
|
if(xInt13) {
|
|
//
|
|
// Arbitrary maximum sector count of 128. For a CD-ROM this is
|
|
// 256K, which considering that the xfer buffer all has to be
|
|
// under 1MB anyway, is pretty unlikely.
|
|
//
|
|
if((BytesLeftToTransfer / SectorSize) > 128) {
|
|
SectorsToTransfer = 128;
|
|
} else {
|
|
SectorsToTransfer = (UCHAR)(BytesLeftToTransfer / SectorSize);
|
|
}
|
|
} else {
|
|
//
|
|
// Because sectors per track is 1-63 we know this will fit in a UCHAR.
|
|
//
|
|
SectorsToTransfer = (UCHAR)min(
|
|
SectorsPerTrack - (CurrentSector % SectorsPerTrack),
|
|
BytesLeftToTransfer / SectorSize
|
|
);
|
|
}
|
|
|
|
if ((ULONG)(SectorSize * SectorsToTransfer) > Length) {
|
|
TransferBuffer = LocalBuffer;
|
|
} else {
|
|
TransferBuffer = UserBuffer;
|
|
}
|
|
|
|
DBGOUT((
|
|
TEXT("BiosDiskRead: reading 0x%x sectors @ 0x%lx%lx; buf=0x%lx\r\n"),
|
|
SectorsToTransfer,
|
|
(ULONG)(CurrentSector >> 32),
|
|
(ULONG)CurrentSector,
|
|
TransferBuffer
|
|
));
|
|
|
|
Status = ReadExtendedPhysicalSectors(
|
|
DeviceHandle,
|
|
CurrentSector,
|
|
SectorsToTransfer,
|
|
TransferBuffer
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
//
|
|
// Trail part isn't contiguous
|
|
//
|
|
DBGOUT((TEXT("BiosDiskRead: read failed with %u\r\n"),Status));
|
|
BytesLeftToTransfer += TailByteCount;
|
|
goto BiosDiskReadDone;
|
|
}
|
|
|
|
if(TransferBuffer == LocalBuffer) {
|
|
RtlMoveMemory(UserBuffer,LocalBuffer,SectorsToTransfer * SectorSize);
|
|
}
|
|
UserBuffer += SectorsToTransfer * SectorSize;
|
|
CurrentSector += SectorsToTransfer;
|
|
BytesLeftToTransfer -= SectorsToTransfer*SectorSize;
|
|
}
|
|
|
|
Status = ESUCCESS;
|
|
DBGOUT((TEXT("BiosDiskRead: exit success\r\n")));
|
|
|
|
BiosDiskReadDone:
|
|
|
|
DBGPAUSE
|
|
*Count = Length - BytesLeftToTransfer;
|
|
BlFileTable[FileId].Position.QuadPart += *Count;
|
|
return(Status);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosDiskRead(
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
{
|
|
USHORT PhysicalSectors;
|
|
|
|
PhysicalSectors = SECTOR_SIZE;
|
|
return(pBiosDiskReadWorker(FileId,Buffer,Length,Count,PhysicalSectors,TRUE));
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosElToritoDiskRead(
|
|
IN ULONG FileId,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG Count
|
|
)
|
|
{
|
|
return(pBiosDiskReadWorker(FileId,Buffer,Length,Count,2048,TRUE));
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BiosPartitionGetFileInfo(
|
|
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;
|
|
}
|
|
|
|
ARC_STATUS
|
|
BiosDiskGetFileInfo(
|
|
IN ULONG FileId,
|
|
OUT PFILE_INFORMATION FileInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the information about the disk.
|
|
|
|
Arguments:
|
|
|
|
FileId - The file id to the disk for which information is needed
|
|
|
|
FileInfo - Place holder for returning information about the disk
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if successful, otherwise appropriate ARC error code.
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status = EINVAL;
|
|
|
|
if (FileInfo) {
|
|
EFI_STATUS EfiStatus;
|
|
EFI_BLOCK_IO *EfiBlockIo = NULL;
|
|
PDRIVE_CONTEXT Context;
|
|
|
|
Context = &BlFileTable[FileId].u.DriveContext;
|
|
Status = EIO;
|
|
|
|
FlipToPhysical();
|
|
|
|
//
|
|
// Get hold for the block IO protocol handle
|
|
//
|
|
EfiStatus = EfiBS->HandleProtocol((EFI_HANDLE)Context->DeviceHandle,
|
|
&EfiBlockIoProtocol,
|
|
&EfiBlockIo);
|
|
|
|
FlipToVirtual();
|
|
|
|
if (!EFI_ERROR(EfiStatus) && EfiBlockIo && EfiBlockIo->Media) {
|
|
LONGLONG DiskSize = (EfiBlockIo->Media->BlockSize *
|
|
EfiBlockIo->Media->LastBlock);
|
|
|
|
if (DiskSize) {
|
|
RtlZeroMemory(FileInfo, sizeof(FILE_INFORMATION));
|
|
|
|
FileInfo->StartingAddress.QuadPart = 0;
|
|
FileInfo->EndingAddress.QuadPart = DiskSize;
|
|
FileInfo->CurrentPosition = BlFileTable[FileId].Position;
|
|
|
|
//
|
|
// NOTE : Anything less than 3MB is floppy drive
|
|
//
|
|
if ((DiskSize < 0x300000) && (EfiBlockIo->Media->RemovableMedia)) {
|
|
FileInfo->Type = FloppyDiskPeripheral;
|
|
} else {
|
|
FileInfo->Type = DiskPeripheral;
|
|
}
|
|
|
|
Status = ESUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
EFI_HANDLE
|
|
GetCd(
|
|
)
|
|
{
|
|
ULONG i;
|
|
ULONGLONG DevicePathSize, SmallestPathSize;
|
|
ULONG HandleCount;
|
|
|
|
EFI_HANDLE *BlockIoHandles;
|
|
|
|
EFI_HANDLE DeviceHandle = NULL;
|
|
EFI_DEVICE_PATH *DevicePath, *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
ATAPI_DEVICE_PATH *AtapiDevicePath;
|
|
SCSI_DEVICE_PATH *ScsiDevicePath;
|
|
UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownDevicePath;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
PBOOT_DEVICE_ATAPI BootDeviceAtapi;
|
|
PBOOT_DEVICE_SCSI BootDeviceScsi;
|
|
PBOOT_DEVICE_FLOPPY BootDeviceFloppy;
|
|
PBOOT_DEVICE_UNKNOWN BootDeviceUnknown;
|
|
EFI_HANDLE ReturnDeviceHandle = (EFI_HANDLE) DEVICE_NOT_FOUND;
|
|
ARC_STATUS ArcStatus;
|
|
|
|
//
|
|
// get all handles that support the block I/O protocol.
|
|
//
|
|
ArcStatus = BlGetEfiProtocolHandles(
|
|
&EfiBlockIoProtocol,
|
|
&BlockIoHandles,
|
|
&HandleCount);
|
|
if (ArcStatus != ESUCCESS) {
|
|
return(ReturnDeviceHandle);
|
|
}
|
|
|
|
FlipToPhysical();
|
|
SmallestPathSize = 0;
|
|
|
|
for (i = 0; i < HandleCount; i++) {
|
|
Status = EfiBS->HandleProtocol (
|
|
BlockIoHandles[i],
|
|
&EfiDevicePathProtocol,
|
|
&DevicePath
|
|
);
|
|
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"GetCd: HandleProtocol failed\r\n");
|
|
goto exit;
|
|
}
|
|
|
|
DevicePathSize = GetDevPathSize(DevicePath);
|
|
|
|
EfiAlignDp(&TestPathAligned,
|
|
DevicePath,
|
|
DevicePathNodeLength(DevicePath));
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
|
|
//
|
|
// In the cd case, just return the device we booted from.
|
|
//
|
|
while (TestPath->Type != END_DEVICE_PATH_TYPE) {
|
|
if (TestPath->Type == MESSAGING_DEVICE_PATH) {
|
|
if (TestPath->SubType == MSG_ATAPI_DP &&
|
|
BootContext.BusType == BootBusAtapi) {
|
|
//
|
|
// For ATAPI, match PrimarySecondary and SlaveMaster
|
|
// fields with the device we booted from.
|
|
//
|
|
AtapiDevicePath = (ATAPI_DEVICE_PATH *) TestPath;
|
|
BootDeviceAtapi = (PBOOT_DEVICE_ATAPI) &(BootContext.BootDevice);
|
|
if ( (AtapiDevicePath->PrimarySecondary == BootDeviceAtapi->PrimarySecondary) &&
|
|
(AtapiDevicePath->SlaveMaster == BootDeviceAtapi->SlaveMaster) &&
|
|
(AtapiDevicePath->Lun == BootDeviceAtapi->Lun) &&
|
|
((SmallestPathSize == 0) || (DevicePathSize < SmallestPathSize)) ) {
|
|
|
|
//
|
|
// Remember the BlockIo Handle
|
|
//
|
|
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
|
|
//
|
|
// Update the SmallestPathSize
|
|
//
|
|
|
|
SmallestPathSize = DevicePathSize;
|
|
|
|
break;
|
|
}
|
|
} else if (TestPath->SubType == MSG_SCSI_DP &&
|
|
BootContext.BusType == BootBusScsi) {
|
|
//
|
|
// For SCSI, match PUN and LUN fields with the
|
|
// device we booted from.
|
|
//
|
|
ScsiDevicePath = (SCSI_DEVICE_PATH *) TestPath;
|
|
BootDeviceScsi = (PBOOT_DEVICE_SCSI) &(BootContext.BootDevice);
|
|
if ((ScsiDevicePath->Pun == BootDeviceScsi->Pun) &&
|
|
(ScsiDevicePath->Lun == BootDeviceScsi->Lun) &&
|
|
((SmallestPathSize == 0) || (DevicePathSize < SmallestPathSize)) ) {
|
|
|
|
//
|
|
// Remember the BlockIo Handle
|
|
//
|
|
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
|
|
//
|
|
// Update the SmallestPathSize
|
|
//
|
|
|
|
SmallestPathSize = DevicePathSize;
|
|
|
|
break;
|
|
}
|
|
}
|
|
} else if (TestPath->Type == HARDWARE_DEVICE_PATH) {
|
|
if (TestPath->SubType == HW_VENDOR_DP &&
|
|
BootContext.BusType == BootBusVendor) {
|
|
UnknownDevicePath = (UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *) TestPath;
|
|
BootDeviceUnknown = (PBOOT_DEVICE_UNKNOWN) &(BootContext.BootDevice);
|
|
|
|
if ( (CompareGuid( &(UnknownDevicePath->DevicePath.Guid),
|
|
&(BootDeviceUnknown->Guid)) == 0) &&
|
|
(UnknownDevicePath->LegacyDriveLetter ==
|
|
BootDeviceUnknown->LegacyDriveLetter) &&
|
|
((SmallestPathSize == 0) || (DevicePathSize < SmallestPathSize)) ) {
|
|
|
|
//
|
|
// Remember the BlockIo Handle
|
|
//
|
|
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
|
|
//
|
|
// Update the SmallestPathSize
|
|
//
|
|
|
|
SmallestPathSize = DevicePathSize;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DevicePath = NextDevicePathNode(DevicePath);
|
|
EfiAlignDp(&TestPathAligned,
|
|
DevicePath,
|
|
DevicePathNodeLength(DevicePath));
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
}
|
|
}
|
|
|
|
#ifdef FORCE_CD_BOOT
|
|
if (ReturnDeviceHandle == (EFI_HANDLE)DEVICE_NOT_FOUND) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"GetCD: LocateHandle failed\r\n");
|
|
ReturnDeviceHandle = 0;
|
|
}
|
|
#endif // for FORCE_CD_BOOT
|
|
|
|
//
|
|
// Change back to virtual mode.
|
|
//
|
|
exit:
|
|
FlipToVirtual();
|
|
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandles >> PAGE_SHIFT) );
|
|
|
|
return ReturnDeviceHandle;
|
|
}
|
|
|
|
ULONG
|
|
BlGetDriveId(
|
|
ULONG DriveType,
|
|
PBOOT_DEVICE Device
|
|
)
|
|
{
|
|
ULONG i;
|
|
EFI_STATUS Status = EFI_INVALID_PARAMETER;
|
|
ULONG nCachedDevicePaths = 0;
|
|
ULONGLONG *CachedDevicePaths;
|
|
EFI_BLOCK_IO * BlkIo;
|
|
ULONG HandleCount;
|
|
EFI_HANDLE *BlockIoHandles;
|
|
EFI_DEVICE_PATH *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
ULONG *BlockIoHandlesBitmap;
|
|
ULONG nFoundDevice = DEVICE_NOT_FOUND;
|
|
ULONG nDriveCount = 0;
|
|
EFI_DEVICE_PATH *CurrentDevicePath;
|
|
BOOLEAN DuplicateFound;
|
|
ULONG DriveId;
|
|
ULONG MemoryPage;
|
|
ARC_STATUS ArcStatus;
|
|
|
|
//
|
|
// get all handles that support the block I/O protocol.
|
|
//
|
|
ArcStatus = BlGetEfiProtocolHandles(
|
|
&EfiBlockIoProtocol,
|
|
&BlockIoHandles,
|
|
&HandleCount);
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlGetEfiProtocolHandles failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
//
|
|
// now that we know how many handles there are, we can allocate space for
|
|
// the CachedDevicePaths and BlockIoHandlesBitmap
|
|
//
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONGLONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
CachedDevicePaths = (ULONGLONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
BlockIoHandlesBitmap = (ULONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
//
|
|
// Change to physical mode so that we can make EFI calls
|
|
//
|
|
FlipToPhysical();
|
|
RtlZeroMemory(CachedDevicePaths, HandleCount*sizeof(ULONGLONG));
|
|
for (i=0;i<HandleCount; i++) {
|
|
BlockIoHandlesBitmap[i] = DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Cache all of the EFI Device Paths
|
|
//
|
|
for (i = 0; i < HandleCount; i++) {
|
|
|
|
Status = EfiBS->HandleProtocol (
|
|
BlockIoHandles[i],
|
|
&EfiDevicePathProtocol,
|
|
&( (EFI_DEVICE_PATH *) CachedDevicePaths[i] )
|
|
);
|
|
}
|
|
|
|
|
|
// Save the number of cached Device Paths
|
|
nCachedDevicePaths = i;
|
|
ASSERT(nCachedDevicePaths = HandleCount);
|
|
|
|
//
|
|
// Find all of the harddrives
|
|
//
|
|
for( i=0; i<nCachedDevicePaths; i++ ) {
|
|
|
|
//
|
|
// Get next device path.
|
|
//
|
|
CurrentDevicePath = (EFI_DEVICE_PATH *) CachedDevicePaths[i];
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
while( ( TestPath->Type != END_DEVICE_PATH_TYPE ) ) {
|
|
|
|
//
|
|
// Look for Media HardDrive node
|
|
//
|
|
if(((EFI_DEVICE_PATH *) NextDevicePathNode( CurrentDevicePath ))->Type == END_DEVICE_PATH_TYPE) {
|
|
|
|
|
|
|
|
//
|
|
// Since we found a harddrive, find the
|
|
// raw device associated with it.
|
|
//
|
|
nFoundDevice = DEVICE_NOT_FOUND;
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_ATAPI_DP ) ) {
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(!BlkIo->Media->RemovableMedia) {
|
|
|
|
//
|
|
// Find the ATAPI raw device
|
|
//
|
|
nFoundDevice = FindAtapiDevice(
|
|
CachedDevicePaths,
|
|
nCachedDevicePaths,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->PrimarySecondary,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->SlaveMaster,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->Lun
|
|
);
|
|
}
|
|
|
|
} else if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_SCSI_DP ) ) {
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(!BlkIo->Media->RemovableMedia) {
|
|
//
|
|
// Find SCSI raw device
|
|
//
|
|
nFoundDevice = FindScsiDevice(
|
|
CachedDevicePaths,
|
|
nCachedDevicePaths,
|
|
((SCSI_DEVICE_PATH *) TestPath)->Pun,
|
|
((SCSI_DEVICE_PATH *) TestPath)->Lun
|
|
);
|
|
}
|
|
|
|
} else if( ( TestPath->Type == HARDWARE_DEVICE_PATH ) &&
|
|
( TestPath->SubType == HW_VENDOR_DP ) ) {
|
|
|
|
//
|
|
// Find the Hardware Vendor raw device by ensuring it is not a
|
|
// removable media
|
|
//
|
|
|
|
Status = EfiBS->HandleProtocol( BlockIoHandles[i], &EfiBlockIoProtocol, &(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(BlkIo->Media->RemovableMedia)
|
|
nFoundDevice = DEVICE_NOT_FOUND;
|
|
else
|
|
nFoundDevice = 1;
|
|
}
|
|
|
|
|
|
if( nFoundDevice != DEVICE_NOT_FOUND ) {
|
|
// Found a raw device
|
|
BlockIoHandlesBitmap[ i ] = i;
|
|
|
|
switch (DriveType) {
|
|
case BL_DISKTYPE_ATAPI:
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_ATAPI_DP ) &&
|
|
( ((ATAPI_DEVICE_PATH *) TestPath)->PrimarySecondary ==
|
|
((PBOOT_DEVICE_ATAPI)Device)->PrimarySecondary) &&
|
|
( ((ATAPI_DEVICE_PATH *) TestPath)->SlaveMaster ==
|
|
((PBOOT_DEVICE_ATAPI)Device)->SlaveMaster) &&
|
|
( ((ATAPI_DEVICE_PATH *) TestPath)->Lun ==
|
|
((PBOOT_DEVICE_ATAPI)Device)->Lun) ) {
|
|
DriveId = nFoundDevice;
|
|
//DriveId = i;
|
|
}
|
|
break;
|
|
case BL_DISKTYPE_SCSI:
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_SCSI_DP ) &&
|
|
( ((SCSI_DEVICE_PATH *) TestPath)->Pun ==
|
|
((PBOOT_DEVICE_SCSI)Device)->Pun) &&
|
|
( ((SCSI_DEVICE_PATH *) TestPath)->Lun ==
|
|
((PBOOT_DEVICE_SCSI)Device)->Lun) ) {
|
|
DriveId = nFoundDevice;
|
|
//DriveId = i;
|
|
}
|
|
break;
|
|
case BL_DISKTYPE_UNKNOWN:
|
|
if( ( TestPath->Type == HARDWARE_DEVICE_PATH ) &&
|
|
( TestPath->SubType == HW_VENDOR_DP ) ) {
|
|
DriveId = nFoundDevice;
|
|
//DriveId = i;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
} // if END_DEVICE_PATH_TYPE
|
|
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode( CurrentDevicePath );
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change back to virtual mode.
|
|
//
|
|
FlipToVirtual();
|
|
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandles >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandlesBitmap >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)CachedDevicePaths >> PAGE_SHIFT) );
|
|
|
|
return nDriveCount;
|
|
//return nFoundDevice;
|
|
//return DriveId;
|
|
}
|
|
|
|
|
|
EFI_HANDLE
|
|
GetHardDrive(
|
|
ULONG DriveId
|
|
)
|
|
{
|
|
ULONG i;
|
|
EFI_STATUS Status = EFI_INVALID_PARAMETER;
|
|
ULONG nCachedDevicePaths = 0;
|
|
ULONGLONG *CachedDevicePaths;
|
|
EFI_BLOCK_IO * BlkIo;
|
|
ULONG HandleCount;
|
|
EFI_HANDLE *BlockIoHandles;
|
|
EFI_DEVICE_PATH *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
ULONG *BlockIoHandlesBitmap;
|
|
ULONG nFoundDevice = DEVICE_NOT_FOUND;
|
|
ULONG nDriveCount = 0;
|
|
EFI_DEVICE_PATH *CurrentDevicePath;
|
|
BOOLEAN DuplicateFound;
|
|
EFI_HANDLE ReturnDeviceHandle = (EFI_HANDLE) DEVICE_NOT_FOUND;
|
|
ULONG MemoryPage;
|
|
ARC_STATUS ArcStatus;
|
|
|
|
//
|
|
// get all handles that support the block I/O protocol.
|
|
//
|
|
ArcStatus = BlGetEfiProtocolHandles(
|
|
&EfiBlockIoProtocol,
|
|
&BlockIoHandles,
|
|
&HandleCount);
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlGetEfiProtocolHandles failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
//
|
|
// now that we know how many handles there are, we can allocate space for
|
|
// the CachedDevicePaths and BlockIoHandlesBitmap
|
|
//
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONGLONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
CachedDevicePaths = (ULONGLONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
BlockIoHandlesBitmap = (ULONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
//
|
|
// Change to physical mode so that we can make EFI calls
|
|
//
|
|
FlipToPhysical();
|
|
RtlZeroMemory(CachedDevicePaths, HandleCount*sizeof(ULONGLONG));
|
|
for (i=0;i<HandleCount; i++) {
|
|
BlockIoHandlesBitmap[i] = DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Cache all of the EFI Device Paths
|
|
//
|
|
for (i = 0; i < HandleCount; i++) {
|
|
|
|
Status = EfiBS->HandleProtocol (
|
|
BlockIoHandles[i],
|
|
&EfiDevicePathProtocol,
|
|
&( (EFI_DEVICE_PATH *) CachedDevicePaths[i] )
|
|
);
|
|
}
|
|
|
|
// Save the number of cached Device Paths
|
|
nCachedDevicePaths = i;
|
|
|
|
//
|
|
// Find all of the harddrives
|
|
//
|
|
for( i=0; i<nCachedDevicePaths; i++ ) {
|
|
|
|
//
|
|
// Get next device path.
|
|
//
|
|
CurrentDevicePath = (EFI_DEVICE_PATH *) CachedDevicePaths[i];
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
while( ( TestPath->Type != END_DEVICE_PATH_TYPE ) ) {
|
|
|
|
//
|
|
// Look for Media HardDrive node
|
|
//
|
|
if(((EFI_DEVICE_PATH *) NextDevicePathNode( CurrentDevicePath ))->Type == END_DEVICE_PATH_TYPE) {
|
|
|
|
//
|
|
// Since we found a harddrive, find the
|
|
// raw device associated with it.
|
|
//
|
|
nFoundDevice = DEVICE_NOT_FOUND;
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_ATAPI_DP ) ) {
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(!BlkIo->Media->RemovableMedia) {
|
|
|
|
//
|
|
// Find the ATAPI raw device
|
|
//
|
|
nFoundDevice = FindAtapiDevice(
|
|
CachedDevicePaths,
|
|
nCachedDevicePaths,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->PrimarySecondary,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->SlaveMaster,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->Lun
|
|
);
|
|
}
|
|
|
|
} else if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_SCSI_DP ) ) {
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(!BlkIo->Media->RemovableMedia) {
|
|
//
|
|
// Find SCSI raw device
|
|
//
|
|
nFoundDevice = FindScsiDevice(
|
|
CachedDevicePaths,
|
|
nCachedDevicePaths,
|
|
((SCSI_DEVICE_PATH *) TestPath)->Pun,
|
|
((SCSI_DEVICE_PATH *) TestPath)->Lun
|
|
);
|
|
}
|
|
|
|
} else if( ( TestPath->Type == HARDWARE_DEVICE_PATH ) &&
|
|
( TestPath->SubType == HW_VENDOR_DP ) ) {
|
|
|
|
//
|
|
// Find the Hardware Vendor raw device by ensuring it is not a
|
|
// removable media
|
|
//
|
|
Status = EfiBS->HandleProtocol( BlockIoHandles[i], &EfiBlockIoProtocol, &(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(BlkIo->Media->RemovableMedia) {
|
|
nFoundDevice = DEVICE_NOT_FOUND;
|
|
}
|
|
else {
|
|
nFoundDevice = 1;
|
|
}
|
|
}
|
|
|
|
|
|
if( nFoundDevice != DEVICE_NOT_FOUND ) {
|
|
// Found a raw device
|
|
BlockIoHandlesBitmap[ i ] = i;
|
|
}
|
|
|
|
} // if END_DEVICE_PATH_TYPE
|
|
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode( CurrentDevicePath );
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Count the bitmap and when we find
|
|
// the DriveId, return the BlockIoHandle
|
|
//
|
|
for( i=0; i<nCachedDevicePaths; i++ ) {
|
|
|
|
if( BlockIoHandlesBitmap[i] != DEVICE_NOT_FOUND ) {
|
|
if( nDriveCount++ == DriveId ) {
|
|
ReturnDeviceHandle = BlockIoHandles[BlockIoHandlesBitmap[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change back to virtual mode.
|
|
//
|
|
FlipToVirtual();
|
|
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandles >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandlesBitmap >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)CachedDevicePaths >> PAGE_SHIFT) );
|
|
|
|
return ReturnDeviceHandle;
|
|
}
|
|
|
|
ULONG
|
|
FindAtapiDevice(
|
|
ULONGLONG *pDevicePaths,
|
|
ULONG nDevicePaths,
|
|
ULONG PrimarySecondary,
|
|
ULONG SlaveMaster,
|
|
ULONG Lun
|
|
)
|
|
{
|
|
ULONG i = 0, nFoundDevice = 0;
|
|
EFI_DEVICE_PATH *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
EFI_DEVICE_PATH *CurrentDevicePath;
|
|
|
|
//
|
|
// Find the Atapi raw device whose PrimarySecondary,
|
|
// SlaveMaster and Lun are a match.
|
|
//
|
|
for( i=0; i<nDevicePaths; i++ ) {
|
|
|
|
//
|
|
// Get next device path.
|
|
//
|
|
CurrentDevicePath = (EFI_DEVICE_PATH *) pDevicePaths[i];
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
while( (TestPath->Type != END_DEVICE_PATH_TYPE) ) {
|
|
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_ATAPI_DP ) ) {
|
|
|
|
if( ( ((ATAPI_DEVICE_PATH *)TestPath)->PrimarySecondary == PrimarySecondary ) &&
|
|
( ((ATAPI_DEVICE_PATH *)TestPath)->SlaveMaster == SlaveMaster ) &&
|
|
( ((ATAPI_DEVICE_PATH *)TestPath)->Lun == Lun )) {
|
|
|
|
nFoundDevice = i;
|
|
|
|
return nFoundDevice;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode( CurrentDevicePath );
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint( TEXT("FindAtapiDevice returning DEVICE_NOT_FOUND\r\n"));
|
|
if (BdDebuggerEnabled == TRUE) {
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
return DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
ULONG
|
|
FindScsiDevice(
|
|
ULONGLONG *pDevicePaths,
|
|
ULONG nDevicePaths,
|
|
ULONG Pun,
|
|
ULONG Lun
|
|
)
|
|
{
|
|
ULONG i = 0, nFoundDevice = 0;
|
|
EFI_DEVICE_PATH *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
EFI_DEVICE_PATH *CurrentDevicePath;
|
|
|
|
//
|
|
// Find the Atapi raw device whose PrimarySecondary,
|
|
// SlaveMaster and Lun are a match.
|
|
//
|
|
for( i=0; i<nDevicePaths; i++ ) {
|
|
|
|
//
|
|
// Get next device path.
|
|
//
|
|
CurrentDevicePath = (EFI_DEVICE_PATH *) pDevicePaths[i];
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
while( (TestPath->Type != END_DEVICE_PATH_TYPE) ) {
|
|
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_SCSI_DP ) ) {
|
|
|
|
if( ( ((SCSI_DEVICE_PATH *)TestPath)->Pun == Pun ) &&
|
|
( ((SCSI_DEVICE_PATH *)TestPath)->Lun == Lun )) {
|
|
|
|
nFoundDevice = i;
|
|
|
|
return nFoundDevice;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode( CurrentDevicePath );
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint( TEXT("FindScsiDevice returning DEVICE_NOT_FOUND\r\n"));
|
|
if (BdDebuggerEnabled == TRUE) {
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
return DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
ULONG
|
|
GetDriveCount(
|
|
)
|
|
{
|
|
ULONG i;
|
|
EFI_STATUS Status = EFI_INVALID_PARAMETER;
|
|
ULONG nCachedDevicePaths = 0;
|
|
ULONGLONG *CachedDevicePaths;
|
|
EFI_BLOCK_IO * BlkIo;
|
|
ULONG HandleCount;
|
|
EFI_HANDLE *BlockIoHandles;
|
|
EFI_DEVICE_PATH *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
ULONG *BlockIoHandlesBitmap;
|
|
ULONG nFoundDevice = 0;
|
|
ULONG nDriveCount = 0;
|
|
EFI_DEVICE_PATH *CurrentDevicePath;
|
|
BOOLEAN DuplicateFound;
|
|
EFI_HANDLE ReturnDeviceHandle = (EFI_HANDLE) DEVICE_NOT_FOUND;
|
|
ULONG MemoryPage;
|
|
ARC_STATUS ArcStatus;
|
|
|
|
//
|
|
// get all handles that support the block I/O protocol.
|
|
//
|
|
ArcStatus = BlGetEfiProtocolHandles(
|
|
&EfiBlockIoProtocol,
|
|
&BlockIoHandles,
|
|
&HandleCount);
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlGetEfiProtocolHandles failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
//
|
|
// now that we know how many handles there are, we can allocate space for
|
|
// the CachedDevicePaths and BlockIoHandlesBitmap
|
|
//
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONGLONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
CachedDevicePaths = (ULONGLONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
BlockIoHandlesBitmap = (ULONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
//
|
|
// Change to physical mode so that we can make EFI calls
|
|
//
|
|
FlipToPhysical();
|
|
RtlZeroMemory(CachedDevicePaths, HandleCount*sizeof(ULONGLONG));
|
|
for (i=0;i<HandleCount; i++) {
|
|
BlockIoHandlesBitmap[i] = DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Cache all of the EFI Device Paths
|
|
//
|
|
for (i = 0; i < HandleCount; i++) {
|
|
|
|
Status = EfiBS->HandleProtocol (
|
|
BlockIoHandles[i],
|
|
&EfiDevicePathProtocol,
|
|
&( (EFI_DEVICE_PATH *) CachedDevicePaths[i] )
|
|
);
|
|
}
|
|
|
|
// Save the number of cached Device Paths
|
|
nCachedDevicePaths = i;
|
|
|
|
//
|
|
// Find all of the harddrives
|
|
//
|
|
for( i=0; i<nCachedDevicePaths; i++ ) {
|
|
|
|
//
|
|
// Get next device path.
|
|
//
|
|
CurrentDevicePath = (EFI_DEVICE_PATH *) CachedDevicePaths[i];
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
while( ( TestPath->Type != END_DEVICE_PATH_TYPE ) ) {
|
|
|
|
//
|
|
// Look for Media HardDrive node
|
|
//
|
|
if(((EFI_DEVICE_PATH *) NextDevicePathNode( CurrentDevicePath ))->Type == END_DEVICE_PATH_TYPE) {
|
|
|
|
//
|
|
// Since we found a harddrive, find the
|
|
// raw device associated with it.
|
|
//
|
|
nFoundDevice = DEVICE_NOT_FOUND;
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_ATAPI_DP ) ) {
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(!BlkIo->Media->RemovableMedia) {
|
|
|
|
//
|
|
// Find the ATAPI raw device
|
|
//
|
|
nFoundDevice = FindAtapiDevice(
|
|
CachedDevicePaths,
|
|
nCachedDevicePaths,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->PrimarySecondary,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->SlaveMaster,
|
|
((ATAPI_DEVICE_PATH *) TestPath)->Lun
|
|
);
|
|
}
|
|
|
|
} else if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_SCSI_DP ) ) {
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(!BlkIo->Media->RemovableMedia) {
|
|
|
|
//
|
|
// Find SCSI raw device
|
|
//
|
|
nFoundDevice = FindScsiDevice(
|
|
CachedDevicePaths,
|
|
nCachedDevicePaths,
|
|
((SCSI_DEVICE_PATH *) TestPath)->Pun,
|
|
((SCSI_DEVICE_PATH *) TestPath)->Lun
|
|
);
|
|
}
|
|
|
|
} else if( ( TestPath->Type == HARDWARE_DEVICE_PATH ) &&
|
|
( TestPath->SubType == HW_VENDOR_DP ) ) {
|
|
|
|
//
|
|
// Find the Hardware Vendor raw device by ensuring it is not a
|
|
// removable media
|
|
//
|
|
|
|
Status = EfiBS->HandleProtocol( BlockIoHandles[i], &EfiBlockIoProtocol, &(( EFI_BLOCK_IO * ) BlkIo) );
|
|
if(BlkIo->Media->RemovableMedia)
|
|
;
|
|
else
|
|
nFoundDevice = 1;
|
|
}
|
|
|
|
|
|
if( nFoundDevice != DEVICE_NOT_FOUND ) {
|
|
// Found a raw device
|
|
BlockIoHandlesBitmap[ i ] = nFoundDevice;
|
|
}
|
|
|
|
} // if END_DEVICE_PATH_TYPE
|
|
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode( CurrentDevicePath );
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
} // while
|
|
} // for
|
|
|
|
//
|
|
// Count the bitmap and when we find
|
|
// the DriveId, return the BlockIoHandle
|
|
//
|
|
for( i=0; i<nCachedDevicePaths; i++ ) {
|
|
|
|
if( BlockIoHandlesBitmap[i] != DEVICE_NOT_FOUND ) {
|
|
|
|
nDriveCount++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change back to virtual mode.
|
|
//
|
|
FlipToVirtual();
|
|
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandles >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandlesBitmap >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)CachedDevicePaths >> PAGE_SHIFT) );
|
|
|
|
return nDriveCount;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsVirtualFloppyDevice(
|
|
EFI_HANDLE DeviceHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out if the given device is a virtual floppy (i.e. RAM Disk).
|
|
|
|
NOTE : Currently we assume that if a device supports
|
|
Block, Disk, File System & LoadedImage protocols then it should
|
|
be virtual floppy. Also assumes that FlipToPhysical(...) has be
|
|
already been called.
|
|
|
|
Arguments:
|
|
|
|
DeviceHandle - Handle to the device which needs to be tested.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the device is virtual floppy otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
|
|
if (DeviceHandle != (EFI_HANDLE)DEVICE_NOT_FOUND) {
|
|
EFI_STATUS EfiStatus;
|
|
EFI_BLOCK_IO *EfiBlock = NULL;
|
|
EFI_DISK_IO *EfiDisk = NULL;
|
|
EFI_LOADED_IMAGE *EfiImage = NULL;
|
|
EFI_FILE_IO_INTERFACE *EfiFs = NULL;
|
|
|
|
//
|
|
// Get hold of the loaded image protocol handle
|
|
//
|
|
EfiStatus = EfiBS->HandleProtocol(DeviceHandle,
|
|
&EfiLoadedImageProtocol,
|
|
&EfiImage);
|
|
|
|
if (!EFI_ERROR(EfiStatus) && EfiImage) {
|
|
//
|
|
// Get hold of the FS protocol handle
|
|
//
|
|
EfiStatus = EfiBS->HandleProtocol(DeviceHandle,
|
|
&EfiFilesystemProtocol,
|
|
&EfiFs);
|
|
|
|
if (!EFI_ERROR(EfiStatus) && EfiFs) {
|
|
//
|
|
// Get hold of the disk protocol
|
|
//
|
|
EfiStatus = EfiBS->HandleProtocol(DeviceHandle,
|
|
&EfiDiskIoProtocol,
|
|
&EfiDisk);
|
|
|
|
if (!EFI_ERROR(EfiStatus) && EfiDisk) {
|
|
//
|
|
// Get hold of the block protocol
|
|
//
|
|
EfiStatus = EfiBS->HandleProtocol(DeviceHandle,
|
|
&EfiBlockIoProtocol,
|
|
&EfiBlock);
|
|
|
|
if (!EFI_ERROR(EfiStatus) && EfiBlock) {
|
|
Result = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
EFI_HANDLE
|
|
GetFloppyDrive(
|
|
ULONG DriveId
|
|
)
|
|
{
|
|
ULONG i;
|
|
EFI_STATUS Status = EFI_INVALID_PARAMETER;
|
|
ULONG nCachedDevicePaths = 0;
|
|
ULONGLONG *CachedDevicePaths;
|
|
|
|
ULONG HandleCount;
|
|
EFI_HANDLE *BlockIoHandles;
|
|
EFI_DEVICE_PATH *TestPath;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
ULONG *BlockIoHandlesBitmap;
|
|
ULONG nFoundDevice = 0;
|
|
ULONG nDriveCount = 0;
|
|
EFI_DEVICE_PATH *CurrentDevicePath;
|
|
BOOLEAN DuplicateFound;
|
|
EFI_HANDLE ReturnDeviceHandle = (EFI_HANDLE) DEVICE_NOT_FOUND;
|
|
ULONG MemoryPage;
|
|
ARC_STATUS ArcStatus;
|
|
|
|
//
|
|
// get all handles that support the block I/O protocol.
|
|
//
|
|
ArcStatus = BlGetEfiProtocolHandles(
|
|
&EfiBlockIoProtocol,
|
|
&BlockIoHandles,
|
|
&HandleCount);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlGetEfiProtocolHandles failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
//
|
|
// now that we know how many handles there are, we can allocate space for
|
|
// the CachedDevicePaths and BlockIoHandlesBitmap
|
|
//
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONGLONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
CachedDevicePaths = (ULONGLONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
ArcStatus = BlAllocateAlignedDescriptor(
|
|
LoaderFirmwareTemporary,
|
|
0,
|
|
(ULONG)((HandleCount*sizeof(ULONG)) >> PAGE_SIZE),
|
|
0,
|
|
&MemoryPage);
|
|
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"BlGetDriveId: BlAllocateAlignedDescriptor failed\r\n");
|
|
EfiBS->Exit(EfiImageHandle, Status, 0, 0);
|
|
}
|
|
|
|
BlockIoHandlesBitmap = (ULONG *)(ULONGLONG)((ULONGLONG)MemoryPage << PAGE_SHIFT);
|
|
|
|
//
|
|
// Change to physical mode so that we can make EFI calls
|
|
//
|
|
FlipToPhysical();
|
|
RtlZeroMemory(CachedDevicePaths, HandleCount*sizeof(ULONGLONG));
|
|
for (i=0;i<HandleCount; i++) {
|
|
BlockIoHandlesBitmap[i] = DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Cache all of the EFI Device Paths
|
|
//
|
|
for (i = 0; i < HandleCount; i++) {
|
|
|
|
Status = EfiBS->HandleProtocol (
|
|
BlockIoHandles[i],
|
|
&EfiDevicePathProtocol,
|
|
&( (EFI_DEVICE_PATH *) CachedDevicePaths[i] )
|
|
);
|
|
}
|
|
|
|
// Save the number of cached Device Paths
|
|
nCachedDevicePaths = i;
|
|
|
|
//
|
|
// Find the floppy.
|
|
//
|
|
for( i=0; i<nCachedDevicePaths; i++ ) {
|
|
//
|
|
// Get next device path.
|
|
//
|
|
CurrentDevicePath = (EFI_DEVICE_PATH *) CachedDevicePaths[i];
|
|
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
while( ( TestPath->Type != END_DEVICE_PATH_TYPE ) ) {
|
|
if (!DriveId) {
|
|
if( ( TestPath->Type == HARDWARE_DEVICE_PATH ) &&
|
|
( TestPath->SubType == HW_VENDOR_DP ) ) {
|
|
//
|
|
// Find the Hardware Vendor raw device
|
|
//
|
|
if(!(((UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *) TestPath)->LegacyDriveLetter & 0x80) &&
|
|
!(((UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *) TestPath)->LegacyDriveLetter == 0xFF)
|
|
) {
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
|
|
// Bail-out.
|
|
i = nCachedDevicePaths;
|
|
break;
|
|
}
|
|
} else if (TestPath->Type == MESSAGING_DEVICE_PATH &&
|
|
TestPath->SubType == MSG_ATAPI_DP) {
|
|
//
|
|
// For ATAPI "floppy drive", we're really looking for a
|
|
// removable block IO device with a 512 byte block size, as
|
|
// this signature matches the ls120 style floppy drives and
|
|
// keeps us from accidentally finding cdrom drives.
|
|
//
|
|
// our search algorithm short-circuits when we find the
|
|
// first suitable device
|
|
//
|
|
EFI_DEVICE_PATH *TmpTestPath, *AtapiTestPath;
|
|
EFI_DEVICE_PATH_ALIGNED AtapiTestPathAligned;
|
|
EFI_BLOCK_IO * BlkIo;
|
|
BOOLEAN DefinitelyACDROM = FALSE;
|
|
|
|
Status = EfiBS->HandleProtocol(
|
|
BlockIoHandles[i],
|
|
&EfiBlockIoProtocol,
|
|
&(( EFI_BLOCK_IO * ) BlkIo) );
|
|
|
|
#if 0
|
|
if (EFI_ERROR(Status)) {
|
|
DBGOUT((L"getting BlkIo interface failed, ec=%x\r\n",Status));
|
|
} else {
|
|
DBGOUT((L"Block size = %x, removable media = %s\r\n",
|
|
BlkIo->Media->BlockSize,
|
|
BlkIo->Media->RemovableMedia ? L"TRUE" : L"FALSE" ));
|
|
}
|
|
#endif
|
|
|
|
|
|
TmpTestPath = (EFI_DEVICE_PATH *) CachedDevicePaths[i];
|
|
|
|
EfiAlignDp(
|
|
&AtapiTestPathAligned,
|
|
TmpTestPath,
|
|
DevicePathNodeLength( TmpTestPath )
|
|
);
|
|
|
|
AtapiTestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
|
|
//
|
|
// test the device
|
|
// removable media? 512 byte block size?
|
|
//
|
|
if (!EFI_ERROR(Status) && (BlkIo->Media->RemovableMedia)
|
|
&& BlkIo->Media->BlockSize == 512) {
|
|
|
|
//
|
|
// let's be doubly sure and make sure there
|
|
// isn't a cdrom device path attached to this
|
|
// device path
|
|
//
|
|
while (AtapiTestPath->Type != END_DEVICE_PATH_TYPE ) {
|
|
|
|
if (AtapiTestPath->Type == MEDIA_DEVICE_PATH &&
|
|
AtapiTestPath->SubType == MEDIA_CDROM_DP) {
|
|
DefinitelyACDROM = TRUE;
|
|
}
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
TmpTestPath = NextDevicePathNode( TmpTestPath );
|
|
|
|
EfiAlignDp(
|
|
&AtapiTestPathAligned,
|
|
TmpTestPath,
|
|
DevicePathNodeLength( TmpTestPath )
|
|
);
|
|
|
|
AtapiTestPath = (EFI_DEVICE_PATH *) &AtapiTestPathAligned;
|
|
|
|
}
|
|
|
|
if (DefinitelyACDROM == FALSE) {
|
|
//
|
|
// found the first floppy drive.
|
|
// Remember the BlockIo Handle
|
|
//
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Find the logical vendor device
|
|
//
|
|
if( ( TestPath->Type == MESSAGING_DEVICE_PATH ) &&
|
|
( TestPath->SubType == MSG_VENDOR_DP ) ) {
|
|
|
|
if (IsVirtualFloppyDevice(BlockIoHandles[i])) {
|
|
DriveId--;
|
|
|
|
//
|
|
// Is this the device we were looking for?
|
|
//
|
|
if (!DriveId) {
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
|
|
i = nCachedDevicePaths; // for outer loop
|
|
break; // found the virtual floppy device we were looking for
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get next device path node.
|
|
//
|
|
CurrentDevicePath = NextDevicePathNode( CurrentDevicePath );
|
|
EfiAlignDp(
|
|
&TestPathAligned,
|
|
CurrentDevicePath,
|
|
DevicePathNodeLength( CurrentDevicePath )
|
|
);
|
|
|
|
TestPath = (EFI_DEVICE_PATH *) &TestPathAligned;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change back to virtual mode.
|
|
//
|
|
FlipToVirtual();
|
|
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandles >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandlesBitmap >> PAGE_SHIFT) );
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)CachedDevicePaths >> PAGE_SHIFT) );
|
|
|
|
return ReturnDeviceHandle;
|
|
}
|
|
|
|
|
|
#ifdef FORCE_CD_BOOT
|
|
|
|
EFI_DEVICE_PATH *
|
|
DevicePathFromHandle (
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH *DevicePath;
|
|
EFI_GUID DevicePathProtocol;
|
|
|
|
Status = EfiBS->HandleProtocol (Handle, &DevicePathProtocol, (VOID*)&DevicePath);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
DevicePath = NULL;
|
|
}
|
|
|
|
return DevicePath;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
IsUDFSFileSystem(
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Mounts the UDFS Volume on the device and updates the
|
|
file system state (global data structures)
|
|
|
|
Arguments:
|
|
|
|
Volume - UDF Volume pointer
|
|
DeviceId - Device on which the Volume may be residing
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if successful otherwise EBADF (if no UDF volume was found)
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status = EBADF;
|
|
UCHAR UBlock[UDF_BLOCK_SIZE+256] = {0};
|
|
PUCHAR Block = ALIGN_BUFFER(UBlock);
|
|
ULONG BlockIdx = 256;
|
|
ULONG LastBlock = 0;
|
|
EFI_STATUS EfiStatus;
|
|
EFI_BLOCK_IO *BlkDev;
|
|
|
|
EfiStatus = EfiBS->HandleProtocol(
|
|
Handle,
|
|
&EfiBlockIoProtocol,
|
|
&BlkDev);
|
|
|
|
if ((EfiStatus == EFI_SUCCESS) && (BlkDev) && (BlkDev->Media) &&
|
|
(BlkDev->Media->RemovableMedia == TRUE)) {
|
|
// get hold of Anchor Volume Descriptor
|
|
EfiStatus = BlkDev->ReadBlocks(
|
|
BlkDev,
|
|
BlkDev->Media->MediaId,
|
|
BlockIdx,
|
|
UDF_BLOCK_SIZE,
|
|
Block);
|
|
|
|
if (EfiStatus == EFI_SUCCESS) {
|
|
if (*(PUSHORT)Block == 0x2) {
|
|
// get partition descriptor
|
|
PNSR_PART Part;
|
|
PWCHAR TagID;
|
|
ULONG BlockIdx = *(PULONG)(Block + 20);
|
|
|
|
do {
|
|
EfiStatus = BlkDev->ReadBlocks(
|
|
BlkDev,
|
|
BlkDev->Media->MediaId,
|
|
BlockIdx++,
|
|
UDF_BLOCK_SIZE,
|
|
Block);
|
|
|
|
TagID = (PWCHAR)Block;
|
|
}
|
|
while ((EfiStatus == ESUCCESS) && (*TagID) &&
|
|
(*TagID != 0x8) && (*TagID != 0x5));
|
|
|
|
if ((EfiStatus == ESUCCESS) && (*TagID == 0x5)) {
|
|
Status = ESUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
IsCDFSFileSystem(
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Mounts the CDFS Volume on the device and updates the
|
|
file system state (global data structures)
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if successful otherwise EBADF (if no CDFS volume was found)
|
|
|
|
--*/
|
|
{
|
|
EFI_DEVICE_PATH *Dp;
|
|
ARC_STATUS Status = EBADF;
|
|
|
|
|
|
Dp=DevicePathFromHandle(Handle);
|
|
|
|
|
|
if (Dp) {
|
|
while (!IsDevicePathEnd (Dp) && (Status == EBADF)) {
|
|
if ((Dp->Type == MEDIA_DEVICE_PATH) &&
|
|
(Dp->SubType == MEDIA_CDROM_DP) ) {
|
|
Status = ESUCCESS;
|
|
}
|
|
Dp=NextDevicePathNode(Dp);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
EFI_HANDLE
|
|
GetCdTest(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i;
|
|
ULONGLONG DevicePathSize, SmallestPathSize;
|
|
ULONG HandleCount;
|
|
|
|
EFI_HANDLE *BlockIoHandles;
|
|
|
|
EFI_HANDLE DeviceHandle = NULL;
|
|
EFI_DEVICE_PATH *DevicePath, *TestPath,*Dp;
|
|
EFI_DEVICE_PATH_ALIGNED TestPathAligned;
|
|
ATAPI_DEVICE_PATH *AtapiDevicePath;
|
|
SCSI_DEVICE_PATH *ScsiDevicePath;
|
|
UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownDevicePath;
|
|
|
|
EFI_STATUS Status;
|
|
PBOOT_DEVICE_ATAPI BootDeviceAtapi;
|
|
PBOOT_DEVICE_SCSI BootDeviceScsi;
|
|
PBOOT_DEVICE_FLOPPY BootDeviceFloppy;
|
|
// PBOOT_DEVICE_TCPIPv4 BootDeviceTcpipV4;
|
|
// PBOOT_DEVICE_TCPIPv6 BootDeviceTcpipV6;
|
|
PBOOT_DEVICE_UNKNOWN BootDeviceUnknown;
|
|
EFI_HANDLE ReturnDeviceHandle = (EFI_HANDLE) 0;
|
|
ARC_STATUS ArcStatus;
|
|
|
|
//
|
|
// get all handles that support the block I/O protocol.
|
|
//
|
|
ArcStatus = BlGetEfiProtocolHandles(
|
|
&EfiBlockIoProtocol,
|
|
&BlockIoHandles,
|
|
&HandleCount);
|
|
if (ArcStatus != ESUCCESS) {
|
|
EfiST->ConOut->OutputString(EfiST->ConOut,
|
|
L"GetCdTest: BlGetEfiProtocolHandles failed\r\n");
|
|
return(ReturnDeviceHandle);
|
|
}
|
|
|
|
//
|
|
// change to physical mode so that we can make EFI calls
|
|
//
|
|
FlipToPhysical();
|
|
|
|
SmallestPathSize = 0;
|
|
|
|
for (i = 0,; i < HandleCount; i++) {
|
|
|
|
if (IsUDFSFileSystem(BlockIoHandles[i]) == ESUCCESS) {
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ReturnDeviceHandle == (EFI_HANDLE) 0) {
|
|
|
|
for (i = 0; i < HandleCount; i++) {
|
|
if (IsCDFSFileSystem (BlockIoHandles[i]) == ESUCCESS) {
|
|
ReturnDeviceHandle = BlockIoHandles[i];
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Change back to virtual mode.
|
|
//
|
|
FlipToVirtual();
|
|
|
|
BlFreeDescriptor( (ULONG)((ULONGLONG)BlockIoHandles >> PAGE_SHIFT) );
|
|
|
|
return ReturnDeviceHandle;
|
|
}
|
|
|
|
#endif // for FORCE_CD_BOOT
|
|
|
|
|
|
//
|
|
// Turn off the timer so we don't reboot waiting for the user to press a key
|
|
//
|
|
void
|
|
DisableEFIWatchDog (
|
|
VOID
|
|
)
|
|
{
|
|
EfiBS->SetWatchdogTimer (0,0,0,NULL);
|
|
}
|
|
|
|
BOOLEAN
|
|
BlDiskGPTDiskReadCallback(
|
|
ULONGLONG StartingLBA,
|
|
ULONG BytesToRead,
|
|
PVOID pContext,
|
|
UNALIGNED PVOID OutputBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback for reading data for a routine that
|
|
validates the GPT partition table.
|
|
|
|
NOTE: This routine changes the seek position on disk, and you must seek
|
|
back to your original seek position if you plan on reading from the
|
|
disk after making this call.
|
|
|
|
Arguments:
|
|
|
|
StartingLBA - starting logical block address to read from.
|
|
|
|
BytesToRead - Indicates how many bytes are to be read.
|
|
|
|
pContext - context pointer for hte function (in this case, a pointer to the disk id.)
|
|
|
|
OutputBuffer - a buffer that receives the data. It's assumed that it is at least
|
|
BytesToRead big enough.
|
|
|
|
Return Value:
|
|
|
|
TRUE - success, data has been read
|
|
|
|
FALSE - failed, data has not been read.
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status;
|
|
LARGE_INTEGER SeekPosition;
|
|
PUSHORT DataPointer;
|
|
ULONG DiskId;
|
|
ULONG ReadCount = 0;
|
|
|
|
|
|
DiskId = *((PULONG)pContext);
|
|
//
|
|
// read from the appropriate LBA on the disk
|
|
//
|
|
SeekPosition.QuadPart = StartingLBA * SECTOR_SIZE;
|
|
|
|
Status = BlSeek(DiskId,
|
|
&SeekPosition,
|
|
SeekAbsolute );
|
|
|
|
if (Status != ESUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
DataPointer = OutputBuffer;
|
|
|
|
Status = BlRead(
|
|
DiskId,
|
|
DataPointer,
|
|
BytesToRead,
|
|
&ReadCount);
|
|
|
|
if ((Status == ESUCCESS) && (ReadCount == BytesToRead)) {
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
BlGetGPTDiskPartitionEntry(
|
|
IN ULONG DiskNumber,
|
|
IN UCHAR PartitionNumber,
|
|
OUT EFI_PARTITION_ENTRY UNALIGNED **PartitionEntry
|
|
)
|
|
{
|
|
ARC_STATUS Status;
|
|
ULONG DiskId;
|
|
LARGE_INTEGER SeekPosition;
|
|
UCHAR DataBuffer[SECTOR_SIZE * 2];
|
|
ULONG ReadCount;
|
|
UCHAR NullGuid[16] = {0};
|
|
UNALIGNED EFI_PARTITION_TABLE *EfiHdr;
|
|
UNALIGNED EFI_PARTITION_ENTRY *PartEntry = NULL;
|
|
|
|
if (PartitionNumber >= 128) {
|
|
return EINVAL;
|
|
}
|
|
|
|
//
|
|
// Open the disk for raw access.
|
|
//
|
|
|
|
Status = BiosDiskOpen( DiskNumber,
|
|
0,
|
|
&DiskId );
|
|
|
|
if (Status != ESUCCESS) {
|
|
DBGOUT((TEXT("BiosDiskOpen (%x) fails, %x\r\n"), DiskNumber, Status));
|
|
return EINVAL;
|
|
}
|
|
|
|
|
|
BlFileTable[DiskId].Flags.Read = 1;
|
|
|
|
//
|
|
// Read the second LBA on the disk.
|
|
//
|
|
|
|
SeekPosition.QuadPart = 1 * SECTOR_SIZE;
|
|
|
|
Status = BlSeek( DiskId, &SeekPosition, SeekAbsolute );
|
|
|
|
if (Status != ESUCCESS) {
|
|
DBGOUT((TEXT("BlSeek fails, %x\r\n"), Status));
|
|
goto done;
|
|
}
|
|
|
|
Status = BlRead( DiskId, DataBuffer, SECTOR_SIZE, &ReadCount );
|
|
|
|
if (Status != ESUCCESS) {
|
|
DBGOUT((TEXT("BlRead fails, %x\r\n"), Status));
|
|
goto done;
|
|
}
|
|
|
|
if (ReadCount != SECTOR_SIZE) {
|
|
Status = EIO;
|
|
DBGOUT((TEXT("BlRead (wrong amt)\r\n")));
|
|
goto done;
|
|
}
|
|
|
|
EfiHdr = (UNALIGNED EFI_PARTITION_TABLE *)DataBuffer;
|
|
|
|
//
|
|
// Verify EFI partition table.
|
|
//
|
|
if (!BlIsValidGUIDPartitionTable(
|
|
(UNALIGNED EFI_PARTITION_TABLE *)EfiHdr,
|
|
1,
|
|
&DiskId,
|
|
BlDiskGPTDiskReadCallback)) {
|
|
DBGOUT((TEXT("BlIsValidGUIDPartitionTable fails, %x\r\n"), Status));
|
|
Status = EBADF;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Locate and read the partition entry that was requested.
|
|
//
|
|
SeekPosition.QuadPart = EfiHdr->PartitionEntryLBA * SECTOR_SIZE;
|
|
|
|
DBG_PRINT(STR_PREFIX"Seeking GPT Partition Entries\r\n");
|
|
|
|
Status = BlSeek( DiskId, &SeekPosition, SeekAbsolute );
|
|
|
|
if (Status != ESUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
Status = BlRead( DiskId, EfiPartitionBuffer, sizeof(EfiPartitionBuffer), &ReadCount );
|
|
|
|
if (Status != ESUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
if (ReadCount != sizeof(EfiPartitionBuffer)) {
|
|
Status = EIO;
|
|
goto done;
|
|
}
|
|
|
|
PartEntry = BlLocateGPTPartition( PartitionNumber - 1, 128, NULL );
|
|
|
|
if ( PartEntry != NULL ) {
|
|
|
|
if ( (memcmp(PartEntry->Type, NullGuid, 16) != 0) &&
|
|
(memcmp(PartEntry->Id, NullGuid, 16) != 0) &&
|
|
(PartEntry->StartingLBA != 0) &&
|
|
(PartEntry->EndingLBA != 0) ) {
|
|
Status = ESUCCESS;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
Status = EBADF;
|
|
|
|
done:
|
|
|
|
*PartitionEntry = PartEntry;
|
|
|
|
BiosDiskClose(DiskId);
|
|
|
|
if (Status != ESUCCESS) {
|
|
Status = ENOENT;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
ARC_STATUS
|
|
XferExtendedPhysicalDiskSectors(
|
|
IN ULONGLONG DeviceHandle,
|
|
IN ULONGLONG StartSector,
|
|
IN USHORT SectorCount,
|
|
PUCHAR Buffer,
|
|
IN BOOLEAN Write
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read or write disk sectors via extended int13.
|
|
|
|
It is assumed that the caller has ensured that the transfer buffer is
|
|
under the 1MB line, that the sector run does not cross a 64K boundary,
|
|
etc.
|
|
|
|
This routine does not check whether extended int13 is actually available
|
|
for the drive.
|
|
|
|
Arguments:
|
|
|
|
Int13UnitNumber - supplies the int13 drive number for the drive
|
|
to be read from/written to.
|
|
|
|
StartSector - supplies the absolute physical sector number. This is 0-based
|
|
relative to all sectors on the drive.
|
|
|
|
SectorCount - supplies the number of sectors to read/write.
|
|
|
|
Buffer - receives data read from the disk or supplies data to be written.
|
|
|
|
Write - supplies a flag indicating whether this is a write operation.
|
|
If FALSE, then it's a read. Otherwise it's a write.
|
|
|
|
Return Value:
|
|
|
|
ARC status code indicating outcome.
|
|
|
|
--*/
|
|
|
|
{
|
|
ARC_STATUS s;
|
|
ULONG l,h;
|
|
UCHAR Operation;
|
|
|
|
if(!SectorCount) {
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
l = (ULONG)StartSector;
|
|
h = (ULONG)(StartSector >> 32);
|
|
|
|
Operation = (UCHAR)(Write ? 0x43 : 0x42);
|
|
|
|
//
|
|
// We don't reset since this routine is only used on hard drives and
|
|
// CD-ROMs, and we don't totally understand the effect of a disk reset
|
|
// on ElTorito.
|
|
//
|
|
s = GET_EDDS_SECTOR(DeviceHandle,l,h,SectorCount,Buffer,Operation);
|
|
|
|
return(s);
|
|
}
|
|
|