kernel: Fix FPU SSE + MMX instruction usage.

* Rename init_sse to init_fpu and handle FPU setup.
* Stop trying to set up FPU before VM init.
  We tried to set up the FPU before VM init, then
  set it up again after VM init with SSE extensions,
  this caused SSE and MMX applications to crash.
* Be more logical in FPU setup by detecting CPU flag prior
  to enabling FPU. (it's unlikely Haiku will run on
  a processor without a fpu... but lets be consistant)
* SSE2 gcc code now runs (faster even) without GPF
* tqh confirms his previously crashing mmx code now works
* The non-SSE FPU enable after VM init needs tested!
This commit is contained in:
Alexander von Gluck IV
2012-01-20 15:06:01 -06:00
parent 67f45bfdf2
commit 8dd1e875c1
4 changed files with 29 additions and 10 deletions
@@ -334,6 +334,7 @@ void i386_fnsave(void* fpuState);
void i386_fxsave(void* fpuState); void i386_fxsave(void* fpuState);
void i386_frstor(const void* fpuState); void i386_frstor(const void* fpuState);
void i386_fxrstor(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_fnsave_swap(void* oldFpuState, const void* newFpuState);
void i386_fxsave_swap(void* oldFpuState, const void* newFpuState); void i386_fxsave_swap(void* oldFpuState, const void* newFpuState);
uint32 x86_read_ebp(); uint32 x86_read_ebp();
+19 -8
View File
@@ -300,14 +300,25 @@ x86_set_mtrrs(uint8 defaultType, const x86_mtrr_info* infos, uint32 count)
extern "C" void extern "C" void
init_sse(void) init_fpu(void)
{ {
if (!x86_check_feature(IA32_FEATURE_SSE, FEATURE_COMMON) if (!x86_check_feature(IA32_FEATURE_FPU, FEATURE_COMMON)) {
|| !x86_check_feature(IA32_FEATURE_FXSR, FEATURE_COMMON)) { // No FPU... time to install one in your 386?
// we don't have proper SSE support dprintf("Warning: CPU has no reported FPU.\n");
gX86SwapFPUFunc = i386_noop_swap;
return; 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 // enable OS support for SSE
x86_write_cr4(x86_read_cr4() | CR4_OS_FXSR | CR4_OS_XMM_EXCEPTION); 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)); x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU));
@@ -658,8 +669,8 @@ x86_double_fault_get_cpu(void)
status_t status_t
arch_cpu_preboot_init_percpu(kernel_args *args, int cpu) arch_cpu_preboot_init_percpu(kernel_args *args, int cpu)
{ {
x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU)); // A simple nop FPU call until init_fpu
gX86SwapFPUFunc = i386_fnsave_swap; gX86SwapFPUFunc = i386_noop_swap;
// On SMP system we want to synchronize the CPUs' TSCs, so system_time() // On SMP system we want to synchronize the CPUs' TSCs, so system_time()
// will return consistent values. // will return consistent values.
@@ -791,8 +802,8 @@ arch_cpu_init_post_vm(kernel_args *args)
DT_DATA_WRITEABLE, DPL_USER); DT_DATA_WRITEABLE, DPL_USER);
} }
// setup SSE2/3 support // setup FPU and SSE if supported
init_sse(); init_fpu();
return B_OK; return B_OK;
} }
+3 -2
View File
@@ -36,7 +36,7 @@
static uint32 sCPUAPICIds[B_MAX_CPU_COUNT]; static uint32 sCPUAPICIds[B_MAX_CPU_COUNT];
static uint32 sAPICVersions[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 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)); TRACE(("arch_smp_init_percpu: setting up the apic on cpu %ld\n", cpu));
apic_per_cpu_init(args, cpu); apic_per_cpu_init(args, cpu);
init_sse(); // setup FPU and SSE if supported
init_fpu();
return B_OK; return B_OK;
} }
+6
View File
@@ -55,6 +55,12 @@ FUNCTION(i386_fxrstor):
ret ret
FUNCTION_END(i386_fxrstor) 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); */ /* void i386_fsave_swap(void *old_fpu_state, const void *new_fpu_state); */
FUNCTION(i386_fnsave_swap): FUNCTION(i386_fnsave_swap):
movl 4(%esp),%eax movl 4(%esp),%eax