xref: /kvm-unit-tests/lib/acpi.c (revision 13182cd7705d9a39fc941bbeb5c587495b15cddc)
1372e3528SPaolo Bonzini #include "libcflat.h"
2372e3528SPaolo Bonzini #include "acpi.h"
3372e3528SPaolo Bonzini 
4c98ce6e0SAlexandru Elisei #ifdef CONFIG_EFI
5169f786fSAlexandru Elisei struct acpi_table_rsdp *efi_rsdp = NULL;
6f20589d6SZixuan Wang 
set_efi_rsdp(struct acpi_table_rsdp * rsdp)7169f786fSAlexandru Elisei void set_efi_rsdp(struct acpi_table_rsdp *rsdp)
8b4e8c300SZixuan Wang {
9f20589d6SZixuan Wang 	efi_rsdp = rsdp;
10f20589d6SZixuan Wang }
11f20589d6SZixuan Wang 
get_rsdp(void)12169f786fSAlexandru Elisei static struct acpi_table_rsdp *get_rsdp(void)
13b4e8c300SZixuan Wang {
14e2ad9858SNikos Nikoleris 	if (efi_rsdp == NULL)
15b4e8c300SZixuan Wang 		printf("Can't find RSDP from UEFI, maybe set_efi_rsdp() was not called\n");
16e2ad9858SNikos Nikoleris 
17f20589d6SZixuan Wang 	return efi_rsdp;
18f20589d6SZixuan Wang }
19f20589d6SZixuan Wang #else
get_rsdp(void)20169f786fSAlexandru Elisei static struct acpi_table_rsdp *get_rsdp(void)
21b4e8c300SZixuan Wang {
22169f786fSAlexandru Elisei 	struct acpi_table_rsdp *rsdp;
23f20589d6SZixuan Wang 	unsigned long addr;
24b4e8c300SZixuan Wang 
2592a6c9b9SPaolo Bonzini 	for (addr = 0xe0000; addr < 0x100000; addr += 16) {
26f20589d6SZixuan Wang 		rsdp = (void *)addr;
27f20589d6SZixuan Wang 		if (rsdp->signature == RSDP_SIGNATURE_8BYTE)
28f20589d6SZixuan Wang 			break;
29f20589d6SZixuan Wang 	}
30b4e8c300SZixuan Wang 
31e2ad9858SNikos Nikoleris 	if (addr == 0x100000)
32f20589d6SZixuan Wang 		return NULL;
33b4e8c300SZixuan Wang 
34f20589d6SZixuan Wang 	return rsdp;
35f20589d6SZixuan Wang }
36c98ce6e0SAlexandru Elisei #endif /* CONFIG_EFI */
37f20589d6SZixuan Wang 
find_acpi_table_addr(u32 sig)38372e3528SPaolo Bonzini void *find_acpi_table_addr(u32 sig)
39372e3528SPaolo Bonzini {
4074e927c7SNikos Nikoleris 	struct acpi_table_rsdt_rev1 *rsdt = NULL;
4174e927c7SNikos Nikoleris 	struct acpi_table_xsdt *xsdt = NULL;
42169f786fSAlexandru Elisei 	struct acpi_table_rsdp *rsdp;
43372e3528SPaolo Bonzini 	void *end;
44372e3528SPaolo Bonzini 	int i;
45372e3528SPaolo Bonzini 
46372e3528SPaolo Bonzini 	/* FACS is special... */
47372e3528SPaolo Bonzini 	if (sig == FACS_SIGNATURE) {
4864cd0cc1SNikos Nikoleris 		struct acpi_table_fadt *fadt;
49e2ad9858SNikos Nikoleris 
50372e3528SPaolo Bonzini 		fadt = find_acpi_table_addr(FACP_SIGNATURE);
51b3e76d57SNikos Nikoleris 		if (!fadt)
52372e3528SPaolo Bonzini 			return NULL;
53372e3528SPaolo Bonzini 		return (void *)(ulong) fadt->firmware_ctrl;
54372e3528SPaolo Bonzini 	}
55372e3528SPaolo Bonzini 
56f20589d6SZixuan Wang 	rsdp = get_rsdp();
57f20589d6SZixuan Wang 	if (rsdp == NULL) {
58372e3528SPaolo Bonzini 		printf("Can't find RSDP\n");
59b3e76d57SNikos Nikoleris 		return NULL;
60372e3528SPaolo Bonzini 	}
61372e3528SPaolo Bonzini 
62b3e76d57SNikos Nikoleris 	if (sig == RSDP_SIGNATURE)
63372e3528SPaolo Bonzini 		return rsdp;
64372e3528SPaolo Bonzini 
65372e3528SPaolo Bonzini 	rsdt = (void *)(ulong) rsdp->rsdt_physical_address;
6674e927c7SNikos Nikoleris 	if (rsdt && rsdt->signature != RSDT_SIGNATURE)
6774e927c7SNikos Nikoleris 		rsdt = NULL;
68372e3528SPaolo Bonzini 
69b3e76d57SNikos Nikoleris 	if (sig == RSDT_SIGNATURE)
70372e3528SPaolo Bonzini 		return rsdt;
71372e3528SPaolo Bonzini 
7274e927c7SNikos Nikoleris 	if (rsdp->revision >= 2) {
7374e927c7SNikos Nikoleris 		xsdt = (void *)(ulong) rsdp->xsdt_physical_address;
7474e927c7SNikos Nikoleris 		if (xsdt && xsdt->signature != XSDT_SIGNATURE)
7574e927c7SNikos Nikoleris 			xsdt = NULL;
7674e927c7SNikos Nikoleris 	}
7774e927c7SNikos Nikoleris 
7874e927c7SNikos Nikoleris 	if (sig == XSDT_SIGNATURE)
7974e927c7SNikos Nikoleris 		return xsdt;
8074e927c7SNikos Nikoleris 
8174e927c7SNikos Nikoleris 	/*
8274e927c7SNikos Nikoleris 	 * When the system implements APCI 2.0 and above and XSDT is valid we
8374e927c7SNikos Nikoleris 	 * have use XSDT to find other ACPI tables, otherwise, we use RSDT.
8474e927c7SNikos Nikoleris 	 */
8574e927c7SNikos Nikoleris 	if (xsdt) {
8674e927c7SNikos Nikoleris 		end = (void *)xsdt + xsdt->length;
8774e927c7SNikos Nikoleris 		for (i = 0; (void *)&xsdt->table_offset_entry[i] < end; i++) {
8874e927c7SNikos Nikoleris 			struct acpi_table *t = (void *)(ulong) xsdt->table_offset_entry[i];
8974e927c7SNikos Nikoleris 
9074e927c7SNikos Nikoleris 			if (t && t->signature == sig)
9174e927c7SNikos Nikoleris 				return t;
9274e927c7SNikos Nikoleris 		}
9374e927c7SNikos Nikoleris 	} else if (rsdt) {
94372e3528SPaolo Bonzini 		end = (void *)rsdt + rsdt->length;
95372e3528SPaolo Bonzini 		for (i = 0; (void *)&rsdt->table_offset_entry[i] < end; i++) {
96372e3528SPaolo Bonzini 			struct acpi_table *t = (void *)(ulong) rsdt->table_offset_entry[i];
97e2ad9858SNikos Nikoleris 
98e2ad9858SNikos Nikoleris 			if (t && t->signature == sig)
99372e3528SPaolo Bonzini 				return t;
100372e3528SPaolo Bonzini 		}
10174e927c7SNikos Nikoleris 	}
102e2ad9858SNikos Nikoleris 
103372e3528SPaolo Bonzini 	return NULL;
104372e3528SPaolo Bonzini }
1053d29f825SNikos Nikoleris 
acpi_table_parse_madt(enum acpi_madt_type mtype,acpi_table_handler handler)106*13182cd7SNikos Nikoleris int acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler)
1073d29f825SNikos Nikoleris {
1083d29f825SNikos Nikoleris 	struct acpi_table_madt *madt;
1093d29f825SNikos Nikoleris 	struct acpi_subtable_header *header;
1103d29f825SNikos Nikoleris 	void *end;
111*13182cd7SNikos Nikoleris 	int count = 0;
1123d29f825SNikos Nikoleris 
1133d29f825SNikos Nikoleris 	madt = find_acpi_table_addr(MADT_SIGNATURE);
1143d29f825SNikos Nikoleris 	assert(madt);
1153d29f825SNikos Nikoleris 
1163d29f825SNikos Nikoleris 	header = (void *)(ulong) madt + sizeof(struct acpi_table_madt);
1173d29f825SNikos Nikoleris 	end = (void *)((ulong) madt + madt->length);
1183d29f825SNikos Nikoleris 
1193d29f825SNikos Nikoleris 	while ((void *)header < end) {
120*13182cd7SNikos Nikoleris 		if (header->type == mtype) {
1213d29f825SNikos Nikoleris 			handler(header);
122*13182cd7SNikos Nikoleris 			count++;
123*13182cd7SNikos Nikoleris 		}
1243d29f825SNikos Nikoleris 
1253d29f825SNikos Nikoleris 		header = (void *)(ulong) header + header->length;
1263d29f825SNikos Nikoleris 	}
127*13182cd7SNikos Nikoleris 
128*13182cd7SNikos Nikoleris 	return count;
1293d29f825SNikos Nikoleris }
130