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.
This commit is contained in:
Bananymous 2024-05-29 15:58:46 +03:00
parent 99270e96a9
commit d4d530e6c8
9 changed files with 224 additions and 0 deletions

View File

@ -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

View File

@ -0,0 +1,72 @@
#pragma once
#include <BAN/HashMap.h>
#include <BAN/UniqPtr.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/MemoryRegion.h>
namespace Kernel
{
class SharedMemoryObject;
class SharedMemoryObjectManager
{
public:
using Key = uint32_t;
public:
static BAN::ErrorOr<void> initialize();
static SharedMemoryObjectManager& get();
BAN::ErrorOr<Key> create_object(size_t size, PageTable::flags_t);
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> map_object(Key, PageTable&, AddressRange);
private:
SharedMemoryObjectManager() {}
private:
struct Object : public BAN::RefCounted<Object>
{
size_t size;
PageTable::flags_t flags;
BAN::Vector<paddr_t> paddrs;
SpinLock spin_lock;
};
private:
Mutex m_mutex;
BAN::HashMap<Key, BAN::RefPtr<Object>> m_objects;
friend class SharedMemoryObject;
friend class BAN::UniqPtr<SharedMemoryObjectManager>;
};
class SharedMemoryObject : public MemoryRegion
{
BAN_NON_COPYABLE(SharedMemoryObject);
BAN_NON_MOVABLE(SharedMemoryObject);
public:
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr) override;
private:
SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table)
: MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags)
, m_object(object)
{ }
private:
BAN::RefPtr<SharedMemoryObjectManager::Object> m_object;
friend class BAN::UniqPtr<SharedMemoryObject>;
};
}

View File

@ -10,6 +10,7 @@
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryRegion.h>
#include <kernel/Memory/SharedMemoryObject.h>
#include <kernel/OpenFileDescriptorSet.h>
#include <kernel/Terminal/TTY.h>
#include <kernel/Thread.h>
@ -157,6 +158,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags);
BAN::ErrorOr<long> sys_smo_create(size_t len, int prot);
BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key);
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
BAN::ErrorOr<long> sys_signal(int, void (*)(int));

View File

@ -0,0 +1,88 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/SharedMemoryObject.h>
#include <kernel/Random.h>
namespace Kernel
{
static BAN::UniqPtr<SharedMemoryObjectManager> s_instance;
BAN::ErrorOr<void> SharedMemoryObjectManager::initialize()
{
ASSERT(!s_instance);
s_instance = TRY(BAN::UniqPtr<SharedMemoryObjectManager>::create());
return {};
}
SharedMemoryObjectManager& SharedMemoryObjectManager::get()
{
ASSERT(s_instance);
return *s_instance;
}
BAN::ErrorOr<SharedMemoryObjectManager::Key> SharedMemoryObjectManager::create_object(size_t size, PageTable::flags_t flags)
{
ASSERT(size % PAGE_SIZE == 0);
auto object = TRY(BAN::RefPtr<Object>::create());
object->size = size;
object->flags = flags;
TRY(object->paddrs.resize(size / PAGE_SIZE, 0));
LockGuard _(m_mutex);
Key key = Random::get<Key>();
while (m_objects.contains(key))
key = Random::get<Key>();
TRY(m_objects.insert(key, object));
return key;
}
BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> 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<BAN::UniqPtr<SharedMemoryObject>> SharedMemoryObject::create(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table, AddressRange address_range)
{
auto smo = TRY(BAN::UniqPtr<SharedMemoryObject>::create(object, page_table));
TRY(smo->initialize(address_range));
return BAN::move(smo);
}
BAN::ErrorOr<bool> 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;
}
}

View File

@ -1392,6 +1392,41 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> 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<long> 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<long> Process::sys_tty_ctrl(int fildes, int command, int flags)
{
LockGuard _(m_process_lock);

View File

@ -14,6 +14,7 @@
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Memory/SharedMemoryObject.h>
#include <kernel/Networking/NetworkManager.h>
#include <kernel/PCI.h>
#include <kernel/PIC.h>
@ -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();

View File

@ -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

View File

@ -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
{

View File

@ -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<void*>(ret);
}