1/* 2 * Copyright 2014-2022 Haiku, Inc. All rights reserved. 3 * Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com. 4 * Copyright 2014, Henry Harrington, henry.harrington@gmail.com. 5 * All rights reserved. 6 * Distributed under the terms of the MIT License. 7 * 8 * Authors: 9 * Alexander von Gluck IV <kallisti5@unixzen.com> 10 */ 11 12 13#include <boot/platform.h> 14#include <boot/stage2.h> 15#include <boot/stdio.h> 16 17#include "mmu.h" 18#include "serial.h" 19#include "smp.h" 20#include "efi_platform.h" 21 22 23// From entry.S 24extern "C" void arch_enter_kernel(uint64 pml4, uint64 entry_point, 25 uint64 stackTop); 26 27// From arch_mmu.cpp 28extern void arch_mmu_post_efi_setup(size_t memory_map_size, 29 efi_memory_descriptor *memory_map, size_t descriptor_size, 30 uint32_t descriptor_version); 31 32extern uint64_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size, 33 efi_memory_descriptor *memory_map, size_t descriptor_size, 34 uint32_t descriptor_version); 35 36 37void 38arch_convert_kernel_args(void) 39{ 40 fix_address(gKernelArgs.ucode_data); 41 fix_address(gKernelArgs.arch_args.apic); 42 fix_address(gKernelArgs.arch_args.hpet); 43} 44 45 46static const char* 47memory_region_type_str(int type) 48{ 49 switch (type) { 50 case EfiReservedMemoryType: 51 return "EfiReservedMemoryType"; 52 case EfiLoaderCode: 53 return "EfiLoaderCode"; 54 case EfiLoaderData: 55 return "EfiLoaderData"; 56 case EfiBootServicesCode: 57 return "EfiBootServicesCode"; 58 case EfiBootServicesData: 59 return "EfiBootServicesData"; 60 case EfiRuntimeServicesCode: 61 return "EfiRuntimeServicesCode"; 62 case EfiRuntimeServicesData: 63 return "EfiRuntimeServicesData"; 64 case EfiConventionalMemory: 65 return "EfiConventionalMemory"; 66 case EfiUnusableMemory: 67 return "EfiUnusableMemory"; 68 case EfiACPIReclaimMemory: 69 return "EfiACPIReclaimMemory"; 70 case EfiACPIMemoryNVS: 71 return "EfiACPIMemoryNVS"; 72 case EfiMemoryMappedIO: 73 return "EfiMemoryMappedIO"; 74 case EfiMemoryMappedIOPortSpace: 75 return "EfiMemoryMappedIOPortSpace"; 76 case EfiPalCode: 77 return "EfiPalCode"; 78 case EfiPersistentMemory: 79 return "EfiPersistentMemory"; 80 default: 81 return "unknown"; 82 } 83} 84 85 86void 87arch_start_kernel(addr_t kernelEntry) 88{ 89 // Prepare to exit EFI boot services. 90 // Read the memory map. 91 // First call is to determine the buffer size. 92 size_t memory_map_size = 0; 93 efi_memory_descriptor dummy; 94 size_t map_key; 95 size_t descriptor_size; 96 uint32_t descriptor_version; 97 if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, 98 &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { 99 panic("Unable to determine size of system memory map"); 100 } 101 102 // Allocate a buffer twice as large as needed just in case it gets bigger 103 // between calls to ExitBootServices. 104 size_t actual_memory_map_size = memory_map_size * 2; 105 efi_memory_descriptor *memory_map 106 = (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size); 107 108 if (memory_map == NULL) 109 panic("Unable to allocate memory map."); 110 111 // Read (and print) the memory map. 112 memory_map_size = actual_memory_map_size; 113 if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 114 &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 115 panic("Unable to fetch system memory map."); 116 } 117 118 addr_t addr = (addr_t)memory_map; 119 dprintf("System provided memory map:\n"); 120 for (size_t i = 0; i < memory_map_size / descriptor_size; i++) { 121 efi_memory_descriptor *entry 122 = (efi_memory_descriptor *)(addr + i * descriptor_size); 123 dprintf(" phys: 0x%08lx-0x%08lx, virt: 0x%08lx-0x%08lx, type: %s (%#x), attr: %#lx\n", 124 entry->PhysicalStart, 125 entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE, 126 entry->VirtualStart, 127 entry->VirtualStart + entry->NumberOfPages * B_PAGE_SIZE, 128 memory_region_type_str(entry->Type), entry->Type, 129 entry->Attribute); 130 } 131 132 // Generate page tables for use after ExitBootServices. 133 uint64_t final_pml4 = arch_mmu_generate_post_efi_page_tables( 134 memory_map_size, memory_map, descriptor_size, descriptor_version); 135 136 // Attempt to fetch the memory map and exit boot services. 137 // This needs to be done in a loop, as ExitBootServices can change the 138 // memory map. 139 // Even better: Only GetMemoryMap and ExitBootServices can be called after 140 // the first call to ExitBootServices, as the firmware is permitted to 141 // partially exit. This is why twice as much space was allocated for the 142 // memory map, as it's impossible to allocate more now. 143 // A changing memory map shouldn't affect the generated page tables, as 144 // they only needed to know about the maximum address, not any specific 145 // entry. 146 147 dprintf("Calling ExitBootServices. So long, EFI!\n"); 148 149 // Re-init and activate serial in a horrific post-EFI landscape. Clowns roam the land freely. 150 serial_init(); 151 serial_disable(); 152 153 while (true) { 154 if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { 155 // Disconnect from EFI serial_io / stdio services 156 serial_kernel_handoff(); 157 dprintf("Unhooked from EFI serial services\n"); 158 break; 159 } 160 161 memory_map_size = actual_memory_map_size; 162 if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 163 &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 164 panic("Unable to fetch system memory map."); 165 } 166 } 167 168 // Update EFI, generate final kernel physical memory map, etc. 169 arch_mmu_post_efi_setup(memory_map_size, memory_map, 170 descriptor_size, descriptor_version); 171 172 // Restart serial. gUART only until we get into the kernel 173 serial_enable(); 174 175 smp_boot_other_cpus(final_pml4, kernelEntry, (addr_t)&gKernelArgs); 176 177 // Enter the kernel! 178 dprintf("arch_enter_kernel(final_pml4: 0x%08" PRIx64 ", kernelArgs: %p, " 179 "kernelEntry: 0x%08" B_PRIxADDR ", sp: 0x%08" B_PRIx64 ")\n", 180 final_pml4, &gKernelArgs, kernelEntry, 181 gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); 182 183 arch_enter_kernel(final_pml4, kernelEntry, 184 gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); 185} 186