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 trampolineCode = 0x9f000; 400 trampolineStack = 0x9e000; 401 402 // copy the trampoline code over 403 memcpy((char *)trampolineCode, (const void*)&smp_trampoline, 404 (uint32)&smp_trampoline_end - (uint32)&smp_trampoline); 405 406 // boot the cpus 407 for (i = 1; i < gKernelArgs.num_cpus; i++) { 408 uint32 *finalStack; 409 uint32 *tempStack; 410 uint32 config; 411 uint32 numStartups; 412 uint32 j; 413 414 // set this stack up 415 finalStack = (uint32 *)gKernelArgs.cpu_kstack[i].start; 416 memset(finalStack, 0, KERNEL_STACK_SIZE); 417 tempStack = (finalStack + KERNEL_STACK_SIZE / sizeof(uint32)) - 1; 418 *tempStack = (uint32)&smp_cpu_ready; 419 420 // set the trampoline stack up 421 tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4); 422 // final location of the stack 423 *tempStack = ((uint32)finalStack) + KERNEL_STACK_SIZE - sizeof(uint32); 424 tempStack--; 425 // page dir 426 *tempStack = gKernelArgs.arch_args.phys_pgdir; 427 428 // put a gdt descriptor at the bottom of the stack 429 *((uint16 *)trampolineStack) = 0x18 - 1; // LIMIT 430 *((uint32 *)(trampolineStack + 2)) = trampolineStack + 8; 431 432 // put the gdt at the bottom 433 memcpy(&((uint32 *)trampolineStack)[2], (void *)gKernelArgs.arch_args.vir_gdt, 6*4); 434 435 /* clear apic errors */ 436 if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) { 437 apic_write(APIC_ERROR_STATUS, 0); 438 apic_read(APIC_ERROR_STATUS); 439 } 440 441 //dprintf("assert INIT\n"); 442 /* send (aka assert) INIT IPI */ 443 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) 444 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); 445 apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */ 446 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) 447 | APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT | APIC_DELIVERY_MODE_INIT; 448 apic_write(APIC_INTR_COMMAND_1, config); 449 450 dprintf("wait for delivery\n"); 451 // wait for pending to end 452 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) 453 ; 454 455 dprintf("deassert INIT\n"); 456 /* deassert INIT */ 457 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) 458 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); 459 apic_write(APIC_INTR_COMMAND_2, config); 460 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) 461 | APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT; 462 apic_write(APIC_INTR_COMMAND_1, config); 463 464 dprintf("wait for delivery\n"); 465 // wait for pending to end 466 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) 467 ; 468 469 /* wait 10ms */ 470 spin(10000); 471 472 /* is this a local apic or an 82489dx ? */ 473 numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0; 474 dprintf("num startups = %ld\n", numStartups); 475 for (j = 0; j < numStartups; j++) { 476 /* it's a local apic, so send STARTUP IPIs */ 477 dprintf("send STARTUP\n"); 478 apic_write(APIC_ERROR_STATUS, 0); 479 480 /* set target pe */ 481 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) 482 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); 483 apic_write(APIC_INTR_COMMAND_2, config); 484 485 /* send the IPI */ 486 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800) 487 | APIC_DELIVERY_MODE_STARTUP | (trampolineCode >> 12); 488 apic_write(APIC_INTR_COMMAND_1, config); 489 490 /* wait */ 491 spin(200); 492 493 dprintf("wait for delivery\n"); 494 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) 495 ; 496 } 497 } 498 499 TRACE(("done trampolining\n")); 500 } 501 502 503 void 504 smp_add_safemode_menus(Menu *menu) 505 { 506 MenuItem *item; 507 508 if (gKernelArgs.num_cpus < 2) 509 return; 510 511 // ToDo: this should work with dual CPUs with HT as well! 512 if (gKernelArgs.num_cpus > 2 || !supports_hyper_threading()) { 513 menu->AddItem(item = new MenuItem("Disable SMP")); 514 item->SetData(B_SAFEMODE_DISABLE_SMP); 515 item->SetType(MENU_ITEM_MARKABLE); 516 } 517 518 if (supports_hyper_threading()) { 519 menu->AddItem(item = new MenuItem("Disable Hyper-Threading")); 520 item->SetData(B_SAFEMODE_DISABLE_HYPER_THREADING); 521 item->SetType(MENU_ITEM_MARKABLE); 522 } 523 } 524 525 526 void 527 smp_init(void) 528 { 529 if (smp_find_mp_config() > 1) { 530 uint32 i; 531 532 TRACE(("smp_boot: had found > 1 cpus\n")); 533 TRACE(("post config:\n")); 534 TRACE(("num_cpus = %ld\n", gKernelArgs.num_cpus)); 535 TRACE(("apic_phys = %p\n", (void *)gKernelArgs.arch_args.apic_phys)); 536 TRACE(("ioapic_phys = %p\n", (void *)gKernelArgs.arch_args.ioapic_phys)); 537 538 // map in the apic & ioapic 539 gKernelArgs.arch_args.apic = (uint32 *)mmu_map_physical_memory( 540 gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags); 541 gKernelArgs.arch_args.ioapic = (uint32 *)mmu_map_physical_memory( 542 gKernelArgs.arch_args.ioapic_phys, B_PAGE_SIZE, kDefaultPageFlags); 543 544 TRACE(("apic = %p\n", gKernelArgs.arch_args.apic)); 545 TRACE(("ioapic = %p\n", gKernelArgs.arch_args.ioapic)); 546 547 // calculate how fast the apic timer is 548 calculate_apic_timer_conversion_factor(); 549 550 for (i = 1; i < gKernelArgs.num_cpus; i++) { 551 // create a final stack the trampoline code will put the ap processor on 552 gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL, KERNEL_STACK_SIZE); 553 gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE; 554 } 555 } 556 } 557 558 559