xref: /dragonfly/sys/platform/pc64/acpica/acpi_sdt.c (revision cf37dc20)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 
39 #include <machine/pmap.h>
40 
41 #include <contrib/dev/acpica/source/include/acpi.h>
42 
43 #include "acpi_sdt_var.h"
44 
45 #define SDT_VPRINTF(fmt, arg...) \
46 do { \
47 	if (bootverbose) \
48 		kprintf("ACPI SDT: " fmt , ##arg); \
49 } while (0)
50 
51 typedef	vm_paddr_t		(*sdt_search_t)(vm_paddr_t, const uint8_t *);
52 
53 static const ACPI_TABLE_RSDP	*sdt_rsdp_search(const uint8_t *, int);
54 static vm_paddr_t		sdt_search_xsdt(vm_paddr_t, const uint8_t *);
55 static vm_paddr_t		sdt_search_rsdt(vm_paddr_t, const uint8_t *);
56 
57 extern u_long			ebda_addr;
58 
59 static sdt_search_t		sdt_search_func;
60 static vm_paddr_t		sdt_search_paddr;
61 
62 static void
63 sdt_probe(void)
64 {
65 	const ACPI_TABLE_RSDP *rsdp;
66 	vm_size_t mapsz;
67 	uint8_t *ptr;
68 
69 	if (ebda_addr != 0) {
70 		mapsz = ACPI_EBDA_WINDOW_SIZE;
71 		ptr = pmap_mapdev(ebda_addr, mapsz);
72 
73 		rsdp = sdt_rsdp_search(ptr, mapsz);
74 		if (rsdp == NULL) {
75 			SDT_VPRINTF("RSDP not in EBDA\n");
76 			pmap_unmapdev((vm_offset_t)ptr, mapsz);
77 
78 			ptr = NULL;
79 			mapsz = 0;
80 		} else {
81 			SDT_VPRINTF("RSDP in EBDA\n");
82 			goto found_rsdp;
83 		}
84 	}
85 
86 	mapsz = ACPI_HI_RSDP_WINDOW_SIZE;
87 	ptr = pmap_mapdev(ACPI_HI_RSDP_WINDOW_BASE, mapsz);
88 
89 	rsdp = sdt_rsdp_search(ptr, mapsz);
90 	if (rsdp == NULL) {
91 		kprintf("sdt_probe: no RSDP\n");
92 		pmap_unmapdev((vm_offset_t)ptr, mapsz);
93 		return;
94 	} else {
95 		SDT_VPRINTF("RSDP in BIOS mem\n");
96 	}
97 
98 found_rsdp:
99 	if (rsdp->Revision != 2 /* || AcpiGbl_DoNotUseXsdt */) {
100 		sdt_search_func = sdt_search_rsdt;
101 		sdt_search_paddr = rsdp->RsdtPhysicalAddress;
102 	} else {
103 		sdt_search_func = sdt_search_xsdt;
104 		sdt_search_paddr = rsdp->XsdtPhysicalAddress;
105 	}
106 	pmap_unmapdev((vm_offset_t)ptr, mapsz);
107 }
108 SYSINIT(sdt_probe, SI_BOOT2_PRESMP, SI_ORDER_FIRST, sdt_probe, 0);
109 
110 static const ACPI_TABLE_RSDP *
111 sdt_rsdp_search(const uint8_t *target, int size)
112 {
113 	const ACPI_TABLE_RSDP *rsdp;
114 	int i;
115 
116 	KKASSERT(size > sizeof(*rsdp));
117 
118 	for (i = 0; i < size - sizeof(*rsdp); i += ACPI_RSDP_SCAN_STEP) {
119 		rsdp = (const ACPI_TABLE_RSDP *)&target[i];
120 		if (memcmp(rsdp->Signature, ACPI_SIG_RSDP,
121 			   sizeof(rsdp->Signature)) == 0)
122 			return rsdp;
123 	}
124 	return NULL;
125 }
126 
127 void *
128 sdt_sdth_map(vm_paddr_t paddr)
129 {
130 	ACPI_TABLE_HEADER *sdth;
131 	vm_size_t mapsz;
132 
133 	sdth = pmap_mapdev(paddr, sizeof(*sdth));
134 	mapsz = sdth->Length;
135 	pmap_unmapdev((vm_offset_t)sdth, sizeof(*sdth));
136 
137 	if (mapsz < sizeof(*sdth))
138 		return NULL;
139 
140 	return pmap_mapdev(paddr, mapsz);
141 }
142 
143 void
144 sdt_sdth_unmap(ACPI_TABLE_HEADER *sdth)
145 {
146 	pmap_unmapdev((vm_offset_t)sdth, sdth->Length);
147 }
148 
149 static vm_paddr_t
150 sdt_search_xsdt(vm_paddr_t xsdt_paddr, const uint8_t *sig)
151 {
152 	ACPI_TABLE_XSDT *xsdt;
153 	vm_paddr_t sdt_paddr = 0;
154 	int i, nent;
155 
156 	if (xsdt_paddr == 0) {
157 		kprintf("sdt_search_xsdt: XSDT paddr == 0\n");
158 		return 0;
159 	}
160 
161 	xsdt = sdt_sdth_map(xsdt_paddr);
162 	if (xsdt == NULL) {
163 		kprintf("sdt_search_xsdt: can't map XSDT\n");
164 		return 0;
165 	}
166 
167 	if (memcmp(xsdt->Header.Signature, ACPI_SIG_XSDT,
168 		   ACPI_NAME_SIZE) != 0) {
169 		kprintf("sdt_search_xsdt: not XSDT\n");
170 		goto back;
171 	}
172 
173 	if (xsdt->Header.Revision != 1) {
174 		kprintf("sdt_search_xsdt: unknown XSDT revision %d\n",
175 			xsdt->Header.Revision);
176 	}
177 
178 	if (xsdt->Header.Length < sizeof(xsdt->Header)) {
179 		kprintf("sdt_search_xsdt: invalid XSDT length %u\n",
180 			xsdt->Header.Length);
181 		goto back;
182 	}
183 
184 	nent = (xsdt->Header.Length - sizeof(xsdt->Header)) /
185 	       sizeof(xsdt->TableOffsetEntry[0]);
186 	for (i = 0; i < nent; ++i) {
187 		ACPI_TABLE_HEADER *sdth;
188 
189 		if (xsdt->TableOffsetEntry[i] == 0)
190 			continue;
191 
192 		sdth = sdt_sdth_map(xsdt->TableOffsetEntry[i]);
193 		if (sdth != NULL) {
194 			int ret;
195 
196 			ret = memcmp(sdth->Signature, sig, ACPI_NAME_SIZE);
197 			sdt_sdth_unmap(sdth);
198 
199 			if (ret == 0) {
200 				sdt_paddr = xsdt->TableOffsetEntry[i];
201 				break;
202 			}
203 		}
204 	}
205 back:
206 	sdt_sdth_unmap(&xsdt->Header);
207 	return sdt_paddr;
208 }
209 
210 static vm_paddr_t
211 sdt_search_rsdt(vm_paddr_t rsdt_paddr, const uint8_t *sig)
212 {
213 	ACPI_TABLE_RSDT *rsdt;
214 	vm_paddr_t sdt_paddr = 0;
215 	int i, nent;
216 
217 	if (rsdt_paddr == 0) {
218 		kprintf("sdt_search_rsdt: RSDT paddr == 0\n");
219 		return 0;
220 	}
221 
222 	rsdt = sdt_sdth_map(rsdt_paddr);
223 	if (rsdt == NULL) {
224 		kprintf("sdt_search_rsdt: can't map RSDT\n");
225 		return 0;
226 	}
227 
228 	if (memcmp(rsdt->Header.Signature, ACPI_SIG_RSDT,
229 		   ACPI_NAME_SIZE) != 0) {
230 		kprintf("sdt_search_rsdt: not RSDT\n");
231 		goto back;
232 	}
233 
234 	if (rsdt->Header.Revision != 1) {
235 		kprintf("sdt_search_rsdt: unknown RSDT revision %d\n",
236 			rsdt->Header.Revision);
237 	}
238 
239 	if (rsdt->Header.Length < sizeof(rsdt->Header)) {
240 		kprintf("sdt_search_rsdt: invalid RSDT length %u\n",
241 			rsdt->Header.Length);
242 		goto back;
243 	}
244 
245 	nent = (rsdt->Header.Length - sizeof(rsdt->Header)) /
246 	       sizeof(rsdt->TableOffsetEntry[0]);
247 	for (i = 0; i < nent; ++i) {
248 		ACPI_TABLE_HEADER *sdth;
249 
250 		if (rsdt->TableOffsetEntry[i] == 0)
251 			continue;
252 
253 		sdth = sdt_sdth_map(rsdt->TableOffsetEntry[i]);
254 		if (sdth != NULL) {
255 			int ret;
256 
257 			ret = memcmp(sdth->Signature, sig, ACPI_NAME_SIZE);
258 			sdt_sdth_unmap(sdth);
259 
260 			if (ret == 0) {
261 				sdt_paddr = rsdt->TableOffsetEntry[i];
262 				break;
263 			}
264 		}
265 	}
266 back:
267 	sdt_sdth_unmap(&rsdt->Header);
268 	return sdt_paddr;
269 }
270 
271 vm_paddr_t
272 sdt_search(const uint8_t *sig)
273 {
274 	if (sdt_search_func == NULL)
275 		return 0;
276 	return sdt_search_func(sdt_search_paddr, sig);
277 }
278