From 586ca19b629d2cc93be46480839746a19298451d Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 11 Jan 2023 23:01:47 +0100 Subject: [PATCH] Add a VERY BASIC and hacky way of allocating memory from userspace Only supports one-page allocations and doesn't have libc wrappers, which means it has to be invoked using syscall(). --- apps/app.c | 19 ++++++++++ kernel/CMakeLists.txt | 1 + kernel/src/sys/allocate_memory.cpp | 60 ++++++++++++++++++++++++++++++ kernel/src/thread/Scheduler.cpp | 6 +++ kernel/src/thread/Thread.h | 3 ++ libc/include/bits/mmap-flags.h | 11 ++++++ luna/include/luna/Syscall.h | 2 +- 7 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 kernel/src/sys/allocate_memory.cpp create mode 100644 libc/include/bits/mmap-flags.h diff --git a/apps/app.c b/apps/app.c index f87ff701..4ece3e50 100644 --- a/apps/app.c +++ b/apps/app.c @@ -1,6 +1,11 @@ +#include +#include #include #include +#include +#include #include +#include void bye() { @@ -18,4 +23,18 @@ int main() for (int i = 0; i < atoi("8"); i++) { console_write(".", 1); } console_write("\n", 1); + + long rc = syscall(SYS_allocate_memory, 4096, PROT_READ | PROT_WRITE); + if (rc < 0) + { + printf("allocate_memory: %s\n", strerror(-rc)); + return 1; + } + char* address = (char*)rc; + printf("address: %p\n", address); + printf("memory at address: %c\n", *address); + *address = 'e'; + printf("memory at address: %c\n", *address); + + syscall(SYS_deallocate_memory, address); } diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 22f2b7ab..2682dcc9 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -19,6 +19,7 @@ set(SOURCES src/sys/exit.cpp src/sys/console_write.cpp src/sys/clock_gettime.cpp + src/sys/allocate_memory.cpp src/InitRD.cpp src/ELF.cpp ) diff --git a/kernel/src/sys/allocate_memory.cpp b/kernel/src/sys/allocate_memory.cpp new file mode 100644 index 00000000..84083cc7 --- /dev/null +++ b/kernel/src/sys/allocate_memory.cpp @@ -0,0 +1,60 @@ +#include "Log.h" +#include "arch/MMU.h" +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include +#include + +constexpr uintptr_t USERSPACE_HEAP_BASE = 0x3000000; + +Result sys_allocate_memory(Registers*, SyscallArgs args) +{ + usize size = (usize)args[0]; + int flags = (int)args[1]; + + if (size != ARCH_PAGE_SIZE) return err(EINVAL); + if (flags < 0) return err(EINVAL); + + if (size == 0) return 0; + + Thread* current = Scheduler::current(); + if (!current->heap_bitmap.initialized()) + { + void* bitmap_location = (void*)TRY(MemoryManager::alloc_for_kernel(1, MMU::ReadWrite)); + current->heap_bitmap.initialize(bitmap_location, ARCH_PAGE_SIZE); + current->heap_bitmap.clear(false); + } + + u64 index = TRY(Result::from_option(current->heap_bitmap.find_and_toggle(false), ENOMEM)); + + u64 address = USERSPACE_HEAP_BASE + (index * 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; + + kdbgln("allocate_memory: allocating memory at %#lx", address); + + return MemoryManager::alloc_at(address, 1, mmu_flags); +} + +Result sys_deallocate_memory(Registers*, SyscallArgs args) +{ + u64 address = (u64)args[0]; + + Thread* current = Scheduler::current(); + if (!current->heap_bitmap.initialized()) return err(EFAULT); + + u64 index = (address - USERSPACE_HEAP_BASE) / ARCH_PAGE_SIZE; + + if (!current->heap_bitmap.get(index)) return err(EFAULT); + + current->heap_bitmap.set(index, false); + + kdbgln("deallocate_memory: deallocating memory at %#lx", address); + + TRY(MemoryManager::unmap_owned(address, 1)); + + return { 0 }; +} diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index f6730d2c..79e2b56e 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -4,6 +4,7 @@ #include "arch/CPU.h" #include "arch/MMU.h" #include "memory/MemoryManager.h" +#include #include #include @@ -177,6 +178,11 @@ namespace Scheduler if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory); + if (thread->heap_bitmap.initialized()) + MemoryManager::unmap_owned_and_free_vm( + (u64)thread->heap_bitmap.location(), + get_blocks_from_size(thread->heap_bitmap.size_in_bytes(), ARCH_PAGE_SIZE)); + delete thread; } diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 3b37923a..fbcae6db 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -1,6 +1,7 @@ #pragma once #include "arch/MMU.h" +#include #include #include #include @@ -35,6 +36,8 @@ struct Thread : public LinkedListNode Stack stack; Stack kernel_stack; + Bitmap heap_bitmap; + ThreadState state = ThreadState::Runnable; bool is_kernel { true }; diff --git a/libc/include/bits/mmap-flags.h b/libc/include/bits/mmap-flags.h new file mode 100644 index 00000000..2a89537d --- /dev/null +++ b/libc/include/bits/mmap-flags.h @@ -0,0 +1,11 @@ +/* bits/mmap-flags.h: PROT_* constants for mmap(). */ + +#ifndef _BITS_MMAP_FLAGS_H +#define _BITS_MMAP_FLAGS_H + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#endif diff --git a/luna/include/luna/Syscall.h b/luna/include/luna/Syscall.h index 2b36b2e9..96277f77 100644 --- a/luna/include/luna/Syscall.h +++ b/luna/include/luna/Syscall.h @@ -1,6 +1,6 @@ #pragma once -#define enumerate_syscalls(_e) _e(exit) _e(console_write) _e(clock_gettime) +#define enumerate_syscalls(_e) _e(exit) _e(console_write) _e(clock_gettime) _e(allocate_memory) _e(deallocate_memory) enum Syscalls {