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
38static acpi_descriptor_header* sAcpiRsdt; // System Description Table
39static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
40static int32 sNumEntries = -1;
41
42
43static status_t
44acpi_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
73static status_t
74acpi_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
85static status_t
86acpi_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
145template<typename PointerType>
146acpi_descriptor_header*
147acpi_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
187acpi_descriptor_header*
188acpi_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
199void __attribute__((weak))
200arch_handle_acpi()
201{
202}
203
204
205void
206acpi_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