kernel+libc: Remove (de)allocate_memory and replace it with POSIX mmap
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
80a897fbc5
commit
08c888eaae
@ -24,7 +24,7 @@ set(SOURCES
|
||||
src/sys/exit.cpp
|
||||
src/sys/console_write.cpp
|
||||
src/sys/clock_gettime.cpp
|
||||
src/sys/allocate_memory.cpp
|
||||
src/sys/mmap.cpp
|
||||
src/sys/usleep.cpp
|
||||
src/sys/open.cpp
|
||||
src/sys/file.cpp
|
||||
|
@ -78,30 +78,33 @@ Result<u64> UserVM::alloc_several_pages(usize count)
|
||||
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);
|
||||
const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE;
|
||||
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);
|
||||
|
||||
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);
|
||||
const u64 index = (address - VM_BASE) / ARCH_PAGE_SIZE;
|
||||
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);
|
||||
|
||||
return {};
|
||||
return true;
|
||||
}
|
||||
|
||||
UserVM::~UserVM()
|
||||
|
@ -12,8 +12,8 @@ class UserVM
|
||||
Result<u64> alloc_one_page();
|
||||
Result<u64> alloc_several_pages(usize count);
|
||||
|
||||
Result<void> free_one_page(u64 address);
|
||||
Result<void> free_several_pages(u64 address, usize count);
|
||||
Result<bool> free_one_page(u64 address);
|
||||
Result<bool> free_several_pages(u64 address, usize count);
|
||||
|
||||
static Result<OwnedPtr<UserVM>> try_create();
|
||||
|
||||
|
@ -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
77
kernel/src/sys/mmap.cpp
Normal 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 };
|
||||
}
|
@ -8,4 +8,8 @@
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
|
||||
#define MAP_PRIVATE 0
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_ANONYMOUS 2
|
||||
|
||||
#endif
|
||||
|
@ -15,8 +15,11 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* allocate_memory(size_t size, int flags);
|
||||
int deallocate_memory(void* address, size_t size);
|
||||
/* Map a file into memory. */
|
||||
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
|
||||
}
|
||||
|
@ -7,29 +7,29 @@
|
||||
|
||||
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*);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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); }
|
||||
return (void*)rc;
|
||||
}
|
||||
|
||||
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); }
|
||||
return {};
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#define enumerate_syscalls(_e) \
|
||||
_e(exit) _e(console_write) _e(clock_gettime) _e(allocate_memory) _e(deallocate_memory) _e(usleep) _e(open) \
|
||||
_e(close) _e(read) _e(getpid) _e(write) _e(lseek) _e(mkdir)
|
||||
_e(exit) _e(console_write) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) \
|
||||
_e(write) _e(lseek) _e(mkdir)
|
||||
|
||||
enum Syscalls
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user