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 "efi_platform.h"
12#include "generic_mmu.h"
13#include "mmu.h"
14#include "serial.h"
15
16#include "aarch64.h"
17
18extern "C" void arch_enter_kernel(
19	struct kernel_args* kernelArgs, addr_t kernelEntry, addr_t kernelStackTop);
20
21extern const char* granule_type_str(int tg);
22
23extern uint32_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size,
24	efi_memory_descriptor* memory_map, size_t descriptor_size, uint32_t descriptor_version);
25
26extern void arch_mmu_post_efi_setup(size_t memory_map_size, efi_memory_descriptor* memory_map,
27	size_t descriptor_size, uint32_t descriptor_version);
28
29extern void arch_mmu_setup_EL1(uint64 tcr);
30
31
32void
33arch_convert_kernel_args(void)
34{
35	fix_address(gKernelArgs.arch_args.fdt);
36}
37
38
39void
40arch_start_kernel(addr_t kernelEntry)
41{
42	// Prepare to exit EFI boot services.
43	// Read the memory map.
44	// First call is to determine the buffer size.
45	size_t memory_map_size = 0;
46	efi_memory_descriptor dummy;
47	efi_memory_descriptor* memory_map;
48	size_t map_key;
49	size_t descriptor_size;
50	uint32_t descriptor_version;
51	if (kBootServices->GetMemoryMap(
52			&memory_map_size, &dummy, &map_key, &descriptor_size, &descriptor_version)
53		!= 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 = (efi_memory_descriptor*) kernel_args_malloc(actual_memory_map_size);
61
62	if (memory_map == NULL)
63		panic("Unable to allocate memory map.");
64
65	// Read (and print) the memory map.
66	memory_map_size = actual_memory_map_size;
67	if (kBootServices->GetMemoryMap(
68			&memory_map_size, memory_map, &map_key, &descriptor_size, &descriptor_version)
69		!= EFI_SUCCESS) {
70		panic("Unable to fetch system memory map.");
71	}
72
73	addr_t addr = (addr_t) memory_map;
74	efi_physical_addr loaderCode = 0LL;
75	dprintf("System provided memory map:\n");
76	for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) {
77		efi_memory_descriptor* entry = (efi_memory_descriptor*) (addr + i * descriptor_size);
78		dprintf("  phys: 0x%0lx-0x%0lx, virt: 0x%0lx-0x%0lx, size = 0x%0lx, type: %s (%#x), attr: "
79				"%#lx\n",
80			entry->PhysicalStart, entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE,
81			entry->VirtualStart, entry->VirtualStart + entry->NumberOfPages * B_PAGE_SIZE,
82			entry->NumberOfPages * B_PAGE_SIZE, memory_region_type_str(entry->Type), entry->Type,
83			entry->Attribute);
84		if (entry->Type == EfiLoaderCode)
85			loaderCode = entry->PhysicalStart;
86	}
87	// This is where our efi loader got relocated, therefore we need to use this
88	// offset for properly align symbols
89	dprintf("Efi loader symbols offset: 0x%0lx:\n", loaderCode);
90
91	/*
92	*   "The AArch64 exception model is made up of a number of exception levels
93	*    (EL0 - EL3), with EL0 and EL1 having a secure and a non-secure
94	*    counterpart.  EL2 is the hypervisor level and exists only in non-secure
95	*    mode. EL3 is the highest priority level and exists only in secure mode."
96	*
97	*	"2.3 UEFI System Environment and Configuration
98	*    The resident UEFI boot-time environment shall use the highest non-secure
99	*    privilege level available. The exact meaning of this is architecture
100	*    dependent, as detailed below."
101
102	*	"2.3.1 AArch64 Exception Levels
103	*    On AArch64 UEFI shall execute as 64-bit code at either EL1 or EL2,
104	*    depending on whether or not virtualization is available at OS load time."
105	*/
106	uint64 el = arch_exception_level();
107	dprintf("Current Exception Level EL%1lx\n", el);
108	dprintf("TTBR0: %" B_PRIx64 " TTBRx: %" B_PRIx64 " SCTLR: %" B_PRIx64 " TCR: %" B_PRIx64 "\n",
109		arch_mmu_base_register(), arch_mmu_base_register(true), _arch_mmu_get_sctlr(),
110		_arch_mmu_get_tcr());
111
112	if (arch_mmu_enabled()) {
113		dprintf("MMU Enabled, Granularity %s, bits %d\n", granule_type_str(arch_mmu_user_granule()),
114			arch_mmu_user_address_bits());
115
116		dprintf("Kernel entry accessibility W: %x R: %x\n", arch_mmu_write_access(kernelEntry),
117			arch_mmu_read_access(kernelEntry));
118
119		if (el == 1) {
120			// Disable CACHE & MMU before dealing with TTBRx
121			arch_cache_disable();
122		}
123	}
124
125	// Generate page tables for use after ExitBootServices.
126	arch_mmu_generate_post_efi_page_tables(
127		memory_map_size, memory_map, descriptor_size, descriptor_version);
128
129	// Attempt to fetch the memory map and exit boot services.
130	// This needs to be done in a loop, as ExitBootServices can change the
131	// memory map.
132	// Even better: Only GetMemoryMap and ExitBootServices can be called after
133	// the first call to ExitBootServices, as the firmware is permitted to
134	// partially exit. This is why twice as much space was allocated for the
135	// memory map, as it's impossible to allocate more now.
136	// A changing memory map shouldn't affect the generated page tables, as
137	// they only needed to know about the maximum address, not any specific
138	// entry.
139
140	dprintf("Calling ExitBootServices. So long, EFI!\n");
141	serial_disable();
142
143	while (true) {
144		if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
145			// Disconnect from EFI serial_io / stdio services
146			serial_kernel_handoff();
147			dprintf("Unhooked from EFI serial services\n");
148			break;
149		}
150
151		memory_map_size = actual_memory_map_size;
152		if (kBootServices->GetMemoryMap(
153				&memory_map_size, memory_map, &map_key, &descriptor_size, &descriptor_version)
154			!= EFI_SUCCESS) {
155			panic("Unable to fetch system memory map.");
156		}
157	}
158
159	// Update EFI, generate final kernel physical memory map, etc.
160	arch_mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size, descriptor_version);
161
162	// Re-init and activate serial in a horrific post-EFI landscape. Clowns roam the land freely.
163	serial_init();
164	serial_enable();
165
166	switch (el) {
167		case 1:
168			arch_mmu_setup_EL1(READ_SPECIALREG(TCR_EL1));
169			break;
170		case 2:
171			arch_mmu_setup_EL1(READ_SPECIALREG(TCR_EL2));
172			arch_cache_disable();
173			_arch_transition_EL2_EL1();
174			break;
175		default:
176			panic("Unexpected Exception Level\n");
177			break;
178	}
179
180	arch_cache_enable();
181
182	// smp_boot_other_cpus(final_pml4, kernelEntry, (addr_t)&gKernelArgs);
183
184	if (arch_mmu_read_access(kernelEntry)
185		&& arch_mmu_read_access(gKernelArgs.cpu_kstack[0].start)) {
186		// Enter the kernel!
187		arch_enter_kernel(&gKernelArgs, kernelEntry,
188			gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size);
189	} else {
190		// _arch_exception_panic("Kernel or Stack memory not accessible\n", __LINE__);
191		panic("Kernel or Stack memory not accessible\n");
192	}
193}
194