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]>
265 lines
6.4 KiB
C++
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;
|
|
}
|