mp_x86.c revision 25164
1/* 2 * Copyright (c) 1996, by Steve Passe 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. The name of the developer may NOT be used to endorse or promote products 11 * derived from this software without specific prior written permission. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $Id: mp_machdep.c,v 1.47 1997/04/26 08:11:49 peter Exp $ 26 */ 27 28#include "opt_smp.h" 29#include "opt_smp_invltlb.h" 30#if defined(APIC_IO) 31#if !defined(SMP_INVLTLB) 32#error you must define BOTH APIC_IO and SMP_INVLTLB or NEITHER 33#endif 34#else /* APIC_IO */ 35#if defined(SMP_INVLTLB) 36#error you must define BOTH APIC_IO and SMP_INVLTLB or NEITHER 37#endif 38#endif /* APIC_IO */ 39#define FIX_MP_TABLE_WORKS_NOT 40 41#include "opt_serial.h" 42 43#include <sys/param.h> /* for KERNBASE */ 44#include <sys/types.h> 45#include <sys/sysproto.h> 46#include <sys/time.h> 47#include <sys/systm.h> 48 49#include <vm/vm.h> /* for KERNBASE */ 50#include <vm/vm_param.h> /* for KERNBASE */ 51#include <vm/pmap.h> /* for KERNBASE */ 52#include <machine/pmap.h> /* for KERNBASE */ 53 54#include <machine/smp.h> 55#include <machine/apic.h> 56#include <machine/mpapic.h> 57#include <machine/cpufunc.h> 58#include <machine/segments.h> 59#include <machine/smptests.h> /** TEST_UPPERPRIO, TEST_DEFAULT_CONFIG */ 60 61#include <i386/i386/cons.h> /* cngetc() */ 62 63#if defined(IPI_INTS) 64#include <i386/isa/isa_device.h> 65#include "vector.h" 66#endif /* IPI_INTS */ 67 68#if defined(SMP_INVLTLB) 69#include <i386/isa/icu.h> 70#endif /* SMP_INVLTLB */ 71 72#define WARMBOOT_TARGET 0 73#define WARMBOOT_OFF (KERNBASE + 0x0467) 74#define WARMBOOT_SEG (KERNBASE + 0x0469) 75 76#define BIOS_BASE (0xf0000) 77#define BIOS_SIZE (0x10000) 78#define BIOS_COUNT (BIOS_SIZE/4) 79 80#define CMOS_REG (0x70) 81#define CMOS_DATA (0x71) 82#define BIOS_RESET (0x0f) 83#define BIOS_WARM (0x0a) 84 85/* 86 * this code MUST be enabled here and in mpboot.s. 87 * it follows the very early stages of AP boot by placing values in CMOS ram. 88 * it NORMALLY will never be needed and thus the primitive method for enabling. 89 * 90#define CHECK_POINTS 91 */ 92 93#if defined(CHECK_POINTS) 94#define CHECK_READ(A) (outb(CMOS_REG, (A)), inb(CMOS_DATA)) 95#define CHECK_WRITE(A,D) (outb(CMOS_REG, (A)), outb(CMOS_DATA, (D))) 96 97#define CHECK_INIT(D); \ 98 CHECK_WRITE(0x34, (D)); \ 99 CHECK_WRITE(0x35, (D)); \ 100 CHECK_WRITE(0x36, (D)); \ 101 CHECK_WRITE(0x37, (D)); \ 102 CHECK_WRITE(0x38, (D)); \ 103 CHECK_WRITE(0x39, (D)); 104 105#define CHECK_PRINT(S); \ 106 printf("%s: %d, %d, %d, %d, %d, %d\n", \ 107 (S), \ 108 CHECK_READ(0x34), \ 109 CHECK_READ(0x35), \ 110 CHECK_READ(0x36), \ 111 CHECK_READ(0x37), \ 112 CHECK_READ(0x38), \ 113 CHECK_READ(0x39)); 114 115#else /* CHECK_POINTS */ 116 117#define CHECK_INIT(D) 118#define CHECK_PRINT(S) 119 120#endif /* CHECK_POINTS */ 121 122 123/** FIXME: what system files declare these??? */ 124extern struct region_descriptor r_gdt, r_idt; 125 126/* global data */ 127struct proc *SMPcurproc[NCPU]; 128struct pcb *SMPcurpcb[NCPU]; 129struct timeval SMPruntime[NCPU]; 130 131int mp_ncpus; /* # of CPUs, including BSP */ 132int mp_naps; /* # of Applications processors */ 133int mp_nbusses; /* # of busses */ 134int mp_napics; /* # of IO APICs */ 135int mpenabled; 136int boot_cpu_id; /* designated BSP */ 137vm_offset_t cpu_apic_address; 138vm_offset_t io_apic_address[NAPIC]; 139 140u_int32_t cpu_apic_versions[NCPU]; 141u_int32_t io_apic_versions[NAPIC]; 142 143/* 144 * APIC ID logical/physical mapping structures 145 */ 146int cpu_num_to_apic_id[NCPU]; 147int io_num_to_apic_id[NAPIC]; 148int apic_id_to_logical[NAPICID]; 149 150/* 151 * look for MP compliant motherboard. 152 */ 153 154static u_int boot_address; 155static u_int base_memory; 156 157static int picmode; /* 0: virtual wire mode, 1: PIC mode */ 158static u_int mpfps; 159static int search_for_sig(u_int32_t target, int count); 160static int mp_probe(u_int base_top); 161static void mp_enable(u_int boot_addr); 162 163#if defined(IPI_INTS) 164static void ipi_intr0(void); 165static void ipi_intr1(void); 166static void ipi_intr2(void); 167static void ipi_intr3(void); 168static int 169ipi_ihandler_attach(int irq, inthand2_t * func, 170 unsigned *maskptr, int unit); 171#endif /* IPI_INTS */ 172 173 174/* 175 * calculate usable address in base memory for AP trampoline code 176 */ 177u_int 178mp_bootaddress(u_int basemem) 179{ 180 base_memory = basemem * 1024; /* convert to bytes */ 181 182 boot_address = base_memory & ~0xfff; /* round down to 4k boundary */ 183 if ((base_memory - boot_address) < bootMP_size) 184 boot_address -= 4096; /* not enough, lower by 4k */ 185 186 return boot_address; 187} 188 189 190/* 191 * startup the SMP processors 192 */ 193void 194mp_start(void) 195{ 196 /* look for MP capable motherboard */ 197 if (mp_probe(base_memory)) 198 mp_enable(boot_address); 199 else { 200 printf("MP FPS NOT FOUND, suggest use of 'mptable' program\n"); 201 panic("can't continue!\n"); 202 } 203 204 /* finish pmap initialization - turn off V==P mapping at zero */ 205 pmap_bootstrap2(); 206} 207 208 209/* 210 * print various information about the SMP system hardware and setup 211 */ 212void 213mp_announce(void) 214{ 215 int x; 216 217 printf("FreeBSD/SMP: Multiprocessor motherboard\n"); 218 printf(" cpu0 (BSP): apic id: %d", CPU_TO_ID(0)); 219 printf(", version: 0x%08x\n", cpu_apic_versions[0]); 220 for (x = 1; x <= mp_naps; ++x) { 221 printf(" cpu%d (AP): apic id: %d", x, CPU_TO_ID(x)); 222 printf(", version: 0x%08x\n", cpu_apic_versions[x]); 223 } 224 225#if defined(APIC_IO) 226 for (x = 0; x < mp_napics; ++x) { 227 printf(" io%d (APIC): apic id: %d", x, IO_TO_ID(x)); 228 printf(", version: 0x%08x\n", io_apic_versions[x]); 229 } 230#else 231 printf(" Warning: APIC I/O disabled\n"); 232#endif /* APIC_IO */ 233} 234 235 236/* 237 * AP cpu's call this to sync up protected mode. 238 */ 239void 240init_secondary(void) 241{ 242 int gsel_tss, slot; 243 244 r_gdt.rd_limit = sizeof(gdt[0]) * (NGDT + NCPU) - 1; 245 r_gdt.rd_base = (int) gdt; 246 lgdt(&r_gdt); /* does magic intra-segment return */ 247 lidt(&r_idt); 248 lldt(_default_ldt); 249 250 slot = NGDT + cpunumber(); 251 gsel_tss = GSEL(slot, SEL_KPL); 252 gdt[slot].sd.sd_type = SDT_SYS386TSS; 253 ltr(gsel_tss); 254 255 load_cr0(0x8005003b); /* XXX! */ 256} 257 258 259#if defined(APIC_IO) 260void 261configure_local_apic(void) 262{ 263 u_char byte; 264 u_int32_t temp; 265 266 if (picmode) { 267 outb(0x22, 0x70); /* select IMCR */ 268 byte = inb(0x23); /* current contents */ 269 byte |= 0x01; /* mask external INTR */ 270 outb(0x23, byte); /* disconnect 8259s/NMI */ 271 } 272 /* mask the LVT1 */ 273 temp = apic_base[APIC_LVT1]; 274 temp |= APIC_LVT_M; 275 apic_base[APIC_LVT1] = temp; 276} 277#endif /* APIC_IO */ 278 279 280/******************************************************************* 281 * local functions and data 282 */ 283 284static int 285mp_probe(u_int base_top) 286{ 287 int x; 288 u_long segment; 289 u_int32_t target; 290 291 /* see if EBDA exists */ 292 if (segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) { 293 /* search first 1K of EBDA */ 294 target = (u_int32_t) (segment << 4); 295 if ((x = search_for_sig(target, 1024 / 4)) >= 0) 296 goto found; 297 } else { 298 /*last 1K of base memory, effective 'top of base' is passed in*/ 299 target = (u_int32_t) (base_top - 0x400); 300 if ((x = search_for_sig(target, 1024 / 4)) >= 0) 301 goto found; 302 } 303 304 /* search the BIOS */ 305 target = (u_int32_t) BIOS_BASE; 306 if ((x = search_for_sig(target, BIOS_COUNT)) >= 0) 307 goto found; 308 309 /* nothing found */ 310 mpfps = mpenabled = 0; 311 return 0; 312 313found: /* please forgive the 'goto'! */ 314 /* flag fact that we are running multiple processors */ 315 mpfps = x; 316 mpenabled = 1; 317 return 1; 318} 319 320 321/* 322 * start the SMP system 323 */ 324static int parse_mp_table(void); 325static void default_mp_table(int type); 326static int start_all_aps(u_int boot_addr); 327 328#if defined(XFAST_IPI32) 329#include <machine/md_var.h> 330#include <i386/isa/isa_device.h> 331extern void Xfastipi32(u_int, u_int, u_int, u_int); 332#endif /* XFAST_IPI32 */ 333 334static void 335mp_enable(u_int boot_addr) 336{ 337 int x; 338#if defined(APIC_IO) 339 int apic; 340 u_int ux; 341#if defined(TEST_UPPERPRIO) 342 u_char select; /* the select register is 8 bits */ 343 u_int32_t flags; /* the window register is 32 bits */ 344#endif /* TEST_UPPERPRIO */ 345#endif /* APIC_IO */ 346 347 /* examine the MP table for needed info */ 348 x = parse_mp_table(); 349 350 /* create pages for (address common) cpu APIC and each IO APIC */ 351 pmap_bootstrap_apics(); 352 353 /* can't process default configs till the CPU APIC is pmapped */ 354 if (x) 355 default_mp_table(x); 356 357#if defined(APIC_IO) 358 /* fill the LOGICAL io_apic_versions table */ 359 for (apic = 0; apic < mp_napics; ++apic) { 360 ux = io_apic_read(apic, IOAPIC_VER); 361 io_apic_versions[apic] = ux; 362 } 363 364 /* 365 */ 366 for (apic = 0; apic < mp_napics; ++apic) 367 if (io_apic_setup(apic) < 0) 368 panic("IO APIC setup failure\n"); 369 370#if defined(IPI_INTS) 371 /* setup IPI INTerrupt mechanism */ 372 ipi_ihandler_attach( /* irq */ 24, 373 /* XXX */ (inthand2_t *) ipi_intr0, NULL, /* unit */ 0); 374 ipi_ihandler_attach( /* irq */ 25, 375 /* XXX */ (inthand2_t *) ipi_intr1, NULL, /* unit */ 0); 376 ipi_ihandler_attach( /* irq */ 26, 377 /* XXX */ (inthand2_t *) ipi_intr2, NULL, /* unit */ 0); 378#if !defined(SMP_INVLTLB) 379 ipi_ihandler_attach( /* irq */ 27, 380 /* XXX */ (inthand2_t *) ipi_intr3, NULL, /* unit */ 0); 381#else 382#if defined(XFAST_IPI32) 383 ipi_ihandler_attach( /* irq */ 27, 384 /* XXX */ (inthand2_t *) ipi_intr3, NULL, /* unit */ 0); 385 setidt(ICU_OFFSET + 32, 386 Xfastipi32, 387 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 388#else 389 ipi_ihandler_attach( /* irq */ 27, 390 /* XXX */ (inthand2_t *) ipi_invltlb, NULL, /* unit */ 0); 391#endif /* XFAST_IPI32 */ 392#endif 393 394#endif /* IPI_INTS */ 395 396#if defined(TEST_UPPERPRIO) 397 398#if 1 399 printf("special IRQ10\n"); 400 select = IOAPIC_REDTBL10; /** HARD_VECTORXXX: */ 401 flags = io_apic_read(0, select); 402 flags &= ~0xff; /** clear vector */ 403 flags |= 64; 404 io_apic_write(0, select, flags); 405#else 406 printf("special IRQ10\n"); 407 cngetc(); 408 select = IOAPIC_REDTBL10; /** HARD_VECTORXXX: */ 409 flags = io_apic_read(0, select); 410 flags &= ~IOART_DELMOD; /* FIXED mode */ 411 io_apic_write(0, select, flags); 412 io_apic_write(0, select + 1, boot_cpu_id << 24); 413#endif /** 0/1 */ 414 415#endif /* TEST_UPPERPRIO */ 416 417#endif /* APIC_IO */ 418 419 /* start each Application Processor */ 420 start_all_aps(boot_addr); 421} 422 423 424/* 425 * look for the MP spec signature 426 */ 427 428/* string defined by the Intel MP Spec as identifying the MP table */ 429#define MP_SIG 0x5f504d5f /* _MP_ */ 430#define NEXT(X) ((X) += 4) 431static int 432search_for_sig(u_int32_t target, int count) 433{ 434 int x; 435 u_int32_t *addr = (u_int32_t *) (KERNBASE + target); 436 437 for (x = 0; x < count; NEXT(x)) 438 if (addr[x] == MP_SIG) 439 /* make array index a byte index */ 440 return (target + (x * sizeof(u_int32_t))); 441 442 return -1; 443} 444 445 446#define PROCENTRY_FLAG_EN 0x01 447#define PROCENTRY_FLAG_BP 0x02 448#define IOAPICENTRY_FLAG_EN 0x01 449 450/* MP Floating Pointer Structure */ 451typedef struct MPFPS { 452 char signature[4]; 453 void *pap; 454 u_char length; 455 u_char spec_rev; 456 u_char checksum; 457 u_char mpfb1; 458 u_char mpfb2; 459 u_char mpfb3; 460 u_char mpfb4; 461 u_char mpfb5; 462} *mpfps_t; 463/* MP Configuration Table Header */ 464typedef struct MPCTH { 465 char signature[4]; 466 u_short base_table_length; 467 u_char spec_rev; 468 u_char checksum; 469 u_char oem_id[8]; 470 u_char product_id[12]; 471 void *oem_table_pointer; 472 u_short oem_table_size; 473 u_short entry_count; 474 void *apic_address; 475 u_short extended_table_length; 476 u_char extended_table_checksum; 477 u_char reserved; 478} *mpcth_t; 479 480 481typedef struct PROCENTRY { 482 u_char type; 483 u_char apic_id; 484 u_char apic_version; 485 u_char cpu_flags; 486 u_long cpu_signature; 487 u_long feature_flags; 488 u_long reserved1; 489 u_long reserved2; 490} *proc_entry_ptr; 491 492typedef struct BUSENTRY { 493 u_char type; 494 u_char bus_id; 495 char bus_type[6]; 496} *bus_entry_ptr; 497 498typedef struct IOAPICENTRY { 499 u_char type; 500 u_char apic_id; 501 u_char apic_version; 502 u_char apic_flags; 503 void *apic_address; 504} *io_apic_entry_ptr; 505 506typedef struct INTENTRY { 507 u_char type; 508 u_char int_type; 509 u_short int_flags; 510 u_char src_bus_id; 511 u_char src_bus_irq; 512 u_char dst_apic_id; 513 u_char dst_apic_int; 514} *int_entry_ptr; 515/* descriptions of MP basetable entries */ 516typedef struct BASETABLE_ENTRY { 517 u_char type; 518 u_char length; 519 char name[16]; 520} basetable_entry; 521 522static basetable_entry basetable_entry_types[] = 523{ 524 {0, 20, "Processor"}, 525 {1, 8, "Bus"}, 526 {2, 8, "I/O APIC"}, 527 {3, 8, "I/O INT"}, 528 {4, 8, "Local INT"} 529}; 530 531typedef struct BUSDATA { 532 u_char bus_id; 533 enum busTypes bus_type; 534} bus_datum; 535 536typedef struct INTDATA { 537 u_char int_type; 538 u_short int_flags; 539 u_char src_bus_id; 540 u_char src_bus_irq; 541 u_char dst_apic_id; 542 u_char dst_apic_int; 543} io_int, local_int; 544 545typedef struct BUSTYPENAME { 546 u_char type; 547 char name[7]; 548} bus_type_name; 549 550static bus_type_name bus_type_table[] = 551{ 552 {CBUS, "CBUS"}, 553 {CBUSII, "CBUSII"}, 554 {EISA, "EISA"}, 555 {UNKNOWN_BUSTYPE, "---"}, 556 {UNKNOWN_BUSTYPE, "---"}, 557 {ISA, "ISA"}, 558 {UNKNOWN_BUSTYPE, "---"}, 559 {UNKNOWN_BUSTYPE, "---"}, 560 {UNKNOWN_BUSTYPE, "---"}, 561 {UNKNOWN_BUSTYPE, "---"}, 562 {UNKNOWN_BUSTYPE, "---"}, 563 {UNKNOWN_BUSTYPE, "---"}, 564 {PCI, "PCI"}, 565 {UNKNOWN_BUSTYPE, "---"}, 566 {UNKNOWN_BUSTYPE, "---"}, 567 {UNKNOWN_BUSTYPE, "---"}, 568 {UNKNOWN_BUSTYPE, "---"}, 569 {XPRESS, "XPRESS"}, 570 {UNKNOWN_BUSTYPE, "---"} 571}; 572/* from MP spec v1.4, table 5-1 */ 573static int default_data[7][5] = 574{ 575/* nbus, id0, type0, id1, type1 */ 576 {1, 0, ISA, 255, 255}, 577 {1, 0, EISA, 255, 255}, 578 {1, 0, EISA, 255, 255}, 579 {0, 255, 255, 255, 255},/* MCA not supported */ 580 {2, 0, ISA, 1, PCI}, 581 {2, 0, EISA, 1, PCI}, 582 {0, 255, 255, 255, 255} /* MCA not supported */ 583}; 584 585 586/* the bus data */ 587bus_datum bus_data[NBUS]; 588 589/* the IO INT data, one entry per possible APIC INTerrupt */ 590io_int io_apic_ints[NINTR]; 591 592static int nintrs; 593 594#if defined(FIX_MP_TABLE_WORKS) 595static void fix_mp_table __P((void)); 596#endif /* FIX_MP_TABLE_WORKS */ 597 598static void processor_entry __P((proc_entry_ptr entry, int *cpu)); 599static void io_apic_entry __P((io_apic_entry_ptr entry, int *apic)); 600static void bus_entry __P((bus_entry_ptr entry, int *bus)); 601static void int_entry __P((int_entry_ptr entry, int *intr)); 602static int lookup_bus_type __P((char *name)); 603 604 605/* 606 * parse an Intel MP specification table 607 */ 608static int 609parse_mp_table(void) 610{ 611 int x; 612 mpfps_t fps; 613 mpcth_t cth; 614 int totalSize; 615 void *position; 616 int count; 617 int type; 618 int apic, bus, cpu, intr; 619 620 /* clear physical APIC ID to logical CPU/IO table */ 621 for (x = 0; x < NAPICID; ++x) 622 ID_TO_IO(x) = -1; 623 624 /* clear logical CPU to APIC ID table */ 625 for (x = 0; x < NCPU; ++x) 626 CPU_TO_ID(x) = -1; 627 628 /* clear logical IO to APIC ID table */ 629 for (x = 0; x < NAPIC; ++x) 630 IO_TO_ID(x) = -1; 631 632 /* clear IO APIC address table */ 633 for (x = 0; x < NAPIC; ++x) 634 io_apic_address[x] = ~0; 635 636 /* clear bus data table */ 637 for (x = 0; x < NBUS; ++x) 638 bus_data[x].bus_id = 0xff; 639 640 /* clear IO APIC INT table */ 641 for (x = 0; x < NINTR; ++x) 642 io_apic_ints[x].int_type = 0xff; 643 nintrs = 0; 644 645 /* count the BSP */ 646 mp_ncpus = 1; 647 648 /* setup the cpu/apic mapping arrays */ 649 boot_cpu_id = -1; 650 651 /* local pointer */ 652 fps = (mpfps_t) mpfps; 653 654 /* record whether PIC or virtual-wire mode */ 655 picmode = (fps->mpfb2 & 0x80) ? 1 : 0; 656 657 /* check for use of 'default' configuration */ 658#if defined(TEST_DEFAULT_CONFIG) 659 /* use default addresses */ 660 cpu_apic_address = DEFAULT_APIC_BASE; 661 io_apic_address[0] = DEFAULT_IO_APIC_BASE; 662 663 /* return default configuration type */ 664 return TEST_DEFAULT_CONFIG; 665#else 666 if (fps->mpfb1 != 0) { 667 /* use default addresses */ 668 cpu_apic_address = DEFAULT_APIC_BASE; 669 io_apic_address[0] = DEFAULT_IO_APIC_BASE; 670 671 /* return default configuration type */ 672 return fps->mpfb1; 673 } 674#endif /* TEST_DEFAULT_CONFIG */ 675 676 if ((cth = fps->pap) == 0) 677 panic("MP Configuration Table Header MISSING!\n"); 678 679 cpu_apic_address = (vm_offset_t) cth->apic_address; 680 681 totalSize = cth->base_table_length - sizeof(struct MPCTH); 682 position = (u_char *) cth + sizeof(struct MPCTH); 683 count = cth->entry_count; 684 685 apic = 0; /* logical apic# start @ 0 */ 686 bus = 0; /* logical bus# start @ 0 */ 687 cpu = 1; /* logical cpu# start @ 0, BUT reserve 0 for */ 688 /* BSP */ 689 intr = 0; /* unknown */ 690 691 /* walk the table, recording info of interest */ 692 while (count--) { 693 switch (type = *(u_char *) position) { 694 case 0: 695 processor_entry(position, &cpu); 696 break; 697 case 1: 698 bus_entry(position, &bus); 699 break; 700 case 2: 701 io_apic_entry(position, &apic); 702 break; 703 case 3: 704 int_entry(position, &intr); 705 break; 706 case 4: 707 /* int_entry(position); */ 708 break; 709 default: 710 panic("mpfps Base Table HOSED!\n"); 711 /* NOTREACHED */ 712 } 713 714 totalSize -= basetable_entry_types[type].length; 715 (u_char *) position += basetable_entry_types[type].length; 716 } 717 718 if (boot_cpu_id == -1) 719 panic("NO BSP found!\n"); 720 721 /* record # of APs found */ 722 mp_naps = (cpu - 1); 723 724 /* record # of busses found */ 725 mp_nbusses = bus; 726 727 /* record # of IO APICs found */ 728 mp_napics = apic; 729 730 /* record # of IO APICs found */ 731 nintrs = intr; 732 733#if defined(FIX_MP_TABLE_WORKS) 734 /* post scan cleanup */ 735 fix_mp_table(); 736#endif /* FIX_MP_TABLE_WORKS */ 737 738 /* report fact that its NOT a default configuration */ 739 return 0; 740} 741 742 743/* 744 * parse an Intel MP specification table 745 */ 746#if defined(FIX_MP_TABLE_WORKS) 747static void 748fix_mp_table(void) 749{ 750 int x; 751 int y; 752 int num_pci_bus; 753 bus_datum bus_record; 754 755 /* 756 * Fix mis-numbering of the PCI bus and its INT entries if the BIOS 757 * did it wrong. The MP spec says that when more than 1 PCI bus 758 * exists the BIOS must begin with bus entries for the PCI bus and use 759 * actual PCI bus numbering. This implies that when only 1 PCI bus 760 * exists the BIOS can choose to ignore this ordering, and indeed many 761 * MP motherboards do ignore it. This causes a problem when the PCI 762 * sub-system makes requests of the MP sub-system based on PCI bus 763 * numbers. So here we look for the situation and renumber the 764 * busses and associated INTs in an effort to "make it right". 765 */ 766 767 /* count the number of PCI busses */ 768 for (num_pci_bus = 0, x = 0; x < mp_nbusses; ++x) { 769 if (bus_data[x].bus_type == PCI) 770 ++num_pci_bus; 771 } 772 773 /* check the 1 PCI bus case for sanity */ 774 if (num_pci_bus == 1) { 775 776 /* if its in the first slot all is well */ 777 if (bus_data[0].bus_type == PCI) 778 return; 779 780 /* mis-numbered, swap with whichever bus uses slot 0 */ 781 782 /* locate the entry holding the PCI bus */ 783 for (x = 1; x < mp_nbusses; ++x) { 784 if (bus_data[x].bus_type == PCI) 785 break; 786 } 787 788 /* swap the bus entry records */ 789 bus_record = bus_data[0]; 790 bus_data[0] = bus_data[x]; 791 bus_data[x] = bus_record; 792 793 /* swap each relavant INTerrupt entry */ 794 for (y = 0; y < nintrs; ++y) { 795 if (io_apic_ints[y].src_bus_id == x) 796 io_apic_ints[y].src_bus_id = 0; 797 else 798 if (io_apic_ints[y].src_bus_id == 0) 799 io_apic_ints[y].src_bus_id = x; 800 } 801 } 802 /* sanity check if more than 1 PCI bus */ 803 else 804 if (num_pci_bus > 1) { 805 for (x = 0; x < num_pci_bus; ++x) { 806 if (bus_data[x].bus_type != PCI) { 807 printf("bad PCI bus numbering\n"); 808 panic("\n"); 809 } 810 } 811 } 812} 813#endif /* FIX_MP_TABLE_WORKS */ 814 815 816static void 817processor_entry(proc_entry_ptr entry, int *cpu) 818{ 819 int x = *cpu; 820 821 /* check for usability */ 822 if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) 823 return; 824 825 /* check for BSP flag */ 826 if (entry->cpu_flags & PROCENTRY_FLAG_BP) { 827 /* always give boot CPU the logical value of 0 */ 828 x = 0; 829 boot_cpu_id = entry->apic_id; 830 } else { 831 /* add another AP to list, if less than max number of CPUs */ 832 if (x == NCPU) { 833 printf("Warning: only using %d of the available CPUs!\n", x); 834 return; 835 } 836 ++(*cpu); 837 } 838 839 CPU_TO_ID(x) = entry->apic_id; 840 ID_TO_CPU(entry->apic_id) = x; 841} 842 843 844static void 845bus_entry(bus_entry_ptr entry, int *bus) 846{ 847 int x, y; 848 char name[8]; 849 char c; 850 851 if ((x = (*bus)++) == NBUS) 852 panic("too many busses, increase 'NBUS'\n"); 853 854 /* encode the name into an index */ 855 for (y = 0; y < 6; ++y) { 856 if ((c = entry->bus_type[y]) == ' ') 857 break; 858 name[y] = c; 859 } 860 name[y] = '\0'; 861 862 if ((y = lookup_bus_type(name)) == UNKNOWN_BUSTYPE) 863 panic("unknown bus type: '%s'\n", name); 864 865 bus_data[x].bus_id = entry->bus_id; 866 bus_data[x].bus_type = y; 867} 868 869 870static void 871io_apic_entry(io_apic_entry_ptr entry, int *apic) 872{ 873 int x; 874 875 if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN)) 876 return; 877 878 if ((x = (*apic)++) == NAPIC) 879 panic("too many APICs, increase 'NAPIC'\n"); 880 881 IO_TO_ID(x) = entry->apic_id; 882 ID_TO_IO(entry->apic_id) = x; 883 884 io_apic_address[x] = (vm_offset_t) entry->apic_address; 885} 886 887 888static int 889lookup_bus_type(char *name) 890{ 891 int x; 892 893 for (x = 0; x < MAX_BUSTYPE; ++x) 894 if (strcmp(bus_type_table[x].name, name) == 0) 895 return bus_type_table[x].type; 896 897 return UNKNOWN_BUSTYPE; 898} 899 900 901static void 902int_entry(int_entry_ptr entry, int *intr) 903{ 904 int x; 905 906 if ((x = (*intr)++) == NINTR) 907 panic("too many INTs, increase 'NINTR'\n"); 908 909 io_apic_ints[x].int_type = entry->int_type; 910 io_apic_ints[x].int_flags = entry->int_flags; 911 io_apic_ints[x].src_bus_id = entry->src_bus_id; 912 io_apic_ints[x].src_bus_irq = entry->src_bus_irq; 913 io_apic_ints[x].dst_apic_id = entry->dst_apic_id; 914 io_apic_ints[x].dst_apic_int = entry->dst_apic_int; 915} 916 917 918static int 919apic_int_is_bus_type(int intr, int bus_type) 920{ 921 int bus; 922 923 for (bus = 0; bus < mp_nbusses; ++bus) 924 if ((bus_data[bus].bus_id == io_apic_ints[intr].src_bus_id) 925 && ((int) bus_data[bus].bus_type == bus_type)) 926 return 1; 927 928 return 0; 929} 930 931 932/* 933 * determine which APIC pin an ISA INT is attached to. 934 */ 935#define INTTYPE(I) (io_apic_ints[(I)].int_type) 936#define INTPIN(I) (io_apic_ints[(I)].dst_apic_int) 937 938#define SRCBUSIRQ(I) (io_apic_ints[(I)].src_bus_irq) 939int 940get_isa_apic_irq(int isaIRQ) 941{ 942 int intr; 943 944#if defined(SMP_TIMER_NC) 945 if (isaIRQ == 0) 946 return -1; 947#endif /* SMP_TIMER_NC */ 948 949 for (intr = 0; intr < nintrs; ++intr) /* search each INT record */ 950 if ((INTTYPE(intr) == 0) 951 && (SRCBUSIRQ(intr) == isaIRQ)) /* a candidate IRQ */ 952 if (apic_int_is_bus_type(intr, ISA)) /* check bus match */ 953 return INTPIN(intr); /* exact match */ 954 955 return -1; /* NOT found */ 956} 957#undef SRCBUSIRQ 958 959 960/* 961 * determine which APIC pin an EISA INT is attached to. 962 */ 963#define SRCBUSIRQ(I) (io_apic_ints[(I)].src_bus_irq) 964int 965get_eisa_apic_irq(int eisaIRQ) 966{ 967 int intr; 968 969#if defined(SMP_TIMER_NC) 970 if (eisaIRQ == 0) 971 return -1; 972#endif /* SMP_TIMER_NC */ 973 974 for (intr = 0; intr < nintrs; ++intr) /* search each INT record */ 975 if ((INTTYPE(intr) == 0) 976 && (SRCBUSIRQ(intr) == eisaIRQ)) /* a candidate IRQ */ 977 if (apic_int_is_bus_type(intr, EISA)) /* check bus match */ 978 return INTPIN(intr); /* exact match */ 979 980 return -1; /* NOT found */ 981} 982#undef SRCBUSIRQ 983 984 985/* 986 * determine which APIC pin a PCI INT is attached to. 987 */ 988#define SRCBUSID(I) (io_apic_ints[(I)].src_bus_id) 989#define SRCBUSDEVICE(I) ((io_apic_ints[(I)].src_bus_irq >> 2) & 0x1f) 990#define SRCBUSLINE(I) (io_apic_ints[(I)].src_bus_irq & 0x03) 991int 992get_pci_apic_irq(int pciBus, int pciDevice, int pciInt) 993{ 994 int intr; 995 996 --pciInt; /* zero based */ 997 998 for (intr = 0; intr < nintrs; ++intr) /* search each record */ 999 if ((INTTYPE(intr) == 0) 1000#if defined(FIX_MP_TABLE_WORKS) 1001 && (SRCBUSID(intr) == pciBus) 1002#endif /* FIX_MP_TABLE_WORKS */ 1003 && (SRCBUSDEVICE(intr) == pciDevice) 1004 && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ 1005 if (apic_int_is_bus_type(intr, PCI)) /* check bus match */ 1006 return INTPIN(intr); /* exact match */ 1007 1008 return -1; /* NOT found */ 1009} 1010#undef SRCBUSLINE 1011#undef SRCBUSDEVICE 1012#undef SRCBUSID 1013 1014#undef INTPIN 1015#undef INTTYPE 1016 1017 1018int 1019undirect_pci_irq(int rirq) 1020{ 1021#if defined(READY) 1022 printf("Freeing irq %d for ISA cards.\n", rirq); 1023 /** FIXME: tickle the MB redirector chip */ 1024 return ???; 1025#else 1026 printf("Freeing (NOT implimented) irq %d for ISA cards.\n", rirq); 1027 return 0; 1028#endif /* READY */ 1029} 1030 1031 1032/* 1033 * given a bus ID, return: 1034 * the bus type if found 1035 * -1 if NOT found 1036 */ 1037int 1038apic_bus_type(int id) 1039{ 1040 int x; 1041 1042 for (x = 0; x < mp_nbusses; ++x) 1043 if (bus_data[x].bus_id == id) 1044 return bus_data[x].bus_type; 1045 1046 return -1; 1047} 1048 1049 1050/* 1051 * given a LOGICAL APIC# and pin#, return: 1052 * the associated src bus ID if found 1053 * -1 if NOT found 1054 */ 1055int 1056apic_src_bus_id(int apic, int pin) 1057{ 1058 int x; 1059 1060 /* search each of the possible INTerrupt sources */ 1061 for (x = 0; x < nintrs; ++x) 1062 if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && 1063 (pin == io_apic_ints[x].dst_apic_int)) 1064 return (io_apic_ints[x].src_bus_id); 1065 1066 return -1; /* NOT found */ 1067} 1068 1069 1070/* 1071 * given a LOGICAL APIC# and pin#, return: 1072 * the associated src bus IRQ if found 1073 * -1 if NOT found 1074 */ 1075int 1076apic_src_bus_irq(int apic, int pin) 1077{ 1078 int x; 1079 1080 for (x = 0; x < nintrs; x++) 1081 if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && 1082 (pin == io_apic_ints[x].dst_apic_int)) 1083 return (io_apic_ints[x].src_bus_irq); 1084 1085 return -1; /* NOT found */ 1086} 1087 1088 1089/* 1090 * given a LOGICAL APIC# and pin#, return: 1091 * the associated INTerrupt type if found 1092 * -1 if NOT found 1093 */ 1094int 1095apic_int_type(int apic, int pin) 1096{ 1097 int x; 1098 1099 /* search each of the possible INTerrupt sources */ 1100 for (x = 0; x < nintrs; ++x) 1101 if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && 1102 (pin == io_apic_ints[x].dst_apic_int)) 1103 return (io_apic_ints[x].int_type); 1104 1105 return -1; /* NOT found */ 1106} 1107 1108 1109/* 1110 * given a LOGICAL APIC# and pin#, return: 1111 * the associated trigger mode if found 1112 * -1 if NOT found 1113 */ 1114int 1115apic_trigger(int apic, int pin) 1116{ 1117 int x; 1118 1119 /* search each of the possible INTerrupt sources */ 1120 for (x = 0; x < nintrs; ++x) 1121 if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && 1122 (pin == io_apic_ints[x].dst_apic_int)) 1123 return ((io_apic_ints[x].int_flags >> 2) & 0x03); 1124 1125 return -1; /* NOT found */ 1126} 1127 1128 1129/* 1130 * given a LOGICAL APIC# and pin#, return: 1131 * the associated 'active' level if found 1132 * -1 if NOT found 1133 */ 1134int 1135apic_polarity(int apic, int pin) 1136{ 1137 int x; 1138 1139 /* search each of the possible INTerrupt sources */ 1140 for (x = 0; x < nintrs; ++x) 1141 if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && 1142 (pin == io_apic_ints[x].dst_apic_int)) 1143 return (io_apic_ints[x].int_flags & 0x03); 1144 1145 return -1; /* NOT found */ 1146} 1147 1148 1149/* 1150 * set data according to MP defaults 1151 * FIXME: probably not complete yet... 1152 */ 1153static void 1154default_mp_table(int type) 1155{ 1156 int ap_cpu_id; 1157#if defined(APIC_IO) 1158 u_int32_t ux; 1159 int io_apic_id; 1160 int pin; 1161#endif /* APIC_IO */ 1162 1163#if 0 1164 printf(" MP default config type: %d\n", type); 1165 switch (type) { 1166 case 1: 1167 printf(" bus: ISA, APIC: 82489DX\n"); 1168 break; 1169 case 2: 1170 printf(" bus: EISA, APIC: 82489DX\n"); 1171 break; 1172 case 3: 1173 printf(" bus: EISA, APIC: 82489DX\n"); 1174 break; 1175 case 4: 1176 printf(" bus: MCA, APIC: 82489DX\n"); 1177 break; 1178 case 5: 1179 printf(" bus: ISA+PCI, APIC: Integrated\n"); 1180 break; 1181 case 6: 1182 printf(" bus: EISA+PCI, APIC: Integrated\n"); 1183 break; 1184 case 7: 1185 printf(" bus: MCA+PCI, APIC: Integrated\n"); 1186 break; 1187 default: 1188 printf(" future type\n"); 1189 break; 1190 /* NOTREACHED */ 1191 } 1192#endif /* 0 */ 1193 1194 boot_cpu_id = (apic_base[APIC_ID] & APIC_ID_MASK) >> 24; 1195 ap_cpu_id = (boot_cpu_id == 0) ? 1 : 0; 1196 1197 /* BSP */ 1198 CPU_TO_ID(0) = boot_cpu_id; 1199 ID_TO_CPU(boot_cpu_id) = 0; 1200 1201 /* one and only AP */ 1202 CPU_TO_ID(1) = ap_cpu_id; 1203 ID_TO_CPU(ap_cpu_id) = 1; 1204 mp_naps = 1; 1205 1206 /* one and only IO APIC */ 1207#if defined(APIC_IO) 1208 io_apic_id = (io_apic_read(0, IOAPIC_ID) & APIC_ID_MASK) >> 24; 1209 1210 /* 1211 * sanity check, refer to MP spec section 3.6.6, last paragraph 1212 * necessary as some hardware isn't properly setting up the IO APIC 1213 */ 1214#if defined(REALLY_ANAL_IOAPICID_VALUE) 1215 if (io_apic_id != 2) { 1216#else 1217 if ((io_apic_id == 0) || (io_apic_id == 1) || (io_apic_id == 15)) { 1218#endif /* REALLY_ANAL_IOAPICID_VALUE */ 1219 ux = io_apic_read(0, IOAPIC_ID); /* get current contents */ 1220 ux &= ~APIC_ID_MASK; /* clear the ID field */ 1221 ux |= 0x02000000; /* set it to '2' */ 1222 io_apic_write(0, IOAPIC_ID, ux); /* write new value */ 1223 ux = io_apic_read(0, IOAPIC_ID); /* re-read && test */ 1224 if ((ux & APIC_ID_MASK) != 0x02000000) 1225 panic("Problem: can't control IO APIC ID, reg: 0x%08x\n", ux); 1226 io_apic_id = 2; 1227 } 1228 IO_TO_ID(0) = io_apic_id; 1229 ID_TO_IO(io_apic_id) = 0; 1230 mp_napics = 1; 1231#else 1232 mp_napics = 0; 1233#endif /* APIC_IO */ 1234 1235 /* fill out bus entries */ 1236 switch (type) { 1237 case 1: 1238 case 2: 1239 case 3: 1240 case 5: 1241 case 6: 1242 mp_nbusses = default_data[type - 1][0]; 1243 bus_data[0].bus_id = default_data[type - 1][1]; 1244 bus_data[0].bus_type = default_data[type - 1][2]; 1245 bus_data[1].bus_id = default_data[type - 1][3]; 1246 bus_data[1].bus_type = default_data[type - 1][4]; 1247 break; 1248 1249 /* case 4: case 7: MCA NOT supported */ 1250 default: /* illegal/reserved */ 1251 panic("BAD default MP config: %d\n", type); 1252 } 1253 1254#if defined(APIC_IO) 1255 /* general cases from MP v1.4, table 5-2 */ 1256 for (pin = 0; pin < 16; ++pin) { 1257 io_apic_ints[pin].int_type = 0; 1258 io_apic_ints[pin].int_flags = 0x05; /* edge-triggered/active-hi */ 1259 io_apic_ints[pin].src_bus_id = 0; 1260 io_apic_ints[pin].src_bus_irq = pin; /* IRQ2 is caught below */ 1261 io_apic_ints[pin].dst_apic_id = io_apic_id; 1262 io_apic_ints[pin].dst_apic_int = pin; /* 1-to-1 correspondence */ 1263 } 1264 1265 /* special cases from MP v1.4, table 5-2 */ 1266 if (type == 2) { 1267 io_apic_ints[2].int_type = 0xff; /* N/C */ 1268 io_apic_ints[13].int_type = 0xff; /* N/C */ 1269#if !defined(APIC_MIXED_MODE) 1270 /** FIXME: ??? */ 1271 panic("sorry, can't support type 2 default yet\n"); 1272#endif /* APIC_MIXED_MODE */ 1273 } else 1274 io_apic_ints[2].src_bus_irq = 0; /* ISA IRQ0 is on APIC INT 2 */ 1275 1276 if (type == 7) 1277 io_apic_ints[0].int_type = 0xff; /* N/C */ 1278 else 1279 io_apic_ints[0].int_type = 3; /* vectored 8259 */ 1280 1281 nintrs = 16; 1282#endif /* APIC_IO */ 1283} 1284 1285 1286static void install_ap_tramp(u_int boot_addr); 1287static int start_ap(int logicalCpu, u_int boot_addr); 1288 1289/* 1290 * start each AP in our list 1291 */ 1292static int 1293start_all_aps(u_int boot_addr) 1294{ 1295 int x; 1296 u_char mpbiosreason; 1297 u_long mpbioswarmvec; 1298 1299 /** 1300 * NOTE: this needs further thought: 1301 * where does it get released? 1302 * should it be set to empy? 1303 * 1304 * get the initial mp_lock with a count of 1 for the BSP 1305 */ 1306 mp_lock = (apic_base[APIC_ID] & APIC_ID_MASK) + 1; 1307 1308 /* initialize BSP's local APIC */ 1309 apic_initialize(1); 1310 1311 /* install the AP 1st level boot code */ 1312 install_ap_tramp(boot_addr); 1313 1314 /* save the current value of the warm-start vector */ 1315 mpbioswarmvec = *((u_long *) WARMBOOT_OFF); 1316 outb(CMOS_REG, BIOS_RESET); 1317 mpbiosreason = inb(CMOS_DATA); 1318 1319 /* start each AP */ 1320 for (x = 1; x <= mp_naps; ++x) { 1321 1322 /* setup a vector to our boot code */ 1323 *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET; 1324 *((volatile u_short *) WARMBOOT_SEG) = (boot_addr >> 4); 1325 outb(CMOS_REG, BIOS_RESET); 1326 outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ 1327 1328 /* attempt to start the Application Processor */ 1329 CHECK_INIT(99); /* setup checkpoints */ 1330 if (!start_ap(x, boot_addr)) { 1331 printf("AP #%d (PHY# %d) failed!\n", x, CPU_TO_ID(x)); 1332 CHECK_PRINT("trace"); /* show checkpoints */ 1333 /* 1334 * better panic as the AP may be running loose 1335 * somewhere 1336 */ 1337 printf("panic y/n? [n] "); 1338 if (cngetc() != 'n') 1339 panic("bye-bye\n"); 1340 } 1341 CHECK_PRINT("trace"); /* show checkpoints */ 1342 1343 /* record its version info */ 1344 cpu_apic_versions[x] = cpu_apic_versions[0]; 1345 } 1346 1347 /* fill in our (BSP) APIC version */ 1348 cpu_apic_versions[0] = apic_base[APIC_VER]; 1349 1350 /* restore the warmstart vector */ 1351 *(u_long *) WARMBOOT_OFF = mpbioswarmvec; 1352 outb(CMOS_REG, BIOS_RESET); 1353 outb(CMOS_DATA, mpbiosreason); 1354 1355 /* number of APs actually started */ 1356 return mp_ncpus - 1; 1357} 1358 1359 1360/* 1361 * load the 1st level AP boot code into base memory. 1362 */ 1363 1364/* targets for relocation */ 1365extern void bigJump(void); 1366extern void bootCodeSeg(void); 1367extern void bootDataSeg(void); 1368extern void MPentry(void); 1369extern u_int MP_GDT; 1370extern u_int mp_gdtbase; 1371 1372static void 1373install_ap_tramp(u_int boot_addr) 1374{ 1375 int x; 1376 int size = *(int *) ((u_long) & bootMP_size); 1377 u_char *src = (u_char *) ((u_long) bootMP); 1378 u_char *dst = (u_char *) boot_addr + KERNBASE; 1379 u_int boot_base = (u_int) bootMP; 1380 u_int8_t *dst8; 1381 u_int16_t *dst16; 1382 u_int32_t *dst32; 1383 1384 for (x = 0; x < size; ++x) 1385 *dst++ = *src++; 1386 1387 /* 1388 * modify addresses in code we just moved to basemem. unfortunately we 1389 * need fairly detailed info about mpboot.s for this to work. changes 1390 * to mpboot.s might require changes here. 1391 */ 1392 1393 /* boot code is located in KERNEL space */ 1394 dst = (u_char *) boot_addr + KERNBASE; 1395 1396 /* modify the lgdt arg */ 1397 dst32 = (u_int32_t *) (dst + ((u_int) & mp_gdtbase - boot_base)); 1398 *dst32 = boot_addr + ((u_int) & MP_GDT - boot_base); 1399 1400 /* modify the ljmp target for MPentry() */ 1401 dst32 = (u_int32_t *) (dst + ((u_int) bigJump - boot_base) + 1); 1402 *dst32 = ((u_int) MPentry - KERNBASE); 1403 1404 /* modify the target for boot code segment */ 1405 dst16 = (u_int16_t *) (dst + ((u_int) bootCodeSeg - boot_base)); 1406 dst8 = (u_int8_t *) (dst16 + 1); 1407 *dst16 = (u_int) boot_addr & 0xffff; 1408 *dst8 = ((u_int) boot_addr >> 16) & 0xff; 1409 1410 /* modify the target for boot data segment */ 1411 dst16 = (u_int16_t *) (dst + ((u_int) bootDataSeg - boot_base)); 1412 dst8 = (u_int8_t *) (dst16 + 1); 1413 *dst16 = (u_int) boot_addr & 0xffff; 1414 *dst8 = ((u_int) boot_addr >> 16) & 0xff; 1415} 1416 1417 1418/* 1419 * this function starts the AP (application processor) identified 1420 * by the APIC ID 'physicalCpu'. It does quite a "song and dance" 1421 * to accomplish this. This is necessary because of the nuances 1422 * of the different hardware we might encounter. It ain't pretty, 1423 * but it seems to work. 1424 */ 1425static int 1426start_ap(int logical_cpu, u_int boot_addr) 1427{ 1428 int physical_cpu; 1429 int vector; 1430 int cpus; 1431 u_long icr_lo, icr_hi; 1432 1433 /* get the PHYSICAL APIC ID# */ 1434 physical_cpu = CPU_TO_ID(logical_cpu); 1435 1436 /* calculate the vector */ 1437 vector = (boot_addr >> 12) & 0xff; 1438 1439 /* used as a watchpoint to signal AP startup */ 1440 cpus = mp_ncpus; 1441 1442 /* 1443 * first we do an INIT/RESET IPI this INIT IPI might be run, reseting 1444 * and running the target CPU. OR this INIT IPI might be latched (P5 1445 * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be 1446 * ignored. 1447 */ 1448 1449 /* setup the address for the target AP */ 1450 icr_hi = apic_base[APIC_ICR_HI] & ~APIC_ID_MASK; 1451 icr_hi |= (physical_cpu << 24); 1452 apic_base[APIC_ICR_HI] = icr_hi; 1453 1454 /* do an INIT IPI: assert RESET */ 1455 icr_lo = apic_base[APIC_ICR_LOW] & 0xfff00000; 1456 apic_base[APIC_ICR_LOW] = icr_lo | 0x0000c500; 1457 1458 /* wait for pending status end */ 1459 while (apic_base[APIC_ICR_LOW] & APIC_DELSTAT_MASK) 1460 /* spin */ ; 1461 1462 /* do an INIT IPI: deassert RESET */ 1463 apic_base[APIC_ICR_LOW] = icr_lo | 0x00008500; 1464 1465 /* wait for pending status end */ 1466 u_sleep(10000); /* wait ~10mS */ 1467 while (apic_base[APIC_ICR_LOW] & APIC_DELSTAT_MASK) 1468 /* spin */ ; 1469 1470 /* 1471 * next we do a STARTUP IPI: the previous INIT IPI might still be 1472 * latched, (P5 bug) this 1st STARTUP would then terminate 1473 * immediately, and the previously started INIT IPI would continue. OR 1474 * the previous INIT IPI has already run. and this STARTUP IPI will 1475 * run. OR the previous INIT IPI was ignored. and this STARTUP IPI 1476 * will run. 1477 */ 1478 1479 /* do a STARTUP IPI */ 1480 apic_base[APIC_ICR_LOW] = icr_lo | 0x00000600 | vector; 1481 while (apic_base[APIC_ICR_LOW] & APIC_DELSTAT_MASK) 1482 /* spin */ ; 1483 u_sleep(200); /* wait ~200uS */ 1484 1485 /* 1486 * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF 1487 * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR 1488 * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is 1489 * recognized after hardware RESET or INIT IPI. 1490 */ 1491 1492 apic_base[APIC_ICR_LOW] = icr_lo | 0x00000600 | vector; 1493 while (apic_base[APIC_ICR_LOW] & APIC_DELSTAT_MASK) 1494 /* spin */ ; 1495 u_sleep(200); /* wait ~200uS */ 1496 1497 /* wait for it to start */ 1498 set_apic_timer(5000000);/* == 5 seconds */ 1499 while (read_apic_timer()) 1500 if (mp_ncpus > cpus) 1501 return 1; /* return SUCCESS */ 1502 1503 return 0; /* return FAILURE */ 1504} 1505 1506 1507#if defined(IPI_INTS) 1508 1509static void 1510ipi_intr0(void) 1511{ 1512 printf("IPI 0\n"); 1513} 1514 1515 1516static void 1517ipi_intr1(void) 1518{ 1519 printf("IPI 1\n"); 1520} 1521 1522 1523static void 1524ipi_intr2(void) 1525{ 1526 printf("IPI 2\n"); 1527} 1528 1529 1530static void 1531ipi_intr3(void) 1532{ 1533 printf("IPI 3\n"); 1534} 1535 1536/*----------------------------------------------------------------------- 1537** 1538** Register an interupt handler for an IPI. 1539** (Stolen from the PCI<->ISA glue code) 1540** 1541**----------------------------------------------------------------------- 1542*/ 1543 1544static int 1545ipi_ihandler_attach(int irq, inthand2_t * func, unsigned *maskptr, int unit) 1546{ 1547 char buf[16]; 1548 char *cp; 1549 int free_id, id, result; 1550 1551 sprintf(buf, "ipi irq%d", irq); 1552 for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { 1553 if (strcmp(cp, buf) == 0) 1554 break; 1555 if (free_id <= 0 && strcmp(cp, "ipi irqnn") == 0) 1556 free_id = id; 1557 while (*cp++ != '\0'); 1558 } 1559 if (id == NR_DEVICES) { 1560 id = free_id; 1561 if (id == 0) { 1562 /* 1563 * All ipi irq counters are in use, perhaps because 1564 * config is old so there aren't any. Abuse the clk0 1565 * counter. 1566 */ 1567 printf( 1568 "ipi_ihandler_attach: counting ipi irq%d's as clk0 irqs\n", 1569 irq); 1570 } 1571 } 1572 result = register_intr( 1573 irq, /* isa irq */ 1574 id, /* device id */ 1575 0, /* flags? */ 1576 func, /* handler */ 1577 maskptr, /* mask pointer */ 1578 unit); /* handler arg */ 1579 1580 if (result) { 1581 printf("WARNING: ipi_ihandler_attach: result=%d\n", result); 1582 return (result); 1583 }; 1584 1585 return (0); 1586} 1587#endif /* IPI_INTS */ 1588 1589 1590#ifdef SMP_INVLTLB 1591/* 1592 * Flush the TLB on all other CPU's 1593 * 1594 * XXX: Needs to handshake and wait for completion before proceding. 1595 */ 1596 1597void 1598smp_invltlb() 1599{ 1600 if (smp_active) { 1601 if (invldebug & 2) 1602#if defined(XFAST_IPI32) 1603 all_but_self_ipi(ICU_OFFSET + 32); 1604#else 1605 all_but_self_ipi(ICU_OFFSET + 27); 1606#endif /* XFAST_IPI32 */ 1607 } 1608} 1609 1610void 1611invlpg(u_int addr) 1612{ 1613 __asm __volatile("invlpg (%0)"::"r"(addr):"memory"); 1614 smp_invltlb(); 1615} 1616 1617void 1618invltlb(void) 1619{ 1620 u_long temp; 1621 /* 1622 * This should be implemented as load_cr3(rcr3()) when load_cr3() is 1623 * inlined. 1624 */ 1625 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3":"=r"(temp) :: "memory"); 1626 smp_invltlb(); 1627} 1628/* 1629 * Handles recieving an "IRQ 27", the invalidate tlb IPI.. 1630 */ 1631void 1632ipi_invltlb(void) 1633{ 1634 u_long temp; 1635 1636 if (invldebug & 4) { 1637 /* 1638 * This should be implemented as load_cr3(rcr3()) when 1639 * load_cr3() is inlined. 1640 */ 1641 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3":"=r"(temp) 1642 :: "memory"); 1643 1644 } 1645} 1646#endif /* SMP_INVLTLB */ 1647