1 /* 2 * Copyright 2019-2021 Haiku, Inc. All rights reserved. 3 * Released under the terms of the MIT License. 4 */ 5 6 7 #include <kernel.h> 8 #include <boot/platform.h> 9 #include <boot/stage2.h> 10 #include <boot/stdio.h> 11 12 #include "efi_platform.h" 13 #include "mmu.h" 14 15 16 #define ALIGN_MEMORY_MAP 4 17 18 19 extern "C" void arch_enter_kernel(uint32_t ttbr, struct kernel_args *kernelArgs, 20 addr_t kernelEntry, addr_t kernelStackTop); 21 22 // From arch_mmu.cpp 23 extern void arch_mmu_post_efi_setup(size_t memory_map_size, 24 efi_memory_descriptor *memory_map, size_t descriptor_size, 25 uint32_t descriptor_version); 26 27 extern uint32_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size, 28 efi_memory_descriptor *memory_map, size_t descriptor_size, 29 uint32_t descriptor_version); 30 31 32 void 33 arch_convert_kernel_args(void) 34 { 35 fix_address(gKernelArgs.arch_args.fdt); 36 } 37 38 39 static const char* 40 memory_region_type_str(int type) 41 { 42 switch (type) { 43 case EfiReservedMemoryType: 44 return "ReservedMemoryType"; 45 case EfiLoaderCode: 46 return "LoaderCode"; 47 case EfiLoaderData: 48 return "LoaderData"; 49 case EfiBootServicesCode: 50 return "BootServicesCode"; 51 case EfiBootServicesData: 52 return "BootServicesData"; 53 case EfiRuntimeServicesCode: 54 return "RuntimeServicesCode"; 55 case EfiRuntimeServicesData: 56 return "RuntimeServicesData"; 57 case EfiConventionalMemory: 58 return "ConventionalMemory"; 59 case EfiUnusableMemory: 60 return "UnusableMemory"; 61 case EfiACPIReclaimMemory: 62 return "ACPIReclaimMemory"; 63 case EfiACPIMemoryNVS: 64 return "ACPIMemoryNVS"; 65 case EfiMemoryMappedIO: 66 return "MMIO"; 67 case EfiMemoryMappedIOPortSpace: 68 return "MMIOPortSpace"; 69 case EfiPalCode: 70 return "PalCode"; 71 case EfiPersistentMemory: 72 return "PersistentMemory"; 73 default: 74 return "unknown"; 75 } 76 } 77 78 79 void 80 arch_start_kernel(addr_t kernelEntry) 81 { 82 // Prepare to exit EFI boot services. 83 // Read the memory map. 84 // First call is to determine the buffer size. 85 size_t memory_map_size = 0; 86 efi_memory_descriptor dummy; 87 efi_memory_descriptor *memory_map; 88 size_t map_key; 89 size_t descriptor_size; 90 uint32_t descriptor_version; 91 if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, 92 &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { 93 panic("Unable to determine size of system memory map"); 94 } 95 96 // Allocate a buffer twice as large as needed just in case it gets bigger 97 // between calls to ExitBootServices. 98 size_t actual_memory_map_size = memory_map_size * 2; 99 memory_map 100 = (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size + 101 ALIGN_MEMORY_MAP); 102 103 // align memory_map to 4-byte boundary 104 // otherwise we get alignment exception when calling GetMemoryMap below 105 memory_map = (efi_memory_descriptor *)ROUNDUP((uint32_t)memory_map, ALIGN_MEMORY_MAP); 106 107 if (memory_map == NULL) 108 panic("Unable to allocate memory map."); 109 110 // Read (and print) the memory map. 111 memory_map_size = actual_memory_map_size; 112 if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 113 &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 114 panic("Unable to fetch system memory map."); 115 } 116 117 addr_t addr = (addr_t)memory_map; 118 dprintf("System provided memory map:\n"); 119 for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { 120 efi_memory_descriptor *entry 121 = (efi_memory_descriptor *)(addr + i * descriptor_size); 122 dprintf(" phys: 0x%08llx-0x%08llx, virt: 0x%08llx-0x%08llx, type: %s (%#x), attr: %#llx\n", 123 entry->PhysicalStart, 124 entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE, 125 entry->VirtualStart, 126 entry->VirtualStart + entry->NumberOfPages * B_PAGE_SIZE, 127 memory_region_type_str(entry->Type), entry->Type, 128 entry->Attribute); 129 } 130 131 // Generate page tables for use after ExitBootServices. 132 uint32_t final_ttbr0 = arch_mmu_generate_post_efi_page_tables( 133 memory_map_size, memory_map, descriptor_size, descriptor_version); 134 135 // Attempt to fetch the memory map and exit boot services. 136 // This needs to be done in a loop, as ExitBootServices can change the 137 // memory map. 138 // Even better: Only GetMemoryMap and ExitBootServices can be called after 139 // the first call to ExitBootServices, as the firmware is permitted to 140 // partially exit. This is why twice as much space was allocated for the 141 // memory map, as it's impossible to allocate more now. 142 // A changing memory map shouldn't affect the generated page tables, as 143 // they only needed to know about the maximum address, not any specific 144 // entry. 145 dprintf("Calling ExitBootServices. So long, EFI!\n"); 146 while (true) { 147 if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { 148 // The console was provided by boot services, disable it. 149 stdout = NULL; 150 stderr = NULL; 151 // Can we adjust gKernelArgs.platform_args.serial_base_ports[0] 152 // to something fixed in qemu for debugging? 153 break; 154 } 155 156 memory_map_size = actual_memory_map_size; 157 if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 158 &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 159 panic("Unable to fetch system memory map."); 160 } 161 } 162 163 // Update EFI, generate final kernel physical memory map, etc. 164 arch_mmu_post_efi_setup(memory_map_size, memory_map, 165 descriptor_size, descriptor_version); 166 167 //smp_boot_other_cpus(final_pml4, kernelEntry); 168 169 // Enter the kernel! 170 dprintf("arch_enter_kernel(ttbr0: 0x%08x, kernelArgs: 0x%08x, " 171 "kernelEntry: 0x%08x, sp: 0x%08x)\n", 172 final_ttbr0, (uint32_t)&gKernelArgs, (uint32_t)kernelEntry, 173 (uint32_t)(gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size)); 174 175 arch_enter_kernel(final_ttbr0, &gKernelArgs, kernelEntry, 176 gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size); 177 } 178