[FREELDR] Minor enhancements for disk/partition boot and UI.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 13 Aug 2019 15:34:57 +0000 (17:34 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 13 Aug 2019 21:07:01 +0000 (23:07 +0200)
- 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
boot/freeldr/freeldr/arch/i386/pcmem.c
boot/freeldr/freeldr/arch/realmode/helpers.inc
boot/freeldr/freeldr/disk/disk.c
boot/freeldr/freeldr/include/arch/pc/pcbios.h
boot/freeldr/freeldr/miscboot.c
boot/freeldr/freeldr/ui/tui.c

index 853d37f..fde0d8a 100644 (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
index 4dd709b..b3b5761 100644 (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,
index 8f5db39..9813548 100644 (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
index 11cc0a7..e9579a0 100644 (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";
     }
 }
 
index 5ad273f..6faeb06 100644 (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
index 0d12e4b..535f9d6 100644 (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,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
index 8fd16aa..44f8016 100644 (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);
 }