[FREELDR] Minor enhancements for disk/partition boot and UI.

- Factor out disk & partition opening in LoadAndBootPartition() and
  LoadAndBootDrive() into a LoadAndBootPartitionOrDrive() helper.

- Use ARC paths and ArcOpen()/ArcRead() instead of calling the
  machine-specific BIOS-oriented DiskGetPartitionEntry() and
  MachDiskReadLogicalSectors() functions to open the disk/partition
  and read their boot sectors.

- Don't forget to close the opened boot sector file in LoadAndBootBootSector().

- Add assertions for DiskReadBufferSize in PcMemFinalizeMemoryMap()
  and EnumerateHarddisks().

- x86/amd64 only:
  * Add a DisableA20 helper for disabling the A20 line, before rebooting
    back, or chain-load a boot sector, into 16-bit world.
    Also pulse the output port of the keyboard controller to clear out
    its state after having set the state of the A20 line.

  * In addition to disabling the A20 line when rebooting or chain-loading
    a boot sector, reset the video back to 80x25 text mode.

- Reset the cursor position back to the origin when initializing or
  terminating the TUI.
This commit is contained in:
Hermès Bélusca-Maïto 2019-08-13 17:34:57 +02:00
parent 4578ee3e20
commit 85d44fca59
No known key found for this signature in database
GPG Key ID: 3B2539C65E7B93D0
7 changed files with 109 additions and 76 deletions

View File

@ -152,7 +152,7 @@ DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
MaxSectors = DiskReadBufferSize / Context->SectorSize;
SectorOffset = Context->SectorNumber + Context->SectorOffset;
// If MaxSectors is 0, this will lead to infinite loop
// If MaxSectors is 0, this will lead to infinite loop.
// In release builds assertions are disabled, however we also have sanity checks in DiskOpen()
ASSERT(MaxSectors > 0);
@ -319,6 +319,8 @@ EnumerateHarddisks(OUT PBOOLEAN BootDriveReported)
DiskCount = 0;
DriveNumber = 0x80;
ASSERT(DiskReadBufferSize > 0);
/*
* There are some really broken BIOSes out there. There are even BIOSes
* that happily report success when you ask them to read from non-existent

View File

@ -571,6 +571,8 @@ PcMemFinalizeMemoryMap(
TRACE("DiskReadBuffer=0x%p, DiskReadBufferSize=0x%lx\n",
DiskReadBuffer, DiskReadBufferSize);
ASSERT(DiskReadBufferSize > 0);
/* Now reserve the range for the disk read buffer */
ReserveMemory(MemoryMap,
(ULONG_PTR)DiskReadBuffer,

View File

@ -18,6 +18,24 @@ EnableA20:
mov al, HEX(0DF) // A20 on
out HEX(060), al
call Empty8042
mov al, HEX(0FF) // pulse output port
out HEX(064), al
call Empty8042
popa
ret
DisableA20:
pusha
call Empty8042
mov al, HEX(0D1) // command write
out HEX(064), al
call Empty8042
mov al, HEX(0DD) // A20 off
out HEX(060), al
call Empty8042
mov al, HEX(0FF) // pulse output port
out HEX(064), al
call Empty8042
popa
ret
@ -95,6 +113,13 @@ writehex_common:
Reboot:
cli
/* Disable A20 address line */
call DisableA20
/* Set the video back to 80x25 text mode */
mov ax, HEX(0003)
int HEX(10)
/* Set the word at location 40h:72h to 0 (cold reboot) */
mov word ptr ds:[HEX(0472)], HEX(0)
@ -103,8 +128,16 @@ Reboot:
ChainLoadBiosBootSectorCode:
/* Load segment registers */
cli
/* Disable A20 address line */
call DisableA20
/* Set the video back to 80x25 text mode */
mov ax, HEX(0003)
int HEX(10)
/* Load segment registers */
xor ax, ax
mov ds, ax
mov es, ax

View File

@ -81,7 +81,7 @@ PCSTR DiskGetErrorCodeString(ULONG ErrorCode)
case 0xE0: return "fixed disk status error/Error reg = 0";
case 0xFF: return "sense operation failed";
default: return "unknown error code";
default: return "unknown error code";
}
}

View File

@ -160,7 +160,6 @@ int __cdecl Int386(int ivec, REGS* in, REGS* out);
// If CF is set then the call failed (usually)
#define INT386_SUCCESS(regs) ((regs.x.eflags & EFLAGS_CF) == 0)
void EnableA20(void);
VOID __cdecl ChainLoadBiosBootSectorCode(VOID); // Implemented in boot.S
VOID __cdecl Reboot(VOID); // Implemented in boot.S
VOID DetectHardware(VOID); // Implemented in hardware.c

View File

@ -54,13 +54,14 @@ LoadAndBootBootSector(
}
/* Read boot sector */
if (ArcRead(FileId, (void*)0x7c00, 512, &BytesRead) != ESUCCESS ||
(BytesRead != 512))
if ((ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead) != ESUCCESS) || (BytesRead != 512))
{
UiMessageBox("Unable to read boot sector.");
return EIO;
}
ArcClose(FileId);
/* Check for validity */
if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
{
@ -81,8 +82,69 @@ LoadAndBootBootSector(
* result in a read error.
*/
// DiskStopFloppyMotor();
// DisableA20();
/* NOTE: Don't touch FrldrBootDrive */
ChainLoadBiosBootSectorCode();
Reboot(); /* Must not return! */
return ESUCCESS;
}
static ARC_STATUS
LoadAndBootPartitionOrDrive(
IN UCHAR DriveNumber,
IN ULONG PartitionNumber OPTIONAL)
{
ULONG FileId;
ULONG BytesRead;
CHAR ArcPath[MAX_PATH];
/* Construct the corresponding ARC path */
ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
*strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
if (ArcOpen(ArcPath, OpenReadOnly, &FileId) != ESUCCESS)
{
UiMessageBox("Unable to open %s", ArcPath);
return ENOENT;
}
/*
* Now try to read the partition boot sector or the MBR (when PartitionNumber == 0).
* If this fails then abort.
*/
if ((ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead) != ESUCCESS) || (BytesRead != 512))
{
if (PartitionNumber != 0)
UiMessageBox("Unable to read partition's boot sector.");
else
UiMessageBox("Unable to read MBR boot sector.");
return EIO;
}
ArcClose(FileId);
/* Check for validity */
if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
{
UiMessageBox("Invalid boot sector magic (0xaa55)");
return ENOEXEC;
}
UiUnInitialize("Booting...");
IniCleanup();
/*
* Don't stop the floppy drive motor when we
* are just booting a bootsector, or drive, or partition.
* If we were to stop the floppy motor then
* the BIOS wouldn't be informed and if the
* next read is to a floppy then the BIOS will
* still think the motor is on and this will
* result in a read error.
*/
// DiskStopFloppyMotor();
FrldrBootDrive = DriveNumber;
FrldrBootPartition = PartitionNumber;
ChainLoadBiosBootSectorCode();
Reboot(); /* Must not return! */
return ESUCCESS;
}
@ -93,7 +155,6 @@ LoadAndBootPartition(
IN PCHAR Envp[])
{
PCSTR ArgValue;
PARTITION_TABLE_ENTRY PartitionTableEntry;
UCHAR DriveNumber;
ULONG PartitionNumber;
@ -118,43 +179,7 @@ LoadAndBootPartition(
}
PartitionNumber = atoi(ArgValue);
/* Get the partition table entry */
if (!DiskGetPartitionEntry(DriveNumber, PartitionNumber, &PartitionTableEntry))
{
return ENOENT;
}
/* Now try to read the partition boot sector. If this fails then abort. */
if (!MachDiskReadLogicalSectors(DriveNumber, PartitionTableEntry.SectorCountBeforePartition, 1, (PVOID)0x7C00))
{
UiMessageBox("Unable to read partition's boot sector.");
return EIO;
}
/* Check for validity */
if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
{
UiMessageBox("Invalid boot sector magic (0xaa55)");
return ENOEXEC;
}
UiUnInitialize("Booting...");
IniCleanup();
/*
* Don't stop the floppy drive motor when we
* are just booting a bootsector, or drive, or partition.
* If we were to stop the floppy motor then
* the BIOS wouldn't be informed and if the
* next read is to a floppy then the BIOS will
* still think the motor is on and this will
* result in a read error.
*/
// DiskStopFloppyMotor();
// DisableA20();
FrldrBootDrive = DriveNumber;
ChainLoadBiosBootSectorCode();
return ESUCCESS;
return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber);
}
ARC_STATUS
@ -178,37 +203,7 @@ LoadAndBootDrive(
}
DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
/* Now try to read the boot sector (or mbr). If this fails then abort. */
if (!MachDiskReadLogicalSectors(DriveNumber, 0, 1, (PVOID)0x7C00))
{
UiMessageBox("Unable to read boot sector");
return EIO;
}
/* Check for validity */
if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
{
UiMessageBox("Invalid boot sector magic (0xaa55)");
return ENOEXEC;
}
UiUnInitialize("Booting...");
IniCleanup();
/*
* Don't stop the floppy drive motor when we
* are just booting a bootsector, or drive, or partition.
* If we were to stop the floppy motor then
* the BIOS wouldn't be informed and if the
* next read is to a floppy then the BIOS will
* still think the motor is on and this will
* result in a read error.
*/
// DiskStopFloppyMotor();
// DisableA20();
FrldrBootDrive = DriveNumber;
ChainLoadBiosBootSectorCode();
return ESUCCESS;
return LoadAndBootPartitionOrDrive(DriveNumber, 0);
}
#endif // _M_IX86

View File

@ -52,6 +52,7 @@ int TuiPrintf(const char *Format, ...)
BOOLEAN TuiInitialize(VOID)
{
MachVideoHideShowTextCursor(FALSE);
MachVideoSetTextCursorPosition(0, 0);
MachVideoClearScreen(ATTR(COLOR_GRAY, COLOR_BLACK));
TextVideoBuffer = VideoAllocateOffScreenBuffer();
@ -75,6 +76,7 @@ VOID TuiUnInitialize(VOID)
}
MachVideoClearScreen(ATTR(COLOR_GRAY, COLOR_BLACK));
MachVideoSetTextCursorPosition(0, 0);
MachVideoHideShowTextCursor(TRUE);
}