1 /* 2 * Copyright 2019-2022 Haiku, Inc. All rights reserved. 3 * Released under the terms of the MIT License. 4 */ 5 6 7 #include <boot/platform.h> 8 #include <boot/stage2.h> 9 #include <boot/stdio.h> 10 11 #include <arch_cpu_defs.h> 12 13 #include "mmu.h" 14 #include "serial.h" 15 #include "smp.h" 16 #include "efi_platform.h" 17 #include "arch_traps.h" 18 19 20 // From entry.S 21 extern "C" void arch_enter_kernel(uint64 satp, addr_t kernelArgs, 22 addr_t kernelEntry, addr_t kernelStackTop); 23 24 // From arch_mmu.cpp 25 extern void arch_mmu_post_efi_setup(size_t memory_map_size, 26 efi_memory_descriptor *memory_map, size_t descriptor_size, 27 uint32_t descriptor_version); 28 29 extern uint64_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size, 30 efi_memory_descriptor *memory_map, size_t descriptor_size, 31 uint32_t descriptor_version); 32 33 34 #include <arch/riscv64/arch_uart_sifive.h> 35 36 37 void 38 arch_convert_kernel_args(void) 39 { 40 fix_address(gKernelArgs.arch_args.fdt); 41 } 42 43 44 void 45 arch_start_kernel(addr_t kernelEntry) 46 { 47 // Allocate virtual memory for kernel args 48 struct kernel_args *kernelArgs = NULL; 49 if (platform_allocate_region((void **)&kernelArgs, 50 sizeof(struct kernel_args), 0, false) != B_OK) 51 panic("Failed to allocate kernel args."); 52 53 addr_t virtKernelArgs; 54 platform_bootloader_address_to_kernel_address((void*)kernelArgs, 55 &virtKernelArgs); 56 57 // EFI assumed to be SBI booted 58 gKernelArgs.arch_args.machine_platform = kPlatformSbi; 59 60 // Prepare to exit EFI boot services. 61 // Read the memory map. 62 // First call is to determine the buffer size. 63 size_t memory_map_size = 0; 64 efi_memory_descriptor dummy; 65 efi_memory_descriptor *memory_map; 66 size_t map_key; 67 size_t descriptor_size; 68 uint32_t descriptor_version; 69 if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key, 70 &descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) { 71 panic("Unable to determine size of system memory map"); 72 } 73 74 // Allocate a buffer twice as large as needed just in case it gets bigger 75 // between calls to ExitBootServices. 76 size_t actual_memory_map_size = memory_map_size * 2; 77 memory_map 78 = (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size); 79 80 if (memory_map == NULL) 81 panic("Unable to allocate memory map."); 82 83 // Read (and print) the memory map. 84 memory_map_size = actual_memory_map_size; 85 if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 86 &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 87 panic("Unable to fetch system memory map."); 88 } 89 90 addr_t addr = (addr_t)memory_map; 91 dprintf("System provided memory map:\n"); 92 for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) { 93 efi_memory_descriptor *entry 94 = (efi_memory_descriptor *)(addr + i * descriptor_size); 95 dprintf(" phys: %#lx, virt: %#lx, size: %#lx, ", 96 entry->PhysicalStart, entry->VirtualStart, 97 entry->NumberOfPages * B_PAGE_SIZE); 98 switch (entry->Type) { 99 case EfiReservedMemoryType: dprintf("reservedMemoryType"); break; 100 case EfiLoaderCode: dprintf("loaderCode"); break; 101 case EfiLoaderData: dprintf("loaderData"); break; 102 case EfiBootServicesCode: dprintf("bootServicesCode"); break; 103 case EfiBootServicesData: dprintf("bootServicesData"); break; 104 case EfiConventionalMemory: dprintf("conventionalMemory"); break; 105 case EfiACPIReclaimMemory: dprintf("ACPIReclaimMemory"); break; 106 case EfiRuntimeServicesCode: dprintf("runtimeServicesCode"); break; 107 case EfiRuntimeServicesData: dprintf("runtimeServicesData"); break; 108 default: dprintf("?(%d)", entry->Type); 109 } 110 dprintf(", attrs: %#lx\n", entry->Attribute); 111 } 112 113 // Generate page tables for use after ExitBootServices. 114 uint64_t satp = arch_mmu_generate_post_efi_page_tables( 115 memory_map_size, memory_map, descriptor_size, descriptor_version); 116 dprintf("SATP: 0x%016" B_PRIx64 "\n", satp); 117 118 // Attempt to fetch the memory map and exit boot services. 119 // This needs to be done in a loop, as ExitBootServices can change the 120 // memory map. 121 // Even better: Only GetMemoryMap and ExitBootServices can be called after 122 // the first call to ExitBootServices, as the firmware is permitted to 123 // partially exit. This is why twice as much space was allocated for the 124 // memory map, as it's impossible to allocate more now. 125 // A changing memory map shouldn't affect the generated page tables, as 126 // they only needed to know about the maximum address, not any specific 127 // entry. 128 dprintf("Calling ExitBootServices. So long, EFI!\n"); 129 while (true) { 130 if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) { 131 // The console was provided by boot services, disable it. 132 stdout = NULL; 133 stderr = NULL; 134 // Also switch to legacy serial output 135 // (may not work on all systems) 136 serial_switch_to_legacy(); 137 dprintf("Switched to legacy serial output\n"); 138 break; 139 } 140 141 memory_map_size = actual_memory_map_size; 142 if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key, 143 &descriptor_size, &descriptor_version) != EFI_SUCCESS) { 144 panic("Unable to fetch system memory map."); 145 } 146 } 147 148 arch_traps_init(); 149 150 // Update EFI, generate final kernel physical memory map, etc. 151 arch_mmu_post_efi_setup(memory_map_size, memory_map, 152 descriptor_size, descriptor_version); 153 154 dprintf("[PRE] SetSatp()\n"); 155 SetSatp(satp); 156 dprintf("[POST] SetSatp()\n"); 157 FlushTlbAll(); 158 dprintf("[POST] FlushTlbAll()\n"); 159 160 // Copy final kernel args 161 // This should be the last step before jumping to the kernel 162 // as there are some fixups happening to kernel_args even in the last minute 163 memcpy(kernelArgs, &gKernelArgs, sizeof(struct kernel_args)); 164 165 smp_boot_other_cpus(satp, kernelEntry, virtKernelArgs); 166 167 // Enter the kernel! 168 dprintf("arch_enter_kernel(satp: %#" B_PRIxADDR ", kernelArgs: %#" B_PRIxADDR 169 ", kernelEntry: %#" B_PRIxADDR ", sp: %#" B_PRIxADDR ")\n", satp, 170 (addr_t)&kernelArgs, (addr_t)kernelEntry, kernelArgs->cpu_kstack[0].start 171 + kernelArgs->cpu_kstack[0].size); 172 173 arch_enter_kernel(satp, virtKernelArgs, kernelEntry, 174 kernelArgs->cpu_kstack[0].start + kernelArgs->cpu_kstack[0].size); 175 } 176