* Copyright 2014-2021 Haiku, Inc. All rights reserved.
* Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com.
* Copyright 2014, Henry Harrington, henry.harrington@gmail.com.
* 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);
}
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);
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;
}
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();
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);
quirks_init();
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();
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;
}