diff --git a/base/setup/lib/bootsup.c b/base/setup/lib/bootsup.c index 047de38b3cb..030ffd6e54c 100644 --- a/base/setup/lib/bootsup.c +++ b/base/setup/lib/bootsup.c @@ -1,17 +1,19 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Setup Library - * FILE: base/setup/lib/bootsup.c - * PURPOSE: Bootloader support functions - * PROGRAMMERS: ... - * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + * PROJECT: ReactOS Setup Library + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Bootloader support functions + * COPYRIGHT: ... + * Copyright 2017-2024 Hermès Bélusca-Maïto */ /* INCLUDES *****************************************************************/ #include "precomp.h" +#include // For STORAGE_DEVICE_NUMBER + #include "bldrsup.h" +#include "devutils.h" #include "filesup.h" #include "partlist.h" #include "bootcode.h" @@ -827,11 +829,12 @@ C_ASSERT(sizeof(PARTITION_SECTOR) == SECTORSIZE); return Status; } +static NTSTATUS InstallMbrBootCodeToDisk( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PCWSTR DestinationDevicePathBuffer) + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCWSTR DestinationDevicePathBuffer) { NTSTATUS Status; WCHAR SourceMbrPathBuffer[MAX_PATH]; @@ -906,10 +909,10 @@ InstallBootloaderFiles( static NTSTATUS InstallFatBootcodeToPartition( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath, - IN PCWSTR FileSystemName) + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath, + _In_ PCWSTR FileSystemName) { NTSTATUS Status; BOOLEAN DoesFreeLdrExist; @@ -1196,9 +1199,9 @@ InstallFatBootcodeToPartition( static NTSTATUS InstallBtrfsBootcodeToPartition( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath) + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath) { NTSTATUS Status; BOOLEAN DoesFreeLdrExist; @@ -1295,9 +1298,9 @@ InstallBtrfsBootcodeToPartition( static NTSTATUS InstallNtfsBootcodeToPartition( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath) + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath) { NTSTATUS Status; BOOLEAN DoesFreeLdrExist; @@ -1389,13 +1392,13 @@ InstallNtfsBootcodeToPartition( return STATUS_SUCCESS; } - +static NTSTATUS InstallVBRToPartition( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath, - IN PCWSTR FileSystemName) + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath, + _In_ PCWSTR FileSystemName) { if (_wcsicmp(FileSystemName, L"FAT") == 0 || _wcsicmp(FileSystemName, L"FAT32") == 0) @@ -1435,74 +1438,464 @@ InstallVBRToPartition( } +/* GENERIC FUNCTIONS *********************************************************/ + +/** + * @brief + * Helper for InstallBootManagerAndBootEntries(). + * + * @param[in] ArchType + * @param[in] SystemRootPath + * See InstallBootManagerAndBootEntries() parameters. + * + * @param[in] DiskNumber + * The NT disk number of the system disk that contains the system partition. + * + * @param[in] DiskStyle + * The partitioning style of the system disk. + * + * @param[in] IsSuperFloppy + * Whether the system disk is a super-floppy. + * + * @param[in] FileSystem + * The file system of the system partition. + * + * @param[in] SourceRootPath + * @param[in] DestinationArcPath + * @param[in] Options + * See InstallBootManagerAndBootEntries() parameters. + * + * @return An NTSTATUS code indicating success or failure. + **/ +static NTSTATUS -InstallFatBootcodeToFloppy( - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath) +InstallBootManagerAndBootEntriesWorker( + _In_ ARCHITECTURE_TYPE ArchType, + _In_ PCUNICODE_STRING SystemRootPath, + _In_ ULONG DiskNumber, // const STORAGE_DEVICE_NUMBER* DeviceNumber, + _In_ PARTITION_STYLE DiskStyle, + _In_ BOOLEAN IsSuperFloppy, + _In_ PCWSTR FileSystem, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath, + _In_ ULONG_PTR Options) { - static const PCWSTR FloppyDevice = L"\\Device\\Floppy0\\"; - NTSTATUS Status; - WCHAR SrcPath[MAX_PATH]; - WCHAR DstPath[MAX_PATH]; + BOOLEAN IsBIOS = ((ArchType == ARCH_PcAT) || (ArchType == ARCH_NEC98x86)); + UCHAR InstallType = (Options & 0x03); - /* Verify that the floppy disk is accessible */ - if (DoesDirExist(NULL, FloppyDevice) == FALSE) + // FIXME: We currently only support BIOS-based PCs + // TODO: Support other platforms + if (!IsBIOS) + return STATUS_NOT_SUPPORTED; + + if (InstallType <= 1) + { + /* Step 1: Write the VBR */ + Status = InstallVBRToPartition(SystemRootPath, + SourceRootPath, + DestinationArcPath, + FileSystem); + if (!NT_SUCCESS(Status)) + { + DPRINT1("InstallVBRToPartition() failed (Status 0x%08lx)\n", Status); + return ERROR_WRITE_BOOT; // Status; STATUS_BAD_MASTER_BOOT_RECORD; + } + + /* Step 2: Write the MBR if the disk containing the + * system partition is MBR and not a super-floppy */ + if ((InstallType == 1) && (DiskStyle == PARTITION_STYLE_MBR) && !IsSuperFloppy) + { + WCHAR SystemDiskPath[MAX_PATH]; + RtlStringCchPrintfW(SystemDiskPath, _countof(SystemDiskPath), + L"\\Device\\Harddisk%d\\Partition0", + DiskNumber); + Status = InstallMbrBootCodeToDisk(SystemRootPath, + SourceRootPath, + SystemDiskPath); + if (!NT_SUCCESS(Status)) + { + DPRINT1("InstallMbrBootCodeToDisk() failed (Status 0x%08lx)\n", Status); + return ERROR_INSTALL_BOOTCODE; // Status; STATUS_BAD_MASTER_BOOT_RECORD; + } + } + } + else if (InstallType == 2) + { + WCHAR SrcPath[MAX_PATH]; + + // FIXME: We currently only support FAT12 file system. + if (_wcsicmp(FileSystem, L"FAT") != 0) + return STATUS_NOT_SUPPORTED; + + // TODO: In the future, we'll be able to use InstallVBRToPartition() + // directly, instead of re-doing manually the copy steps below. + + /* Install the bootloader to the boot partition */ + Status = InstallBootloaderFiles(SystemRootPath, SourceRootPath); + if (!NT_SUCCESS(Status)) + { + DPRINT1("InstallBootloaderFiles() failed (Status 0x%08lx)\n", Status); + return Status; + } + + /* Create new 'freeldr.ini' */ + DPRINT("Create new 'freeldr.ini'\n"); + Status = CreateFreeLoaderIniForReactOS(SystemRootPath->Buffer, DestinationArcPath->Buffer); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status 0x%08lx)\n", Status); + return Status; + } + + /* Install FAT12 bootsector */ + CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); + + DPRINT1("Install FAT12 bootcode: %S ==> %S\n", SrcPath, SystemRootPath->Buffer); + Status = InstallBootCodeToDisk(SrcPath, SystemRootPath->Buffer, InstallFat12BootCode); + if (!NT_SUCCESS(Status)) + { + DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status 0x%08lx)\n", Status); + return Status; + } + } + + return Status; +} + + +NTSTATUS +GetDeviceInfo_UStr( + _In_opt_ PCUNICODE_STRING DeviceName, + _In_opt_ HANDLE DeviceHandle, + _Out_ PFILE_FS_DEVICE_INFORMATION DeviceInfo) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + + if (DeviceName && DeviceHandle) + return STATUS_INVALID_PARAMETER_MIX; + + /* Open the device if a name has been given; + * otherwise just use the provided handle. */ + if (DeviceName) + { + Status = pOpenDeviceEx_UStr(DeviceName, &DeviceHandle, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Cannot open device '%wZ' (Status 0x%08lx)\n", + DeviceName, Status); + return Status; + } + } + + /* Query the device */ + Status = NtQueryVolumeInformationFile(DeviceHandle, + &IoStatusBlock, + DeviceInfo, + sizeof(*DeviceInfo), + FileFsDeviceInformation); + if (!NT_SUCCESS(Status)) + DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status); + + /* Close the device if we've opened it */ + if (DeviceName) + NtClose(DeviceHandle); + + return Status; +} + +NTSTATUS +GetDeviceInfo( + _In_opt_ PCWSTR DeviceName, + _In_opt_ HANDLE DeviceHandle, + _Out_ PFILE_FS_DEVICE_INFORMATION DeviceInfo) +{ + UNICODE_STRING DeviceNameU; + + if (DeviceName && DeviceHandle) + return STATUS_INVALID_PARAMETER_MIX; + + if (DeviceName) + RtlInitUnicodeString(&DeviceNameU, DeviceName); + + return GetDeviceInfo_UStr(DeviceName ? &DeviceNameU : NULL, + DeviceName ? NULL : DeviceHandle, + DeviceInfo); +} + + +/** + * @brief + * Installs FreeLoader on the system and configure the boot entries. + * + * @todo + * Split this function into just the InstallBootManager, and a separate one + * for just the boot entries. + * + * @param[in] ArchType + * The target architecture. + * + * @param[in] SystemRootPath + * The system partition path, where the FreeLdr boot manager and its + * settings are saved to. + * + * @param[in] SourceRootPath + * The installation source, where to copy the FreeLdr boot manager from. + * + * @param[in] DestinationArcPath + * The ReactOS installation path in ARC format. + * + * @param[in] Options + * For BIOS-based PCs: + * LOBYTE: + * 0: Install only on VBR; + * 1: Install on both VBR and MBR. + * 2: Install on removable disk. + * + * @return An NTSTATUS code indicating success or failure. + **/ +NTSTATUS +InstallBootManagerAndBootEntries( + _In_ ARCHITECTURE_TYPE ArchType, + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath, + _In_ ULONG_PTR Options) +{ + NTSTATUS Status; + HANDLE DeviceHandle; + FILE_FS_DEVICE_INFORMATION DeviceInfo; + ULONG DiskNumber; + PARTITION_STYLE PartitionStyle; + BOOLEAN IsSuperFloppy; + WCHAR FileSystem[MAX_PATH+1]; + + /* Remove any trailing backslash if needed */ + UNICODE_STRING RootPartition = *SystemRootPath; + TrimTrailingPathSeparators_UStr(&RootPartition); + + /* Open the volume */ + Status = pOpenDeviceEx_UStr(&RootPartition, &DeviceHandle, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Cannot open %wZ for bootloader installation (Status 0x%08lx)\n", + &RootPartition, Status); + return Status; + } + + /* Retrieve the volume file system (it will also be mounted) */ + Status = GetFileSystemName_UStr(NULL, DeviceHandle, + FileSystem, sizeof(FileSystem)); + if (!NT_SUCCESS(Status) || !*FileSystem) + { + DPRINT1("GetFileSystemName() failed (Status 0x%08lx)\n", Status); + goto Quit; + } + + /* Retrieve the device type and characteristics */ + Status = GetDeviceInfo_UStr(NULL, DeviceHandle, &DeviceInfo); + if (!NT_SUCCESS(Status)) + { + DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status); + goto Quit; + } + + /* Ignore volumes that are NOT on usual disks */ + if (DeviceInfo.DeviceType != FILE_DEVICE_DISK /*&& + DeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK*/) + { + DPRINT1("Invalid volume; device type %lu\n", DeviceInfo.DeviceType); + Status = STATUS_INVALID_DEVICE_REQUEST; + goto Quit; + } + + + /* Check whether this is a floppy or a partitionable device */ + if (DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) + { + /* Floppies don't have partitions */ + // NOTE: See ntoskrnl/io/iomgr/rawfs.c!RawQueryFsSizeInfo() + DiskNumber = ULONG_MAX; + PartitionStyle = PARTITION_STYLE_MBR; + IsSuperFloppy = TRUE; + } + else + { + IO_STATUS_BLOCK IoStatusBlock; + STORAGE_DEVICE_NUMBER DeviceNumber; + + /* The maximum information a DISK_GEOMETRY_EX dynamic structure can contain */ + typedef struct _DISK_GEOMETRY_EX_INTERNAL + { + DISK_GEOMETRY Geometry; + LARGE_INTEGER DiskSize; + DISK_PARTITION_INFO Partition; + /* Followed by: DISK_DETECTION_INFO Detection; unused here */ + } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL; + + DISK_GEOMETRY_EX_INTERNAL DiskGeoEx; + PARTITION_INFORMATION PartitionInfo; + + /* Retrieve the disk number. NOTE: Fails for floppy disks. */ + Status = NtDeviceIoControlFile(DeviceHandle, + NULL, NULL, NULL, + &IoStatusBlock, + IOCTL_STORAGE_GET_DEVICE_NUMBER, + NULL, 0, + &DeviceNumber, sizeof(DeviceNumber)); + if (!NT_SUCCESS(Status)) + goto Quit; /* This may be a dynamic volume, which is unsupported */ + ASSERT(DeviceNumber.DeviceType == DeviceInfo.DeviceType); + if (DeviceNumber.DeviceNumber == ULONG_MAX) + { + DPRINT1("Invalid disk number reported, bail out\n"); + Status = STATUS_NOT_FOUND; + goto Quit; + } + + /* Retrieve the drive geometry. NOTE: Fails for floppy disks; + * use IOCTL_DISK_GET_DRIVE_GEOMETRY instead. */ + Status = NtDeviceIoControlFile(DeviceHandle, + NULL, NULL, NULL, + &IoStatusBlock, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + NULL, 0, + &DiskGeoEx, + sizeof(DiskGeoEx)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed (Status 0x%08lx)\n", Status); + goto Quit; + } + + /* + * Retrieve the volume's partition information. + * NOTE: Fails for floppy disks. + * + * NOTE: We can use the non-EX IOCTL because the super-floppy test will + * fail anyway if the disk is NOT MBR-partitioned. (If the disk is GPT, + * the IOCTL would return only the MBR protective partition, but the + * super-floppy test would fail due to the wrong partitioning style.) + */ + Status = NtDeviceIoControlFile(DeviceHandle, + NULL, NULL, NULL, + &IoStatusBlock, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, 0, + &PartitionInfo, + sizeof(PartitionInfo)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IOCTL_DISK_GET_PARTITION_INFO failed (Status 0x%08lx)\n", Status); + goto Quit; + } + + DiskNumber = DeviceNumber.DeviceNumber; + PartitionStyle = DiskGeoEx.Partition.PartitionStyle; + IsSuperFloppy = IsDiskSuperFloppy2(&DiskGeoEx.Partition, + (PULONGLONG)&DiskGeoEx.DiskSize.QuadPart, + &PartitionInfo); + } + + Status = InstallBootManagerAndBootEntriesWorker( + ArchType, SystemRootPath, + DiskNumber, PartitionStyle, IsSuperFloppy, FileSystem, + SourceRootPath, DestinationArcPath, Options); + +Quit: + NtClose(DeviceHandle); + return Status; +} + +NTSTATUS +InstallBootcodeToRemovable( + _In_ ARCHITECTURE_TYPE ArchType, + _In_ PCUNICODE_STRING RemovableRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath) +{ + NTSTATUS Status; + FILE_FS_DEVICE_INFORMATION DeviceInfo; + PCWSTR FileSystemName; + BOOLEAN IsFloppy; + + /* Remove any trailing backslash if needed */ + UNICODE_STRING RootDrive = *RemovableRootPath; + TrimTrailingPathSeparators_UStr(&RootDrive); + + /* Verify that the removable disk is accessible */ + if (!DoesDirExist(NULL, RemovableRootPath->Buffer)) return STATUS_DEVICE_NOT_READY; - /* Format the floppy disk */ - // FormatPartition(...) - Status = FormatFileSystem(FloppyDevice, - L"FAT", - FMIFS_FLOPPY, - NULL, - TRUE, - 0, - NULL); + /* Retrieve the device type and characteristics */ + Status = GetDeviceInfo_UStr(&RootDrive, NULL, &DeviceInfo); + if (!NT_SUCCESS(Status)) + { + static const UNICODE_STRING DeviceFloppy = RTL_CONSTANT_STRING(L"\\Device\\Floppy"); + + DPRINT1("FileFsDeviceInformation failed (Status 0x%08lx)\n", Status); + + /* Definitively fail if the device is not a floppy */ + if (!RtlPrefixUnicodeString(&DeviceFloppy, &RootDrive, TRUE)) + return Status; /* We cannot cope with a failure */ + + /* Try to fall back to something "sane" if the device may be a floppy */ + DeviceInfo.DeviceType = FILE_DEVICE_DISK; + DeviceInfo.Characteristics = FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE; + } + + /* Ignore volumes that are NOT on usual disks */ + if (DeviceInfo.DeviceType != FILE_DEVICE_DISK /*&& + DeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK*/) + { + DPRINT1("Invalid volume; device type %lu\n", DeviceInfo.DeviceType); + return STATUS_INVALID_DEVICE_REQUEST; + } + + /* Fail if the disk is not removable */ + if (!(DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)) + { + DPRINT1("Device is NOT removable!\n"); + return STATUS_INVALID_DEVICE_REQUEST; + } + + /* Check whether this is a floppy or another removable device */ + IsFloppy = !!(DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE); + + /* Use FAT32, unless the device is a floppy disk */ + FileSystemName = (IsFloppy ? L"FAT" : L"FAT32"); + + /* Format the removable disk */ + Status = FormatFileSystem_UStr(&RootDrive, + FileSystemName, + (IsFloppy ? FMIFS_FLOPPY : FMIFS_REMOVABLE), + NULL, + TRUE, + 0, + NULL); if (!NT_SUCCESS(Status)) { if (Status == STATUS_NOT_SUPPORTED) - DPRINT1("FAT FS non existent on this system?!\n"); + DPRINT1("%s FS non-existent on this system!\n", FileSystemName); else - DPRINT1("VfatFormat() failed (Status %lx)\n", Status); - + DPRINT1("FormatFileSystem(%s) failed (Status 0x%08lx)\n", FileSystemName, Status); return Status; } - /* Copy FreeLoader to the boot partition */ - CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\freeldr.sys"); - CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice, L"freeldr.sys"); - - DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath); - Status = SetupCopyFile(SrcPath, DstPath, FALSE); + /* Copy FreeLoader to the removable disk and save the boot entries */ + Status = InstallBootManagerAndBootEntries(ArchType, + RemovableRootPath, + SourceRootPath, + DestinationArcPath, + 2 /* Install on removable media */); if (!NT_SUCCESS(Status)) - { - DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); - return Status; - } - - /* Create new 'freeldr.ini' */ - DPRINT("Create new 'freeldr.ini'\n"); - Status = CreateFreeLoaderIniForReactOS(FloppyDevice, DestinationArcPath->Buffer); - if (!NT_SUCCESS(Status)) - { - DPRINT1("CreateFreeLoaderIniForReactOS() failed (Status %lx)\n", Status); - return Status; - } - - /* Install FAT12 boosector */ - CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 2, SourceRootPath->Buffer, L"\\loader\\fat.bin"); - CombinePaths(DstPath, ARRAYSIZE(DstPath), 1, FloppyDevice); - - DPRINT("Install FAT12 bootcode: %S ==> %S\n", SrcPath, DstPath); - Status = InstallBootCodeToDisk(SrcPath, DstPath, InstallFat12BootCode); - if (!NT_SUCCESS(Status)) - { - DPRINT1("InstallBootCodeToDisk(FAT12) failed (Status %lx)\n", Status); - return Status; - } - - return STATUS_SUCCESS; + DPRINT1("InstallBootManagerAndBootEntries() failed (Status 0x%08lx)\n", Status); + return Status; } /* EOF */ diff --git a/base/setup/lib/bootsup.h b/base/setup/lib/bootsup.h index 3dcb2b6fd03..faacff7fbb1 100644 --- a/base/setup/lib/bootsup.h +++ b/base/setup/lib/bootsup.h @@ -1,47 +1,25 @@ /* - * ReactOS kernel - * Copyright (C) 2002 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Setup Library - * FILE: base/setup/lib/bootsup.h - * PURPOSE: Bootloader support functions - * PROGRAMMER: + * PROJECT: ReactOS Setup Library + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Bootloader support functions + * COPYRIGHT: Copyright 2017-2024 Hermès Bélusca-Maïto */ #pragma once NTSTATUS -InstallMbrBootCodeToDisk( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PCWSTR DestinationDevicePathBuffer); +InstallBootManagerAndBootEntries( + _In_ ARCHITECTURE_TYPE ArchType, + _In_ PCUNICODE_STRING SystemRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath, + _In_ ULONG_PTR Options); NTSTATUS -InstallVBRToPartition( - IN PUNICODE_STRING SystemRootPath, - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath, - IN PCWSTR FileSystemName); - -NTSTATUS -InstallFatBootcodeToFloppy( - IN PUNICODE_STRING SourceRootPath, - IN PUNICODE_STRING DestinationArcPath); +InstallBootcodeToRemovable( + _In_ ARCHITECTURE_TYPE ArchType, + _In_ PCUNICODE_STRING RemovableRootPath, + _In_ PCUNICODE_STRING SourceRootPath, + _In_ PCUNICODE_STRING DestinationArcPath); /* EOF */ diff --git a/base/setup/lib/setuplib.h b/base/setup/lib/setuplib.h index 02abdedc658..93edbebad14 100644 --- a/base/setup/lib/setuplib.h +++ b/base/setup/lib/setuplib.h @@ -40,6 +40,17 @@ extern HANDLE ProcessHeap; #include "utils/arcname.h" #include "utils/osdetect.h" #include "utils/regutil.h" + +typedef enum _ARCHITECTURE_TYPE +{ + ARCH_PcAT, //< Standard BIOS-based PC-AT + ARCH_NEC98x86, //< NEC PC-98 + ARCH_Xbox, //< Original Xbox + ARCH_Arc, //< ARC-based (MIPS, SGI) + ARCH_Efi, //< EFI and UEFI +// Place other architectures supported by the Setup below. +} ARCHITECTURE_TYPE; + #include "bootcode.h" #include "fsutil.h" #include "bootsup.h" @@ -66,16 +77,6 @@ struct _USETUP_DATA; typedef VOID (__cdecl *PSETUP_ERROR_ROUTINE)(IN struct _USETUP_DATA*, ...); -typedef enum _ARCHITECTURE_TYPE -{ - ARCH_PcAT, //< Standard BIOS-based PC-AT - ARCH_NEC98x86, //< NEC PC-98 - ARCH_Xbox, //< Original Xbox - ARCH_Arc, //< ARC-based (MIPS, SGI) - ARCH_Efi, //< EFI and UEFI -// Place other architectures supported by the Setup below. -} ARCHITECTURE_TYPE; - typedef struct _USETUP_DATA { /* Error handling *****/ diff --git a/base/setup/usetup/usetup.c b/base/setup/usetup/usetup.c index 8eb4864091a..806353223a8 100644 --- a/base/setup/usetup/usetup.c +++ b/base/setup/usetup/usetup.c @@ -3618,30 +3618,45 @@ Retry: CONSOLE_ConInKey(Ir); if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && - (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ + (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ { if (ConfirmQuit(Ir)) return FALSE; - break; } - else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ { - Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath, + // FIXME: So far USETUP only supports the 1st floppy. + static const UNICODE_STRING FloppyDrive = RTL_CONSTANT_STRING(L"\\Device\\Floppy0\\"); + Status = InstallBootcodeToRemovable(USetupData.ArchType, + &FloppyDrive, + &USetupData.SourceRootPath, &USetupData.DestinationArcPath); - if (!NT_SUCCESS(Status)) + if (Status == STATUS_SUCCESS) + return TRUE; /* Successful installation */ + + if (Status == STATUS_DEVICE_NOT_READY) { - if (Status == STATUS_DEVICE_NOT_READY) - MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER); - - /* TODO: Print error message */ - goto Retry; + MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER); } + else if (!NT_SUCCESS(Status)) + { + /* Any other NTSTATUS failure code */ + CHAR Buffer[MAX_PATH]; - return TRUE; + DPRINT1("InstallBootcodeToRemovable() failed: Status 0x%lx\n", Status); + RtlStringCbPrintfA(Buffer, sizeof(Buffer), + "Setup could not install the bootloader.\n" + "(Status 0x%08lx).\n" + "Press ENTER to continue anyway.", + Status); + PopupError(Buffer, + MUIGetString(STRING_CONTINUE), + Ir, POPUP_WAIT_ENTER); + } + goto Retry; } } - goto Retry; } @@ -3652,54 +3667,54 @@ static BOOLEAN BootLoaderHardDiskPage(PINPUT_RECORD Ir) { NTSTATUS Status; - WCHAR DestinationDevicePathBuffer[MAX_PATH]; - if (USetupData.BootLoaderLocation == 2) + /* Copy FreeLoader to the disk and save the boot entries */ + Status = InstallBootManagerAndBootEntries( + USetupData.ArchType, + &USetupData.SystemRootPath, + &USetupData.SourceRootPath, + &USetupData.DestinationArcPath, + (USetupData.BootLoaderLocation == 2) + ? 1 /* Install MBR and VBR */ + : 0 /* Install VBR only */); + if (Status == STATUS_SUCCESS) + return TRUE; /* Successful installation */ + + if (Status == ERROR_WRITE_BOOT) { - /* Step 1: Write the VBR */ - Status = InstallVBRToPartition(&USetupData.SystemRootPath, - &USetupData.SourceRootPath, - &USetupData.DestinationArcPath, - SystemVolume->Info.FileSystem); - if (!NT_SUCCESS(Status)) - { - MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, - SystemVolume->Info.FileSystem); - return FALSE; - } - - /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */ - if (!IsSuperFloppy(SystemPartition->DiskEntry)) - { - RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer), - L"\\Device\\Harddisk%d\\Partition0", - SystemPartition->DiskEntry->DiskNumber); - Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath, - &USetupData.SourceRootPath, - DestinationDevicePathBuffer); - if (!NT_SUCCESS(Status)) - { - DPRINT1("InstallMbrBootCodeToDisk() failed: Status 0x%lx\n", Status); - MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR"); - return FALSE; - } - } + /* Error when writing the VBR */ + MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, + SystemVolume->Info.FileSystem); } - else + else if (Status == ERROR_INSTALL_BOOTCODE) { - Status = InstallVBRToPartition(&USetupData.SystemRootPath, - &USetupData.SourceRootPath, - &USetupData.DestinationArcPath, - SystemVolume->Info.FileSystem); - if (!NT_SUCCESS(Status)) - { - MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, - SystemVolume->Info.FileSystem); - return FALSE; - } + /* Error when writing the MBR */ + MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR"); } + else if (Status == STATUS_NOT_SUPPORTED) + { + PopupError("Setup does not currently support installing\n" + "the bootloader on the computer you are using.\n" + "Press ENTER to continue anyway.", + MUIGetString(STRING_CONTINUE), + Ir, POPUP_WAIT_ENTER); + } + else if (!NT_SUCCESS(Status)) + { + /* Any other NTSTATUS failure code */ + CHAR Buffer[MAX_PATH]; - return TRUE; + DPRINT1("InstallBootManagerAndBootEntries() failed: Status 0x%lx\n", Status); + RtlStringCbPrintfA(Buffer, sizeof(Buffer), + "Setup could not install the bootloader.\n" + "(Status 0x%08lx).\n" + "Press ENTER to continue anyway.", + Status); + PopupError(Buffer, + MUIGetString(STRING_CONTINUE), + Ir, POPUP_WAIT_ENTER); + } + return FALSE; } /* @@ -3717,16 +3732,11 @@ BootLoaderHardDiskPage(PINPUT_RECORD Ir) static PAGE_NUMBER BootLoaderInstallPage(PINPUT_RECORD Ir) { - WCHAR PathBuffer[MAX_PATH]; - - // /* We must have a supported system partition by now */ - // ASSERT(SystemPartition && SystemPartition->IsPartitioned && SystemPartition->PartitionNumber != 0); + WCHAR PathBuffer[RTL_NUMBER_OF_FIELD(PARTENTRY, DeviceName) + 1]; RtlFreeUnicodeString(&USetupData.SystemRootPath); - RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), - L"\\Device\\Harddisk%lu\\Partition%lu\\", - SystemPartition->DiskEntry->DiskNumber, - SystemPartition->PartitionNumber); + RtlStringCchPrintfW(PathBuffer, _countof(PathBuffer), + L"%s\\", SystemPartition->DeviceName); RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer); DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath); @@ -3735,19 +3745,17 @@ BootLoaderInstallPage(PINPUT_RECORD Ir) switch (USetupData.BootLoaderLocation) { - /* Skip installation */ - case 0: - return SUCCESS_PAGE; - /* Install on removable disk */ case 1: return BootLoaderRemovableDiskPage(Ir) ? SUCCESS_PAGE : QUIT_PAGE; - /* Install on hard-disk (both MBR and VBR, or VBR only) */ - case 2: - case 3: + /* Install on hard-disk */ + case 2: // System partition / MBR and VBR (on BIOS-based PC) + case 3: // VBR only (on BIOS-based PC) return BootLoaderHardDiskPage(Ir) ? SUCCESS_PAGE : QUIT_PAGE; + /* Skip installation */ + case 0: default: return SUCCESS_PAGE; }