kernel: Move stack checking and expansion into an architecture-independent file
Some checks failed
Build and test / build (push) Failing after 1m45s
Some checks failed
Build and test / build (push) Failing after 1m45s
This commit is contained in:
parent
de6f5c38d8
commit
1d0f18cab9
@ -14,7 +14,6 @@
|
|||||||
#include "video/TextConsole.h"
|
#include "video/TextConsole.h"
|
||||||
#include <bits/signal.h>
|
#include <bits/signal.h>
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#include <luna/Alignment.h>
|
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
#include <luna/CircularQueue.h>
|
#include <luna/CircularQueue.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
@ -57,8 +56,6 @@ void FPData::restore()
|
|||||||
asm volatile("fxrstor (%0)" : : "r"(m_data));
|
asm volatile("fxrstor (%0)" : : "r"(m_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr usize MAX_STACK_SIZE = 8 * 1024 * 1024; // 8 MB
|
|
||||||
|
|
||||||
// Interrupt handling
|
// Interrupt handling
|
||||||
|
|
||||||
#define FIXME_UNHANDLED_INTERRUPT(name) \
|
#define FIXME_UNHANDLED_INTERRUPT(name) \
|
||||||
@ -78,63 +75,6 @@ void decode_page_fault_error_code(u64 code)
|
|||||||
(code & PF_RESERVED) ? " | Reserved bits set" : "", (code & PF_NX_VIOLATION) ? " | NX violation" : "");
|
(code & PF_RESERVED) ? " | Reserved bits set" : "", (code & PF_NX_VIOLATION) ? " | NX violation" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_stack(Thread* current, Registers* regs)
|
|
||||||
{
|
|
||||||
if (regs->rsp < current->stack.bottom() || regs->rsp >= current->stack.top())
|
|
||||||
kerrorln("Abnormal stack (RSP outside the normal range, %.16lx-%.16lx)", current->stack.bottom(),
|
|
||||||
current->stack.top());
|
|
||||||
|
|
||||||
if (regs->rsp >= (current->stack.bottom() - (ARCH_PAGE_SIZE * 8)) && regs->rsp < current->stack.bottom())
|
|
||||||
{
|
|
||||||
kerrorln("Likely stack overflow (CPU exception a few pages below the stack)");
|
|
||||||
// Try to grow the stack
|
|
||||||
// FIXME: This should be extracted into an architecture-independent file.
|
|
||||||
usize stack_space_remaining = MAX_STACK_SIZE - current->stack.bytes();
|
|
||||||
if (!stack_space_remaining)
|
|
||||||
{
|
|
||||||
kwarnln("Failed to grow stack: this thread already used up all its stack space");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
usize exceeded_bytes = align_up<ARCH_PAGE_SIZE>(current->stack.bottom() - regs->rsp);
|
|
||||||
if (exceeded_bytes > stack_space_remaining)
|
|
||||||
{
|
|
||||||
kwarnln("Failed to grow stack: this thread needs more space than the one it has remaining (%zu bytes out "
|
|
||||||
"of %zu remaining)",
|
|
||||||
exceeded_bytes, stack_space_remaining);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can, we'll add 2 more pages of buffer space, otherwise we use whatever we can.
|
|
||||||
usize bytes_to_grow = min(stack_space_remaining, exceeded_bytes + 2 * ARCH_PAGE_SIZE);
|
|
||||||
auto maybe_base =
|
|
||||||
current->address_space->grow_region(current->stack.bottom(), bytes_to_grow / ARCH_PAGE_SIZE, true);
|
|
||||||
if (maybe_base.has_error())
|
|
||||||
{
|
|
||||||
kwarnln("Failed to grow stack: could not allocate virtual memory space (%s)", maybe_base.error_string());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 base = maybe_base.release_value();
|
|
||||||
auto result = MemoryManager::alloc_at_zeroed(base, bytes_to_grow / ARCH_PAGE_SIZE,
|
|
||||||
MMU::ReadWrite | MMU::NoExecute | MMU::User);
|
|
||||||
if (result.has_error())
|
|
||||||
{
|
|
||||||
current->address_space->free_region(base, bytes_to_grow / ARCH_PAGE_SIZE);
|
|
||||||
kwarnln("Failed to grow stack: could not allocate physical pages (%s)", result.error_string());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
kinfoln("Stack expanded from %lx (%zu bytes) to %lx (%zu bytes)", current->stack.bottom(),
|
|
||||||
current->stack.bytes(), base, current->stack.bytes() + bytes_to_grow);
|
|
||||||
|
|
||||||
current->stack = Stack { base, current->stack.bytes() + bytes_to_grow };
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_cpu_exception(int signo, const char* err, Registers* regs)
|
void handle_cpu_exception(int signo, const char* err, Registers* regs)
|
||||||
{
|
{
|
||||||
if (err) kerrorln("Caught CPU exception: %s", err);
|
if (err) kerrorln("Caught CPU exception: %s", err);
|
||||||
@ -148,7 +88,7 @@ void handle_cpu_exception(int signo, const char* err, Registers* regs)
|
|||||||
if (!is_in_kernel(regs))
|
if (!is_in_kernel(regs))
|
||||||
{
|
{
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
if (check_stack(current, regs)) return;
|
if (current->check_stack_on_exception(regs->rsp)) return;
|
||||||
|
|
||||||
current->send_signal(signo);
|
current->send_signal(signo);
|
||||||
current->process_pending_signals(regs);
|
current->process_pending_signals(regs);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <bits/open-flags.h>
|
#include <bits/open-flags.h>
|
||||||
#include <bits/signal.h>
|
#include <bits/signal.h>
|
||||||
#include <bits/waitpid.h>
|
#include <bits/waitpid.h>
|
||||||
|
#include <luna/Alignment.h>
|
||||||
#include <luna/Alloc.h>
|
#include <luna/Alloc.h>
|
||||||
#include <luna/Atomic.h>
|
#include <luna/Atomic.h>
|
||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
@ -265,6 +266,66 @@ void Thread::send_signal(int signo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr usize MAX_STACK_SIZE = 8 * 1024 * 1024; // 8 MB
|
||||||
|
|
||||||
|
bool Thread::check_stack_on_exception(u64 stack_pointer)
|
||||||
|
{
|
||||||
|
if (stack_pointer < stack.bottom() || stack_pointer >= stack.top())
|
||||||
|
kwarnln("Abnormal stack (Stack pointer outside the normal range, %.16lx-%.16lx)", stack.bottom(), stack.top());
|
||||||
|
|
||||||
|
// Check whether the stack pointer is within 8 pages of the bottom of the stack
|
||||||
|
u64 threshold = stack.bottom() - (ARCH_PAGE_SIZE * 8);
|
||||||
|
|
||||||
|
if (stack_pointer >= threshold && stack_pointer < stack.bottom())
|
||||||
|
{
|
||||||
|
kwarnln("Likely stack overflow (CPU exception a few pages below the stack)");
|
||||||
|
|
||||||
|
// Try to grow the stack
|
||||||
|
usize stack_space_remaining = MAX_STACK_SIZE - stack.bytes();
|
||||||
|
if (!stack_space_remaining)
|
||||||
|
{
|
||||||
|
kwarnln("Failed to grow stack: this thread already used up all its stack space");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize exceeded_bytes = align_up<ARCH_PAGE_SIZE>(stack.bottom() - stack_pointer);
|
||||||
|
if (exceeded_bytes > stack_space_remaining)
|
||||||
|
{
|
||||||
|
kwarnln("Failed to grow stack: this thread needs more space than the one it has remaining (%zu bytes out "
|
||||||
|
"of %zu remaining)",
|
||||||
|
exceeded_bytes, stack_space_remaining);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can, we'll add 2 more pages of buffer space, otherwise we use whatever we can.
|
||||||
|
usize bytes_to_grow = min(stack_space_remaining, exceeded_bytes + 2 * ARCH_PAGE_SIZE);
|
||||||
|
auto maybe_base = address_space->grow_region(stack.bottom(), bytes_to_grow / ARCH_PAGE_SIZE, true);
|
||||||
|
if (maybe_base.has_error())
|
||||||
|
{
|
||||||
|
kwarnln("Failed to grow stack: could not allocate virtual memory space (%s)", maybe_base.error_string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 base = maybe_base.release_value();
|
||||||
|
auto result = MemoryManager::alloc_at_zeroed(base, bytes_to_grow / ARCH_PAGE_SIZE,
|
||||||
|
MMU::ReadWrite | MMU::NoExecute | MMU::User);
|
||||||
|
if (result.has_error())
|
||||||
|
{
|
||||||
|
address_space->free_region(base, bytes_to_grow / ARCH_PAGE_SIZE);
|
||||||
|
kwarnln("Failed to grow stack: could not allocate physical pages (%s)", result.error_string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
kinfoln("Stack expanded from %lx (%zu bytes) to %lx (%zu bytes)", stack.bottom(), stack.bytes(), base,
|
||||||
|
stack.bytes() + bytes_to_grow);
|
||||||
|
|
||||||
|
stack = Stack { base, stack.bytes() + bytes_to_grow };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Thread::stop()
|
void Thread::stop()
|
||||||
{
|
{
|
||||||
state = ThreadState::Stopped;
|
state = ThreadState::Stopped;
|
||||||
|
@ -169,6 +169,8 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
Result<u64> push_mem_on_stack(const u8* mem, usize size);
|
Result<u64> push_mem_on_stack(const u8* mem, usize size);
|
||||||
Result<u64> pop_mem_from_stack(u8* mem, usize size);
|
Result<u64> pop_mem_from_stack(u8* mem, usize size);
|
||||||
|
|
||||||
|
bool Thread::check_stack_on_exception(u64 stack_pointer);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user