1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * This software may be distributed and modified according to the terms of 5 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 6 * See "LICENSE_GPLv2.txt" for details. 7 * 8 * @TAG(GD_GPL) 9 */ 10 11#include <model/statedata.h> 12#include <arch/machine/fpu.h> 13#include <arch/machine/cpu_registers.h> 14#include <arch/object/structures.h> 15#include <arch/machine/fpu.h> 16 17/* 18 * Setup the FPU register state for a new thread. 19 */ 20void 21Arch_initFpuContext(user_context_t *context) 22{ 23 context->fpuState = x86KSnullFpuState; 24} 25 26/* 27 * Initialise the FPU for this machine. 28 */ 29BOOT_CODE bool_t 30Arch_initFpu(void) 31{ 32 /* Enable FPU / SSE / SSE2 / SSE3 / SSSE3 / SSE4 Extensions. */ 33 write_cr4(read_cr4() | CR4_OSFXSR); 34 35 /* Enable the FPU in general. */ 36 write_cr0((read_cr0() & ~CR0_EMULATION) | CR0_MONITOR_COPROC | CR0_NUMERIC_ERROR); 37 enableFpu(); 38 39 /* Initialize the fpu state */ 40 finit(); 41 42 if (config_set(CONFIG_XSAVE)) { 43 uint64_t xsave_features; 44 uint32_t xsave_instruction; 45 uint64_t desired_features = config_ternary(CONFIG_XSAVE, CONFIG_XSAVE_FEATURE_SET, 1); 46 xsave_state_t *nullFpuState = (xsave_state_t *) &x86KSnullFpuState; 47 48 /* create NULL state for FPU to be used by XSAVE variants */ 49 memzero(&x86KSnullFpuState, sizeof(x86KSnullFpuState)); 50 51 /* check for XSAVE support */ 52 if (!(x86_cpuid_ecx(1, 0) & BIT(26))) { 53 printf("XSAVE not supported\n"); 54 return false; 55 } 56 /* enable XSAVE support */ 57 write_cr4(read_cr4() | CR4_OSXSAVE); 58 /* check feature mask */ 59 xsave_features = ((uint64_t)x86_cpuid_edx(0x0d, 0x0) << 32) | x86_cpuid_eax(0x0d, 0x0); 60 if ((xsave_features & desired_features) != desired_features) { 61 printf("Requested feature mask is 0x%llx, but only 0x%llx supported\n", desired_features, (long long)xsave_features); 62 return false; 63 } 64 /* enable feature mask */ 65 write_xcr0(desired_features); 66 /* validate the xsave buffer size and instruction */ 67 if (x86_cpuid_ebx(0x0d, 0x0) > CONFIG_XSAVE_SIZE) { 68 printf("XSAVE buffer set set to %d, but needs to be at least %d\n", CONFIG_XSAVE_SIZE, x86_cpuid_ebx(0x0d, 0x0)); 69 return false; 70 } 71 if (x86_cpuid_ebx(0x0d, 0x0) < CONFIG_XSAVE_SIZE) { 72 printf("XSAVE buffer set set to %d, but only needs to be %d.\n" 73 "Warning: Memory may be wasted with larger than needed TCBs.\n", 74 CONFIG_XSAVE_SIZE, x86_cpuid_ebx(0x0d, 0x0)); 75 } 76 /* check if a specialized XSAVE instruction was requested */ 77 xsave_instruction = x86_cpuid_eax(0x0d, 0x1); 78 if (config_set(CONFIG_XSAVE_XSAVEOPT)) { 79 if (!(xsave_instruction & BIT(0))) { 80 printf("XSAVEOPT requested, but not supported\n"); 81 return false; 82 } 83 } else if (config_set(CONFIG_XSAVE_XSAVEC)) { 84 if (!(xsave_instruction & BIT(1))) { 85 printf("XSAVEC requested, but not supported\n"); 86 return false; 87 } 88 } else if (config_set(CONFIG_XSAVE_XSAVES)) { 89 if (!(xsave_instruction & BIT(3))) { 90 printf("XSAVES requested, but not supported\n"); 91 return false; 92 } 93 94 /* AVX state from extended region should be in compacted format */ 95 nullFpuState->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT; 96 97 /* initialize the XSS MSR */ 98 x86_wrmsr(IA32_XSS_MSR, desired_features); 99 } 100 101 /* copy i387 FPU initial state from FPU */ 102 saveFpuState(&x86KSnullFpuState); 103 nullFpuState->i387.mxcsr = MXCSR_INIT_VALUE; 104 } else { 105 /* Store the null fpu state */ 106 saveFpuState(&x86KSnullFpuState); 107 } 108 /* Set the FPU to lazy switch mode */ 109 disableFpu(); 110 return true; 111} 112