1 /*
2 * Copyright 2020 Haiku, Inc. All rights reserved.
3 * Copyright 2014, Jessica Hamilton, jessica.l.hamilton@gmail.com.
4 * Copyright 2011, Rene Gollent, rene@gollent.com.
5 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
6 * Copyright 2007, Michael Lotz, mmlr@mlotz.ch
7 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de.
8 * Distributed under the terms of the MIT License.
9 *
10 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
11 * Distributed under the terms of the NewOS License.
12 */
13
14
15 #include <string.h>
16
17 #include <KernelExport.h>
18 #include <SupportDefs.h>
19
20 #include <arch_acpi.h>
21 #include <boot/stage2.h>
22 #include <boot/platform.h>
23 #include <boot/stdio.h>
24
25 #include "efi_platform.h"
26 #include "acpi.h"
27 #include "mmu.h"
28
29
30 #define TRACE_ACPI
31 #ifdef TRACE_ACPI
32 # define TRACE(x) dprintf x
33 #else
34 # define TRACE(x) ;
35 #endif
36
37
38 static acpi_descriptor_header* sAcpiRsdt; // System Description Table
39 static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
40 static int32 sNumEntries = -1;
41
42
43 static status_t
acpi_validate_rsdp(acpi_rsdp * rsdp)44 acpi_validate_rsdp(acpi_rsdp* rsdp)
45 {
46 const char* data = (const char*)rsdp;
47 unsigned char checksum = 0;
48 for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++)
49 checksum += data[i];
50
51 if ((checksum & 0xff) != 0) {
52 TRACE(("acpi: rsdp failed basic checksum\n"));
53 return B_BAD_DATA;
54 }
55
56 // for ACPI 2.0+ we need to also validate the extended checksum
57 if (rsdp->revision > 0) {
58 for (uint32 i = sizeof(acpi_rsdp_legacy);
59 i < sizeof(acpi_rsdp_extended); i++) {
60 checksum += data[i];
61 }
62
63 if ((checksum & 0xff) != 0) {
64 TRACE(("acpi: rsdp failed extended checksum\n"));
65 return B_BAD_DATA;
66 }
67 }
68
69 return B_OK;
70 }
71
72
73 static status_t
acpi_validate_rsdt(acpi_descriptor_header * rsdt)74 acpi_validate_rsdt(acpi_descriptor_header* rsdt)
75 {
76 const char* data = (const char*)rsdt;
77 unsigned char checksum = 0;
78 for (uint32 i = 0; i < rsdt->length; i++)
79 checksum += data[i];
80
81 return checksum == 0 ? B_OK : B_BAD_DATA;
82 }
83
84
85 static status_t
acpi_check_rsdt(acpi_rsdp * rsdp)86 acpi_check_rsdt(acpi_rsdp* rsdp)
87 {
88 if (acpi_validate_rsdp(rsdp) != B_OK)
89 return B_BAD_DATA;
90
91 bool usingXsdt = false;
92
93 TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n",
94 rsdp, rsdp->oem_id, rsdp->revision));
95 TRACE(("acpi: rsdp points to rsdt at 0x%" B_PRIx32 "\n", rsdp->rsdt_address));
96
97 acpi_descriptor_header* rsdt = NULL;
98 if (rsdp->revision > 0) {
99 rsdt = (acpi_descriptor_header*)(addr_t)rsdp->xsdt_address;
100 if (rsdt != NULL
101 && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) {
102 rsdt = NULL;
103 TRACE(("acpi: invalid extended system description table\n"));
104 } else
105 usingXsdt = true;
106 }
107
108 // if we're ACPI v1 or we fail to map the XSDT for some reason,
109 // attempt to use the RSDT instead.
110 if (rsdt == NULL) {
111 // validate the root system description table
112 rsdt = (acpi_descriptor_header*)(addr_t)rsdp->rsdt_address;
113 if (rsdt == NULL) {
114 TRACE(("acpi: couldn't map rsdt header\n"));
115 return B_ERROR;
116 }
117 if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) {
118 rsdt = NULL;
119 TRACE(("acpi: invalid root system description table\n"));
120 return B_ERROR;
121 }
122
123 TRACE(("acpi: rsdt length: %" B_PRIu32 "\n", rsdt->length));
124 }
125
126 if (rsdt != NULL) {
127 if (acpi_validate_rsdt(rsdt) != B_OK) {
128 TRACE(("acpi: rsdt failed checksum validation\n"));
129 return B_ERROR;
130 } else {
131 if (usingXsdt)
132 sAcpiXsdt = rsdt;
133 else
134 sAcpiRsdt = rsdt;
135 TRACE(("acpi: found valid %s at %p\n",
136 usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE,
137 rsdt));
138 }
139 } else
140 return B_ERROR;
141
142 return B_OK;
143 }
144
145 template<typename PointerType>
146 acpi_descriptor_header*
acpi_find_table_generic(const char * signature,acpi_descriptor_header * acpiSdt)147 acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt)
148 {
149 if (acpiSdt == NULL)
150 return NULL;
151
152 if (sNumEntries == -1) {
153 // if using the xsdt, our entries are 64 bits wide.
154 sNumEntries = (acpiSdt->length - sizeof(acpi_descriptor_header))
155 / sizeof(PointerType);
156 }
157
158 if (sNumEntries <= 0) {
159 TRACE(("acpi: root system description table is empty\n"));
160 return NULL;
161 }
162
163 TRACE(("acpi: searching %" B_PRId32 " entries for table '%.4s'\n", sNumEntries,
164 signature));
165
166 PointerType* pointer = (PointerType*)((uint8*)acpiSdt
167 + sizeof(acpi_descriptor_header));
168
169 acpi_descriptor_header* header = NULL;
170 for (int32 j = 0; j < sNumEntries; j++, pointer++) {
171 header = (acpi_descriptor_header*)(addr_t)*pointer;
172 if (header != NULL && strncmp(header->signature, signature, 4) == 0) {
173 TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));
174 return header;
175 }
176
177 TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",
178 signature, header != NULL ? header->signature : "null"));
179 header = NULL;
180 continue;
181 }
182
183 return NULL;
184 }
185
186
187 acpi_descriptor_header*
acpi_find_table(const char * signature)188 acpi_find_table(const char* signature)
189 {
190 if (sAcpiRsdt != NULL)
191 return acpi_find_table_generic<uint32>(signature, sAcpiRsdt);
192 else if (sAcpiXsdt != NULL)
193 return acpi_find_table_generic<uint64>(signature, sAcpiXsdt);
194
195 return NULL;
196 }
197
198
199 void __attribute__((weak))
arch_handle_acpi()200 arch_handle_acpi()
201 {
202 }
203
204
205 void
acpi_init()206 acpi_init()
207 {
208 efi_guid acpi = ACPI_20_TABLE_GUID;
209 efi_configuration_table *table = kSystemTable->ConfigurationTable;
210 size_t entries = kSystemTable->NumberOfTableEntries;
211
212 // Try to find the ACPI RSDP.
213 for (uint32 i = 0; i < entries; i++) {
214 if (!table[i].VendorGuid.equals(acpi))
215 continue;
216
217 acpi_rsdp *rsdp = (acpi_rsdp *)(table[i].VendorTable);
218 if (strncmp((char *)rsdp, ACPI_RSDP_SIGNATURE, 8) == 0)
219 TRACE(("acpi_init: found ACPI RSDP signature at %p\n", rsdp));
220
221 if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) {
222 gKernelArgs.arch_args.acpi_root = rsdp;
223 arch_handle_acpi();
224 break;
225 }
226 }
227 }
228