1735f1daeSFredrik Holmqvist /* 2735f1daeSFredrik Holmqvist * Copyright 2014-2016 Haiku, Inc. All rights reserved. 3b3215a62SHenry Harrington * Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com. 4b3215a62SHenry Harrington * Copyright 2014, Henry Harrington, henry.harrington@gmail.com. 5b3215a62SHenry Harrington * All rights reserved. 647a21c5cSAugustin Cavalier * Distributed under the terms of the MIT License. 7735f1daeSFredrik Holmqvist */ 8735f1daeSFredrik Holmqvist 9735f1daeSFredrik Holmqvist 10b3215a62SHenry Harrington #include <string.h> 11b3215a62SHenry Harrington 12b3215a62SHenry Harrington #include <KernelExport.h> 13b3215a62SHenry Harrington 14b3215a62SHenry Harrington #include <arch/cpu.h> 157b4d924fSAndrej Antunovikj #include <kernel.h> 167b4d924fSAndrej Antunovikj 177b4d924fSAndrej Antunovikj #include <boot/arch/x86/arch_cpu.h> 186e6efaecSJessica Hamilton #include <boot/kernel_args.h> 19e2e1558aSJessica Hamilton #include <boot/platform.h> 20e2e1558aSJessica Hamilton #include <boot/stage2.h> 21e2e1558aSJessica Hamilton #include <boot/stdio.h> 22735f1daeSFredrik Holmqvist 237c32619cSAlexander von Gluck IV #include "arch_mmu.h" 246e6efaecSJessica Hamilton #include "acpi.h" 25735f1daeSFredrik Holmqvist #include "console.h" 26735f1daeSFredrik Holmqvist #include "efi_platform.h" 27b3215a62SHenry Harrington #include "mmu.h" 28*d38ba84dSAlexander von Gluck IV #include "quirks.h" 299e487d8dSFredrik Holmqvist #include "serial.h" 30a99a0c00SNick Smallbone #include "smp.h" 31b482adb1SAlexander von Gluck IV #include "timer.h" 32735f1daeSFredrik Holmqvist 33735f1daeSFredrik Holmqvist 34735f1daeSFredrik Holmqvist extern void (*__ctor_list)(void); 35735f1daeSFredrik Holmqvist extern void (*__ctor_end)(void); 36735f1daeSFredrik Holmqvist 37735f1daeSFredrik Holmqvist 38485b5cf8SAlexander von Gluck IV const efi_system_table *kSystemTable; 39485b5cf8SAlexander von Gluck IV const efi_boot_services *kBootServices; 40485b5cf8SAlexander von Gluck IV const efi_runtime_services *kRuntimeServices; 41485b5cf8SAlexander von Gluck IV efi_handle kImage; 42b3215a62SHenry Harrington 43735f1daeSFredrik Holmqvist 4496f4d68bSJessica Hamilton static uint32 sBootOptions; 45b3215a62SHenry Harrington static uint64 gLongKernelEntry; 46b3215a62SHenry Harrington 47b3215a62SHenry Harrington 48b3215a62SHenry Harrington extern "C" int main(stage2_args *args); 49b3215a62SHenry Harrington extern "C" void _start(void); 50b3215a62SHenry Harrington extern "C" void efi_enter_kernel(uint64 pml4, uint64 entry_point, uint64 stack); 5196f4d68bSJessica Hamilton 52735f1daeSFredrik Holmqvist 53735f1daeSFredrik Holmqvist static void 54735f1daeSFredrik Holmqvist call_ctors(void) 55735f1daeSFredrik Holmqvist { 56735f1daeSFredrik Holmqvist void (**f)(void); 57735f1daeSFredrik Holmqvist 58735f1daeSFredrik Holmqvist for (f = &__ctor_list; f < &__ctor_end; f++) 59735f1daeSFredrik Holmqvist (**f)(); 60735f1daeSFredrik Holmqvist } 61735f1daeSFredrik Holmqvist 62735f1daeSFredrik Holmqvist 63e2e1558aSJessica Hamilton extern "C" uint32 64e2e1558aSJessica Hamilton platform_boot_options() 65e2e1558aSJessica Hamilton { 6696f4d68bSJessica Hamilton return sBootOptions; 67e2e1558aSJessica Hamilton } 68e2e1558aSJessica Hamilton 69e2e1558aSJessica Hamilton 70b3215a62SHenry Harrington static void 71b3215a62SHenry Harrington convert_preloaded_image(preloaded_elf64_image* image) 72b3215a62SHenry Harrington { 73b3215a62SHenry Harrington fix_address(image->next); 74b3215a62SHenry Harrington fix_address(image->name); 75b3215a62SHenry Harrington fix_address(image->debug_string_table); 76b3215a62SHenry Harrington fix_address(image->syms); 77b3215a62SHenry Harrington fix_address(image->rel); 78b3215a62SHenry Harrington fix_address(image->rela); 79b3215a62SHenry Harrington fix_address(image->pltrel); 80b3215a62SHenry Harrington fix_address(image->debug_symbols); 81b3215a62SHenry Harrington } 82b3215a62SHenry Harrington 83b3215a62SHenry Harrington 84b3215a62SHenry Harrington /*! Convert all addresses in kernel_args to 64-bit addresses. */ 85b3215a62SHenry Harrington static void 86b3215a62SHenry Harrington convert_kernel_args() 87b3215a62SHenry Harrington { 88b3215a62SHenry Harrington fix_address(gKernelArgs.boot_volume); 89b3215a62SHenry Harrington fix_address(gKernelArgs.vesa_modes); 90b3215a62SHenry Harrington fix_address(gKernelArgs.edid_info); 91b3215a62SHenry Harrington fix_address(gKernelArgs.debug_output); 92b3215a62SHenry Harrington fix_address(gKernelArgs.boot_splash); 93b482adb1SAlexander von Gluck IV #if defined(__x86_64__) || defined(__x86__) 94b3215a62SHenry Harrington fix_address(gKernelArgs.arch_args.apic); 95b3215a62SHenry Harrington fix_address(gKernelArgs.arch_args.hpet); 96b482adb1SAlexander von Gluck IV #endif 97b3215a62SHenry Harrington 98b3215a62SHenry Harrington convert_preloaded_image(static_cast<preloaded_elf64_image*>( 99b3215a62SHenry Harrington gKernelArgs.kernel_image.Pointer())); 100b3215a62SHenry Harrington fix_address(gKernelArgs.kernel_image); 101b3215a62SHenry Harrington 102b3215a62SHenry Harrington // Iterate over the preloaded images. Must save the next address before 103b3215a62SHenry Harrington // converting, as the next pointer will be converted. 104b3215a62SHenry Harrington preloaded_image* image = gKernelArgs.preloaded_images; 105b3215a62SHenry Harrington fix_address(gKernelArgs.preloaded_images); 106b3215a62SHenry Harrington while (image != NULL) { 107b3215a62SHenry Harrington preloaded_image* next = image->next; 108b3215a62SHenry Harrington convert_preloaded_image(static_cast<preloaded_elf64_image*>(image)); 109b3215a62SHenry Harrington image = next; 110b3215a62SHenry Harrington } 111b3215a62SHenry Harrington 112b3215a62SHenry Harrington // Fix driver settings files. 113b3215a62SHenry Harrington driver_settings_file* file = gKernelArgs.driver_settings; 114b3215a62SHenry Harrington fix_address(gKernelArgs.driver_settings); 115b3215a62SHenry Harrington while (file != NULL) { 116b3215a62SHenry Harrington driver_settings_file* next = file->next; 117b3215a62SHenry Harrington fix_address(file->next); 118b3215a62SHenry Harrington fix_address(file->buffer); 119b3215a62SHenry Harrington file = next; 120b3215a62SHenry Harrington } 121b3215a62SHenry Harrington } 122b3215a62SHenry Harrington 123b3215a62SHenry Harrington 124e2e1558aSJessica Hamilton extern "C" void 125e2e1558aSJessica Hamilton platform_start_kernel(void) 126e2e1558aSJessica Hamilton { 127b3215a62SHenry Harrington if (gKernelArgs.kernel_image->elf_class != ELFCLASS64) 128b3215a62SHenry Harrington panic("32-bit kernels not supported with EFI"); 129b3215a62SHenry Harrington 130a99a0c00SNick Smallbone smp_init_other_cpus(); 131ec239abcSJessica Hamilton 132b3215a62SHenry Harrington preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>( 133b3215a62SHenry Harrington gKernelArgs.kernel_image.Pointer()); 134b3215a62SHenry Harrington 1357c32619cSAlexander von Gluck IV arch_mmu_init(); 136b3215a62SHenry Harrington convert_kernel_args(); 137b3215a62SHenry Harrington 138b3215a62SHenry Harrington // Save the kernel entry point address. 139b3215a62SHenry Harrington gLongKernelEntry = image->elf_header.e_entry; 140b3215a62SHenry Harrington dprintf("kernel entry at %#lx\n", gLongKernelEntry); 141b3215a62SHenry Harrington 142b3215a62SHenry Harrington // map in a kernel stack 143b3215a62SHenry Harrington void *stack_address = NULL; 144485b5cf8SAlexander von Gluck IV if (platform_allocate_region(&stack_address, 145485b5cf8SAlexander von Gluck IV KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0, false) 146485b5cf8SAlexander von Gluck IV != B_OK) { 147b3215a62SHenry Harrington panic("Unabled to allocate a stack"); 148b3215a62SHenry Harrington } 149b3215a62SHenry Harrington gKernelArgs.cpu_kstack[0].start = fix_address((uint64_t)stack_address); 150485b5cf8SAlexander von Gluck IV gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE 151485b5cf8SAlexander von Gluck IV + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; 152b3215a62SHenry Harrington dprintf("Kernel stack at %#lx\n", gKernelArgs.cpu_kstack[0].start); 153b3215a62SHenry Harrington 154*d38ba84dSAlexander von Gluck IV // Apply any weird EFI quirks 155*d38ba84dSAlexander von Gluck IV quirks_init(); 156*d38ba84dSAlexander von Gluck IV 157b3215a62SHenry Harrington // Prepare to exit EFI boot services. 158b3215a62SHenry Harrington // Read the memory map. 159b3215a62SHenry Harrington // First call is to determine the buffer size. 160485b5cf8SAlexander von Gluck IV size_t memory_map_size = 0; 161485b5cf8SAlexander von Gluck IV efi_memory_descriptor dummy; 162485b5cf8SAlexander von Gluck IV efi_memory_descriptor *memory_map; 163485b5cf8SAlexander von Gluck IV size_t map_key; 164485b5cf8SAlexander von Gluck IV size_t descriptor_size; 165485b5cf8SAlexander von Gluck IV uint32_t descriptor_version; 166485b5cf8SAlexander von Gluck IV if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, 167485b5cf8SAlexander von Gluck IV &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { 168b3215a62SHenry Harrington panic("Unable to determine size of system memory map"); 169b3215a62SHenry Harrington } 170b3215a62SHenry Harrington 171b3215a62SHenry Harrington // Allocate a buffer twice as large as needed just in case it gets bigger between 172b3215a62SHenry Harrington // calls to ExitBootServices. 173485b5cf8SAlexander von Gluck IV size_t actual_memory_map_size = memory_map_size * 2; 174485b5cf8SAlexander von Gluck IV memory_map 175485b5cf8SAlexander von Gluck IV = (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size); 176485b5cf8SAlexander von Gluck IV 177b3215a62SHenry Harrington if (memory_map == NULL) 178b3215a62SHenry Harrington panic("Unable to allocate memory map."); 179b3215a62SHenry Harrington 180b3215a62SHenry Harrington // Read (and print) the memory map. 181b3215a62SHenry Harrington memory_map_size = actual_memory_map_size; 182485b5cf8SAlexander von Gluck IV if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 183485b5cf8SAlexander von Gluck IV &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 184b3215a62SHenry Harrington panic("Unable to fetch system memory map."); 185b3215a62SHenry Harrington } 186b3215a62SHenry Harrington 187b3215a62SHenry Harrington addr_t addr = (addr_t)memory_map; 188b3215a62SHenry Harrington dprintf("System provided memory map:\n"); 189485b5cf8SAlexander von Gluck IV for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { 190485b5cf8SAlexander von Gluck IV efi_memory_descriptor *entry 191485b5cf8SAlexander von Gluck IV = (efi_memory_descriptor *)(addr + i * descriptor_size); 192485b5cf8SAlexander von Gluck IV dprintf(" %#lx-%#lx %#lx %#x %#lx\n", entry->PhysicalStart, 193485b5cf8SAlexander von Gluck IV entry->PhysicalStart + entry->NumberOfPages * 4096, 194b3215a62SHenry Harrington entry->VirtualStart, entry->Type, entry->Attribute); 195b3215a62SHenry Harrington } 196b3215a62SHenry Harrington 197b3215a62SHenry Harrington // Generate page tables for use after ExitBootServices. 198485b5cf8SAlexander von Gluck IV uint64_t final_pml4 = mmu_generate_post_efi_page_tables(memory_map_size, 199485b5cf8SAlexander von Gluck IV memory_map, descriptor_size, descriptor_version); 200b3215a62SHenry Harrington dprintf("Final PML4 at %#lx\n", final_pml4); 201b3215a62SHenry Harrington 202b3215a62SHenry Harrington // Attempt to fetch the memory map and exit boot services. 203b3215a62SHenry Harrington // This needs to be done in a loop, as ExitBootServices can change the 204b3215a62SHenry Harrington // memory map. 205b3215a62SHenry Harrington // Even better: Only GetMemoryMap and ExitBootServices can be called after 206b3215a62SHenry Harrington // the first call to ExitBootServices, as the firmware is permitted to 207b3215a62SHenry Harrington // partially exit. This is why twice as much space was allocated for the 208b3215a62SHenry Harrington // memory map, as it's impossible to allocate more now. 209b3215a62SHenry Harrington // A changing memory map shouldn't affect the generated page tables, as 210b3215a62SHenry Harrington // they only needed to know about the maximum address, not any specific 211b3215a62SHenry Harrington // entry. 212b3215a62SHenry Harrington dprintf("Calling ExitBootServices. So long, EFI!\n"); 213b3215a62SHenry Harrington while (true) { 214b3215a62SHenry Harrington if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { 2159e487d8dSFredrik Holmqvist // The console was provided by boot services, disable it. 2169e487d8dSFredrik Holmqvist stdout = NULL; 2179e487d8dSFredrik Holmqvist stderr = NULL; 2189e487d8dSFredrik Holmqvist // Also switch to legacy serial output (may not work on all systems) 2199e487d8dSFredrik Holmqvist serial_switch_to_legacy(); 2209e487d8dSFredrik Holmqvist dprintf("Switched to legacy serial output\n"); 221b3215a62SHenry Harrington break; 222b3215a62SHenry Harrington } 223b3215a62SHenry Harrington 224b3215a62SHenry Harrington memory_map_size = actual_memory_map_size; 225485b5cf8SAlexander von Gluck IV if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 226485b5cf8SAlexander von Gluck IV &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 227b3215a62SHenry Harrington panic("Unable to fetch system memory map."); 228b3215a62SHenry Harrington } 229b3215a62SHenry Harrington } 230b3215a62SHenry Harrington 231b3215a62SHenry Harrington // Update EFI, generate final kernel physical memory map, etc. 232485b5cf8SAlexander von Gluck IV mmu_post_efi_setup(memory_map_size, memory_map, 233485b5cf8SAlexander von Gluck IV descriptor_size, descriptor_version); 234b3215a62SHenry Harrington 2357c32619cSAlexander von Gluck IV smp_boot_other_cpus(final_pml4, gLongKernelEntry); 236a99a0c00SNick Smallbone 237b3215a62SHenry Harrington // Enter the kernel! 238485b5cf8SAlexander von Gluck IV efi_enter_kernel(final_pml4, gLongKernelEntry, 239b3215a62SHenry Harrington gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); 240b3215a62SHenry Harrington 241b3215a62SHenry Harrington panic("Shouldn't get here"); 242e2e1558aSJessica Hamilton } 243e2e1558aSJessica Hamilton 244e2e1558aSJessica Hamilton 245e2e1558aSJessica Hamilton extern "C" void 246e2e1558aSJessica Hamilton platform_exit(void) 247e2e1558aSJessica Hamilton { 248e2e1558aSJessica Hamilton return; 249e2e1558aSJessica Hamilton } 250e2e1558aSJessica Hamilton 251e2e1558aSJessica Hamilton 252735f1daeSFredrik Holmqvist /** 253735f1daeSFredrik Holmqvist * efi_main - The entry point for the EFI application 254735f1daeSFredrik Holmqvist * @image: firmware-allocated handle that identifies the image 255735f1daeSFredrik Holmqvist * @systemTable: EFI system table 256735f1daeSFredrik Holmqvist */ 257485b5cf8SAlexander von Gluck IV extern "C" efi_status 258485b5cf8SAlexander von Gluck IV efi_main(efi_handle image, efi_system_table *systemTable) 259735f1daeSFredrik Holmqvist { 260e2e1558aSJessica Hamilton stage2_args args; 261e2e1558aSJessica Hamilton 262b3215a62SHenry Harrington memset(&args, 0, sizeof(stage2_args)); 263b3215a62SHenry Harrington 264b3215a62SHenry Harrington kImage = image; 265735f1daeSFredrik Holmqvist kSystemTable = systemTable; 266735f1daeSFredrik Holmqvist kBootServices = systemTable->BootServices; 267735f1daeSFredrik Holmqvist kRuntimeServices = systemTable->RuntimeServices; 268735f1daeSFredrik Holmqvist 269735f1daeSFredrik Holmqvist call_ctors(); 270735f1daeSFredrik Holmqvist 271735f1daeSFredrik Holmqvist console_init(); 2729e487d8dSFredrik Holmqvist serial_init(); 2739e487d8dSFredrik Holmqvist serial_enable(); 274735f1daeSFredrik Holmqvist 27596f4d68bSJessica Hamilton sBootOptions = console_check_boot_keys(); 27696f4d68bSJessica Hamilton 277b3215a62SHenry Harrington // disable apm in case we ever load a 32-bit kernel... 278b3215a62SHenry Harrington gKernelArgs.platform_args.apm.version = 0; 2796e6efaecSJessica Hamilton 280b3215a62SHenry Harrington gKernelArgs.num_cpus = 1; 281b482adb1SAlexander von Gluck IV #if defined(__x86_64__) || defined(__x86__) 282b3215a62SHenry Harrington gKernelArgs.arch_args.hpet_phys = 0; 283b3215a62SHenry Harrington gKernelArgs.arch_args.hpet = NULL; 284b482adb1SAlexander von Gluck IV #endif 285b3215a62SHenry Harrington 28686b12d85SJessica Hamilton cpu_init(); 28786b12d85SJessica Hamilton acpi_init(); 288b482adb1SAlexander von Gluck IV timer_init(); 28986b12d85SJessica Hamilton smp_init(); 29086b12d85SJessica Hamilton 291e2e1558aSJessica Hamilton main(&args); 292735f1daeSFredrik Holmqvist 293735f1daeSFredrik Holmqvist return EFI_SUCCESS; 294735f1daeSFredrik Holmqvist } 295