x86, FPU: Fix XSAVES

Add config choice and change the default from XSAVEOPT to XSAVE.

The first config choice is used as the default option. Only XSAVE
is guaranteed to always work, the others require newer CPUs.

Get rid of dubious FPU state headers, we don't need them:
- XCOMP_BV_COMPACTED_FORMAT is set by xsavec or xsaves.
- We can init MXCSR with the ldmxcsr instruction.

Only system state should be configured in IA32_XSS_MSR,
setting FPU user state bits causes an exception.

All memory should be zeroed already, no need to do it again.

See also issue #179.

Signed-off-by: Indan Zupancic <indan@nul.nu>
This commit is contained in:
Indan Zupancic 2024-09-11 10:45:00 +01:00 committed by Gerwin Klein
parent 1bd0e3b788
commit a96982e576
4 changed files with 13 additions and 40 deletions

View file

@ -29,7 +29,7 @@
#define IA32_FMASK_MSR 0xC0000084
#define IA32_EFER_MSR 0xC0000080
#define IA32_PLATFORM_INFO_MSR 0xCE
#define IA32_XSS_MSR 0xD0A
#define IA32_XSS_MSR 0xDA0
#define IA32_FEATURE_CONTROL_MSR 0x3A
#define IA32_KERNEL_GS_BASE_MSR 0xC0000102
#define IA32_VMX_BASIC_MSR 0x480

View file

@ -14,31 +14,6 @@
#include <arch/machine/cpu_registers.h>
#define MXCSR_INIT_VALUE 0x1f80
#define XCOMP_BV_COMPACTED_FORMAT (1ull << 63)
/* The state format, as saved by FXSAVE and restored by FXRSTOR instructions. */
typedef struct i387_state {
uint16_t cwd; /* control word */
uint16_t swd; /* status word */
uint16_t twd; /* tag word */
uint16_t fop; /* last instruction opcode */
uint32_t reserved[4]; /* instruction and data pointers */
uint32_t mxcsr; /* MXCSR register state */
uint32_t mxcsr_mask; /* MXCSR mask */
uint32_t st_space[32]; /* FPU registers */
uint32_t xmm_space[64]; /* XMM registers */
uint32_t padding[13];
} PACKED i387_state_t;
/* The state format, as saved by XSAVE and restored by XRSTOR instructions. */
typedef struct xsave_state {
i387_state_t i387;
struct {
uint64_t xfeatures;
uint64_t xcomp_bv; /* state-component bitmap */
uint64_t reserved[6];
} header;
} PACKED xsave_state_t;
/* Initialise the FPU. */
bool_t Arch_initFpu(void);

View file

@ -165,12 +165,14 @@ config_choice(
XSAVE buffer, if using non contiguous features, XSAVEC will attempt to use the init optimization \
when saving \
XSAVEOPT -> Save state taking advantage of both the init optimization and modified optimization \
XSAVES -> Save state taking advantage of the modified optimization. This instruction is only \
XSAVES -> Save state taking advantage of all optimizations. This instruction is only \
available in OS code, and is the preferred save method if it exists."
"XSAVEOPT;KernelXSaveXSaveOpt;XSAVE_XSAVEOPT;KernelFPUXSave"
"XSAVE;KernelXSaveXSave;XSAVE_XSAVE;KernelFPUXSave"
"XSAVES;KernelXSaveXSaveS;XSAVE_XSAVES;KernelFPUXSave"
"XSAVEOPT;KernelXSaveXSaveOpt;XSAVE_XSAVEOPT;KernelFPUXSave"
"XSAVEC;KernelXSaveXSaveC;XSAVE_XSAVEC;KernelFPUXSave"
)
config_string(
KernelXSaveFeatureSet XSAVE_FEATURE_SET
"XSAVE can save and restore the state for various features \
@ -186,7 +188,11 @@ config_string(
)
if(KernelFPUXSave)
set(default_xsave_size 576)
if ("${KernelXSaveFeatureSet}" EQUAL 7)
set(default_xsave_size 832)
else()
set(default_xsave_size 576)
endif()
else()
set(default_xsave_size 512)
endif()

View file

@ -37,10 +37,6 @@ BOOT_CODE bool_t Arch_initFpu(void)
uint64_t xsave_features;
uint32_t xsave_instruction;
uint64_t desired_features = config_ternary(CONFIG_XSAVE, CONFIG_XSAVE_FEATURE_SET, 1);
xsave_state_t *nullFpuState = (xsave_state_t *) &x86KSnullFpuState;
/* create NULL state for FPU to be used by XSAVE variants */
memzero(&x86KSnullFpuState, sizeof(x86KSnullFpuState));
/* check for XSAVE support */
if (!(x86_cpuid_ecx(1, 0) & BIT(26))) {
@ -84,14 +80,10 @@ BOOT_CODE bool_t Arch_initFpu(void)
printf("XSAVES requested, but not supported\n");
return false;
}
/* AVX state from extended region should be in compacted format */
nullFpuState->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT;
/* initialize the XSS MSR */
x86_wrmsr(IA32_XSS_MSR, desired_features);
}
nullFpuState->i387.mxcsr = MXCSR_INIT_VALUE;
/* Init MXCSR */
unsigned int mxcsr = MXCSR_INIT_VALUE;
asm volatile("ldmxcsr %0" :: "m"(mxcsr));
}
return true;
}