1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:45:07 +00:00

Kernel: More signal handling improvements.

Finally fixed the weird flaky crashing when resizing Terminal windows.
It was because we were dispatching a signal to "current" from the scheduler.
Yet another thing I dislike about even having a "current" process while
we're in the scheduler. Not sure yet how to fix this.

Let the signal handler's kernel stack be a kmalloc() allocation for now.
Once we can do allocation of consecutive physical pages in the supervisor
memory region, we can use that for all types of kernel stacks.
This commit is contained in:
Andreas Kling 2019-03-05 12:50:55 +01:00
parent 086a0fc969
commit 91031346e5
6 changed files with 93 additions and 55 deletions

View file

@ -26,7 +26,7 @@
//#define DEBUG_IO
//#define TASK_DEBUG
//#define FORK_DEBUG
#define SIGNAL_DEBUG
//#define SIGNAL_DEBUG
#define MAX_PROCESS_GIDS 32
//#define SHARED_BUFFER_DEBUG
@ -370,7 +370,8 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
}
}
m_signal_stack_kernel_region = nullptr;
kfree(m_kernel_stack_for_signal_handler);
m_kernel_stack_for_signal_handler = nullptr;
m_signal_stack_user_region = nullptr;
m_display_framebuffer_region = nullptr;
set_default_signal_dispositions();
@ -725,6 +726,11 @@ Process::~Process()
kfree(m_kernel_stack);
m_kernel_stack = nullptr;
}
if (m_kernel_stack_for_signal_handler) {
kfree(m_kernel_stack_for_signal_handler);
m_kernel_stack_for_signal_handler = nullptr;
}
}
void Process::dump_regions()
@ -912,8 +918,11 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
word ret_cs = m_tss.cs;
dword ret_eip = m_tss.eip;
dword ret_eflags = m_tss.eflags;
bool interrupting_in_kernel = (ret_cs & 3) == 0;
ProcessPagingScope paging_scope(*this);
create_signal_trampolines_if_needed();
if (interrupting_in_kernel) {
#ifdef SIGNAL_DEBUG
kprintf("dispatch_signal to %s(%u) in state=%s with return to %w:%x\n", name().characters(), pid(), to_string(state()), ret_cs, ret_eip);
@ -921,23 +930,23 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
ASSERT(is_blocked());
m_tss_to_resume_kernel = m_tss;
#ifdef SIGNAL_DEBUG
kprintf("resume tss pc: %w:%x\n", m_tss_to_resume_kernel.cs, m_tss_to_resume_kernel.eip);
kprintf("resume tss pc: %w:%x stack: %w:%x flags: %x cr3: %x\n", m_tss_to_resume_kernel.cs, m_tss_to_resume_kernel.eip, m_tss_to_resume_kernel.ss, m_tss_to_resume_kernel.esp, m_tss_to_resume_kernel.eflags, m_tss_to_resume_kernel.cr3);
#endif
}
ProcessPagingScope paging_scope(*this);
if (interrupting_in_kernel) {
if (!m_signal_stack_user_region) {
m_signal_stack_user_region = allocate_region(LinearAddress(), default_userspace_stack_size, "signal stack (user)");
m_signal_stack_user_region = allocate_region(LinearAddress(), default_userspace_stack_size, "Signal stack (user)");
ASSERT(m_signal_stack_user_region);
m_signal_stack_kernel_region = allocate_region(LinearAddress(), default_userspace_stack_size, "signal stack (kernel)");
ASSERT(m_signal_stack_kernel_region);
}
if (!m_kernel_stack_for_signal_handler) {
m_kernel_stack_for_signal_handler = kmalloc(default_kernel_stack_size);
ASSERT(m_kernel_stack_for_signal_handler);
}
m_tss.ss = 0x23;
m_tss.esp = m_signal_stack_user_region->laddr().offset(default_userspace_stack_size).get();
m_tss.ss0 = 0x10;
m_tss.esp0 = m_signal_stack_kernel_region->laddr().offset(default_userspace_stack_size).get();
m_tss.esp0 = (dword)m_kernel_stack_for_signal_handler + default_kernel_stack_size;
push_value_on_stack(0);
} else {
push_value_on_stack(ret_eip);
push_value_on_stack(ret_eflags);
@ -952,6 +961,9 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
push_value_on_stack(m_tss.ebp);
push_value_on_stack(m_tss.esi);
push_value_on_stack(m_tss.edi);
// Align the stack.
m_tss.esp -= 12;
}
// PUSH old_signal_mask
@ -964,42 +976,6 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
m_tss.gs = 0x23;
m_tss.eip = handler_laddr.get();
if (m_return_to_ring3_from_signal_trampoline.is_null()) {
// FIXME: This should be a global trampoline shared by all processes, not one created per process!
// FIXME: Remap as read-only after setup.
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "signal_trampoline", true, true);
m_return_to_ring3_from_signal_trampoline = region->laddr();
byte* code_ptr = m_return_to_ring3_from_signal_trampoline.as_ptr();
*code_ptr++ = 0x58; // pop eax (Skip over signal argument)
*code_ptr++ = 0x5a; // pop edx
*code_ptr++ = 0xb8; // mov eax, <dword>
*(dword*)code_ptr = Syscall::SC_restore_signal_mask;
code_ptr += sizeof(dword);
*code_ptr++ = 0xcd; // int 0x82
*code_ptr++ = 0x82;
*code_ptr++ = 0x61; // popa
*code_ptr++ = 0x9d; // popf
*code_ptr++ = 0xc3; // ret
*code_ptr++ = 0x0f; // ud2
*code_ptr++ = 0x0b;
m_return_to_ring0_from_signal_trampoline = LinearAddress((dword)code_ptr);
*code_ptr++ = 0x58; // pop eax (Skip over signal argument)
*code_ptr++ = 0x5a; // pop edx
*code_ptr++ = 0xb8; // mov eax, <dword>
*(dword*)code_ptr = Syscall::SC_restore_signal_mask;
code_ptr += sizeof(dword);
*code_ptr++ = 0xcd; // int 0x82
*code_ptr++ = 0x82;
*code_ptr++ = 0xb8; // mov eax, <dword>
*(dword*)code_ptr = Syscall::SC_sigreturn;
code_ptr += sizeof(dword);
*code_ptr++ = 0xcd; // int 0x82
*code_ptr++ = 0x82;
*code_ptr++ = 0x0f; // ud2
*code_ptr++ = 0x0b;
}
// FIXME: Should we worry about the stack being 16 byte aligned when entering a signal handler?
push_value_on_stack(signal);
@ -1008,6 +984,8 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
else
push_value_on_stack(m_return_to_ring3_from_signal_trampoline.get());
ASSERT((m_tss.esp % 16) == 0);
// FIXME: This state is such a hack. It avoids trouble if 'current' is the process receiving a signal.
set_state(Skip1SchedulerPass);
@ -1017,6 +995,54 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
return ShouldUnblockProcess::Yes;
}
void Process::create_signal_trampolines_if_needed()
{
if (!m_return_to_ring3_from_signal_trampoline.is_null())
return;
// FIXME: This should be a global trampoline shared by all processes, not one created per process!
// FIXME: Remap as read-only after setup.
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "Signal trampolines", true, true);
m_return_to_ring3_from_signal_trampoline = region->laddr();
byte* code_ptr = m_return_to_ring3_from_signal_trampoline.as_ptr();
*code_ptr++ = 0x58; // pop eax (Argument to signal handler (ignored here))
*code_ptr++ = 0x5a; // pop edx (Original signal mask to restore)
*code_ptr++ = 0xb8; // mov eax, <dword>
*(dword*)code_ptr = Syscall::SC_restore_signal_mask;
code_ptr += sizeof(dword);
*code_ptr++ = 0xcd; // int 0x82
*code_ptr++ = 0x82;
*code_ptr++ = 0x83; // add esp, (stack alignment padding)
*code_ptr++ = 0xc4;
*code_ptr++ = sizeof(dword) * 3;
*code_ptr++ = 0x61; // popa
*code_ptr++ = 0x9d; // popf
*code_ptr++ = 0xc3; // ret
*code_ptr++ = 0x0f; // ud2
*code_ptr++ = 0x0b;
m_return_to_ring0_from_signal_trampoline = LinearAddress((dword)code_ptr);
*code_ptr++ = 0x58; // pop eax (Argument to signal handler (ignored here))
*code_ptr++ = 0x5a; // pop edx (Original signal mask to restore)
*code_ptr++ = 0xb8; // mov eax, <dword>
*(dword*)code_ptr = Syscall::SC_restore_signal_mask;
code_ptr += sizeof(dword);
*code_ptr++ = 0xcd; // int 0x82
// NOTE: Stack alignment padding doesn't matter when returning to ring0.
// Nothing matters really, as we're returning by replacing the entire TSS.
*code_ptr++ = 0x82;
*code_ptr++ = 0xb8; // mov eax, <dword>
*(dword*)code_ptr = Syscall::SC_sigreturn;
code_ptr += sizeof(dword);
*code_ptr++ = 0xcd; // int 0x82
*code_ptr++ = 0x82;
*code_ptr++ = 0x0f; // ud2
*code_ptr++ = 0x0b;
}
int Process::sys$restore_signal_mask(dword mask)
{
m_signal_mask = mask;
@ -1030,7 +1056,7 @@ void Process::sys$sigreturn()
m_tss = m_tss_to_resume_kernel;
#ifdef SIGNAL_DEBUG
kprintf("sys$sigreturn in %s(%u)\n", name().characters(), pid());
kprintf(" -> resuming execution at %w:%x\n", m_tss.cs, m_tss.eip);
kprintf(" -> resuming execution at %w:%x stack %w:%x flags %x cr3 %x\n", m_tss.cs, m_tss.eip, m_tss.ss, m_tss.esp, m_tss.eflags, m_tss.cr3);
#endif
set_state(Skip1SchedulerPass);
Scheduler::yield();