20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/Spinlock.h"
22#include "pedigree/kernel/process/Thread.h"
23#include "pedigree/kernel/processor/InterruptManager.h"
24#include "pedigree/kernel/processor/NMFaultHandler.h"
25#include "pedigree/kernel/processor/Processor.h"
26#include "pedigree/kernel/processor/ProcessorInformation.h"
27#include "pedigree/kernel/processor/state.h"
28#include "pedigree/kernel/utilities/lib.h"
32#define NM_FAULT_EXCEPTION 0x07
34#define CR0_NE (1 << 5)
35#define CR0_TS (1 << 3)
36#define CR0_EM (1 << 2)
37#define CR0_MP (1 << 1)
38#define CR4_OSFXSR (1 << 9)
39#define CR4_OSXMMEXCPT (1 << 10)
40#define CPUID_FEAT_EDX_FXSR (1 << 24)
41#define CPUID_FEAT_EDX_FPU (1 << 0)
42#define CPUID_FEAT_EDX_SSE (1 << 25)
44#define MXCSR_PM (1 << 12)
45#define MXCSR_UM (1 << 11)
46#define MXCSR_OM (1 << 10)
47#define MXCSR_ZM (1 << 9)
48#define MXCSR_DM (1 << 8)
49#define MXCSR_IM (1 << 7)
53#define MXCSR_RC_NEAREST 0
54#define MXCSR_RC_DOWN 1
56#define MXCSR_RC_TRUNCATE 3
60static bool FXSR_Support, FPU_Support;
62static bool g_InitialFxStateValid =
false;
63static Spinlock g_InitialFxStateLock(
false,
true);
65static_assert(__builtin_offsetof(
X64SchedulerState, x87FPU_MMX_XMM_MXCSR_State) == 112,
66 "x64 Scheduler.s FXSAVE offset is stale");
69 uintptr_t address =
reinterpret_cast<uintptr_t
>(state.x87FPU_MMX_XMM_MXCSR_State);
70 return reinterpret_cast<void*
>((address + 15) & ~uintptr_t(15));
74 uintptr_t address =
reinterpret_cast<uintptr_t
>(state.x87FPU_MMX_XMM_MXCSR_State);
75 return reinterpret_cast<const void*
>((address + 15) & ~uintptr_t(15));
78static inline void _SetFPUControlWord(uint16_t cw) {
80 asm volatile(
" fldcw %0; " ::
"m"(cw));
94 uint32_t eax, ebx, ecx, edx, mxcsr = 0;
97 asm volatile(
"mov %%cr0, %0" :
"=r"(cr0));
98 asm volatile(
"mov %%cr4, %0" :
"=r"(cr4));
101 if (edx & CPUID_FEAT_EDX_FPU) {
104 cr0 = (cr0 | CR0_NE | CR0_MP) & ~(CR0_EM | CR0_TS);
105 asm volatile(
"mov %0, %%cr0" ::
"r"(cr0));
108 asm volatile(
"finit");
111 _SetFPUControlWord(0x37F);
113 asm volatile(
"mov %0, %%cr0" ::
"r"(cr0));
117 if (edx & CPUID_FEAT_EDX_FXSR) {
121 FXSR_Support =
false;
123 if (edx & CPUID_FEAT_EDX_SSE) {
124 cr4 |= CR4_OSXMMEXCPT;
126 asm volatile(
"mov %0, %%cr4;" ::
"r"(cr4));
133 asm volatile(
"ldmxcsr %0;" ::
"m"(mxcsr));
135 asm volatile(
"mov %0, %%cr4;" ::
"r"(cr4));
138 while (!g_InitialFxStateLock.
acquire(
false,
false))
140 if (!g_InitialFxStateValid) {
141 void* blankState = fpuStateBuffer(x87FPU_MMX_XMM_MXCSR_StateBlank);
142 asm volatile(
"fxsave64 (%0)" ::
"r"(blankState) :
"memory");
143 x87FPU_MMX_XMM_MXCSR_StateBlank.flags |= (1 << 1);
144 g_InitialFxStateValid =
true;
146 g_InitialFxStateLock.
release();
152 asm volatile(
"mov %0, %%cr0" ::
"r"(cr0));
158 if (!FXSR_Support || !g_InitialFxStateValid || !buffer ||
159 (
reinterpret_cast<uintptr_t
>(buffer) & 0xF)) {
172 void* threadState = fpuStateBuffer(state);
173 const void* blankState = fpuStateBuffer(x87FPU_MMX_XMM_MXCSR_StateBlank);
176 asm volatile(
"mov %%cr0, %0" :
"=r"(cr0));
178 if (state.flags & (1 << 1)) {
179 MemoryCopy(buffer, threadState, 512);
181 MemoryCopy(buffer, blankState, 512);
184 asm volatile(
"fxsave64 (%0)" ::
"r"(buffer) :
"memory");
185 MemoryCopy(threadState, buffer, 512);
186 state.flags |= (1 << 1);
189 if (resetForSignalHandler) {
190 MemoryCopy(threadState, blankState, 512);
191 state.flags |= (1 << 1);
192 if (!(cr0 & CR0_TS)) {
193 asm volatile(
"fxrstor64 (%0)" ::
"r"(blankState) :
"memory");
202 if (!FXSR_Support || !g_InitialFxStateValid || !buffer ||
203 (
reinterpret_cast<uintptr_t
>(buffer) & 0xF)) {
208 uint32_t mxcsrMask = 0;
209 MemoryCopy(&mxcsr, adjust_pointer(buffer, 24),
sizeof(mxcsr));
210 MemoryCopy(&mxcsrMask, adjust_pointer(fpuStateBuffer(x87FPU_MMX_XMM_MXCSR_StateBlank), 28),
215 if (mxcsr & ~mxcsrMask) {
228 MemoryCopy(fpuStateBuffer(state), buffer, 512);
229 state.flags |= (1 << 1);
232 asm volatile(
"mov %%cr0, %0" :
"=r"(cr0));
233 if (!(cr0 & CR0_TS)) {
234 asm volatile(
"fxrstor64 (%0)" ::
"r"(buffer) :
"memory");
246 alignas(16) uint8_t inherited[512];
252 MemoryCopy(fpuStateBuffer(state), inherited,
sizeof(inherited));
253 state.flags |= (1 << 1);
262 if (!pCurrentThread) {
263 FATAL_NOLOCK(
"NM: no current thread");
267 asm volatile(
"mov %%cr0, %0" :
"=r"(cr0));
270 asm volatile(
"mov %0, %%cr0" ::
"r"(cr0));
272 FATAL_NOLOCK(
"NM: TS already disabled");
280 if (!(pCurrentState->flags & (1 << 1))) {
281 MemoryCopy(fpuStateBuffer(*pCurrentState), fpuStateBuffer(x87FPU_MMX_XMM_MXCSR_StateBlank),
283 pCurrentState->flags |= (1 << 1);
286 asm volatile(
"fxrstor64 (%0)" ::
"r"(fpuStateBuffer(*pCurrentState)) :
"memory");
287 }
else if (FPU_Support) {
288 if (!(pCurrentState->flags & (1 << 1))) {
289 MemoryCopy(fpuStateBuffer(*pCurrentState), fpuStateBuffer(x87FPU_MMX_XMM_MXCSR_StateBlank),
292 pCurrentState->flags |= (1 << 1);
295 asm volatile(
"frstor (%0)" ::
"r"(fpuStateBuffer(*pCurrentState)) :
"memory");
297 ERROR(
"FXSAVE and FSAVE are not supported");
303void NMFaultHandler::threadTerminated(
Thread* pThread) {
static EXPORTED_PUBLIC InterruptManager & instance()
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
virtual void interrupt(size_t interruptNumber, InterruptState &state)
NMFaultHandler() INITIALISATION_ONLY
static EXPORTED_PUBLIC bool saveCurrentThreadFpuState(void *buffer, bool resetForSignalHandler)
static NMFaultHandler m_Instance
static bool inheritCurrentThreadFpuState(class Thread *thread)
static EXPORTED_PUBLIC bool restoreCurrentThreadFpuState(const void *buffer)
bool initialiseProcessor()
static bool getInterrupts()
static ProcessorInformation & information()
static void setInterrupts(bool bEnable)
bool acquire(bool recurse=false, bool safe=true)
static void cpuid(uint32_t inEax, uint32_t inEcx, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx)