1 /*
2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
3 * Copyright 2004-2010, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 *
6 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
9
10
11 #include "smp.h"
12
13 #include <string.h>
14
15 #include <KernelExport.h>
16
17 #include <kernel.h>
18 #include <safemode.h>
19 #include <boot/stage2.h>
20 #include <boot/menu.h>
21 #include <arch/x86/apic.h>
22 #include <arch/x86/arch_cpu.h>
23 #include <arch/x86/arch_smp.h>
24 #include <arch/x86/arch_system_info.h>
25 #include <arch/x86/descriptors.h>
26
27 #include "mmu.h"
28 #include "acpi.h"
29
30
31 #define NO_SMP 0
32
33 //#define TRACE_SMP
34 #ifdef TRACE_SMP
35 # define TRACE(x) dprintf x
36 #else
37 # define TRACE(x) ;
38 #endif
39
40
41 static struct scan_spots_struct smp_scan_spots[] = {
42 { 0x9fc00, 0xa0000, 0xa0000 - 0x9fc00 },
43 { 0xf0000, 0x100000, 0x100000 - 0xf0000 },
44 { 0, 0, 0 }
45 };
46
47 extern "C" void execute_n_instructions(int count);
48
49 extern "C" void smp_trampoline(void);
50 extern "C" void smp_trampoline_end(void);
51
52
53 static uint32
apic_read(uint32 offset)54 apic_read(uint32 offset)
55 {
56 return *(volatile uint32 *)((addr_t)(void *)gKernelArgs.arch_args.apic + offset);
57 }
58
59
60 static void
apic_write(uint32 offset,uint32 data)61 apic_write(uint32 offset, uint32 data)
62 {
63 *(volatile uint32 *)((addr_t)(void *)gKernelArgs.arch_args.apic + offset) = data;
64 }
65
66
67 static mp_floating_struct *
smp_mp_probe(uint32 base,uint32 limit)68 smp_mp_probe(uint32 base, uint32 limit)
69 {
70 TRACE(("smp_mp_probe: entry base 0x%x, limit 0x%x\n", base, limit));
71 for (uint32 *pointer = (uint32 *)base; (uint32)pointer < limit; pointer++) {
72 if (*pointer == MP_FLOATING_SIGNATURE) {
73 TRACE(("smp_mp_probe: found floating pointer structure at %p\n",
74 pointer));
75 return (mp_floating_struct *)pointer;
76 }
77 }
78
79 return NULL;
80 }
81
82
83 static status_t
smp_do_mp_config(mp_floating_struct * floatingStruct)84 smp_do_mp_config(mp_floating_struct *floatingStruct)
85 {
86 if (floatingStruct->config_length != 1) {
87 dprintf("smp: unsupported structure length of %" B_PRIu8 " units\n",
88 floatingStruct->config_length);
89 return B_UNSUPPORTED;
90 }
91
92 dprintf("smp: intel mp version %s, %s",
93 (floatingStruct->spec_revision == 1) ? "1.1" : "1.4",
94 (floatingStruct->mp_feature_2 & 0x80)
95 ? "imcr and pic compatibility mode.\n"
96 : "virtual wire compatibility mode.\n");
97
98 if (floatingStruct->config_table == NULL) {
99 #if 1
100 // TODO: need to implement
101 dprintf("smp: standard configuration %d unimplemented\n",
102 floatingStruct->mp_feature_1);
103 gKernelArgs.num_cpus = 1;
104 return B_OK;
105 #else
106 // this system conforms to one of the default configurations
107 TRACE(("smp: standard configuration %d\n", floatingStruct->mp_feature_1));
108 gKernelArgs.num_cpus = 2;
109 gKernelArgs.cpu_apic_id[0] = 0;
110 gKernelArgs.cpu_apic_id[1] = 1;
111 apic_phys = (unsigned int *)0xfee00000;
112 ioapic_phys = (unsigned int *)0xfec00000;
113 dprintf("smp: WARNING: standard configuration code is untested");
114 return B_OK;
115 #endif
116 }
117
118 // We are not running in standard configuration, so we have to look through
119 // all of the mp configuration table crap to figure out how many processors
120 // we have, where our apics are, etc.
121
122 mp_config_table *config = floatingStruct->config_table;
123 gKernelArgs.num_cpus = 0;
124
125 if (config->signature != MP_CONFIG_TABLE_SIGNATURE) {
126 dprintf("smp: invalid config table signature, aborting\n");
127 return B_ERROR;
128 }
129
130 if (config->base_table_length < sizeof(mp_config_table)) {
131 dprintf("smp: config table length %" B_PRIu16
132 " too short for structure, aborting\n",
133 config->base_table_length);
134 return B_ERROR;
135 }
136
137 // print our new found configuration.
138 dprintf("smp: oem id: %.8s product id: %.12s\n", config->oem,
139 config->product);
140 dprintf("smp: base table has %d entries, extended section %d bytes\n",
141 config->num_base_entries, config->ext_length);
142
143 gKernelArgs.arch_args.apic_phys = (uint32)config->apic;
144 if ((gKernelArgs.arch_args.apic_phys % 4096) != 0) {
145 // MP specs mandate a 4K alignment for the local APIC(s)
146 dprintf("smp: local apic %p has bad alignment, aborting\n",
147 (void *)gKernelArgs.arch_args.apic_phys);
148 return B_ERROR;
149 }
150
151 char *pointer = (char *)((uint32)config + sizeof(struct mp_config_table));
152 for (int32 i = 0; i < config->num_base_entries; i++) {
153 switch (*pointer) {
154 case MP_BASE_PROCESSOR:
155 {
156 struct mp_base_processor *processor
157 = (struct mp_base_processor *)pointer;
158 pointer += sizeof(struct mp_base_processor);
159
160 if (gKernelArgs.num_cpus == SMP_MAX_CPUS) {
161 TRACE(("smp: already reached maximum CPUs (%d)\n",
162 SMP_MAX_CPUS));
163 continue;
164 }
165
166 // skip if the processor is not enabled.
167 if (!(processor->cpu_flags & 0x1)) {
168 TRACE(("smp: skip apic id %d: disabled\n",
169 processor->apic_id));
170 continue;
171 }
172
173 gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus]
174 = processor->apic_id;
175 gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus]
176 = processor->apic_version;
177
178 #ifdef TRACE_SMP
179 const char *cpuFamily[] = { "", "", "", "", "Intel 486",
180 "Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" };
181 #endif
182 TRACE(("smp: cpu#%d: %s, apic id %d, version %d%s\n",
183 gKernelArgs.num_cpus,
184 cpuFamily[(processor->signature & 0xf00) >> 8],
185 processor->apic_id, processor->apic_version,
186 (processor->cpu_flags & 0x2) ? ", BSP" : ""));
187
188 gKernelArgs.num_cpus++;
189 break;
190 }
191 case MP_BASE_BUS:
192 {
193 #ifdef TRACE_SMP
194 struct mp_base_bus *bus = (struct mp_base_bus *)pointer;
195 #endif
196 pointer += sizeof(struct mp_base_bus);
197
198 TRACE(("smp: bus %d: %c%c%c%c%c%c\n", bus->bus_id,
199 bus->name[0], bus->name[1], bus->name[2], bus->name[3],
200 bus->name[4], bus->name[5]));
201 break;
202 }
203 case MP_BASE_IO_APIC:
204 {
205 struct mp_base_ioapic *io = (struct mp_base_ioapic *)pointer;
206 pointer += sizeof(struct mp_base_ioapic);
207
208 if (gKernelArgs.arch_args.ioapic_phys == 0) {
209 gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr;
210 if (gKernelArgs.arch_args.ioapic_phys % 1024) {
211 // MP specs mandate a 1K alignment for the IO-APICs
212 TRACE(("smp: io apic %p has bad alignment, aborting\n",
213 (void *)gKernelArgs.arch_args.ioapic_phys));
214 return B_ERROR;
215 }
216 }
217
218 TRACE(("smp: found io apic with apic id %d, version %d\n",
219 io->ioapic_id, io->ioapic_version));
220
221 break;
222 }
223 case MP_BASE_IO_INTR:
224 case MP_BASE_LOCAL_INTR:
225 {
226 struct mp_base_interrupt *interrupt
227 = (struct mp_base_interrupt *)pointer;
228 pointer += sizeof(struct mp_base_interrupt);
229
230 dprintf("smp: %s int: type %d, source bus %d, irq %3d, dest "
231 "apic %d, int %3d, polarity %d, trigger mode %d\n",
232 interrupt->type == MP_BASE_IO_INTR ? "I/O" : "local",
233 interrupt->interrupt_type, interrupt->source_bus_id,
234 interrupt->source_bus_irq, interrupt->dest_apic_id,
235 interrupt->dest_apic_int, interrupt->polarity,
236 interrupt->trigger_mode);
237 break;
238 }
239 }
240 }
241
242 if (gKernelArgs.num_cpus == 0) {
243 dprintf("smp: didn't find any processors, aborting\n");
244 return B_ERROR;
245 }
246
247 dprintf("smp: apic @ %p, i/o apic @ %p, total %d processors detected\n",
248 (void *)gKernelArgs.arch_args.apic_phys,
249 (void *)gKernelArgs.arch_args.ioapic_phys,
250 gKernelArgs.num_cpus);
251
252 return B_OK;
253 }
254
255
256 static status_t
smp_do_acpi_config(void)257 smp_do_acpi_config(void)
258 {
259 dprintf("smp: using ACPI to detect MP configuration\n");
260
261 // reset CPU count
262 gKernelArgs.num_cpus = 0;
263
264 acpi_madt *madt = (acpi_madt *)acpi_find_table(ACPI_MADT_SIGNATURE);
265
266 if (madt == NULL) {
267 dprintf("smp: Failed to find MADT!\n");
268 return B_ERROR;
269 }
270
271 gKernelArgs.arch_args.apic_phys = madt->local_apic_address;
272 dprintf("smp: local apic address is 0x%x\n", madt->local_apic_address);
273
274 acpi_apic *apic = (acpi_apic *)((uint8 *)madt + sizeof(acpi_madt));
275 acpi_apic *end = (acpi_apic *)((uint8 *)madt + madt->header.length);
276 while (apic < end) {
277 switch (apic->type) {
278 case ACPI_MADT_LOCAL_APIC:
279 {
280 if (gKernelArgs.num_cpus == SMP_MAX_CPUS) {
281 TRACE(("smp: already reached maximum CPUs (%d)\n",
282 SMP_MAX_CPUS));
283 break;
284 }
285
286 acpi_local_apic *localApic = (acpi_local_apic *)apic;
287 dprintf("smp: found local APIC with id %u\n",
288 localApic->apic_id);
289 if ((localApic->flags & ACPI_LOCAL_APIC_ENABLED) == 0) {
290 dprintf("smp: APIC is disabled and will not be used\n");
291 break;
292 }
293
294 gKernelArgs.arch_args.cpu_apic_id[gKernelArgs.num_cpus]
295 = localApic->apic_id;
296 // TODO: how to find out? putting 0x10 in to indicate a local apic
297 gKernelArgs.arch_args.cpu_apic_version[gKernelArgs.num_cpus]
298 = 0x10;
299 gKernelArgs.num_cpus++;
300 break;
301 }
302
303 case ACPI_MADT_IO_APIC: {
304 acpi_io_apic *ioApic = (acpi_io_apic *)apic;
305 dprintf("smp: found io APIC with id %u and address 0x%x\n",
306 ioApic->io_apic_id, ioApic->io_apic_address);
307 if (gKernelArgs.arch_args.ioapic_phys == 0)
308 gKernelArgs.arch_args.ioapic_phys = ioApic->io_apic_address;
309 break;
310 }
311 default:
312 break;
313 }
314
315 apic = (acpi_apic *)((uint8 *)apic + apic->length);
316 }
317
318 return gKernelArgs.num_cpus > 0 ? B_OK : B_ERROR;
319 }
320
321
322 static void
calculate_apic_timer_conversion_factor(void)323 calculate_apic_timer_conversion_factor(void)
324 {
325 int64 t1, t2;
326 uint32 config;
327 uint32 count;
328
329 // setup the timer
330 config = apic_read(APIC_LVT_TIMER);
331 config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED;
332 // timer masked, vector 0
333 apic_write(APIC_LVT_TIMER, config);
334
335 config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f);
336 apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1);
337 // divide clock by one
338
339 t1 = system_time();
340 apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter
341
342 execute_n_instructions(128 * 20000);
343
344 count = apic_read(APIC_CURRENT_TIMER_COUNT);
345 t2 = system_time();
346
347 count = 0xffffffff - count;
348
349 gKernelArgs.arch_args.apic_time_cv_factor
350 = (uint32)((1000000.0/(t2 - t1)) * count);
351
352 dprintf("APIC ticks/sec = %d\n",
353 gKernelArgs.arch_args.apic_time_cv_factor);
354 }
355
356
357 // #pragma mark -
358
359
360 int
smp_get_current_cpu(void)361 smp_get_current_cpu(void)
362 {
363 if (gKernelArgs.arch_args.apic == NULL)
364 return 0;
365
366 uint8 apicID = apic_read(APIC_ID) >> 24;
367 for (uint32 i = 0; i < gKernelArgs.num_cpus; i++) {
368 if (gKernelArgs.arch_args.cpu_apic_id[i] == apicID)
369 return i;
370 }
371
372 return 0;
373 }
374
375
376 void
smp_init_other_cpus(void)377 smp_init_other_cpus(void)
378 {
379 if (get_safemode_boolean(B_SAFEMODE_DISABLE_SMP, false)) {
380 // SMP has been disabled!
381 dprintf("smp disabled per safemode setting\n");
382 gKernelArgs.num_cpus = 1;
383 }
384
385 if (get_safemode_boolean(B_SAFEMODE_DISABLE_APIC, false)) {
386 dprintf("local apic disabled per safemode setting, disabling smp\n");
387 gKernelArgs.arch_args.apic_phys = 0;
388 gKernelArgs.num_cpus = 1;
389 }
390
391 if (gKernelArgs.arch_args.apic_phys == 0)
392 return;
393
394 dprintf("smp: found %d cpu%s\n", gKernelArgs.num_cpus,
395 gKernelArgs.num_cpus != 1 ? "s" : "");
396 dprintf("smp: apic_phys = %p\n", (void *)gKernelArgs.arch_args.apic_phys);
397 dprintf("smp: ioapic_phys = %p\n",
398 (void *)gKernelArgs.arch_args.ioapic_phys);
399
400 // map in the apic
401 gKernelArgs.arch_args.apic = (void *)mmu_map_physical_memory(
402 gKernelArgs.arch_args.apic_phys, B_PAGE_SIZE, kDefaultPageFlags);
403
404 dprintf("smp: apic (mapped) = %p\n", (void *)gKernelArgs.arch_args.apic);
405
406 // calculate how fast the apic timer is
407 calculate_apic_timer_conversion_factor();
408
409 if (gKernelArgs.num_cpus < 2)
410 return;
411
412 for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
413 // create a final stack the trampoline code will put the ap processor on
414 gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL,
415 KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE);
416 gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE
417 + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
418 }
419 }
420
421
422 void
smp_boot_other_cpus(void (* entryFunc)(void))423 smp_boot_other_cpus(void (*entryFunc)(void))
424 {
425 if (gKernelArgs.num_cpus < 2)
426 return;
427
428 TRACE(("trampolining other cpus\n"));
429
430 // The first 8 MB are identity mapped, either 0x9e000-0x9ffff is reserved
431 // for this, or when PXE services are used 0x8b000-0x8cfff.
432
433 // allocate a stack and a code area for the smp trampoline
434 // (these have to be < 1M physical, 0xa0000-0xfffff is reserved by the BIOS,
435 // and when PXE services are used, the 0x8d000-0x9ffff is also reserved)
436 #ifdef _PXE_ENV
437 uint32 trampolineCode = 0x8b000;
438 uint32 trampolineStack = 0x8c000;
439 #else
440 uint32 trampolineCode = 0x9f000;
441 uint32 trampolineStack = 0x9e000;
442 #endif
443
444 // copy the trampoline code over
445 memcpy((char *)trampolineCode, (const void*)&smp_trampoline,
446 (uint32)&smp_trampoline_end - (uint32)&smp_trampoline);
447
448 // boot the cpus
449 for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
450 uint32 *finalStack;
451 uint32 *tempStack;
452 uint32 config;
453 uint32 numStartups;
454 uint32 j;
455
456 // set this stack up
457 finalStack = (uint32 *)gKernelArgs.cpu_kstack[i].start;
458 memset((uint8*)finalStack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0,
459 KERNEL_STACK_SIZE);
460 tempStack = (finalStack
461 + (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE)
462 / sizeof(uint32)) - 1;
463 *tempStack = (uint32)entryFunc;
464
465 // set the trampoline stack up
466 tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4);
467 // final location of the stack
468 *tempStack = ((uint32)finalStack) + KERNEL_STACK_SIZE
469 + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE - sizeof(uint32);
470 tempStack--;
471 // page dir
472 *tempStack = x86_read_cr3() & 0xfffff000;
473
474 // put a gdt descriptor at the bottom of the stack
475 *((uint16 *)trampolineStack) = 0x18 - 1; // LIMIT
476 *((uint32 *)(trampolineStack + 2)) = trampolineStack + 8;
477
478 // construct a temporary gdt at the bottom
479 segment_descriptor* tempGDT
480 = (segment_descriptor*)&((uint32 *)trampolineStack)[2];
481 clear_segment_descriptor(&tempGDT[0]);
482 set_segment_descriptor(&tempGDT[1], 0, 0xffffffff, DT_CODE_READABLE,
483 DPL_KERNEL);
484 set_segment_descriptor(&tempGDT[2], 0, 0xffffffff, DT_DATA_WRITEABLE,
485 DPL_KERNEL);
486
487 /* clear apic errors */
488 if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
489 apic_write(APIC_ERROR_STATUS, 0);
490 apic_read(APIC_ERROR_STATUS);
491 }
492
493 /* send (aka assert) INIT IPI */
494 TRACE(("assert INIT\n"));
495 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK)
496 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
497 apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */
498 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000)
499 | APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT
500 | APIC_DELIVERY_MODE_INIT;
501 apic_write(APIC_INTR_COMMAND_1, config);
502
503 // wait for pending to end
504 TRACE(("wait for delivery\n"));
505 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
506 asm volatile ("pause;");
507
508 /* deassert INIT */
509 TRACE(("deassert INIT\n"));
510 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK)
511 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
512 apic_write(APIC_INTR_COMMAND_2, config);
513 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000)
514 | APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT;
515 apic_write(APIC_INTR_COMMAND_1, config);
516
517 // wait for pending to end
518 TRACE(("wait for delivery\n"));
519 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
520 asm volatile ("pause;");
521
522 /* wait 10ms */
523 spin(10000);
524
525 /* is this a local apic or an 82489dx ? */
526 numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0)
527 ? 2 : 0;
528 TRACE(("num startups = %d\n", numStartups));
529
530 for (j = 0; j < numStartups; j++) {
531 /* it's a local apic, so send STARTUP IPIs */
532 TRACE(("send STARTUP\n"));
533 apic_write(APIC_ERROR_STATUS, 0);
534
535 /* set target pe */
536 config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK)
537 | (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
538 apic_write(APIC_INTR_COMMAND_2, config);
539
540 /* send the IPI */
541 config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800)
542 | APIC_DELIVERY_MODE_STARTUP | (trampolineCode >> 12);
543 apic_write(APIC_INTR_COMMAND_1, config);
544
545 /* wait */
546 spin(200);
547
548 TRACE(("wait for delivery\n"));
549 while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
550 asm volatile ("pause;");
551 }
552
553 // Wait for the trampoline code to clear the final stack location.
554 // This serves as a notification for us that it has loaded the address
555 // and it is safe for us to overwrite it to trampoline the next CPU.
556 tempStack++;
557 while (*tempStack != 0)
558 spin(1000);
559 }
560
561 TRACE(("done trampolining\n"));
562 }
563
564
565 void
smp_add_safemode_menus(Menu * menu)566 smp_add_safemode_menus(Menu *menu)
567 {
568 MenuItem *item;
569
570 if (gKernelArgs.arch_args.ioapic_phys != 0) {
571 menu->AddItem(item = new(nothrow) MenuItem("Disable IO-APIC"));
572 item->SetType(MENU_ITEM_MARKABLE);
573 item->SetData(B_SAFEMODE_DISABLE_IOAPIC);
574 item->SetHelpText("Disables using the IO APIC for interrupt routing, "
575 "forcing the use of the legacy PIC instead.");
576 }
577
578 if (gKernelArgs.arch_args.apic_phys != 0) {
579 menu->AddItem(item = new(nothrow) MenuItem("Disable local APIC"));
580 item->SetType(MENU_ITEM_MARKABLE);
581 item->SetData(B_SAFEMODE_DISABLE_APIC);
582 item->SetHelpText("Disables using the local APIC, also disables SMP.");
583
584 cpuid_info info;
585 if (get_current_cpuid(&info, 1, 0) == B_OK
586 && (info.regs.ecx & IA32_FEATURE_EXT_X2APIC) != 0) {
587 menu->AddItem(item = new(nothrow) MenuItem("Disable X2APIC"));
588 item->SetType(MENU_ITEM_MARKABLE);
589 item->SetData(B_SAFEMODE_DISABLE_X2APIC);
590 item->SetHelpText("Disables using X2APIC.");
591 }
592
593 get_current_cpuid(&info, 0, 0);
594 uint32 maxBasicLeaf = info.eax_0.max_eax;
595 if (maxBasicLeaf >= 7) {
596 if (get_current_cpuid(&info, 7, 0) == B_OK
597 && (info.regs.ebx & (IA32_FEATURE_SMEP
598 | IA32_FEATURE_SMAP)) != 0) {
599 menu->AddItem(item = new(nothrow) MenuItem(
600 "Disable SMEP and SMAP"));
601 item->SetType(MENU_ITEM_MARKABLE);
602 item->SetData(B_SAFEMODE_DISABLE_SMEP_SMAP);
603 item->SetHelpText("Disables using SMEP and SMAP.");
604 }
605
606 if (get_current_cpuid(&info, 7, 0) == B_OK
607 && (info.regs.ecx & IA32_FEATURE_LA57) != 0) {
608 menu->AddItem(item = new(nothrow) MenuItem(
609 "Ignore memory beyond 256 TiB"));
610 item->SetType(MENU_ITEM_MARKABLE);
611 item->SetData(B_SAFEMODE_256_TB_MEMORY_LIMIT);
612 item->SetHelpText("Ignores all memory beyond the 256 TiB "
613 "address limit, overriding the setting in the kernel "
614 "settings file.");
615 }
616 }
617 }
618
619 cpuid_info info;
620 if (get_current_cpuid(&info, 1, 0) == B_OK
621 && (info.regs.edx & IA32_FEATURE_PAT) != 0) {
622 menu->AddItem(item = new(nothrow) MenuItem("Disable PAT"));
623 item->SetType(MENU_ITEM_MARKABLE);
624 item->SetData(B_SAFEMODE_DISABLE_PAT);
625 item->SetHelpText("Disables using page attribute tables for memory "
626 "type setting, falling back to MTRRs.");
627 }
628
629 if (gKernelArgs.num_cpus < 2)
630 return;
631
632 item = new(nothrow) MenuItem("Disable SMP");
633 menu->AddItem(item);
634 item->SetData(B_SAFEMODE_DISABLE_SMP);
635 item->SetType(MENU_ITEM_MARKABLE);
636 item->SetHelpText("Disables all but one CPU core.");
637 }
638
639
640 void
smp_init(void)641 smp_init(void)
642 {
643 #if NO_SMP
644 gKernelArgs.num_cpus = 1;
645 return;
646 #endif
647
648 cpuid_info info;
649 if (get_current_cpuid(&info, 1, 0) != B_OK)
650 return;
651
652 if ((info.eax_1.features & IA32_FEATURE_APIC) == 0) {
653 // Local APICs aren't present; As they form the basis for all inter CPU
654 // communication and therefore SMP, we don't need to go any further.
655 dprintf("no local APIC present, not attempting SMP init\n");
656 return;
657 }
658
659 // first try to find ACPI tables to get MP configuration as it handles
660 // physical as well as logical MP configurations as in multiple cpus,
661 // multiple cores or hyper threading.
662 if (smp_do_acpi_config() == B_OK)
663 return;
664
665 // then try to find MPS tables and do configuration based on them
666 for (int32 i = 0; smp_scan_spots[i].length > 0; i++) {
667 mp_floating_struct *floatingStruct = smp_mp_probe(
668 smp_scan_spots[i].start, smp_scan_spots[i].stop);
669 if (floatingStruct != NULL && smp_do_mp_config(floatingStruct) == B_OK)
670 return;
671 }
672
673 // Everything failed or we are not running an SMP system, reset anything
674 // that might have been set through an incomplete configuration attempt.
675 gKernelArgs.arch_args.apic_phys = 0;
676 gKernelArgs.arch_args.ioapic_phys = 0;
677 gKernelArgs.num_cpus = 1;
678 }
679