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