xref: /haiku/src/system/boot/platform/efi/arch/arm/arch_start.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2019-2020 Haiku, Inc. All rights reserved.
3  * Released under the terms of the MIT License.
4  */
5 
6 
7 #include <kernel.h>
8 #include <boot/platform.h>
9 #include <boot/stage2.h>
10 #include <boot/stdio.h>
11 
12 #include "efi_platform.h"
13 
14 
15 #define ALIGN_MEMORY_MAP	4
16 
17 
18 extern "C" void arch_enter_kernel(uint32_t ttbr, struct kernel_args *kernelArgs,
19 	addr_t kernelEntry, addr_t kernelStackTop);
20 
21 // From arch_mmu.cpp
22 extern void arch_mmu_post_efi_setup(size_t memory_map_size,
23 	efi_memory_descriptor *memory_map, size_t descriptor_size,
24 	uint32_t descriptor_version);
25 
26 extern uint32_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size,
27 	efi_memory_descriptor *memory_map, size_t descriptor_size,
28 	uint32_t descriptor_version);
29 
30 
31 static const char*
32 memory_region_type_str(int type)
33 {
34 	switch (type)	{
35 	case EfiReservedMemoryType:
36 		return "ReservedMemoryType";
37 	case EfiLoaderCode:
38 		return "LoaderCode";
39 	case EfiLoaderData:
40 		return "LoaderData";
41 	case EfiBootServicesCode:
42 		return "BootServicesCode";
43 	case EfiBootServicesData:
44 		return "BootServicesData";
45 	case EfiRuntimeServicesCode:
46 		return "RuntimeServicesCode";
47 	case EfiRuntimeServicesData:
48 		return "RuntimeServicesData";
49 	case EfiConventionalMemory:
50 		return "ConventionalMemory";
51 	case EfiUnusableMemory:
52 		return "UnusableMemory";
53 	case EfiACPIReclaimMemory:
54 		return "ACPIReclaimMemory";
55 	case EfiACPIMemoryNVS:
56 		return "ACPIMemoryNVS";
57 	case EfiMemoryMappedIO:
58 		return "MMIO";
59 	case EfiMemoryMappedIOPortSpace:
60 		return "MMIOPortSpace";
61 	case EfiPalCode:
62 		return "PalCode";
63 	case EfiPersistentMemory:
64 		return "PersistentMemory";
65 	default:
66 		return "unknown";
67 	}
68 }
69 
70 
71 void
72 arch_start_kernel(addr_t kernelEntry)
73 {
74 	// Prepare to exit EFI boot services.
75 	// Read the memory map.
76 	// First call is to determine the buffer size.
77 	size_t memory_map_size = 0;
78 	efi_memory_descriptor dummy;
79 	efi_memory_descriptor *memory_map;
80 	size_t map_key;
81 	size_t descriptor_size;
82 	uint32_t descriptor_version;
83 	if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key,
84 			&descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) {
85 		panic("Unable to determine size of system memory map");
86 	}
87 
88 	// Allocate a buffer twice as large as needed just in case it gets bigger
89 	// between calls to ExitBootServices.
90 	size_t actual_memory_map_size = memory_map_size * 2;
91 	memory_map
92 		= (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size +
93 			ALIGN_MEMORY_MAP);
94 
95 	// align memory_map to 4-byte boundary
96 	// otherwise we get alignment exception when calling GetMemoryMap below
97 	memory_map = (efi_memory_descriptor *)ROUNDUP((uint32_t)memory_map, ALIGN_MEMORY_MAP);
98 
99 	if (memory_map == NULL)
100 		panic("Unable to allocate memory map.");
101 
102 	// Read (and print) the memory map.
103 	memory_map_size = actual_memory_map_size;
104 	if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
105 			&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
106 		panic("Unable to fetch system memory map.");
107 	}
108 
109 	addr_t addr = (addr_t)memory_map;
110 	dprintf("System provided memory map:\n");
111 	for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) {
112 		efi_memory_descriptor *entry
113 			= (efi_memory_descriptor *)(addr + i * descriptor_size);
114 		dprintf("  phys: 0x%08llx-0x%08llx, virt: 0x%08llx-0x%08llx, type: %s (%#x), attr: %#llx\n",
115 			entry->PhysicalStart,
116 			entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE,
117 			entry->VirtualStart,
118 			entry->VirtualStart + entry->NumberOfPages * B_PAGE_SIZE,
119 			memory_region_type_str(entry->Type), entry->Type,
120 			entry->Attribute);
121 	}
122 
123 	// Generate page tables for use after ExitBootServices.
124 	uint32_t final_ttbr0 = arch_mmu_generate_post_efi_page_tables(
125 		memory_map_size, memory_map, descriptor_size, descriptor_version);
126 
127 	// Attempt to fetch the memory map and exit boot services.
128 	// This needs to be done in a loop, as ExitBootServices can change the
129 	// memory map.
130 	// Even better: Only GetMemoryMap and ExitBootServices can be called after
131 	// the first call to ExitBootServices, as the firmware is permitted to
132 	// partially exit. This is why twice as much space was allocated for the
133 	// memory map, as it's impossible to allocate more now.
134 	// A changing memory map shouldn't affect the generated page tables, as
135 	// they only needed to know about the maximum address, not any specific
136 	// entry.
137 	dprintf("Calling ExitBootServices. So long, EFI!\n");
138 	while (true) {
139 		if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
140 			// The console was provided by boot services, disable it.
141 			stdout = NULL;
142 			stderr = NULL;
143 			// Can we adjust gKernelArgs.platform_args.serial_base_ports[0]
144 			// to something fixed in qemu for debugging?
145 			break;
146 		}
147 
148 		memory_map_size = actual_memory_map_size;
149 		if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
150 				&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
151 			panic("Unable to fetch system memory map.");
152 		}
153 	}
154 
155 	// Update EFI, generate final kernel physical memory map, etc.
156 	arch_mmu_post_efi_setup(memory_map_size, memory_map,
157 			descriptor_size, descriptor_version);
158 
159 	//smp_boot_other_cpus(final_pml4, kernelEntry);
160 
161 	// Enter the kernel!
162 	dprintf("arch_enter_kernel(ttbr0: 0x%08x, kernelArgs: 0x%08x, "
163 		"kernelEntry: 0x%08x, sp: 0x%08x)\n",
164 		final_ttbr0, (uint32_t)&gKernelArgs, (uint32_t)&kernelEntry,
165 		(uint32_t)(gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size));
166 
167 	arch_enter_kernel(final_ttbr0, &gKernelArgs, kernelEntry,
168 		gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size);
169 }
170