From 251293f2e1178370d85c1dd4f3808ed9681fdb3c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 5 Mar 2019 10:34:08 +0100 Subject: Kernel: Block a signal from being dispatched again until handler returns. We don't handle nesting yet, but this is a step in the right direction. --- Kernel/BXVGADevice.cpp | 2 + Kernel/Process.cpp | 133 +++++++++++++++++++++++++++++++++++++------------ Kernel/Process.h | 40 ++------------- Kernel/Syscall.cpp | 2 + Kernel/Syscall.h | 1 + Kernel/UnixTypes.h | 1 + 6 files changed, 110 insertions(+), 69 deletions(-) diff --git a/Kernel/BXVGADevice.cpp b/Kernel/BXVGADevice.cpp index dbdc224268..0d6e2fd48d 100644 --- a/Kernel/BXVGADevice.cpp +++ b/Kernel/BXVGADevice.cpp @@ -51,6 +51,8 @@ void BXVGADevice::set_register(word index, word data) void BXVGADevice::set_resolution(int width, int height) { + m_framebuffer_size = { width, height }; + set_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); set_register(VBE_DISPI_INDEX_XRES, (word)width); set_register(VBE_DISPI_INDEX_YRES, (word)height); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 3ef3e9d4ca..dbb0822d1a 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -374,7 +374,7 @@ int Process::do_exec(String path, Vector arguments, Vector envir m_signal_stack_user_region = nullptr; m_display_framebuffer_region = nullptr; set_default_signal_dispositions(); - m_signal_mask = 0xffffffff; + m_signal_mask = 0; m_pending_signals = 0; for (int i = 0; i < m_fds.size(); ++i) { @@ -778,13 +778,13 @@ void Process::send_signal(byte signal, Process* sender) bool Process::has_unmasked_pending_signals() const { - return m_pending_signals & m_signal_mask; + return m_pending_signals & ~m_signal_mask; } ShouldUnblockProcess Process::dispatch_one_pending_signal() { ASSERT_INTERRUPTS_DISABLED(); - dword signal_candidates = m_pending_signals & m_signal_mask; + dword signal_candidates = m_pending_signals & ~m_signal_mask; ASSERT(signal_candidates); byte signal = 0; @@ -854,7 +854,9 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) ASSERT_INTERRUPTS_DISABLED(); ASSERT(signal < 32); - dbgprintf("dispatch_signal %s(%u) <- %u\n", name().characters(), pid(), signal); +#ifdef SIGNAL_DEBUG + kprintf("dispatch_signal %s(%u) <- %u\n", name().characters(), pid(), signal); +#endif auto& action = m_signal_action_data[signal]; // FIXME: Implement SA_SIGINFO signal handlers. @@ -890,10 +892,21 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) } if (handler_laddr.as_ptr() == SIG_IGN) { - dbgprintf("%s(%u) ignored signal %u\n", name().characters(), pid(), signal); +#ifdef SIGNAL_DEBUG + kprintf("%s(%u) ignored signal %u\n", name().characters(), pid(), signal); +#endif return ShouldUnblockProcess::Yes; } + dword old_signal_mask = m_signal_mask; + dword new_signal_mask = action.mask; + if (action.flags & SA_NODEFER) + new_signal_mask &= ~(1 << signal); + else + new_signal_mask |= 1 << signal; + + m_signal_mask |= new_signal_mask; + Scheduler::prepare_to_modify_tss(*this); word ret_cs = m_tss.cs; @@ -902,11 +915,13 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) bool interrupting_in_kernel = (ret_cs & 3) == 0; if (interrupting_in_kernel) { - dbgprintf("dispatch_signal to %s(%u) in state=%s with return to %w:%x\n", name().characters(), pid(), to_string(state()), ret_cs, ret_eip); +#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); +#endif ASSERT(is_blocked()); m_tss_to_resume_kernel = m_tss; #ifdef SIGNAL_DEBUG - dbgprintf("resume tss pc: %w:%x\n", m_tss_to_resume_kernel.cs, m_tss_to_resume_kernel.eip); + kprintf("resume tss pc: %w:%x\n", m_tss_to_resume_kernel.cs, m_tss_to_resume_kernel.eip); #endif } @@ -917,33 +932,31 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) 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_user_region); + ASSERT(m_signal_stack_kernel_region); } m_tss.ss = 0x23; - m_tss.esp = m_signal_stack_user_region->laddr().offset(default_userspace_stack_size).get() & 0xfffffff8; + 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() & 0xfffffff8; - push_value_on_stack(ret_eflags); - push_value_on_stack(ret_cs); - push_value_on_stack(ret_eip); + m_tss.esp0 = m_signal_stack_kernel_region->laddr().offset(default_userspace_stack_size).get(); } else { - push_value_on_stack(ret_cs); push_value_on_stack(ret_eip); push_value_on_stack(ret_eflags); + + // PUSHA + dword old_esp = m_tss.esp; + push_value_on_stack(m_tss.eax); + push_value_on_stack(m_tss.ecx); + push_value_on_stack(m_tss.edx); + push_value_on_stack(m_tss.ebx); + push_value_on_stack(old_esp); + push_value_on_stack(m_tss.ebp); + push_value_on_stack(m_tss.esi); + push_value_on_stack(m_tss.edi); } - // PUSHA - dword old_esp = m_tss.esp; - push_value_on_stack(m_tss.eax); - push_value_on_stack(m_tss.ecx); - push_value_on_stack(m_tss.edx); - push_value_on_stack(m_tss.ebx); - push_value_on_stack(old_esp); - push_value_on_stack(m_tss.ebp); - push_value_on_stack(m_tss.esi); - push_value_on_stack(m_tss.edi); + // PUSH old_signal_mask + push_value_on_stack(old_signal_mask); - m_tss.eax = (dword)signal; m_tss.cs = 0x1b; m_tss.ds = 0x23; m_tss.es = 0x23; @@ -957,6 +970,12 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) 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++ = 0x5a; // pop edx + *code_ptr++ = 0xb8; // mov eax, + *(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 @@ -964,7 +983,12 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) *code_ptr++ = 0x0b; m_return_to_ring0_from_signal_trampoline = LinearAddress((dword)code_ptr); - *code_ptr++ = 0x61; // popa + *code_ptr++ = 0x5a; // pop edx + *code_ptr++ = 0xb8; // mov eax, + *(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*)code_ptr = Syscall::SC_sigreturn; code_ptr += sizeof(dword); @@ -972,12 +996,11 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) *code_ptr++ = 0x82; *code_ptr++ = 0x0f; // ud2 *code_ptr++ = 0x0b; - - // FIXME: For !SA_NODEFER, maybe we could do something like emitting an int 0x80 syscall here that - // unmasks the signal so it can be received again? I guess then I would need one trampoline - // per signal number if it's hard-coded, but it's just a few bytes per each. } + // FIXME: Should we worry about the stack being 16 byte aligned when entering a signal handler? + push_value_on_stack(signal); + if (interrupting_in_kernel) push_value_on_stack(m_return_to_ring0_from_signal_trampoline.get()); else @@ -987,19 +1010,25 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal) set_state(Skip1SchedulerPass); #ifdef SIGNAL_DEBUG - dbgprintf("signal: Okay, %s(%u) {%s} has been primed with signal handler %w:%x\n", name().characters(), pid(), to_string(state()), m_tss.cs, m_tss.eip); + kprintf("signal: Okay, %s(%u) {%s} has been primed with signal handler %w:%x\n", name().characters(), pid(), to_string(state()), m_tss.cs, m_tss.eip); #endif return ShouldUnblockProcess::Yes; } +int Process::sys$restore_signal_mask(dword mask) +{ + m_signal_mask = mask; + return 0; +} + void Process::sys$sigreturn() { InterruptDisabler disabler; Scheduler::prepare_to_modify_tss(*this); m_tss = m_tss_to_resume_kernel; #ifdef SIGNAL_DEBUG - dbgprintf("sys$sigreturn in %s(%u)\n", name().characters(), pid()); - dbgprintf(" -> resuming execution at %w:%x\n", m_tss.cs, m_tss.eip); + kprintf("sys$sigreturn in %s(%u)\n", name().characters(), pid()); + kprintf(" -> resuming execution at %w:%x\n", m_tss.cs, m_tss.eip); #endif set_state(Skip1SchedulerPass); Scheduler::yield(); @@ -2638,3 +2667,41 @@ void* Process::sys$get_shared_buffer(int shared_buffer_id) #endif return shared_buffer.retain(*this); } + +const char* to_string(Process::State state) +{ + switch (state) { + case Process::Invalid: return "Invalid"; + case Process::Runnable: return "Runnable"; + case Process::Running: return "Running"; + case Process::Dying: return "Dying"; + case Process::Dead: return "Dead"; + case Process::Stopped: return "Stopped"; + case Process::Skip1SchedulerPass: return "Skip1"; + case Process::Skip0SchedulerPasses: return "Skip0"; + case Process::BlockedSleep: return "Sleep"; + case Process::BlockedWait: return "Wait"; + case Process::BlockedRead: return "Read"; + case Process::BlockedWrite: return "Write"; + case Process::BlockedSignal: return "Signal"; + case Process::BlockedSelect: return "Select"; + case Process::BlockedLurking: return "Lurking"; + case Process::BlockedConnect: return "Connect"; + case Process::BeingInspected: return "Inspect"; + } + kprintf("to_string(Process::State): Invalid state: %u\n", state); + ASSERT_NOT_REACHED(); + return nullptr; +} + +const char* to_string(Process::Priority priority) +{ + switch (priority) { + case Process::LowPriority: return "Low"; + case Process::NormalPriority: return "Normal"; + case Process::HighPriority: return "High"; + } + kprintf("to_string(Process::Priority): Invalid priority: %u\n", priority); + ASSERT_NOT_REACHED(); + return nullptr; +} diff --git a/Kernel/Process.h b/Kernel/Process.h index ab8439e4aa..db1080ad52 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -227,6 +227,7 @@ public: int sys$listen(int sockfd, int backlog); int sys$accept(int sockfd, sockaddr*, socklen_t*); int sys$connect(int sockfd, const sockaddr*, socklen_t); + int sys$restore_signal_mask(dword mask); int sys$create_shared_buffer(pid_t peer_pid, size_t, void** buffer); void* sys$get_shared_buffer(int shared_buffer_id); @@ -365,7 +366,7 @@ private: size_t m_max_open_file_descriptors { 16 }; SignalActionData m_signal_action_data[32]; dword m_pending_signals { 0 }; - dword m_signal_mask { 0xffffffff }; + dword m_signal_mask { 0 }; RetainPtr m_blocked_connecting_socket; byte m_termination_status { 0 }; @@ -439,41 +440,8 @@ private: Process::State m_original_state { Process::Invalid }; }; -static inline const char* to_string(Process::State state) -{ - switch (state) { - case Process::Invalid: return "Invalid"; - case Process::Runnable: return "Runnable"; - case Process::Running: return "Running"; - case Process::Dying: return "Dying"; - case Process::Dead: return "Dead"; - case Process::Stopped: return "Stopped"; - case Process::Skip1SchedulerPass: return "Skip1"; - case Process::Skip0SchedulerPasses: return "Skip0"; - case Process::BlockedSleep: return "Sleep"; - case Process::BlockedWait: return "Wait"; - case Process::BlockedRead: return "Read"; - case Process::BlockedWrite: return "Write"; - case Process::BlockedSignal: return "Signal"; - case Process::BlockedSelect: return "Select"; - case Process::BlockedLurking: return "Lurking"; - case Process::BlockedConnect: return "Connect"; - case Process::BeingInspected: return "Inspect"; - } - ASSERT_NOT_REACHED(); - return nullptr; -} - -static inline const char* to_string(Process::Priority state) -{ - switch (state) { - case Process::LowPriority: return "Low"; - case Process::NormalPriority: return "Normal"; - case Process::HighPriority: return "High"; - } - ASSERT_NOT_REACHED(); - return nullptr; -} +extern const char* to_string(Process::State); +extern const char* to_string(Process::Priority); extern void block(Process::State); extern void sleep(dword ticks); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 2c339ea176..945be0e679 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -221,6 +221,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, return current->sys$release_shared_buffer((int)arg1); case Syscall::SC_chown: return current->sys$chown((const char*)arg1, (uid_t)arg2, (gid_t)arg3); + case Syscall::SC_restore_signal_mask: + return current->sys$restore_signal_mask((dword)arg1); default: kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index bdf5dc7fcb..f4e3255957 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -85,6 +85,7 @@ __ENUMERATE_SYSCALL(chown) \ __ENUMERATE_SYSCALL(fchmod) \ __ENUMERATE_SYSCALL(symlink) \ + __ENUMERATE_SYSCALL(restore_signal_mask) \ namespace Syscall { diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 9c1d94ebb9..300951cb4d 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -249,6 +249,7 @@ struct sigaction { #define SA_NOCLDSTOP 1 #define SA_NOCLDWAIT 2 #define SA_SIGINFO 4 +#define SA_NODEFER 0x40000000 #define SIG_BLOCK 0 #define SIG_UNBLOCK 1 -- cgit v1.2.3