mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
Kernel: Implement signal handling for x86_64
This commit is contained in:
parent
36ce2a2b76
commit
6dde7dac8f
Notes:
sideshowbarker
2024-07-18 11:20:13 +09:00
Author: https://github.com/gunnarbeutner Commit: https://github.com/SerenityOS/serenity/commit/6dde7dac8f7 Pull-request: https://github.com/SerenityOS/serenity/pull/8317
3 changed files with 72 additions and 9 deletions
|
@ -308,9 +308,25 @@ void signal_trampoline_dummy()
|
|||
"asm_signal_trampoline_end:\n"
|
||||
".att_syntax" ::"i"(Syscall::SC_sigreturn));
|
||||
#elif ARCH(X86_64)
|
||||
asm("asm_signal_trampoline:\n"
|
||||
"cli;hlt\n"
|
||||
"asm_signal_trampoline_end:\n");
|
||||
// The trampoline preserves the current rax, pushes the signal code and
|
||||
// then calls the signal handler. We do this because, when interrupting a
|
||||
// blocking syscall, that syscall may return some special error code in eax;
|
||||
// This error code would likely be overwritten by the signal handler, so it's
|
||||
// necessary to preserve it here.
|
||||
asm(
|
||||
".intel_syntax noprefix\n"
|
||||
"asm_signal_trampoline:\n"
|
||||
"push rbp\n"
|
||||
"mov rbp, rsp\n"
|
||||
"push rax\n" // we have to store rax 'cause it might be the return value from a syscall
|
||||
"sub rsp, 8\n" // align the stack to 16 bytes
|
||||
"mov rdi, [rbp+24]\n" // push the signal code
|
||||
"call [rbp+16]\n" // call the signal handler
|
||||
"add rsp, 8\n"
|
||||
"mov rax, %P0\n"
|
||||
"int 0x82\n" // sigreturn syscall
|
||||
"asm_signal_trampoline_end:\n"
|
||||
".att_syntax" ::"i"(Syscall::SC_sigreturn));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,28 @@ KResultOr<FlatPtr> Process::sys$sigreturn([[maybe_unused]] RegisterState& regist
|
|||
registers.userspace_esp = registers.esp;
|
||||
return smuggled_eax;
|
||||
#else
|
||||
PANIC("sys$sigreturn() not implemented.");
|
||||
//Here, we restore the state pushed by dispatch signal and asm_signal_trampoline.
|
||||
FlatPtr* stack_ptr = (FlatPtr*)registers.userspace_rsp;
|
||||
FlatPtr smuggled_rax = *stack_ptr;
|
||||
|
||||
//pop the stored rax, rbp, return address, handler and signal code
|
||||
stack_ptr += 5;
|
||||
|
||||
Thread::current()->m_signal_mask = *stack_ptr;
|
||||
stack_ptr++;
|
||||
|
||||
//pop rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, r8, r9, r10, r11, r12, r13, r14 and r15
|
||||
memcpy(®isters.rdi, stack_ptr, 16 * sizeof(FlatPtr));
|
||||
stack_ptr += 16;
|
||||
|
||||
registers.rip = *stack_ptr;
|
||||
stack_ptr++;
|
||||
|
||||
registers.rflags = (registers.rflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask);
|
||||
stack_ptr++;
|
||||
|
||||
registers.userspace_rsp = registers.rsp;
|
||||
return smuggled_rax;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -822,7 +822,11 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
|
|||
dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to EIP {:p}, ESP {:p}", ret_eip, old_esp);
|
||||
#elif ARCH(X86_64)
|
||||
FlatPtr* stack = &state.userspace_rsp;
|
||||
TODO();
|
||||
FlatPtr old_rsp = *stack;
|
||||
FlatPtr ret_rip = state.rip;
|
||||
FlatPtr ret_rflags = state.rflags;
|
||||
|
||||
dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to RIP {:p}, RSP {:p}", ret_rip, old_rsp);
|
||||
#endif
|
||||
|
||||
#if ARCH(I386)
|
||||
|
@ -843,10 +847,32 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
|
|||
push_value_on_user_stack(stack, state.ebp);
|
||||
push_value_on_user_stack(stack, state.esi);
|
||||
push_value_on_user_stack(stack, state.edi);
|
||||
|
||||
#else
|
||||
// FIXME
|
||||
PANIC("Thread:dispatch_signal() not implemented");
|
||||
// Align the stack to 16 bytes.
|
||||
// Note that we push 176 bytes (8 * 22) on to the stack,
|
||||
// so we need to account for this here.
|
||||
FlatPtr stack_alignment = (*stack - 112) % 16;
|
||||
*stack -= stack_alignment;
|
||||
|
||||
push_value_on_user_stack(stack, ret_rflags);
|
||||
|
||||
push_value_on_user_stack(stack, ret_rip);
|
||||
push_value_on_user_stack(stack, state.r15);
|
||||
push_value_on_user_stack(stack, state.r14);
|
||||
push_value_on_user_stack(stack, state.r13);
|
||||
push_value_on_user_stack(stack, state.r12);
|
||||
push_value_on_user_stack(stack, state.r11);
|
||||
push_value_on_user_stack(stack, state.r10);
|
||||
push_value_on_user_stack(stack, state.r9);
|
||||
push_value_on_user_stack(stack, state.r8);
|
||||
push_value_on_user_stack(stack, state.rax);
|
||||
push_value_on_user_stack(stack, state.rcx);
|
||||
push_value_on_user_stack(stack, state.rdx);
|
||||
push_value_on_user_stack(stack, state.rbx);
|
||||
push_value_on_user_stack(stack, old_rsp);
|
||||
push_value_on_user_stack(stack, state.rbp);
|
||||
push_value_on_user_stack(stack, state.rsi);
|
||||
push_value_on_user_stack(stack, state.rdi);
|
||||
#endif
|
||||
|
||||
// PUSH old_signal_mask
|
||||
|
@ -887,7 +913,7 @@ RegisterState& Thread::get_register_dump_from_stack()
|
|||
|
||||
// We should *always* have a trap. If we don't we're probably a kernel
|
||||
// thread that hasn't been pre-empted. If we want to support this, we
|
||||
// need to capture the registers probably into m_tss and return it
|
||||
// need to capture the registers probably into m_regs and return it
|
||||
VERIFY(trap);
|
||||
|
||||
while (trap) {
|
||||
|
|
Loading…
Reference in a new issue