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. */
20 typedef 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. */
34 typedef 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. */
44 bool_t Arch_initFpu(void);
45
46 /* Initialise the FPU state of the given user context. */
47 void Arch_initFpuContext(user_context_t *context);
48
xsave_features_high(void)49 static 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
xsave_features_low(void)55 static 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. */
saveFpuState(user_fpu_state_t * dest)62 static 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. */
loadFpuState(user_fpu_state_t * src)78 static 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. */
finit(void)92 static 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 */
enableFpu(void)101 static 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 */
disableFpu(void)109 static inline void disableFpu(void)
110 {
111 write_cr0(read_cr0() | CR0_TASK_SWITCH);
112 }
113
114 #ifdef CONFIG_VTX
vcpuThreadUsingFPU(tcb_t * thread)115 static 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