1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:47:44 +00:00

Kernel: Fix retreiving frame pointer from a thread

If we're trying to walk the stack for another thread, we can
no longer retreive the EBP register from Thread::m_tss. Instead,
we need to look at the top of the kernel stack, because all threads
not currently running were last in kernel mode. Context switches
now always trigger a brief switch to kernel mode, and Thread::m_tss
only is used to save ESP and EIP.

Fixes #2678
This commit is contained in:
Tom 2020-07-03 12:12:34 -06:00 committed by Andreas Kling
parent 6d5bd8c76b
commit bb84fad0bf
4 changed files with 67 additions and 28 deletions

View file

@ -960,6 +960,45 @@ const DescriptorTablePointer& Processor::get_gdtr()
return m_gdtr;
}
bool Processor::get_context_frame_ptr(Thread& thread, u32& frame_ptr, u32& eip)
{
ScopedCritical critical;
auto& proc = Processor::current();
if (&thread == proc.current_thread()) {
ASSERT(thread.state() == Thread::Running);
asm volatile("movl %%ebp, %%eax"
: "=g"(frame_ptr));
} else {
// Since the thread may be running on another processor, there
// is a chance a context switch may happen while we're trying
// to get it. It also won't be entirely accurate and merely
// reflect the status at the last context switch.
ScopedSpinLock lock(g_scheduler_lock);
if (thread.state() == Thread::Running) {
ASSERT(thread.cpu() != proc.id());
// TODO: If this is the case, the thread is currently running
// on another processor. We can't trust the kernel stack as
// it may be changing at any time. We need to probably send
// an ICI to that processor, have it walk the stack and wait
// until it returns the data back to us
dbg() << "CPU[" << proc.id() << "] getting stack for "
<< thread << " on other CPU# " << thread.cpu() << " not yet implemented!";
frame_ptr = eip = 0; // TODO
return false;
} else {
// We need to retrieve ebp from what was last pushed to the kernel
// stack. Before switching out of that thread, it switch_context
// pushed the callee-saved registers, and the last of them happens
// to be ebp.
auto& tss = thread.tss();
u32* stack_top = reinterpret_cast<u32*>(tss.esp);
frame_ptr = stack_top[0];
eip = tss.eip;
}
}
return true;
}
extern "C" void enter_thread_context(Thread* from_thread, Thread* to_thread)
{
ASSERT(from_thread == to_thread || from_thread->state() != Thread::Running);