1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#pragma once 8 9#include <config.h> 10#include <types.h> 11#include <arch/object/vcpu.h> 12#include <object/structures.h> 13#include <model/statedata.h> 14#include <arch/machine/cpu_registers.h> 15 16#define MXCSR_INIT_VALUE 0x1f80 17#define XCOMP_BV_COMPACTED_FORMAT (1ull << 63) 18 19/* The state format, as saved by FXSAVE and restored by FXRSTOR instructions. */ 20typedef struct i387_state { 21 uint16_t cwd; /* control word */ 22 uint16_t swd; /* status word */ 23 uint16_t twd; /* tag word */ 24 uint16_t fop; /* last instruction opcode */ 25 uint32_t reserved[4]; /* instruction and data pointers */ 26 uint32_t mxcsr; /* MXCSR register state */ 27 uint32_t mxcsr_mask; /* MXCSR mask */ 28 uint32_t st_space[32]; /* FPU registers */ 29 uint32_t xmm_space[64]; /* XMM registers */ 30 uint32_t padding[13]; 31} PACKED i387_state_t; 32 33/* The state format, as saved by XSAVE and restored by XRSTOR instructions. */ 34typedef struct xsave_state { 35 i387_state_t i387; 36 struct { 37 uint64_t xfeatures; 38 uint64_t xcomp_bv; /* state-component bitmap */ 39 uint64_t reserved[6]; 40 } header; 41} PACKED xsave_state_t; 42 43/* Initialise the FPU. */ 44bool_t Arch_initFpu(void); 45 46/* Initialise the FPU state of the given user context. */ 47void Arch_initFpuContext(user_context_t *context); 48 49static inline uint32_t xsave_features_high(void) 50{ 51 uint64_t features = config_ternary(CONFIG_XSAVE, CONFIG_XSAVE_FEATURE_SET, 1); 52 return (uint32_t)(features >> 32); 53} 54 55static inline uint32_t xsave_features_low(void) 56{ 57 uint64_t features = config_ternary(CONFIG_XSAVE, CONFIG_XSAVE_FEATURE_SET, 1); 58 return (uint32_t)(features & 0xffffffff); 59} 60 61/* Store state in the FPU registers into memory. */ 62static inline void saveFpuState(user_fpu_state_t *dest) 63{ 64 if (config_set(CONFIG_FXSAVE)) { 65 asm volatile("fxsave %[dest]" : [dest] "=m"(*dest)); 66 } else if (config_set(CONFIG_XSAVE_XSAVEOPT)) { 67 asm volatile("xsaveopt %[dest]" : [dest] "=m"(*dest) : "d"(xsave_features_high()), "a"(xsave_features_low())); 68 } else if (config_set(CONFIG_XSAVE_XSAVE)) { 69 asm volatile("xsave %[dest]" : [dest] "=m"(*dest) : "d"(xsave_features_high()), "a"(xsave_features_low())); 70 } else if (config_set(CONFIG_XSAVE_XSAVEC)) { 71 asm volatile("xsavec %[dest]" : [dest] "=m"(*dest) : "d"(xsave_features_high()), "a"(xsave_features_low())); 72 } else if (config_set(CONFIG_XSAVE_XSAVES)) { 73 asm volatile("xsaves %[dest]" : [dest] "=m"(*dest) : "d"(xsave_features_high()), "a"(xsave_features_low())); 74 } 75} 76 77/* Load FPU state from memory into the FPU registers. */ 78static inline void loadFpuState(user_fpu_state_t *src) 79{ 80 if (config_set(CONFIG_FXSAVE)) { 81 asm volatile("fxrstor %[src]" :: [src] "m"(*src)); 82 } else if (config_set(CONFIG_XSAVE)) { 83 if (config_set(CONFIG_XSAVE_XSAVES)) { 84 asm volatile("xrstors %[src]" :: [src] "m"(*src), "d"(xsave_features_high()), "a"(xsave_features_low())); 85 } else { 86 asm volatile("xrstor %[src]" :: [src] "m"(*src), "d"(xsave_features_high()), "a"(xsave_features_low())); 87 } 88 } 89} 90 91/* Reset the FPU registers into their initial blank state. */ 92static inline void finit(void) 93{ 94 asm volatile("finit" :: "m"(control_reg_order)); 95} 96 97/* 98 * Enable the FPU to be used without faulting. 99 * Required even if the kernel attempts to use the FPU. 100 */ 101static inline void enableFpu(void) 102{ 103 asm volatile("clts" :: "m"(control_reg_order)); 104} 105 106/* 107 * Disable the FPU so that usage of it causes a fault 108 */ 109static inline void disableFpu(void) 110{ 111 write_cr0(read_cr0() | CR0_TASK_SWITCH); 112} 113 114#ifdef CONFIG_VTX 115static inline bool_t vcpuThreadUsingFPU(tcb_t *thread) 116{ 117 return thread->tcbArch.tcbVCPU && &thread->tcbArch.tcbVCPU->fpuState == NODE_STATE(ksActiveFPUState); 118} 119#endif /* CONFIG_VTX */ 120 121