kernel+libc: Remove (de)allocate_memory and replace it with POSIX mmap
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-03-14 20:43:15 +01:00
parent 80a897fbc5
commit 08c888eaae
Signed by: apio
GPG Key ID: B8A7D06E42258954
9 changed files with 106 additions and 72 deletions

View File

@ -24,7 +24,7 @@ set(SOURCES
src/sys/exit.cpp src/sys/exit.cpp
src/sys/console_write.cpp src/sys/console_write.cpp
src/sys/clock_gettime.cpp src/sys/clock_gettime.cpp
src/sys/allocate_memory.cpp src/sys/mmap.cpp
src/sys/usleep.cpp src/sys/usleep.cpp
src/sys/open.cpp src/sys/open.cpp
src/sys/file.cpp src/sys/file.cpp

View File

@ -78,30 +78,33 @@ Result<u64> UserVM::alloc_several_pages(usize count)
return VM_BASE + index * ARCH_PAGE_SIZE; return VM_BASE + index * ARCH_PAGE_SIZE;
} }
Result<void> UserVM::free_one_page(u64 address) Result<bool> UserVM::free_one_page(u64 address)
{ {
if (address < VM_BASE) return err(EINVAL); if (address < VM_BASE) return err(EINVAL);
const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE; const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE;
if (index > (MAX_VM_SIZE * 8)) return err(EINVAL); if (index > (MAX_VM_SIZE * 8)) return err(EINVAL);
if (!m_bitmap.get(index)) return err(EFAULT); // NOTE: POSIX says munmap() should silently do nothing if the address is not mapped, instead of throwing an error
// like EFAULT.
if (!m_bitmap.get(index)) return false;
m_bitmap.set(index, false); m_bitmap.set(index, false);
return {}; return true;
} }
Result<void> UserVM::free_several_pages(u64 address, usize count) Result<bool> UserVM::free_several_pages(u64 address, usize count)
{ {
if (address < VM_BASE) return err(EINVAL); if (address < VM_BASE) return err(EINVAL);
const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE; const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE;
if ((index + count) > (MAX_VM_SIZE * 8)) return err(EINVAL); if ((index + count) > (MAX_VM_SIZE * 8)) return err(EINVAL);
if (!TRY(m_bitmap.try_match_region(index, count, true))) return err(EFAULT); // NOTE: Same as above.
if (!TRY(m_bitmap.try_match_region(index, count, true))) return false;
m_bitmap.clear_region(index, count, false); m_bitmap.clear_region(index, count, false);
return {}; return true;
} }
UserVM::~UserVM() UserVM::~UserVM()

View File

@ -12,8 +12,8 @@ class UserVM
Result<u64> alloc_one_page(); Result<u64> alloc_one_page();
Result<u64> alloc_several_pages(usize count); Result<u64> alloc_several_pages(usize count);
Result<void> free_one_page(u64 address); Result<bool> free_one_page(u64 address);
Result<void> free_several_pages(u64 address, usize count); Result<bool> free_several_pages(u64 address, usize count);
static Result<OwnedPtr<UserVM>> try_create(); static Result<OwnedPtr<UserVM>> try_create();

View File

@ -1,53 +0,0 @@
#include "Log.h"
#include "arch/MMU.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/mmap-flags.h>
#include <luna/Alignment.h>
constexpr uintptr_t USERSPACE_HEAP_BASE = 0x3000000;
Result<u64> sys_allocate_memory(Registers*, SyscallArgs args)
{
usize size = (usize)args[0];
int flags = (int)args[1];
if (flags < 0) return err(EINVAL);
if (size == 0) return 0;
size = align_up<ARCH_PAGE_SIZE>(size);
Thread* current = Scheduler::current();
u64 address = TRY(current->vm_allocator->alloc_several_pages(size / ARCH_PAGE_SIZE));
int mmu_flags = MMU::User | MMU::NoExecute;
if (flags & PROT_WRITE) mmu_flags |= MMU::ReadWrite;
if (flags & PROT_EXEC) mmu_flags &= ~MMU::NoExecute;
if (flags == PROT_NONE) mmu_flags = MMU::NoExecute;
kdbgln("allocate_memory: allocating memory at %#lx, size=%zu", address, size);
return MemoryManager::alloc_at(address, size / ARCH_PAGE_SIZE, mmu_flags);
}
Result<u64> sys_deallocate_memory(Registers*, SyscallArgs args)
{
u64 address = (u64)args[0];
usize size = (usize)args[1];
if (size == 0) return 0;
size = align_up<ARCH_PAGE_SIZE>(size);
Thread* current = Scheduler::current();
TRY(current->vm_allocator->free_several_pages(address, size / ARCH_PAGE_SIZE));
kdbgln("deallocate_memory: deallocating memory at %#lx, size=%zu", address, size);
TRY(MemoryManager::unmap_owned(address, size / ARCH_PAGE_SIZE));
return { 0 };
}

77
kernel/src/sys/mmap.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "Log.h"
#include "arch/MMU.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/mmap-flags.h>
#include <luna/Alignment.h>
constexpr uintptr_t USERSPACE_HEAP_BASE = 0x3000000;
Result<u64> sys_mmap(Registers*, SyscallArgs args)
{
void* addr = (void*)args[0];
usize len = (usize)args[1];
int prot = (int)args[2];
int flags = (int)args[3];
if (len == 0) return err(EINVAL);
if (flags < 0) return err(EINVAL);
// We support only anonymous mappings for now.
if ((flags & MAP_ANONYMOUS) != MAP_ANONYMOUS)
{
kwarnln("mmap: FIXME: attempt to mmap file instead of anonymous memory");
return err(ENOTSUP);
}
if (flags & MAP_SHARED)
{
kwarnln("mmap: FIXME: attempt to mmap shared memory");
return err(ENOTSUP);
}
len = align_up<ARCH_PAGE_SIZE>(len);
Thread* current = Scheduler::current();
u64 address;
if (!addr) address = TRY(current->vm_allocator->alloc_several_pages(len / ARCH_PAGE_SIZE));
else
{
kwarnln("mmap: FIXME: tried to mmap at a given address, instead of letting us choose");
return err(ENOTSUP);
}
int mmu_flags = MMU::User | MMU::NoExecute;
if (prot & PROT_WRITE) mmu_flags |= MMU::ReadWrite;
if (prot & PROT_EXEC) mmu_flags &= ~MMU::NoExecute;
if (prot == PROT_NONE) mmu_flags = MMU::NoExecute;
kdbgln("mmap: mapping memory at %#lx, size=%zu", address, len);
return MemoryManager::alloc_at(address, len / ARCH_PAGE_SIZE, mmu_flags);
}
Result<u64> sys_munmap(Registers*, SyscallArgs args)
{
u64 address = (u64)args[0];
usize size = (usize)args[1];
if (size == 0) return err(EINVAL);
if (!is_aligned<ARCH_PAGE_SIZE>(size)) return err(EINVAL);
Thread* current = Scheduler::current();
bool ok = TRY(current->vm_allocator->free_several_pages(address, size / ARCH_PAGE_SIZE));
// POSIX says munmap should silently do nothing if the memory was not already mapped.
if (!ok) return 0;
kdbgln("munmap: unmapping memory at %#lx, size=%zu", address, size);
TRY(MemoryManager::unmap_owned(address, size / ARCH_PAGE_SIZE));
return { 0 };
}

View File

@ -8,4 +8,8 @@
#define PROT_WRITE 2 #define PROT_WRITE 2
#define PROT_EXEC 4 #define PROT_EXEC 4
#define MAP_PRIVATE 0
#define MAP_SHARED 1
#define MAP_ANONYMOUS 2
#endif #endif

View File

@ -15,8 +15,11 @@ extern "C"
{ {
#endif #endif
void* allocate_memory(size_t size, int flags); /* Map a file into memory. */
int deallocate_memory(void* address, size_t size); void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
/* Remove a memory mapping. */
int munmap(void* addr, size_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -7,29 +7,29 @@
extern "C" extern "C"
{ {
void* allocate_memory(size_t size, int flags) void* mmap(void* addr, size_t len, int prot, int flags, int, off_t)
{ {
long rc = syscall(SYS_allocate_memory, size, flags); long rc = syscall(SYS_mmap, addr, len, prot, flags);
__errno_return(rc, void*); __errno_return(rc, void*);
} }
int deallocate_memory(void* address, size_t size) int munmap(void* addr, size_t len)
{ {
long rc = syscall(SYS_deallocate_memory, address, size); long rc = syscall(SYS_munmap, addr, len);
__errno_return(rc, int); __errno_return(rc, int);
} }
} }
Result<void*> allocate_pages_impl(usize count) Result<void*> allocate_pages_impl(usize count)
{ {
long rc = syscall(SYS_allocate_memory, count * PAGE_SIZE, PROT_READ | PROT_WRITE); long rc = syscall(SYS_mmap, nullptr, count * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS);
if (rc < 0) { return err((int)-rc); } if (rc < 0) { return err((int)-rc); }
return (void*)rc; return (void*)rc;
} }
Result<void> release_pages_impl(void* address, usize count) Result<void> release_pages_impl(void* address, usize count)
{ {
long rc = syscall(SYS_deallocate_memory, address, count * PAGE_SIZE); long rc = syscall(SYS_munmap, address, count * PAGE_SIZE);
if (rc < 0) { return err((int)-rc); } if (rc < 0) { return err((int)-rc); }
return {}; return {};
} }

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#define enumerate_syscalls(_e) \ #define enumerate_syscalls(_e) \
_e(exit) _e(console_write) _e(clock_gettime) _e(allocate_memory) _e(deallocate_memory) _e(usleep) _e(open) \ _e(exit) _e(console_write) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) \
_e(close) _e(read) _e(getpid) _e(write) _e(lseek) _e(mkdir) _e(write) _e(lseek) _e(mkdir)
enum Syscalls enum Syscalls
{ {