[FREELDR] Limit the usage of DiskStopFloppyMotor() in hardware/platform-specific...
[reactos.git] / boot / freeldr / freeldr / miscboot.c
index 4ad2daa..e8f91c8 100644 (file)
 
 /* FUNCTIONS ******************************************************************/
 
-VOID
-LoadAndBootBootSector(IN OperatingSystemItem* OperatingSystem,
-                      IN USHORT OperatingSystemVersion)
+ARC_STATUS
+LoadAndBootBootSector(
+    IN ULONG Argc,
+    IN PCHAR Argv[],
+    IN PCHAR Envp[])
 {
-    ULONG_PTR SectionId;
-    PCSTR SectionName = OperatingSystem->SystemPartition;
-    CHAR  FileName[260];
-    PFILE FilePointer;
+    ARC_STATUS Status;
+    PCSTR ArgValue;
+    PCSTR BootPath;
+    PCSTR FileName;
+    UCHAR DriveNumber = 0;
+    ULONG PartitionNumber = 0;
+    ULONG FileId;
     ULONG BytesRead;
+    CHAR ArcPath[MAX_PATH];
 
     /* Find all the message box settings and run them */
-    UiShowMessageBoxesInSection(SectionName);
+    UiShowMessageBoxesInArgv(Argc, Argv);
 
-    /* Try to open the operating system section in the .ini file */
-    if (!IniOpenSection(SectionName, &SectionId))
+    /*
+     * Check whether we have a "BootPath" value (takes precedence
+     * over both "BootDrive" and "BootPartition").
+     */
+    BootPath = GetArgumentValue(Argc, Argv, "BootPath");
+    if (!BootPath || !*BootPath)
     {
-        UiMessageBox("Section [%s] not found in freeldr.ini.", SectionName);
-        return;
+        /* We don't have one, check whether we use "BootDrive" and "BootPartition" */
+
+        /* Retrieve the boot drive (optional, fall back to using default path otherwise) */
+        ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
+        if (ArgValue && *ArgValue)
+        {
+            DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
+
+            /* Retrieve the boot partition (not optional and cannot be zero) */
+            PartitionNumber = 0;
+            ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
+            if (ArgValue && *ArgValue)
+                PartitionNumber = atoi(ArgValue);
+            if (PartitionNumber == 0)
+            {
+                UiMessageBox("Boot partition cannot be 0!");
+                return EINVAL;
+            }
+
+            /* Construct the corresponding ARC path */
+            ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
+            *strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
+
+            BootPath = ArcPath;
+        }
+        else
+        {
+            /* Fall back to using the system partition as default path */
+            BootPath = GetArgumentValue(Argc, Argv, "SystemPartition");
+        }
     }
 
-    if (!IniReadSettingByName(SectionId, "BootSectorFile", FileName, sizeof(FileName)))
+    /* Retrieve the file name */
+    FileName = GetArgumentValue(Argc, Argv, "BootSectorFile");
+    if (!FileName || !*FileName)
     {
         UiMessageBox("Boot sector file not specified for selected OS!");
-        return;
+        return EINVAL;
     }
 
-    FilePointer = FsOpenFile(FileName);
-    if (!FilePointer)
+    /* Open the boot sector file */
+    Status = FsOpenFile(FileName, BootPath, OpenReadOnly, &FileId);
+    if (Status != ESUCCESS)
     {
-        UiMessageBox("%s not found.", FileName);
-        return;
+        UiMessageBox("Unable to open %s", FileName);
+        return Status;
     }
 
-    /* Read boot sector */
-    if (!FsReadFile(FilePointer, 512, &BytesRead, (void*)0x7c00) || (BytesRead != 512))
+    /* Now try to load the boot sector. If this fails then abort. */
+    Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
+    ArcClose(FileId);
+    if ((Status != ESUCCESS) || (BytesRead != 512))
     {
-        UiMessageBox("Unable to read boot sector.");
-        return;
+        UiMessageBox("Unable to load boot sector.");
+        return EIO;
     }
 
     /* Check for validity */
     if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
     {
         UiMessageBox("Invalid boot sector magic (0xaa55)");
-        return;
+        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();
-    ChainLoadBiosBootSectorCode();
+    ChainLoadBiosBootSectorCode(0 /*DriveNumber*/, 0 /*PartitionNumber*/);
+    /* Must not return! */
+    return ESUCCESS;
 }
 
-VOID
-LoadAndBootPartition(IN OperatingSystemItem* OperatingSystem,
-                     IN USHORT OperatingSystemVersion)
+static ARC_STATUS
+LoadAndBootPartitionOrDrive(
+    IN UCHAR DriveNumber,
+    IN ULONG PartitionNumber OPTIONAL,
+    IN PCSTR BootPath OPTIONAL)
 {
-    ULONG_PTR SectionId;
-    PCSTR SectionName = OperatingSystem->SystemPartition;
-    CHAR  SettingValue[80];
-    PARTITION_TABLE_ENTRY PartitionTableEntry;
-    UCHAR DriveNumber;
-    ULONG PartitionNumber;
-
-    /* Find all the message box settings and run them */
-    UiShowMessageBoxesInSection(SectionName);
+    ARC_STATUS Status;
+    ULONG FileId;
+    ULONG BytesRead;
+    CHAR ArcPath[MAX_PATH];
 
-    /* Try to open the operating system section in the .ini file */
-    if (!IniOpenSection(SectionName, &SectionId))
+    /*
+     * If the user specifies an ARC "BootPath" value, it takes precedence
+     * over both the DriveNumber and PartitionNumber options.
+     */
+    if (BootPath && *BootPath)
     {
-        UiMessageBox("Section [%s] not found in freeldr.ini.", SectionName);
-        return;
+        PCSTR FileName = NULL;
+
+        /*
+         * Retrieve the BIOS drive and partition numbers; verify also that the
+         * path is "valid" in the sense that it must not contain any file name.
+         */
+        if (!DissectArcPath(BootPath, &FileName, &DriveNumber, &PartitionNumber) ||
+            (FileName && *FileName))
+        {
+            return EINVAL;
+        }
     }
-
-    /* Read the boot drive */
-    if (!IniReadSettingByName(SectionId, "BootDrive", SettingValue, sizeof(SettingValue)))
+    else
     {
-        UiMessageBox("Boot drive not specified for selected OS!");
-        return;
-    }
-
-    DriveNumber = DriveMapGetBiosDriveNumber(SettingValue);
+        /* We don't have one, so construct the corresponding ARC path */
+        ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
+        *strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
 
-    /* Read the boot partition */
-    if (!IniReadSettingByName(SectionId, "BootPartition", SettingValue, sizeof(SettingValue)))
-    {
-        UiMessageBox("Boot partition not specified for selected OS!");
-        return;
+        BootPath = ArcPath;
     }
 
-    PartitionNumber = atoi(SettingValue);
-
-    /* Get the partition table entry */
-    if (!DiskGetPartitionEntry(DriveNumber, PartitionNumber, &PartitionTableEntry))
+    /* Open the volume */
+    Status = ArcOpen((PSTR)BootPath, OpenReadOnly, &FileId);
+    if (Status != ESUCCESS)
     {
-        return;
+        UiMessageBox("Unable to open %s", BootPath);
+        return Status;
     }
 
-    /* Now try to read the partition boot sector. If this fails then abort. */
-    if (!MachDiskReadLogicalSectors(DriveNumber, PartitionTableEntry.SectorCountBeforePartition, 1, (PVOID)0x7C00))
+    /*
+     * Now try to load the partition boot sector or the MBR (when PartitionNumber == 0).
+     * If this fails then abort.
+     */
+    Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
+    ArcClose(FileId);
+    if ((Status != ESUCCESS) || (BytesRead != 512))
     {
-        UiMessageBox("Unable to read partition's boot sector.");
-        return;
+        if (PartitionNumber != 0)
+            UiMessageBox("Unable to load partition's boot sector.");
+        else
+            UiMessageBox("Unable to load MBR boot sector.");
+        return EIO;
     }
 
     /* Check for validity */
     if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
     {
         UiMessageBox("Invalid boot sector magic (0xaa55)");
-        return;
+        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();
+    ChainLoadBiosBootSectorCode(DriveNumber, PartitionNumber);
+    /* Must not return! */
+    return ESUCCESS;
 }
 
-VOID
-LoadAndBootDrive(IN OperatingSystemItem* OperatingSystem,
-                 IN USHORT OperatingSystemVersion)
+ARC_STATUS
+LoadAndBootPartition(
+    IN ULONG Argc,
+    IN PCHAR Argv[],
+    IN PCHAR Envp[])
 {
-    ULONG_PTR SectionId;
-    PCSTR SectionName = OperatingSystem->SystemPartition;
-    CHAR  SettingValue[80];
-    UCHAR DriveNumber;
+    PCSTR ArgValue;
+    PCSTR BootPath;
+    UCHAR DriveNumber = 0;
+    ULONG PartitionNumber = 0;
 
     /* Find all the message box settings and run them */
-    UiShowMessageBoxesInSection(SectionName);
+    UiShowMessageBoxesInArgv(Argc, Argv);
 
-    /* Try to open the operating system section in the .ini file */
-    if (!IniOpenSection(SectionName, &SectionId))
+    /*
+     * Check whether we have a "BootPath" value (takes precedence
+     * over both "BootDrive" and "BootPartition").
+     */
+    BootPath = GetArgumentValue(Argc, Argv, "BootPath");
+    if (!BootPath || !*BootPath)
     {
-        UiMessageBox("Section [%s] not found in freeldr.ini.", SectionName);
-        return;
+        /* We don't have one */
+
+        /* Retrieve the boot drive */
+        ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
+        if (!ArgValue || !*ArgValue)
+        {
+            UiMessageBox("Boot drive not specified for selected OS!");
+            return EINVAL;
+        }
+        DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
+
+        /* Retrieve the boot partition (optional, fall back to zero otherwise) */
+        PartitionNumber = 0;
+        ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
+        if (ArgValue && *ArgValue)
+            PartitionNumber = atoi(ArgValue);
     }
 
-    if (!IniReadSettingByName(SectionId, "BootDrive", SettingValue, sizeof(SettingValue)))
-    {
-        UiMessageBox("Boot drive not specified for selected OS!");
-        return;
-    }
+    return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber, BootPath);
+}
 
-    DriveNumber = DriveMapGetBiosDriveNumber(SettingValue);
+ARC_STATUS
+LoadAndBootDrive(
+    IN ULONG Argc,
+    IN PCHAR Argv[],
+    IN PCHAR Envp[])
+{
+    PCSTR ArgValue;
+    PCSTR BootPath;
+    UCHAR DriveNumber = 0;
+
+    /* Find all the message box settings and run them */
+    UiShowMessageBoxesInArgv(Argc, Argv);
 
-    /* Now try to read the boot sector (or mbr). If this fails then abort. */
-    if (!MachDiskReadLogicalSectors(DriveNumber, 0, 1, (PVOID)0x7C00))
+    /* Check whether we have a "BootPath" value (takes precedence over "BootDrive") */
+    BootPath = GetArgumentValue(Argc, Argv, "BootPath");
+    if (BootPath && *BootPath)
     {
-        UiMessageBox("Unable to read boot sector");
-        return;
+        /*
+         * We have one, check that it does not contain any
+         * "partition()" specification, and fail if so.
+         */
+        if (strstr(BootPath, ")partition("))
+        {
+            UiMessageBox("Invalid 'BootPath' value!");
+            return EINVAL;
+        }
     }
-
-    /* Check for validity */
-    if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
+    else
     {
-        UiMessageBox("Invalid boot sector magic (0xaa55)");
-        return;
+        /* We don't, retrieve the boot drive value instead */
+        ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
+        if (!ArgValue || !*ArgValue)
+        {
+            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 LoadAndBootPartitionOrDrive(DriveNumber, 0, BootPath);
 }
 
 #endif // _M_IX86