From cdd16a2b9ffd9640c38da58846678927d81b2d11 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sat, 28 May 2011 23:35:46 +0200 Subject: [PATCH] add the SSE support => context switch stores also the SSE registers --- arch/x86/include/asm/processor.h | 41 ++++++++++++++++++++++++++++++ arch/x86/include/asm/tasks_types.h | 6 ++++- arch/x86/kernel/isrs.c | 35 ++++++++++++++++++++----- arch/x86/kernel/processor.c | 23 +++++++++++++++++ kernel/tests.c | 1 + 5 files changed, 99 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index a1f6246a..cbab6148 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -39,6 +39,45 @@ extern "C" { #endif +// feature list 1 +#define CPU_FEATURE_FPU (1 << 0) +#define CPU_FEATURE_MMX (1 << 23) +#define CPU_FEATURE_FXSR (1 << 24) +#define CPU_FEATURE_SSE (1 << 25) +#define CPU_FEATURE_SSE2 (1 << 26) + +// feature list 2 +#define CPU_FEATURE_AVX (1 << 28) + +typedef struct { + uint32_t feature1, feature2; +} cpu_info_t; + +extern cpu_info_t cpu_info; + +// determine the cpu features +int cpu_detection(void); + +inline static uint32_t has_fpu(void) +{ + return (cpu_info.feature1 & CPU_FEATURE_FPU); +} + +inline static uint32_t has_fxsr(void) +{ + return (cpu_info.feature1 & CPU_FEATURE_FXSR); +} + +inline static uint32_t has_xmm(void) +{ + return (cpu_info.feature1 & CPU_FEATURE_SSE); +} + +inline static uint32_t has_avx(void) +{ + return (cpu_info.feature2 & CPU_FEATURE_AVX); +} + /** @brief Read out time stamp counter * * The rdtsc asm command puts a 64 bit time stamp value @@ -250,6 +289,8 @@ inline static int system_init(void) #ifdef CONFIG_PCI pci_init(); #endif + cpu_detection(); + return 0; } diff --git a/arch/x86/include/asm/tasks_types.h b/arch/x86/include/asm/tasks_types.h index 138fbd1c..ffaee4fd 100644 --- a/arch/x86/include/asm/tasks_types.h +++ b/arch/x86/include/asm/tasks_types.h @@ -22,6 +22,7 @@ #define __ARCH_TASKS_TYPES__ #include +#include #ifdef __cplusplus extern "C" { @@ -61,7 +62,10 @@ union fpu_state { }; static inline void save_fpu_state(union fpu_state* state) { - asm volatile ("fsave %0; fwait" : "=m"((*state).fsave)); + if (has_fxsr()) + asm volatile ("fxsave %0; fnclex" : "=m"((*state).fxsave)); + else + asm volatile ("fsave %0; fwait" : "=m"((*state).fsave)); } #ifdef __cplusplus diff --git a/arch/x86/kernel/isrs.c b/arch/x86/kernel/isrs.c index cfb45389..4c461894 100644 --- a/arch/x86/kernel/isrs.c +++ b/arch/x86/kernel/isrs.c @@ -165,6 +165,26 @@ void isrs_install(void) irq_install_handler(7, fpu_handler); } +static void fpu_init(union fpu_state* fpu) +{ + if (has_fxsr()) { + i387_fxsave_t* fx = &fpu->fxsave; + + memset(fx, 0, sizeof(union fpu_state)); + fx->cwd = 0x37f; + if (has_xmm) + fx->mxcsr = 0x1f80; + } else { + i387_fsave_t *fp = &fpu->fsave; + memset(fp, 0, sizeof(union fpu_state)); + fp->cwd = 0xffff037fu; + fp->swd = 0xffff0000u; + fp->twd = 0xffffffffu; + fp->fos = 0xffff0000u; + } + +} + static void fpu_handler(struct state *s) { task_t* task = per_core(current_task); @@ -172,13 +192,16 @@ static void fpu_handler(struct state *s) asm volatile ("clts"); // clear the TS flag of cr0 if (!(task->flags & TASK_FPU_INIT)) { // use the FPU at the first time => Initialize FPU - asm volatile ("finit"); - task->flags = task->flags|TASK_FPU_INIT|TASK_FPU_USED; - } else { - // restore the FPU context - asm volatile ("frstor %0" :: "m"(task->fpu.fsave)); // restore fpu state - task->flags |= TASK_FPU_USED; + fpu_init(&task->fpu); + task->flags |= TASK_FPU_INIT; } + + // restore the FPU context + if (has_fxsr()) + asm volatile ("fxrstor %0" :: "m"(task->fpu.fxsave)); + else + asm volatile ("frstor %0" :: "m"(task->fpu.fsave)); + task->flags |= TASK_FPU_USED; } /** @brief Exception messages diff --git a/arch/x86/kernel/processor.c b/arch/x86/kernel/processor.c index aa4988f4..4210c38f 100644 --- a/arch/x86/kernel/processor.c +++ b/arch/x86/kernel/processor.c @@ -25,8 +25,31 @@ #include #endif +cpu_info_t cpu_info = { 0, 0 }; static uint32_t cpu_freq = 0; +int cpu_detection(void) +{ + uint32_t a, b, cr4; + + cpuid(1, &a, &b, &cpu_info.feature2, &cpu_info.feature1); + + cr4 = read_cr4(); + if (has_fxsr()) + cr4 |= 0x200; // set the OSFXSR bit + if (has_xmm()) + cr4 |= 0x400; // set the OSXMMEXCPT bit + write_cr4(cr4); + + if (has_avx()) + kprintf("The CPU owns the Advanced Vector Extensions (AVX). However, MetalSVM doesn't support AVX!\n"); + + if (has_fpu()) + asm volatile ("fninit"); + + return 0; +} + uint32_t detect_cpu_frequency(void) { #ifdef CONFIG_ROCKCREEK diff --git a/kernel/tests.c b/kernel/tests.c index 5c26d41d..e8d8a828 100644 --- a/kernel/tests.c +++ b/kernel/tests.c @@ -133,6 +133,7 @@ int test_init(void) //create_user_task(NULL, "/bin/hello", argv); create_user_task(NULL, "/bin/tests", argv); //create_user_task(NULL, "/bin/jacobi", argv); + //create_user_task(NULL, "/bin/jacobi", argv); return 0; }