From 85d44fca5923089cd10e03efe58c4854a2b8b176 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Tue, 13 Aug 2019 17:34:57 +0200 Subject: [PATCH] [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. --- boot/freeldr/freeldr/arch/i386/hwdisk.c | 4 +- boot/freeldr/freeldr/arch/i386/pcmem.c | 2 + .../freeldr/freeldr/arch/realmode/helpers.inc | 35 ++++- boot/freeldr/freeldr/disk/disk.c | 2 +- boot/freeldr/freeldr/include/arch/pc/pcbios.h | 1 - boot/freeldr/freeldr/miscboot.c | 125 +++++++++--------- boot/freeldr/freeldr/ui/tui.c | 2 + 7 files changed, 102 insertions(+), 69 deletions(-) diff --git a/boot/freeldr/freeldr/arch/i386/hwdisk.c b/boot/freeldr/freeldr/arch/i386/hwdisk.c index 853d37f0981..fde0d8acf89 100644 --- a/boot/freeldr/freeldr/arch/i386/hwdisk.c +++ b/boot/freeldr/freeldr/arch/i386/hwdisk.c @@ -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 diff --git a/boot/freeldr/freeldr/arch/i386/pcmem.c b/boot/freeldr/freeldr/arch/i386/pcmem.c index 4dd709b247c..b3b5761d957 100644 --- a/boot/freeldr/freeldr/arch/i386/pcmem.c +++ b/boot/freeldr/freeldr/arch/i386/pcmem.c @@ -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, diff --git a/boot/freeldr/freeldr/arch/realmode/helpers.inc b/boot/freeldr/freeldr/arch/realmode/helpers.inc index 8f5db395892..981354826ae 100644 --- a/boot/freeldr/freeldr/arch/realmode/helpers.inc +++ b/boot/freeldr/freeldr/arch/realmode/helpers.inc @@ -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 diff --git a/boot/freeldr/freeldr/disk/disk.c b/boot/freeldr/freeldr/disk/disk.c index 11cc0a7a63d..e9579a0beab 100644 --- a/boot/freeldr/freeldr/disk/disk.c +++ b/boot/freeldr/freeldr/disk/disk.c @@ -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"; } } diff --git a/boot/freeldr/freeldr/include/arch/pc/pcbios.h b/boot/freeldr/freeldr/include/arch/pc/pcbios.h index 5ad273f0442..6faeb06986d 100644 --- a/boot/freeldr/freeldr/include/arch/pc/pcbios.h +++ b/boot/freeldr/freeldr/include/arch/pc/pcbios.h @@ -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 diff --git a/boot/freeldr/freeldr/miscboot.c b/boot/freeldr/freeldr/miscboot.c index 0d12e4bc2c6..535f9d6efab 100644 --- a/boot/freeldr/freeldr/miscboot.c +++ b/boot/freeldr/freeldr/miscboot.c @@ -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,56 +82,45 @@ LoadAndBootBootSector( * result in a read error. */ // DiskStopFloppyMotor(); - // DisableA20(); + /* NOTE: Don't touch FrldrBootDrive */ ChainLoadBiosBootSectorCode(); + Reboot(); /* Must not return! */ return ESUCCESS; } -ARC_STATUS -LoadAndBootPartition( - IN ULONG Argc, - IN PCHAR Argv[], - IN PCHAR Envp[]) +static ARC_STATUS +LoadAndBootPartitionOrDrive( + IN UCHAR DriveNumber, + IN ULONG PartitionNumber OPTIONAL) { - PCSTR ArgValue; - PARTITION_TABLE_ENTRY PartitionTableEntry; - UCHAR DriveNumber; - ULONG PartitionNumber; - - /* Find all the message box settings and run them */ - UiShowMessageBoxesInArgv(Argc, Argv); - - /* Read the boot drive */ - ArgValue = GetArgumentValue(Argc, Argv, "BootDrive"); - if (!ArgValue) - { - UiMessageBox("Boot drive not specified for selected OS!"); - return EINVAL; - } - DriveNumber = DriveMapGetBiosDriveNumber(ArgValue); - - /* Read the boot partition */ - ArgValue = GetArgumentValue(Argc, Argv, "BootPartition"); - if (!ArgValue) - { - UiMessageBox("Boot partition not specified for selected OS!"); - return EINVAL; - } - PartitionNumber = atoi(ArgValue); + ULONG FileId; + ULONG BytesRead; + CHAR ArcPath[MAX_PATH]; - /* Get the partition table entry */ - if (!DiskGetPartitionEntry(DriveNumber, PartitionNumber, &PartitionTableEntry)) + /* 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. If this fails then abort. */ - if (!MachDiskReadLogicalSectors(DriveNumber, PartitionTableEntry.SectorCountBeforePartition, 1, (PVOID)0x7C00)) + /* + * 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)) { - UiMessageBox("Unable to read partition's boot sector."); + 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) { @@ -151,20 +141,22 @@ LoadAndBootPartition( * result in a read error. */ // DiskStopFloppyMotor(); - // DisableA20(); FrldrBootDrive = DriveNumber; + FrldrBootPartition = PartitionNumber; ChainLoadBiosBootSectorCode(); + Reboot(); /* Must not return! */ return ESUCCESS; } ARC_STATUS -LoadAndBootDrive( +LoadAndBootPartition( IN ULONG Argc, IN PCHAR Argv[], IN PCHAR Envp[]) { PCSTR ArgValue; UCHAR DriveNumber; + ULONG PartitionNumber; /* Find all the message box settings and run them */ UiShowMessageBoxesInArgv(Argc, Argv); @@ -178,37 +170,40 @@ 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)) + /* Read the boot partition */ + ArgValue = GetArgumentValue(Argc, Argv, "BootPartition"); + if (!ArgValue) { - UiMessageBox("Unable to read boot sector"); - return EIO; + UiMessageBox("Boot partition not specified for selected OS!"); + return EINVAL; } + PartitionNumber = atoi(ArgValue); - /* Check for validity */ - if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55) + return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber); +} + +ARC_STATUS +LoadAndBootDrive( + IN ULONG Argc, + IN PCHAR Argv[], + IN PCHAR Envp[]) +{ + PCSTR ArgValue; + UCHAR DriveNumber; + + /* Find all the message box settings and run them */ + UiShowMessageBoxesInArgv(Argc, Argv); + + /* Read the boot drive */ + ArgValue = GetArgumentValue(Argc, Argv, "BootDrive"); + if (!ArgValue) { - UiMessageBox("Invalid boot sector magic (0xaa55)"); - return ENOEXEC; + UiMessageBox("Boot drive not specified for selected OS!"); + return EINVAL; } + DriveNumber = DriveMapGetBiosDriveNumber(ArgValue); - 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 diff --git a/boot/freeldr/freeldr/ui/tui.c b/boot/freeldr/freeldr/ui/tui.c index 8fd16aabc72..44f80163a5b 100644 --- a/boot/freeldr/freeldr/ui/tui.c +++ b/boot/freeldr/freeldr/ui/tui.c @@ -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); } -- 2.17.1