xref: /haiku/src/system/boot/platform/efi/arch/riscv64/arch_start.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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