From 8fcd6b8e61e367a9f832f7e9fe60f8d7c6868313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 26 Oct 2005 22:57:13 +0000 Subject: [PATCH] * renamed smp_boot.c to smp.cpp * there is now a "Disable Hyper-Threading" safemode in the boot loader * the SMP & HT menu items are now added in smp.cpp - and are only added if the system supports one of them. * more cleanup to smp_apic.h * removed cpuid() from the boot loader's support.S - instead, it will now use the one from the kernel. * added a very weak HT detection: if the MP config only listed one CPU, and this CPU supports HT, we enable the other logic processor manually - as this currently doesn't work, it's disabled, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14536 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/arch/x86/smp_apic.h | 139 ++++++++-------- headers/private/kernel/safemode.h | 3 +- src/system/Jamfile | 1 + src/system/boot/platform/bios_ia32/Jamfile | 2 +- src/system/boot/platform/bios_ia32/menu.cpp | 10 +- .../bios_ia32/{smp_boot.c => smp.cpp} | 151 +++++++++++++----- src/system/boot/platform/bios_ia32/smp.h | 4 + src/system/boot/platform/bios_ia32/support.S | 24 --- src/system/kernel/arch/x86/arch_smp.c | 88 +++++----- src/system/kernel/smp.c | 2 +- 10 files changed, 251 insertions(+), 173 deletions(-) rename src/system/boot/platform/bios_ia32/{smp_boot.c => smp.cpp} (75%) diff --git a/headers/private/kernel/arch/x86/smp_apic.h b/headers/private/kernel/arch/x86/smp_apic.h index a66d41a744..08eaaadba5 100644 --- a/headers/private/kernel/arch/x86/smp_apic.h +++ b/headers/private/kernel/arch/x86/smp_apic.h @@ -8,70 +8,83 @@ #ifndef _KERNEL_ARCH_x86_SMP_APIC_H #define _KERNEL_ARCH_x86_SMP_APIC_H -#define MP_FLT_SIGNATURE '_PM_' -#define MP_CTH_SIGNATURE 'PCMP' +#define MP_FLOATING_SIGNATURE '_PM_' +#define MP_CONFIG_TABLE_SIGNATURE 'PCMP' #define APIC_ENABLE 0x100 #define APIC_FOCUS (~(1 << 9)) #define APIC_SIV (0xff) // offsets to APIC register -#define APIC_ID 0x020 -#define APIC_VERSION 0x030 -#define APIC_TPRI 0x080 -#define APIC_EOI 0x0b0 -#define APIC_LDR 0x0d0 -#define APIC_SIVR 0x0f0 -#define APIC_ESR 0x280 -#define APIC_ICR1 0x300 -#define APIC_ICR2 0x310 -#define APIC_LVTT 0x320 -#define APIC_LINT0 0x350 -#define APIC_LINT1 0x360 -#define APIC_LVT3 0x370 -#define APIC_ICRT 0x380 -#define APIC_CCRT 0x390 -#define APIC_TDCR 0x3e0 +#define APIC_ID 0x020 +#define APIC_VERSION 0x030 +#define APIC_TASK_PRIORITY 0x080 +#define APIC_ARBITRATION_PRIORITY 0x090 +#define APIC_PROCESSOR_PRIORITY 0x0a0 +#define APIC_EOI 0x0b0 +#define APIC_LOGICAL_DEST 0x0d0 +#define APIC_DEST_FORMAT 0x0e0 +#define APIC_SPURIOUS_INTR_VECTOR 0x0f0 +#define APIC_ERROR_STATUS 0x280 +#define APIC_INTR_COMMAND_1 0x300 // bits 0-31 +#define APIC_INTR_COMMAND_2 0x310 // bits 32-63 +#define APIC_LVT_TIMER 0x320 +#define APIC_LVT_THERMAL_SENSOR 0x330 +#define APIC_LVT_PERFMON_COUNTERS 0x340 +#define APIC_LVT_LINT0 0x350 +#define APIC_LVT_LINT1 0x360 +#define APIC_LVT_ERROR 0x370 +#define APIC_INITIAL_TIMER_COUNT 0x380 +#define APIC_CURRENT_TIMER_COUNT 0x390 +#define APIC_TIMER_DIVIDE_CONFIG 0x3e0 -/* ICR defines */ -#define APIC_ICR1_WRITE_MASK 0xfff3f000 -#define APIC_ICR1_READ_MASK 0xfff32000 -#define APIC_ICR2_MASK 0x00ffffff +/* standard APIC interrupt defines */ +#define APIC_DELIVERY_MODE_FIXED 0 +#define APIC_DELIVERY_MODE_LOWESTPRI (1 << 8) // ICR1 only +#define APIC_DELIVERY_MODE_SMI (2 << 8) +#define APIC_DELIVERY_MODE_NMI (4 << 8) +#define APIC_DELIVERY_MODE_INIT (5 << 8) +#define APIC_DELIVERY_MODE_STARTUP (6 << 8) // ICR1 only +#define APIC_DELIVERY_MODE_ExtINT (7 << 8) // LINT0/1 only -#define APIC_ICR1_DELIVERY_MODE_FIXED 0 -#define APIC_ICR1_DELIVERY_MODE_LOWESTPRI (1 << 8) -#define APIC_ICR1_DELIVERY_MODE_INIT (5 << 8) -#define APIC_ICR1_DELIVERY_MODE_STARTUP (6 << 8) +#define APIC_DELIVERY_STATUS (1 << 12) +#define APIC_TRIGGER_MODE_LEVEL (1 << 15) -#define APIC_ICR1_DEST_MODE_PHYSICAL 0 -#define APIC_ICR1_DEST_MODE_LOGICAL (1 << 11) +/* Interrupt Command defines */ +#define APIC_INTR_COMMAND_1_MASK 0xfff3f000 +#define APIC_INTR_COMMAND_2_MASK 0x00ffffff -#define APIC_ICR1_ASSERT (1 << 13) -#define APIC_ICR1_TRIGGER_MODE_LEVEL (1 << 14) -#define APIC_ICR1_DELIVERY_STATUS (1 << 12) +#define APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL 0 +#define APIC_INTR_COMMAND_1_DEST_MODE_LOGICAL (1 << 11) -#define APIC_ICR1_DEST_FIELD 0 -#define APIC_ICR1_DEST_SELF (1 << 18) -#define APIC_ICR1_DEST_ALL (2 << 18) -#define APIC_ICR1_DEST_ALL_BUT_SELF (3 << 18) +#define APIC_INTR_COMMAND_1_ASSERT (1 << 14) -/* other defines */ +#define APIC_INTR_COMMAND_1_DEST_FIELD 0 +#define APIC_INTR_COMMAND_1_DEST_SELF (1 << 18) +#define APIC_INTR_COMMAND_1_DEST_ALL (2 << 18) +#define APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF (3 << 18) -#define APIC_TDCR_2 0x00 -#define APIC_TDCR_4 0x01 -#define APIC_TDCR_8 0x02 -#define APIC_TDCR_16 0x03 -#define APIC_TDCR_32 0x08 -#define APIC_TDCR_64 0x09 -#define APIC_TDCR_128 0x0a -#define APIC_TDCR_1 0x0b +/* Local Vector Table defines */ +#define APIC_LVT_MASKED (1 << 16) -#define APIC_LVTT_MASK 0x000310ff -#define APIC_LVTT_VECTOR 0x000000ff -#define APIC_LVTT_DS 0x00001000 -#define APIC_LVTT_M 0x00010000 -#define APIC_LVTT_TM 0x00020000 +// timer defines +#define APIC_LVT_TIMER_MASK 0xfffcef00 +// LINT0/1 defines +#define APIC_LVT_LINT_MASK 0xfffe0800 +#define APIC_LVT_LINT_INPUT_POLARITY (1 << 13) + +// Timer Divide Config Divisors +#define APIC_TIMER_DIVIDE_CONFIG_1 0x0b +#define APIC_TIMER_DIVIDE_CONFIG_2 0x00 +#define APIC_TIMER_DIVIDE_CONFIG_4 0x01 +#define APIC_TIMER_DIVIDE_CONFIG_8 0x02 +#define APIC_TIMER_DIVIDE_CONFIG_16 0x03 +#define APIC_TIMER_DIVIDE_CONFIG_32 0x08 +#define APIC_TIMER_DIVIDE_CONFIG_64 0x09 +#define APIC_TIMER_DIVIDE_CONFIG_128 0x0a + +/* #define APIC_LVT_DM 0x00000700 #define APIC_LVT_DM_ExtINT 0x00000700 #define APIC_LVT_DM_NMI 0x00000400 @@ -87,10 +100,6 @@ #define APIC_SVR_SWEN 0x00000100 #define APIC_SVR_FOCUS 0x00000200 -#define APIC_DEST_STARTUP 0x00600 - -#define LOPRIO_LEVEL 0x00000010 - #define IOAPIC_ID 0x0 #define IOAPIC_VERSION 0x1 #define IOAPIC_ARB 0x2 @@ -101,12 +110,7 @@ #define IPI_INV_PTE 0x42 #define IPI_INV_RESCHED 0x43 #define IPI_STOP 0x44 - -#define MP_EXT_PE 0 -#define MP_EXT_BUS 1 -#define MP_EXT_IO_APIC 2 -#define MP_EXT_IO_INT 3 -#define MP_EXT_LOCAL_INT 4 +*/ struct mp_config_table { uint32 signature; /* "PCMP" */ @@ -134,6 +138,15 @@ struct mp_floating_struct { uint8 mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */ }; +/* base config entry types */ +enum { + MP_BASE_PROCESSOR = 0, + MP_BASE_BUS, + MP_BASE_IO_APIC, + MP_BASE_IO_INTR, + MP_BASE_LOCAL_INTR, +}; + struct mp_base_processor { uint8 type; uint8 apic_id; @@ -171,10 +184,10 @@ struct mp_base_interrupt { }; enum { - MP_INT_TYPE_INT = 0, - MP_INT_TYPE_NMI, - MP_INT_TYPE_SMI, - MP_INT_TYPE_ExtINT, + MP_INTR_TYPE_INT = 0, + MP_INTR_TYPE_NMI, + MP_INTR_TYPE_SMI, + MP_INTR_TYPE_ExtINT, }; #endif /* _KERNEL_ARCH_x86_SMP_APIC_H */ diff --git a/headers/private/kernel/safemode.h b/headers/private/kernel/safemode.h index b087d8a204..e0091e4bfa 100644 --- a/headers/private/kernel/safemode.h +++ b/headers/private/kernel/safemode.h @@ -14,7 +14,8 @@ #define B_SAFEMODE_DISABLE_USER_ADD_ONS "disableuseraddons" #define B_SAFEMODE_DISABLE_IDE_DMA "disableidedma" -#define B_SAFEMODE_DISABLE_SMP "disablesmp" +#define B_SAFEMODE_DISABLE_SMP "disable_smp" +#define B_SAFEMODE_DISABLE_HYPER_THREADING "disable_hyperthreading" #ifdef __cplusplus diff --git a/src/system/Jamfile b/src/system/Jamfile index b21ea1a615..3743904085 100644 --- a/src/system/Jamfile +++ b/src/system/Jamfile @@ -34,6 +34,7 @@ KernelLd boot_loader : <$(SOURCE_GRIST)!libroot!posix!string>strrchr.o <$(SOURCE_GRIST)!libroot!posix!stdlib>strtol.o <$(SOURCE_GRIST)!libroot>qsort.o + <$(SOURCE_GRIST)!kernel!arch!$(OBOS_ARCH)>cpuid.o : $(SUBDIR)/ldscripts/$(OBOS_ARCH)/boot_loader.ld : -Bstatic ; diff --git a/src/system/boot/platform/bios_ia32/Jamfile b/src/system/boot/platform/bios_ia32/Jamfile index 471c0348b0..078c4ce875 100644 --- a/src/system/boot/platform/bios_ia32/Jamfile +++ b/src/system/boot/platform/bios_ia32/Jamfile @@ -20,7 +20,7 @@ KernelMergeObject boot_platform_bios_ia32.o : menu.cpp mmu.cpp cpu.cpp - smp_boot.c + smp.cpp smp_trampoline.S support.S video.cpp diff --git a/src/system/boot/platform/bios_ia32/menu.cpp b/src/system/boot/platform/bios_ia32/menu.cpp index 9c5bcc0c55..c280328d3e 100644 --- a/src/system/boot/platform/bios_ia32/menu.cpp +++ b/src/system/boot/platform/bios_ia32/menu.cpp @@ -4,9 +4,10 @@ */ -#include "keyboard.h" -#include "console.h" #include "bios.h" +#include "console.h" +#include "keyboard.h" +#include "smp.h" #include "video.h" #include @@ -464,9 +465,8 @@ platform_add_menus(Menu *menu) item->SetTarget(video_mode_hook); break; case SAFE_MODE_MENU: - menu->AddItem(item = new MenuItem("Disable SMP")); - item->SetData(B_SAFEMODE_DISABLE_SMP); - item->SetType(MENU_ITEM_MARKABLE); + smp_add_safemode_menus(menu); + menu->AddItem(item = new MenuItem("Don't call the BIOS")); item->SetType(MENU_ITEM_MARKABLE); break; diff --git a/src/system/boot/platform/bios_ia32/smp_boot.c b/src/system/boot/platform/bios_ia32/smp.cpp similarity index 75% rename from src/system/boot/platform/bios_ia32/smp_boot.c rename to src/system/boot/platform/bios_ia32/smp.cpp index a0219ce04e..7aa217ee75 100644 --- a/src/system/boot/platform/bios_ia32/smp_boot.c +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -12,10 +12,12 @@ #include -#include -#include -#include #include +#include +#include +#include +#include +#include #include @@ -46,10 +48,10 @@ static struct smp_scan_spots_struct smp_scan_spots[] = { }; -extern void execute_n_instructions(int count); +extern "C" void execute_n_instructions(int count); -extern void smp_trampoline(void); -extern void smp_trampoline_end(void); +extern "C" void smp_trampoline(void); +extern "C" void smp_trampoline_end(void); static struct mp_floating_struct *sFloatingStruct = NULL; @@ -72,6 +74,21 @@ apic_write(uint32 offset, uint32 data) } +static bool +supports_hyper_threading(void) +{ + cpuid_info info; + if (get_current_cpuid(&info, 0) == B_OK + && !strncmp(info.eax_0.vendor_id, "GenuineIntel", 12) + && info.eax_0.max_eax > 0) { + if (get_current_cpuid(&info, 1) == B_OK) + return (info.eax_1.features & (1 << 28)) != 0; + } + + return false; +} + + static int smp_get_current_cpu(void) { @@ -90,7 +107,7 @@ smp_probe(uint32 base, uint32 limit) TRACE(("smp_probe: entry base 0x%lx, limit 0x%lx\n", base, limit)); for (ptr = (uint32 *) base; (uint32)ptr < limit; ptr++) { - if (*ptr == MP_FLT_SIGNATURE) { + if (*ptr == MP_FLOATING_SIGNATURE) { TRACE(("smp_probe: found floating pointer structure at %p\n", ptr)); return ptr; } @@ -134,7 +151,7 @@ smp_do_config(void) ptr = (char *)((uint32)config + sizeof(struct mp_config_table)); for (i = 0; i < config->num_base_entries; i++) { switch (*ptr) { - case MP_EXT_PE: + case MP_BASE_PROCESSOR: { struct mp_base_processor *processor = (struct mp_base_processor *)ptr; @@ -151,7 +168,7 @@ smp_do_config(void) ptr += sizeof(struct mp_base_processor); break; } - case MP_EXT_BUS: + case MP_BASE_BUS: { struct mp_base_bus *bus = (struct mp_base_bus *)ptr; @@ -162,7 +179,7 @@ smp_do_config(void) ptr += sizeof(struct mp_base_bus); break; } - case MP_EXT_IO_APIC: + case MP_BASE_IO_APIC: { struct mp_base_ioapic *io = (struct mp_base_ioapic *) ptr; gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr; @@ -173,13 +190,13 @@ smp_do_config(void) ptr += sizeof(struct mp_base_ioapic); break; } - case MP_EXT_IO_INT: - case MP_EXT_LOCAL_INT: + case MP_BASE_IO_INTR: + case MP_BASE_LOCAL_INTR: { struct mp_base_interrupt *interrupt = (struct mp_base_interrupt *)ptr; dprintf("smp: %s int: type %d, source bus %d, irq %d, dest apic %d, int %d, polarity %d, trigger mode %d\n", - interrupt->type == MP_EXT_IO_INT ? "I/O" : "local", + interrupt->type == MP_BASE_IO_INTR ? "I/O" : "local", interrupt->interrupt_type, interrupt->source_bus_id, interrupt->source_bus_irq, interrupt->dest_apic_id, interrupt->dest_apic_int, interrupt->polarity, @@ -195,6 +212,26 @@ smp_do_config(void) (void *)gKernelArgs.arch_args.ioapic_phys, gKernelArgs.num_cpus); + // Try to detect single CPU hyper threading setup + // ToDo: this should be done using the ACPI APIC table + // ToDo: this only works with a single HT enabled CPU anyway + + if (gKernelArgs.num_cpus == 1 && supports_hyper_threading()) { + cpuid_info info; + get_current_cpuid(&info, 1); + + dprintf("CPU supports Hyper-Threading, %ld processors in package\n", + info.eax_1.logical_cpus); + + // enable the second logical processor +/* + gKernelArgs.num_cpus = 2; + gKernelArgs.arch_args.cpu_apic_id[1] = gKernelArgs.arch_args.cpu_apic_id[0] + 1; + gKernelArgs.arch_args.cpu_os_id[gKernelArgs.arch_args.cpu_apic_id[1]] = 1; + gKernelArgs.arch_args.cpu_apic_version[1] = gKernelArgs.arch_args.cpu_apic_version[0];; +*/ + } + // this BIOS looks broken, because it didn't report any cpus (VMWare) if (gKernelArgs.num_cpus == 0) gKernelArgs.num_cpus = 1; @@ -211,7 +248,6 @@ smp_find_mp_config(void) return gKernelArgs.num_cpus = 1; #endif - // XXX for now, assume the memory is identity mapped by the 1st stage for (i = 0; smp_scan_spots[i].length > 0; i++) { sFloatingStruct = (struct mp_floating_struct *)smp_probe(smp_scan_spots[i].start, smp_scan_spots[i].stop); @@ -308,19 +344,20 @@ calculate_apic_timer_conversion_factor(void) uint32 count; // setup the timer - config = apic_read(APIC_LVTT); - config = (config & ~APIC_LVTT_MASK) + APIC_LVTT_M; // timer masked, vector 0 - apic_write(APIC_LVTT, config); + config = apic_read(APIC_LVT_TIMER); + config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED; // timer masked, vector 0 + apic_write(APIC_LVT_TIMER, config); - config = (apic_read(APIC_TDCR) & ~0x0000000f) + 0xb; // divide clock by one - apic_write(APIC_TDCR, config); + config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f); + apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1); + // divide clock by one t1 = system_time(); - apic_write(APIC_ICRT, 0xffffffff); // start the counter + apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter execute_n_instructions(128*20000); - count = apic_read(APIC_CCRT); + count = apic_read(APIC_CURRENT_TIMER_COUNT); t2 = system_time(); count = 0xffffffff - count; @@ -397,32 +434,36 @@ smp_boot_other_cpus(void) /* clear apic errors */ if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) { - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); + apic_write(APIC_ERROR_STATUS, 0); + apic_read(APIC_ERROR_STATUS); } +//dprintf("assert INIT\n"); /* send (aka assert) INIT IPI */ - config = (apic_read(APIC_ICR2) & APIC_ICR2_MASK) + config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); - apic_write(APIC_ICR2, config); /* set target pe */ - config = (apic_read(APIC_ICR1) & 0xfff00000) | APIC_ICR1_TRIGGER_MODE_LEVEL - | APIC_ICR1_ASSERT | APIC_ICR1_DELIVERY_MODE_INIT; - apic_write(APIC_ICR1, config); + apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */ + config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) + | APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT | APIC_DELIVERY_MODE_INIT; + apic_write(APIC_INTR_COMMAND_1, config); +dprintf("wait for delivery\n"); // wait for pending to end - while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0) + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) ; +dprintf("deassert INIT\n"); /* deassert INIT */ - config = (apic_read(APIC_ICR2) & APIC_ICR2_MASK) + config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); - apic_write(APIC_ICR2, config); - config = (apic_read(APIC_ICR1) & 0xfff00000) | APIC_ICR1_TRIGGER_MODE_LEVEL - | APIC_ICR1_DELIVERY_MODE_INIT; - apic_write(APIC_ICR1, config); + apic_write(APIC_INTR_COMMAND_2, config); + config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000) + | APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT; + apic_write(APIC_INTR_COMMAND_1, config); +dprintf("wait for delivery\n"); // wait for pending to end - while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0) + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) ; /* wait 10ms */ @@ -430,24 +471,27 @@ smp_boot_other_cpus(void) /* is this a local apic or an 82489dx ? */ numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0; +dprintf("num startups = %ld\n", numStartups); for (j = 0; j < numStartups; j++) { /* it's a local apic, so send STARTUP IPIs */ - apic_write(APIC_ESR, 0); +dprintf("send STARTUP\n"); + apic_write(APIC_ERROR_STATUS, 0); /* set target pe */ - config = (apic_read(APIC_ICR2) & APIC_ICR2_MASK) + config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK) | (gKernelArgs.arch_args.cpu_apic_id[i] << 24); - apic_write(APIC_ICR2, config); + apic_write(APIC_INTR_COMMAND_2, config); /* send the IPI */ - config = (apic_read(APIC_ICR1) & 0xfff0f800) | APIC_ICR1_DELIVERY_MODE_STARTUP - | (trampolineCode >> 12); - apic_write(APIC_ICR1, config); + config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800) + | APIC_DELIVERY_MODE_STARTUP | (trampolineCode >> 12); + apic_write(APIC_INTR_COMMAND_1, config); /* wait */ spin(200); - while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0) +dprintf("wait for delivery\n"); + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) ; } } @@ -456,6 +500,29 @@ smp_boot_other_cpus(void) } +void +smp_add_safemode_menus(Menu *menu) +{ + MenuItem *item; + + if (gKernelArgs.num_cpus < 2) + return; + + // ToDo: this should work with dual CPUs with HT as well! + if (gKernelArgs.num_cpus > 2 || !supports_hyper_threading()) { + menu->AddItem(item = new MenuItem("Disable SMP")); + item->SetData(B_SAFEMODE_DISABLE_SMP); + item->SetType(MENU_ITEM_MARKABLE); + } + + if (supports_hyper_threading()) { + menu->AddItem(item = new MenuItem("Disable Hyper-Threading")); + item->SetData(B_SAFEMODE_DISABLE_HYPER_THREADING); + item->SetType(MENU_ITEM_MARKABLE); + } +} + + void smp_init(void) { diff --git a/src/system/boot/platform/bios_ia32/smp.h b/src/system/boot/platform/bios_ia32/smp.h index 09e9d9dac5..6603e7be79 100644 --- a/src/system/boot/platform/bios_ia32/smp.h +++ b/src/system/boot/platform/bios_ia32/smp.h @@ -10,6 +10,10 @@ #ifdef __cplusplus +// this is only available in C++ +# include +extern void smp_add_safemode_menus(Menu *menu); + extern "C" { #endif diff --git a/src/system/boot/platform/bios_ia32/support.S b/src/system/boot/platform/bios_ia32/support.S index 08fb412d6f..525faf588d 100644 --- a/src/system/boot/platform/bios_ia32/support.S +++ b/src/system/boot/platform/bios_ia32/support.S @@ -54,30 +54,6 @@ FUNCTION(system_time): popl %ebx ret -FUNCTION(cpuid): - pushl %ebx - pushl %edi - movl 12(%esp),%eax - movl 16(%esp),%edi - cpuid - movl %eax,0(%edi) - movl %ebx,4(%edi) - movl %ecx,8(%edi) - movl %edx,12(%edi) - popl %edi - popl %ebx - ret - -FUNCTION(get_eflags): - pushfl - popl %eax - ret - -FUNCTION(set_eflags): - pushl 4(%esp) - popfl - ret - null_idt_descr: .word 0 .word 0,0 diff --git a/src/system/kernel/arch/x86/arch_smp.c b/src/system/kernel/arch/x86/arch_smp.c index afc982424b..68b52fab55 100644 --- a/src/system/kernel/arch/x86/arch_smp.c +++ b/src/system/kernel/arch/x86/arch_smp.c @@ -103,12 +103,12 @@ setup_apic(kernel_args *args, int32 cpu) { uint32 config; - TRACE(("setting up the apic...")); + TRACE(("setting up the APIC for CPU %ld...\n", cpu)); /* set spurious interrupt vector to 0xff */ - config = apic_read(APIC_SIVR) & 0xffffff00; + config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00; config |= APIC_ENABLE | 0xff; - apic_write(APIC_SIVR, config); + apic_write(APIC_SPURIOUS_INTR_VECTOR, config); // don't touch the LINT0/1 configuration in virtual wire mode // ToDo: implement support for other modes... @@ -124,32 +124,45 @@ setup_apic(kernel_args *args, int32 cpu) config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; apic_write(APIC_LINT1, config); } + if (cpu > 0) { + dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0)); + dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1)); + + /* disable LINT0/1 */ + config = apic_read(APIC_LINT0); + apic_write(APIC_LINT0, config | APIC_LVT_MASKED); + + config = apic_read(APIC_LINT1); + apic_write(APIC_LINT1, config | APIC_LVT_MASKED); + } else { + dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0)); + dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1)); + } #endif /* setup timer */ - config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK; - config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked - apic_write(APIC_LVTT, config); + config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK; + config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked + apic_write(APIC_LVT_TIMER, config); - apic_write(APIC_ICRT, 0); // zero out the clock + apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock - config = apic_read(APIC_TDCR) & ~0x0000000f; - config |= APIC_TDCR_1; // clock division by 1 - apic_write(APIC_TDCR, config); + config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0; + config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 + apic_write(APIC_TIMER_DIVIDE_CONFIG, config); /* setup error vector to 0xfe */ - config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe; - apic_write(APIC_LVT3, config); + config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe; + apic_write(APIC_LVT_ERROR, config); /* accept all interrupts */ - config = apic_read(APIC_TPRI) & 0xffffff00; - apic_write(APIC_TPRI, config); + config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00; + apic_write(APIC_TASK_PRIORITY, config); - config = apic_read(APIC_SIVR); + config = apic_read(APIC_SPURIOUS_INTR_VECTOR); apic_write(APIC_EOI, 0); - TRACE((" done\n")); - return 0; + return B_OK; } @@ -203,9 +216,11 @@ arch_smp_send_broadcast_ici(void) uint32 config; cpu_status state = disable_interrupts(); - config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK; - apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELIVERY_MODE_FIXED - | APIC_ICR1_DEST_MODE_PHYSICAL | APIC_ICR1_DEST_ALL_BUT_SELF); + config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK; + apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED + | APIC_INTR_COMMAND_1_ASSERT + | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL + | APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF); restore_interrupts(state); } @@ -217,15 +232,17 @@ arch_smp_send_ici(int32 target_cpu) uint32 config; int state = disable_interrupts(); - config = apic_read(APIC_ICR2) & APIC_ICR2_MASK; - apic_write(APIC_ICR2, config | cpu_apic_id[target_cpu] << 24); + config = apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK; + apic_write(APIC_INTR_COMMAND_2, config | cpu_apic_id[target_cpu] << 24); - config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK; - apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELIVERY_MODE_FIXED - | APIC_ICR1_DEST_MODE_PHYSICAL | APIC_ICR1_DEST_FIELD); + config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK; + apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED + | APIC_INTR_COMMAND_1_ASSERT + | APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL + | APIC_INTR_COMMAND_1_DEST_FIELD); // wait for message to be sent - while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0) + while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0) ; restore_interrupts(state); @@ -258,18 +275,18 @@ arch_smp_set_apic_timer(bigtime_t relativeTimeout) state = disable_interrupts(); - config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer - apic_write(APIC_LVTT, config); + config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer + apic_write(APIC_LVT_TIMER, config); - apic_write(APIC_ICRT, 0); // zero out the timer + apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer - config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer - apic_write(APIC_LVTT, config); + config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer + apic_write(APIC_LVT_TIMER, config); TRACE(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n", config, relativeTimeout, apic_timer_tics_per_sec, ticks)); - apic_write(APIC_ICRT, ticks); // start it up + apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up restore_interrupts(state); @@ -288,13 +305,12 @@ arch_smp_clear_apic_timer(void) state = disable_interrupts(); - config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer - apic_write(APIC_LVTT, config); + config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer + apic_write(APIC_LVT_TIMER, config); - apic_write(APIC_ICRT, 0); // zero out the timer + apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer restore_interrupts(state); - return 0; } diff --git a/src/system/kernel/smp.c b/src/system/kernel/smp.c index 86f77bbf80..62f963f4fb 100644 --- a/src/system/kernel/smp.c +++ b/src/system/kernel/smp.c @@ -355,7 +355,7 @@ process_pending_ici(int32 currentCPU) if (msg == NULL) return retval; - TRACE((" message = %d\n", msg->message)); + TRACE((" cpu %d message = %d\n", curr_cpu, msg->message)); switch (msg->message) { case SMP_MSG_INVL_PAGE_RANGE: