1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdint.h>
7 #include <stddef.h>
8 #include <string.h>
9 #include "efi.h"
10 #include "printf.h"
11 #include <zefi-segments.h>
12 #include <zephyr/arch/x86/efi.h>
13 
14 #define PUTCHAR_BUFSZ 128
15 
16 /* EFI GUID for RSDP
17  * See "Finding the RSDP on UEFI Enabled Systems" in ACPI specs.
18  */
19 #define ACPI_1_0_RSDP_EFI_GUID						\
20 	{								\
21 		.Data1 = 0xeb9d2d30,					\
22 		.Data2 = 0x2d88,					\
23 		.Data3 = 0x11d3,					\
24 		.Data4 = { 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }, \
25 	}
26 
27 #define ACPI_2_0_RSDP_EFI_GUID						\
28 	{								\
29 		.Data1 = 0x8868e871,					\
30 		.Data2 = 0xe4f1,					\
31 		.Data3 = 0x11d3,					\
32 		.Data4 = { 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 }, \
33 	}
34 
35 #define EFI_LOADED_IMAGE_PROTOCOL_GUID					\
36 	{								\
37 		.Data1 = 0x5b1b31a1,					\
38 		.Data2 = 0x9562,					\
39 		.Data3 = 0x11d2,					\
40 		.Data4 = { 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
41 	}
42 
43 /* The linker places this dummy last in the data memory.  We can't use
44  * traditional linker address symbols because we're relocatable; the
45  * linker doesn't know what the runtime address will be.  The compiler
46  * has to emit code to find this thing's address at runtime via an
47  * offset from RIP.  It's a qword so we can guarantee alignment of the
48  * stuff after.
49  */
50 static __attribute__((section(".runtime_data_end")))
51 uint64_t runtime_data_end[1] = { 0x1111aa8888aa1111L };
52 
53 #define EXT_DATA_START ((void *) &runtime_data_end[1])
54 
55 static struct efi_system_table *efi;
56 static struct efi_boot_arg efi_arg;
57 
efi_putchar(int c)58 static void efi_putchar(int c)
59 {
60 	static uint16_t efibuf[PUTCHAR_BUFSZ + 1];
61 	static int n;
62 
63 	if (c == '\n') {
64 		efi_putchar('\r');
65 	}
66 
67 	efibuf[n] = c;
68 	++n;
69 
70 	if (c == '\n' || n == PUTCHAR_BUFSZ) {
71 		efibuf[n] = 0U;
72 		efi->ConOut->OutputString(efi->ConOut, efibuf);
73 		n = 0;
74 	}
75 }
76 
efi_guid_compare(efi_guid_t * s1,efi_guid_t * s2)77 static inline bool efi_guid_compare(efi_guid_t *s1, efi_guid_t *s2)
78 {
79 	return ((s1->Part1 == s2->Part1) && (s1->Part2 == s2->Part2));
80 }
81 
efi_config_get_vendor_table_by_guid(efi_guid_t * guid)82 static void *efi_config_get_vendor_table_by_guid(efi_guid_t *guid)
83 {
84 	struct efi_configuration_table *ect_tmp;
85 	int n_ct;
86 
87 	if (efi == NULL) {
88 		return NULL;
89 	}
90 
91 	ect_tmp = efi->ConfigurationTable;
92 
93 	for (n_ct = 0; n_ct < efi->NumberOfTableEntries; n_ct++) {
94 		if (efi_guid_compare(&ect_tmp->VendorGuid, guid)) {
95 			return ect_tmp->VendorTable;
96 		}
97 
98 		ect_tmp++;
99 	}
100 
101 	return NULL;
102 }
103 
efi_prepare_boot_arg(void)104 static void efi_prepare_boot_arg(void)
105 {
106 	efi_guid_t rsdp_guid_1 = ACPI_1_0_RSDP_EFI_GUID;
107 	efi_guid_t rsdp_guid_2 = ACPI_2_0_RSDP_EFI_GUID;
108 
109 	/* Let's lookup for most recent ACPI table first */
110 	efi_arg.acpi_rsdp = efi_config_get_vendor_table_by_guid(&rsdp_guid_2);
111 	if (efi_arg.acpi_rsdp == NULL) {
112 		efi_arg.acpi_rsdp =
113 			efi_config_get_vendor_table_by_guid(&rsdp_guid_1);
114 	}
115 
116 	if (efi_arg.acpi_rsdp != NULL) {
117 		printf("RSDP found at %p\n", efi_arg.acpi_rsdp);
118 	}
119 }
120 
121 /* Existing x86_64 EFI environments have a bad habit of leaving the
122  * HPET timer running.  This then fires later on, once the OS has
123  * started.  If the timing isn't right, it can happen before the OS
124  * HPET driver gets a chance to disable it.  And because we do the
125  * handoff (necessarily) with interrupts disabled, it's not actually
126  * possible for the OS to reliably disable it in time anyway.
127  *
128  * Basically: it's our job as the bootloader to ensure that no
129  * interrupt sources are live before entering the OS. Clear the
130  * interrupt enable bit of HPET timer zero.
131  */
disable_hpet(void)132 static void disable_hpet(void)
133 {
134 	uint64_t *hpet = (uint64_t *)0xfed00000L;
135 
136 	hpet[32] &= ~4;
137 }
138 
139 /* FIXME: if you check the generated code, "ms_abi" calls like this
140  * have to SPILL HALF OF THE SSE REGISTER SET TO THE STACK on entry
141  * because of the way the conventions collide.  Is there a way to
142  * prevent/suppress that?
143  */
efi_entry(void * img_handle,struct efi_system_table * sys_tab)144 uintptr_t __abi efi_entry(void *img_handle, struct efi_system_table *sys_tab)
145 {
146 #ifndef CONFIG_DYNAMIC_BOOTARGS
147 	(void)img_handle;
148 #endif /* CONFIG_DYNAMIC_BOOTARGS */
149 
150 	efi = sys_tab;
151 	z_putchar = efi_putchar;
152 	printf("*** Zephyr EFI Loader ***\n");
153 
154 	efi_prepare_boot_arg();
155 
156 	for (int i = 0; i < sizeof(zefi_zsegs)/sizeof(zefi_zsegs[0]); i++) {
157 		int bytes = zefi_zsegs[i].sz;
158 		uint8_t *dst = (uint8_t *)zefi_zsegs[i].addr;
159 
160 		printf("Zeroing %d bytes of memory at %p\n", bytes, dst);
161 		for (int j = 0; j < bytes; j++) {
162 			dst[j] = 0U;
163 		}
164 	}
165 
166 	for (int i = 0; i < sizeof(zefi_dsegs)/sizeof(zefi_dsegs[0]); i++) {
167 		int bytes = zefi_dsegs[i].sz;
168 		int off = zefi_dsegs[i].off;
169 		uint8_t *dst = (uint8_t *)zefi_dsegs[i].addr;
170 		uint8_t *src = &((uint8_t *)EXT_DATA_START)[off];
171 
172 		printf("Copying %d data bytes to %p from image offset %d\n",
173 		       bytes, dst, zefi_dsegs[i].off);
174 		for (int j = 0; j < bytes; j++) {
175 			dst[j] = src[j];
176 		}
177 
178 		/* Page-aligned blocks below 1M are the .locore
179 		 * section, which has a jump in its first bytes for
180 		 * the benefit of 32 bit entry.  Those have to be
181 		 * written over with NOP instructions. (See comment
182 		 * about OUTRAGEOUS HACK in locore.S) before Zephyr
183 		 * starts, because the very first thing it does is
184 		 * install its own page table that disallows writes.
185 		 */
186 		if (((long)dst & 0xfff) == 0 && dst < (uint8_t *)0x100000L) {
187 			for (int i = 0; i < 8; i++) {
188 				dst[i] = 0x90; /* 0x90 == 1-byte NOP */
189 			}
190 		}
191 	}
192 
193 #ifdef CONFIG_DYNAMIC_BOOTARGS
194 	char *dst_bootargs = (char *)zefi_bootargs;
195 	struct efi_loaded_image_protocol *loaded_image;
196 	efi_guid_t loaded_image_protocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
197 	efi_status_t loaded_image_status = sys_tab->BootServices->HandleProtocol(
198 		img_handle,
199 		&loaded_image_protocol,
200 		(void **)&loaded_image
201 	);
202 
203 	if (loaded_image_status == EFI_SUCCESS) {
204 		uint16_t *src_bootargs = (uint16_t *)loaded_image->LoadOptions;
205 
206 		while (*src_bootargs != '\0' &&
207 		       dst_bootargs + 1 <
208 			       (char *)zefi_bootargs + CONFIG_BOOTARGS_ARGS_BUFFER_SIZE) {
209 			*dst_bootargs++ = *src_bootargs++ & 0x7f;
210 		}
211 		*dst_bootargs = '\0';
212 	} else {
213 		*dst_bootargs = '\0';
214 	}
215 #endif /* CONFIG_DYNAMIC_BOOTARGS */
216 
217 	unsigned char *code = (void *)zefi_entry;
218 
219 	efi_arg.efi_systab = efi;
220 	__asm__ volatile("movq %%cr3, %0" : "=r"(efi_arg.efi_cr3));
221 
222 	printf("Jumping to Entry Point: %p (%x %x %x %x %x %x %x)\n",
223 	       code, code[0], code[1], code[2], code[3],
224 	       code[4], code[5], code[6]);
225 
226 	disable_hpet();
227 
228 	/* The EFI console seems to be buffered, give it a little time
229 	 * to drain before we start banging on the same UART from the
230 	 * OS.
231 	 */
232 	for (volatile int i = 0; i < 50000000; i++) {
233 	}
234 
235 	__asm__ volatile("cli; movq %0, %%rbx; jmp *%1"
236 			 :: "r"(&efi_arg), "r"(code) : "rbx");
237 
238 	return 0;
239 }
240 
241 /* Trick cribbed shamelessly from gnu-efi.  We need to emit a ".reloc"
242  * section into the image with a single dummy entry for the EFI loader
243  * to think we're a valid PE file, gcc won't because it thinks we're
244  * ELF.
245  */
246 uint32_t relocation_dummy;
247 __asm__(".section .reloc\n"
248 	"base_relocation_block:\n"
249 	".long relocation_dummy - base_relocation_block\n"
250 	".long 0x0a\n"
251 	".word	0\n");
252