[FREELDR] Merge boot-drive and partition functionalities together (#6760)

And deprecate corresponding boot types "Drive" and "Partition".
These are replaced by the more general "BootSector" boot type.

Finish the unification of the code, started in commit ff85aa0c3,
that loads and boots disk MBR, partition VBR or boot sector in file.

A "WarnDeprecated()" helper is added to warn the user about the
deprecated features, and to inform them to adjust their FREELDR.INI
file in accordance.

In addition, bump FreeLoader version to 3.2 (at last!): a lot of
features have been added or deprecated since its last release.
This commit is contained in:
Hermès Bélusca-Maïto 2024-04-05 12:33:23 +02:00
parent 5949c20d97
commit 5f3554a40c
No known key found for this signature in database
GPG Key ID: 3B2539C65E7B93D0
8 changed files with 254 additions and 535 deletions

View File

@ -64,36 +64,24 @@
; DarkGray, LightBlue, LightGreen, LightCyan, LightRed, LightMagenta,
; Yellow, White, Default.
;
; Default color is the one that is being used by BIOS firmware by default.
; Default color is the one that is being used by the firmware by default.
; On PC/AT-compatible machines it's Gray, and on NEC PC-98 series it's White.
; [OS-General] Section Commands:
;
; BootType - Specifies the boot type: Windows, WindowsNT40, Windows2003,
; ReactOSSetup, Linux, BootSector, Partition, Drive
; BootType - Specifies the boot type: BootSector, Linux,
; Windows, WindowsNT40, Windows2003, ReactOSSetup.
;
; BootPath - ARC path, e.g. multi(0)disk(0)rdisk(x)partition(y)
; DriveMap - Maps a BIOS drive number to another (i.e. DriveMap=hd1,hd0
; maps harddisk1 to harddisk0; or DriveMap=fd1,fd0).
; ["Drive" OSType] Section Commands:
;
; BootDrive - BIOS drive number to be used.
;
; REMARK: If a "BootPath" ARC path is specified, its value takes precedence
; over the "BootDrive" value.
; ["Partition" OSType] Section Commands:
;
; BootDrive - BIOS drive number to be used.
; BootPartition - Partition number to be used (default: 0).
;
; REMARK: If a "BootPath" ARC path is specified, its value takes precedence
; over both the "BootDrive" and "BootPartition" values.
; DriveMap - For BIOS-based PCs, maps a BIOS drive number to another
; (i.e. DriveMap=hd1,hd0 maps hard-disk 1 to hard-disk 0;
; or DriveMap=fd1,fd0 for mapping floppy disks).
; ["BootSector" OSType] Section Commands:
;
; BootDrive - BIOS drive number to be used.
; BootPartition - Partition number to be used (cannot be 0).
; BootPartition - Partition number to be used (optional).
;
; REMARK: If a "BootPath" ARC path is specified, its value takes precedence
; over both the "BootDrive" and "BootPartition" values.
@ -102,7 +90,11 @@
; If none of them are given and a relative file path is specified by the
; "BootSectorFile" value, the default boot partition will be used instead.
;
; BootSectorFile - File name of the bootsector to be loaded.
; When a non-zero partition is specified (either via "BootPartition" or
; via the "BootPath" ARC path), the drive is accessed in partitioned mode,
; and the "BootSectorFile" option is checked for its presence.
;
; BootSectorFile - File name of the boot sector to be loaded.
; It can be either relative to "BootDrive" and "BootPartition"
; (or to "BootPath"), or be an absolute ARC path, in which case
; the "BootDrive" and "BootPartition" (or "BootPath") values
@ -195,6 +187,7 @@ SpecialEffects=Yes
[Operating Systems]
ReactOSHD="ReactOS (HardDrive)"
;ReactOS_Debug="ReactOS (Debug)"
ReactOSFloppy="ReactOS (Floppy)"
Linux="Debian Linux"
Floppy="3 1/2 Floppy (A:)"
@ -209,6 +202,13 @@ Options=/DEBUGPORT=SCREEN
Kernel=\REACTOS\SYSTEM32\NTOSKRNL.EXE
Hal=\REACTOS\SYSTEM32\HAL.DLL
;[ReactOS_Debug]
;BootType=Windows2003
;SystemPath=multi(0)disk(0)rdisk(0)partition(1)\reactos
;Options=/DEBUG /DEBUGPORT=COM1 /BAUDRATE=19200
;Kernel=\NTOSKRNL.EXE
;Hal=\HAL.DLL
; Load ReactOS from floppy (drive A:)
[ReactOSFloppy]
BootType=Windows2003
@ -217,13 +217,6 @@ Options=/DEBUGPORT=SCREEN
Kernel=\reactos\NTOSKRNL.EXE
Hal=\reactos\HAL.DLL
;[ReactOS (Debug)]
;BootType=Windows2003
;SystemPath=multi(0)disk(0)rdisk(0)partition(1)\reactos
;Options=/DEBUG /DEBUGPORT=COM1 /BAUDRATE=19200
;Kernel=\NTOSKRNL.EXE
;Hal=\HAL.DLL
[Linux]
BootType=Linux
BootPath=multi(0)disk(0)rdisk(1)partition(1)
@ -232,16 +225,16 @@ Initrd=/initrd.img
CommandLine="root=/dev/sdb1"
[Floppy]
BootType=Drive
BootType=BootSector
BootDrive=fd0
[MSWinders]
BootType=Partition
BootType=BootSector
BootPath=multi(0)disk(0)rdisk(0)partition(1)
;DriveMap=hd1,hd0
;DriveMap=hd2,hd0
;DriveMap=hd3,hd0
[DriveD]
BootType=Partition
BootType=BootSector
BootPath=multi(0)disk(0)rdisk(1)partition(1)

View File

@ -58,22 +58,48 @@ OSLoadingMethods[] =
#if defined(_M_IX86) || defined(_M_AMD64)
#ifndef UEFIBOOT
{"Drive" , EditCustomBootDisk , LoadAndBootDevice},
{"Partition" , EditCustomBootPartition , LoadAndBootDevice},
{"BootSector" , EditCustomBootSectorFile, LoadAndBootDevice},
{"Linux" , EditCustomBootLinux, LoadAndBootLinux },
{"BootSector", EditCustomBootSector, LoadAndBootSector},
{"Linux" , EditCustomBootLinux , LoadAndBootLinux },
#endif
#endif
#ifdef _M_IX86
{"WindowsNT40" , EditCustomBootNTOS , LoadAndBootWindows},
{"WindowsNT40" , EditCustomBootNTOS, LoadAndBootWindows},
#endif
{"Windows" , EditCustomBootNTOS , LoadAndBootWindows},
{"Windows2003" , EditCustomBootNTOS , LoadAndBootWindows},
{"WindowsVista", EditCustomBootNTOS , LoadAndBootWindows},
{"Windows" , EditCustomBootNTOS, LoadAndBootWindows},
{"Windows2003" , EditCustomBootNTOS, LoadAndBootWindows},
{"WindowsVista", EditCustomBootNTOS, LoadAndBootWindows},
};
/* FUNCTIONS ******************************************************************/
#ifdef HAS_DEPRECATED_OPTIONS
/**
* @brief Helper for dealing with DEPRECATED features.
**/
VOID
WarnDeprecated(
_In_ PCSTR MsgFmt,
...)
{
va_list ap;
CHAR msgString[300];
va_start(ap, MsgFmt);
RtlStringCbVPrintfA(msgString, sizeof(msgString),
MsgFmt, ap);
va_end(ap);
UiMessageBox(
" WARNING!\n"
"\n"
"%s\n"
"\n"
"Should you need assistance, please contact ReactOS developers\n"
"on the official ReactOS Mattermost server <chat.reactos.org>.",
msgString);
}
#endif // HAS_DEPRECATED_OPTIONS
static const OS_LOADING_METHOD*
GetOSLoadingMethod(
_In_ ULONG_PTR SectionId)
@ -90,11 +116,43 @@ GetOSLoadingMethod(
IniReadSettingByName(SectionId, "BootType", BootType, sizeof(BootType));
ASSERT(*BootType);
////
#ifdef HAS_DEPRECATED_OPTIONS
if ((_stricmp(BootType, "Drive") == 0) ||
(_stricmp(BootType, "Partition") == 0))
{
/* Display the deprecation warning message */
WarnDeprecated(
"The '%s' configuration you are booting into is no longer\n"
"supported and will be removed in future FreeLoader versions.\n"
"\n"
"Please edit FREELDR.INI to replace all occurrences of\n"
"\n"
" %*s to:\n"
" BootType=%s ------> BootType=BootSector",
BootType,
strlen(BootType), "", // Indentation
BootType);
/* Type fixup */
strcpy(BootType, "BootSector");
if (!IniModifySettingValue(SectionId, "BootType", BootType))
{
ERR("Could not fixup the BootType entry for OS '%s', ignoring.\n",
((PINI_SECTION)SectionId)->SectionName);
}
}
#endif // HAS_DEPRECATED_OPTIONS
////
/* Find the suitable OS loading method */
for (i = 0; ; ++i)
{
if (i >= RTL_NUMBER_OF(OSLoadingMethods))
{
UiMessageBox("Unknown boot entry type '%s'", BootType);
return NULL;
}
if (_stricmp(BootType, OSLoadingMethods[i].BootType) == 0)
return &OSLoadingMethods[i];
}

View File

@ -24,27 +24,27 @@
/* GLOBALS ********************************************************************/
#if defined(_M_IX86) || defined(_M_AMD64)
const PCSTR BootSectorFilePrompt =
static const PCSTR BootSectorFilePrompt =
"Enter the boot sector file path.\n"
"Leave blank for booting a disk or partition.\n"
"\n"
"Examples:\n"
"\\BOOTSECT.DOS\n"
"/boot/bootsect.dos";
const PCSTR LinuxKernelPrompt =
static const PCSTR LinuxKernelPrompt =
"Enter the Linux kernel image path.\n"
"\n"
"Examples:\n"
"/vmlinuz\n"
"/boot/vmlinuz-2.4.18";
const PCSTR LinuxInitrdPrompt =
static const PCSTR LinuxInitrdPrompt =
"Enter the initrd image path.\n"
"Leave blank for no initial ramdisk.\n"
"\n"
"Examples:\n"
"/initrd.gz\n"
"/boot/root.img.gz\n"
"\n"
"Leave blank for no initial ram disk.";
const PCSTR LinuxCommandLinePrompt =
"/boot/root.img.gz";
static const PCSTR LinuxCommandLinePrompt =
"Enter the Linux kernel command line.\n"
"\n"
"Examples:\n"
@ -53,7 +53,7 @@ const PCSTR LinuxCommandLinePrompt =
"root=/dev/sdb1 init=/sbin/init";
#endif /* _M_IX86 || _M_AMD64 */
const PCSTR BootDrivePrompt =
static const PCSTR BootDrivePrompt =
"Enter the boot drive.\n"
"\n"
"Examples:\n"
@ -66,25 +66,30 @@ const PCSTR BootDrivePrompt =
"0 - first floppy drive\n"
"0x80 - first hard drive\n"
"0x81 - second hard drive";
const PCSTR BootPartitionPrompt =
"Enter the boot partition.\n"
"\n"
"Enter 0 for the active (bootable) partition.";
static const PCSTR BootPartitionPrompt =
"Enter the boot partition.\n";
// "\n"
// "Enter 0 for the active (bootable) partition.";
/* NOTE: "Active"/bootable partition is a per-platform concept,
* and may not really exist. In addition, partition(0) in ARC
* means the whole disk (in non-partitioned access).
* Commit f2854a864 (r17736) and CORE-156 are thus inaccurate
* in this regard. */
const PCSTR ARCPathPrompt =
static const PCSTR ARCPathPrompt =
"Enter the boot ARC path.\n"
"\n"
"Examples:\n"
"multi(0)disk(0)rdisk(0)partition(1)\n"
"multi(0)disk(0)fdisk(0)";
const PCSTR ReactOSSystemPathPrompt =
static const PCSTR ReactOSSystemPathPrompt =
"Enter the path to your ReactOS system directory.\n"
"\n"
"Examples:\n"
"\\REACTOS\n"
"\\ROS";
const PCSTR ReactOSOptionsPrompt =
static const PCSTR ReactOSOptionsPrompt =
"Enter the load options you want passed to the kernel.\n"
"\n"
"Examples:\n"
@ -92,7 +97,7 @@ const PCSTR ReactOSOptionsPrompt =
"/FASTDETECT /SOS /NOGUIBOOT\n"
"/BASEVIDEO /MAXMEM=64\n"
"/KERNEL=NTKRNLMP.EXE /HAL=HALMPS.DLL";
const PCSTR ReactOSSetupOptionsPrompt =
static const PCSTR ReactOSSetupOptionsPrompt =
"Enter additional load options you want passed to the ReactOS Setup.\n"
"These options will supplement those obtained from the TXTSETUP.SIF\n"
"file, unless you also specify the /SIFOPTIONSOVERRIDE option switch.\n"
@ -100,7 +105,7 @@ const PCSTR ReactOSSetupOptionsPrompt =
"Example:\n"
"/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200 /NOGUIBOOT";
const PCSTR CustomBootPrompt =
static const PCSTR CustomBootPrompt =
"Press ENTER to boot your custom boot setup.";
/* FUNCTIONS ******************************************************************/
@ -111,9 +116,7 @@ VOID OptionMenuCustomBoot(VOID)
{
PCSTR CustomBootMenuList[] = {
#if defined(_M_IX86) || defined(_M_AMD64)
"Disk",
"Partition",
"Boot Sector File",
"Boot Sector (Disk/Partition/File)",
"Linux",
#endif
"ReactOS",
@ -140,22 +143,16 @@ VOID OptionMenuCustomBoot(VOID)
switch (SelectedMenuItem)
{
#if defined(_M_IX86) || defined(_M_AMD64)
case 0: // Disk
EditCustomBootDisk(&OperatingSystem);
case 0: // Boot Sector (Disk/Partition/File)
EditCustomBootSector(&OperatingSystem);
break;
case 1: // Partition
EditCustomBootPartition(&OperatingSystem);
break;
case 2: // Boot Sector File
EditCustomBootSectorFile(&OperatingSystem);
break;
case 3: // Linux
case 1: // Linux
EditCustomBootLinux(&OperatingSystem);
break;
case 4: // ReactOS
case 2: // ReactOS
EditCustomBootReactOS(&OperatingSystem, FALSE);
break;
case 5: // ReactOS Setup
case 3: // ReactOS Setup
EditCustomBootReactOS(&OperatingSystem, TRUE);
break;
#else
@ -181,103 +178,8 @@ VOID OptionMenuCustomBoot(VOID)
#if defined(_M_IX86) || defined(_M_AMD64)
VOID
EditCustomBootDisk(
IN OUT OperatingSystemItem* OperatingSystem)
{
TIMEINFO* TimeInfo;
ULONG_PTR SectionId = OperatingSystem->SectionId;
CHAR SectionName[100];
/* This construct 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
EditCustomBootPartition(
IN OUT OperatingSystemItem* OperatingSystem)
EditCustomBootSector(
_Inout_ OperatingSystemItem* OperatingSystem)
{
TIMEINFO* TimeInfo;
ULONG_PTR SectionId = OperatingSystem->SectionId;
@ -294,9 +196,11 @@ EditCustomBootPartition(
};
CHAR ArcPath[200];
} BootStrings;
CHAR BootSectorFile[200];
RtlZeroMemory(SectionName, sizeof(SectionName));
RtlZeroMemory(&BootStrings, sizeof(BootStrings));
RtlZeroMemory(BootSectorFile, sizeof(BootSectorFile));
if (SectionId != 0)
{
@ -314,6 +218,9 @@ EditCustomBootPartition(
IniReadSettingByName(SectionId, "BootDrive", BootStrings.Drive, sizeof(BootStrings.Drive));
IniReadSettingByName(SectionId, "BootPartition", BootStrings.Partition, sizeof(BootStrings.Partition));
}
/* Always load the file name; it will only be handled later if a partition has been specified */
IniReadSettingByName(SectionId, "BootSectorFile", BootSectorFile, sizeof(BootSectorFile));
}
if (!*BootStrings.ArcPath)
@ -333,122 +240,15 @@ EditCustomBootPartition(
return;
}
/* Modify the settings values and return if we were in edit mode */
if (SectionId != 0)
/* Edit the file name only if a partition has been specified */
if ((!*BootStrings.ArcPath && atoi(BootStrings.Partition) != 0) ||
(*BootStrings.ArcPath && !strstr(BootStrings.ArcPath, ")partition()") &&
!strstr(BootStrings.ArcPath, ")partition(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))
if (!UiEditBox(BootSectorFilePrompt, BootSectorFile, sizeof(BootSectorFile)))
return;
}
OperatingSystem->SectionId = SectionId;
OperatingSystem->LoadIdentifier = NULL;
}
VOID
EditCustomBootSectorFile(
IN OUT OperatingSystemItem* OperatingSystem)
{
TIMEINFO* TimeInfo;
ULONG_PTR SectionId = OperatingSystem->SectionId;
CHAR SectionName[100];
/* This construct 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)
@ -467,22 +267,23 @@ EditCustomBootSectorFile(
else
{
/*
* Otherwise, zero out all values: BootSectorFile will be
* relative to the default system partition.
* Otherwise, reset all values: BootSectorFile
* will be relative to the default system partition.
*/
IniModifySettingValue(SectionId, "BootPath", "");
IniModifySettingValue(SectionId, "BootDrive", "");
IniModifySettingValue(SectionId, "BootPartition", "");
}
IniModifySettingValue(SectionId, "BootSectorFile", BootSectorFileString);
/* Always write back the file name */
IniModifySettingValue(SectionId, "BootSectorFile", BootSectorFile);
return;
}
/* Generate a unique section name */
TimeInfo = ArcGetTime();
RtlStringCbPrintfA(SectionName, sizeof(SectionName),
"CustomBootSectorFile%u%u%u%u%u%u",
"CustomBootSector%u%u%u%u%u%u",
TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
@ -510,9 +311,12 @@ EditCustomBootSectorFile(
return;
}
/* Add the BootSectorFile */
if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", BootSectorFileString))
return;
/* Add the BootSectorFile if any */
if (*BootSectorFile)
{
if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", BootSectorFile))
return;
}
OperatingSystem->SectionId = SectionId;
OperatingSystem->LoadIdentifier = NULL;
@ -612,8 +416,8 @@ EditCustomBootLinux(
else
{
/*
* Otherwise, zero out all values: BootSectorFile will be
* relative to the default system partition.
* Otherwise, reset all values: the files will
* be relative to the default system partition.
*/
IniModifySettingValue(SectionId, "BootPath", "");
IniModifySettingValue(SectionId, "BootDrive", "");

View File

@ -30,16 +30,8 @@ VOID OptionMenuCustomBoot(VOID);
#if defined(_M_IX86) || defined(_M_AMD64)
VOID
EditCustomBootDisk(
IN OUT OperatingSystemItem* OperatingSystem);
VOID
EditCustomBootPartition(
IN OUT OperatingSystemItem* OperatingSystem);
VOID
EditCustomBootSectorFile(
IN OUT OperatingSystemItem* OperatingSystem);
EditCustomBootSector(
_Inout_ OperatingSystemItem* OperatingSystem);
VOID
EditCustomBootLinux(

View File

@ -20,6 +20,10 @@
#ifndef __FREELDR_H
#define __FREELDR_H
/* Enabled for supporting the deprecated boot options
* that will be removed in a future FreeLdr version */
#define HAS_DEPRECATED_OPTIONS
#define UINT64_C(val) val##ULL
#define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
@ -126,6 +130,13 @@
VOID __cdecl BootMain(IN PCCH CmdLine);
#ifdef HAS_DEPRECATED_OPTIONS
VOID
WarnDeprecated(
_In_ PCSTR MsgFmt,
...);
#endif
VOID
LoadOperatingSystem(
_In_ OperatingSystemItem* OperatingSystem);

View File

@ -22,9 +22,9 @@
#if defined(_M_IX86) || defined(_M_AMD64)
ARC_STATUS
LoadAndBootDevice(
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR Envp[]);
LoadAndBootSector(
_In_ ULONG Argc,
_In_ PCHAR Argv[],
_In_ PCHAR Envp[]);
#endif /* _M_IX86 || _M_AMD64 */

View File

@ -20,7 +20,7 @@
#pragma once
/* Just some stuff */
#define VERSION "FreeLoader v3.0"
#define VERSION "FreeLoader v3.2"
#define COPYRIGHT "Copyright (C) 1996-" COPYRIGHT_YEAR " ReactOS Project"
#define AUTHOR_EMAIL "<www.reactos.org>"
#define BY_AUTHOR "by ReactOS Project"
@ -33,7 +33,7 @@
// If you add major functionality then you increment the major version and zero the minor & patch versions
//
#define FREELOADER_MAJOR_VERSION 3
#define FREELOADER_MINOR_VERSION 0
#define FREELOADER_MINOR_VERSION 2
#define FREELOADER_PATCH_VERSION 0
extern const PCSTR FrLdrVersionString;

View File

@ -23,26 +23,44 @@
#include <freeldr.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(DISK);
/* FUNCTIONS ******************************************************************/
static ARC_STATUS
LoadBootSector(
IN ULONG Argc,
IN PCHAR Argv[],
OUT PUCHAR DriveNumber,
OUT PULONG PartitionNumber)
/**
* @brief
* Loads and boots a disk MBR, a partition VBR or a file boot sector.
**/
ARC_STATUS
LoadAndBootSector(
_In_ ULONG Argc,
_In_ PCHAR Argv[],
_In_ PCHAR Envp[])
{
ARC_STATUS Status;
PCSTR ArgValue;
PCSTR BootPath;
PCSTR FileName;
UCHAR BiosDriveNumber = 0;
ULONG PartitionNumber = 0;
ULONG LoadAddress;
ULONG FileId;
ULONG BytesRead;
CHAR ArcPath[MAX_PATH];
ULONG LoadAddress;
*DriveNumber = 0;
*PartitionNumber = 0;
#if DBG
/* Ensure the boot type is the one expected */
ArgValue = GetArgumentValue(Argc, Argv, "BootType");
if (!ArgValue || !*ArgValue || _stricmp(ArgValue, "BootSector") != 0)
{
ERR("Unexpected boot type '%s', aborting\n", ArgValue ? ArgValue : "n/a");
return EINVAL;
}
#endif
/* Find all the message box settings and run them */
UiShowMessageBoxesInArgv(Argc, Argv);
/*
* Check whether we have a "BootPath" value (takes precedence
@ -57,24 +75,13 @@ LoadBootSector(
ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
if (ArgValue && *ArgValue)
{
*DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
BiosDriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
/* Retrieve the boot partition (not optional and cannot be zero) */
*PartitionNumber = 0;
/* Retrieve the boot partition (optional, fall back to zero otherwise) */
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;
PartitionNumber = atoi(ArgValue);
}
else
{
@ -83,268 +90,122 @@ LoadBootSector(
}
}
/* Retrieve the file name */
FileName = GetArgumentValue(Argc, Argv, "BootSectorFile");
if (!FileName || !*FileName)
{
UiMessageBox("Boot sector file not specified for selected OS!");
return EINVAL;
}
/* Open the boot sector file */
Status = FsOpenFile(FileName, BootPath, OpenReadOnly, &FileId);
if (Status != ESUCCESS)
{
UiMessageBox("Unable to open %s", FileName);
return Status;
}
#if defined(SARCH_PC98)
LoadAddress = Pc98GetBootSectorLoadAddress(*DriveNumber);
#else
LoadAddress = 0x7C00;
#endif
/* Now try to load the boot sector. If this fails then abort. */
Status = ArcRead(FileId, UlongToPtr(LoadAddress), 512, &BytesRead);
ArcClose(FileId);
if ((Status != ESUCCESS) || (BytesRead != 512))
{
UiMessageBox("Unable to load boot sector.");
return EIO;
}
/* Check for validity */
if (*(USHORT*)UlongToPtr(LoadAddress + 0x1FE) != 0xAA55)
{
UiMessageBox("Invalid boot sector magic (0xaa55)");
return ENOEXEC;
}
/* Reset the drive and partition numbers so as to use their default values */
*DriveNumber = 0;
*PartitionNumber = 0;
return ESUCCESS;
}
static ARC_STATUS
LoadPartitionOrDrive(
IN OUT PUCHAR DriveNumber,
IN OUT PULONG PartitionNumber,
IN PCSTR BootPath OPTIONAL)
{
ARC_STATUS Status;
ULONG FileId;
ULONG BytesRead;
CHAR ArcPath[MAX_PATH];
ULONG LoadAddress;
/*
* The ARC "BootPath" value takes precedence over
* both the DriveNumber and PartitionNumber options.
* both the BiosDriveNumber and PartitionNumber options.
*/
if (BootPath && *BootPath)
{
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 = NULL;
if (!DissectArcPath(BootPath, &FileName, &BiosDriveNumber, &PartitionNumber) ||
(FileName && *FileName))
{
UiMessageBox("Currently unsupported BootPath value:\n%s", BootPath);
return EINVAL;
}
}
else
{
/* We don't have one, so construct the corresponding ARC path */
ConstructArcPath(ArcPath, "", *DriveNumber, *PartitionNumber);
ConstructArcPath(ArcPath, "", BiosDriveNumber, PartitionNumber);
*strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
BootPath = ArcPath;
}
/* Open the volume */
Status = ArcOpen((PSTR)BootPath, OpenReadOnly, &FileId);
FileName = NULL;
if (strstr(BootPath, ")partition()") || strstr(BootPath, ")partition(0)"))
{
/*
* The partition specifier is zero i.e. the device is accessed
* in an unpartitioned fashion, do not retrieve a file name.
*
* NOTE: If we access a floppy drive, we would not have a
* partition specifier, and PartitionNumber would be == 0,
* so don't check explicitly for PartitionNumber because
* we want to retrieve a file name.
*/
}
else
{
/* Retrieve the file name, if any, and normalize
* the pointer to make subsequent tests simpler */
FileName = GetArgumentValue(Argc, Argv, "BootSectorFile");
if (FileName && !*FileName)
FileName = NULL;
}
/* If we load a boot sector file, reset the drive number
* so as to use the original boot drive/partition */
if (FileName)
BiosDriveNumber = 0;
if (!BiosDriveNumber)
{
BiosDriveNumber = FrldrBootDrive;
PartitionNumber = FrldrBootPartition;
}
/* Open the boot sector file or the volume */
if (FileName)
Status = FsOpenFile(FileName, BootPath, OpenReadOnly, &FileId);
else
Status = ArcOpen((PSTR)BootPath, OpenReadOnly, &FileId);
if (Status != ESUCCESS)
{
UiMessageBox("Unable to open %s", BootPath);
UiMessageBox("Unable to open %s", FileName ? FileName : BootPath);
return Status;
}
#if defined(SARCH_PC98)
LoadAddress = Pc98GetBootSectorLoadAddress(*DriveNumber);
LoadAddress = Pc98GetBootSectorLoadAddress(BiosDriveNumber);
#else
LoadAddress = 0x7C00;
#endif
/*
* Now try to load the partition boot sector or the MBR (when PartitionNumber == 0).
* If this fails then abort.
* Now try to load the boot sector: disk MBR (when PartitionNumber == 0),
* partition VBR or boot sector file. If this fails, abort.
*/
Status = ArcRead(FileId, UlongToPtr(LoadAddress), 512, &BytesRead);
ArcClose(FileId);
if ((Status != ESUCCESS) || (BytesRead != 512))
{
if (*PartitionNumber != 0)
UiMessageBox("Unable to load partition's boot sector.");
PCSTR WhatFailed;
if (FileName)
WhatFailed = "boot sector file";
else if (PartitionNumber != 0)
WhatFailed = "partition's boot sector";
else
UiMessageBox("Unable to load MBR boot sector.");
WhatFailed = "MBR boot sector";
UiMessageBox("Unable to load %s.", WhatFailed);
return EIO;
}
/* Check for validity */
if (*(USHORT*)UlongToPtr(LoadAddress + 0x1FE) != 0xAA55)
{
UiMessageBox("Invalid boot sector magic (0xaa55)");
UiMessageBox("Invalid boot sector magic (0xAA55)");
return ENOEXEC;
}
return ESUCCESS;
}
static ARC_STATUS
LoadPartition(
IN ULONG Argc,
IN PCHAR Argv[],
OUT PUCHAR DriveNumber,
OUT PULONG PartitionNumber)
{
PCSTR ArgValue;
PCSTR BootPath;
*DriveNumber = 0;
*PartitionNumber = 0;
/*
* 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 */
/* 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);
}
return LoadPartitionOrDrive(DriveNumber, PartitionNumber, BootPath);
}
static ARC_STATUS
LoadDrive(
IN ULONG Argc,
IN PCHAR Argv[],
OUT PUCHAR DriveNumber,
OUT PULONG PartitionNumber)
{
PCSTR ArgValue;
PCSTR BootPath;
*DriveNumber = 0;
*PartitionNumber = 0;
/* Check whether we have a "BootPath" value (takes precedence over "BootDrive") */
BootPath = GetArgumentValue(Argc, Argv, "BootPath");
if (BootPath && *BootPath)
{
/*
* 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);
}
return LoadPartitionOrDrive(DriveNumber, PartitionNumber, BootPath);
}
ARC_STATUS
LoadAndBootDevice(
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR Envp[])
{
ARC_STATUS Status;
PCSTR ArgValue;
UCHAR Type;
UCHAR DriveNumber = 0;
ULONG PartitionNumber = 0;
/* Retrieve the (mandatory) boot type */
ArgValue = GetArgumentValue(Argc, Argv, "BootType");
if (!ArgValue || !*ArgValue)
return EINVAL;
if (_stricmp(ArgValue, "Drive") == 0)
Type = 1;
else if (_stricmp(ArgValue, "Partition") == 0)
Type = 2;
else if (_stricmp(ArgValue, "BootSector") == 0)
Type = 3;
else
return EINVAL;
/* Find all the message box settings and run them */
UiShowMessageBoxesInArgv(Argc, Argv);
/* Load the corresponding device */
switch (Type)
{
case 1:
Status = LoadDrive(Argc, Argv, &DriveNumber, &PartitionNumber);
break;
case 2:
Status = LoadPartition(Argc, Argv, &DriveNumber, &PartitionNumber);
break;
case 3:
Status = LoadBootSector(Argc, Argv, &DriveNumber, &PartitionNumber);
break;
default:
return EINVAL;
}
if (Status != ESUCCESS)
return Status;
UiUnInitialize("Booting...");
IniCleanup();
#ifndef UEFIBOOT
/* Boot the loaded sector code */
ChainLoadBiosBootSectorCode(DriveNumber, PartitionNumber);
ChainLoadBiosBootSectorCode(BiosDriveNumber, PartitionNumber);
#endif
/* Must not return! */
return ESUCCESS;
}
#endif /* _M_IX86 || _M_AMD64 */
/* EOF */