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