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:
@@ -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);
|
||||
~VirtualRange();
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> clone(PageTable&);
|
||||
|
||||
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); }
|
||||
PageTable::flags_t flags() const { return m_flags; }
|
||||
|
||||
@@ -110,36 +110,6 @@ namespace Kernel
|
||||
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)
|
||||
{
|
||||
ASSERT(contains(vaddr));
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
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_userspace_thread();
|
||||
|
||||
@@ -200,15 +206,9 @@ namespace Kernel
|
||||
|
||||
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(
|
||||
page_table,
|
||||
stack_addr_start, USERSPACE_END,
|
||||
s_user_stack_addr_start, USERSPACE_END,
|
||||
kernel_stack_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true, true
|
||||
@@ -217,7 +217,7 @@ namespace Kernel
|
||||
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||
page_table,
|
||||
userspace_stack_size,
|
||||
{ stack_addr_start, USERSPACE_END },
|
||||
{ s_user_stack_addr_start, USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
O_RDWR
|
||||
@@ -346,7 +346,24 @@ namespace Kernel
|
||||
|
||||
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());
|
||||
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());
|
||||
|
||||
Reference in New Issue
Block a user