xref: /openbsd-src/sys/arch/i386/i386/mpbios.c (revision fabcfecb28af5579f8c0c1cb806278199e88da42)
1 /*	$OpenBSD: mpbios.c,v 1.48 2024/10/22 21:50:02 jsg Exp $	*/
2 /*	$NetBSD: mpbios.c,v 1.2 2002/10/01 12:56:57 fvdl Exp $	*/
3 
4 /*-
5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by RedBack Networks Inc.
10  *
11  * Author: Bill Sommerfeld
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1999 Stefan Grefen
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *      This product includes software developed by the NetBSD
49  *      Foundation, Inc. and its contributors.
50  * 4. Neither the name of The NetBSD Foundation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
55  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  */
66 /*
67  * Derived from FreeBSD's mp_machdep.c
68  */
69 /*
70  * Copyright (c) 1996, by Steve Passe
71  * All rights reserved.
72  *
73  * Redistribution and use in source and binary forms, with or without
74  * modification, are permitted provided that the following conditions
75  * are met:
76  * 1. Redistributions of source code must retain the above copyright
77  *    notice, this list of conditions and the following disclaimer.
78  * 2. The name of the developer may NOT be used to endorse or promote products
79  *    derived from this software without specific prior written permission.
80  *
81  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
82  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
85  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91  * SUCH DAMAGE.
92  */
93 
94 /*
95  * The Intel MP-stuff is just one way of x86 SMP systems
96  * so only Intel MP specific stuff is here.
97  */
98 
99 #include <sys/param.h>
100 #include <sys/systm.h>
101 #include <sys/device.h>
102 #include <sys/malloc.h>
103 
104 #include <uvm/uvm_extern.h>
105 
106 #include <machine/cpuvar.h>
107 #include <machine/bus.h>
108 #include <machine/biosvar.h>
109 #include <machine/mpbiosreg.h>
110 #include <machine/mpbiosvar.h>
111 
112 #include <machine/i82093reg.h>
113 #include <machine/i82093var.h>
114 #include <machine/i82489reg.h>
115 #include <machine/i82489var.h>
116 
117 #include <dev/isa/isareg.h>
118 #include <dev/pci/pcivar.h>
119 
120 #include <dev/eisa/eisavar.h>	/* for ELCR* def'ns */
121 
122 #include "pci.h"
123 
124 #include "apm.h"
125 #include "acpi.h"
126 #if NAPM > 0 && NACPI > 0
127 extern int haveacpibutusingapm;
128 #endif
129 
130 /* descriptions of MP basetable entries */
131 struct mpbios_baseentry {
132 	u_int8_t  	type;
133 	u_int8_t  	length;
134 	u_int16_t	count;
135 	const char    	*name;
136 };
137 
138 static const char *loc_where[] = {
139 	"extended bios data area",
140 	"last page of base memory",
141 	"bios"
142 };
143 
144 struct mp_map {
145 	vaddr_t 	baseva;
146 	int	 	vsize;
147 	paddr_t 	pa;
148 	paddr_t 	pg;
149 	int		psize;
150 };
151 
152 int	mp_print(void *, const char *);
153 int	mp_match(struct device *, void *, void *);
154 const void *mpbios_search(struct device *, paddr_t, int, struct mp_map *);
155 static __inline int mpbios_cksum(const void *, int);
156 
157 void	mp_cfg_special_intr(const struct mpbios_int *, u_int32_t *);
158 void	mp_print_special_intr(int);
159 
160 void	mp_cfg_pci_intr(const struct mpbios_int *, u_int32_t *);
161 void	mp_print_pci_intr(int);
162 
163 void	mp_cfg_eisa_intr(const struct mpbios_int *, u_int32_t *);
164 void	mp_print_eisa_intr(int);
165 
166 void	mp_cfg_isa_intr(const struct mpbios_int *, u_int32_t *);
167 void	mp_print_isa_intr(int);
168 
169 void	mpbios_cpu(const u_int8_t *, struct device *);
170 void	mpbios_bus(const u_int8_t *, struct device *);
171 void	mpbios_ioapic(const u_int8_t *, struct device *);
172 int	mpbios_int(const u_int8_t *, struct mp_intr_map *);
173 
174 const void *mpbios_map(paddr_t, int, struct mp_map *);
175 void	mpbios_unmap(struct mp_map *);
176 
177 /*
178  * globals to help us bounce our way through parsing the config table.
179  */
180 
181 static struct mp_map mp_cfg_table_map;
182 static struct mp_map mp_fp_map;
183 const struct mpbios_cth	*mp_cth;
184 const struct mpbios_fps	*mp_fps;
185 
186 #ifdef MPVERBOSE
187 int mp_verbose = 1;
188 #else
189 int mp_verbose = 0;
190 #endif
191 
192 int	mpbios_match(struct device *, void *, void *);
193 void	mpbios_attach(struct device *, struct device *, void *);
194 
195 const struct cfattach mpbios_ca = {
196 	sizeof(struct device), mpbios_match, mpbios_attach
197 };
198 
199 struct cfdriver mpbios_cd = {
200 	NULL, "mpbios", DV_DULL
201 };
202 
203 int
204 mpbios_match(struct device *parent, void *match, void *aux)
205 {
206 	struct cfdata *cf = match;
207 	struct bios_attach_args *bia = aux;
208 
209 	if (strcmp(bia->ba_name, cf->cf_driver->cd_name) == 0)
210 		return (1);
211 	return (0);
212 }
213 
214 void
215 mpbios_attach(struct device *parent, struct device *self, void *aux)
216 {
217 	mpbios_scan(self);
218 }
219 
220 int
221 mp_print(void *aux, const char *pnp)
222 {
223 	struct cpu_attach_args *caa = aux;
224 
225 	if (pnp)
226 		printf("%s at %s:", caa->caa_name, pnp);
227 	return (UNCONF);
228 }
229 
230 int
231 mp_match(struct device *parent, void *cfv, void *aux)
232 {
233 	struct cfdata *cf = cfv;
234 	struct cpu_attach_args *caa = aux;
235 
236 	if (strcmp(caa->caa_name, cf->cf_driver->cd_name))
237 		return 0;
238 
239 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
240 }
241 
242 /*
243  * Map a chunk of memory read-only and return an appropriately
244  * const'ed pointer.
245  */
246 const void *
247 mpbios_map(paddr_t pa, int len, struct mp_map *handle)
248 {
249 	paddr_t pgpa = trunc_page(pa);
250 	paddr_t endpa = round_page(pa + len);
251 	vaddr_t va = (vaddr_t)km_alloc(endpa - pgpa, &kv_any, &kp_none,
252 	    &kd_nowait);
253 	vaddr_t retva = va + (pa & PGOFSET);
254 
255 	handle->pa = pa;
256 	handle->pg = pgpa;
257 	handle->psize = len;
258 	handle->baseva = va;
259 	handle->vsize = endpa - pgpa;
260 
261 	do {
262 		pmap_kenter_pa(va, pgpa, PROT_READ);
263 		va += PAGE_SIZE;
264 		pgpa += PAGE_SIZE;
265 	} while (pgpa < endpa);
266 
267 	return ((const void *)retva);
268 }
269 
270 void
271 mpbios_unmap(struct mp_map *handle)
272 {
273 	pmap_kremove(handle->baseva, handle->vsize);
274 	km_free((void *)handle->baseva, handle->vsize, &kv_any, &kp_none);
275 }
276 
277 /*
278  * Look for an Intel MP spec table, indicating SMP capable hardware.
279  */
280 int
281 mpbios_probe(struct device *self)
282 {
283 	paddr_t  	ebda, memtop;
284 
285 	paddr_t		cthpa;
286 	int		cthlen;
287 	const u_int8_t	*mpbios_page;
288 	int 		scan_loc;
289 
290 	struct		mp_map t;
291 
292 #if NAPM > 0 && NACPI > 0
293 	/*
294 	 * If we have acpi but chose to use apm, then we really should
295 	 * not go use mpbios.  Systems with usable acpi typically have
296 	 * unusable mpbios
297 	 */
298 	if (haveacpibutusingapm)
299 		return (0);
300 #endif
301 
302 	/*
303 	 * Skip probe if someone else (e.g. acpi) already provided the
304 	 * necessary details.
305 	 */
306 	if (mp_busses)
307 		return (0);
308 
309 	/* see if EBDA exists */
310 
311 	mpbios_page = mpbios_map(0, PAGE_SIZE, &t);
312 
313 	/* XXX Ugly magic constants below. */
314 	ebda = *(const u_int16_t *)(&mpbios_page[0x40e]);
315 	ebda <<= 4;
316 
317 	memtop = *(const u_int16_t *)(&mpbios_page[0x413]);
318 	memtop <<= 10;
319 
320 	mpbios_page = NULL;
321 	mpbios_unmap(&t);
322 
323 	scan_loc = 0;
324 
325 	if (ebda && ebda < IOM_BEGIN ) {
326 		mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map);
327 		if (mp_fps != NULL)
328 			goto found;
329 	}
330 
331 	scan_loc = 1;
332 
333 	if (memtop && memtop <= IOM_BEGIN ) {
334 		mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map);
335 		if (mp_fps != NULL)
336 			goto found;
337 	}
338 
339 	scan_loc = 2;
340 
341 	mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map);
342 	if (mp_fps != NULL)
343 		goto found;
344 
345 	/* nothing found */
346 	return (0);
347 
348  found:
349 	if (mp_verbose)
350 		printf("%s: MP floating pointer found in %s at 0x%lx\n",
351 		    self->dv_xname, loc_where[scan_loc], mp_fp_map.pa);
352 
353 	if (mp_fps->pap == 0) {
354 		if (mp_fps->mpfb1 == 0)
355 			printf("%s: MP fps invalid: "
356 			    "no default config and no configuration table\n",
357 			    self->dv_xname);
358 		else
359 			printf("%s: MP default configuration %d not "
360     			    "supported\n", self->dv_xname, mp_fps->mpfb1);
361 		goto err;
362 	}
363 
364 	cthpa = mp_fps->pap;
365 
366 	mp_cth = mpbios_map(cthpa, sizeof (*mp_cth), &mp_cfg_table_map);
367 	cthlen = mp_cth->base_len;
368 	mpbios_unmap(&mp_cfg_table_map);
369 
370 	mp_cth = mpbios_map(cthpa, cthlen, &mp_cfg_table_map);
371 
372 	if (mp_verbose)
373 		printf("%s: MP config table at 0x%lx, %d bytes long\n",
374 		    self->dv_xname, cthpa, cthlen);
375 
376 	if (mp_cth->signature != MP_CT_SIG) {
377 		printf("%s: MP signature mismatch (%x vs %x)\n",
378 		    self->dv_xname,
379 		    MP_CT_SIG, mp_cth->signature);
380 		goto err;
381 	}
382 
383 	if (mpbios_cksum(mp_cth, cthlen)) {
384 		printf ("%s: MP Configuration Table checksum mismatch\n",
385 		    self->dv_xname);
386 		goto err;
387 	}
388 	return (1);
389 
390  err:
391 	if (mp_fps) {
392 		mp_fps = NULL;
393 		mpbios_unmap(&mp_fp_map);
394 	}
395 	if (mp_cth) {
396 		mp_cth = NULL;
397 		mpbios_unmap(&mp_cfg_table_map);
398 	}
399 	return (0);
400 }
401 
402 
403 /*
404  * Simple byte checksum used on config tables.
405  */
406 
407 static __inline int
408 mpbios_cksum(const void *start, int len)
409 {
410 	unsigned char res=0;
411 	const char *p = start;
412 	const char *end = p + len;
413 
414 	while (p < end)
415 		res += *p++;
416 
417 	return res;
418 }
419 
420 
421 /*
422  * Look for the MP floating pointer signature in the given physical
423  * address range.
424  *
425  * We map the memory, scan through it, and unmap it.
426  * If we find it, remap the floating pointer structure and return it.
427  */
428 
429 const void *
430 mpbios_search(struct device *self, paddr_t start, int count, struct mp_map *map)
431 {
432 	struct mp_map t;
433 
434 	int i, len;
435 	const struct mpbios_fps *m;
436 	int end = count - sizeof(*m);
437 	const u_int8_t *base = mpbios_map(start, count, &t);
438 
439 	if (mp_verbose)
440 		printf("%s: scanning 0x%lx to 0x%lx for MP signature\n",
441 		    self->dv_xname, start, start + count - sizeof(*m));
442 
443 	for (i = 0; i <= end; i += 4) {
444 		m = (struct mpbios_fps *)&base[i];
445 
446 		if ((m->signature == MP_FP_SIG) &&
447 		    ((len = m->length << 4) != 0) &&
448 		    mpbios_cksum(m, (m->length << 4)) == 0) {
449 			mpbios_unmap(&t);
450 
451 			return (mpbios_map(start + i, len, map));
452 		}
453 	}
454 	mpbios_unmap(&t);
455 
456 	return (0);
457 }
458 
459 /*
460  * MP configuration table parsing.
461  */
462 
463 static struct mpbios_baseentry mp_conf[] =
464 {
465 	{0, 20, 0, "cpu"},
466 	{1, 8, 0, "bus"},
467 	{2, 8, 0, "ioapic"},
468 	{3, 8, 0, "ioint"},
469 	{4, 8, 0, "lint"},
470 };
471 
472 struct mp_bus *mp_busses;
473 int mp_nbusses;
474 struct mp_intr_map *mp_intrs;
475 int mp_nintrs;
476 
477 struct mp_bus *mp_isa_bus;
478 struct mp_bus *mp_eisa_bus;
479 
480 static struct mp_bus extint_bus = {
481 	"ExtINT",
482 	-1,
483 	mp_print_special_intr,
484 	mp_cfg_special_intr,
485 	0
486 };
487 static struct mp_bus smi_bus = {
488 	"SMI",
489 	-1,
490 	mp_print_special_intr,
491 	mp_cfg_special_intr,
492 	0
493 };
494 static struct mp_bus nmi_bus = {
495 	"NMI",
496 	-1,
497 	mp_print_special_intr,
498 	mp_cfg_special_intr,
499 	0
500 };
501 
502 
503 /*
504  * 1st pass on BIOS's Intel MP specification table.
505  *
506  * initializes:
507  *	mp_ncpus = 1
508  *
509  * determines:
510  *	cpu_apic_address (common to all CPUs)
511  *	ioapic_address[N]
512  *	mp_naps
513  *	mp_nbusses
514  *	mp_napics
515  *	nintrs
516  */
517 void
518 mpbios_scan(struct device *self)
519 {
520 	const u_int8_t 	*position, *end;
521 	int		count;
522 	int		type;
523 	int		intr_cnt;
524 	paddr_t		lapic_base;
525 
526 	printf(": Intel MP Specification 1.%d\n", mp_fps->spec_rev);
527 
528 	/*
529 	 * looks like we've got a MP system.  start setting up
530 	 * infrastructure..
531 	 * XXX is this the right place??
532 	 */
533 
534 	lapic_base = LAPIC_BASE;
535 	if (mp_cth != NULL)
536 		lapic_base = (paddr_t)mp_cth->apic_address;
537 
538 	lapic_boot_init(lapic_base);
539 
540 	/*
541 	 * Walk the table once, counting items
542 	 */
543 	for (count = mp_cth->entry_count,
544 	    position = (const u_int8_t *)mp_cth + sizeof(*mp_cth),
545 	    end = position + mp_cth->base_len;
546 	    count-- && position < end;
547 	    position += mp_conf[type].length) {
548 
549 		type = *position;
550 		if (type >= MPS_MCT_NTYPES) {
551 			printf("%s: unknown entry type %x"
552 			    " in MP config table\n",
553 			    self->dv_xname, type);
554 			end = position;
555 			break;
556 		}
557 		mp_conf[type].count++;
558 	}
559 
560 	/*
561 	 * Walk the table twice, counting int and bus entries
562 	 */
563 	for (count = mp_cth->entry_count,
564 	    intr_cnt = 15,	/* presume all isa irqs missing */
565 	    position = (const u_int8_t *)mp_cth + sizeof(*mp_cth);
566 	    count-- && position < end;
567 	    position += mp_conf[type].length) {
568 		type = *position;
569 		if (type == MPS_MCT_BUS) {
570 			const struct mpbios_bus *bp =
571 			    (const struct mpbios_bus *)position;
572 			if (bp->bus_id >= mp_nbusses)
573 				mp_nbusses = bp->bus_id + 1;
574 		}
575 
576 		/*
577 		 * Count actual interrupt instances.
578 		 * dst_apic_id of MPS_ALL_APICS means "wired to all
579 		 * apics of this type".
580 		 */
581 		if ((type == MPS_MCT_IOINT) ||
582 		    (type == MPS_MCT_LINT)) {
583 			const struct mpbios_int *ie =
584 			    (const struct mpbios_int *)position;
585 			if (ie->dst_apic_id != MPS_ALL_APICS)
586 				intr_cnt++;
587 			else if (type == MPS_MCT_IOINT)
588 				intr_cnt +=
589 				    mp_conf[MPS_MCT_IOAPIC].count;
590 			else
591 				intr_cnt += mp_conf[MPS_MCT_CPU].count;
592 		}
593 	}
594 
595 	mp_busses = mallocarray(mp_nbusses, sizeof(struct mp_bus),
596 	    M_DEVBUF, M_WAITOK|M_ZERO);
597 	mp_intrs = mallocarray(intr_cnt, sizeof(struct mp_intr_map),
598 	    M_DEVBUF, M_WAITOK);
599 
600 	/* re-walk the table, recording info of interest */
601 	position = (const u_int8_t *)mp_cth + sizeof(*mp_cth);
602 	count = mp_cth->entry_count;
603 	mp_nintrs = 0;
604 
605 	while ((count--) && (position < end)) {
606 		switch (type = *(u_char *)position) {
607 		case MPS_MCT_CPU:
608 			mpbios_cpu(position, self);
609 			break;
610 		case MPS_MCT_BUS:
611 			mpbios_bus(position, self);
612 			break;
613 		case MPS_MCT_IOAPIC:
614 			mpbios_ioapic(position, self);
615 			break;
616 		case MPS_MCT_IOINT:
617 		case MPS_MCT_LINT:
618 			if (mpbios_int(position,
619 			    &mp_intrs[mp_nintrs]) == 0)
620 				mp_nintrs++;
621 			break;
622 		default:
623 			printf("%s: unknown entry type %x "
624 			    "in MP config table\n",
625 			    self->dv_xname, type);
626 			/* NOTREACHED */
627 			return;
628 		}
629 
630 		position += mp_conf[type].length;
631 	}
632 	if (mp_verbose && mp_cth->ext_len)
633 		printf("%s: MP WARNING: %d "
634 		    "bytes of extended entries not examined\n",
635 		    self->dv_xname, mp_cth->ext_len);
636 
637 	/* Clean up. */
638 	mp_fps = NULL;
639 	mpbios_unmap(&mp_fp_map);
640 	if (mp_cth != NULL) {
641 		mp_cth = NULL;
642 		mpbios_unmap(&mp_cfg_table_map);
643 	}
644 
645 #if NPCI > 0
646 	if (pci_mode_detect() != 0)
647 		mpbios_intr_fixup();
648 #endif
649 }
650 
651 int
652 mpbios_invent(int irq, int type, int bus)
653 {
654 	struct mp_intr_map *mip;
655 	struct mpbios_int e;
656 
657 	e.type = MPS_MCT_IOINT;
658 	e.int_type = MPS_INTTYPE_INT;
659 	switch (type) {
660 	case IST_EDGE:
661 		e.int_flags = MPS_INT(MPS_INTPO_ACTHI, MPS_INTTR_EDGE);
662 		break;
663 
664 	case IST_LEVEL:
665 		e.int_flags = MPS_INT(MPS_INTPO_ACTLO, MPS_INTTR_LEVEL);
666 		break;
667 
668 	case IST_NONE:
669 	case IST_PULSE:
670 		e.int_flags = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF);
671 		break;
672 	}
673 	e.src_bus_id = bus;
674 	e.src_bus_irq = irq;
675 	e.dst_apic_id = mp_busses[bus].mb_intrs->ioapic->sc_apicid;
676 	e.dst_apic_int = irq;
677 
678 	if (mpbios_int((const u_int8_t *)&e, &mp_intrs[mp_nintrs]) == 0) {
679 		mip = &mp_intrs[mp_nintrs++];
680 		return (mip->ioapic_ih | irq);
681 	}
682 
683 	return irq;
684 }
685 
686 void
687 mpbios_cpu(const u_int8_t *ent, struct device *self)
688 {
689 	const struct mpbios_proc *entry = (const struct mpbios_proc *)ent;
690 	struct device *mainbus = self->dv_parent->dv_parent;
691 	struct cpu_attach_args caa;
692 
693 	/* XXX move this into the CPU attachment goo. */
694 	/* check for usability */
695 	if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
696 		return;
697 
698 	/* check for BSP flag */
699 	if (entry->cpu_flags & PROCENTRY_FLAG_BP)
700 		caa.cpu_role = CPU_ROLE_BP;
701 	else {
702 		caa.cpu_role = CPU_ROLE_AP;
703 		ncpusfound++;
704 	}
705 
706 	caa.caa_name = "cpu";
707 	caa.cpu_apicid = entry->apic_id;
708 #ifdef MULTIPROCESSOR
709 	caa.cpu_func = &mp_cpu_funcs;
710 #endif
711 #if 1 /* XXX Will be removed when the real stuff is probed */
712 	caa.cpu_signature = entry->cpu_signature;
713 
714 	/*
715 	 * XXX this is truncated to just contain the low-order 16 bits
716 	 * of the flags on at least some MP bioses
717 	 */
718 	caa.feature_flags = entry->feature_flags;
719 
720 	/*
721 	 * XXX some MP bioses don't specify a valid CPU signature; use
722 	 * the result of the 'cpuid' instruction for the processor
723 	 * we're running on
724 	 */
725 	if ((caa.cpu_signature & 0x00000fff) == 0) {
726 		caa.cpu_signature = cpu_id;
727 		caa.feature_flags = cpu_feature;
728 	}
729 #endif
730 
731 	config_found_sm(mainbus, &caa, mp_print, mp_match);
732 }
733 
734 /*
735  * The following functions conspire to compute base ioapic redirection
736  * table entry for a given interrupt line.
737  *
738  * Fill in: trigger mode, polarity, and possibly delivery mode.
739  */
740 void
741 mp_cfg_special_intr(const struct mpbios_int *entry, u_int32_t *redir)
742 {
743 
744 	/*
745 	 * All of these require edge triggered, zero vector,
746 	 * appropriate delivery mode.
747 	 * see page 13 of the 82093AA datasheet.
748 	 */
749 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
750 	*redir &= ~IOAPIC_REDLO_VECTOR_MASK;
751 	*redir &= ~IOAPIC_REDLO_LEVEL;
752 
753 	switch (entry->int_type) {
754 	case MPS_INTTYPE_NMI:
755 		*redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT);
756 		break;
757 
758 	case MPS_INTTYPE_SMI:
759 		*redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT);
760 		break;
761 	case MPS_INTTYPE_ExtINT:
762 		/*
763 		 * We are using the ioapic in "native" mode.
764 		 * This indicates where the 8259 is wired to the ioapic
765 		 * and/or local apic..
766 		 */
767 		*redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT);
768 		*redir |= (IOAPIC_REDLO_MASK);
769 		break;
770 	default:
771 		panic("unknown MPS interrupt type %d", entry->int_type);
772 	}
773 }
774 
775 /* XXX too much duplicated code here. */
776 
777 void
778 mp_cfg_pci_intr(const struct mpbios_int *entry, u_int32_t *redir)
779 {
780 	int mpspo = (entry->int_flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
781 	int mpstrig = (entry->int_flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
782 
783 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
784 	switch (mpspo) {
785 	case MPS_INTPO_ACTHI:
786 		*redir &= ~IOAPIC_REDLO_ACTLO;
787 		break;
788 	case MPS_INTPO_DEF:
789 	case MPS_INTPO_ACTLO:
790 		*redir |= IOAPIC_REDLO_ACTLO;
791 		break;
792 	default:
793 		panic("unknown MPS interrupt polarity %d", mpspo);
794 	}
795 
796 	if (entry->int_type != MPS_INTTYPE_INT) {
797 		mp_cfg_special_intr(entry, redir);
798 		return;
799 	}
800 	*redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
801 
802 	switch (mpstrig) {
803 	case MPS_INTTR_DEF:
804 	case MPS_INTTR_LEVEL:
805 		*redir |= IOAPIC_REDLO_LEVEL;
806 		break;
807 	case MPS_INTTR_EDGE:
808 		*redir &= ~IOAPIC_REDLO_LEVEL;
809 		break;
810 	default:
811 		panic("unknown MPS interrupt trigger %d", mpstrig);
812 	}
813 }
814 
815 void
816 mp_cfg_eisa_intr(const struct mpbios_int *entry, u_int32_t *redir)
817 {
818 	int mpspo = (entry->int_flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
819 	int mpstrig = (entry->int_flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
820 
821 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
822 	switch (mpspo) {
823 	case MPS_INTPO_DEF:
824 	case MPS_INTPO_ACTHI:
825 		*redir &= ~IOAPIC_REDLO_ACTLO;
826 		break;
827 	case MPS_INTPO_ACTLO:
828 		*redir |= IOAPIC_REDLO_ACTLO;
829 		break;
830 	default:
831 		panic("unknown MPS interrupt polarity %d", mpspo);
832 	}
833 
834 	if (entry->int_type != MPS_INTTYPE_INT) {
835 		mp_cfg_special_intr(entry, redir);
836 		return;
837 	}
838 	*redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
839 
840 	switch (mpstrig) {
841 	case MPS_INTTR_LEVEL:
842 		*redir |= IOAPIC_REDLO_LEVEL;
843 		break;
844 	case MPS_INTTR_EDGE:
845 		*redir &= ~IOAPIC_REDLO_LEVEL;
846 		break;
847 	case MPS_INTTR_DEF:
848 		/*
849 		 * Set "default" setting based on ELCR value snagged
850 		 * earlier.
851 		 */
852 		if (mp_busses[entry->src_bus_id].mb_data &
853 		    (1<<entry->src_bus_irq)) {
854 			*redir |= IOAPIC_REDLO_LEVEL;
855 		} else {
856 			*redir &= ~IOAPIC_REDLO_LEVEL;
857 		}
858 		break;
859 	default:
860 		panic("unknown MPS interrupt trigger %d", mpstrig);
861 	}
862 }
863 
864 
865 void
866 mp_cfg_isa_intr(const struct mpbios_int *entry, u_int32_t *redir)
867 {
868 	int mpspo = (entry->int_flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
869 	int mpstrig = (entry->int_flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
870 
871 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
872 	switch (mpspo) {
873 	case MPS_INTPO_DEF:
874 	case MPS_INTPO_ACTHI:
875 		*redir &= ~IOAPIC_REDLO_ACTLO;
876 		break;
877 	case MPS_INTPO_ACTLO:
878 		*redir |= IOAPIC_REDLO_ACTLO;
879 		break;
880 	default:
881 		panic("unknown MPS interrupt polarity %d", mpspo);
882 	}
883 
884 	if (entry->int_type != MPS_INTTYPE_INT) {
885 		mp_cfg_special_intr(entry, redir);
886 		return;
887 	}
888 	*redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
889 
890 	switch (mpstrig) {
891 	case MPS_INTTR_LEVEL:
892 		*redir |= IOAPIC_REDLO_LEVEL;
893 		break;
894 	case MPS_INTTR_DEF:
895 	case MPS_INTTR_EDGE:
896 		*redir &= ~IOAPIC_REDLO_LEVEL;
897 		break;
898 	default:
899 		panic("unknown MPS interrupt trigger %d", mpstrig);
900 	}
901 }
902 
903 
904 void
905 mp_print_special_intr(int intr)
906 {
907 }
908 
909 void
910 mp_print_pci_intr(int intr)
911 {
912 	printf(" device %d INT_%c", (intr >> 2) & 0x1f, 'A' + (intr & 0x3));
913 }
914 
915 void
916 mp_print_isa_intr(int intr)
917 {
918 	printf(" irq %d", intr);
919 }
920 
921 void
922 mp_print_eisa_intr(int intr)
923 {
924 	printf(" EISA irq %d", intr);
925 }
926 
927 void
928 mpbios_bus(const u_int8_t *ent, struct device *self)
929 {
930 	const struct mpbios_bus *entry = (const struct mpbios_bus *)ent;
931 	int bus_id = entry->bus_id;
932 
933 	printf("%s: bus %d is type %6.6s\n", self->dv_xname,
934 	    bus_id, entry->bus_type);
935 
936 #ifdef DIAGNOSTIC
937 	/*
938 	 * This "should not happen" unless the table changes out
939 	 * from underneath us
940 	 */
941 	if (bus_id >= mp_nbusses) {
942 		panic("%s: bus number %d out of range?? (type %6.6s)",
943 		    self->dv_xname, bus_id, entry->bus_type);
944 	}
945 #endif
946 
947 	mp_busses[bus_id].mb_intrs = NULL;
948 
949 	if (memcmp(entry->bus_type, "PCI   ", 6) == 0) {
950 		mp_busses[bus_id].mb_name = "pci";
951 		mp_busses[bus_id].mb_idx = bus_id;
952 		mp_busses[bus_id].mb_intr_print = mp_print_pci_intr;
953 		mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr;
954 	} else if (memcmp(entry->bus_type, "EISA  ", 6) == 0) {
955 		mp_busses[bus_id].mb_name = "eisa";
956 		mp_busses[bus_id].mb_idx = bus_id;
957 		mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr;
958 		mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr;
959 
960 		mp_busses[bus_id].mb_data = inb(ELCR0) | (inb(ELCR1) << 8);
961 
962 		if (mp_eisa_bus)
963 			printf("%s: multiple eisa busses?\n",
964 			    self->dv_xname);
965 		else
966 			mp_eisa_bus = &mp_busses[bus_id];
967 	} else if (memcmp(entry->bus_type, "ISA   ", 6) == 0) {
968 		mp_busses[bus_id].mb_name = "isa";
969 		mp_busses[bus_id].mb_idx = bus_id;
970 		mp_busses[bus_id].mb_intr_print = mp_print_isa_intr;
971 		mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr;
972 		if (mp_isa_bus)
973 			printf("%s: multiple isa busses?\n",
974 			    self->dv_xname);
975 		else
976 			mp_isa_bus = &mp_busses[bus_id];
977 	} else {
978 		printf("%s: unsupported bus type %6.6s\n", self->dv_xname,
979 		    entry->bus_type);
980 	}
981 }
982 
983 
984 void
985 mpbios_ioapic(const u_int8_t *ent, struct device *self)
986 {
987 	const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent;
988 	struct device *mainbus = self->dv_parent->dv_parent;
989 	struct apic_attach_args aaa;
990 
991 	/* XXX let flags checking happen in ioapic driver.. */
992 	if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN))
993 		return;
994 
995 	aaa.aaa_name = "ioapic";
996 	aaa.apic_id = entry->apic_id;
997 	aaa.apic_version = entry->apic_version;
998 	aaa.apic_address = (u_int32_t)entry->apic_address;
999 	aaa.apic_vecbase = -1;
1000 	aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE;
1001 
1002 	config_found_sm(mainbus, &aaa, mp_print, mp_match);
1003 }
1004 
1005 int
1006 mpbios_int(const u_int8_t *ent, struct mp_intr_map *mpi)
1007 {
1008 	const struct mpbios_int *entry = (const struct mpbios_int *)ent;
1009 	struct mpbios_int rw_entry = *entry;
1010 	struct ioapic_softc *sc = NULL, *sc2;
1011 
1012 	struct mp_intr_map *altmpi;
1013 	struct mp_bus *mpb;
1014 
1015 	u_int32_t id = entry->dst_apic_id;
1016 	u_int32_t pin = entry->dst_apic_int;
1017 	u_int32_t bus = entry->src_bus_id;
1018 	u_int32_t dev = entry->src_bus_irq;
1019 	u_int32_t type = entry->int_type;
1020 	u_int32_t flags = entry->int_flags;
1021 
1022 	rw_entry.dst_apic_id = id;
1023 
1024 	switch (type) {
1025 	case MPS_INTTYPE_INT:
1026 		mpb = &(mp_busses[bus]);
1027 		break;
1028 	case MPS_INTTYPE_ExtINT:
1029 		mpb = &extint_bus;
1030 		break;
1031 	case MPS_INTTYPE_SMI:
1032 		mpb = &smi_bus;
1033 		break;
1034 	case MPS_INTTYPE_NMI:
1035 		mpb = &nmi_bus;
1036 		break;
1037 	default:
1038 		panic("unknown MPS interrupt type %d", entry->int_type);
1039 	}
1040 	mpi->bus = mpb;
1041 	mpi->bus_pin = dev;
1042 
1043 	mpi->ioapic_ih = APIC_INT_VIA_APIC |
1044 	    ((id << APIC_INT_APIC_SHIFT) | ((pin << APIC_INT_PIN_SHIFT)));
1045 
1046 	mpi->type = type;
1047 	mpi->flags = flags;
1048 	mpi->redir = 0;
1049 	if (mpb->mb_intr_cfg == NULL) {
1050 		printf("mpbios: can't find bus %d for apic %d pin %d\n",
1051 		    bus, id, pin);
1052 		return (1);
1053 	}
1054 
1055 	(*mpb->mb_intr_cfg)(&rw_entry, &mpi->redir);
1056 
1057 	if (entry->type == MPS_MCT_IOINT) {
1058 		sc = ioapic_find(id);
1059 		if (sc == NULL) {
1060 			printf("mpbios: can't find ioapic %d\n", id);
1061 			return (1);
1062 		}
1063 
1064 		/*
1065 		 * XXX workaround for broken BIOSs that put the ACPI
1066 		 * global interrupt number in the entry, not the pin
1067 		 * number.
1068 		 */
1069 		if (pin >= sc->sc_apic_sz) {
1070 			sc2 = ioapic_find_bybase(pin);
1071 			if (sc2 != sc) {
1072 				printf("mpbios: bad pin %d for apic %d\n",
1073 				    pin, id);
1074 				return (1);
1075 			}
1076 			printf("mpbios: WARNING: pin %d for apic %d too high; "
1077 			       "assuming ACPI global int value\n", pin, id);
1078 			pin -= sc->sc_apic_vecbase;
1079 		}
1080 
1081 		mpi->ioapic = sc;
1082 		mpi->ioapic_pin = pin;
1083 
1084 		altmpi = sc->sc_pins[pin].ip_map;
1085 
1086 		if (altmpi != NULL) {
1087 			if ((altmpi->type != type) ||
1088 			    (altmpi->flags != flags)) {
1089 				printf(
1090 				    "%s: conflicting map entries for pin %d\n",
1091 				    sc->sc_pic.pic_dev.dv_xname, pin);
1092 			}
1093 		} else {
1094 			sc->sc_pins[pin].ip_map = mpi;
1095 		}
1096 	} else {
1097 		if (pin >= 2)
1098 			printf("pin %d of local apic doesn't exist!\n", pin);
1099 		else {
1100 			mpi->ioapic = NULL;
1101 			mpi->ioapic_pin = pin;
1102 			mpi->cpu_id = id;
1103 		}
1104 	}
1105 
1106 	if (mp_verbose) {
1107 		printf("%s: int%d attached to %s",
1108 		    sc ? sc->sc_pic.pic_dev.dv_xname : "local apic", pin,
1109 		    mpb->mb_name);
1110 		if (mpb->mb_idx != -1)
1111 			printf("%d", mpb->mb_idx);
1112 
1113 		(*(mpb->mb_intr_print))(dev);
1114 
1115 		printf(" (type 0x%x flags 0x%x)\n", type, flags);
1116 	}
1117 
1118 	mpi->next = mpb->mb_intrs;
1119 	mpb->mb_intrs = mpi;
1120 
1121 	return (0);
1122 }
1123