xref: /openbmc/linux/arch/x86/boot/compressed/acpi.c (revision 8ebc80a25f9d9bf7a8e368b266d5b740c485c362)
13c98e71bSChao Fan // SPDX-License-Identifier: GPL-2.0
23c98e71bSChao Fan #define BOOT_CTYPE_H
33c98e71bSChao Fan #include "misc.h"
43c98e71bSChao Fan #include "error.h"
53c98e71bSChao Fan #include "../string.h"
65dc91f2dSBorislav Petkov #include "efi.h"
73c98e71bSChao Fan 
802a3e3cdSChao Fan #include <linux/numa.h>
93c98e71bSChao Fan 
103c98e71bSChao Fan /*
1102a3e3cdSChao Fan  * Longest parameter of 'acpi=' is 'copy_dsdt', plus an extra '\0'
1202a3e3cdSChao Fan  * for termination.
1302a3e3cdSChao Fan  */
1402a3e3cdSChao Fan #define MAX_ACPI_ARG_LENGTH 10
1502a3e3cdSChao Fan 
1602a3e3cdSChao Fan /*
1702a3e3cdSChao Fan  * Immovable memory regions representation. Max amount of memory regions is
1802a3e3cdSChao Fan  * MAX_NUMNODES*2.
1902a3e3cdSChao Fan  */
2002a3e3cdSChao Fan struct mem_vector immovable_mem[MAX_NUMNODES*2];
2102a3e3cdSChao Fan 
220a23ebc6SJunichi Nomura static acpi_physical_address
__efi_get_rsdp_addr(unsigned long cfg_tbl_pa,unsigned int cfg_tbl_len)23dee602ddSMichael Roth __efi_get_rsdp_addr(unsigned long cfg_tbl_pa, unsigned int cfg_tbl_len)
2433f0df8dSChao Fan {
2533f0df8dSChao Fan #ifdef CONFIG_EFI
26dee602ddSMichael Roth 	unsigned long rsdp_addr;
27dee602ddSMichael Roth 	int ret;
280a23ebc6SJunichi Nomura 
29dee602ddSMichael Roth 	/*
30dee602ddSMichael Roth 	 * Search EFI system tables for RSDP. Preferred is ACPI_20_TABLE_GUID to
31dee602ddSMichael Roth 	 * ACPI_TABLE_GUID because it has more features.
32dee602ddSMichael Roth 	 */
33*c59843e8SArd Biesheuvel 	rsdp_addr = efi_find_vendor_table(boot_params_ptr, cfg_tbl_pa, cfg_tbl_len,
34dee602ddSMichael Roth 					  ACPI_20_TABLE_GUID);
35dee602ddSMichael Roth 	if (rsdp_addr)
36dee602ddSMichael Roth 		return (acpi_physical_address)rsdp_addr;
370a23ebc6SJunichi Nomura 
38dee602ddSMichael Roth 	/* No ACPI_20_TABLE_GUID found, fallback to ACPI_TABLE_GUID. */
39*c59843e8SArd Biesheuvel 	rsdp_addr = efi_find_vendor_table(boot_params_ptr, cfg_tbl_pa, cfg_tbl_len,
40dee602ddSMichael Roth 					  ACPI_TABLE_GUID);
41dee602ddSMichael Roth 	if (rsdp_addr)
42dee602ddSMichael Roth 		return (acpi_physical_address)rsdp_addr;
430a23ebc6SJunichi Nomura 
44dee602ddSMichael Roth 	debug_putstr("Error getting RSDP address.\n");
450a23ebc6SJunichi Nomura #endif
46dee602ddSMichael Roth 	return 0;
470a23ebc6SJunichi Nomura }
480a23ebc6SJunichi Nomura 
efi_get_rsdp_addr(void)490a23ebc6SJunichi Nomura static acpi_physical_address efi_get_rsdp_addr(void)
500a23ebc6SJunichi Nomura {
510a23ebc6SJunichi Nomura #ifdef CONFIG_EFI
5261c14cedSMichael Roth 	unsigned long cfg_tbl_pa = 0;
5361c14cedSMichael Roth 	unsigned int cfg_tbl_len;
5461c14cedSMichael Roth 	unsigned long systab_pa;
55f9d230e8SBorislav Petkov 	unsigned int nr_tables;
567c4146e8SMichael Roth 	enum efi_type et;
5761c14cedSMichael Roth 	int ret;
5833f0df8dSChao Fan 
59*c59843e8SArd Biesheuvel 	et = efi_get_type(boot_params_ptr);
60dee602ddSMichael Roth 	if (et == EFI_TYPE_NONE)
6133f0df8dSChao Fan 		return 0;
6233f0df8dSChao Fan 
63*c59843e8SArd Biesheuvel 	systab_pa = efi_get_system_table(boot_params_ptr);
6458f3e6b7SMichael Roth 	if (!systab_pa)
6558f3e6b7SMichael Roth 		error("EFI support advertised, but unable to locate system table.");
6633f0df8dSChao Fan 
67*c59843e8SArd Biesheuvel 	ret = efi_get_conf_table(boot_params_ptr, &cfg_tbl_pa, &cfg_tbl_len);
6861c14cedSMichael Roth 	if (ret || !cfg_tbl_pa)
6961c14cedSMichael Roth 		error("EFI config table not found.");
7033f0df8dSChao Fan 
71dee602ddSMichael Roth 	return __efi_get_rsdp_addr(cfg_tbl_pa, cfg_tbl_len);
720a23ebc6SJunichi Nomura #else
7333f0df8dSChao Fan 	return 0;
7433f0df8dSChao Fan #endif
7533f0df8dSChao Fan }
7693a209aaSChao Fan 
compute_checksum(u8 * buffer,u32 length)7793a209aaSChao Fan static u8 compute_checksum(u8 *buffer, u32 length)
7893a209aaSChao Fan {
7993a209aaSChao Fan 	u8 *end = buffer + length;
8093a209aaSChao Fan 	u8 sum = 0;
8193a209aaSChao Fan 
8293a209aaSChao Fan 	while (buffer < end)
8393a209aaSChao Fan 		sum += *(buffer++);
8493a209aaSChao Fan 
8593a209aaSChao Fan 	return sum;
8693a209aaSChao Fan }
8793a209aaSChao Fan 
8893a209aaSChao Fan /* Search a block of memory for the RSDP signature. */
scan_mem_for_rsdp(u8 * start,u32 length)8993a209aaSChao Fan static u8 *scan_mem_for_rsdp(u8 *start, u32 length)
9093a209aaSChao Fan {
9193a209aaSChao Fan 	struct acpi_table_rsdp *rsdp;
9293a209aaSChao Fan 	u8 *address, *end;
9393a209aaSChao Fan 
9493a209aaSChao Fan 	end = start + length;
9593a209aaSChao Fan 
9693a209aaSChao Fan 	/* Search from given start address for the requested length */
9793a209aaSChao Fan 	for (address = start; address < end; address += ACPI_RSDP_SCAN_STEP) {
9893a209aaSChao Fan 		/*
9993a209aaSChao Fan 		 * Both RSDP signature and checksum must be correct.
10093a209aaSChao Fan 		 * Note: Sometimes there exists more than one RSDP in memory;
10193a209aaSChao Fan 		 * the valid RSDP has a valid checksum, all others have an
10293a209aaSChao Fan 		 * invalid checksum.
10393a209aaSChao Fan 		 */
10493a209aaSChao Fan 		rsdp = (struct acpi_table_rsdp *)address;
10593a209aaSChao Fan 
10693a209aaSChao Fan 		/* BAD Signature */
10793a209aaSChao Fan 		if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature))
10893a209aaSChao Fan 			continue;
10993a209aaSChao Fan 
11093a209aaSChao Fan 		/* Check the standard checksum */
11193a209aaSChao Fan 		if (compute_checksum((u8 *)rsdp, ACPI_RSDP_CHECKSUM_LENGTH))
11293a209aaSChao Fan 			continue;
11393a209aaSChao Fan 
11493a209aaSChao Fan 		/* Check extended checksum if table version >= 2 */
11593a209aaSChao Fan 		if ((rsdp->revision >= 2) &&
11693a209aaSChao Fan 		    (compute_checksum((u8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)))
11793a209aaSChao Fan 			continue;
11893a209aaSChao Fan 
11993a209aaSChao Fan 		/* Signature and checksum valid, we have found a real RSDP */
12093a209aaSChao Fan 		return address;
12193a209aaSChao Fan 	}
12293a209aaSChao Fan 	return NULL;
12393a209aaSChao Fan }
12493a209aaSChao Fan 
12593a209aaSChao Fan /* Search RSDP address in EBDA. */
bios_get_rsdp_addr(void)12693a209aaSChao Fan static acpi_physical_address bios_get_rsdp_addr(void)
12793a209aaSChao Fan {
12893a209aaSChao Fan 	unsigned long address;
12993a209aaSChao Fan 	u8 *rsdp;
13093a209aaSChao Fan 
13193a209aaSChao Fan 	/* Get the location of the Extended BIOS Data Area (EBDA) */
13293a209aaSChao Fan 	address = *(u16 *)ACPI_EBDA_PTR_LOCATION;
13393a209aaSChao Fan 	address <<= 4;
13493a209aaSChao Fan 
13593a209aaSChao Fan 	/*
13693a209aaSChao Fan 	 * Search EBDA paragraphs (EBDA is required to be a minimum of
13793a209aaSChao Fan 	 * 1K length)
13893a209aaSChao Fan 	 */
13993a209aaSChao Fan 	if (address > 0x400) {
14093a209aaSChao Fan 		rsdp = scan_mem_for_rsdp((u8 *)address, ACPI_EBDA_WINDOW_SIZE);
14193a209aaSChao Fan 		if (rsdp)
14293a209aaSChao Fan 			return (acpi_physical_address)(unsigned long)rsdp;
14393a209aaSChao Fan 	}
14493a209aaSChao Fan 
14593a209aaSChao Fan 	/* Search upper memory: 16-byte boundaries in E0000h-FFFFFh */
14693a209aaSChao Fan 	rsdp = scan_mem_for_rsdp((u8 *) ACPI_HI_RSDP_WINDOW_BASE,
14793a209aaSChao Fan 					ACPI_HI_RSDP_WINDOW_SIZE);
14893a209aaSChao Fan 	if (rsdp)
14993a209aaSChao Fan 		return (acpi_physical_address)(unsigned long)rsdp;
15093a209aaSChao Fan 
15193a209aaSChao Fan 	return 0;
15293a209aaSChao Fan }
1533a63f70bSChao Fan 
1543a63f70bSChao Fan /* Return RSDP address on success, otherwise 0. */
get_rsdp_addr(void)1553a63f70bSChao Fan acpi_physical_address get_rsdp_addr(void)
1563a63f70bSChao Fan {
1573a63f70bSChao Fan 	acpi_physical_address pa;
1583a63f70bSChao Fan 
159*c59843e8SArd Biesheuvel 	pa = boot_params_ptr->acpi_rsdp_addr;
1603a63f70bSChao Fan 
1613a63f70bSChao Fan 	if (!pa)
1623a63f70bSChao Fan 		pa = efi_get_rsdp_addr();
1633a63f70bSChao Fan 
1643a63f70bSChao Fan 	if (!pa)
1653a63f70bSChao Fan 		pa = bios_get_rsdp_addr();
1663a63f70bSChao Fan 
1673a63f70bSChao Fan 	return pa;
1683a63f70bSChao Fan }
16902a3e3cdSChao Fan 
17002a3e3cdSChao Fan #if defined(CONFIG_RANDOMIZE_BASE) && defined(CONFIG_MEMORY_HOTREMOVE)
171228d1200SZhenzhong Duan /*
172228d1200SZhenzhong Duan  * Max length of 64-bit hex address string is 19, prefix "0x" + 16 hex
173228d1200SZhenzhong Duan  * digits, and '\0' for termination.
174228d1200SZhenzhong Duan  */
175228d1200SZhenzhong Duan #define MAX_ADDR_LEN 19
176228d1200SZhenzhong Duan 
get_cmdline_acpi_rsdp(void)17740ba9309SVamshi K Sthambamkadi static unsigned long get_cmdline_acpi_rsdp(void)
178228d1200SZhenzhong Duan {
17940ba9309SVamshi K Sthambamkadi 	unsigned long addr = 0;
180228d1200SZhenzhong Duan 
181228d1200SZhenzhong Duan #ifdef CONFIG_KEXEC
182228d1200SZhenzhong Duan 	char val[MAX_ADDR_LEN] = { };
183228d1200SZhenzhong Duan 	int ret;
184228d1200SZhenzhong Duan 
185228d1200SZhenzhong Duan 	ret = cmdline_find_option("acpi_rsdp", val, MAX_ADDR_LEN);
186228d1200SZhenzhong Duan 	if (ret < 0)
187228d1200SZhenzhong Duan 		return 0;
188228d1200SZhenzhong Duan 
18940ba9309SVamshi K Sthambamkadi 	if (boot_kstrtoul(val, 16, &addr))
190228d1200SZhenzhong Duan 		return 0;
191228d1200SZhenzhong Duan #endif
192228d1200SZhenzhong Duan 	return addr;
193228d1200SZhenzhong Duan }
194228d1200SZhenzhong Duan 
19502a3e3cdSChao Fan /* Compute SRAT address from RSDP. */
get_acpi_srat_table(void)19602a3e3cdSChao Fan static unsigned long get_acpi_srat_table(void)
19702a3e3cdSChao Fan {
19802a3e3cdSChao Fan 	unsigned long root_table, acpi_table;
19902a3e3cdSChao Fan 	struct acpi_table_header *header;
20002a3e3cdSChao Fan 	struct acpi_table_rsdp *rsdp;
20102a3e3cdSChao Fan 	u32 num_entries, size, len;
20202a3e3cdSChao Fan 	char arg[10];
20302a3e3cdSChao Fan 	u8 *entry;
20402a3e3cdSChao Fan 
20541fa1ee9SJosh Boyer 	/*
20641fa1ee9SJosh Boyer 	 * Check whether we were given an RSDP on the command line. We don't
20741fa1ee9SJosh Boyer 	 * stash this in boot params because the kernel itself may have
20841fa1ee9SJosh Boyer 	 * different ideas about whether to trust a command-line parameter.
20941fa1ee9SJosh Boyer 	 */
21041fa1ee9SJosh Boyer 	rsdp = (struct acpi_table_rsdp *)get_cmdline_acpi_rsdp();
21141fa1ee9SJosh Boyer 	if (!rsdp)
21241fa1ee9SJosh Boyer 		rsdp = (struct acpi_table_rsdp *)(long)
213*c59843e8SArd Biesheuvel 			boot_params_ptr->acpi_rsdp_addr;
21441fa1ee9SJosh Boyer 
21502a3e3cdSChao Fan 	if (!rsdp)
21602a3e3cdSChao Fan 		return 0;
21702a3e3cdSChao Fan 
21802a3e3cdSChao Fan 	/* Get ACPI root table from RSDP.*/
21902a3e3cdSChao Fan 	if (!(cmdline_find_option("acpi", arg, sizeof(arg)) == 4 &&
22002a3e3cdSChao Fan 	    !strncmp(arg, "rsdt", 4)) &&
22102a3e3cdSChao Fan 	    rsdp->xsdt_physical_address &&
22202a3e3cdSChao Fan 	    rsdp->revision > 1) {
22302a3e3cdSChao Fan 		root_table = rsdp->xsdt_physical_address;
22402a3e3cdSChao Fan 		size = ACPI_XSDT_ENTRY_SIZE;
22502a3e3cdSChao Fan 	} else {
22602a3e3cdSChao Fan 		root_table = rsdp->rsdt_physical_address;
22702a3e3cdSChao Fan 		size = ACPI_RSDT_ENTRY_SIZE;
22802a3e3cdSChao Fan 	}
22902a3e3cdSChao Fan 
23002a3e3cdSChao Fan 	if (!root_table)
23102a3e3cdSChao Fan 		return 0;
23202a3e3cdSChao Fan 
23302a3e3cdSChao Fan 	header = (struct acpi_table_header *)root_table;
23402a3e3cdSChao Fan 	len = header->length;
23502a3e3cdSChao Fan 	if (len < sizeof(struct acpi_table_header) + size)
23602a3e3cdSChao Fan 		return 0;
23702a3e3cdSChao Fan 
23802a3e3cdSChao Fan 	num_entries = (len - sizeof(struct acpi_table_header)) / size;
23902a3e3cdSChao Fan 	entry = (u8 *)(root_table + sizeof(struct acpi_table_header));
24002a3e3cdSChao Fan 
24102a3e3cdSChao Fan 	while (num_entries--) {
24202a3e3cdSChao Fan 		if (size == ACPI_RSDT_ENTRY_SIZE)
24302a3e3cdSChao Fan 			acpi_table = *(u32 *)entry;
24402a3e3cdSChao Fan 		else
24502a3e3cdSChao Fan 			acpi_table = *(u64 *)entry;
24602a3e3cdSChao Fan 
24702a3e3cdSChao Fan 		if (acpi_table) {
24802a3e3cdSChao Fan 			header = (struct acpi_table_header *)acpi_table;
24902a3e3cdSChao Fan 
2505599fb69SBob Moore 			if (ACPI_COMPARE_NAMESEG(header->signature, ACPI_SIG_SRAT))
25102a3e3cdSChao Fan 				return acpi_table;
25202a3e3cdSChao Fan 		}
25302a3e3cdSChao Fan 		entry += size;
25402a3e3cdSChao Fan 	}
25502a3e3cdSChao Fan 	return 0;
25602a3e3cdSChao Fan }
25702a3e3cdSChao Fan 
25802a3e3cdSChao Fan /**
25902a3e3cdSChao Fan  * count_immovable_mem_regions - Parse SRAT and cache the immovable
26002a3e3cdSChao Fan  * memory regions into the immovable_mem array.
26102a3e3cdSChao Fan  *
26202a3e3cdSChao Fan  * Return the number of immovable memory regions on success, 0 on failure:
26302a3e3cdSChao Fan  *
26402a3e3cdSChao Fan  * - Too many immovable memory regions
26502a3e3cdSChao Fan  * - ACPI off or no SRAT found
26602a3e3cdSChao Fan  * - No immovable memory region found.
26702a3e3cdSChao Fan  */
count_immovable_mem_regions(void)26802a3e3cdSChao Fan int count_immovable_mem_regions(void)
26902a3e3cdSChao Fan {
27002a3e3cdSChao Fan 	unsigned long table_addr, table_end, table;
27102a3e3cdSChao Fan 	struct acpi_subtable_header *sub_table;
27202a3e3cdSChao Fan 	struct acpi_table_header *table_header;
27302a3e3cdSChao Fan 	char arg[MAX_ACPI_ARG_LENGTH];
27402a3e3cdSChao Fan 	int num = 0;
27502a3e3cdSChao Fan 
27602a3e3cdSChao Fan 	if (cmdline_find_option("acpi", arg, sizeof(arg)) == 3 &&
27702a3e3cdSChao Fan 	    !strncmp(arg, "off", 3))
27802a3e3cdSChao Fan 		return 0;
27902a3e3cdSChao Fan 
28002a3e3cdSChao Fan 	table_addr = get_acpi_srat_table();
28102a3e3cdSChao Fan 	if (!table_addr)
28202a3e3cdSChao Fan 		return 0;
28302a3e3cdSChao Fan 
28402a3e3cdSChao Fan 	table_header = (struct acpi_table_header *)table_addr;
28502a3e3cdSChao Fan 	table_end = table_addr + table_header->length;
28602a3e3cdSChao Fan 	table = table_addr + sizeof(struct acpi_table_srat);
28702a3e3cdSChao Fan 
28802a3e3cdSChao Fan 	while (table + sizeof(struct acpi_subtable_header) < table_end) {
2892b73ea37SSteven Clarkson 
29002a3e3cdSChao Fan 		sub_table = (struct acpi_subtable_header *)table;
2912b73ea37SSteven Clarkson 		if (!sub_table->length) {
2922b73ea37SSteven Clarkson 			debug_putstr("Invalid zero length SRAT subtable.\n");
2932b73ea37SSteven Clarkson 			return 0;
2942b73ea37SSteven Clarkson 		}
2952b73ea37SSteven Clarkson 
29602a3e3cdSChao Fan 		if (sub_table->type == ACPI_SRAT_TYPE_MEMORY_AFFINITY) {
29702a3e3cdSChao Fan 			struct acpi_srat_mem_affinity *ma;
29802a3e3cdSChao Fan 
29902a3e3cdSChao Fan 			ma = (struct acpi_srat_mem_affinity *)sub_table;
30002a3e3cdSChao Fan 			if (!(ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && ma->length) {
30102a3e3cdSChao Fan 				immovable_mem[num].start = ma->base_address;
30202a3e3cdSChao Fan 				immovable_mem[num].size = ma->length;
30302a3e3cdSChao Fan 				num++;
30402a3e3cdSChao Fan 			}
30502a3e3cdSChao Fan 
30602a3e3cdSChao Fan 			if (num >= MAX_NUMNODES*2) {
30702a3e3cdSChao Fan 				debug_putstr("Too many immovable memory regions, aborting.\n");
30802a3e3cdSChao Fan 				return 0;
30902a3e3cdSChao Fan 			}
31002a3e3cdSChao Fan 		}
31102a3e3cdSChao Fan 		table += sub_table->length;
31202a3e3cdSChao Fan 	}
31302a3e3cdSChao Fan 	return num;
31402a3e3cdSChao Fan }
31502a3e3cdSChao Fan #endif /* CONFIG_RANDOMIZE_BASE && CONFIG_MEMORY_HOTREMOVE */
316