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/kernel.h>
37 #include <sys/systm.h>
39 #include <machine/pmap.h>
40 #include <machine/smp.h>
41 #include <machine/md_var.h>
42 #include <machine/specialreg.h>
43 #include <machine_base/apic/mpapic.h>
45 #define MADT_VPRINTF(fmt, arg...) \
48 kprintf("ACPI MADT: " fmt , ##arg); \
51 #define ACPI_RSDP_EBDA_MAPSZ 1024
52 #define ACPI_RSDP_BIOS_MAPSZ 0x20000
53 #define ACPI_RSDP_BIOS_MAPADDR 0xe0000
55 #define ACPI_RSDP_ALIGN 16
57 #define ACPI_RSDP_SIGLEN 8
58 #define ACPI_RSDP_SIG "RSD PTR "
60 #define ACPI_SDTH_SIGLEN 4
61 #define ACPI_RSDT_SIG "RSDT"
62 #define ACPI_XSDT_SIG "XSDT"
63 #define ACPI_MADT_SIG "APIC"
65 /* Root System Description Pointer */
67 uint8_t rsdp_sig
[ACPI_RSDP_SIGLEN
];
69 uint8_t rsdp_oem_id
[6];
74 uint8_t rsdp_ext_cksum
;
78 /* System Description Table Header */
80 uint8_t sdth_sig
[ACPI_SDTH_SIGLEN
];
84 uint8_t sdth_oem_id
[6];
85 uint8_t sdth_oem_tbid
[8];
86 uint32_t sdth_oem_rev
;
88 uint32_t sdth_crt_rev
;
91 /* Extended System Description Table */
93 struct acpi_sdth xsdt_hdr
;
94 uint64_t xsdt_ents
[1];
97 /* Root System Description Table */
99 struct acpi_sdth rsdt_hdr
;
100 uint32_t rsdt_ents
[1];
103 /* Multiple APIC Description Table */
105 struct acpi_sdth madt_hdr
;
106 uint32_t madt_lapic_addr
;
108 uint8_t madt_ents
[1];
111 /* Common parts of MADT APIC structure */
112 struct acpi_madt_ent
{
113 uint8_t me_type
; /* MADT_ENT_ */
117 #define MADT_ENT_LAPIC 0
118 #define MADT_ENT_IOAPIC 1
119 #define MADT_ENT_LAPIC_ADDR 5
121 /* MADT Processor Local APIC */
122 struct acpi_madt_lapic
{
123 struct acpi_madt_ent ml_hdr
;
126 uint32_t ml_flags
; /* MADT_LAPIC_ */
129 #define MADT_LAPIC_ENABLED 0x1
132 struct acpi_madt_ioapic
{
133 struct acpi_madt_ent mio_hdr
;
135 uint8_t mio_reserved
;
137 uint32_t mio_gsi_base
;
140 /* MADT Local APIC Address Override */
141 struct acpi_madt_lapic_addr
{
142 struct acpi_madt_ent mla_hdr
;
143 uint16_t mla_reserved
;
144 uint64_t mla_lapic_addr
;
147 struct madt_lapic_enumerator
{
148 struct lapic_enumerator enumerator
;
149 vm_paddr_t madt_paddr
;
152 typedef vm_paddr_t (*madt_search_t
)(vm_paddr_t
);
153 typedef int (*madt_iter_t
)(void *,
154 const struct acpi_madt_ent
*);
156 static const struct acpi_rsdp
*madt_rsdp_search(const uint8_t *, int);
157 static void *madt_sdth_map(vm_paddr_t
);
158 static void madt_sdth_unmap(struct acpi_sdth
*);
159 static vm_paddr_t
madt_search_xsdt(vm_paddr_t
);
160 static vm_paddr_t
madt_search_rsdt(vm_paddr_t
);
161 static int madt_check(vm_paddr_t
);
162 static int madt_iterate_entries(struct acpi_madt
*,
163 madt_iter_t
, void *);
165 static vm_paddr_t
madt_probe(void);
166 static vm_offset_t
madt_pass1(vm_paddr_t
);
167 static int madt_pass2(vm_paddr_t
, int);
169 static void madt_lapic_enumerate(struct lapic_enumerator
*);
170 static int madt_lapic_probe(struct lapic_enumerator
*);
172 extern u_long ebda_addr
;
177 const struct acpi_rsdp
*rsdp
;
178 madt_search_t search
;
179 vm_paddr_t search_paddr
, madt_paddr
;
183 if (ebda_addr
!= 0) {
184 mapsz
= ACPI_RSDP_EBDA_MAPSZ
;
185 ptr
= pmap_mapdev(ebda_addr
, mapsz
);
187 rsdp
= madt_rsdp_search(ptr
, mapsz
);
189 MADT_VPRINTF("RSDP not in EBDA\n");
190 pmap_unmapdev((vm_offset_t
)ptr
, mapsz
);
195 MADT_VPRINTF("RSDP in EBDA\n");
200 mapsz
= ACPI_RSDP_BIOS_MAPSZ
;
201 ptr
= pmap_mapdev(ACPI_RSDP_BIOS_MAPADDR
, mapsz
);
203 rsdp
= madt_rsdp_search(ptr
, mapsz
);
205 kprintf("madt_probe: no RSDP\n");
206 pmap_unmapdev((vm_offset_t
)ptr
, mapsz
);
209 MADT_VPRINTF("RSDP in BIOS mem\n");
213 if (rsdp
->rsdp_rev
!= 2) {
214 search_paddr
= rsdp
->rsdp_rsdt
;
215 search
= madt_search_rsdt
;
217 search_paddr
= rsdp
->rsdp_xsdt
;
218 search
= madt_search_xsdt
;
220 pmap_unmapdev((vm_offset_t
)ptr
, mapsz
);
222 madt_paddr
= search(search_paddr
);
223 if (madt_paddr
== 0) {
224 kprintf("madt_probe: can't locate MADT\n");
228 /* Preliminary checks */
229 if (madt_check(madt_paddr
))
234 static const struct acpi_rsdp
*
235 madt_rsdp_search(const uint8_t *target
, int size
)
237 const struct acpi_rsdp
*rsdp
;
240 KKASSERT(size
> sizeof(*rsdp
));
242 for (i
= 0; i
< size
- sizeof(*rsdp
); i
+= ACPI_RSDP_ALIGN
) {
243 rsdp
= (const struct acpi_rsdp
*)&target
[i
];
244 if (memcmp(rsdp
->rsdp_sig
, ACPI_RSDP_SIG
,
245 ACPI_RSDP_SIGLEN
) == 0)
252 madt_sdth_map(vm_paddr_t paddr
)
254 struct acpi_sdth
*sdth
;
257 sdth
= pmap_mapdev(paddr
, sizeof(*sdth
));
258 mapsz
= sdth
->sdth_len
;
259 pmap_unmapdev((vm_offset_t
)sdth
, sizeof(*sdth
));
261 if (mapsz
< sizeof(*sdth
))
264 return pmap_mapdev(paddr
, mapsz
);
268 madt_sdth_unmap(struct acpi_sdth
*sdth
)
270 pmap_unmapdev((vm_offset_t
)sdth
, sdth
->sdth_len
);
274 madt_search_xsdt(vm_paddr_t xsdt_paddr
)
276 struct acpi_xsdt
*xsdt
;
277 vm_paddr_t madt_paddr
= 0;
280 if (xsdt_paddr
== 0) {
281 kprintf("madt_search_xsdt: XSDT paddr == 0\n");
285 xsdt
= madt_sdth_map(xsdt_paddr
);
287 kprintf("madt_search_xsdt: can't map XSDT\n");
291 if (memcmp(xsdt
->xsdt_hdr
.sdth_sig
, ACPI_XSDT_SIG
,
292 ACPI_SDTH_SIGLEN
) != 0) {
293 kprintf("madt_search_xsdt: not XSDT\n");
297 if (xsdt
->xsdt_hdr
.sdth_rev
!= 1) {
298 kprintf("madt_search_xsdt: unsupported XSDT revision %d\n",
299 xsdt
->xsdt_hdr
.sdth_rev
);
303 nent
= (xsdt
->xsdt_hdr
.sdth_len
- sizeof(xsdt
->xsdt_hdr
)) /
304 sizeof(xsdt
->xsdt_ents
[0]);
305 for (i
= 0; i
< nent
; ++i
) {
306 struct acpi_sdth
*sdth
;
308 if (xsdt
->xsdt_ents
[i
] == 0)
311 sdth
= madt_sdth_map(xsdt
->xsdt_ents
[i
]);
315 ret
= memcmp(sdth
->sdth_sig
, ACPI_MADT_SIG
,
317 madt_sdth_unmap(sdth
);
320 MADT_VPRINTF("MADT in XSDT\n");
321 madt_paddr
= xsdt
->xsdt_ents
[i
];
327 madt_sdth_unmap(&xsdt
->xsdt_hdr
);
332 madt_search_rsdt(vm_paddr_t rsdt_paddr
)
334 struct acpi_rsdt
*rsdt
;
335 vm_paddr_t madt_paddr
= 0;
338 if (rsdt_paddr
== 0) {
339 kprintf("madt_search_rsdt: RSDT paddr == 0\n");
343 rsdt
= madt_sdth_map(rsdt_paddr
);
345 kprintf("madt_search_rsdt: can't map RSDT\n");
349 if (memcmp(rsdt
->rsdt_hdr
.sdth_sig
, ACPI_RSDT_SIG
,
350 ACPI_SDTH_SIGLEN
) != 0) {
351 kprintf("madt_search_rsdt: not RSDT\n");
355 if (rsdt
->rsdt_hdr
.sdth_rev
!= 1) {
356 kprintf("madt_search_rsdt: unsupported RSDT revision %d\n",
357 rsdt
->rsdt_hdr
.sdth_rev
);
361 nent
= (rsdt
->rsdt_hdr
.sdth_len
- sizeof(rsdt
->rsdt_hdr
)) /
362 sizeof(rsdt
->rsdt_ents
[0]);
363 for (i
= 0; i
< nent
; ++i
) {
364 struct acpi_sdth
*sdth
;
366 if (rsdt
->rsdt_ents
[i
] == 0)
369 sdth
= madt_sdth_map(rsdt
->rsdt_ents
[i
]);
373 ret
= memcmp(sdth
->sdth_sig
, ACPI_MADT_SIG
,
375 madt_sdth_unmap(sdth
);
378 MADT_VPRINTF("MADT in RSDT\n");
379 madt_paddr
= rsdt
->rsdt_ents
[i
];
385 madt_sdth_unmap(&rsdt
->rsdt_hdr
);
390 madt_pass1_callback(void *xarg
, const struct acpi_madt_ent
*ent
)
392 const struct acpi_madt_lapic_addr
*lapic_addr_ent
;
393 uint64_t *addr64
= xarg
;
395 if (ent
->me_type
!= MADT_ENT_LAPIC_ADDR
)
397 if (ent
->me_len
< sizeof(*lapic_addr_ent
)) {
398 kprintf("madt_pass1: invalid LAPIC address override length\n");
401 lapic_addr_ent
= (const struct acpi_madt_lapic_addr
*)ent
;
403 *addr64
= lapic_addr_ent
->mla_lapic_addr
;
408 madt_pass1(vm_paddr_t madt_paddr
)
410 struct acpi_madt
*madt
;
411 vm_offset_t lapic_addr
;
412 uint64_t lapic_addr64
;
415 KKASSERT(madt_paddr
!= 0);
417 madt
= madt_sdth_map(madt_paddr
);
418 KKASSERT(madt
!= NULL
);
420 MADT_VPRINTF("LAPIC address 0x%08x, flags %#x\n",
421 madt
->madt_lapic_addr
, madt
->madt_flags
);
422 lapic_addr
= madt
->madt_lapic_addr
;
425 error
= madt_iterate_entries(madt
, madt_pass1_callback
, &lapic_addr64
);
427 panic("madt_iterate_entries(pass1) failed\n");
429 if (lapic_addr64
!= 0) {
430 kprintf("Warning: 64bits lapic address 0x%llx\n", lapic_addr64
);
431 /* XXX vm_offset_t is 32bits on i386 */
432 lapic_addr
= lapic_addr64
;
435 madt_sdth_unmap(&madt
->madt_hdr
);
440 struct madt_pass2_cbarg
{
447 madt_pass2_callback(void *xarg
, const struct acpi_madt_ent
*ent
)
449 const struct acpi_madt_lapic
*lapic_ent
;
450 struct madt_pass2_cbarg
*arg
= xarg
;
452 if (ent
->me_type
!= MADT_ENT_LAPIC
)
455 lapic_ent
= (const struct acpi_madt_lapic
*)ent
;
456 if (lapic_ent
->ml_flags
& MADT_LAPIC_ENABLED
) {
457 MADT_VPRINTF("cpu_id %d, apic_id %d\n",
458 lapic_ent
->ml_cpu_id
, lapic_ent
->ml_apic_id
);
459 if (lapic_ent
->ml_apic_id
== arg
->bsp_apic_id
) {
460 mp_set_cpuids(0, lapic_ent
->ml_apic_id
);
463 mp_set_cpuids(arg
->cpu
, lapic_ent
->ml_apic_id
);
471 madt_pass2(vm_paddr_t madt_paddr
, int bsp_apic_id
)
473 struct acpi_madt
*madt
;
474 struct madt_pass2_cbarg arg
;
477 MADT_VPRINTF("BSP apic id %d\n", bsp_apic_id
);
479 KKASSERT(madt_paddr
!= 0);
481 madt
= madt_sdth_map(madt_paddr
);
482 KKASSERT(madt
!= NULL
);
484 bzero(&arg
, sizeof(arg
));
486 arg
.bsp_apic_id
= bsp_apic_id
;
488 error
= madt_iterate_entries(madt
, madt_pass2_callback
, &arg
);
490 panic("madt_iterate_entries(pass2) failed\n");
492 KKASSERT(arg
.bsp_found
);
493 KKASSERT(arg
.cpu
> 1);
494 mp_naps
= arg
.cpu
- 1; /* exclude BSP */
496 madt_sdth_unmap(&madt
->madt_hdr
);
501 struct madt_check_cbarg
{
506 madt_check_callback(void *xarg
, const struct acpi_madt_ent
*ent
)
508 struct madt_check_cbarg
*arg
= xarg
;
509 const struct acpi_madt_lapic
*lapic_ent
;
511 if (ent
->me_type
!= MADT_ENT_LAPIC
)
513 lapic_ent
= (const struct acpi_madt_lapic
*)ent
;
515 if (lapic_ent
->ml_flags
& MADT_LAPIC_ENABLED
)
521 madt_check(vm_paddr_t madt_paddr
)
523 struct madt_check_cbarg arg
;
524 struct acpi_madt
*madt
;
527 KKASSERT(madt_paddr
!= 0);
529 madt
= madt_sdth_map(madt_paddr
);
530 KKASSERT(madt
!= NULL
);
532 if (madt
->madt_hdr
.sdth_rev
!= 1 && madt
->madt_hdr
.sdth_rev
!= 2) {
533 kprintf("madt_check: unsupported MADT revision %d\n",
534 madt
->madt_hdr
.sdth_rev
);
539 if (madt
->madt_hdr
.sdth_len
<
540 sizeof(*madt
) - sizeof(madt
->madt_ents
)) {
541 kprintf("madt_check: invalid MADT length %u\n",
542 madt
->madt_hdr
.sdth_len
);
547 bzero(&arg
, sizeof(arg
));
549 error
= madt_iterate_entries(madt
, madt_check_callback
, &arg
);
551 if (arg
.cpu_count
<= 1) {
552 kprintf("madt_check: less than 2 CPUs is found\n");
557 madt_sdth_unmap(&madt
->madt_hdr
);
562 madt_iterate_entries(struct acpi_madt
*madt
, madt_iter_t func
, void *arg
)
564 int size
, cur
, error
;
566 size
= madt
->madt_hdr
.sdth_len
-
567 (sizeof(*madt
) - sizeof(madt
->madt_ents
));
571 while (size
- cur
> sizeof(struct acpi_madt_ent
)) {
572 const struct acpi_madt_ent
*ent
;
574 ent
= (const struct acpi_madt_ent
*)&madt
->madt_ents
[cur
];
575 if (ent
->me_len
< sizeof(*ent
)) {
576 kprintf("madt_iterate_entries: invalid MADT "
577 "entry len %d\n", ent
->me_len
);
581 if (ent
->me_len
> (size
- cur
)) {
582 kprintf("madt_iterate_entries: invalid MADT "
583 "entry len %d, > table length\n", ent
->me_len
);
591 * Only Local APIC and I/O APIC are defined in
592 * ACPI specification 1.0 - 3.0
594 switch (ent
->me_type
) {
596 if (ent
->me_len
< sizeof(struct acpi_madt_lapic
)) {
597 kprintf("madt_iterate_entries: invalid MADT "
598 "lapic entry len %d\n", ent
->me_len
);
603 case MADT_ENT_IOAPIC
:
604 if (ent
->me_len
< sizeof(struct acpi_madt_ioapic
)) {
605 kprintf("madt_iterate_entries: invalid MADT "
606 "ioapic entry len %d\n", ent
->me_len
);
614 error
= func(arg
, ent
);
622 madt_lapic_probe(struct lapic_enumerator
*e
)
624 vm_paddr_t madt_paddr
;
626 madt_paddr
= madt_probe();
630 ((struct madt_lapic_enumerator
*)e
)->madt_paddr
= madt_paddr
;
635 madt_lapic_enumerate(struct lapic_enumerator
*e
)
637 vm_paddr_t madt_paddr
;
638 vm_offset_t lapic_addr
;
641 madt_paddr
= ((struct madt_lapic_enumerator
*)e
)->madt_paddr
;
642 KKASSERT(madt_paddr
!= 0);
644 lapic_addr
= madt_pass1(madt_paddr
);
646 panic("madt_lapic_enumerate no local apic\n");
648 lapic_map(lapic_addr
);
650 bsp_apic_id
= APIC_ID(lapic
.id
);
651 if (madt_pass2(madt_paddr
, bsp_apic_id
))
652 panic("mp_enable: madt_pass2 failed\n");
655 static struct madt_lapic_enumerator madt_lapic_enumerator
= {
657 .lapic_prio
= LAPIC_ENUM_PRIO_MADT
,
658 .lapic_probe
= madt_lapic_probe
,
659 .lapic_enumerate
= madt_lapic_enumerate
664 madt_apic_register(void)
668 prio
= LAPIC_ENUM_PRIO_MADT
;
669 kgetenv_int("hw.madt_lapic_prio", &prio
);
670 madt_lapic_enumerator
.enumerator
.lapic_prio
= prio
;
672 lapic_enumerator_register(&madt_lapic_enumerator
.enumerator
);
674 SYSINIT(madt
, SI_BOOT2_PRESMP
, SI_ORDER_ANY
, madt_apic_register
, 0);