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