diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 67ebe5ee6f..ff5523bc80 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -33,6 +33,9 @@ #define IA32_MSR_MTRR_PHYSICAL_BASE_0 0x200 #define IA32_MSR_MTRR_PHYSICAL_MASK_0 0x201 +// K8 MSR registers +#define K8_MSR_IPM 0xc0010055 + // x86 features from cpuid eax 1, edx register // reference http://www.intel.com/assets/pdf/appnote/241618.pdf (Table 5-5) #define IA32_FEATURE_FPU (1 << 0) // x87 fpu diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index c199afc81d..81daaf850f 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -64,6 +64,11 @@ static const struct cpu_vendor_info vendor_info[VENDOR_NUM] = { #define CR4_OS_FXSR (1UL << 9) #define CR4_OS_XMM_EXCEPTION (1UL << 10) +#define K8_SMIONCMPHALT (1ULL << 27) +#define K8_C1EONCMPHALT (1ULL << 28) + +#define K8_CMPHALT (K8_SMIONCMPHALT | K8_C1EONCMPHALT) + struct set_mtrr_parameter { int32 index; uint64 base; @@ -82,6 +87,7 @@ extern "C" void reboot(void); // from arch_x86.S void (*gX86SwapFPUFunc)(void *oldState, const void *newState); +void (*gCpuIdleFunc)(void); bool gHasSSE = false; static uint32 sCpuRendezvous; @@ -699,6 +705,40 @@ arch_cpu_preboot_init_percpu(kernel_args *args, int cpu) } +static void +halt_idle(void) +{ + asm("hlt"); +} + + +static void +amdc1e_noarat_idle(void) +{ + uint64 msr = x86_read_msr(K8_MSR_IPM); + if (msr & K8_CMPHALT) + x86_write_msr(K8_MSR_IPM, msr & ~K8_CMPHALT); + halt_idle(); +} + + +static bool +detect_amdc1e_noarat() +{ + cpu_ent *cpu = get_cpu_struct(); + + if (cpu->arch.vendor != VENDOR_AMD) + return false; + + // Family 0x12 and higher processors support ARAT + // Family lower than 0xf processors doesn't support C1E + // Family 0xf with model <= 0x40 procssors doesn't support C1E + uint32 family = cpu->arch.family + cpu->arch.extended_family; + uint32 model = (cpu->arch.extended_model << 4) | cpu->arch.model; + return (family < 0x12 && family > 0xf) || (family == 0xf && model > 0x40); +} + + status_t arch_cpu_init_percpu(kernel_args *args, int cpu) { @@ -721,9 +761,16 @@ arch_cpu_init_percpu(kernel_args *args, int cpu) asm volatile("lidt %0" : : "m"(descriptor)); } + if (!gCpuIdleFunc) { + if (detect_amdc1e_noarat()) + gCpuIdleFunc = amdc1e_noarat_idle; + else + gCpuIdleFunc = halt_idle; + } return 0; } + status_t arch_cpu_init(kernel_args *args) { @@ -882,6 +929,7 @@ i386_set_tss_and_kstack(addr_t kstack) get_cpu_struct()->arch.tss.sp0 = kstack; } + void arch_cpu_global_TLB_invalidate(void) { @@ -1008,7 +1056,7 @@ arch_cpu_shutdown(bool rebootSystem) void arch_cpu_idle(void) { - asm("hlt"); + gCpuIdleFunc(); }