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