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