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. 6b3215a62SHenry Harrington * Distributed under the terms of the Haiku 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> 15b3215a62SHenry Harrington #include <arch/x86/descriptors.h> 166e6efaecSJessica Hamilton #include <boot/kernel_args.h> 17e2e1558aSJessica Hamilton #include <boot/platform.h> 18e2e1558aSJessica Hamilton #include <boot/stage2.h> 19e2e1558aSJessica Hamilton #include <boot/stdio.h> 20b3215a62SHenry Harrington #include <kernel.h> 21735f1daeSFredrik Holmqvist 226e6efaecSJessica Hamilton #include "acpi.h" 23735f1daeSFredrik Holmqvist #include "console.h" 24735f1daeSFredrik Holmqvist #include "efi_platform.h" 25a1d0102eSJessica Hamilton #include "hpet.h" 26a7142a50SJessica Hamilton #include "cpu.h" 27b3215a62SHenry Harrington #include "mmu.h" 28*9e487d8dSFredrik Holmqvist #include "serial.h" 29a99a0c00SNick Smallbone #include "smp.h" 30735f1daeSFredrik Holmqvist 31735f1daeSFredrik Holmqvist 32735f1daeSFredrik Holmqvist extern void (*__ctor_list)(void); 33735f1daeSFredrik Holmqvist extern void (*__ctor_end)(void); 34735f1daeSFredrik Holmqvist 35735f1daeSFredrik Holmqvist 36735f1daeSFredrik Holmqvist const EFI_SYSTEM_TABLE *kSystemTable; 37735f1daeSFredrik Holmqvist const EFI_BOOT_SERVICES *kBootServices; 38735f1daeSFredrik Holmqvist const EFI_RUNTIME_SERVICES *kRuntimeServices; 39b3215a62SHenry Harrington EFI_HANDLE kImage; 40b3215a62SHenry Harrington 41735f1daeSFredrik Holmqvist 4296f4d68bSJessica Hamilton static uint32 sBootOptions; 43b3215a62SHenry Harrington static uint64 gLongKernelEntry; 44b3215a62SHenry Harrington extern uint64 gLongGDT; 45a99a0c00SNick Smallbone extern uint64 gLongGDTR; 46b3215a62SHenry Harrington segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT]; 47b3215a62SHenry Harrington 48b3215a62SHenry Harrington 49b3215a62SHenry Harrington extern "C" int main(stage2_args *args); 50b3215a62SHenry Harrington extern "C" void _start(void); 51b3215a62SHenry Harrington extern "C" void efi_enter_kernel(uint64 pml4, uint64 entry_point, uint64 stack); 5296f4d68bSJessica Hamilton 53735f1daeSFredrik Holmqvist 54735f1daeSFredrik Holmqvist static void 55735f1daeSFredrik Holmqvist call_ctors(void) 56735f1daeSFredrik Holmqvist { 57735f1daeSFredrik Holmqvist void (**f)(void); 58735f1daeSFredrik Holmqvist 59735f1daeSFredrik Holmqvist for (f = &__ctor_list; f < &__ctor_end; f++) 60735f1daeSFredrik Holmqvist (**f)(); 61735f1daeSFredrik Holmqvist } 62735f1daeSFredrik Holmqvist 63735f1daeSFredrik Holmqvist 64e2e1558aSJessica Hamilton extern "C" uint32 65e2e1558aSJessica Hamilton platform_boot_options() 66e2e1558aSJessica Hamilton { 6796f4d68bSJessica Hamilton return sBootOptions; 68e2e1558aSJessica Hamilton } 69e2e1558aSJessica Hamilton 70e2e1558aSJessica Hamilton 71b3215a62SHenry Harrington static void 72b3215a62SHenry Harrington long_gdt_init() 73b3215a62SHenry Harrington { 74b3215a62SHenry Harrington clear_segment_descriptor(&gBootGDT[0]); 75b3215a62SHenry Harrington 76b3215a62SHenry Harrington // Set up code/data segments (TSS segments set up later in the kernel). 77b3215a62SHenry Harrington set_segment_descriptor(&gBootGDT[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, 78b3215a62SHenry Harrington DPL_KERNEL); 79b3215a62SHenry Harrington set_segment_descriptor(&gBootGDT[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE, 80b3215a62SHenry Harrington DPL_KERNEL); 81b3215a62SHenry Harrington set_segment_descriptor(&gBootGDT[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY, 82b3215a62SHenry Harrington DPL_USER); 83b3215a62SHenry Harrington set_segment_descriptor(&gBootGDT[USER_DATA_SEGMENT], DT_DATA_WRITEABLE, 84b3215a62SHenry Harrington DPL_USER); 85b3215a62SHenry Harrington 86b3215a62SHenry Harrington // Used by long_enter_kernel(). 8734a6dd67SHenry Harrington gLongGDT = (addr_t)gBootGDT + 0xFFFFFF0000000000; 88b3215a62SHenry Harrington dprintf("GDT at 0x%lx\n", gLongGDT); 89b3215a62SHenry Harrington } 90b3215a62SHenry Harrington 91b3215a62SHenry Harrington 92b3215a62SHenry Harrington static void 93b3215a62SHenry Harrington convert_preloaded_image(preloaded_elf64_image* image) 94b3215a62SHenry Harrington { 95b3215a62SHenry Harrington fix_address(image->next); 96b3215a62SHenry Harrington fix_address(image->name); 97b3215a62SHenry Harrington fix_address(image->debug_string_table); 98b3215a62SHenry Harrington fix_address(image->syms); 99b3215a62SHenry Harrington fix_address(image->rel); 100b3215a62SHenry Harrington fix_address(image->rela); 101b3215a62SHenry Harrington fix_address(image->pltrel); 102b3215a62SHenry Harrington fix_address(image->debug_symbols); 103b3215a62SHenry Harrington } 104b3215a62SHenry Harrington 105b3215a62SHenry Harrington 106b3215a62SHenry Harrington /*! Convert all addresses in kernel_args to 64-bit addresses. */ 107b3215a62SHenry Harrington static void 108b3215a62SHenry Harrington convert_kernel_args() 109b3215a62SHenry Harrington { 110b3215a62SHenry Harrington fix_address(gKernelArgs.boot_volume); 111b3215a62SHenry Harrington fix_address(gKernelArgs.vesa_modes); 112b3215a62SHenry Harrington fix_address(gKernelArgs.edid_info); 113b3215a62SHenry Harrington fix_address(gKernelArgs.debug_output); 114b3215a62SHenry Harrington fix_address(gKernelArgs.boot_splash); 115b3215a62SHenry Harrington fix_address(gKernelArgs.arch_args.apic); 116b3215a62SHenry Harrington fix_address(gKernelArgs.arch_args.hpet); 117b3215a62SHenry Harrington 118b3215a62SHenry Harrington convert_preloaded_image(static_cast<preloaded_elf64_image*>( 119b3215a62SHenry Harrington gKernelArgs.kernel_image.Pointer())); 120b3215a62SHenry Harrington fix_address(gKernelArgs.kernel_image); 121b3215a62SHenry Harrington 122b3215a62SHenry Harrington // Iterate over the preloaded images. Must save the next address before 123b3215a62SHenry Harrington // converting, as the next pointer will be converted. 124b3215a62SHenry Harrington preloaded_image* image = gKernelArgs.preloaded_images; 125b3215a62SHenry Harrington fix_address(gKernelArgs.preloaded_images); 126b3215a62SHenry Harrington while (image != NULL) { 127b3215a62SHenry Harrington preloaded_image* next = image->next; 128b3215a62SHenry Harrington convert_preloaded_image(static_cast<preloaded_elf64_image*>(image)); 129b3215a62SHenry Harrington image = next; 130b3215a62SHenry Harrington } 131b3215a62SHenry Harrington 132b3215a62SHenry Harrington // Fix driver settings files. 133b3215a62SHenry Harrington driver_settings_file* file = gKernelArgs.driver_settings; 134b3215a62SHenry Harrington fix_address(gKernelArgs.driver_settings); 135b3215a62SHenry Harrington while (file != NULL) { 136b3215a62SHenry Harrington driver_settings_file* next = file->next; 137b3215a62SHenry Harrington fix_address(file->next); 138b3215a62SHenry Harrington fix_address(file->buffer); 139b3215a62SHenry Harrington file = next; 140b3215a62SHenry Harrington } 141b3215a62SHenry Harrington } 142b3215a62SHenry Harrington 143b3215a62SHenry Harrington 144e2e1558aSJessica Hamilton extern "C" void 145e2e1558aSJessica Hamilton platform_start_kernel(void) 146e2e1558aSJessica Hamilton { 147b3215a62SHenry Harrington if (gKernelArgs.kernel_image->elf_class != ELFCLASS64) 148b3215a62SHenry Harrington panic("32-bit kernels not supported with EFI"); 149b3215a62SHenry Harrington 150ec239abcSJessica Hamilton cpu_init(); 151ec239abcSJessica Hamilton acpi_init(); 152ec239abcSJessica Hamilton hpet_init(); 153a99a0c00SNick Smallbone smp_init(); 154a99a0c00SNick Smallbone smp_init_other_cpus(); 155ec239abcSJessica Hamilton 156b3215a62SHenry Harrington preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>( 157b3215a62SHenry Harrington gKernelArgs.kernel_image.Pointer()); 158b3215a62SHenry Harrington 159b3215a62SHenry Harrington long_gdt_init(); 160b3215a62SHenry Harrington convert_kernel_args(); 161b3215a62SHenry Harrington 162b3215a62SHenry Harrington // Save the kernel entry point address. 163b3215a62SHenry Harrington gLongKernelEntry = image->elf_header.e_entry; 164b3215a62SHenry Harrington dprintf("kernel entry at %#lx\n", gLongKernelEntry); 165b3215a62SHenry Harrington 166b3215a62SHenry Harrington // map in a kernel stack 167b3215a62SHenry Harrington void *stack_address = NULL; 168b3215a62SHenry Harrington if (platform_allocate_region(&stack_address, KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0, false) != B_OK) { 169b3215a62SHenry Harrington panic("Unabled to allocate a stack"); 170b3215a62SHenry Harrington } 171b3215a62SHenry Harrington gKernelArgs.cpu_kstack[0].start = fix_address((uint64_t)stack_address); 172b3215a62SHenry Harrington gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE; 173b3215a62SHenry Harrington dprintf("Kernel stack at %#lx\n", gKernelArgs.cpu_kstack[0].start); 174b3215a62SHenry Harrington 175b3215a62SHenry Harrington // Prepare to exit EFI boot services. 176b3215a62SHenry Harrington // Read the memory map. 177b3215a62SHenry Harrington // First call is to determine the buffer size. 178b3215a62SHenry Harrington UINTN memory_map_size = 0; 179b3215a62SHenry Harrington EFI_MEMORY_DESCRIPTOR dummy; 180b3215a62SHenry Harrington EFI_MEMORY_DESCRIPTOR *memory_map; 181b3215a62SHenry Harrington UINTN map_key; 182b3215a62SHenry Harrington UINTN descriptor_size; 183b3215a62SHenry Harrington UINT32 descriptor_version; 184b3215a62SHenry Harrington if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { 185b3215a62SHenry Harrington panic("Unable to determine size of system memory map"); 186b3215a62SHenry Harrington } 187b3215a62SHenry Harrington 188b3215a62SHenry Harrington // Allocate a buffer twice as large as needed just in case it gets bigger between 189b3215a62SHenry Harrington // calls to ExitBootServices. 190b3215a62SHenry Harrington UINTN actual_memory_map_size = memory_map_size * 2; 191b3215a62SHenry Harrington memory_map = (EFI_MEMORY_DESCRIPTOR *)kernel_args_malloc(actual_memory_map_size); 192b3215a62SHenry Harrington if (memory_map == NULL) 193b3215a62SHenry Harrington panic("Unable to allocate memory map."); 194b3215a62SHenry Harrington 195b3215a62SHenry Harrington // Read (and print) the memory map. 196b3215a62SHenry Harrington memory_map_size = actual_memory_map_size; 197b3215a62SHenry Harrington if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 198b3215a62SHenry Harrington panic("Unable to fetch system memory map."); 199b3215a62SHenry Harrington } 200b3215a62SHenry Harrington 201b3215a62SHenry Harrington addr_t addr = (addr_t)memory_map; 202b3215a62SHenry Harrington dprintf("System provided memory map:\n"); 203b3215a62SHenry Harrington for (UINTN i = 0; i < memory_map_size / descriptor_size; ++i) { 204b3215a62SHenry Harrington EFI_MEMORY_DESCRIPTOR *entry = (EFI_MEMORY_DESCRIPTOR *)(addr + i * descriptor_size); 205b3215a62SHenry Harrington dprintf(" %#lx-%#lx %#lx %#x %#lx\n", 206b3215a62SHenry Harrington entry->PhysicalStart, entry->PhysicalStart + entry->NumberOfPages * 4096, 207b3215a62SHenry Harrington entry->VirtualStart, entry->Type, entry->Attribute); 208b3215a62SHenry Harrington } 209b3215a62SHenry Harrington 210b3215a62SHenry Harrington // Generate page tables for use after ExitBootServices. 211b3215a62SHenry Harrington uint64_t final_pml4 = mmu_generate_post_efi_page_tables(memory_map_size, memory_map, descriptor_size, descriptor_version); 212b3215a62SHenry Harrington dprintf("Final PML4 at %#lx\n", final_pml4); 213b3215a62SHenry Harrington 214b3215a62SHenry Harrington // Attempt to fetch the memory map and exit boot services. 215b3215a62SHenry Harrington // This needs to be done in a loop, as ExitBootServices can change the 216b3215a62SHenry Harrington // memory map. 217b3215a62SHenry Harrington // Even better: Only GetMemoryMap and ExitBootServices can be called after 218b3215a62SHenry Harrington // the first call to ExitBootServices, as the firmware is permitted to 219b3215a62SHenry Harrington // partially exit. This is why twice as much space was allocated for the 220b3215a62SHenry Harrington // memory map, as it's impossible to allocate more now. 221b3215a62SHenry Harrington // A changing memory map shouldn't affect the generated page tables, as 222b3215a62SHenry Harrington // they only needed to know about the maximum address, not any specific 223b3215a62SHenry Harrington // entry. 224b3215a62SHenry Harrington dprintf("Calling ExitBootServices. So long, EFI!\n"); 225b3215a62SHenry Harrington while (true) { 226b3215a62SHenry Harrington if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { 227*9e487d8dSFredrik Holmqvist // The console was provided by boot services, disable it. 228*9e487d8dSFredrik Holmqvist stdout = NULL; 229*9e487d8dSFredrik Holmqvist stderr = NULL; 230*9e487d8dSFredrik Holmqvist // Also switch to legacy serial output (may not work on all systems) 231*9e487d8dSFredrik Holmqvist serial_switch_to_legacy(); 232*9e487d8dSFredrik Holmqvist dprintf("Switched to legacy serial output\n"); 233b3215a62SHenry Harrington break; 234b3215a62SHenry Harrington } 235b3215a62SHenry Harrington 236b3215a62SHenry Harrington memory_map_size = actual_memory_map_size; 237b3215a62SHenry Harrington if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 238b3215a62SHenry Harrington panic("Unable to fetch system memory map."); 239b3215a62SHenry Harrington } 240b3215a62SHenry Harrington } 241b3215a62SHenry Harrington 242b3215a62SHenry Harrington // Update EFI, generate final kernel physical memory map, etc. 243b3215a62SHenry Harrington mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size, descriptor_version); 244b3215a62SHenry Harrington 245a99a0c00SNick Smallbone smp_boot_other_cpus(final_pml4, (uint32_t)(uint64_t)&gLongGDTR, gLongKernelEntry); 246a99a0c00SNick Smallbone 247b3215a62SHenry Harrington // Enter the kernel! 248b3215a62SHenry Harrington efi_enter_kernel(final_pml4, 249b3215a62SHenry Harrington gLongKernelEntry, 250b3215a62SHenry Harrington gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); 251b3215a62SHenry Harrington 252b3215a62SHenry Harrington panic("Shouldn't get here"); 253e2e1558aSJessica Hamilton } 254e2e1558aSJessica Hamilton 255e2e1558aSJessica Hamilton 256e2e1558aSJessica Hamilton extern "C" void 257e2e1558aSJessica Hamilton platform_exit(void) 258e2e1558aSJessica Hamilton { 259e2e1558aSJessica Hamilton return; 260e2e1558aSJessica Hamilton } 261e2e1558aSJessica Hamilton 262e2e1558aSJessica Hamilton 263735f1daeSFredrik Holmqvist /** 264735f1daeSFredrik Holmqvist * efi_main - The entry point for the EFI application 265735f1daeSFredrik Holmqvist * @image: firmware-allocated handle that identifies the image 266735f1daeSFredrik Holmqvist * @systemTable: EFI system table 267735f1daeSFredrik Holmqvist */ 268735f1daeSFredrik Holmqvist extern "C" EFI_STATUS 269735f1daeSFredrik Holmqvist efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) 270735f1daeSFredrik Holmqvist { 271e2e1558aSJessica Hamilton stage2_args args; 272e2e1558aSJessica Hamilton 273b3215a62SHenry Harrington memset(&args, 0, sizeof(stage2_args)); 274b3215a62SHenry Harrington 275b3215a62SHenry Harrington kImage = image; 276735f1daeSFredrik Holmqvist kSystemTable = systemTable; 277735f1daeSFredrik Holmqvist kBootServices = systemTable->BootServices; 278735f1daeSFredrik Holmqvist kRuntimeServices = systemTable->RuntimeServices; 279735f1daeSFredrik Holmqvist 280e2e1558aSJessica Hamilton memset(&args, 0, sizeof(stage2_args)); 281e2e1558aSJessica Hamilton 282735f1daeSFredrik Holmqvist call_ctors(); 283735f1daeSFredrik Holmqvist 284735f1daeSFredrik Holmqvist console_init(); 285*9e487d8dSFredrik Holmqvist serial_init(); 286*9e487d8dSFredrik Holmqvist serial_enable(); 287735f1daeSFredrik Holmqvist 28896f4d68bSJessica Hamilton sBootOptions = console_check_boot_keys(); 28996f4d68bSJessica Hamilton 290b3215a62SHenry Harrington // disable apm in case we ever load a 32-bit kernel... 291b3215a62SHenry Harrington gKernelArgs.platform_args.apm.version = 0; 2926e6efaecSJessica Hamilton 293b3215a62SHenry Harrington gKernelArgs.num_cpus = 1; 294b3215a62SHenry Harrington gKernelArgs.arch_args.hpet_phys = 0; 295b3215a62SHenry Harrington gKernelArgs.arch_args.hpet = NULL; 296b3215a62SHenry Harrington 297e2e1558aSJessica Hamilton main(&args); 298735f1daeSFredrik Holmqvist 299735f1daeSFredrik Holmqvist return EFI_SUCCESS; 300735f1daeSFredrik Holmqvist } 301