[FREELDR] Limit the usage of DiskStopFloppyMotor() in hardware/platform-specific...
[reactos.git] / boot / freeldr / freeldr / miscboot.c
index 535f9d6..e8f91c8 100644 (file)
@@ -31,37 +31,83 @@ LoadAndBootBootSector(
     IN PCHAR Argv[],
     IN PCHAR Envp[])
 {
+    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 */
     UiShowMessageBoxesInArgv(Argc, Argv);
 
-    /* Read the file name */
+    /*
+     * Check whether we have a "BootPath" value (takes precedence
+     * over both "BootDrive" and "BootPartition").
+     */
+    BootPath = GetArgumentValue(Argc, Argv, "BootPath");
+    if (!BootPath || !*BootPath)
+    {
+        /* 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");
+        }
+    }
+
+    /* Retrieve the file name */
     FileName = GetArgumentValue(Argc, Argv, "BootSectorFile");
-    if (!FileName)
+    if (!FileName || !*FileName)
     {
         UiMessageBox("Boot sector file not specified for selected OS!");
         return EINVAL;
     }
 
-    FileId = FsOpenFile(FileName);
-    if (!FileId)
+    /* Open the boot sector file */
+    Status = FsOpenFile(FileName, BootPath, OpenReadOnly, &FileId);
+    if (Status != ESUCCESS)
     {
-        UiMessageBox("%s not found.", FileName);
-        return ENOENT;
+        UiMessageBox("Unable to open %s", FileName);
+        return Status;
     }
 
-    /* Read boot sector */
-    if ((ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead) != ESUCCESS) || (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.");
+        UiMessageBox("Unable to load boot sector.");
         return EIO;
     }
 
-    ArcClose(FileId);
-
     /* Check for validity */
     if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
     {
@@ -72,55 +118,72 @@ LoadAndBootBootSector(
     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();
-    /* NOTE: Don't touch FrldrBootDrive */
-    ChainLoadBiosBootSectorCode();
-    Reboot(); /* Must not return! */
+    ChainLoadBiosBootSectorCode(0 /*DriveNumber*/, 0 /*PartitionNumber*/);
+    /* Must not return! */
     return ESUCCESS;
 }
 
 static ARC_STATUS
 LoadAndBootPartitionOrDrive(
     IN UCHAR DriveNumber,
-    IN ULONG PartitionNumber OPTIONAL)
+    IN ULONG PartitionNumber OPTIONAL,
+    IN PCSTR BootPath OPTIONAL)
 {
+    ARC_STATUS Status;
     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)
+    /*
+     * If the user specifies an ARC "BootPath" value, it takes precedence
+     * over both the DriveNumber and PartitionNumber options.
+     */
+    if (BootPath && *BootPath)
     {
-        UiMessageBox("Unable to open %s", ArcPath);
-        return ENOENT;
+        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;
+        }
+    }
+    else
+    {
+        /* We don't have one, so construct the corresponding ARC path */
+        ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
+        *strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
+
+        BootPath = ArcPath;
+    }
+
+    /* Open the volume */
+    Status = ArcOpen((PSTR)BootPath, OpenReadOnly, &FileId);
+    if (Status != ESUCCESS)
+    {
+        UiMessageBox("Unable to open %s", BootPath);
+        return Status;
     }
 
     /*
-     * Now try to read the partition boot sector or the MBR (when PartitionNumber == 0).
+     * Now try to load 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))
+    Status = ArcRead(FileId, (PVOID)0x7c00, 512, &BytesRead);
+    ArcClose(FileId);
+    if ((Status != ESUCCESS) || (BytesRead != 512))
     {
         if (PartitionNumber != 0)
-            UiMessageBox("Unable to read partition's boot sector.");
+            UiMessageBox("Unable to load partition's boot sector.");
         else
-            UiMessageBox("Unable to read MBR boot sector.");
+            UiMessageBox("Unable to load MBR boot sector.");
         return EIO;
     }
 
-    ArcClose(FileId);
-
     /* Check for validity */
     if (*((USHORT*)(0x7c00 + 0x1fe)) != 0xaa55)
     {
@@ -131,20 +194,8 @@ LoadAndBootPartitionOrDrive(
     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! */
+    ChainLoadBiosBootSectorCode(DriveNumber, PartitionNumber);
+    /* Must not return! */
     return ESUCCESS;
 }
 
@@ -155,31 +206,39 @@ LoadAndBootPartition(
     IN PCHAR Envp[])
 {
     PCSTR ArgValue;
-    UCHAR DriveNumber;
-    ULONG PartitionNumber;
+    PCSTR BootPath;
+    UCHAR DriveNumber = 0;
+    ULONG PartitionNumber = 0;
 
     /* Find all the message box settings and run them */
     UiShowMessageBoxesInArgv(Argc, Argv);
 
-    /* Read the boot drive */
-    ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
-    if (!ArgValue)
+    /*
+     * Check whether we have a "BootPath" value (takes precedence
+     * over both "BootDrive" and "BootPartition").
+     */
+    BootPath = GetArgumentValue(Argc, Argv, "BootPath");
+    if (!BootPath || !*BootPath)
     {
-        UiMessageBox("Boot drive not specified for selected OS!");
-        return EINVAL;
-    }
-    DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
+        /* We don't have one */
 
-    /* Read the boot partition */
-    ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
-    if (!ArgValue)
-    {
-        UiMessageBox("Boot partition not specified for selected OS!");
-        return EINVAL;
+        /* 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);
     }
-    PartitionNumber = atoi(ArgValue);
 
-    return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber);
+    return LoadAndBootPartitionOrDrive(DriveNumber, PartitionNumber, BootPath);
 }
 
 ARC_STATUS
@@ -189,21 +248,39 @@ LoadAndBootDrive(
     IN PCHAR Envp[])
 {
     PCSTR ArgValue;
-    UCHAR DriveNumber;
+    PCSTR BootPath;
+    UCHAR DriveNumber = 0;
 
     /* Find all the message box settings and run them */
     UiShowMessageBoxesInArgv(Argc, Argv);
 
-    /* Read the boot drive */
-    ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
-    if (!ArgValue)
+    /* Check whether we have a "BootPath" value (takes precedence over "BootDrive") */
+    BootPath = GetArgumentValue(Argc, Argv, "BootPath");
+    if (BootPath && *BootPath)
     {
-        UiMessageBox("Boot drive not specified for selected OS!");
-        return EINVAL;
+        /*
+         * 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;
+        }
+    }
+    else
+    {
+        /* 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);
     }
-    DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
 
-    return LoadAndBootPartitionOrDrive(DriveNumber, 0);
+    return LoadAndBootPartitionOrDrive(DriveNumber, 0, BootPath);
 }
 
 #endif // _M_IX86