From d4d530e6c8c3f623be54caa8ccbba63f640e5809 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 29 May 2024 15:58:46 +0300 Subject: [PATCH] Kernel: Implement basic shared memory objects These can allocate memory that can be shared between processes using a global key. There is currenly no safety checks meaning anyone can map any shared memory object just by trying to map every possible key. --- kernel/CMakeLists.txt | 1 + .../kernel/Memory/SharedMemoryObject.h | 72 +++++++++++++++ kernel/include/kernel/Process.h | 4 + kernel/kernel/Memory/SharedMemoryObject.cpp | 88 +++++++++++++++++++ kernel/kernel/Process.cpp | 35 ++++++++ kernel/kernel/kernel.cpp | 4 + libc/include/sys/banan-os.h | 5 ++ libc/include/sys/syscall.h | 2 + libc/sys/banan-os.cpp | 13 +++ 9 files changed, 224 insertions(+) create mode 100644 kernel/include/kernel/Memory/SharedMemoryObject.h create mode 100644 kernel/kernel/Memory/SharedMemoryObject.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 61d1fe24..62446c3a 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -57,6 +57,7 @@ set(KERNEL_SOURCES kernel/Memory/MemoryBackedRegion.cpp kernel/Memory/MemoryRegion.cpp kernel/Memory/PhysicalRange.cpp + kernel/Memory/SharedMemoryObject.cpp kernel/Memory/VirtualRange.cpp kernel/Networking/ARPTable.cpp kernel/Networking/E1000/E1000.cpp diff --git a/kernel/include/kernel/Memory/SharedMemoryObject.h b/kernel/include/kernel/Memory/SharedMemoryObject.h new file mode 100644 index 00000000..79dcb650 --- /dev/null +++ b/kernel/include/kernel/Memory/SharedMemoryObject.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel +{ + + class SharedMemoryObject; + + class SharedMemoryObjectManager + { + public: + using Key = uint32_t; + + public: + static BAN::ErrorOr initialize(); + static SharedMemoryObjectManager& get(); + + BAN::ErrorOr create_object(size_t size, PageTable::flags_t); + BAN::ErrorOr> map_object(Key, PageTable&, AddressRange); + + private: + SharedMemoryObjectManager() {} + + private: + struct Object : public BAN::RefCounted + { + size_t size; + PageTable::flags_t flags; + BAN::Vector paddrs; + SpinLock spin_lock; + }; + + private: + Mutex m_mutex; + BAN::HashMap> m_objects; + + friend class SharedMemoryObject; + friend class BAN::UniqPtr; + }; + + class SharedMemoryObject : public MemoryRegion + { + BAN_NON_COPYABLE(SharedMemoryObject); + BAN_NON_MOVABLE(SharedMemoryObject); + + public: + static BAN::ErrorOr> create(BAN::RefPtr, PageTable&, AddressRange); + + virtual BAN::ErrorOr> clone(PageTable& new_page_table) override { return BAN::Error::from_errno(ENOTSUP); } + virtual BAN::ErrorOr msync(vaddr_t, size_t, int) override { return {}; } + + protected: + virtual BAN::ErrorOr allocate_page_containing_impl(vaddr_t vaddr) override; + + private: + SharedMemoryObject(BAN::RefPtr object, PageTable& page_table) + : MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags) + , m_object(object) + { } + + private: + BAN::RefPtr m_object; + + friend class BAN::UniqPtr; + }; + +} diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 72df79c8..31ec14fe 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -157,6 +158,9 @@ namespace Kernel BAN::ErrorOr sys_munmap(void* addr, size_t len); BAN::ErrorOr sys_msync(void* addr, size_t len, int flags); + BAN::ErrorOr sys_smo_create(size_t len, int prot); + BAN::ErrorOr sys_smo_map(SharedMemoryObjectManager::Key); + BAN::ErrorOr sys_tty_ctrl(int fildes, int command, int flags); BAN::ErrorOr sys_signal(int, void (*)(int)); diff --git a/kernel/kernel/Memory/SharedMemoryObject.cpp b/kernel/kernel/Memory/SharedMemoryObject.cpp new file mode 100644 index 00000000..bd41b60c --- /dev/null +++ b/kernel/kernel/Memory/SharedMemoryObject.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +namespace Kernel +{ + + static BAN::UniqPtr s_instance; + + BAN::ErrorOr SharedMemoryObjectManager::initialize() + { + ASSERT(!s_instance); + s_instance = TRY(BAN::UniqPtr::create()); + return {}; + } + + SharedMemoryObjectManager& SharedMemoryObjectManager::get() + { + ASSERT(s_instance); + return *s_instance; + } + + BAN::ErrorOr SharedMemoryObjectManager::create_object(size_t size, PageTable::flags_t flags) + { + ASSERT(size % PAGE_SIZE == 0); + + auto object = TRY(BAN::RefPtr::create()); + object->size = size; + object->flags = flags; + TRY(object->paddrs.resize(size / PAGE_SIZE, 0)); + + LockGuard _(m_mutex); + + Key key = Random::get(); + while (m_objects.contains(key)) + key = Random::get(); + + TRY(m_objects.insert(key, object)); + return key; + } + + BAN::ErrorOr> SharedMemoryObjectManager::map_object(Key key, PageTable& page_table, AddressRange address_range) + { + LockGuard _(m_mutex); + + auto it = m_objects.find(key); + if (it == m_objects.end()) + return BAN::Error::from_errno(ENOENT); + + return TRY(SharedMemoryObject::create(it->value, page_table, address_range)); + } + + BAN::ErrorOr> SharedMemoryObject::create(BAN::RefPtr object, PageTable& page_table, AddressRange address_range) + { + auto smo = TRY(BAN::UniqPtr::create(object, page_table)); + TRY(smo->initialize(address_range)); + return BAN::move(smo); + } + + BAN::ErrorOr SharedMemoryObject::allocate_page_containing_impl(vaddr_t address) + { + ASSERT(contains(address)); + + // Check if address is already mapped + vaddr_t vaddr = address & PAGE_ADDR_MASK; + if (m_page_table.physical_address_of(vaddr) != 0) + return false; + + SpinLockGuard _(m_object->spin_lock); + + paddr_t paddr = m_object->paddrs[(vaddr - m_vaddr) / PAGE_SIZE]; + if (paddr == 0) + { + paddr = Heap::get().take_free_page(); + if (paddr == 0) + return BAN::Error::from_errno(ENOMEM); + PageTable::with_fast_page(paddr, [&] { + memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE); + }); + m_object->paddrs[(vaddr - m_vaddr) / PAGE_SIZE] = paddr; + } + m_page_table.map_page_at(paddr, vaddr, m_flags); + + return true; + } + +} diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 53a54c58..b99fe012 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1392,6 +1392,41 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_smo_create(size_t len, int prot) + { + if (len == 0) + return BAN::Error::from_errno(EINVAL); + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_NONE)) + return BAN::Error::from_errno(EINVAL); + + if (auto rem = len % PAGE_SIZE) + len += PAGE_SIZE - rem; + + PageTable::flags_t page_flags = 0; + if (prot & PROT_READ) + page_flags |= PageTable::Flags::Present; + if (prot & PROT_WRITE) + page_flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present; + if (prot & PROT_EXEC) + page_flags |= PageTable::Flags::Execute | PageTable::Flags::Present; + + if (page_flags == 0) + page_flags |= PageTable::Flags::Reserved; + else + page_flags |= PageTable::Flags::UserSupervisor; + + return TRY(SharedMemoryObjectManager::get().create_object(len, page_flags)); + } + + BAN::ErrorOr Process::sys_smo_map(SharedMemoryObjectManager::Key key) + { + auto region = TRY(SharedMemoryObjectManager::get().map_object(key, page_table(), { .start = 0x400000, .end = KERNEL_OFFSET })); + + LockGuard _(m_process_lock); + TRY(m_mapped_regions.push_back(BAN::move(region))); + return m_mapped_regions.back()->vaddr(); + } + BAN::ErrorOr Process::sys_tty_ctrl(int fildes, int command, int flags) { LockGuard _(m_process_lock); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index a717094a..89c5ee3a 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -143,6 +144,9 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info) ProcFileSystem::initialize(); dprintln("procfs initialized"); + MUST(SharedMemoryObjectManager::initialize()); + dprintln("Shared memory object system initialized"); + if (Serial::has_devices()) { Serial::initialize_devices(); diff --git a/libc/include/sys/banan-os.h b/libc/include/sys/banan-os.h index 665082e5..e69d690a 100644 --- a/libc/include/sys/banan-os.h +++ b/libc/include/sys/banan-os.h @@ -36,6 +36,11 @@ int poweroff(int command); int load_keymap(const char* path); +// Create shared memory object and return its key or -1 on error +long smo_create(size_t size, int prot); +// Map shared memory object defined by its key and return address or null on error +void* smo_map(long key); + __END_DECLS #endif diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index daebd556..0ccab637 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -74,6 +74,8 @@ __BEGIN_DECLS O(SYS_LISTEN, listen) \ O(SYS_PSELECT, pselect) \ O(SYS_TRUNCATE, truncate) \ + O(SYS_SMO_CREATE, smo_create) \ + O(SYS_SMO_MAP, smo_map) \ enum Syscall { diff --git a/libc/sys/banan-os.cpp b/libc/sys/banan-os.cpp index bdeccd55..66504751 100644 --- a/libc/sys/banan-os.cpp +++ b/libc/sys/banan-os.cpp @@ -16,3 +16,16 @@ int load_keymap(const char* path) { return syscall(SYS_LOAD_KEYMAP, path); } + +long smo_create(size_t size, int prot) +{ + return syscall(SYS_SMO_CREATE, size, prot); +} + +void* smo_map(long key) +{ + long ret = syscall(SYS_SMO_MAP, key); + if (ret < 0) + return nullptr; + return reinterpret_cast(ret); +}