[FREELDR] Limit the usage of DiskStopFloppyMotor() in hardware/platform-specific...
[reactos.git] / boot / freeldr / freeldr / custom.c
index 6d9dab2..cf60653 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+/* INCLUDES *******************************************************************/
+
 #include <freeldr.h>
 
+/* GLOBALS ********************************************************************/
+
+#ifdef _M_IX86
+
+const CHAR BootSectorFilePrompt[] = "Enter the boot sector file path.\n\nExamples:\n\\BOOTSECT.DOS\n/boot/bootsect.dos";
+const CHAR LinuxKernelPrompt[] = "Enter the Linux kernel image path.\n\nExamples:\n/vmlinuz\n/boot/vmlinuz-2.4.18";
+const CHAR LinuxInitrdPrompt[] = "Enter the initrd image path.\n\nExamples:\n/initrd.gz\n/boot/root.img.gz\n\nLeave blank for no initial ram disk.";
+const CHAR LinuxCommandLinePrompt[] = "Enter the Linux kernel command line.\n\nExamples:\nroot=/dev/hda1\nroot=/dev/fd0 read-only\nroot=/dev/sdb1 init=/sbin/init";
+
+#endif // _M_IX86
 
-const CHAR     BootDrivePrompt[] = "Enter the boot drive.\n\nExamples:\nfd0 - first floppy drive\nhd0 - first hard drive\nhd1 - second hard drive\ncd0 - first CD-ROM drive.\n\nBIOS drive numbers may also be used:\n0 - first floppy drive\n0x80 - first hard drive\n0x81 - second hard drive";
-const CHAR     BootPartitionPrompt[] = "Enter the boot partition.\n\nEnter 0 for the active (bootable) partition.";
-const CHAR     BootSectorFilePrompt[] = "Enter the boot sector file path.\n\nExamples:\n\\BOOTSECT.DOS\n/boot/bootsect.dos";
-const CHAR     LinuxKernelPrompt[] = "Enter the Linux kernel image path.\n\nExamples:\n/vmlinuz\n/boot/vmlinuz-2.4.18";
-const CHAR     LinuxInitrdPrompt[] = "Enter the initrd image path.\n\nExamples:\n/initrd.gz\n/boot/root.img.gz\n\nLeave blank for no initial ram disk.";
-const CHAR     LinuxCommandLinePrompt[] = "Enter the Linux kernel command line.\n\nExamples:\nroot=/dev/hda1\nroot=/dev/fd0 read-only\nroot=/dev/sdb1 init=/sbin/init";
-const CHAR     ReactOSSystemPathPrompt[] = "Enter the path to your ReactOS system directory.\n\nExamples:\n\\REACTOS\n\\ROS";
-const CHAR     ReactOSOptionsPrompt[] = "Enter the options you want passed to the kernel.\n\nExamples:\n/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200\n/FASTDETECT /SOS /NOGUIBOOT\n/BASEVIDEO /MAXMEM=64\n/KERNEL=NTKRNLMP.EXE /HAL=HALMPS.DLL";
+const CHAR BootDrivePrompt[] = "Enter the boot drive.\n\nExamples:\nfd0 - first floppy drive\nhd0 - first hard drive\nhd1 - second hard drive\ncd0 - first CD-ROM drive.\n\nBIOS drive numbers may also be used:\n0 - first floppy drive\n0x80 - first hard drive\n0x81 - second hard drive";
+const CHAR BootPartitionPrompt[] = "Enter the boot partition.\n\nEnter 0 for the active (bootable) partition.";
+const CHAR ARCPathPrompt[] = "Enter the boot ARC path.\n\nExamples:\nmulti(0)disk(0)rdisk(0)partition(1)\nmulti(0)disk(0)fdisk(0)";
+const CHAR ReactOSSystemPathPrompt[] = "Enter the path to your ReactOS system directory.\n\nExamples:\n\\REACTOS\n\\ROS";
+const CHAR ReactOSOptionsPrompt[] = "Enter the options you want passed to the kernel.\n\nExamples:\n/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200\n/FASTDETECT /SOS /NOGUIBOOT\n/BASEVIDEO /MAXMEM=64\n/KERNEL=NTKRNLMP.EXE /HAL=HALMPS.DLL";
+const CHAR CustomBootPrompt[] = "Press ENTER to boot your custom boot setup.";
 
-const CHAR     CustomBootPrompt[] = "Press ENTER to boot your custom boot setup.";
+/* FUNCTIONS ******************************************************************/
+
+#ifdef HAS_OPTION_MENU_CUSTOM_BOOT
 
 VOID OptionMenuCustomBoot(VOID)
 {
-       PCSTR   CustomBootMenuList[] = {
-#ifdef __i386__
-               "Disk",
-               "Partition",
-               "Boot Sector File",
-               "ReactOS",
-               "Linux"
-#endif /* __i386__ */
-               };
-       ULONG           CustomBootMenuCount = sizeof(CustomBootMenuList) / sizeof(CustomBootMenuList[0]);
-       ULONG           SelectedMenuItem;
-
-       if (!UiDisplayMenu(CustomBootMenuList, CustomBootMenuCount, 0, -1, &SelectedMenuItem, TRUE, NULL))
-       {
-               // The user pressed ESC
-               return;
-       }
-
-       switch (SelectedMenuItem)
-       {
-#ifdef __i386__
-       case 0: // Disk
-               OptionMenuCustomBootDisk();
-               break;
-       case 1: // Partition
-               OptionMenuCustomBootPartition();
-               break;
-       case 2: // Boot Sector File
-               OptionMenuCustomBootBootSectorFile();
-               break;
-       case 3: // ReactOS
-               OptionMenuCustomBootReactOS();
-               break;
-       case 4: // Linux
-               OptionMenuCustomBootLinux();
-               break;
-#endif /* __i386__ */
-       }
+    PCSTR CustomBootMenuList[] = {
+#ifdef _M_IX86
+        "Disk",
+        "Partition",
+        "Boot Sector File",
+        "Linux",
+#endif
+        "ReactOS",
+        "ReactOS Setup"
+        };
+    ULONG SelectedMenuItem;
+    OperatingSystemItem OperatingSystem;
+
+    if (!UiDisplayMenu("Please choose a boot method:", NULL,
+                       FALSE,
+                       CustomBootMenuList,
+                       sizeof(CustomBootMenuList) / sizeof(CustomBootMenuList[0]),
+                       0, -1,
+                       &SelectedMenuItem,
+                       TRUE,
+                       NULL, NULL))
+    {
+        /* The user pressed ESC */
+        return;
+    }
+
+    /* Initialize a new custom OS entry */
+    OperatingSystem.SectionId = 0;
+    switch (SelectedMenuItem)
+    {
+#ifdef _M_IX86
+        case 0: // Disk
+            EditCustomBootDisk(&OperatingSystem);
+            break;
+        case 1: // Partition
+            EditCustomBootPartition(&OperatingSystem);
+            break;
+        case 2: // Boot Sector File
+            EditCustomBootSectorFile(&OperatingSystem);
+            break;
+        case 3: // Linux
+            EditCustomBootLinux(&OperatingSystem);
+            break;
+        case 4: // ReactOS
+            EditCustomBootReactOS(&OperatingSystem, FALSE);
+            break;
+        case 5: // ReactOS Setup
+            EditCustomBootReactOS(&OperatingSystem, TRUE);
+            break;
+#else
+        case 0: // ReactOS
+            EditCustomBootReactOS(&OperatingSystem, FALSE);
+            break;
+        case 1: // ReactOS Setup
+            EditCustomBootReactOS(&OperatingSystem, TRUE);
+            break;
+#endif
+    }
+
+    /* And boot it */
+    if (OperatingSystem.SectionId != 0)
+    {
+        UiMessageBox(CustomBootPrompt);
+        LoadOperatingSystem(&OperatingSystem);
+    }
 }
 
-#ifdef __i386__
-VOID OptionMenuCustomBootDisk(VOID)
+#endif // HAS_OPTION_MENU_CUSTOM_BOOT
+
+#ifdef _M_IX86
+
+VOID
+EditCustomBootDisk(
+    IN OUT OperatingSystemItem* OperatingSystem)
 {
-       CHAR    SectionName[100];
-       CHAR    BootDriveString[20];
-       ULONG   SectionId;
-       ULONG   Year, Month, Day, Hour, Minute, Second;
-
-       RtlZeroMemory(SectionName, sizeof(SectionName));
-       RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
-
-       if (!UiEditBox(BootDrivePrompt, BootDriveString, 20))
-       {
-               return;
-       }
-
-       // Generate a unique section name
-       MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
-       sprintf(SectionName, "CustomBootDisk%ld%ld%ld%ld%ld%ld", Year, Day, Month, Hour, Minute, Second);
-
-       // Add the section
-       if (!IniAddSection(SectionName, &SectionId))
-       {
-               return;
-       }
-
-       // Add the BootType
-       if (!IniAddSettingValueToSection(SectionId, "BootType", "Drive"))
-       {
-               return;
-       }
-
-       // Add the BootDrive
-       if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
-       {
-               return;
-       }
-
-       UiMessageBox(CustomBootPrompt);
-
-       LoadAndBootDrive(SectionName);
+    TIMEINFO* TimeInfo;
+    ULONG_PTR SectionId = OperatingSystem->SectionId;
+    CHAR SectionName[100];
+    /* The following is a trick for saving some stack space */
+    union
+    {
+        struct
+        {
+            CHAR Guard1;
+            CHAR Drive[20];
+            CHAR Guard2;
+        };
+        CHAR ArcPath[200];
+    } BootStrings;
+
+    RtlZeroMemory(SectionName, sizeof(SectionName));
+    RtlZeroMemory(&BootStrings, sizeof(BootStrings));
+
+    if (SectionId != 0)
+    {
+        /* Load the settings */
+
+        /* Check whether we have a "BootPath" value (takes precedence over "BootDrive") */
+        *BootStrings.ArcPath = ANSI_NULL;
+        IniReadSettingByName(SectionId, "BootPath", BootStrings.ArcPath, sizeof(BootStrings.ArcPath));
+        if (!*BootStrings.ArcPath)
+        {
+            /* We don't, retrieve the boot drive value instead */
+            IniReadSettingByName(SectionId, "BootDrive", BootStrings.Drive, sizeof(BootStrings.Drive));
+        }
+    }
+
+    if (!*BootStrings.ArcPath)
+    {
+        if (!UiEditBox(BootDrivePrompt, BootStrings.Drive, sizeof(BootStrings.Drive)))
+            return;
+    }
+    if (!*BootStrings.Drive)
+    {
+        if (!UiEditBox(ARCPathPrompt, BootStrings.ArcPath, sizeof(BootStrings.ArcPath)))
+            return;
+    }
+
+    /* Modify the settings values and return if we were in edit mode */
+    if (SectionId != 0)
+    {
+        /* Modify the BootPath if we have one */
+        if (*BootStrings.ArcPath)
+        {
+            IniModifySettingValue(SectionId, "BootPath", BootStrings.ArcPath);
+        }
+        else if (*BootStrings.Drive)
+        {
+            /* Otherwise, modify the BootDrive */
+            IniModifySettingValue(SectionId, "BootDrive", BootStrings.Drive);
+        }
+        return;
+    }
+
+    /* Generate a unique section name */
+    TimeInfo = ArcGetTime();
+    RtlStringCbPrintfA(SectionName, sizeof(SectionName),
+                       "CustomBootDisk%u%u%u%u%u%u",
+                       TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+                       TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+
+    /* Add the section */
+    if (!IniAddSection(SectionName, &SectionId))
+        return;
+
+    /* Add the BootType */
+    if (!IniAddSettingValueToSection(SectionId, "BootType", "Drive"))
+        return;
+
+    /* Add the BootPath if we have one */
+    if (*BootStrings.ArcPath)
+    {
+        if (!IniAddSettingValueToSection(SectionId, "BootPath", BootStrings.ArcPath))
+            return;
+    }
+    else if (*BootStrings.Drive)
+    {
+        /* Otherwise, add the BootDrive */
+        if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootStrings.Drive))
+            return;
+    }
+
+    OperatingSystem->SectionId = SectionId;
+    OperatingSystem->LoadIdentifier = NULL;
 }
 
-VOID OptionMenuCustomBootPartition(VOID)
+VOID
+EditCustomBootPartition(
+    IN OUT OperatingSystemItem* OperatingSystem)
 {
-       CHAR    SectionName[100];
-       CHAR    BootDriveString[20];
-       CHAR    BootPartitionString[20];
-       ULONG   SectionId;
-       ULONG   Year, Month, Day, Hour, Minute, Second;
-
-       RtlZeroMemory(SectionName, sizeof(SectionName));
-       RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
-       RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
-
-       if (!UiEditBox(BootDrivePrompt, BootDriveString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(BootPartitionPrompt, BootPartitionString, 20))
-       {
-               return;
-       }
-
-       // Generate a unique section name
-       MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
-       sprintf(SectionName, "CustomBootPartition%ld%ld%ld%ld%ld%ld", Year, Day, Month, Hour, Minute, Second);
-
-       // Add the section
-       if (!IniAddSection(SectionName, &SectionId))
-       {
-               return;
-       }
-
-       // Add the BootType
-       if (!IniAddSettingValueToSection(SectionId, "BootType", "Partition"))
-       {
-               return;
-       }
-
-       // Add the BootDrive
-       if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
-       {
-               return;
-       }
-
-       // Add the BootPartition
-       if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootPartitionString))
-       {
-               return;
-       }
-
-       UiMessageBox(CustomBootPrompt);
-
-       LoadAndBootPartition(SectionName);
+    TIMEINFO* TimeInfo;
+    ULONG_PTR SectionId = OperatingSystem->SectionId;
+    CHAR SectionName[100];
+    /* The following is a trick for saving some stack space */
+    union
+    {
+        struct
+        {
+            CHAR Guard1;
+            CHAR Drive[20];
+            CHAR Partition[20];
+            CHAR Guard2;
+        };
+        CHAR ArcPath[200];
+    } BootStrings;
+
+    RtlZeroMemory(SectionName, sizeof(SectionName));
+    RtlZeroMemory(&BootStrings, sizeof(BootStrings));
+
+    if (SectionId != 0)
+    {
+        /* Load the settings */
+
+        /*
+         * Check whether we have a "BootPath" value (takes precedence
+         * over both "BootDrive" and "BootPartition").
+         */
+        *BootStrings.ArcPath = ANSI_NULL;
+        IniReadSettingByName(SectionId, "BootPath", BootStrings.ArcPath, sizeof(BootStrings.ArcPath));
+        if (!*BootStrings.ArcPath)
+        {
+            /* We don't, retrieve the boot drive and partition values instead */
+            IniReadSettingByName(SectionId, "BootDrive", BootStrings.Drive, sizeof(BootStrings.Drive));
+            IniReadSettingByName(SectionId, "BootPartition", BootStrings.Partition, sizeof(BootStrings.Partition));
+        }
+    }
+
+    if (!*BootStrings.ArcPath)
+    {
+        if (!UiEditBox(BootDrivePrompt, BootStrings.Drive, sizeof(BootStrings.Drive)))
+            return;
+
+        if (*BootStrings.Drive)
+        {
+            if (!UiEditBox(BootPartitionPrompt, BootStrings.Partition, sizeof(BootStrings.Partition)))
+                return;
+        }
+    }
+    if (!*BootStrings.Drive)
+    {
+        if (!UiEditBox(ARCPathPrompt, BootStrings.ArcPath, sizeof(BootStrings.ArcPath)))
+            return;
+    }
+
+    /* Modify the settings values and return if we were in edit mode */
+    if (SectionId != 0)
+    {
+        /* Modify the BootPath if we have one */
+        if (*BootStrings.ArcPath)
+        {
+            IniModifySettingValue(SectionId, "BootPath", BootStrings.ArcPath);
+        }
+        else if (*BootStrings.Drive)
+        {
+            /* Otherwise, modify the BootDrive and BootPartition */
+            IniModifySettingValue(SectionId, "BootDrive", BootStrings.Drive);
+            IniModifySettingValue(SectionId, "BootPartition", BootStrings.Partition);
+        }
+        return;
+    }
+
+    /* Generate a unique section name */
+    TimeInfo = ArcGetTime();
+    RtlStringCbPrintfA(SectionName, sizeof(SectionName),
+                       "CustomBootPartition%u%u%u%u%u%u",
+                       TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+                       TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+
+    /* Add the section */
+    if (!IniAddSection(SectionName, &SectionId))
+        return;
+
+    /* Add the BootType */
+    if (!IniAddSettingValueToSection(SectionId, "BootType", "Partition"))
+        return;
+
+    /* Add the BootPath if we have one */
+    if (*BootStrings.ArcPath)
+    {
+        if (!IniAddSettingValueToSection(SectionId, "BootPath", BootStrings.ArcPath))
+            return;
+    }
+    else if (*BootStrings.Drive)
+    {
+        /* Otherwise, add the BootDrive and BootPartition */
+        if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootStrings.Drive))
+            return;
+
+        if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootStrings.Partition))
+            return;
+    }
+
+    OperatingSystem->SectionId = SectionId;
+    OperatingSystem->LoadIdentifier = NULL;
 }
 
-VOID OptionMenuCustomBootBootSectorFile(VOID)
+VOID
+EditCustomBootSectorFile(
+    IN OUT OperatingSystemItem* OperatingSystem)
 {
-       CHAR    SectionName[100];
-       CHAR    BootDriveString[20];
-       CHAR    BootPartitionString[20];
-       CHAR    BootSectorFileString[200];
-       ULONG   SectionId;
-       ULONG   Year, Month, Day, Hour, Minute, Second;
-
-       RtlZeroMemory(SectionName, sizeof(SectionName));
-       RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
-       RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
-       RtlZeroMemory(BootSectorFileString, sizeof(BootSectorFileString));
-
-       if (!UiEditBox(BootDrivePrompt, BootDriveString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(BootPartitionPrompt, BootPartitionString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(BootSectorFilePrompt, BootSectorFileString, 200))
-       {
-               return;
-       }
-
-       // Generate a unique section name
-       MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
-       sprintf(SectionName, "CustomBootSectorFile%ld%ld%ld%ld%ld%ld", Year, Day, Month, Hour, Minute, Second);
-
-       // Add the section
-       if (!IniAddSection(SectionName, &SectionId))
-       {
-               return;
-       }
-
-       // Add the BootType
-       if (!IniAddSettingValueToSection(SectionId, "BootType", "BootSector"))
-       {
-               return;
-       }
-
-       // Add the BootDrive
-       if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
-       {
-               return;
-       }
-
-       // Add the BootPartition
-       if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootPartitionString))
-       {
-               return;
-       }
-
-       // Add the BootSectorFile
-       if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", BootSectorFileString))
-       {
-               return;
-       }
-
-       UiMessageBox(CustomBootPrompt);
-
-       LoadAndBootBootSector(SectionName);
+    TIMEINFO* TimeInfo;
+    ULONG_PTR SectionId = OperatingSystem->SectionId;
+    CHAR SectionName[100];
+    /* The following is a trick for saving some stack space */
+    union
+    {
+        struct
+        {
+            CHAR Guard1;
+            CHAR Drive[20];
+            CHAR Partition[20];
+            CHAR Guard2;
+        };
+        CHAR ArcPath[200];
+    } BootStrings;
+    CHAR BootSectorFileString[200];
+
+    RtlZeroMemory(SectionName, sizeof(SectionName));
+    RtlZeroMemory(&BootStrings, sizeof(BootStrings));
+    RtlZeroMemory(BootSectorFileString, sizeof(BootSectorFileString));
+
+    if (SectionId != 0)
+    {
+        /* Load the settings */
+
+        /*
+         * Check whether we have a "BootPath" value (takes precedence
+         * over both "BootDrive" and "BootPartition").
+         */
+        *BootStrings.ArcPath = ANSI_NULL;
+        IniReadSettingByName(SectionId, "BootPath", BootStrings.ArcPath, sizeof(BootStrings.ArcPath));
+        if (!*BootStrings.ArcPath)
+        {
+            /* We don't, retrieve the boot drive and partition values instead */
+            IniReadSettingByName(SectionId, "BootDrive", BootStrings.Drive, sizeof(BootStrings.Drive));
+            IniReadSettingByName(SectionId, "BootPartition", BootStrings.Partition, sizeof(BootStrings.Partition));
+        }
+
+        IniReadSettingByName(SectionId, "BootSectorFile", BootSectorFileString, sizeof(BootSectorFileString));
+    }
+
+    if (!*BootStrings.ArcPath)
+    {
+        if (!UiEditBox(BootDrivePrompt, BootStrings.Drive, sizeof(BootStrings.Drive)))
+            return;
+
+        if (*BootStrings.Drive)
+        {
+            if (!UiEditBox(BootPartitionPrompt, BootStrings.Partition, sizeof(BootStrings.Partition)))
+                return;
+        }
+    }
+    if (!*BootStrings.Drive)
+    {
+        if (!UiEditBox(ARCPathPrompt, BootStrings.ArcPath, sizeof(BootStrings.ArcPath)))
+            return;
+    }
+
+    if (!UiEditBox(BootSectorFilePrompt, BootSectorFileString, sizeof(BootSectorFileString)))
+        return;
+
+    /* Modify the settings values and return if we were in edit mode */
+    if (SectionId != 0)
+    {
+        /* Modify the BootPath if we have one */
+        if (*BootStrings.ArcPath)
+        {
+            IniModifySettingValue(SectionId, "BootPath", BootStrings.ArcPath);
+        }
+        else if (*BootStrings.Drive)
+        {
+            /* Otherwise, modify the BootDrive and BootPartition */
+            IniModifySettingValue(SectionId, "BootDrive", BootStrings.Drive);
+            IniModifySettingValue(SectionId, "BootPartition", BootStrings.Partition);
+        }
+        else
+        {
+            /*
+             * Otherwise, zero out all values: BootSectorFile will be
+             * relative to the default system partition.
+             */
+            IniModifySettingValue(SectionId, "BootPath", "");
+            IniModifySettingValue(SectionId, "BootDrive", "");
+            IniModifySettingValue(SectionId, "BootPartition", "");
+        }
+
+        IniModifySettingValue(SectionId, "BootSectorFile", BootSectorFileString);
+        return;
+    }
+
+    /* Generate a unique section name */
+    TimeInfo = ArcGetTime();
+    RtlStringCbPrintfA(SectionName, sizeof(SectionName),
+                       "CustomBootSectorFile%u%u%u%u%u%u",
+                       TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+                       TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+
+    /* Add the section */
+    if (!IniAddSection(SectionName, &SectionId))
+        return;
+
+    /* Add the BootType */
+    if (!IniAddSettingValueToSection(SectionId, "BootType", "BootSector"))
+        return;
+
+    /* Add the BootPath if we have one */
+    if (*BootStrings.ArcPath)
+    {
+        if (!IniAddSettingValueToSection(SectionId, "BootPath", BootStrings.ArcPath))
+            return;
+    }
+    else if (*BootStrings.Drive)
+    {
+        /* Otherwise, add the BootDrive and BootPartition */
+        if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootStrings.Drive))
+            return;
+
+        if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootStrings.Partition))
+            return;
+    }
+
+    /* Add the BootSectorFile */
+    if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", BootSectorFileString))
+        return;
+
+    OperatingSystem->SectionId = SectionId;
+    OperatingSystem->LoadIdentifier = NULL;
 }
 
-VOID OptionMenuCustomBootReactOS(VOID)
+VOID
+EditCustomBootLinux(
+    IN OUT OperatingSystemItem* OperatingSystem)
 {
-       CHAR    SectionName[100];
-       CHAR    BootDriveString[20];
-       CHAR    BootPartitionString[20];
-       CHAR    ReactOSSystemPath[200];
-       CHAR    ReactOSARCPath[200];
-       CHAR    ReactOSOptions[200];
-       ULONG   SectionId;
-       ULONG   Year, Month, Day, Hour, Minute, Second;
-
-       RtlZeroMemory(SectionName, sizeof(SectionName));
-       RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
-       RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
-       RtlZeroMemory(ReactOSSystemPath, sizeof(ReactOSSystemPath));
-       RtlZeroMemory(ReactOSOptions, sizeof(ReactOSOptions));
-
-       if (!UiEditBox(BootDrivePrompt, BootDriveString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(BootPartitionPrompt, BootPartitionString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(ReactOSSystemPathPrompt, ReactOSSystemPath, 200))
-       {
-               return;
-       }
-
-       if (!UiEditBox(ReactOSOptionsPrompt, ReactOSOptions, 200))
-       {
-               return;
-       }
-
-       // Generate a unique section name
-       MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
-       sprintf(SectionName, "CustomReactOS%ld%ld%ld%ld%ld%ld", Year, Day, Month, Hour, Minute, Second);
-
-       // Add the section
-       if (!IniAddSection(SectionName, &SectionId))
-       {
-               return;
-       }
-
-       // Add the BootType
-       if (!IniAddSettingValueToSection(SectionId, "BootType", "ReactOS"))
-       {
-               return;
-       }
-
-       // Construct the ReactOS ARC system path
-       ConstructArcPath(ReactOSARCPath, ReactOSSystemPath, DriveMapGetBiosDriveNumber(BootDriveString), atoi(BootPartitionString));
-
-       // Add the system path
-       if (!IniAddSettingValueToSection(SectionId, "SystemPath", ReactOSARCPath))
-       {
-               return;
-       }
-
-       // Add the CommandLine
-       if (!IniAddSettingValueToSection(SectionId, "Options", ReactOSOptions))
-       {
-               return;
-       }
-
-       UiMessageBox(CustomBootPrompt);
-
-       LoadAndBootReactOS(SectionName);
+    TIMEINFO* TimeInfo;
+    ULONG_PTR SectionId = OperatingSystem->SectionId;
+    CHAR SectionName[100];
+    /* The following is a trick for saving some stack space */
+    union
+    {
+        struct
+        {
+            CHAR Guard1;
+            CHAR Drive[20];
+            CHAR Partition[20];
+            CHAR Guard2;
+        };
+        CHAR ArcPath[200];
+    } BootStrings;
+    CHAR LinuxKernelString[200];
+    CHAR LinuxInitrdString[200];
+    CHAR LinuxCommandLineString[200];
+
+    RtlZeroMemory(SectionName, sizeof(SectionName));
+    RtlZeroMemory(&BootStrings, sizeof(BootStrings));
+    RtlZeroMemory(LinuxKernelString, sizeof(LinuxKernelString));
+    RtlZeroMemory(LinuxInitrdString, sizeof(LinuxInitrdString));
+    RtlZeroMemory(LinuxCommandLineString, sizeof(LinuxCommandLineString));
+
+    if (SectionId != 0)
+    {
+        /* Load the settings */
+
+        /*
+         * Check whether we have a "BootPath" value (takes precedence
+         * over both "BootDrive" and "BootPartition").
+         */
+        *BootStrings.ArcPath = ANSI_NULL;
+        IniReadSettingByName(SectionId, "BootPath", BootStrings.ArcPath, sizeof(BootStrings.ArcPath));
+        if (!*BootStrings.ArcPath)
+        {
+            /* We don't, retrieve the boot drive and partition values instead */
+            IniReadSettingByName(SectionId, "BootDrive", BootStrings.Drive, sizeof(BootStrings.Drive));
+            IniReadSettingByName(SectionId, "BootPartition", BootStrings.Partition, sizeof(BootStrings.Partition));
+        }
+
+        IniReadSettingByName(SectionId, "Kernel", LinuxKernelString, sizeof(LinuxKernelString));
+        IniReadSettingByName(SectionId, "Initrd", LinuxInitrdString, sizeof(LinuxInitrdString));
+        IniReadSettingByName(SectionId, "CommandLine", LinuxCommandLineString, sizeof(LinuxCommandLineString));
+    }
+
+    if (!*BootStrings.ArcPath)
+    {
+        if (!UiEditBox(BootDrivePrompt, BootStrings.Drive, sizeof(BootStrings.Drive)))
+            return;
+
+        if (*BootStrings.Drive)
+        {
+            if (!UiEditBox(BootPartitionPrompt, BootStrings.Partition, sizeof(BootStrings.Partition)))
+                return;
+        }
+    }
+    if (!*BootStrings.Drive)
+    {
+        if (!UiEditBox(ARCPathPrompt, BootStrings.ArcPath, sizeof(BootStrings.ArcPath)))
+            return;
+    }
+
+    if (!UiEditBox(LinuxKernelPrompt, LinuxKernelString, sizeof(LinuxKernelString)))
+        return;
+
+    if (!UiEditBox(LinuxInitrdPrompt, LinuxInitrdString, sizeof(LinuxInitrdString)))
+        return;
+
+    if (!UiEditBox(LinuxCommandLinePrompt, LinuxCommandLineString, sizeof(LinuxCommandLineString)))
+        return;
+
+    /* Modify the settings values and return if we were in edit mode */
+    if (SectionId != 0)
+    {
+        /* Modify the BootPath if we have one */
+        if (*BootStrings.ArcPath)
+        {
+            IniModifySettingValue(SectionId, "BootPath", BootStrings.ArcPath);
+        }
+        else if (*BootStrings.Drive)
+        {
+            /* Otherwise, modify the BootDrive and BootPartition */
+            IniModifySettingValue(SectionId, "BootDrive", BootStrings.Drive);
+            IniModifySettingValue(SectionId, "BootPartition", BootStrings.Partition);
+        }
+        else
+        {
+            /*
+             * Otherwise, zero out all values: BootSectorFile will be
+             * relative to the default system partition.
+             */
+            IniModifySettingValue(SectionId, "BootPath", "");
+            IniModifySettingValue(SectionId, "BootDrive", "");
+            IniModifySettingValue(SectionId, "BootPartition", "");
+        }
+
+        IniModifySettingValue(SectionId, "Kernel", LinuxKernelString);
+        IniModifySettingValue(SectionId, "Initrd", LinuxInitrdString);
+        IniModifySettingValue(SectionId, "CommandLine", LinuxCommandLineString);
+        return;
+    }
+
+    /* Generate a unique section name */
+    TimeInfo = ArcGetTime();
+    RtlStringCbPrintfA(SectionName, sizeof(SectionName),
+                       "CustomLinux%u%u%u%u%u%u",
+                       TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+                       TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+
+    /* Add the section */
+    if (!IniAddSection(SectionName, &SectionId))
+        return;
+
+    /* Add the BootType */
+    if (!IniAddSettingValueToSection(SectionId, "BootType", "Linux"))
+        return;
+
+    /* Add the BootPath if we have one */
+    if (*BootStrings.ArcPath)
+    {
+        if (!IniAddSettingValueToSection(SectionId, "BootPath", BootStrings.ArcPath))
+            return;
+    }
+    else if (*BootStrings.Drive)
+    {
+        /* Otherwise, add the BootDrive and BootPartition */
+        if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootStrings.Drive))
+            return;
+
+        if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootStrings.Partition))
+            return;
+    }
+
+    /* Add the Kernel */
+    if (!IniAddSettingValueToSection(SectionId, "Kernel", LinuxKernelString))
+        return;
+
+    /* Add the Initrd */
+    if (*LinuxInitrdString)
+    {
+        if (!IniAddSettingValueToSection(SectionId, "Initrd", LinuxInitrdString))
+            return;
+    }
+
+    /* Add the CommandLine */
+    if (!IniAddSettingValueToSection(SectionId, "CommandLine", LinuxCommandLineString))
+        return;
+
+    OperatingSystem->SectionId = SectionId;
+    OperatingSystem->LoadIdentifier = "Custom Linux Setup";
 }
 
-VOID OptionMenuCustomBootLinux(VOID)
+#endif // _M_IX86
+
+VOID
+EditCustomBootReactOS(
+    IN OUT OperatingSystemItem* OperatingSystem,
+    IN BOOLEAN IsSetup)
+{
+    TIMEINFO* TimeInfo;
+    ULONG_PTR SectionId = OperatingSystem->SectionId;
+    CHAR SectionName[100];
+    CHAR BootDriveString[20];
+    CHAR BootPartitionString[20];
+    CHAR ReactOSSystemPath[200];
+    CHAR ReactOSARCPath[200];
+    CHAR ReactOSOptions[200];
+
+    RtlZeroMemory(SectionName, sizeof(SectionName));
+    RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
+    RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
+    RtlZeroMemory(ReactOSSystemPath, sizeof(ReactOSSystemPath));
+    RtlZeroMemory(ReactOSARCPath, sizeof(ReactOSARCPath));
+    RtlZeroMemory(ReactOSOptions, sizeof(ReactOSOptions));
+
+    if (SectionId != 0)
+    {
+        /* Load the settings */
+        IniReadSettingByName(SectionId, "SystemPath", ReactOSARCPath, sizeof(ReactOSARCPath));
+        IniReadSettingByName(SectionId, "Options", ReactOSOptions, sizeof(ReactOSOptions));
+    }
+
+    if (SectionId == 0)
+    {
+        if (!UiEditBox(BootDrivePrompt, BootDriveString, sizeof(BootDriveString)))
+            return;
+
+        if (!UiEditBox(BootPartitionPrompt, BootPartitionString, sizeof(BootPartitionString)))
+            return;
+
+        if (!UiEditBox(ReactOSSystemPathPrompt, ReactOSSystemPath, sizeof(ReactOSSystemPath)))
+            return;
+    }
+    else
+    {
+        if (!UiEditBox(ReactOSSystemPathPrompt, ReactOSARCPath, sizeof(ReactOSARCPath)))
+            return;
+    }
+
+    if (!UiEditBox(ReactOSOptionsPrompt, ReactOSOptions, sizeof(ReactOSOptions)))
+        return;
+
+    /* Modify the settings values and return if we were in edit mode */
+    if (SectionId != 0)
+    {
+        IniModifySettingValue(SectionId, "SystemPath", ReactOSARCPath);
+        IniModifySettingValue(SectionId, "Options", ReactOSOptions);
+        return;
+    }
+
+    /* Generate a unique section name */
+    TimeInfo = ArcGetTime();
+    RtlStringCbPrintfA(SectionName, sizeof(SectionName),
+                       "CustomReactOS%u%u%u%u%u%u",
+                       TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+                       TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+
+    /* Add the section */
+    if (!IniAddSection(SectionName, &SectionId))
+        return;
+
+    /* Add the BootType */
+    if (!IniAddSettingValueToSection(SectionId, "BootType", IsSetup ? "ReactOSSetup" : "Windows2003"))
+        return;
+
+    /* Construct the ReactOS ARC system path */
+    ConstructArcPath(ReactOSARCPath, ReactOSSystemPath, DriveMapGetBiosDriveNumber(BootDriveString), atoi(BootPartitionString));
+
+    /* Add the system path */
+    if (!IniAddSettingValueToSection(SectionId, "SystemPath", ReactOSARCPath))
+        return;
+
+    /* Add the CommandLine */
+    if (!IniAddSettingValueToSection(SectionId, "Options", ReactOSOptions))
+        return;
+
+    OperatingSystem->SectionId = SectionId;
+    OperatingSystem->LoadIdentifier = NULL;
+}
+
+#ifdef HAS_OPTION_MENU_REBOOT
+
+VOID OptionMenuReboot(VOID)
 {
-       CHAR    SectionName[100];
-       CHAR    BootDriveString[20];
-       CHAR    BootPartitionString[20];
-       CHAR    LinuxKernelString[200];
-       CHAR    LinuxInitrdString[200];
-       CHAR    LinuxCommandLineString[200];
-       ULONG   SectionId;
-       ULONG   Year, Month, Day, Hour, Minute, Second;
-
-       RtlZeroMemory(SectionName, sizeof(SectionName));
-       RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
-       RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
-       RtlZeroMemory(LinuxKernelString, sizeof(LinuxKernelString));
-       RtlZeroMemory(LinuxInitrdString, sizeof(LinuxInitrdString));
-       RtlZeroMemory(LinuxCommandLineString, sizeof(LinuxCommandLineString));
-
-       if (!UiEditBox(BootDrivePrompt, BootDriveString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(BootPartitionPrompt, BootPartitionString, 20))
-       {
-               return;
-       }
-
-       if (!UiEditBox(LinuxKernelPrompt, LinuxKernelString, 200))
-       {
-               return;
-       }
-
-       if (!UiEditBox(LinuxInitrdPrompt, LinuxInitrdString, 200))
-       {
-               return;
-       }
-
-       if (!UiEditBox(LinuxCommandLinePrompt, LinuxCommandLineString, 200))
-       {
-               return;
-       }
-
-       // Generate a unique section name
-       MachRTCGetCurrentDateTime(&Year, &Month, &Day, &Hour, &Minute, &Second);
-       sprintf(SectionName, "CustomLinux%ld%ld%ld%ld%ld%ld", Year, Day, Month, Hour, Minute, Second);
-
-       // Add the section
-       if (!IniAddSection(SectionName, &SectionId))
-       {
-               return;
-       }
-
-       // Add the BootType
-       if (!IniAddSettingValueToSection(SectionId, "BootType", "Linux"))
-       {
-               return;
-       }
-
-       // Add the BootDrive
-       if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
-       {
-               return;
-       }
-
-       // Add the BootPartition
-       if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootPartitionString))
-       {
-               return;
-       }
-
-       // Add the Kernel
-       if (!IniAddSettingValueToSection(SectionId, "Kernel", LinuxKernelString))
-       {
-               return;
-       }
-
-       // Add the Initrd
-       if (strlen(LinuxInitrdString) > 0)
-       {
-               if (!IniAddSettingValueToSection(SectionId, "Initrd", LinuxInitrdString))
-               {
-                       return;
-               }
-       }
-
-       // Add the CommandLine
-       if (!IniAddSettingValueToSection(SectionId, "CommandLine", LinuxCommandLineString))
-       {
-               return;
-       }
-
-       UiMessageBox(CustomBootPrompt);
-
-       LoadAndBootLinux(SectionName, "Custom Linux Setup");
+    UiMessageBox("The system will now reboot.");
+    Reboot();
 }
-#endif /* __i386__ */
+
+#endif // HAS_OPTION_MENU_REBOOT