1 /* 2 * Copyright 2021-2022 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 #include "serial.h" 15 #include "smp.h" 16 17 18 struct gdt_idt_descr { 19 uint16 limit; 20 void* base; 21 } _PACKED; 22 23 24 extern gdt_idt_descr gBootGDTDescriptor; 25 26 27 extern "C" typedef void (*enter_kernel_t)(uint32_t, addr_t, addr_t, addr_t, 28 struct gdt_idt_descr *); 29 30 31 // From entry.S 32 extern "C" void arch_enter_kernel(uint32_t pageDirectory, addr_t kernelArgs, 33 addr_t kernelEntry, addr_t kernelStackTop, struct gdt_idt_descr *gdtDescriptor); 34 35 // From arch_mmu.cpp 36 extern void arch_mmu_post_efi_setup(size_t memoryMapSize, 37 efi_memory_descriptor *memoryMap, size_t descriptorSize, 38 uint32_t descriptorVersion); 39 40 extern uint32_t arch_mmu_generate_post_efi_page_tables(size_t memoryMapSize, 41 efi_memory_descriptor *memoryMap, size_t descriptorSize, 42 uint32_t descriptorVersion); 43 44 45 void 46 arch_convert_kernel_args(void) 47 { 48 fix_address(gKernelArgs.ucode_data); 49 fix_address(gKernelArgs.arch_args.apic); 50 fix_address(gKernelArgs.arch_args.hpet); 51 } 52 53 54 static const char* 55 memory_region_type_str(int type) 56 { 57 switch (type) { 58 case EfiReservedMemoryType: 59 return "ReservedMemoryType"; 60 case EfiLoaderCode: 61 return "LoaderCode"; 62 case EfiLoaderData: 63 return "LoaderData"; 64 case EfiBootServicesCode: 65 return "BootServicesCode"; 66 case EfiBootServicesData: 67 return "BootServicesData"; 68 case EfiRuntimeServicesCode: 69 return "RuntimeServicesCode"; 70 case EfiRuntimeServicesData: 71 return "RuntimeServicesData"; 72 case EfiConventionalMemory: 73 return "ConventionalMemory"; 74 case EfiUnusableMemory: 75 return "UnusableMemory"; 76 case EfiACPIReclaimMemory: 77 return "ACPIReclaimMemory"; 78 case EfiACPIMemoryNVS: 79 return "ACPIMemoryNVS"; 80 case EfiMemoryMappedIO: 81 return "MMIO"; 82 case EfiMemoryMappedIOPortSpace: 83 return "MMIOPortSpace"; 84 case EfiPalCode: 85 return "PalCode"; 86 case EfiPersistentMemory: 87 return "PersistentMemory"; 88 default: 89 return "unknown"; 90 } 91 } 92 93 94 void 95 arch_start_kernel(addr_t kernelEntry) 96 { 97 // Copy entry.S trampoline to lower 1M 98 enter_kernel_t enter_kernel = (enter_kernel_t)0xa000; 99 memcpy((void *)enter_kernel, (void *)arch_enter_kernel, B_PAGE_SIZE); 100 101 // Allocate virtual memory for kernel args 102 struct kernel_args *kernelArgs = NULL; 103 if (platform_allocate_region((void **)&kernelArgs, 104 sizeof(struct kernel_args), 0, false) != B_OK) 105 panic("Failed to allocate kernel args."); 106 107 addr_t virtKernelArgs; 108 platform_bootloader_address_to_kernel_address((void*)kernelArgs, 109 &virtKernelArgs); 110 111 // Prepare to exit EFI boot services. 112 // Read the memory map. 113 // First call is to determine the buffer size. 114 size_t memoryMapSize = 0; 115 efi_memory_descriptor dummy; 116 size_t mapKey; 117 size_t descriptorSize; 118 uint32_t descriptorVersion; 119 if (kBootServices->GetMemoryMap(&memoryMapSize, &dummy, &mapKey, 120 &descriptorSize, &descriptorVersion) != EFI_BUFFER_TOO_SMALL) { 121 panic("Unable to determine size of system memory map"); 122 } 123 124 // Allocate a buffer twice as large as needed just in case it gets bigger 125 // between calls to ExitBootServices. 126 size_t actualMemoryMapSize = memoryMapSize * 2; 127 efi_memory_descriptor *memoryMap 128 = (efi_memory_descriptor *)kernel_args_malloc(actualMemoryMapSize); 129 130 if (memoryMap == NULL) 131 panic("Unable to allocate memory map."); 132 133 // Read (and print) the memory map. 134 memoryMapSize = actualMemoryMapSize; 135 if (kBootServices->GetMemoryMap(&memoryMapSize, memoryMap, &mapKey, 136 &descriptorSize, &descriptorVersion) != EFI_SUCCESS) { 137 panic("Unable to fetch system memory map."); 138 } 139 140 addr_t addr = (addr_t)memoryMap; 141 dprintf("System provided memory map:\n"); 142 for (size_t i = 0; i < memoryMapSize / descriptorSize; i++) { 143 efi_memory_descriptor *entry 144 = (efi_memory_descriptor *)(addr + i * descriptorSize); 145 dprintf(" phys: 0x%08" PRIx64 "-0x%08" PRIx64 146 ", virt: 0x%08" PRIx64 "-0x%08" PRIx64 147 ", type: %s (%#x), attr: %#" PRIx64 "\n", 148 entry->PhysicalStart, 149 entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE, 150 entry->VirtualStart, 151 entry->VirtualStart + entry->NumberOfPages * B_PAGE_SIZE, 152 memory_region_type_str(entry->Type), entry->Type, 153 entry->Attribute); 154 } 155 156 // Generate page tables for use after ExitBootServices. 157 uint32_t pageDirectory = arch_mmu_generate_post_efi_page_tables( 158 memoryMapSize, memoryMap, descriptorSize, descriptorVersion); 159 160 // Attempt to fetch the memory map and exit boot services. 161 // This needs to be done in a loop, as ExitBootServices can change the 162 // memory map. 163 // Even better: Only GetMemoryMap and ExitBootServices can be called after 164 // the first call to ExitBootServices, as the firmware is permitted to 165 // partially exit. This is why twice as much space was allocated for the 166 // memory map, as it's impossible to allocate more now. 167 // A changing memory map shouldn't affect the generated page tables, as 168 // they only needed to know about the maximum address, not any specific 169 // entry. 170 dprintf("Calling ExitBootServices. So long, EFI!\n"); 171 while (true) { 172 if (kBootServices->ExitBootServices(kImage, mapKey) == EFI_SUCCESS) { 173 // The console was provided by boot services, disable it. 174 stdout = NULL; 175 stderr = NULL; 176 // Also switch to legacy serial output 177 // (may not work on all systems) 178 serial_switch_to_legacy(); 179 dprintf("Switched to legacy serial output\n"); 180 break; 181 } 182 183 memoryMapSize = actualMemoryMapSize; 184 if (kBootServices->GetMemoryMap(&memoryMapSize, memoryMap, &mapKey, 185 &descriptorSize, &descriptorVersion) != EFI_SUCCESS) { 186 panic("Unable to fetch system memory map."); 187 } 188 } 189 190 // Update EFI, generate final kernel physical memory map, etc. 191 arch_mmu_post_efi_setup(memoryMapSize, memoryMap, 192 descriptorSize, descriptorVersion); 193 194 // Copy final kernel args 195 // This should be the last step before jumping to the kernel 196 // as there are some fixups happening to kernel_args even in the last minute 197 memcpy(kernelArgs, &gKernelArgs, sizeof(struct kernel_args)); 198 199 smp_boot_other_cpus(pageDirectory, kernelEntry); 200 201 // Enter the kernel! 202 dprintf("enter_kernel(pageDirectory: 0x%08x, kernelArgs: 0x%08x, " 203 "kernelEntry: 0x%08x, sp: 0x%08x, gBootGDTDescriptor: 0x%08x)\n", 204 pageDirectory, (uint32_t)virtKernelArgs, (uint32_t)kernelEntry, 205 (uint32_t)(gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size), 206 (uint32_t)&gBootGDTDescriptor); 207 208 enter_kernel(pageDirectory, virtKernelArgs, kernelEntry, 209 gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size, 210 &gBootGDTDescriptor); 211 } 212