diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index c88ea9bcb4..df9f69307c 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -334,6 +334,7 @@ void i386_fnsave(void* fpuState); void i386_fxsave(void* fpuState); void i386_frstor(const void* fpuState); void i386_fxrstor(const void* fpuState); +void i386_noop_swap(void* oldFpuState, const void* newFpuState); void i386_fnsave_swap(void* oldFpuState, const void* newFpuState); void i386_fxsave_swap(void* oldFpuState, const void* newFpuState); uint32 x86_read_ebp(); diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 035c3520ff..e508513b24 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -300,14 +300,25 @@ x86_set_mtrrs(uint8 defaultType, const x86_mtrr_info* infos, uint32 count) extern "C" void -init_sse(void) +init_fpu(void) { - if (!x86_check_feature(IA32_FEATURE_SSE, FEATURE_COMMON) - || !x86_check_feature(IA32_FEATURE_FXSR, FEATURE_COMMON)) { - // we don't have proper SSE support + if (!x86_check_feature(IA32_FEATURE_FPU, FEATURE_COMMON)) { + // No FPU... time to install one in your 386? + dprintf("Warning: CPU has no reported FPU.\n"); + gX86SwapFPUFunc = i386_noop_swap; return; } + if (!x86_check_feature(IA32_FEATURE_SSE, FEATURE_COMMON) + || !x86_check_feature(IA32_FEATURE_FXSR, FEATURE_COMMON)) { + dprintf("CPU has no SSE... just enabling FPU.\n"); + // we don't have proper SSE support, just enable FPU + x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU)); + gX86SwapFPUFunc = i386_fnsave_swap; + return; + } + dprintf("CPU has SSE... enabling FXSR and XMM.\n"); + // enable OS support for SSE x86_write_cr4(x86_read_cr4() | CR4_OS_FXSR | CR4_OS_XMM_EXCEPTION); x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU)); @@ -658,8 +669,8 @@ x86_double_fault_get_cpu(void) status_t 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; + // A simple nop FPU call until init_fpu + gX86SwapFPUFunc = i386_noop_swap; // On SMP system we want to synchronize the CPUs' TSCs, so system_time() // will return consistent values. @@ -791,8 +802,8 @@ arch_cpu_init_post_vm(kernel_args *args) DT_DATA_WRITEABLE, DPL_USER); } - // setup SSE2/3 support - init_sse(); + // setup FPU and SSE if supported + init_fpu(); return B_OK; } diff --git a/src/system/kernel/arch/x86/arch_smp.cpp b/src/system/kernel/arch/x86/arch_smp.cpp index dd67bea52c..4f4e53a168 100644 --- a/src/system/kernel/arch/x86/arch_smp.cpp +++ b/src/system/kernel/arch/x86/arch_smp.cpp @@ -36,7 +36,7 @@ static uint32 sCPUAPICIds[B_MAX_CPU_COUNT]; static uint32 sAPICVersions[B_MAX_CPU_COUNT]; -extern "C" void init_sse(void); +extern "C" void init_fpu(void); static int32 @@ -107,7 +107,8 @@ arch_smp_per_cpu_init(kernel_args *args, int32 cpu) TRACE(("arch_smp_init_percpu: setting up the apic on cpu %ld\n", cpu)); apic_per_cpu_init(args, cpu); - init_sse(); + // setup FPU and SSE if supported + init_fpu(); return B_OK; } diff --git a/src/system/kernel/arch/x86/arch_x86.S b/src/system/kernel/arch/x86/arch_x86.S index a0c60ff2af..28611fe247 100644 --- a/src/system/kernel/arch/x86/arch_x86.S +++ b/src/system/kernel/arch/x86/arch_x86.S @@ -55,6 +55,12 @@ FUNCTION(i386_fxrstor): ret FUNCTION_END(i386_fxrstor) +/* void i386_noop_swap(void *old_fpu_state, const void *new_fpu_state); */ +FUNCTION(i386_noop_swap): + nop + ret +FUNCTION_END(i386_noop_swap) + /* void i386_fsave_swap(void *old_fpu_state, const void *new_fpu_state); */ FUNCTION(i386_fnsave_swap): movl 4(%esp),%eax