smp.c (16117B)
1 /* $Id: //depot/blt/kernel/smp.c#6 $ 2 ** 3 ** Copyright 1998 Sidney Cammeresi 4 ** All rights reserved. 5 ** Copyright (c) 1996, by Steve Passe 6 ** All rights reserved. 7 ** 8 ** Redistribution and use in source and binary forms, with or without 9 ** modification, are permitted provided that the following conditions 10 ** are met: 11 ** 1. Redistributions of source code must retain the above copyright 12 ** notice, this list of conditions, and the following disclaimer. 13 ** 2. Redistributions in binary form must reproduce the above copyright 14 ** notice, this list of conditions, and the following disclaimer in the 15 ** documentation and/or other materials provided with the distribution. 16 ** 3. The name of the author may not be used to endorse or promote products 17 ** derived from this software without specific prior written permission. 18 ** 19 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "kernel.h" 32 #include "i386/io.h" 33 #include "init.h" 34 #include "smp.h" 35 36 #undef SMP_DEBUG 37 38 #ifdef SMP_DEBUG 39 #define SMP_PRINTF(f,a...) kprintf (f, ## a) 40 #else 41 #define SMP_PRINTF(f,a...) 42 #endif 43 44 const char *cpu_family[] __initdata__ = { "", "", "", "", "Intel 486", 45 "Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" }; 46 const unsigned int temp_gdt[] = {0x00000000, 0x00000000, /* null descriptor */ 47 0x0000ffff, 0x00cf9a00, /* kernel text */ 48 0x0000ffff, 0x00cf9200 };/* kernel data */ 49 50 char mp_num_def_config, smp_num_cpus = 1, smp_num_running_cpus; 51 volatile char smp_cpus_ready[BLT_MAX_CPUS], smp_configured = 0, smp_begun = 0; 52 unsigned int cpuid_max_level, cpuid_eax, cpuid_edx, apic_addr, 53 cpu_apic_id[BLT_MAX_CPUS], cpu_os_id[BLT_MAX_CPUS], 54 cpu_apic_version[BLT_MAX_CPUS], *apic, *apic_virt, *ioapic; 55 56 mp_flt_ptr *mp_config; 57 58 extern aspace_t *flat; 59 extern void (*flush) (void); 60 61 volatile char ipi_lock = 0; 62 63 volatile unsigned int apic_read (unsigned int *addr) 64 { 65 return *addr; 66 } 67 68 void apic_write (unsigned int *addr, unsigned int data) 69 { 70 *addr = data; 71 } 72 73 /* XXX - hack until we can figure this out */ 74 int bus_clock (void) 75 { 76 return 66000000; 77 } 78 79 /********** adapted from FreeBSD's i386/i386/mpapic.c **********/ 80 81 void __init__ apic_set_timer (int value) 82 { 83 unsigned long lvtt; 84 long ticks_per_us; 85 86 /* calculate divisor and count from value */ 87 apic_write (APIC_TDCR, APIC_TDCR_1); 88 ticks_per_us = bus_clock () / 1000000; 89 90 /* configure timer as one-shot */ 91 lvtt = apic_read (APIC_LVTT) & ~(APIC_LVTT_VECTOR | APIC_LVTT_DS | 92 APIC_LVTT_M | APIC_LVTT_TM) | APIC_LVTT_M | 0xff; 93 apic_write (APIC_LVTT, lvtt); 94 apic_write (APIC_ICRT, value * ticks_per_us); 95 } 96 97 /************************* end FreeBSD *************************/ 98 99 int apic_read_timer (void) 100 { 101 return apic_read (APIC_CCRT); 102 } 103 104 void __init__ u_sleep (int count) 105 { 106 int i; 107 108 apic_set_timer (count); 109 while (i = apic_read (APIC_CCRT)) ; 110 } 111 112 void __init__ mp_probe (int base, int limit) 113 { 114 unsigned int i, *ptr; 115 116 for (ptr = (unsigned int *) base; (unsigned int) ptr < limit; ptr++) 117 if (*ptr == MP_FLT_SIGNATURE) 118 { 119 SMP_PRINTF ("smp: found floating pointer structure at %x", ptr); 120 mp_config = (mp_flt_ptr *) ptr; 121 return; 122 } 123 } 124 125 int __init__ mp_verify_data (void) 126 { 127 char *ptr, total; 128 int i; 129 130 /* check signature */ 131 if (mp_config->signature != MP_FLT_SIGNATURE) 132 return 0; 133 134 /* compute floating pointer structure checksum */ 135 ptr = (unsigned char *) mp_config; 136 for (i = total = 0; i < (mp_config->mpc_len * 16); i++) 137 total += ptr[i]; 138 if (total) 139 return 0; 140 kprintf ("smp: CHECKSUMMED"); 141 142 /* compute mp configuration table checksum if we have one*/ 143 if ((ptr = (unsigned char *) mp_config->mpc) != NULL) 144 { 145 for (i = total = 0; i < sizeof (mp_config_table); i++) 146 total += ptr[i]; 147 if (total) 148 return 0; 149 } 150 else 151 kprintf ("smp: no configuration table\n"); 152 153 return 1; 154 } 155 156 void __init__ mp_do_config (void) 157 { 158 char *ptr; 159 int i; 160 mp_ext_pe *pe; 161 mp_ext_ioapic *io; 162 163 /* 164 * we are not running in standard configuration, so we have to look through 165 * all of the mp configuration table crap to figure out how many processors 166 * we have, where our apics are, etc. 167 */ 168 smp_num_cpus = 0; 169 170 /* print out our new found configuration. */ 171 ptr = (char *) &(mp_config->mpc->oem[0]); 172 kprintf ("smp: oem id: %c%c%c%c%c%c%c%c product id: " 173 "%c%c%c%c%c%c%c%c%c%c%c%c", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], 174 ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], 175 ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19], 176 ptr[20]); 177 SMP_PRINTF ("smp: base table has %d entries, extended section %d bytes", 178 mp_config->mpc->num_entries, mp_config->mpc->ext_len); 179 apic = (unsigned int *) mp_config->mpc->apic; 180 181 ptr = (char *) ((unsigned int) mp_config->mpc + sizeof (mp_config_table)); 182 for (i = 0; i < mp_config->mpc->num_entries; i++) 183 switch (*ptr) 184 { 185 case MP_EXT_PE: 186 pe = (mp_ext_pe *) ptr; 187 cpu_apic_id[smp_num_cpus] = pe->apic_id; 188 cpu_os_id[pe->apic_id] = smp_num_cpus; 189 cpu_apic_version [smp_num_cpus] = pe->apic_version; 190 kprintf ("smp: cpu#%d: %s, apic id %d, version %d%s", 191 smp_num_cpus++, cpu_family[(pe->signature & 0xf00) >> 8], 192 pe->apic_id, pe->apic_version, (pe->cpu_flags & 0x2) ? 193 ", BSP" : ""); 194 ptr += 20; 195 break; 196 case MP_EXT_BUS: 197 ptr += 8; 198 break; 199 case MP_EXT_IO_APIC: 200 io = (mp_ext_ioapic *) ptr; 201 ioapic = io->addr; 202 SMP_PRINTF ("smp: found io apic with apic id %d, version %d", 203 io->ioapic_id, io->ioapic_version); 204 ptr += 8; 205 break; 206 case MP_EXT_IO_INT: 207 ptr += 8; 208 break; 209 case MP_EXT_LOCAL_INT: 210 ptr += 8; 211 break; 212 } 213 214 kprintf ("smp: apic @ 0x%x, i/o apic @ 0x%x, total %d processors detected", 215 (unsigned int) apic, (unsigned int) ioapic, smp_num_cpus); 216 } 217 218 /* FIXME - this is a very long stretch that needs to be broken up. */ 219 void __init__ smp_init (void) 220 { 221 unsigned char *ptr, init_val; 222 unsigned int i, j, config, num_startups, *new_stack, *dir, *table, *page, 223 *common; 224 225 SMP_PRINTF ("smp: initialising"); 226 /* 227 * first let's check the kind of processor this is since only intel chips 228 * support the MP specification. 229 */ 230 #if 0 231 /* FIXME - this check doesn't work */ 232 if (!smp_check_cpu ()) 233 SMP_ERROR ("smp: processor is not Genuine Intel or is a 386 or 486\n"); 234 #else 235 j = smp_check_cpu (); 236 SMP_PRINTF ("smp: cpu is %x", j); 237 #endif 238 239 /* 240 * scan the three spec-defined regions for the floating pointer 241 * structure. if we find one, copy its address into mp_config, 242 * otherwise, abort smp initialisation. after that, check the 243 * integrity of the structures. 244 */ 245 mp_config = (mp_flt_ptr *) 0x1000; /* small hack */ 246 /* mp_probe (0, 0x400); */ 247 mp_probe (0x9fc00, 0xa0000); 248 mp_probe (0xf0000, 0x100000); 249 if (mp_config == (mp_flt_ptr *) 0x1000) /* if unchanged */ 250 SMP_ERROR ("smp: no floating pointer structure detected\n"); 251 252 #if 0 253 /* FIXME - this check doesn't work */ 254 if (!smp_verify_data ()) 255 SMP_ERROR ("smp: bad configuration information\n"); 256 kprintf ("smp: it's all good\n"); 257 #endif 258 259 /* 260 * whee, we're running on an smp machine with valid configuration 261 * information. print out some of this new intelligence. 262 */ 263 kprintf ("smp: intel mp version %s, %s", (mp_config->mp_rev == 1) ? "1.1" : 264 "1.4", (mp_config->mp_feature_2 & 0x80) ? 265 "imcr and pic compatibility mode." : "virtual wire compatibility mode."); 266 267 if (!mp_config->mpc) 268 { 269 /* this system conforms to one of the default configurations */ 270 mp_num_def_config = mp_config->mp_feature_1; 271 kprintf ("smp: standard configuration %d", mp_num_def_config); 272 smp_num_cpus = 2; 273 cpu_apic_id[0] = 0; 274 cpu_apic_id[1] = 1; 275 apic = (unsigned int *) 0xfee00000; 276 ioapic = (unsigned int *) 0xfec00000; 277 kprintf ("smp: WARNING: standard configuration code is untested"); 278 else 279 { 280 /* 281 * we don't have a default configuration, so now we have to locate all 282 * of our hardware. boy, do we have a lot of work to do. 283 */ 284 SMP_PRINTF ("smp: not a standard configuration"); 285 mp_num_def_config = 0; 286 mp_do_config (); 287 } 288 smp_configured = 1; 289 290 /* set up the apic */ 291 aspace_maphi (flat, 0xfee00, 0x3fc, 1, 0x13); 292 apic_virt = (unsigned int *) 0x803fc000; 293 asm ("mov %0, %%cr3" : : "r" (_cr3)); 294 295 config = apic_read ((unsigned int *) APIC_SIVR) & APIC_FOCUS | APIC_ENABLE | 296 0xff; /* set spurious interrupt vector to 0xff */ 297 apic_write (APIC_SIVR, config); 298 config = apic_read (APIC_TPRI) & 0xffffff00; /* accept all interrupts */ 299 apic_write (APIC_TPRI, config); 300 301 apic_read (APIC_SIVR); 302 apic_write (APIC_EOI, 0); 303 304 config = apic_read (APIC_LVT3) & 0xffffff00 | 0xfe; /* XXX - set vector */ 305 apic_write (APIC_LVT3, config); 306 307 /* grab a page at 0x9000 for communicating with the aps */ 308 aspace_map (flat, 0x9, 0x9, 1, 3); 309 common = (unsigned int *) 0x9000; 310 for (i = 0; i < 6; i++) 311 common [i + 1] = temp_gdt [i]; 312 *((unsigned int *) 0x9024) = _cr3; 313 aspace_map (flat, 0xa, 0xa, 1, 3); 314 ptr = (unsigned char *) 0xa000; 315 for (j = 0; j < ((unsigned int) &trampoline_end - (unsigned int) 316 &trampoline + 1); j++) 317 ptr[j] = ((unsigned char *) &trampoline)[j]; 318 319 /* 320 * okay, we're ready to go. boot all of the ap's now. we loop through 321 * using the kernel pe id numbers which were set up in smp_do_config () 322 * 323 * XXX - we assume the bsp is the first detected. trying to boot it here 324 * would be, ahem, bad. 325 */ 326 for (i = 1; i < smp_num_cpus; i++) 327 { 328 kprintf ("smp: booting cpu#%d with stack 0x%x", i, i * 0x1000); 329 330 /* map stacks and copy bootstrap code onto them */ 331 aspace_map (flat, i, i, 1, 3); 332 ptr = (unsigned char *) (0x1000 * i); 333 for (j = 0; j < ((unsigned int) &trampoline_end - (unsigned int) 334 &trampoline + 1); j++) 335 ptr[j] = ((unsigned char *) &trampoline)[j]; 336 337 /* 338 * modify the bootstrap code, specifically, the third highest order 339 * byte of the ljmp. we need to do this if we have more than two 340 * processors, i.e. more than one ap. 341 */ 342 ptr = (char *) flush; 343 *(ptr - 5) = i << 4; 344 345 /* write the location of the stack into a fixed spot in memory */ 346 *common = 0x1000 * i; 347 348 /* set shutdown code and warm reset vector */ 349 ptr = (unsigned char *) 0xf; 350 *ptr = 0xa; 351 ptr = (unsigned char *) 0x467; 352 *ptr = 0x1000 * i; 353 ptr = (unsigned char *) 0x469; 354 *ptr = 0; 355 356 /* reset cpu ready bit */ 357 smp_cpus_ready[i] = 0; 358 359 /* clear apic errors */ 360 if (cpu_apic_version[i] & 0xf0) 361 { 362 apic_write (APIC_ESR, 0); 363 apic_read (APIC_ESR); 364 } 365 366 /* send (aka assert) INIT IPI */ 367 SMP_PRINTF ("smp: asserting INIT"); 368 config = apic_read (APIC_ICR2) & 0xf0ffffff | (cpu_apic_id[i] << 24); 369 apic_write (APIC_ICR2, config); /* set target pe */ 370 config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DM_INIT | 371 APIC_LEVEL_TRIG | APIC_ASSERT; 372 apic_write (APIC_ICR1, config); 373 374 /* deassert INIT */ 375 SMP_PRINTF ("smp: deasserting INIT"); 376 config = apic_read (APIC_ICR2) & 0xffffff | (cpu_apic_id[i] << 24); 377 apic_write (APIC_ICR2, config); 378 config = apic_read (APIC_ICR1) & ~0xcdfff | APIC_LEVEL_TRIG | 379 APIC_DM_INIT; 380 381 /* wait 10ms */ 382 u_sleep (10000); 383 384 /* is this a local apic or an 82489dx ? */ 385 num_startups = (cpu_apic_version[i] & 0xf0) ? 2 : 0; 386 for (j = 0; j < num_startups; j++) 387 { 388 /* it's a local apic, so send STARTUP IPIs */ 389 SMP_PRINTF ("smp: sending STARTUP"); 390 apic_write (APIC_ESR, 0); 391 392 /* set target pe */ 393 config = apic_read (APIC_ICR2) & 0xf0ffffff | (cpu_apic_id[i] << 394 24); 395 apic_write (APIC_ICR2, config); 396 397 /* send the IPI */ 398 config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DM_STARTUP | 399 ((0x1000 * i) >> 12); 400 apic_write (APIC_ICR1, config); 401 402 /* wait */ 403 u_sleep (200); 404 while (apic_read (APIC_ICR1) & 0x1000) ; 405 } 406 407 /* wait for processor to boot */ 408 SMP_PRINTF ("smp: waiting for cpu#%d to come online", i); 409 apic_set_timer (5000000); /* 5 seconds */ 410 while (apic_read_timer ()) 411 if (smp_cpus_ready[i]) 412 break; 413 if (!smp_cpus_ready[i]) 414 kprintf ("smp: initialisation of cpu#%d failed", i); 415 } 416 417 /* this processor is already booted */ 418 smp_cpus_ready[smp_my_cpu ()] = 1; 419 420 //ioapic_init (); 421 //apic_write (APIC_LVTT, 0x100fe); 422 //ipi_all_but_self (0x40); 423 } 424 425 void __init__ smp_cpu_setup (void) 426 { 427 unsigned int config; 428 429 /* load the correct values into the idtr and gdtr */ 430 i386lidt ((uint32) idt, 0x3ff); 431 i386lgdt ((uint32) gdt, 0x400 / 8); 432 433 /* set up the local apic */ 434 config = apic_read ((unsigned int *) APIC_SIVR) & APIC_FOCUS | APIC_ENABLE | 435 0xff; /* set spurious interrupt vector to 0xff */ 436 apic_write (APIC_SIVR, config); 437 config = apic_read (APIC_TPRI) & 0xffffff00; /* accept all interrupts */ 438 apic_write (APIC_TPRI, config); 439 440 apic_read (APIC_SIVR); 441 apic_write (APIC_EOI, 0); 442 443 config = apic_read (APIC_LVT3) & 0xffffff00; /* XXX - set vector */ 444 apic_write (APIC_LVT3, config); 445 } 446 447 void __init__ smp_final_setup (void) 448 { 449 unsigned int config, ticks_per_us; 450 451 ticks_per_us = bus_clock () / 1000000; 452 apic_write (APIC_ICRT, ticks_per_us * 10000); /* 10 ms */ 453 config = 0x20030; 454 apic_write (APIC_LVTT, config); 455 456 if (smp_my_cpu ()) 457 sti (); 458 else 459 mask_irq (0); 460 } 461 462 void __init__ smp_cpu_ready (void) 463 { 464 /* 465 * C code entry point for aps. we finish initialisation and wait for the 466 * signal from the bsp before heading off into the wild blue yonder. 467 */ 468 469 /* finish processor initialisation. */ 470 smp_cpu_setup (); 471 472 /* inform the world of our presence. */ 473 kprintf ("smp: cpu#%d is online", smp_my_cpu ()); 474 smp_cpus_ready[smp_my_cpu ()] = 1; 475 476 /* wait for signal from bsp. */ 477 while (!smp_begun) ; 478 kprintf ("smp: cpu#%d running", smp_my_cpu ()); 479 480 /* set up local apic to generate timer interrupts. */ 481 smp_final_setup (); 482 483 /* bon voyage. */ 484 //swtch (); 485 while (1) ; 486 } 487 488 void __init__ smp_begin (void) 489 { 490 /* 491 * begin smp. we set the begun bit to release the application processors 492 * out of their cages. they storm out, fly into the scheduler, and off 493 * we go. 494 */ 495 smp_begun = 1; 496 } 497 498 int smp_my_cpu (void) 499 { 500 if (!smp_configured) 501 return 0; 502 else 503 return cpu_os_id [(apic_read (APIC_ID) & 0xffffffff) >> 24]; 504 } 505 506 void ipi_dest (int num, int pe) 507 { 508 int config; 509 510 p (&ipi_lock); 511 cli (); 512 config = apic_read (APIC_ICR2) & 0xffffff | (pe << 24); 513 apic_write (APIC_ICR2, config); 514 config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DEST_FIELD | num | 515 0x4000; 516 apic_write (APIC_ICR1, config); 517 sti (); 518 v (&ipi_lock); 519 } 520 521 void ipi_self (int num) 522 { 523 int config; 524 525 p (&ipi_lock); 526 cli (); 527 config = apic_read (APIC_ICR2) & 0xffffff; 528 apic_write (APIC_ICR2, config); 529 config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_SELF | num; 530 apic_write (APIC_ICR1, config); 531 sti (); 532 v (&ipi_lock); 533 } 534 535 void ipi_all (int num) 536 { 537 int config; 538 539 p (&ipi_lock); 540 cli (); 541 config = apic_read (APIC_ICR2) & 0xffffff; 542 apic_write (APIC_ICR2, config); 543 config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_ALL | num; 544 apic_write (APIC_ICR1, config); 545 sti (); 546 v (&ipi_lock); 547 } 548 549 void ipi_all_but_self (int num) 550 { 551 int config; 552 553 p (&ipi_lock); 554 cli (); 555 config = apic_read (APIC_ICR2) & 0xffffff; 556 apic_write (APIC_ICR2, config); 557 config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_ALL_BUT_SELF | num; 558 apic_write (APIC_ICR1, config); 559 sti (); 560 v (&ipi_lock); 561 } 562 563 volatile unsigned int ioapic_read (unsigned int offset) 564 { 565 *ioapic = offset; 566 return *(ioapic + 4); /* ioapic + 16 bytes */ 567 } 568 569 void ioapic_write (unsigned int offset, unsigned int data) 570 { 571 *ioapic = offset; 572 *(ioapic + 4) = data; /* ioapic + 16 bytes */ 573 } 574 575 void ioapic_init (void) 576 { 577 } 578 579 void apic_eoi (void) 580 { 581 apic_write (APIC_EOI, 0); 582 } 583