xref: /haiku/src/system/boot/platform/efi/arch/riscv64/arch_start.cpp (revision 9e25244c5e9051f6cd333820d6332397361abd6c)
1 /*
2  * Copyright 2019-2021 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, struct kernel_args *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 	// empty
41 }
42 
43 
44 void
45 arch_start_kernel(addr_t kernelEntry)
46 {
47 	// EFI assumed to be SBI booted
48 	gKernelArgs.arch_args.machine_platform = kPlatformSbi;
49 
50 	// Prepare to exit EFI boot services.
51 	// Read the memory map.
52 	// First call is to determine the buffer size.
53 	size_t memory_map_size = 0;
54 	efi_memory_descriptor dummy;
55 	efi_memory_descriptor *memory_map;
56 	size_t map_key;
57 	size_t descriptor_size;
58 	uint32_t descriptor_version;
59 	if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key,
60 		&descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) {
61 		panic("Unable to determine size of system memory map");
62 	}
63 
64 	// Allocate a buffer twice as large as needed just in case it gets bigger
65 	// between calls to ExitBootServices.
66 	size_t actual_memory_map_size = memory_map_size * 2;
67 	memory_map
68 		= (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size);
69 
70 	if (memory_map == NULL)
71 		panic("Unable to allocate memory map.");
72 
73 	// Read (and print) the memory map.
74 	memory_map_size = actual_memory_map_size;
75 	if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
76 		&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
77 		panic("Unable to fetch system memory map.");
78 	}
79 
80 	addr_t addr = (addr_t)memory_map;
81 	dprintf("System provided memory map:\n");
82 	for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) {
83 		efi_memory_descriptor *entry
84 			= (efi_memory_descriptor *)(addr + i * descriptor_size);
85 		dprintf("  phys: %#lx, virt: %#lx, size: %#lx, ",
86 			entry->PhysicalStart, entry->VirtualStart,
87 			entry->NumberOfPages * B_PAGE_SIZE);
88 		switch (entry->Type) {
89 		case EfiReservedMemoryType:  dprintf("reservedMemoryType"); break;
90 		case EfiLoaderCode:          dprintf("loaderCode"); break;
91 		case EfiLoaderData:          dprintf("loaderData"); break;
92 		case EfiBootServicesCode:    dprintf("bootServicesCode"); break;
93 		case EfiBootServicesData:    dprintf("bootServicesData"); break;
94 		case EfiConventionalMemory:  dprintf("conventionalMemory"); break;
95 		case EfiACPIReclaimMemory:   dprintf("ACPIReclaimMemory"); break;
96 		case EfiRuntimeServicesCode: dprintf("runtimeServicesCode"); break;
97 		case EfiRuntimeServicesData: dprintf("runtimeServicesData"); break;
98 		default: dprintf("?(%d)", entry->Type);
99 		}
100 		dprintf(", attrs: %#lx\n", entry->Attribute);
101 	}
102 
103 	// Generate page tables for use after ExitBootServices.
104 	uint64_t satp = arch_mmu_generate_post_efi_page_tables(
105 		memory_map_size, memory_map, descriptor_size, descriptor_version);
106 	dprintf("SATP: 0x%016" B_PRIx64 "\n", satp);
107 
108 	// Attempt to fetch the memory map and exit boot services.
109 	// This needs to be done in a loop, as ExitBootServices can change the
110 	// memory map.
111 	// Even better: Only GetMemoryMap and ExitBootServices can be called after
112 	// the first call to ExitBootServices, as the firmware is permitted to
113 	// partially exit. This is why twice as much space was allocated for the
114 	// memory map, as it's impossible to allocate more now.
115 	// A changing memory map shouldn't affect the generated page tables, as
116 	// they only needed to know about the maximum address, not any specific
117 	// entry.
118 	dprintf("Calling ExitBootServices. So long, EFI!\n");
119 	while (true) {
120 		if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
121 			// The console was provided by boot services, disable it.
122 			stdout = NULL;
123 			stderr = NULL;
124 			// Also switch to legacy serial output
125 			// (may not work on all systems)
126 			serial_switch_to_legacy();
127 			dprintf("Switched to legacy serial output\n");
128 			break;
129 		}
130 
131 		memory_map_size = actual_memory_map_size;
132 		if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
133 				&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
134 			panic("Unable to fetch system memory map.");
135 		}
136 	}
137 
138 	arch_traps_init();
139 
140 	// Update EFI, generate final kernel physical memory map, etc.
141 	arch_mmu_post_efi_setup(memory_map_size, memory_map,
142 			descriptor_size, descriptor_version);
143 
144 	dprintf("[PRE] SetSatp()\n");
145 	SetSatp(satp);
146 	dprintf("[POST] SetSatp()\n");
147 	FlushTlbAll();
148 	dprintf("[POST] FlushTlbAll()\n");
149 
150 	smp_boot_other_cpus(satp, kernelEntry);
151 
152 	// Enter the kernel!
153 	dprintf("arch_enter_kernel(satp: %#" B_PRIxADDR ", kernelArgs: %#" B_PRIxADDR
154 		", kernelEntry: %#" B_PRIxADDR ", sp: %#" B_PRIxADDR ")\n",	satp,
155 		(addr_t)&gKernelArgs, (addr_t)kernelEntry, gKernelArgs.cpu_kstack[0].start
156 			+ gKernelArgs.cpu_kstack[0].size);
157 
158 	arch_enter_kernel(satp, &gKernelArgs, kernelEntry,
159 		gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size);
160 }
161