Files
haiku-beta6/src/system/boot/platform/efi/start.cpp
T
Augustin Cavalier 0463b9511c bootloader: Refactor semantics of platform_allocate_region() functions.
This cleans up a lot of subtle or hidden inconsistencies:

 * Drop the "exactAddress" parameter. It was added in hrev15708 (2005),
   but all callers in all bootloaders passed "false" to it until 2022,
   when one codepath in the ARM32 EFI loader started using it.

 * Adjust EFI's platform_allocate_lomem to platform_allocate_region_below,
   and add a platform_assign_kernel_address_for_region(). This allows the
   aforementioned ARM EFI codepath to continue to do what it wants,
   which is to get an identity-mapped trampoline page, without having
   functions with confusingly different semantics ("allocate_lomem"
   assigned the virtual addresses as identity-mapped unconditionally,
   but it didn't insert these into the virtual allocated ranges.)

   This also paves the way for other EFI loaders to use this method
   to allocate memory below whatever default the boot services
   would give us.

 * Drop fixed virtual address allocation for all arches on EFI, with the
   exception of fixed addresses inside KERNEL_LOAD_BASE, same as on
   other boot platforms. Anything which wants fixed virtual addresses
   outside that region can use the new "assign kernel address" method.

 * Validate kernel base and size against kMaxKernelSize, instead of
   assuming it fits. This matches behavior of other boot platforms.
   Ideally we would have some more generic routine for mapping the
   kernel, but this suffices for now.

Tested with x86_64 and ARM; both still boot (well, ARM boots as
far as it did before this commit, anyway.)

Change-Id: Ieb4fba752994101191a2335cb5395eb2b726fcbb
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9024
Reviewed-by: waddlesplash <[email protected]>
2025-02-21 04:08:51 +00:00

265 lines
6.4 KiB
C++

/*
* Copyright 2014-2021 Haiku, Inc. All rights reserved.
* Copyright 2013-2014, Fredrik Holmqvist, [email protected].
* Copyright 2014, Henry Harrington, [email protected].
* All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <KernelExport.h>
#include <arch/cpu.h>
#include <arch_cpu_defs.h>
#include <kernel.h>
#include <boot/kernel_args.h>
#include <boot/platform.h>
#include <boot/stage2.h>
#include <boot/stdio.h>
#include "arch_mmu.h"
#include "arch_start.h"
#include "acpi.h"
#include "console.h"
#include "cpu.h"
#include "debug.h"
#ifdef _BOOT_FDT_SUPPORT
#include "dtb.h"
#endif
#include "efi_platform.h"
#include "mmu.h"
#include "quirks.h"
#include "serial.h"
#include "smp.h"
#include "timer.h"
extern void (*__ctor_list)(void);
extern void (*__ctor_end)(void);
const efi_system_table *kSystemTable;
const efi_boot_services *kBootServices;
const efi_runtime_services *kRuntimeServices;
efi_handle kImage;
static uint32 sBootOptions;
extern "C" int main(stage2_args *args);
extern "C" void _start(void);
extern "C" void efi_enter_kernel(uint64 pml4, uint64 entry_point, uint64 stack);
static void
call_ctors(void)
{
void (**f)(void);
for (f = &__ctor_list; f < &__ctor_end; f++)
(**f)();
}
extern "C" uint32
platform_boot_options()
{
return sBootOptions;
}
template<class T> static void
convert_preloaded_image(preloaded_image* _image)
{
T* image = static_cast<T*>(_image);
fix_address(image->next);
fix_address(image->name);
fix_address(image->debug_string_table);
fix_address(image->syms);
fix_address(image->rel);
fix_address(image->rela);
fix_address(image->pltrel);
fix_address(image->debug_symbols);
}
/*! Convert all addresses in kernel_args to virtual addresses. */
static void
convert_kernel_args()
{
fix_address(gKernelArgs.boot_volume);
fix_address(gKernelArgs.vesa_modes);
fix_address(gKernelArgs.edid_info);
fix_address(gKernelArgs.debug_output);
fix_address(gKernelArgs.boot_splash);
arch_convert_kernel_args();
if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
convert_preloaded_image<preloaded_elf64_image>(gKernelArgs.kernel_image);
} else {
convert_preloaded_image<preloaded_elf32_image>(gKernelArgs.kernel_image);
}
fix_address(gKernelArgs.kernel_image);
// Iterate over the preloaded images. Must save the next address before
// converting, as the next pointer will be converted.
preloaded_image* image = gKernelArgs.preloaded_images;
fix_address(gKernelArgs.preloaded_images);
while (image != NULL) {
preloaded_image* next = image->next;
if (image->elf_class == ELFCLASS64) {
convert_preloaded_image<preloaded_elf64_image>(image);
} else {
convert_preloaded_image<preloaded_elf32_image>(image);
}
image = next;
}
// Fix driver settings files.
driver_settings_file* file = gKernelArgs.driver_settings;
fix_address(gKernelArgs.driver_settings);
while (file != NULL) {
driver_settings_file* next = file->next;
fix_address(file->next);
fix_address(file->buffer);
file = next;
}
}
static addr_t
get_kernel_entry(void)
{
if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>(
gKernelArgs.kernel_image.Pointer());
return image->elf_header.e_entry;
} else if (gKernelArgs.kernel_image->elf_class == ELFCLASS32) {
preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
gKernelArgs.kernel_image.Pointer());
return image->elf_header.e_entry;
}
panic("Unknown kernel format! Not 32-bit or 64-bit!");
return 0;
}
static void
get_kernel_regions(addr_range& text, addr_range& data)
{
if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>(
gKernelArgs.kernel_image.Pointer());
text.start = image->text_region.start;
text.size = image->text_region.size;
data.start = image->data_region.start;
data.size = image->data_region.size;
return;
} else if (gKernelArgs.kernel_image->elf_class == ELFCLASS32) {
preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
gKernelArgs.kernel_image.Pointer());
text.start = image->text_region.start;
text.size = image->text_region.size;
data.start = image->data_region.start;
data.size = image->data_region.size;
return;
}
panic("Unknown kernel format! Not 32-bit or 64-bit!");
}
extern "C" void
platform_start_kernel(void)
{
smp_init_other_cpus();
#ifdef _BOOT_FDT_SUPPORT
dtb_set_kernel_args();
#endif
addr_t kernelEntry = get_kernel_entry();
addr_range textRegion = {.start = 0, .size = 0}, dataRegion = {.start = 0, .size = 0};
get_kernel_regions(textRegion, dataRegion);
dprintf("kernel:\n");
dprintf(" text: %#" B_PRIx64 ", %#" B_PRIx64 "\n", textRegion.start, textRegion.size);
dprintf(" data: %#" B_PRIx64 ", %#" B_PRIx64 "\n", dataRegion.start, dataRegion.size);
dprintf(" entry: %#lx\n", kernelEntry);
debug_cleanup();
arch_mmu_init();
convert_kernel_args();
// map in a kernel stack
void *stack_address = NULL;
if (platform_allocate_region(&stack_address,
KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0) != B_OK) {
panic("Unabled to allocate a stack");
}
gKernelArgs.cpu_kstack[0].start = fix_address((addr_t)stack_address);
gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE
+ KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
dprintf("Kernel stack at %#" B_PRIx64 "\n", gKernelArgs.cpu_kstack[0].start);
// Apply any weird EFI quirks
quirks_init();
// Begin architecture-centric kernel entry.
arch_start_kernel(kernelEntry);
panic("Shouldn't get here!");
}
extern "C" void
platform_exit(void)
{
kRuntimeServices->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
return;
}
/**
* efi_main - The entry point for the EFI application
* @image: firmware-allocated handle that identifies the image
* @systemTable: EFI system table
*/
extern "C" efi_status
efi_main(efi_handle image, efi_system_table *systemTable)
{
stage2_args args;
memset(&args, 0, sizeof(stage2_args));
kImage = image;
kSystemTable = systemTable;
kBootServices = systemTable->BootServices;
kRuntimeServices = systemTable->RuntimeServices;
call_ctors();
console_init();
serial_init();
serial_enable();
sBootOptions = console_check_boot_keys();
// disable apm in case we ever load a 32-bit kernel...
gKernelArgs.platform_args.apm.version = 0;
cpu_init();
acpi_init();
#ifdef _BOOT_FDT_SUPPORT
dtb_init();
#endif
timer_init();
smp_init();
main(&args);
return EFI_SUCCESS;
}