xref: /openbmc/u-boot/arch/x86/cpu/efi/payload.c (revision 53287a89e90a842f7265446be89c3c6b2aff3271)
14f1dacd4SBin Meng // SPDX-License-Identifier: GPL-2.0+
24f1dacd4SBin Meng /*
34f1dacd4SBin Meng  * Copyright (c) 2015 Google, Inc
44f1dacd4SBin Meng  * Written by Simon Glass <sjg@chromium.org>
54f1dacd4SBin Meng  */
64f1dacd4SBin Meng 
74f1dacd4SBin Meng #include <common.h>
84f1dacd4SBin Meng #include <efi.h>
94f1dacd4SBin Meng #include <errno.h>
101ab2c010SBin Meng #include <usb.h>
111fdeacd3SBin Meng #include <asm/bootparam.h>
12aac79251SBin Meng #include <asm/e820.h>
133773c6a2SBin Meng #include <asm/post.h>
144f1dacd4SBin Meng 
154f1dacd4SBin Meng DECLARE_GLOBAL_DATA_PTR;
164f1dacd4SBin Meng 
174f1dacd4SBin Meng /*
184f1dacd4SBin Meng  * This function looks for the highest region of memory lower than 4GB which
194f1dacd4SBin Meng  * has enough space for U-Boot where U-Boot is aligned on a page boundary.
204f1dacd4SBin Meng  * It overrides the default implementation found elsewhere which simply
214f1dacd4SBin Meng  * picks the end of ram, wherever that may be. The location of the stack,
224f1dacd4SBin Meng  * the relocation address, and how far U-Boot is moved by relocation are
234f1dacd4SBin Meng  * set in the global data structure.
244f1dacd4SBin Meng  */
board_get_usable_ram_top(ulong total_size)254f1dacd4SBin Meng ulong board_get_usable_ram_top(ulong total_size)
264f1dacd4SBin Meng {
274f1dacd4SBin Meng 	struct efi_mem_desc *desc, *end;
284f1dacd4SBin Meng 	struct efi_entry_memmap *map;
294f1dacd4SBin Meng 	int ret, size;
304f1dacd4SBin Meng 	uintptr_t dest_addr = 0;
314f1dacd4SBin Meng 	struct efi_mem_desc *largest = NULL;
324f1dacd4SBin Meng 
334f1dacd4SBin Meng 	/*
344f1dacd4SBin Meng 	 * Find largest area of memory below 4GB. We could
354f1dacd4SBin Meng 	 * call efi_build_mem_table() for a more accurate picture since it
364f1dacd4SBin Meng 	 * merges areas together where possible. But that function uses more
374f1dacd4SBin Meng 	 * pre-relocation memory, and it's not critical that we find the
384f1dacd4SBin Meng 	 * absolute largest region.
394f1dacd4SBin Meng 	 */
404f1dacd4SBin Meng 	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
414f1dacd4SBin Meng 	if (ret) {
424f1dacd4SBin Meng 		/* We should have stopped in dram_init(), something is wrong */
434f1dacd4SBin Meng 		debug("%s: Missing memory map\n", __func__);
444f1dacd4SBin Meng 		goto err;
454f1dacd4SBin Meng 	}
464f1dacd4SBin Meng 
474f1dacd4SBin Meng 	end = (struct efi_mem_desc *)((ulong)map + size);
484f1dacd4SBin Meng 	desc = map->desc;
494f1dacd4SBin Meng 	for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
504f1dacd4SBin Meng 		if (desc->type != EFI_CONVENTIONAL_MEMORY ||
514f1dacd4SBin Meng 		    desc->physical_start >= 1ULL << 32)
524f1dacd4SBin Meng 			continue;
534f1dacd4SBin Meng 		if (!largest || desc->num_pages > largest->num_pages)
544f1dacd4SBin Meng 			largest = desc;
554f1dacd4SBin Meng 	}
564f1dacd4SBin Meng 
574f1dacd4SBin Meng 	/* If no suitable area was found, return an error. */
584f1dacd4SBin Meng 	assert(largest);
594f1dacd4SBin Meng 	if (!largest || (largest->num_pages << EFI_PAGE_SHIFT) < (2 << 20))
604f1dacd4SBin Meng 		goto err;
614f1dacd4SBin Meng 
624f1dacd4SBin Meng 	dest_addr = largest->physical_start + (largest->num_pages <<
634f1dacd4SBin Meng 			EFI_PAGE_SHIFT);
644f1dacd4SBin Meng 
654f1dacd4SBin Meng 	return (ulong)dest_addr;
664f1dacd4SBin Meng err:
674f1dacd4SBin Meng 	panic("No available memory found for relocation");
684f1dacd4SBin Meng 	return 0;
694f1dacd4SBin Meng }
704f1dacd4SBin Meng 
dram_init(void)714f1dacd4SBin Meng int dram_init(void)
724f1dacd4SBin Meng {
734f1dacd4SBin Meng 	struct efi_mem_desc *desc, *end;
744f1dacd4SBin Meng 	struct efi_entry_memmap *map;
754f1dacd4SBin Meng 	int size, ret;
764f1dacd4SBin Meng 
774f1dacd4SBin Meng 	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
784f1dacd4SBin Meng 	if (ret) {
794f1dacd4SBin Meng 		printf("Cannot find EFI memory map tables, ret=%d\n", ret);
804f1dacd4SBin Meng 
814f1dacd4SBin Meng 		return -ENODEV;
824f1dacd4SBin Meng 	}
834f1dacd4SBin Meng 
844f1dacd4SBin Meng 	end = (struct efi_mem_desc *)((ulong)map + size);
854f1dacd4SBin Meng 	gd->ram_size = 0;
864f1dacd4SBin Meng 	desc = map->desc;
874f1dacd4SBin Meng 	for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
884f1dacd4SBin Meng 		if (desc->type < EFI_MMAP_IO)
894f1dacd4SBin Meng 			gd->ram_size += desc->num_pages << EFI_PAGE_SHIFT;
904f1dacd4SBin Meng 	}
914f1dacd4SBin Meng 
924f1dacd4SBin Meng 	return 0;
934f1dacd4SBin Meng }
944f1dacd4SBin Meng 
dram_init_banksize(void)954f1dacd4SBin Meng int dram_init_banksize(void)
964f1dacd4SBin Meng {
974f1dacd4SBin Meng 	struct efi_mem_desc *desc, *end;
984f1dacd4SBin Meng 	struct efi_entry_memmap *map;
994f1dacd4SBin Meng 	int ret, size;
1004f1dacd4SBin Meng 	int num_banks;
1014f1dacd4SBin Meng 
1024f1dacd4SBin Meng 	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
1034f1dacd4SBin Meng 	if (ret) {
1044f1dacd4SBin Meng 		/* We should have stopped in dram_init(), something is wrong */
1054f1dacd4SBin Meng 		debug("%s: Missing memory map\n", __func__);
1064f1dacd4SBin Meng 		return -ENXIO;
1074f1dacd4SBin Meng 	}
1084f1dacd4SBin Meng 	end = (struct efi_mem_desc *)((ulong)map + size);
1094f1dacd4SBin Meng 	desc = map->desc;
1104f1dacd4SBin Meng 	for (num_banks = 0;
1114f1dacd4SBin Meng 	     desc < end && num_banks < CONFIG_NR_DRAM_BANKS;
1124f1dacd4SBin Meng 	     desc = efi_get_next_mem_desc(map, desc)) {
1134f1dacd4SBin Meng 		/*
11459837472SBin Meng 		 * We only use conventional memory and ignore
1154f1dacd4SBin Meng 		 * anything less than 1MB.
1164f1dacd4SBin Meng 		 */
1174f1dacd4SBin Meng 		if (desc->type != EFI_CONVENTIONAL_MEMORY ||
1184f1dacd4SBin Meng 		    (desc->num_pages << EFI_PAGE_SHIFT) < 1 << 20)
1194f1dacd4SBin Meng 			continue;
1204f1dacd4SBin Meng 		gd->bd->bi_dram[num_banks].start = desc->physical_start;
1214f1dacd4SBin Meng 		gd->bd->bi_dram[num_banks].size = desc->num_pages <<
1224f1dacd4SBin Meng 			EFI_PAGE_SHIFT;
1234f1dacd4SBin Meng 		num_banks++;
1244f1dacd4SBin Meng 	}
1254f1dacd4SBin Meng 
1264f1dacd4SBin Meng 	return 0;
1274f1dacd4SBin Meng }
1284f1dacd4SBin Meng 
arch_cpu_init(void)1293773c6a2SBin Meng int arch_cpu_init(void)
1303773c6a2SBin Meng {
1313773c6a2SBin Meng 	post_code(POST_CPU_INIT);
1323773c6a2SBin Meng 
1333773c6a2SBin Meng 	return x86_cpu_init_f();
1343773c6a2SBin Meng }
1353773c6a2SBin Meng 
checkcpu(void)1364f1dacd4SBin Meng int checkcpu(void)
1374f1dacd4SBin Meng {
1384f1dacd4SBin Meng 	return 0;
1394f1dacd4SBin Meng }
1404f1dacd4SBin Meng 
print_cpuinfo(void)1414f1dacd4SBin Meng int print_cpuinfo(void)
1424f1dacd4SBin Meng {
1434f1dacd4SBin Meng 	return default_print_cpuinfo();
1444f1dacd4SBin Meng }
1454f1dacd4SBin Meng 
1464f1dacd4SBin Meng /* Find any available tables and copy them to a safe place */
reserve_arch(void)1474f1dacd4SBin Meng int reserve_arch(void)
1484f1dacd4SBin Meng {
1494f1dacd4SBin Meng 	struct efi_info_hdr *hdr;
1504f1dacd4SBin Meng 
1514f1dacd4SBin Meng 	debug("table=%lx\n", gd->arch.table);
1524f1dacd4SBin Meng 	if (!gd->arch.table)
1534f1dacd4SBin Meng 		return 0;
1544f1dacd4SBin Meng 
1554f1dacd4SBin Meng 	hdr = (struct efi_info_hdr *)gd->arch.table;
1564f1dacd4SBin Meng 
1574f1dacd4SBin Meng 	gd->start_addr_sp -= hdr->total_size;
1584f1dacd4SBin Meng 	memcpy((void *)gd->start_addr_sp, hdr, hdr->total_size);
1594f1dacd4SBin Meng 	debug("Stashing EFI table at %lx to %lx, size %x\n",
1604f1dacd4SBin Meng 	      gd->arch.table, gd->start_addr_sp, hdr->total_size);
1614f1dacd4SBin Meng 	gd->arch.table = gd->start_addr_sp;
1624f1dacd4SBin Meng 
1634f1dacd4SBin Meng 	return 0;
1644f1dacd4SBin Meng }
1651ab2c010SBin Meng 
last_stage_init(void)1661ab2c010SBin Meng int last_stage_init(void)
1671ab2c010SBin Meng {
1681ab2c010SBin Meng 	/* start usb so that usb keyboard can be used as input device */
169*d3d65318SBin Meng 	if (CONFIG_IS_ENABLED(USB_KEYBOARD))
1701ab2c010SBin Meng 		usb_init();
1711ab2c010SBin Meng 
1721ab2c010SBin Meng 	return 0;
1731ab2c010SBin Meng }
174aac79251SBin Meng 
install_e820_map(unsigned int max_entries,struct e820_entry * entries)175aac79251SBin Meng unsigned int install_e820_map(unsigned int max_entries,
176aac79251SBin Meng 			      struct e820_entry *entries)
177aac79251SBin Meng {
178aac79251SBin Meng 	struct efi_mem_desc *desc, *end;
179aac79251SBin Meng 	struct efi_entry_memmap *map;
180aac79251SBin Meng 	int size, ret;
181aac79251SBin Meng 	efi_physical_addr_t last_end_addr = 0;
182aac79251SBin Meng 	struct e820_entry *last_entry = NULL;
183aac79251SBin Meng 	__u32 e820_type;
184aac79251SBin Meng 	unsigned int num_entries = 0;
185aac79251SBin Meng 
186aac79251SBin Meng 	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
187aac79251SBin Meng 	if (ret) {
188aac79251SBin Meng 		printf("Cannot find EFI memory map tables, ret=%d\n", ret);
189aac79251SBin Meng 
190aac79251SBin Meng 		return -ENODEV;
191aac79251SBin Meng 	}
192aac79251SBin Meng 
193aac79251SBin Meng 	end = (struct efi_mem_desc *)((ulong)map + size);
194aac79251SBin Meng 	for (desc = map->desc; desc < end;
195aac79251SBin Meng 	     desc = efi_get_next_mem_desc(map, desc)) {
196aac79251SBin Meng 		if (desc->num_pages == 0)
197aac79251SBin Meng 			continue;
198aac79251SBin Meng 
199aac79251SBin Meng 		switch (desc->type) {
200aac79251SBin Meng 		case EFI_LOADER_CODE:
201aac79251SBin Meng 		case EFI_LOADER_DATA:
202aac79251SBin Meng 		case EFI_BOOT_SERVICES_CODE:
203aac79251SBin Meng 		case EFI_BOOT_SERVICES_DATA:
204aac79251SBin Meng 		case EFI_CONVENTIONAL_MEMORY:
205aac79251SBin Meng 			e820_type = E820_RAM;
206aac79251SBin Meng 			break;
207aac79251SBin Meng 
208aac79251SBin Meng 		case EFI_RESERVED_MEMORY_TYPE:
209aac79251SBin Meng 		case EFI_RUNTIME_SERVICES_CODE:
210aac79251SBin Meng 		case EFI_RUNTIME_SERVICES_DATA:
211aac79251SBin Meng 		case EFI_MMAP_IO:
212aac79251SBin Meng 		case EFI_MMAP_IO_PORT:
213aac79251SBin Meng 		case EFI_PAL_CODE:
214aac79251SBin Meng 			e820_type = E820_RESERVED;
215aac79251SBin Meng 			break;
216aac79251SBin Meng 
217aac79251SBin Meng 		case EFI_ACPI_RECLAIM_MEMORY:
218aac79251SBin Meng 			e820_type = E820_ACPI;
219aac79251SBin Meng 			break;
220aac79251SBin Meng 
221aac79251SBin Meng 		case EFI_ACPI_MEMORY_NVS:
222aac79251SBin Meng 			e820_type = E820_NVS;
223aac79251SBin Meng 			break;
224aac79251SBin Meng 
225aac79251SBin Meng 		case EFI_UNUSABLE_MEMORY:
226aac79251SBin Meng 			e820_type = E820_UNUSABLE;
227aac79251SBin Meng 			break;
228aac79251SBin Meng 
229aac79251SBin Meng 		default:
230aac79251SBin Meng 			printf("Invalid EFI memory descriptor type (0x%x)!\n",
231aac79251SBin Meng 			       desc->type);
232aac79251SBin Meng 			continue;
233aac79251SBin Meng 		}
234aac79251SBin Meng 
235aac79251SBin Meng 		if (last_entry != NULL && last_entry->type == e820_type &&
236aac79251SBin Meng 		    desc->physical_start == last_end_addr) {
237aac79251SBin Meng 			last_entry->size += (desc->num_pages << EFI_PAGE_SHIFT);
238aac79251SBin Meng 			last_end_addr += (desc->num_pages << EFI_PAGE_SHIFT);
239aac79251SBin Meng 		} else {
240aac79251SBin Meng 			if (num_entries >= E820MAX)
241aac79251SBin Meng 				break;
242aac79251SBin Meng 
243aac79251SBin Meng 			entries[num_entries].addr = desc->physical_start;
244aac79251SBin Meng 			entries[num_entries].size = desc->num_pages;
245aac79251SBin Meng 			entries[num_entries].size <<= EFI_PAGE_SHIFT;
246aac79251SBin Meng 			entries[num_entries].type = e820_type;
247aac79251SBin Meng 			last_entry = &entries[num_entries];
248aac79251SBin Meng 			last_end_addr = last_entry->addr + last_entry->size;
249aac79251SBin Meng 			num_entries++;
250aac79251SBin Meng 		}
251aac79251SBin Meng 	}
252aac79251SBin Meng 
253aac79251SBin Meng 	return num_entries;
254aac79251SBin Meng }
2551fdeacd3SBin Meng 
setup_efi_info(struct efi_info * efi_info)2561fdeacd3SBin Meng void setup_efi_info(struct efi_info *efi_info)
2571fdeacd3SBin Meng {
2581fdeacd3SBin Meng 	struct efi_entry_systable *table;
2591fdeacd3SBin Meng 	struct efi_entry_memmap *map;
2601fdeacd3SBin Meng 	char *signature;
2611fdeacd3SBin Meng 	int size, ret;
2621fdeacd3SBin Meng 
2631fdeacd3SBin Meng 	memset(efi_info, 0, sizeof(struct efi_info));
2641fdeacd3SBin Meng 
2651fdeacd3SBin Meng 	ret = efi_info_get(EFIET_SYS_TABLE, (void **)&table, &size);
2661fdeacd3SBin Meng 	if (ret) {
2671fdeacd3SBin Meng 		printf("Cannot find EFI system table, ret=%d\n", ret);
2681fdeacd3SBin Meng 		return;
2691fdeacd3SBin Meng 	}
2701fdeacd3SBin Meng 	efi_info->efi_systab = (u32)(table->sys_table);
2711fdeacd3SBin Meng 
2721fdeacd3SBin Meng 	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
2731fdeacd3SBin Meng 	if (ret) {
2741fdeacd3SBin Meng 		printf("Cannot find EFI memory map tables, ret=%d\n", ret);
2751fdeacd3SBin Meng 		return;
2761fdeacd3SBin Meng 	}
2771fdeacd3SBin Meng 	efi_info->efi_memdesc_size = map->desc_size;
2781fdeacd3SBin Meng 	efi_info->efi_memdesc_version = map->version;
2791fdeacd3SBin Meng 	efi_info->efi_memmap = (u32)(map->desc);
2801fdeacd3SBin Meng 	efi_info->efi_memmap_size = size - sizeof(struct efi_entry_memmap);
2811fdeacd3SBin Meng 
2821fdeacd3SBin Meng #ifdef CONFIG_EFI_STUB_64BIT
2831fdeacd3SBin Meng 	efi_info->efi_systab_hi = table->sys_table >> 32;
2841fdeacd3SBin Meng 	efi_info->efi_memmap_hi = (u64)(u32)(map->desc) >> 32;
2851fdeacd3SBin Meng 	signature = EFI64_LOADER_SIGNATURE;
2861fdeacd3SBin Meng #else
2871fdeacd3SBin Meng 	signature = EFI32_LOADER_SIGNATURE;
2881fdeacd3SBin Meng #endif
2891fdeacd3SBin Meng 	memcpy(&efi_info->efi_loader_signature, signature, 4);
2901fdeacd3SBin Meng }
291