2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <machine/pmap.h>
39 #include <machine/smp.h>
41 #define ACPI_RSDP_EBDA_MAPSZ 1024
42 #define ACPI_RSDP_BIOS_MAPSZ 0x20000
43 #define ACPI_RSDP_BIOS_MAPADDR 0xe0000
45 #define ACPI_RSDP_ALIGN 16
47 #define ACPI_RSDP_SIGLEN 8
48 #define ACPI_RSDP_SIG "RSD PTR "
50 #define ACPI_SDTH_SIGLEN 4
51 #define ACPI_RSDT_SIG "RSDT"
52 #define ACPI_XSDT_SIG "XSDT"
53 #define ACPI_MADT_SIG "APIC"
55 /* Root System Description Pointer */
57 uint8_t rsdp_sig
[ACPI_RSDP_SIGLEN
];
59 uint8_t rsdp_oem_id
[6];
64 uint8_t rsdp_ext_cksum
;
68 /* System Description Table Header */
70 uint8_t sdth_sig
[ACPI_SDTH_SIGLEN
];
74 uint8_t sdth_oem_id
[6];
75 uint8_t sdth_oem_tbid
[8];
76 uint32_t sdth_oem_rev
;
78 uint32_t sdth_crt_rev
;
81 /* Extended System Description Table */
83 struct acpi_sdth xsdt_hdr
;
84 uint64_t xsdt_ents
[1];
87 /* Root System Description Table */
89 struct acpi_sdth rsdt_hdr
;
90 uint32_t rsdt_ents
[1];
93 /* Multiple APIC Description Table */
95 struct acpi_sdth madt_hdr
;
96 uint32_t madt_lapic_addr
;
101 /* Common parts of MADT APIC structure */
102 struct acpi_madt_ent
{
103 uint8_t me_type
; /* MADT_ENT_ */
107 #define MADT_ENT_LAPIC 0
109 /* MADT Processor Local APIC */
110 struct acpi_madt_lapic
{
111 struct acpi_madt_ent ml_hdr
;
114 uint32_t ml_flags
; /* MADT_LAPIC_ */
117 #define MADT_LAPIC_ENABLED 0x1
119 typedef vm_paddr_t (*madt_search_t
)(vm_paddr_t
);
121 static const struct acpi_rsdp
*madt_rsdp_search(const uint8_t *, int);
122 static void *madt_sdth_map(vm_paddr_t
);
123 static void madt_sdth_unmap(struct acpi_sdth
*);
124 static vm_paddr_t
madt_search_xsdt(vm_paddr_t
);
125 static vm_paddr_t
madt_search_rsdt(vm_paddr_t
);
126 static int madt_parse(vm_paddr_t
);
128 extern u_long ebda_addr
;
133 const struct acpi_rsdp
*rsdp
;
134 madt_search_t search
;
135 vm_paddr_t search_paddr
, madt_paddr
;
139 if (ebda_addr
!= 0) {
140 mapsz
= ACPI_RSDP_EBDA_MAPSZ
;
141 ptr
= pmap_mapdev(ebda_addr
, mapsz
);
143 rsdp
= madt_rsdp_search(ptr
, mapsz
);
145 kprintf("madt: RSDP not in EBDA\n");
146 pmap_unmapdev((vm_offset_t
)ptr
, mapsz
);
151 kprintf("madt: RSDP in EBDA\n");
156 mapsz
= ACPI_RSDP_BIOS_MAPSZ
;
157 ptr
= pmap_mapdev(ACPI_RSDP_BIOS_MAPADDR
, mapsz
);
159 rsdp
= madt_rsdp_search(ptr
, mapsz
);
161 kprintf("madt_probe: no RSDP\n");
162 pmap_unmapdev((vm_offset_t
)ptr
, mapsz
);
165 kprintf("madt: RSDP in BIOS mem\n");
169 if (rsdp
->rsdp_rev
!= 2) {
170 search_paddr
= rsdp
->rsdp_rsdt
;
171 search
= madt_search_rsdt
;
173 search_paddr
= rsdp
->rsdp_xsdt
;
174 search
= madt_search_xsdt
;
176 pmap_unmapdev((vm_offset_t
)ptr
, mapsz
);
178 madt_paddr
= search(search_paddr
);
179 if (madt_paddr
== 0) {
180 kprintf("madt_probe: can't locate MADT\n");
183 return madt_parse(madt_paddr
);
186 static const struct acpi_rsdp
*
187 madt_rsdp_search(const uint8_t *target
, int size
)
189 const struct acpi_rsdp
*rsdp
;
192 KKASSERT(size
> sizeof(*rsdp
));
194 for (i
= 0; i
< size
- sizeof(*rsdp
); i
+= ACPI_RSDP_ALIGN
) {
195 rsdp
= (const struct acpi_rsdp
*)&target
[i
];
196 if (memcmp(rsdp
->rsdp_sig
, ACPI_RSDP_SIG
,
197 ACPI_RSDP_SIGLEN
) == 0)
204 madt_sdth_map(vm_paddr_t paddr
)
206 struct acpi_sdth
*sdth
;
209 sdth
= pmap_mapdev(paddr
, sizeof(*sdth
));
210 mapsz
= sdth
->sdth_len
;
211 pmap_unmapdev((vm_offset_t
)sdth
, sizeof(*sdth
));
213 if (mapsz
< sizeof(*sdth
))
216 return pmap_mapdev(paddr
, mapsz
);
220 madt_sdth_unmap(struct acpi_sdth
*sdth
)
222 pmap_unmapdev((vm_offset_t
)sdth
, sdth
->sdth_len
);
226 madt_search_xsdt(vm_paddr_t xsdt_paddr
)
228 struct acpi_xsdt
*xsdt
;
229 vm_paddr_t madt_paddr
= 0;
232 if (xsdt_paddr
== 0) {
233 kprintf("madt_search_xsdt: XSDT paddr == 0\n");
237 xsdt
= madt_sdth_map(xsdt_paddr
);
239 kprintf("madt_search_xsdt: can't map XSDT\n");
243 if (memcmp(xsdt
->xsdt_hdr
.sdth_sig
, ACPI_XSDT_SIG
,
244 ACPI_SDTH_SIGLEN
) != 0) {
245 kprintf("madt_search_xsdt: not XSDT\n");
249 if (xsdt
->xsdt_hdr
.sdth_rev
!= 1) {
250 kprintf("madt_search_xsdt: unsupported XSDT revision %d\n",
251 xsdt
->xsdt_hdr
.sdth_rev
);
255 nent
= (xsdt
->xsdt_hdr
.sdth_len
- sizeof(xsdt
->xsdt_hdr
)) /
256 sizeof(xsdt
->xsdt_ents
[0]);
257 for (i
= 0; i
< nent
; ++i
) {
258 struct acpi_sdth
*sdth
;
260 if (xsdt
->xsdt_ents
[i
] == 0)
263 sdth
= madt_sdth_map(xsdt
->xsdt_ents
[i
]);
267 ret
= memcmp(sdth
->sdth_sig
, ACPI_MADT_SIG
,
269 madt_sdth_unmap(sdth
);
272 kprintf("madt: MADT in XSDT\n");
273 madt_paddr
= xsdt
->xsdt_ents
[i
];
279 madt_sdth_unmap(&xsdt
->xsdt_hdr
);
284 madt_search_rsdt(vm_paddr_t rsdt_paddr
)
286 struct acpi_rsdt
*rsdt
;
287 vm_paddr_t madt_paddr
= 0;
290 if (rsdt_paddr
== 0) {
291 kprintf("madt_search_rsdt: RSDT paddr == 0\n");
295 rsdt
= madt_sdth_map(rsdt_paddr
);
297 kprintf("madt_search_rsdt: can't map RSDT\n");
301 if (memcmp(rsdt
->rsdt_hdr
.sdth_sig
, ACPI_RSDT_SIG
,
302 ACPI_SDTH_SIGLEN
) != 0) {
303 kprintf("madt_search_rsdt: not RSDT\n");
307 if (rsdt
->rsdt_hdr
.sdth_rev
!= 1) {
308 kprintf("madt_search_rsdt: unsupported RSDT revision %d\n",
309 rsdt
->rsdt_hdr
.sdth_rev
);
313 nent
= (rsdt
->rsdt_hdr
.sdth_len
- sizeof(rsdt
->rsdt_hdr
)) /
314 sizeof(rsdt
->rsdt_ents
[0]);
315 for (i
= 0; i
< nent
; ++i
) {
316 struct acpi_sdth
*sdth
;
318 if (rsdt
->rsdt_ents
[i
] == 0)
321 sdth
= madt_sdth_map(rsdt
->rsdt_ents
[i
]);
325 ret
= memcmp(sdth
->sdth_sig
, ACPI_MADT_SIG
,
327 madt_sdth_unmap(sdth
);
330 kprintf("madt: MADT in RSDT\n");
331 madt_paddr
= rsdt
->rsdt_ents
[i
];
337 madt_sdth_unmap(&rsdt
->rsdt_hdr
);
342 madt_parse(vm_paddr_t madt_paddr
)
344 struct acpi_madt
*madt
;
345 int size
, cur
, error
;
347 KKASSERT(madt_paddr
!= 0);
349 madt
= madt_sdth_map(madt_paddr
);
350 KKASSERT(madt
!= NULL
);
352 if (madt
->madt_hdr
.sdth_rev
!= 1 && madt
->madt_hdr
.sdth_rev
!= 2) {
353 kprintf("madt_parse: unsupported MADT revision %d\n",
354 madt
->madt_hdr
.sdth_rev
);
359 if (madt
->madt_hdr
.sdth_len
<
360 sizeof(*madt
) - sizeof(madt
->madt_ents
)) {
361 kprintf("madt_parse: invalid MADT length %u\n",
362 madt
->madt_hdr
.sdth_len
);
367 kprintf("madt: LAPIC address 0x%08x, flags %#x\n",
368 madt
->madt_lapic_addr
, madt
->madt_flags
);
370 size
= madt
->madt_hdr
.sdth_len
-
371 (sizeof(*madt
) - sizeof(madt
->madt_ents
));
375 while (size
- cur
> sizeof(struct acpi_madt_ent
)) {
376 const struct acpi_madt_ent
*ent
;
378 ent
= (const struct acpi_madt_ent
*)&madt
->madt_ents
[cur
];
379 if (ent
->me_len
< sizeof(*ent
)) {
380 kprintf("madt_parse: invalid MADT entry len %d\n",
385 if (ent
->me_len
> (size
- cur
)) {
386 kprintf("madt_parse: invalid MADT entry len %d, "
387 "> table length\n", ent
->me_len
);
394 if (ent
->me_type
== MADT_ENT_LAPIC
) {
395 const struct acpi_madt_lapic
*lapic_ent
;
397 if (ent
->me_len
< sizeof(*lapic_ent
)) {
398 kprintf("madt_parse: invalid MADT lapic entry "
399 "len %d\n", ent
->me_len
);
403 lapic_ent
= (const struct acpi_madt_lapic
*)ent
;
404 if (lapic_ent
->ml_flags
& MADT_LAPIC_ENABLED
) {
405 kprintf("madt: cpu_id %d, apic_id %d\n",
406 lapic_ent
->ml_cpu_id
,
407 lapic_ent
->ml_apic_id
);
412 madt_sdth_unmap(&madt
->madt_hdr
);