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:
parent
99270e96a9
commit
d4d530e6c8
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue