kernel: Add shared memory

This commit is contained in:
apio 2023-08-02 22:18:36 +02:00
parent b4527786d4
commit 9443551d71
Signed by: apio
GPG Key ID: B8A7D06E42258954
8 changed files with 190 additions and 0 deletions

View File

@ -14,6 +14,7 @@ set(SOURCES
src/memory/KernelVM.cpp
src/memory/AddressSpace.cpp
src/memory/MemoryMap.cpp
src/memory/SharedMemory.cpp
src/boot/Init.cpp
src/arch/Serial.cpp
src/arch/Timer.cpp

View File

@ -113,6 +113,11 @@ namespace VFS
{
}
virtual Result<u64> query_shared_memory(off_t, usize)
{
return err(EACCES);
}
// Directory-specific methods
virtual Result<SharedPtr<Inode>> find(const char* name) const = 0;
@ -186,6 +191,7 @@ namespace VFS
protected:
mutable InodeMetadata m_metadata;
Option<u64> m_shmid {};
};
class FileInode : public Inode

View File

@ -34,6 +34,11 @@ namespace Ext2
{
}
Result<u64> query_shared_memory(off_t, usize) override
{
return err(ENOTSUP);
}
Result<void> set_metadata(const VFS::InodeMetadata&) override
{
return err(EROFS);

View File

@ -1,4 +1,6 @@
#include "fs/tmpfs/Inode.h"
#include "arch/MMU.h"
#include "memory/SharedMemory.h"
namespace TmpFS
{
@ -127,4 +129,28 @@ namespace TmpFS
return {};
}
Result<u64> FileInode::query_shared_memory(off_t offset, usize count)
{
if (offset + (count * ARCH_PAGE_SIZE) > m_data_buffer.size()) return err(EINVAL);
if (!m_shmid.has_value())
{
u64 shmid = TRY(SharedMemory::create(m_data_buffer.data() + offset, offset, count));
m_shmid = shmid;
return shmid;
}
auto* shm = g_shared_memory_map.try_get_ref(*m_shmid);
if (shm->offset > offset)
{
TRY(shm->grow_backward(m_data_buffer.data() + offset, (shm->offset - offset) / ARCH_PAGE_SIZE));
}
if (shm->frames.size() < count)
{
TRY(shm->grow_forward(m_data_buffer.data() + offset + (shm->frames.size() * ARCH_PAGE_SIZE),
count - shm->frames.size()));
}
return *m_shmid;
}
}

View File

@ -33,6 +33,8 @@ namespace TmpFS
Result<void> truncate(usize size) override;
Result<u64> query_shared_memory(off_t offset, usize count) override;
void did_link() override
{
m_metadata.nlinks++;

View File

@ -0,0 +1,120 @@
#include "memory/SharedMemory.h"
#include "memory/MemoryManager.h"
#include <bits/mmap-flags.h>
#include <luna/ScopeGuard.h>
HashMap<u64, SharedMemory> g_shared_memory_map;
Atomic<u64> g_next_shmem_id;
Result<u64> SharedMemory::create(u8* mem, off_t offset, usize count)
{
SharedMemory shmem;
shmem.offset = offset;
auto guard = make_scope_guard([&shmem] {
for (u64 frame : shmem.frames) { MemoryManager::free_frame(frame); }
});
while (count--)
{
u64 frame = TRY(MemoryManager::alloc_frame());
TRY(shmem.frames.try_append(frame));
if (mem)
{
memcpy((void*)MMU::translate_physical_address(frame), mem, ARCH_PAGE_SIZE);
mem += ARCH_PAGE_SIZE;
}
else { memset((void*)MMU::translate_physical_address(frame), 0, ARCH_PAGE_SIZE); }
}
const u64 id = g_next_shmem_id++;
check(TRY(g_shared_memory_map.try_set(id, move(shmem))));
guard.deactivate();
return id;
}
Result<void> SharedMemory::grow_forward(u8* mem, usize count)
{
u64 old_count = frames.size();
auto guard = make_scope_guard([old_count, this] {
while (old_count < this->frames.size()) { MemoryManager::free_frame(*this->frames.try_pop()); }
});
while (count--)
{
u64 frame = TRY(MemoryManager::alloc_frame());
TRY(frames.try_append(frame));
if (mem)
{
memcpy((void*)MMU::translate_physical_address(frame), mem, ARCH_PAGE_SIZE);
mem += ARCH_PAGE_SIZE;
}
}
guard.deactivate();
return {};
}
Result<void> SharedMemory::grow_backward(u8* mem, usize count)
{
Vector<u64> new_frames;
const usize bytes = count * ARCH_PAGE_SIZE;
auto guard = make_scope_guard([&new_frames, count] {
for (u64 i = 0; i < count && i < new_frames.size(); i++) { MemoryManager::free_frame(new_frames[i]); }
});
while (count--)
{
u64 frame = TRY(MemoryManager::alloc_frame());
TRY(new_frames.try_append(frame));
if (mem)
{
memcpy((void*)MMU::translate_physical_address(frame), mem, ARCH_PAGE_SIZE);
mem += ARCH_PAGE_SIZE;
}
}
for (u64 frame : frames) { TRY(new_frames.try_append(frame)); }
frames = move(new_frames);
offset -= bytes;
guard.deactivate();
return {};
}
Result<void> SharedMemory::map(u64 virt, int flags, off_t _offset, usize count)
{
usize off = _offset / ARCH_PAGE_SIZE;
if (off + count > frames.size()) return err(EINVAL);
for (usize i = off; i < count; i++)
{
TRY(MMU::map(virt, frames[i], flags, MMU::UseHugePages::No));
virt += ARCH_PAGE_SIZE;
}
return {};
}
void SharedMemory::free()
{
if (inode && (prot & PROT_WRITE))
{
for (u64 i = 0; i < frames.size(); i++)
{
inode->write((u8*)MMU::translate_physical_address(frames[i]), offset + (i * ARCH_PAGE_SIZE),
ARCH_PAGE_SIZE);
}
}
for (u64 frame : frames) { MemoryManager::free_frame(frame); }
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "fs/VFS.h"
#include <luna/HashMap.h>
#include <luna/Vector.h>
#include <sys/types.h>
struct SharedMemory
{
Vector<u64> frames;
off_t offset;
int prot;
SharedPtr<VFS::Inode> inode {};
int refs { 0 };
static Result<u64> create(u8* mem, off_t offset, usize count);
Result<void> grow_forward(u8* mem, usize count);
Result<void> grow_backward(u8* mem, usize count);
Result<void> map(u64 virt, int flags, off_t offset, usize count);
void free();
};
extern HashMap<u64, SharedMemory> g_shared_memory_map;

View File

@ -20,6 +20,11 @@ template <typename K, typename V> u64 hash(const HashPair<K, V>& value, u64 salt
template <typename K, typename V> struct HashMap
{
public:
Result<bool> try_set(const K& key, V&& value)
{
return m_table.try_set(HashPair<K, V> { key, move(value) });
}
Result<bool> try_set(const K& key, const V& value)
{
return m_table.try_set(HashPair<K, V> { key, value });