acpi_machdep.c revision 302408
1/*-
2 * Copyright (c) 2001 Mitsuru IWASAKI
3 * Copyright (c) 2015 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * This software was developed by Andrew Turner under
7 * sponsorship from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/11/sys/arm64/acpica/acpi_machdep.c 284273 2015-06-11 15:45:33Z andrew $");
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/kernel.h>
37
38#include <vm/vm.h>
39#include <vm/pmap.h>
40
41#include <contrib/dev/acpica/include/acpi.h>
42#include <contrib/dev/acpica/include/accommon.h>
43#include <contrib/dev/acpica/include/actables.h>
44
45#include <dev/acpica/acpivar.h>
46
47int
48acpi_machdep_init(device_t dev)
49{
50
51	return (0);
52}
53
54int
55acpi_machdep_quirks(int *quirks)
56{
57
58	return (0);
59}
60
61static void *
62map_table(vm_paddr_t pa, int offset, const char *sig)
63{
64	ACPI_TABLE_HEADER *header;
65	vm_offset_t length;
66	void *table;
67
68	header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER));
69	if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
70		pmap_unmapbios((vm_offset_t)header, sizeof(ACPI_TABLE_HEADER));
71		return (NULL);
72	}
73	length = header->Length;
74	pmap_unmapbios((vm_offset_t)header, sizeof(ACPI_TABLE_HEADER));
75
76	table = pmap_mapbios(pa, length);
77	if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
78		if (bootverbose)
79			printf("ACPI: Failed checksum for table %s\n", sig);
80#if (ACPI_CHECKSUM_ABORT)
81		pmap_unmapbios(table, length);
82		return (NULL);
83#endif
84	}
85	return (table);
86}
87
88/*
89 * See if a given ACPI table is the requested table.  Returns the
90 * length of the able if it matches or zero on failure.
91 */
92static int
93probe_table(vm_paddr_t address, const char *sig)
94{
95	ACPI_TABLE_HEADER *table;
96
97	table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER));
98	if (table == NULL) {
99		if (bootverbose)
100			printf("ACPI: Failed to map table at 0x%jx\n",
101			    (uintmax_t)address);
102		return (0);
103	}
104	if (bootverbose)
105		printf("Table '%.4s' at 0x%jx\n", table->Signature,
106		    (uintmax_t)address);
107
108	if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
109		pmap_unmapbios((vm_offset_t)table, sizeof(ACPI_TABLE_HEADER));
110		return (0);
111	}
112	pmap_unmapbios((vm_offset_t)table, sizeof(ACPI_TABLE_HEADER));
113	return (1);
114}
115
116/* Unmap a table previously mapped via acpi_map_table(). */
117void
118acpi_unmap_table(void *table)
119{
120	ACPI_TABLE_HEADER *header;
121
122	header = (ACPI_TABLE_HEADER *)table;
123	pmap_unmapbios((vm_offset_t)table, header->Length);
124}
125
126/*
127 * Try to map a table at a given physical address previously returned
128 * by acpi_find_table().
129 */
130void *
131acpi_map_table(vm_paddr_t pa, const char *sig)
132{
133
134	return (map_table(pa, 0, sig));
135}
136
137/*
138 * Return the physical address of the requested table or zero if one
139 * is not found.
140 */
141vm_paddr_t
142acpi_find_table(const char *sig)
143{
144	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
145	ACPI_TABLE_RSDP *rsdp;
146	ACPI_TABLE_XSDT *xsdt;
147	ACPI_TABLE_HEADER *table;
148	vm_paddr_t addr;
149	int i, count;
150
151	if (resource_disabled("acpi", 0))
152		return (0);
153
154	/*
155	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
156	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
157	 * pmap_mapbios() to map the RSDP.
158	 */
159	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
160		return (0);
161	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
162	if (rsdp == NULL) {
163		if (bootverbose)
164			printf("ACPI: Failed to map RSDP\n");
165		return (0);
166	}
167
168	addr = 0;
169	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
170		/*
171		 * AcpiOsGetRootPointer only verifies the checksum for
172		 * the version 1.0 portion of the RSDP.  Version 2.0 has
173		 * an additional checksum that we verify first.
174		 */
175		if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
176			if (bootverbose)
177				printf("ACPI: RSDP failed extended checksum\n");
178			return (0);
179		}
180		xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
181		if (xsdt == NULL) {
182			if (bootverbose)
183				printf("ACPI: Failed to map XSDT\n");
184			pmap_unmapbios((vm_offset_t)rsdp,
185			    sizeof(ACPI_TABLE_RSDP));
186			return (0);
187		}
188		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
189		    sizeof(UINT64);
190		for (i = 0; i < count; i++)
191			if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
192				addr = xsdt->TableOffsetEntry[i];
193				break;
194			}
195		acpi_unmap_table(xsdt);
196	}
197	pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
198
199	if (addr == 0) {
200		if (bootverbose)
201			printf("ACPI: No %s table found\n", sig);
202		return (0);
203	}
204	if (bootverbose)
205		printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
206
207	/*
208	 * Verify that we can map the full table and that its checksum is
209	 * correct, etc.
210	 */
211	table = map_table(addr, 0, sig);
212	if (table == NULL)
213		return (0);
214	acpi_unmap_table(table);
215
216	return (addr);
217}
218