1 /* 2 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include "smp.h" 11 #include "mmu.h" 12 13 #include <KernelExport.h> 14 15 #include <kernel.h> 16 #include <safemode.h> 17 #include <boot/stage2.h> 18 #include <boot/menu.h> 19 #include <arch/x86/smp_apic.h> 20 #include <arch/x86/arch_system_info.h> 21 22 #include <string.h> 23 24 #define NO_SMP 0 25 26 #define TRACE_SMP 27 #ifdef TRACE_SMP 28 # define TRACE(x) dprintf x 29 #else 30 # define TRACE(x) ; 31 #endif 32 33 struct gdt_idt_descr { 34 uint16 a; 35 uint32 *b; 36 } _PACKED; 37 38 struct smp_scan_spots_struct { 39 uint32 start; 40 uint32 stop; 41 uint32 length; 42 }; 43 44 static struct smp_scan_spots_struct smp_scan_spots[] = { 45 { 0x9fc00, 0xa0000, 0xa0000 - 0x9fc00 }, 46 { 0xf0000, 0x100000, 0x100000 - 0xf0000 }, 47 { 0, 0, 0 } 48 }; 49 50 51 extern "C" void execute_n_instructions(int count); 52 53 extern "C" void smp_trampoline(void); 54 extern "C" void smp_trampoline_end(void); 55 56 57 static struct mp_floating_struct *sFloatingStruct = NULL; 58 59 static int smp_get_current_cpu(void); 60 61 62 static uint32 63 apic_read(uint32 offset) 64 { 65 return *(uint32 *)((uint32)gKernelArgs.arch_args.apic + offset); 66 } 67 68 69 static void 70 apic_write(uint32 offset, uint32 data) 71 { 72 uint32 *addr = (uint32 *)((uint32)gKernelArgs.arch_args.apic + offset); 73 *addr = data; 74 } 75 76 77 static bool 78 supports_hyper_threading(void) 79 { 80 cpuid_info info; 81 if (get_current_cpuid(&info, 0) == B_OK 82 && !strncmp(info.eax_0.vendor_id, "GenuineIntel", 12) 83 && info.eax_0.max_eax > 0) { 84 if (get_current_cpuid(&info, 1) == B_OK) 85 return (info.eax_1.features & (1 << 28)) != 0; 86 } 87 88 return false; 89 } 90 91 92 static int 93 smp_get_current_cpu(void) 94 { 95 if (gKernelArgs.arch_args.apic == NULL) 96 return 0; 97 98 return gKernelArgs.arch_args.cpu_os_id[(apic_read(APIC_ID) & 0xffffffff) >> 24]; 99 } 100 101 102 static uint32 * 103 smp_probe(uint32 base, uint32 limit) 104 { 105 uint32 *ptr; 106 107 TRACE(("smp_probe: entry base 0x%lx, limit 0x%lx\n", base, limit)); 108 109 for (ptr = (uint32 *) base; (uint32)ptr < limit; ptr++) { 110 if (*ptr == MP_FLOATING_SIGNATURE) { 111 TRACE(("smp_probe: found floating pointer structure at %p\n", ptr)); 112 return ptr; 113 } 114 } 115 return NULL; 116 } 117 118 119 static void 120 smp_do_config(void) 121 { 122 struct mp_config_table *config; 123 char *ptr; 124 int i; 125 #ifdef TRACE_SMP 126 const char *cpu_family[] = { "", "", "", "", "Intel 486", 127 "Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" }; 128 #endif 129 130 /* 131 * we are not running in standard configuration, so we have to look through 132 * all of the mp configuration table crap to figure out how many processors 133 * we have, where our apics are, etc. 134 */ 135 gKernelArgs.num_cpus = 0; 136 137 config = sFloatingStruct->config_table; 138 139 /* print out our new found configuration. */ 140 141 ptr = (char *)&(config->oem[0]); 142 TRACE(("smp: oem id: %c%c%c%c%c%c%c%c product id: " 143 "%c%c%c%c%c%c%c%c%c%c%c%c\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], 144 ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], 145 ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19])); 146 TRACE(("smp: base table has %d entries, extended section %d bytes\n", 147 config->num_base_entries, config->ext_length)); 148 149 gKernelArgs.arch_args.apic_phys = (uint32)config->apic; 150 151 ptr = (char *)((uint32)config + sizeof(struct mp_config_table)); 152 for (i = 0; i < config->num_base_entries; i++) { 153 switch (*ptr) { 154 case MP_BASE_PROCESSOR: 155 { 156 struct mp_base_processor *processor = (struct mp_base_processor *)ptr; 157 158 gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus] = processor->apic_id; 159 gKernelArgs.arch_args.cpu_os_id[processor->apic_id] = gKernelArgs.num_cpus; 160 gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus] = processor->apic_version; 161 162 TRACE(("smp: cpu#%ld: %s, apic id %d, version %d%s\n", 163 gKernelArgs.num_cpus, cpu_family[(processor->signature & 0xf00) >> 8], 164 processor->apic_id, processor->apic_version, (processor->cpu_flags & 0x2) ? 165 ", BSP" : "")); 166 167 gKernelArgs.num_cpus++; 168 ptr += sizeof(struct mp_base_processor); 169 break; 170 } 171 case MP_BASE_BUS: 172 { 173 struct mp_base_bus *bus = (struct mp_base_bus *)ptr; 174 175 TRACE(("smp: bus %d: %c%c%c%c%c%c\n", bus->bus_id, 176 bus->name[0], bus->name[1], bus->name[2], bus->name[3], 177 bus->name[4], bus->name[5])); 178 179 ptr += sizeof(struct mp_base_bus); 180 break; 181 } 182 case MP_BASE_IO_APIC: 183 { 184 struct mp_base_ioapic *io = (struct mp_base_ioapic *) ptr; 185 gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr; 186 187 TRACE(("smp: found io apic with apic id %d, version %d\n", 188 io->ioapic_id, io->ioapic_version)); 189 190 ptr += sizeof(struct mp_base_ioapic); 191 break; 192 } 193 case MP_BASE_IO_INTR: 194 case MP_BASE_LOCAL_INTR: 195 { 196 struct mp_base_interrupt *interrupt = (struct mp_base_interrupt *)ptr; 197 198 dprintf("smp: %s int: type %d, source bus %d, irq %d, dest apic %d, int %d, polarity %d, trigger mode %d\n", 199 interrupt->type == MP_BASE_IO_INTR ? "I/O" : "local", 200 interrupt->interrupt_type, interrupt->source_bus_id, 201 interrupt->source_bus_irq, interrupt->dest_apic_id, 202 interrupt->dest_apic_int, interrupt->polarity, 203 interrupt->trigger_mode); 204 ptr += sizeof(struct mp_base_interrupt); 205 break; 206 } 207 } 208 } 209 210 dprintf("smp: apic @ %p, i/o apic @ %p, total %ld processors detected\n", 211 (void *)gKernelArgs.arch_args.apic_phys, 212 (void *)gKernelArgs.arch_args.ioapic_phys, 213 gKernelArgs.num_cpus); 214 215 // Try to detect single CPU hyper threading setup 216 // ToDo: this should be done using the ACPI APIC table 217 // ToDo: this only works with a single HT enabled CPU anyway 218 219 if (gKernelArgs.num_cpus == 1 && supports_hyper_threading()) { 220 cpuid_info info; 221 get_current_cpuid(&info, 1); 222 223 dprintf("CPU supports Hyper-Threading, %ld processors in package\n", 224 info.eax_1.logical_cpus); 225 226 // enable the second logical processor 227 /* 228 gKernelArgs.num_cpus = 2; 229 gKernelArgs.arch_args.cpu_apic_id[1] = gKernelArgs.arch_args.cpu_apic_id[0] + 1; 230 gKernelArgs.arch_args.cpu_os_id[gKernelArgs.arch_args.cpu_apic_id[1]] = 1; 231 gKernelArgs.arch_args.cpu_apic_version[1] = gKernelArgs.arch_args.cpu_apic_version[0];; 232 */ 233 } 234 235 // this BIOS looks broken, because it didn't report any cpus (VMWare) 236 if (gKernelArgs.num_cpus == 0) 237 gKernelArgs.num_cpus = 1; 238 } 239 240 241 static int 242 smp_find_mp_config(void) 243 { 244 int i; 245 246 #if NO_SMP 247 if (1) 248 return gKernelArgs.num_cpus = 1; 249 #endif 250 251 for (i = 0; smp_scan_spots[i].length > 0; i++) { 252 sFloatingStruct = (struct mp_floating_struct *)smp_probe(smp_scan_spots[i].start, 253 smp_scan_spots[i].stop); 254 if (sFloatingStruct != NULL) 255 break; 256 } 257 258 if (sFloatingStruct != NULL) { 259 TRACE(("smp_boot: intel mp version %s, %s", 260 (sFloatingStruct->spec_revision == 1) ? "1.1" : "1.4", 261 (sFloatingStruct->mp_feature_2 & 0x80) 262 ? "imcr and pic compatibility mode.\n" 263 : "virtual wire compatibility mode.\n")); 264 265 if (sFloatingStruct->config_table == NULL) { 266 // XXX need to implement 267 #if 1 268 gKernelArgs.num_cpus = 1; 269 return 1; 270 #else 271 /* this system conforms to one of the default configurations */ 272 // mp_num_def_config = sFloatingStruct->mp_feature_1; 273 TRACE(("smp: standard configuration %d\n", sFloatingStruct->mp_feature_1)); 274 /* num_cpus = 2; 275 gKernelArgs.cpu_apic_id[0] = 0; 276 gKernelArgs.cpu_apic_id[1] = 1; 277 apic_phys = (unsigned int *) 0xfee00000; 278 ioapic_phys = (unsigned int *) 0xfec00000; 279 kprintf ("smp: WARNING: standard configuration code is untested"); 280 */ 281 #endif 282 } else { 283 smp_do_config(); 284 } 285 return gKernelArgs.num_cpus; 286 } 287 288 return gKernelArgs.num_cpus = 1; 289 } 290 291 292 /** Target function of the trampoline code. 293 * The trampoline code should have the pgdir and a gdt set up for us, 294 * along with us being on the final stack for this processor. We need 295 * to set up the local APIC and load the global idt and gdt. When we're 296 * done, we'll jump into the kernel with the cpu number as an argument. 297 */ 298 299 static int 300 smp_cpu_ready(void) 301 { 302 uint32 curr_cpu = smp_get_current_cpu(); 303 struct gdt_idt_descr idt_descr; 304 struct gdt_idt_descr gdt_descr; 305 306 //TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu)); 307 308 // Important. Make sure supervisor threads can fault on read only pages... 309 asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1)); 310 asm("cld"); 311 asm("fninit"); 312 313 // Set up the final idt 314 idt_descr.a = IDT_LIMIT - 1; 315 idt_descr.b = (uint32 *)gKernelArgs.arch_args.vir_idt; 316 317 asm("lidt %0;" 318 : : "m" (idt_descr)); 319 320 // Set up the final gdt 321 gdt_descr.a = GDT_LIMIT - 1; 322 gdt_descr.b = (uint32 *)gKernelArgs.arch_args.vir_gdt; 323 324 asm("lgdt %0;" 325 : : "m" (gdt_descr)); 326 327 asm("pushl %0; " // push the cpu number 328 "pushl %1; " // kernel args 329 "pushl $0x0;" // dummy retval for call to main 330 "pushl %2; " // this is the start address 331 "ret; " // jump. 332 : : "g" (curr_cpu), "g" (&gKernelArgs), "g" (gKernelArgs.kernel_image.elf_header.e_entry)); 333 334 // no where to return to 335 return 0; 336 } 337 338 339 static void 340 calculate_apic_timer_conversion_factor(void) 341 { 342 int64 t1, t2; 343 uint32 config; 344 uint32 count; 345 346 // setup the timer 347 config = apic_read(APIC_LVT_TIMER); 348 config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED; // timer masked, vector 0 349 apic_write(APIC_LVT_TIMER, config); 350 351 config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f); 352 apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1); 353 // divide clock by one 354 355 t1 = system_time(); 356 apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter 357 358 execute_n_instructions(128*20000); 359 360 count = apic_read(APIC_CURRENT_TIMER_COUNT); 361 t2 = system_time(); 362 363 count = 0xffffffff - count; 364 365 gKernelArgs.arch_args.apic_time_cv_factor = (uint32)((1000000.0/(t2 - t1)) * count); 366 367 TRACE(("APIC ticks/sec = %ld\n", gKernelArgs.arch_args.apic_time_cv_factor)); 368 } 369 370 371 // #pragma mark - 372 373 374 void 375 smp_boot_other_cpus(void) 376 { 377 uint32 trampolineCode; 378 uint32 trampolineStack; 379 uint32 i; 380 381 void *handle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); 382 if (handle != NULL) { 383 if (get_driver_boolean_parameter(handle, B_SAFEMODE_DISABLE_SMP, false, false)) { 384 // SMP has been disabled! 385 gKernelArgs.num_cpus = 1; 386 } 387 unload_driver_settings(handle); 388 } 389 390 if (gKernelArgs.num_cpus < 2) 391 return; 392 393 TRACE(("trampolining other cpus\n")); 394 395 // The first 8 MB are identity mapped, 0x9e000-0x9ffff is reserved for this 396 397 // allocate a stack and a code area for the smp trampoline 398 // (these have to be < 1M physical, 0xa0000-0xfffff is reserved by the BIOS) 399 #ifdef _PXE_ENV 400 trampolineCode = 0x8b000; 401 trampolineStack = 0x8c000; 402 #else 403 trampolineCode = 0x9f000; 404 trampolineStack = 0x9e000; 405 #endif 406 407 // copy the trampoline code over 408 memcpy((char *)trampolineCode, (const void*)&smp_trampoline, 409 (uint32)&smp_trampoline_end - (uint32)&smp_trampoline); 410 411 // boot the cpus 412 for (i = 1; i < gKernelArgs.num_cpus; i++) { 413 uint32 *finalStack; 414 uint32 *tempStack; 415 uint32 config; 416 uint32 numStartups; 417 uint32 j; 418 419 // set this stack up 420 finalStack = (uint32 *)gKernelArgs.cpu_kstack[i].start; 421 memset(finalStack, 0, KERNEL_STACK_SIZE); 422 tempStack = (finalStack + KERNEL_STACK_SIZE / sizeof(uint32)) - 1; 423 *tempStack = (uint32)&smp_cpu_ready; 424 425 // set the trampoline stack up 426 tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4); 427 // final location of the stack 428 *tempStack = ((uint32)finalStack) + KERNEL_STACK_SIZE - sizeof(uint32); 429 tempStack--; 430 // page dir 431 *tempStack = gKernelArgs.arch_args.phys_pgdir; 432 433 // put a gdt descriptor at the bottom of the stack 434 *((uint16 *)trampolineStack) = 0x18 - 1; // LIMIT 435 *((uint32 *)(trampolineStack + 2)) = trampolineStack + 8; 436 437 // put the gdt at the bottom 438 memcpy(&((uint32 *)trampolineStack)[2], (void *)gKernelArgs.arch_args.vir_gdt, 6*4); 439 440 /* clear apic errors */ 441 if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) { 442 apic_write(APIC_ERROR_STATUS, 0); 443 apic_read(APIC_ERROR_STATUS); 444 } 445 446 //dprintf("assert INIT\n"); 447 /* send (aka assert) INIT IPI */ 448 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) 449 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); 450 apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */ 451 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) 452 | APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT | APIC_DELIVERY_MODE_INIT; 453 apic_write(APIC_INTR_COMMAND_1, config); 454 455 dprintf("wait for delivery\n"); 456 // wait for pending to end 457 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) 458 ; 459 460 dprintf("deassert INIT\n"); 461 /* deassert INIT */ 462 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) 463 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); 464 apic_write(APIC_INTR_COMMAND_2, config); 465 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) 466 | APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT; 467 apic_write(APIC_INTR_COMMAND_1, config); 468 469 dprintf("wait for delivery\n"); 470 // wait for pending to end 471 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) 472 ; 473 474 /* wait 10ms */ 475 spin(10000); 476 477 /* is this a local apic or an 82489dx ? */ 478 numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0; 479 dprintf("num startups = %ld\n", numStartups); 480 for (j = 0; j < numStartups; j++) { 481 /* it's a local apic, so send STARTUP IPIs */ 482 dprintf("send STARTUP\n"); 483 apic_write(APIC_ERROR_STATUS, 0); 484 485 /* set target pe */ 486 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) 487 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); 488 apic_write(APIC_INTR_COMMAND_2, config); 489 490 /* send the IPI */ 491 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800) 492 | APIC_DELIVERY_MODE_STARTUP | (trampolineCode >> 12); 493 apic_write(APIC_INTR_COMMAND_1, config); 494 495 /* wait */ 496 spin(200); 497 498 dprintf("wait for delivery\n"); 499 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) 500 ; 501 } 502 } 503 504 TRACE(("done trampolining\n")); 505 } 506 507 508 void 509 smp_add_safemode_menus(Menu *menu) 510 { 511 MenuItem *item; 512 513 if (gKernelArgs.num_cpus < 2) 514 return; 515 516 // ToDo: this should work with dual CPUs with HT as well! 517 if (gKernelArgs.num_cpus > 2 || !supports_hyper_threading()) { 518 menu->AddItem(item = new(nothrow) MenuItem("Disable SMP")); 519 item->SetData(B_SAFEMODE_DISABLE_SMP); 520 item->SetType(MENU_ITEM_MARKABLE); 521 } 522 523 if (supports_hyper_threading()) { 524 menu->AddItem(item = new(nothrow) MenuItem("Disable Hyper-Threading")); 525 item->SetData(B_SAFEMODE_DISABLE_HYPER_THREADING); 526 item->SetType(MENU_ITEM_MARKABLE); 527 } 528 } 529 530 531 void 532 smp_init(void) 533 { 534 if (smp_find_mp_config() > 1) { 535 uint32 i; 536 537 TRACE(("smp_boot: had found > 1 cpus\n")); 538 TRACE(("post config:\n")); 539 TRACE(("num_cpus = %ld\n", gKernelArgs.num_cpus)); 540 TRACE(("apic_phys = %p\n", (void *)gKernelArgs.arch_args.apic_phys)); 541 TRACE(("ioapic_phys = %p\n", (void *)gKernelArgs.arch_args.ioapic_phys)); 542 543 // map in the apic & ioapic 544 gKernelArgs.arch_args.apic = (uint32 *)mmu_map_physical_memory( 545 gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags); 546 gKernelArgs.arch_args.ioapic = (uint32 *)mmu_map_physical_memory( 547 gKernelArgs.arch_args.ioapic_phys, B_PAGE_SIZE, kDefaultPageFlags); 548 549 TRACE(("apic = %p\n", gKernelArgs.arch_args.apic)); 550 TRACE(("ioapic = %p\n", gKernelArgs.arch_args.ioapic)); 551 552 // calculate how fast the apic timer is 553 calculate_apic_timer_conversion_factor(); 554 555 for (i = 1; i < gKernelArgs.num_cpus; i++) { 556 // create a final stack the trampoline code will put the ap processor on 557 gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE); 558 gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE; 559 } 560 } 561 } 562 563 564