xref: /kvm-unit-tests/lib/acpi.c (revision 13182cd7705d9a39fc941bbeb5c587495b15cddc)
1 #include "libcflat.h"
2 #include "acpi.h"
3 
4 #ifdef CONFIG_EFI
5 struct acpi_table_rsdp *efi_rsdp = NULL;
6 
set_efi_rsdp(struct acpi_table_rsdp * rsdp)7 void set_efi_rsdp(struct acpi_table_rsdp *rsdp)
8 {
9 	efi_rsdp = rsdp;
10 }
11 
get_rsdp(void)12 static struct acpi_table_rsdp *get_rsdp(void)
13 {
14 	if (efi_rsdp == NULL)
15 		printf("Can't find RSDP from UEFI, maybe set_efi_rsdp() was not called\n");
16 
17 	return efi_rsdp;
18 }
19 #else
get_rsdp(void)20 static struct acpi_table_rsdp *get_rsdp(void)
21 {
22 	struct acpi_table_rsdp *rsdp;
23 	unsigned long addr;
24 
25 	for (addr = 0xe0000; addr < 0x100000; addr += 16) {
26 		rsdp = (void *)addr;
27 		if (rsdp->signature == RSDP_SIGNATURE_8BYTE)
28 			break;
29 	}
30 
31 	if (addr == 0x100000)
32 		return NULL;
33 
34 	return rsdp;
35 }
36 #endif /* CONFIG_EFI */
37 
find_acpi_table_addr(u32 sig)38 void *find_acpi_table_addr(u32 sig)
39 {
40 	struct acpi_table_rsdt_rev1 *rsdt = NULL;
41 	struct acpi_table_xsdt *xsdt = NULL;
42 	struct acpi_table_rsdp *rsdp;
43 	void *end;
44 	int i;
45 
46 	/* FACS is special... */
47 	if (sig == FACS_SIGNATURE) {
48 		struct acpi_table_fadt *fadt;
49 
50 		fadt = find_acpi_table_addr(FACP_SIGNATURE);
51 		if (!fadt)
52 			return NULL;
53 		return (void *)(ulong) fadt->firmware_ctrl;
54 	}
55 
56 	rsdp = get_rsdp();
57 	if (rsdp == NULL) {
58 		printf("Can't find RSDP\n");
59 		return NULL;
60 	}
61 
62 	if (sig == RSDP_SIGNATURE)
63 		return rsdp;
64 
65 	rsdt = (void *)(ulong) rsdp->rsdt_physical_address;
66 	if (rsdt && rsdt->signature != RSDT_SIGNATURE)
67 		rsdt = NULL;
68 
69 	if (sig == RSDT_SIGNATURE)
70 		return rsdt;
71 
72 	if (rsdp->revision >= 2) {
73 		xsdt = (void *)(ulong) rsdp->xsdt_physical_address;
74 		if (xsdt && xsdt->signature != XSDT_SIGNATURE)
75 			xsdt = NULL;
76 	}
77 
78 	if (sig == XSDT_SIGNATURE)
79 		return xsdt;
80 
81 	/*
82 	 * When the system implements APCI 2.0 and above and XSDT is valid we
83 	 * have use XSDT to find other ACPI tables, otherwise, we use RSDT.
84 	 */
85 	if (xsdt) {
86 		end = (void *)xsdt + xsdt->length;
87 		for (i = 0; (void *)&xsdt->table_offset_entry[i] < end; i++) {
88 			struct acpi_table *t = (void *)(ulong) xsdt->table_offset_entry[i];
89 
90 			if (t && t->signature == sig)
91 				return t;
92 		}
93 	} else if (rsdt) {
94 		end = (void *)rsdt + rsdt->length;
95 		for (i = 0; (void *)&rsdt->table_offset_entry[i] < end; i++) {
96 			struct acpi_table *t = (void *)(ulong) rsdt->table_offset_entry[i];
97 
98 			if (t && t->signature == sig)
99 				return t;
100 		}
101 	}
102 
103 	return NULL;
104 }
105 
acpi_table_parse_madt(enum acpi_madt_type mtype,acpi_table_handler handler)106 int acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler)
107 {
108 	struct acpi_table_madt *madt;
109 	struct acpi_subtable_header *header;
110 	void *end;
111 	int count = 0;
112 
113 	madt = find_acpi_table_addr(MADT_SIGNATURE);
114 	assert(madt);
115 
116 	header = (void *)(ulong) madt + sizeof(struct acpi_table_madt);
117 	end = (void *)((ulong) madt + madt->length);
118 
119 	while ((void *)header < end) {
120 		if (header->type == mtype) {
121 			handler(header);
122 			count++;
123 		}
124 
125 		header = (void *)(ulong) header + header->length;
126 	}
127 
128 	return count;
129 }
130