Kernel: Make on-demand paging thread safe

This commit is contained in:
Bananymous 2025-08-03 21:46:16 +03:00
parent d25a5034db
commit 927fbda1e8
3 changed files with 17 additions and 9 deletions

View File

@ -220,7 +220,7 @@ namespace Kernel
// Returns error if page could not be allocated
// Returns true if the page was allocated successfully
// Return false if access was page violation (segfault)
BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t addr, bool wants_write);
BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t addr, bool wants_write, bool wants_exec);
// FIXME: remove this API
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;

View File

@ -214,7 +214,7 @@ namespace Kernel
page_fault_error.raw = error;
Processor::set_interrupt_state(InterruptState::Enabled);
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write);
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2, page_fault_error.write, page_fault_error.instruction);
Processor::set_interrupt_state(InterruptState::Disabled);
if (!result.is_error() && result.value())

View File

@ -981,24 +981,32 @@ namespace Kernel
return {};
}
BAN::ErrorOr<bool> Process::allocate_page_for_demand_paging(vaddr_t address, bool wants_write)
BAN::ErrorOr<bool> Process::allocate_page_for_demand_paging(vaddr_t address, bool wants_write, bool wants_exec)
{
ASSERT(&Process::current() == this);
LockGuard _(m_process_lock);
if (Thread::current().userspace_stack().contains(address))
{
TRY(Thread::current().userspace_stack().allocate_page_for_demand_paging(address));
return true;
// NOTE: page can be already allocated by another thread!
PageTable::flags_t wanted_flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
if (wants_write)
wanted_flags |= PageTable::Flags::ReadWrite;
if (wants_exec)
wanted_flags |= PageTable::Flags::Execute;
if ((m_page_table->get_page_flags(address & PAGE_ADDR_MASK) & wanted_flags) == wanted_flags)
return true;
}
if (Thread::current().userspace_stack().contains(address))
return Thread::current().userspace_stack().allocate_page_for_demand_paging(address);
for (auto& region : m_mapped_regions)
{
if (!region->contains(address))
continue;
TRY(region->allocate_page_containing(address, wants_write));
return true;
return region->allocate_page_containing(address, wants_write);
}
return false;
@ -3112,7 +3120,7 @@ unauthorized_access:
const vaddr_t current = page_start + i * PAGE_SIZE;
if (page_table().get_page_flags(current) & PageTable::Flags::Present)
continue;
TRY(Process::allocate_page_for_demand_paging(current, needs_write));
TRY(Process::allocate_page_for_demand_paging(current, needs_write, false));
}
return {};