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/KernelVM.cpp
|
||||||
src/memory/AddressSpace.cpp
|
src/memory/AddressSpace.cpp
|
||||||
src/memory/MemoryMap.cpp
|
src/memory/MemoryMap.cpp
|
||||||
|
src/memory/SharedMemory.cpp
|
||||||
src/boot/Init.cpp
|
src/boot/Init.cpp
|
||||||
src/arch/Serial.cpp
|
src/arch/Serial.cpp
|
||||||
src/arch/Timer.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
|
// Directory-specific methods
|
||||||
virtual Result<SharedPtr<Inode>> find(const char* name) const = 0;
|
virtual Result<SharedPtr<Inode>> find(const char* name) const = 0;
|
||||||
|
|
||||||
@ -186,6 +191,7 @@ namespace VFS
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable InodeMetadata m_metadata;
|
mutable InodeMetadata m_metadata;
|
||||||
|
Option<u64> m_shmid {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileInode : public Inode
|
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
|
Result<void> set_metadata(const VFS::InodeMetadata&) override
|
||||||
{
|
{
|
||||||
return err(EROFS);
|
return err(EROFS);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "fs/tmpfs/Inode.h"
|
#include "fs/tmpfs/Inode.h"
|
||||||
|
#include "arch/MMU.h"
|
||||||
|
#include "memory/SharedMemory.h"
|
||||||
|
|
||||||
namespace TmpFS
|
namespace TmpFS
|
||||||
{
|
{
|
||||||
@ -127,4 +129,28 @@ namespace TmpFS
|
|||||||
|
|
||||||
return {};
|
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<void> truncate(usize size) override;
|
||||||
|
|
||||||
|
Result<u64> query_shared_memory(off_t offset, usize count) override;
|
||||||
|
|
||||||
void did_link() override
|
void did_link() override
|
||||||
{
|
{
|
||||||
m_metadata.nlinks++;
|
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
|
template <typename K, typename V> struct HashMap
|
||||||
{
|
{
|
||||||
public:
|
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)
|
Result<bool> try_set(const K& key, const V& value)
|
||||||
{
|
{
|
||||||
return m_table.try_set(HashPair<K, V> { key, value });
|
return m_table.try_set(HashPair<K, V> { key, value });
|
||||||
|
Loading…
Reference in New Issue
Block a user