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