summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-03-05 10:34:08 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-03-05 10:34:08 +0100
commit251293f2e1178370d85c1dd4f3808ed9681fdb3c (patch)
tree6f5b3fcb24c210f5007832aa3445331b461ef830
parentb67d0a363239c3ecf72f7514da74f0536595430b (diff)
downloadserenity-251293f2e1178370d85c1dd4f3808ed9681fdb3c.zip
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.
-rw-r--r--Kernel/BXVGADevice.cpp2
-rw-r--r--Kernel/Process.cpp133
-rw-r--r--Kernel/Process.h40
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--Kernel/Syscall.h1
-rw-r--r--Kernel/UnixTypes.h1
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<String> arguments, Vector<String> 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>
+ *(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>
+ *(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);
@@ -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<Socket> 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