1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 03:08:13 +00:00

Kernel: Track previous mode when entering/exiting traps

This allows us to determine what the previous mode (user or kernel)
was, e.g. in the timer interrupt. This is used e.g. to determine
whether a signal handler should be set up.

Fixes #5096
This commit is contained in:
Tom 2021-01-25 13:19:34 -07:00 committed by Andreas Kling
parent fa18010477
commit 0bd558081e
6 changed files with 70 additions and 7 deletions

View file

@ -1463,6 +1463,7 @@ u32 Processor::init_context(Thread& thread, bool leave_crit)
TrapFrame& trap = *reinterpret_cast<TrapFrame*>(stack_top);
trap.regs = &iretframe;
trap.prev_irq_level = 0;
trap.next_trap = nullptr;
stack_top -= sizeof(u32); // pointer to TrapFrame
*reinterpret_cast<u32*>(stack_top) = stack_top + 4;
@ -1612,6 +1613,15 @@ void Processor::enter_trap(TrapFrame& trap, bool raise_irq)
trap.prev_irq_level = m_in_irq;
if (raise_irq)
m_in_irq++;
if (m_current_thread) {
auto& current_trap = m_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
m_current_thread->set_previous_mode(((trap.regs->cs & 3) != 0) ? Thread::PreviousMode::UserMode : Thread::PreviousMode::KernelMode);
} else {
trap.next_trap = nullptr;
}
}
void Processor::exit_trap(TrapFrame& trap)
@ -1624,6 +1634,21 @@ void Processor::exit_trap(TrapFrame& trap)
if (!m_in_irq && !m_in_critical)
check_invoke_scheduler();
if (m_current_thread) {
auto& current_trap = m_current_thread->current_trap();
current_trap = trap.next_trap;
if (current_trap) {
// 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
m_current_thread->set_previous_mode(((current_trap->regs->cs & 3) != 0) ? Thread::PreviousMode::UserMode : Thread::PreviousMode::KernelMode);
} else {
// If we don't have a higher level trap then we're back in user mode.
// Unless we're a kernel process, in which case we're always in kernel mode
m_current_thread->set_previous_mode(m_current_thread->process().is_kernel_process() ? Thread::PreviousMode::KernelMode : Thread::PreviousMode::UserMode);
}
}
}
void Processor::check_invoke_scheduler()