kernel/x86_64: Store FPU state from int_bottom_user in arch_thread always.

The XSAVE area can be quite large (1-2KB+), so rather than always
putting it on the kernel stack, just use the arch_thread FPU state.

Change-Id: Ie64c3ea3ca52cd8a4425ae1da69792588a69832a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9090
Reviewed-by: Jérôme Duval <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Augustin Cavalier
2025-03-11 02:13:26 +00:00
committed by waddlesplash
parent bdb6d7db1a
commit 6db4b42346
6 changed files with 22 additions and 31 deletions
@@ -63,7 +63,7 @@ struct arch_thread {
// have enough space for all the registers, at least 2560 bytes according
// to Intel Architecture Instruction Set Extensions Programming Reference,
// Section 3.2.4, table 3-8
uint8 fpu_state[2560] _ALIGNED(64);
uint8 user_fpu_state[2560] _ALIGNED(64);
#endif
addr_t GetFramePointer() const;
+8 -19
View File
@@ -207,7 +207,6 @@ STATIC_FUNCTION(int_bottom):
// Push the rest of the interrupt frame to the stack.
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
cld
// Frame pointer is the iframe.
@@ -265,33 +264,24 @@ STATIC_FUNCTION(int_bottom_user):
// Frame pointer is the iframe.
movq %rsp, %rbp
andq $~15, %rsp
// Get thread pointer.
movq %gs:0, %r12
// xsave needs a 64-byte alignment
andq $~63, %rsp
movq (gFPUSaveLength), %rcx
subq %rcx, %rsp
leaq (%rsp), %rdi
shrq $3, %rcx
movq $0, %rax
rep stosq
movl (gXsaveMask), %eax
movl (gXsaveMask+4), %edx
movq %rsp, %rdi
leaq THREAD_user_fpu_state(%r12), %rdi
CODEPATCH_START
fxsaveq (%rdi)
CODEPATCH_END(ALTCODEPATCH_TAG_XSAVE)
movq %rsp, IFRAME_fpu(%rbp)
movq %rdi, IFRAME_fpu(%rbp)
// Set the RF (resume flag) in RFLAGS. This prevents an instruction
// breakpoint on the instruction we're returning to to trigger a debug
// exception.
orq $X86_EFLAGS_RESUME, IFRAME_flags(%rbp)
// Get thread pointer.
movq %gs:0, %r12
STOP_USER_DEBUGGING()
UPDATE_THREAD_USER_TIME()
@@ -314,7 +304,7 @@ STATIC_FUNCTION(int_bottom_user):
movl (gXsaveMask), %eax
movl (gXsaveMask+4), %edx
movq %rsp, %rdi
leaq THREAD_user_fpu_state(%r12), %rdi
CODEPATCH_START
fxrstorq (%rdi)
CODEPATCH_END(ALTCODEPATCH_TAG_XRSTOR)
@@ -347,7 +337,7 @@ STATIC_FUNCTION(int_bottom_user):
1:
movl (gXsaveMask), %eax
movl (gXsaveMask+4), %edx
movq %rsp, %rdi
leaq THREAD_user_fpu_state(%r12), %rdi
CODEPATCH_START
fxrstorq (%rdi)
CODEPATCH_END(ALTCODEPATCH_TAG_XRSTOR)
@@ -392,7 +382,6 @@ FUNCTION(x86_64_syscall_entry):
push $0 // error_code
push $99 // vector
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_SYSCALL)
cld
// Frame pointer is the iframe.
+8 -8
View File
@@ -181,7 +181,7 @@ arch_thread_init(kernel_args* args)
"movl $0x7,%%eax;" \
"movl $0x0,%%edx;" \
"xsavec64 %0"
:: "m" (sInitialState.fpu_state));
:: "m" (sInitialState.user_fpu_state));
} else {
asm volatile (
"clts;" \
@@ -190,7 +190,7 @@ arch_thread_init(kernel_args* args)
"movl $0x7,%%eax;" \
"movl $0x0,%%edx;" \
"xsave64 %0"
:: "m" (sInitialState.fpu_state));
:: "m" (sInitialState.user_fpu_state));
}
} else {
asm volatile (
@@ -198,11 +198,11 @@ arch_thread_init(kernel_args* args)
"fninit;" \
"fnclex;" \
"fxsaveq %0"
:: "m" (sInitialState.fpu_state));
:: "m" (sInitialState.user_fpu_state));
}
// FNINIT does not affect MXCSR or data registers, so we reset them in the state.
savefpu* initialState = ((savefpu*)&sInitialState.fpu_state);
savefpu* initialState = ((savefpu*)&sInitialState.user_fpu_state);
initialState->fp_fxsave.mxcsr = 0x1F80; // __INITIAL_MXCSR__
memset(initialState->fp_fxsave.fp, 0, sizeof(initialState->fp_fxsave.fp));
memset(initialState->fp_fxsave.xmm, 0, sizeof(initialState->fp_fxsave.xmm));
@@ -265,7 +265,7 @@ arch_thread_dump_info(void* info)
kprintf("\trsp: %p\n", thread->current_stack);
kprintf("\tsyscall_rsp: %p\n", thread->syscall_rsp);
kprintf("\tuser_rsp: %p\n", thread->user_rsp);
kprintf("\tfpu_state at %p\n", thread->fpu_state);
kprintf("\tuser_fpu_state at %p\n", thread->user_fpu_state);
}
@@ -374,7 +374,7 @@ arch_setup_signal_frame(Thread* thread, struct sigaction* action,
gFPUSaveLength);
} else {
memcpy((void*)&signalFrameData->context.uc_mcontext.fpu,
sInitialState.fpu_state, gFPUSaveLength);
sInitialState.user_fpu_state, gFPUSaveLength);
}
// Fill in signalFrameData->context.uc_stack.
@@ -446,9 +446,9 @@ arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
Thread* thread = thread_get_current_thread();
memcpy(thread->arch_info.fpu_state,
memcpy(thread->arch_info.user_fpu_state,
(void*)&signalFrameData->context.uc_mcontext.fpu, gFPUSaveLength);
frame->fpu = &thread->arch_info.fpu_state;
frame->fpu = &thread->arch_info.user_fpu_state;
// The syscall return code overwrites frame->ax with the return value of
// the syscall, need to return it here to ensure the correct value is
+1 -1
View File
@@ -1908,7 +1908,7 @@ arch_cpu_init_post_vm(kernel_args* args)
call_all_cpus_sync(&enable_xsavemask, NULL);
get_current_cpuid(&cpuid, IA32_CPUID_LEAF_XSTATE, 0);
gFPUSaveLength = cpuid.regs.ebx;
if (gFPUSaveLength > sizeof(((struct arch_thread *)0)->fpu_state))
if (gFPUSaveLength > sizeof(((struct arch_thread *)0)->user_fpu_state))
gFPUSaveLength = 832;
arch_altcodepatch_replace(ALTCODEPATCH_TAG_XSAVE,
@@ -748,9 +748,9 @@ arch_set_debug_cpu_state(const debug_cpu_state* cpuState)
// not use these registers (not even indirectly).
#ifdef __x86_64__
Thread* thread = thread_get_current_thread();
memcpy(thread->arch_info.fpu_state, &cpuState->extended_registers,
memcpy(thread->arch_info.user_fpu_state, &cpuState->extended_registers,
sizeof(cpuState->extended_registers));
frame->fpu = &thread->arch_info.fpu_state;
frame->fpu = &thread->arch_info.user_fpu_state;
#else
if (gHasSSE) {
// Since fxrstor requires 16-byte alignment and this isn't
@@ -49,6 +49,8 @@ dummy()
DEFINE_OFFSET_MACRO(THREAD, Thread, fault_handler);
#ifdef __x86_64__
DEFINE_MACRO(THREAD_user_fpu_state, offsetof(Thread, arch_info.user_fpu_state));
// struct arch_thread
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, syscall_rsp);
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, user_rsp);