diff --git a/Kernel/Arch/aarch64/Processor.cpp b/Kernel/Arch/aarch64/Processor.cpp index d421cf6505..cfd0b9aacd 100644 --- a/Kernel/Arch/aarch64/Processor.cpp +++ b/Kernel/Arch/aarch64/Processor.cpp @@ -292,10 +292,9 @@ void Processor::enter_trap(TrapFrame& trap, bool raise_irq) auto& current_trap = current_thread->current_trap(); trap.next_trap = current_trap; current_trap = &trap; - // FIXME: Determine PreviousMode from TrapFrame when userspace programs can run on aarch64 - auto new_previous_mode = Thread::PreviousMode::KernelMode; + auto new_previous_mode = trap.regs->previous_mode(); if (current_thread->set_previous_mode(new_previous_mode)) { - current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), new_previous_mode == Thread::PreviousMode::KernelMode, false); + current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), new_previous_mode == ExecutionMode::Kernel, false); } } else { trap.next_trap = nullptr; @@ -321,15 +320,14 @@ void Processor::exit_trap(TrapFrame& trap) if (current_thread) { auto& current_trap = current_thread->current_trap(); current_trap = trap.next_trap; - Thread::PreviousMode new_previous_mode; + ExecutionMode new_previous_mode; if (current_trap) { VERIFY(current_trap->regs); - // FIXME: Determine PreviousMode from TrapFrame when userspace programs can run on aarch64 - new_previous_mode = Thread::PreviousMode::KernelMode; + new_previous_mode = current_trap->regs->previous_mode(); } else { // If we don't have a higher level trap then we're back in user mode. // Which means that the previous mode prior to being back in user mode was kernel mode - new_previous_mode = Thread::PreviousMode::KernelMode; + new_previous_mode = ExecutionMode::Kernel; } if (current_thread->set_previous_mode(new_previous_mode)) diff --git a/Kernel/Arch/aarch64/RegisterState.h b/Kernel/Arch/aarch64/RegisterState.h index fd456f0306..e7a1502084 100644 --- a/Kernel/Arch/aarch64/RegisterState.h +++ b/Kernel/Arch/aarch64/RegisterState.h @@ -8,6 +8,8 @@ #include +#include + #include VALIDATE_IS_AARCH64() @@ -33,6 +35,11 @@ struct RegisterState { TODO_AARCH64(); } FlatPtr bp() const { TODO_AARCH64(); } + + ExecutionMode previous_mode() const + { + return ((spsr_el1 & 0b1111) == 0) ? ExecutionMode::User : ExecutionMode::Kernel; + } }; inline void copy_kernel_registers_into_ptrace_registers(PtraceRegisters& ptrace_regs, RegisterState const& kernel_regs) diff --git a/Kernel/Arch/x86_64/CrashHandler.cpp b/Kernel/Arch/x86_64/CrashHandler.cpp index c33276717a..10130cb990 100644 --- a/Kernel/Arch/x86_64/CrashHandler.cpp +++ b/Kernel/Arch/x86_64/CrashHandler.cpp @@ -19,7 +19,7 @@ void handle_crash(Kernel::RegisterState const& regs, char const* description, in if (!current_thread) PANIC("{} with !Thread::current()", description); - auto crashed_in_kernel = (regs.cs & 3) == 0; + auto crashed_in_kernel = regs.previous_mode() == ExecutionMode::Kernel; if (!crashed_in_kernel && current_thread->has_signal_handler(signal) && !current_thread->should_ignore_signal(signal) && !current_thread->is_signal_masked(signal)) { current_thread->send_urgent_signal_to_self(signal); return; @@ -31,7 +31,7 @@ void handle_crash(Kernel::RegisterState const& regs, char const* description, in // make sure we switch back to the right page tables. Memory::MemoryManager::enter_process_address_space(process); - dmesgln("CRASH: CPU #{} {} in ring {}", Processor::current_id(), description, (regs.cs & 3)); + dmesgln("CRASH: CPU #{} {} in {}", Processor::current_id(), description, regs.previous_mode() == ExecutionMode::Kernel ? "kernel"sv : "userspace"sv); dump_registers(regs); if (crashed_in_kernel) { diff --git a/Kernel/Arch/x86_64/Processor.cpp b/Kernel/Arch/x86_64/Processor.cpp index a169988e8a..20b6cb26df 100644 --- a/Kernel/Arch/x86_64/Processor.cpp +++ b/Kernel/Arch/x86_64/Processor.cpp @@ -918,10 +918,10 @@ void Processor::enter_trap(TrapFrame& trap, bool raise_irq) auto& current_trap = current_thread->current_trap(); trap.next_trap = current_trap; current_trap = &trap; - // The cs register of this trap tells us where we will return back to - auto new_previous_mode = ((trap.regs->cs & 3) != 0) ? Thread::PreviousMode::UserMode : Thread::PreviousMode::KernelMode; + + auto new_previous_mode = trap.regs->previous_mode(); if (current_thread->set_previous_mode(new_previous_mode) && trap.prev_irq_level == 0) { - current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), new_previous_mode == Thread::PreviousMode::KernelMode, false); + current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), new_previous_mode == ExecutionMode::Kernel, false); } } else { trap.next_trap = nullptr; @@ -954,17 +954,16 @@ void Processor::exit_trap(TrapFrame& trap) if (current_thread) { auto& current_trap = current_thread->current_trap(); current_trap = trap.next_trap; - Thread::PreviousMode new_previous_mode; + ExecutionMode new_previous_mode; if (current_trap) { VERIFY(current_trap->regs); // If we have another higher level trap then we probably returned - // from an interrupt or irq handler. The cs register of the - // new/higher level trap tells us what the mode prior to it was - new_previous_mode = ((current_trap->regs->cs & 3) != 0) ? Thread::PreviousMode::UserMode : Thread::PreviousMode::KernelMode; + // from an interrupt or irq handler. + new_previous_mode = current_trap->regs->previous_mode(); } else { // If we don't have a higher level trap then we're back in user mode. // Which means that the previous mode prior to being back in user mode was kernel mode - new_previous_mode = Thread::PreviousMode::KernelMode; + new_previous_mode = ExecutionMode::Kernel; } if (current_thread->set_previous_mode(new_previous_mode)) diff --git a/Kernel/Arch/x86_64/RegisterState.h b/Kernel/Arch/x86_64/RegisterState.h index abdf67b9d8..21ed49f463 100644 --- a/Kernel/Arch/x86_64/RegisterState.h +++ b/Kernel/Arch/x86_64/RegisterState.h @@ -11,6 +11,7 @@ #include #include +#include #include VALIDATE_IS_X86() @@ -68,6 +69,11 @@ struct [[gnu::packed]] RegisterState { arg3 = rbx; arg4 = rsi; } + + ExecutionMode previous_mode() const + { + return ((cs & 3) != 0) ? ExecutionMode::User : ExecutionMode::Kernel; + } }; #define REGISTER_STATE_SIZE (22 * 8) diff --git a/Kernel/ExecutionMode.h b/Kernel/ExecutionMode.h new file mode 100644 index 0000000000..b84e7e66e0 --- /dev/null +++ b/Kernel/ExecutionMode.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Kernel { + +enum class ExecutionMode : u8 { + Kernel = 0, + User, +}; + +} diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 15c3d110f0..789b43da54 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -427,7 +427,7 @@ void Scheduler::timer_tick(RegisterState const& regs) current_thread->update_time_scheduled(TimeManagement::scheduler_current_time(), true, false); } - if (current_thread->previous_mode() == Thread::PreviousMode::UserMode && current_thread->should_die() && !current_thread->is_blocked()) { + if (current_thread->previous_mode() == ExecutionMode::User && current_thread->should_die() && !current_thread->is_blocked()) { SpinlockLocker scheduler_lock(g_scheduler_lock); dbgln_if(SCHEDULER_DEBUG, "Scheduler[{}]: Terminating user mode thread {}", Processor::current_id(), *current_thread); current_thread->set_state(Thread::State::Dying); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index de769c04c1..bb01695bb3 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -145,7 +145,7 @@ NEVER_INLINE void syscall_handler(TrapFrame* trap) auto& regs = *trap->regs; auto* current_thread = Thread::current(); - VERIFY(current_thread->previous_mode() == Thread::PreviousMode::UserMode); + VERIFY(current_thread->previous_mode() == ExecutionMode::User); auto& process = current_thread->process(); if (process.is_dying()) { // It's possible this thread is just about to make a syscall while another is @@ -205,7 +205,7 @@ NEVER_INLINE void syscall_handler(TrapFrame* trap) current_thread->check_dispatch_pending_signal(); // If the previous mode somehow changed something is seriously messed up... - VERIFY(current_thread->previous_mode() == Thread::PreviousMode::UserMode); + VERIFY(current_thread->previous_mode() == ExecutionMode::User); // Check if we're supposed to return to userspace or just die. current_thread->die_if_needed(); diff --git a/Kernel/Syscalls/exit.cpp b/Kernel/Syscalls/exit.cpp index cf1f0c400e..ef5d5450c1 100644 --- a/Kernel/Syscalls/exit.cpp +++ b/Kernel/Syscalls/exit.cpp @@ -14,7 +14,7 @@ namespace Kernel { void Process::sys$exit(int status) { // FIXME: We have callers from kernel which don't acquire the big process lock. - if (Thread::current()->previous_mode() == Thread::PreviousMode::UserMode) { + if (Thread::current()->previous_mode() == ExecutionMode::User) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); } diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 3f892fad61..b4cbfe7946 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -631,7 +631,7 @@ void Thread::update_time_scheduled(u64 current_scheduler_time, bool is_kernel, b bool Thread::tick() { - if (previous_mode() == PreviousMode::KernelMode) { + if (previous_mode() == ExecutionMode::Kernel) { ++m_process->m_ticks_in_kernel; ++m_ticks_in_kernel; } else { diff --git a/Kernel/Thread.h b/Kernel/Thread.h index b8b2a55e1e..a45889c2ea 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -987,12 +987,8 @@ public: u64 time_in_user() const { return m_total_time_scheduled_user.load(AK::MemoryOrder::memory_order_relaxed); } u64 time_in_kernel() const { return m_total_time_scheduled_kernel.load(AK::MemoryOrder::memory_order_relaxed); } - enum class PreviousMode : u8 { - KernelMode = 0, - UserMode - }; - PreviousMode previous_mode() const { return m_previous_mode; } - bool set_previous_mode(PreviousMode mode) + ExecutionMode previous_mode() const { return m_previous_mode; } + bool set_previous_mode(ExecutionMode mode) { if (m_previous_mode == mode) return false; @@ -1215,7 +1211,7 @@ private: Atomic m_is_active { false }; bool m_is_joinable { true }; bool m_handling_page_fault { false }; - PreviousMode m_previous_mode { PreviousMode::KernelMode }; // We always start out in kernel mode + ExecutionMode m_previous_mode { ExecutionMode::Kernel }; // We always start out in kernel mode unsigned m_syscall_count { 0 }; unsigned m_inode_faults { 0 };