diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index ac40cca3b8..5b34644279 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -22,6 +22,7 @@ // MSR registers (possibly Intel specific) +#define IA32_MSR_TSC 0x10 #define IA32_MSR_APIC_BASE 0x1b #define IA32_MSR_MTRR_CAPABILITIES 0xfe diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 34d7b69b12..82a682b6cb 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -78,6 +78,7 @@ bool gHasSSE = false; static uint32 sCpuRendezvous; static uint32 sCpuRendezvous2; +static vint32 sTSCSyncRendezvous; segment_descriptor *gGDT = NULL; @@ -501,6 +502,28 @@ arch_cpu_preboot_init_percpu(kernel_args *args, int cpu) x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU)); gX86SwapFPUFunc = i386_fnsave_swap; + // On SMP system we want to synchronize the CPUs' TSCs, so system_time() + // will return consistent values. + if (smp_get_num_cpus() > 1) { + // let the first CPU prepare the rendezvous point + if (cpu == 0) + sTSCSyncRendezvous = smp_get_num_cpus() - 1; + + // One CPU after the other will drop out of this loop and be caught by + // the loop below, until the last CPU (0) gets there. Save for +/- a few + // cycles the CPUs should pass the second loop at the same time. + while (sTSCSyncRendezvous > cpu) { + } + + sTSCSyncRendezvous = cpu - 1; + + while (sTSCSyncRendezvous != -1) { + } + + // reset TSC to 0 + x86_write_msr(IA32_MSR_TSC, 0); + } + return B_OK; }