Kernel: Don't clone entire kernel stack on fork

We only need to copy area between [ret_sp, stack_end]. This range is
always very small compared to the whole stack (64 KiB).
This commit is contained in:
2026-04-04 23:26:39 +03:00
parent 9d83424346
commit 9fce114e8e
3 changed files with 26 additions and 41 deletions

View File

@@ -20,8 +20,6 @@ namespace Kernel
static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages); static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages);
~VirtualRange(); ~VirtualRange();
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> clone(PageTable&);
vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); } vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); }
size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); } size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); }
PageTable::flags_t flags() const { return m_flags; } PageTable::flags_t flags() const { return m_flags; }

View File

@@ -110,36 +110,6 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> VirtualRange::clone(PageTable& page_table)
{
ASSERT(&PageTable::current() == &m_page_table);
ASSERT(&m_page_table != &page_table);
SpinLockGuard _(m_lock);
auto result = TRY(create_to_vaddr(page_table, vaddr(), size(), m_flags, m_preallocated, m_has_guard_pages));
const size_t page_count = size() / PAGE_SIZE;
for (size_t i = 0; i < page_count; i++)
{
if (m_paddrs[i] == 0)
continue;
if (!result->m_preallocated)
{
result->m_paddrs[i] = Heap::get().take_free_page();
if (result->m_paddrs[i] == 0)
return BAN::Error::from_errno(ENOMEM);
result->m_page_table.map_page_at(result->m_paddrs[i], vaddr() + i * PAGE_SIZE, m_flags);
}
PageTable::with_fast_page(result->m_paddrs[i], [&] {
memcpy(PageTable::fast_page_as_ptr(), reinterpret_cast<void*>(vaddr() + i * PAGE_SIZE), PAGE_SIZE);
});
}
return result;
}
BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr) BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
{ {
ASSERT(contains(vaddr)); ASSERT(contains(vaddr));

View File

@@ -13,6 +13,12 @@
namespace Kernel namespace Kernel
{ {
#if ARCH(x86_64)
static constexpr vaddr_t s_user_stack_addr_start = 0x0000700000000000;
#elif ARCH(i686)
static constexpr vaddr_t s_user_stack_addr_start = 0xB0000000;
#endif
extern "C" [[noreturn]] void start_kernel_thread(); extern "C" [[noreturn]] void start_kernel_thread();
extern "C" [[noreturn]] void start_userspace_thread(); extern "C" [[noreturn]] void start_userspace_thread();
@@ -200,15 +206,9 @@ namespace Kernel
thread->m_is_userspace = true; thread->m_is_userspace = true;
#if ARCH(x86_64)
static constexpr vaddr_t stack_addr_start = 0x0000700000000000;
#elif ARCH(i686)
static constexpr vaddr_t stack_addr_start = 0xB0000000;
#endif
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range( thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
page_table, page_table,
stack_addr_start, USERSPACE_END, s_user_stack_addr_start, USERSPACE_END,
kernel_stack_size, kernel_stack_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present, PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true, true true, true
@@ -217,7 +217,7 @@ namespace Kernel
auto userspace_stack = TRY(MemoryBackedRegion::create( auto userspace_stack = TRY(MemoryBackedRegion::create(
page_table, page_table,
userspace_stack_size, userspace_stack_size,
{ stack_addr_start, USERSPACE_END }, { s_user_stack_addr_start, USERSPACE_END },
MemoryRegion::Type::PRIVATE, MemoryRegion::Type::PRIVATE,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
O_RDWR O_RDWR
@@ -346,7 +346,24 @@ namespace Kernel
thread->m_is_userspace = true; thread->m_is_userspace = true;
thread->m_kernel_stack = TRY(m_kernel_stack->clone(new_process->page_table())); thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
new_process->page_table(),
s_user_stack_addr_start, USERSPACE_END,
kernel_stack_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
true, true
));
// NOTE: copy [sp, stack_end] so fork return works
PageTable::with_fast_page(thread->m_kernel_stack->paddr_of(thread->kernel_stack_top() - PAGE_SIZE), [&] {
const size_t ncopy = kernel_stack_top() - sp;
ASSERT(ncopy <= PAGE_SIZE);
memcpy(
PageTable::fast_page_as_ptr(PAGE_SIZE - ncopy),
reinterpret_cast<void*>(sp),
ncopy
);
});
const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr()); const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr());
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr()); thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());