64c2b9e88b42e765dd56b03cf71efc76c4fe2f24
[dragonfly.git] / sys / platform / pc32 / acpica5 / acpi_sdt.c
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/bus.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39
40 #include <machine/pmap.h>
41 #include <machine/smp.h>
42 #include <machine/md_var.h>
43 #include <machine/specialreg.h>
44 #include <machine_base/apic/mpapic.h>
45
46 #include "acpi_sdt.h"
47 #include "acpi_sdt_var.h"
48
49 #define SDT_VPRINTF(fmt, arg...) \
50 do { \
51         if (bootverbose) \
52                 kprintf("ACPI SDT: " fmt , ##arg); \
53 } while (0)
54
55 #define ACPI_RSDP_EBDA_MAPSZ    1024
56 #define ACPI_RSDP_BIOS_MAPSZ    0x20000
57 #define ACPI_RSDP_BIOS_MAPADDR  0xe0000
58
59 #define ACPI_RSDP_ALIGN         16
60
61 #define ACPI_RSDP_SIGLEN        8
62 #define ACPI_RSDP_SIG           "RSD PTR "
63
64 /* Root System Description Pointer */
65 struct acpi_rsdp {
66         uint8_t                 rsdp_sig[ACPI_RSDP_SIGLEN];
67         uint8_t                 rsdp_cksum;
68         uint8_t                 rsdp_oem_id[6];
69         uint8_t                 rsdp_rev;
70         uint32_t                rsdp_rsdt;
71         uint32_t                rsdp_len;
72         uint64_t                rsdp_xsdt;
73         uint8_t                 rsdp_ext_cksum;
74         uint8_t                 rsdp_rsvd[3];
75 } __packed;
76
77 /* Extended System Description Table */
78 struct acpi_xsdt {
79         struct acpi_sdth        xsdt_hdr;
80         uint64_t                xsdt_ents[1];
81 } __packed;
82
83 /* Root System Description Table */
84 struct acpi_rsdt {
85         struct acpi_sdth        rsdt_hdr;
86         uint32_t                rsdt_ents[1];
87 } __packed;
88
89 typedef vm_paddr_t              (*sdt_search_t)(vm_paddr_t, const uint8_t *);
90
91 static const struct acpi_rsdp   *sdt_rsdp_search(const uint8_t *, int);
92 static vm_paddr_t               sdt_search_xsdt(vm_paddr_t, const uint8_t *);
93 static vm_paddr_t               sdt_search_rsdt(vm_paddr_t, const uint8_t *);
94
95 extern u_long                   ebda_addr;
96
97 static sdt_search_t             sdt_search_func;
98 static vm_paddr_t               sdt_search_paddr;
99
100 static void
101 sdt_probe(void)
102 {
103         const struct acpi_rsdp *rsdp;
104         vm_size_t mapsz;
105         uint8_t *ptr;
106
107         if (ebda_addr != 0) {
108                 mapsz = ACPI_RSDP_EBDA_MAPSZ;
109                 ptr = pmap_mapdev(ebda_addr, mapsz);
110
111                 rsdp = sdt_rsdp_search(ptr, mapsz);
112                 if (rsdp == NULL) {
113                         SDT_VPRINTF("RSDP not in EBDA\n");
114                         pmap_unmapdev((vm_offset_t)ptr, mapsz);
115
116                         ptr = NULL;
117                         mapsz = 0;
118                 } else {
119                         SDT_VPRINTF("RSDP in EBDA\n");
120                         goto found_rsdp;
121                 }
122         }
123
124         mapsz = ACPI_RSDP_BIOS_MAPSZ;
125         ptr = pmap_mapdev(ACPI_RSDP_BIOS_MAPADDR, mapsz);
126
127         rsdp = sdt_rsdp_search(ptr, mapsz);
128         if (rsdp == NULL) {
129                 kprintf("sdt_probe: no RSDP\n");
130                 pmap_unmapdev((vm_offset_t)ptr, mapsz);
131                 return;
132         } else {
133                 SDT_VPRINTF("RSDP in BIOS mem\n");
134         }
135
136 found_rsdp:
137         if (rsdp->rsdp_rev != 2) {
138                 sdt_search_func = sdt_search_rsdt;
139                 sdt_search_paddr = rsdp->rsdp_rsdt;
140         } else {
141                 sdt_search_func = sdt_search_xsdt;
142                 sdt_search_paddr = rsdp->rsdp_xsdt;
143         }
144         pmap_unmapdev((vm_offset_t)ptr, mapsz);
145 }
146 SYSINIT(sdt_probe, SI_BOOT2_PRESMP, SI_ORDER_FIRST, sdt_probe, 0);
147
148 static const struct acpi_rsdp *
149 sdt_rsdp_search(const uint8_t *target, int size)
150 {
151         const struct acpi_rsdp *rsdp;
152         int i;
153
154         KKASSERT(size > sizeof(*rsdp));
155
156         for (i = 0; i < size - sizeof(*rsdp); i += ACPI_RSDP_ALIGN) {
157                 rsdp = (const struct acpi_rsdp *)&target[i];
158                 if (memcmp(rsdp->rsdp_sig, ACPI_RSDP_SIG,
159                            ACPI_RSDP_SIGLEN) == 0)
160                         return rsdp;
161         }
162         return NULL;
163 }
164
165 void *
166 sdt_sdth_map(vm_paddr_t paddr)
167 {
168         struct acpi_sdth *sdth;
169         vm_size_t mapsz;
170
171         sdth = pmap_mapdev(paddr, sizeof(*sdth));
172         mapsz = sdth->sdth_len;
173         pmap_unmapdev((vm_offset_t)sdth, sizeof(*sdth));
174
175         if (mapsz < sizeof(*sdth))
176                 return NULL;
177
178         return pmap_mapdev(paddr, mapsz);
179 }
180
181 void
182 sdt_sdth_unmap(struct acpi_sdth *sdth)
183 {
184         pmap_unmapdev((vm_offset_t)sdth, sdth->sdth_len);
185 }
186
187 static vm_paddr_t
188 sdt_search_xsdt(vm_paddr_t xsdt_paddr, const uint8_t *sig)
189 {
190         struct acpi_xsdt *xsdt;
191         vm_paddr_t sdt_paddr = 0;
192         int i, nent;
193
194         if (xsdt_paddr == 0) {
195                 kprintf("sdt_search_xsdt: XSDT paddr == 0\n");
196                 return 0;
197         }
198
199         xsdt = sdt_sdth_map(xsdt_paddr);
200         if (xsdt == NULL) {
201                 kprintf("sdt_search_xsdt: can't map XSDT\n");
202                 return 0;
203         }
204
205         if (memcmp(xsdt->xsdt_hdr.sdth_sig, ACPI_XSDT_SIG,
206                    ACPI_SDTH_SIGLEN) != 0) {
207                 kprintf("sdt_search_xsdt: not XSDT\n");
208                 goto back;
209         }
210
211         if (xsdt->xsdt_hdr.sdth_rev != 1) {
212                 kprintf("sdt_search_xsdt: unsupported XSDT revision %d\n",
213                         xsdt->xsdt_hdr.sdth_rev);
214                 goto back;
215         }
216
217         nent = (xsdt->xsdt_hdr.sdth_len - sizeof(xsdt->xsdt_hdr)) /
218                sizeof(xsdt->xsdt_ents[0]);
219         for (i = 0; i < nent; ++i) {
220                 struct acpi_sdth *sdth;
221
222                 if (xsdt->xsdt_ents[i] == 0)
223                         continue;
224
225                 sdth = sdt_sdth_map(xsdt->xsdt_ents[i]);
226                 if (sdth != NULL) {
227                         int ret;
228
229                         ret = memcmp(sdth->sdth_sig, sig, ACPI_SDTH_SIGLEN);
230                         sdt_sdth_unmap(sdth);
231
232                         if (ret == 0) {
233                                 sdt_paddr = xsdt->xsdt_ents[i];
234                                 break;
235                         }
236                 }
237         }
238 back:
239         sdt_sdth_unmap(&xsdt->xsdt_hdr);
240         return sdt_paddr;
241 }
242
243 static vm_paddr_t
244 sdt_search_rsdt(vm_paddr_t rsdt_paddr, const uint8_t *sig)
245 {
246         struct acpi_rsdt *rsdt;
247         vm_paddr_t sdt_paddr = 0;
248         int i, nent;
249
250         if (rsdt_paddr == 0) {
251                 kprintf("sdt_search_rsdt: RSDT paddr == 0\n");
252                 return 0;
253         }
254
255         rsdt = sdt_sdth_map(rsdt_paddr);
256         if (rsdt == NULL) {
257                 kprintf("sdt_search_rsdt: can't map RSDT\n");
258                 return 0;
259         }
260
261         if (memcmp(rsdt->rsdt_hdr.sdth_sig, ACPI_RSDT_SIG,
262                    ACPI_SDTH_SIGLEN) != 0) {
263                 kprintf("sdt_search_rsdt: not RSDT\n");
264                 goto back;
265         }
266
267         if (rsdt->rsdt_hdr.sdth_rev != 1) {
268                 kprintf("sdt_search_rsdt: unsupported RSDT revision %d\n",
269                         rsdt->rsdt_hdr.sdth_rev);
270                 goto back;
271         }
272
273         nent = (rsdt->rsdt_hdr.sdth_len - sizeof(rsdt->rsdt_hdr)) /
274                sizeof(rsdt->rsdt_ents[0]);
275         for (i = 0; i < nent; ++i) {
276                 struct acpi_sdth *sdth;
277
278                 if (rsdt->rsdt_ents[i] == 0)
279                         continue;
280
281                 sdth = sdt_sdth_map(rsdt->rsdt_ents[i]);
282                 if (sdth != NULL) {
283                         int ret;
284
285                         ret = memcmp(sdth->sdth_sig, sig, ACPI_SDTH_SIGLEN);
286                         sdt_sdth_unmap(sdth);
287
288                         if (ret == 0) {
289                                 sdt_paddr = rsdt->rsdt_ents[i];
290                                 break;
291                         }
292                 }
293         }
294 back:
295         sdt_sdth_unmap(&rsdt->rsdt_hdr);
296         return sdt_paddr;
297 }
298
299 vm_paddr_t
300 sdt_search(const uint8_t *sig)
301 {
302         if (sdt_search_func == NULL)
303                 return 0;
304         return sdt_search_func(sdt_search_paddr, sig);
305 }