kernel: Add shared memory
This commit is contained in:
parent
b4527786d4
commit
9443551d71
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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++;
|
||||
|
120
kernel/src/memory/SharedMemory.cpp
Normal file
120
kernel/src/memory/SharedMemory.cpp
Normal 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); }
|
||||
}
|
25
kernel/src/memory/SharedMemory.h
Normal file
25
kernel/src/memory/SharedMemory.h
Normal 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;
|
@ -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 });
|
||||
|
Loading…
Reference in New Issue
Block a user