Compare commits

...

20 Commits

Author SHA1 Message Date
77887eed80
luna -> libluna
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-27 15:22:39 +01:00
65dd3cd7fb
TmpFS: Use StaticString<128> instead of char[128] 2023-02-27 15:22:39 +01:00
5a9d31c2be
luna: Add StaticString, an OOP char[] 2023-02-27 15:22:39 +01:00
8ba571a30e
TmpFS: Use a fixed char array in DirInode's Entry instead of OwnedStringView 2023-02-27 15:22:39 +01:00
f88dc050a9
luna: Add strlcpy() 2023-02-27 15:22:38 +01:00
4fc16915d3
Vector: Fix try_append (hopefully)
Still doesn't work with OwnedStringViews inside of structs.
2023-02-27 15:22:38 +01:00
01b6294f76
kernel: Implement creating file inodes in tmpfs directories 2023-02-27 15:22:38 +01:00
a65f4311aa
tmpfs: make the root inode a DirInode instead of a FileInode 2023-02-27 15:22:38 +01:00
dd2f31d8d0
tmpfs: add DirInode skeleton 2023-02-27 15:22:38 +01:00
5fb292bc0e
tmpfs: rename tmpfs::Inode to tmpfs::FileInode 2023-02-27 15:22:37 +01:00
d3bda46325
tmpfs: Make m_next_inode_number atomic 2023-02-27 15:22:37 +01:00
ba9d725481
kernel: Rename FileSystem::root() to root_inode() and add a shortcut for the root filesystem's root inode 2023-02-27 15:22:37 +01:00
3a2b8bcfd7
kernel: Make a factory function for filesystem creation of inodes, and add inode numbers
Now every filesystem must provide fs->create_file_inode() for new inodes :)
2023-02-27 15:22:37 +01:00
a49555addc
kernel: Add a subclass of VFS::Inode to make it easier to implement file inodes 2023-02-27 15:22:36 +01:00
529b84cd1e
kernel, luna: Port non-VFS changes over from pull request #22
OwnedPtr, SharedPtr: Add operator bool
Option, Result: Make try_move_value() non-const since it modifies the Option
kernel: Switch to a stack we control for the main task as soon as we leave early boot
Heap: Fix GPF caused when making many small allocations
Heap: Avoid accessing a block after it's potentially deleted
luna: Skip UBSAN.cpp in CMakeLists as that's not implemented yet
luna: Use spinlocks in the heap implementation
kernel, luna: Move Spinlock.h to luna
Option: Use __builtin_launder to ensure that the compiler doesn't label this as UB
SharedPtr: Implement make_shared using adopt_shared
SharedPtr: Delete ptr on failure in all adopt_shared* functions
2023-02-27 15:22:36 +01:00
b9fb4c1ce6
SharedPtr: Implement make_shared using adopt_shared 2023-02-27 15:22:36 +01:00
be408c4cdb
SharedPtr: Delete ptr on failure in all adopt_shared* functions 2023-02-27 15:22:36 +01:00
38f0d3a4e6
luna: Skip UBSAN.cpp in CMakeLists as that's not implemented yet 2023-02-27 15:22:24 +01:00
9274ad0404
kernel, luna: Move Spinlock.h to luna 2023-02-27 15:22:24 +01:00
c422d11682
kernel: Start working on a VFS implementation using OOP and SharedPtr 2023-02-27 15:22:24 +01:00
64 changed files with 358 additions and 196 deletions

View File

@ -28,7 +28,7 @@ set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/${LUNA_ARCH}-luna)
message(STATUS "Configuring Luna for ${LUNA_ARCH}") message(STATUS "Configuring Luna for ${LUNA_ARCH}")
add_subdirectory(luna) add_subdirectory(libluna)
add_subdirectory(libc) add_subdirectory(libc)
add_subdirectory(kernel) add_subdirectory(kernel)
add_subdirectory(apps) add_subdirectory(apps)

View File

@ -26,6 +26,8 @@ set(SOURCES
src/sys/clock_gettime.cpp src/sys/clock_gettime.cpp
src/sys/allocate_memory.cpp src/sys/allocate_memory.cpp
src/sys/usleep.cpp src/sys/usleep.cpp
src/fs/VFS.cpp
src/fs/tmpfs/FileSystem.cpp
src/InitRD.cpp src/InitRD.cpp
src/ELF.cpp src/ELF.cpp
) )

11
kernel/src/fs/VFS.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "fs/VFS.h"
namespace VFS
{
SharedPtr<FileSystem> root_fs;
Inode& root_inode()
{
return root_fs->root_inode();
}
}

70
kernel/src/fs/VFS.h Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include <luna/SharedPtr.h>
namespace VFS
{
enum class InodeType
{
RegularFile,
Directory
};
class FileSystem;
class Inode
{
public:
// Directory-specific methods
virtual Result<SharedPtr<Inode>> find(const char* name) const = 0;
virtual Result<SharedPtr<Inode>> create_file(const char* name) = 0;
// Generic methods
virtual FileSystem& fs() const = 0;
virtual ~Inode() = default;
virtual InodeType type() const = 0;
virtual usize inode_number() const = 0;
};
class FileInode : Inode
{
public:
Result<SharedPtr<Inode>> find(const char*) const override
{
return err(ENOTDIR);
}
Result<SharedPtr<Inode>> create_file(const char*) override
{
return err(ENOTDIR);
}
InodeType type() const override
{
return InodeType::RegularFile;
}
virtual ~FileInode() = default;
};
class FileSystem
{
public:
virtual Inode& root_inode() const = 0;
virtual Result<SharedPtr<Inode>> create_file_inode() = 0;
virtual Result<SharedPtr<Inode>> create_dir_inode(SharedPtr<Inode> parent) = 0;
virtual ~FileSystem() = default;
};
extern SharedPtr<FileSystem> root_fs;
Result<Inode*> resolve_path(const char* path);
Inode& root_inode();
}

View File

@ -0,0 +1,71 @@
#include "fs/tmpfs/FileSystem.h"
#include <luna/Alloc.h>
#include <luna/CString.h>
#include <luna/Ignore.h>
namespace TmpFS
{
Result<SharedPtr<VFS::FileSystem>> FileSystem::create()
{
SharedPtr<FileSystem> fs = TRY(adopt_shared(new (std::nothrow) FileSystem()));
SharedPtr<VFS::Inode> root = TRY(fs->create_dir_inode({}));
fs->set_root(root);
return (SharedPtr<VFS::FileSystem>)fs;
}
Result<SharedPtr<VFS::Inode>> FileSystem::create_file_inode()
{
SharedPtr<FileInode> inode = TRY(make_shared<FileInode>());
inode->set_fs(*this, {});
inode->set_inode_number(m_next_inode_number, {});
TRY(m_inodes.try_append(inode));
m_next_inode_number++;
return (SharedPtr<VFS::Inode>)inode;
}
Result<SharedPtr<VFS::Inode>> FileSystem::create_dir_inode(SharedPtr<VFS::Inode> parent)
{
SharedPtr<DirInode> inode = TRY(make_shared<DirInode>());
TRY(inode->add_entry(inode, "."));
TRY(inode->add_entry(parent ? parent : (SharedPtr<VFS::Inode>)inode, ".."));
inode->set_fs(*this, {});
inode->set_inode_number(m_next_inode_number, {});
TRY(m_inodes.try_append(inode));
m_next_inode_number++;
return (SharedPtr<VFS::Inode>)inode;
}
void FileSystem::set_root(SharedPtr<VFS::Inode> root)
{
m_root_inode = root;
}
Result<SharedPtr<VFS::Inode>> DirInode::find(const char* name) const
{
for (const auto& entry : m_entries)
{
if (!strcmp(name, entry.name.chars())) return entry.inode;
}
return err(ENOENT);
}
Result<void> DirInode::add_entry(SharedPtr<VFS::Inode> inode, const char* name)
{
Entry entry { inode, name };
TRY(m_entries.try_append(move(entry)));
return {};
}
Result<SharedPtr<VFS::Inode>> DirInode::create_file(const char* name)
{
auto inode = TRY(m_fs->create_file_inode());
TRY(add_entry(inode, name));
return inode;
}
}

View File

@ -0,0 +1,118 @@
#pragma once
#include "fs/VFS.h"
#include <luna/Atomic.h>
#include <luna/Badge.h>
#include <luna/StaticString.h>
#include <luna/Vector.h>
namespace TmpFS
{
class FileSystem : public VFS::FileSystem
{
public:
VFS::Inode& root_inode() const override
{
return *m_root_inode;
}
Result<SharedPtr<VFS::Inode>> create_file_inode() override;
Result<SharedPtr<VFS::Inode>> create_dir_inode(SharedPtr<VFS::Inode> parent) override;
static Result<SharedPtr<VFS::FileSystem>> create();
virtual ~FileSystem() = default;
private:
FileSystem() = default;
void set_root(SharedPtr<VFS::Inode> root);
SharedPtr<VFS::Inode> m_root_inode;
Vector<SharedPtr<VFS::Inode>> m_inodes;
Atomic<usize> m_next_inode_number { 2 };
};
class FileInode : public VFS::FileInode
{
public:
FileInode() = default;
void set_fs(FileSystem& fs, Badge<FileSystem>)
{
m_fs = &fs;
}
void set_inode_number(usize inum, Badge<FileSystem>)
{
m_inode_number = inum;
}
VFS::FileSystem& fs() const override
{
return *m_fs;
}
usize inode_number() const override
{
return m_inode_number;
}
virtual ~FileInode() = default;
private:
VFS::FileSystem* m_fs;
usize m_inode_number;
};
class DirInode : public VFS::Inode
{
public:
DirInode() = default;
void set_fs(FileSystem& fs, Badge<FileSystem>)
{
m_fs = &fs;
}
void set_inode_number(usize inum, Badge<FileSystem>)
{
m_inode_number = inum;
}
Result<SharedPtr<VFS::Inode>> find(const char* name) const override;
VFS::FileSystem& fs() const override
{
return *m_fs;
}
usize inode_number() const override
{
return m_inode_number;
}
VFS::InodeType type() const override
{
return VFS::InodeType::Directory;
}
Result<SharedPtr<VFS::Inode>> create_file(const char* name) override;
Result<void> add_entry(SharedPtr<VFS::Inode> inode, const char* name);
virtual ~DirInode() = default;
private:
VFS::FileSystem* m_fs;
usize m_inode_number;
struct Entry
{
SharedPtr<VFS::Inode> inode;
StaticString<128> name;
};
Vector<Entry> m_entries;
};
}

View File

@ -7,6 +7,7 @@
#include "arch/Timer.h" #include "arch/Timer.h"
#include "boot/Init.h" #include "boot/Init.h"
#include "config.h" #include "config.h"
#include "fs/tmpfs/FileSystem.h"
#include "memory/Heap.h" #include "memory/Heap.h"
#include "memory/KernelVM.h" #include "memory/KernelVM.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
@ -55,6 +56,18 @@ Result<void> init()
Thread::init(); Thread::init();
Scheduler::init(); Scheduler::init();
VFS::root_fs = TRY(TmpFS::FileSystem::create());
VFS::Inode& root_inode = VFS::root_inode();
kinfoln("root inode number: %zu", root_inode.inode_number());
kinfoln("root inode's '.' entry inode number: %zu", TRY(root_inode.find("."))->inode_number());
kinfoln("root inode's '..' entry inode number: %zu", TRY(root_inode.find(".."))->inode_number());
TRY(root_inode.create_file("usr"));
kinfoln("root inode's 'usr' entry inode number: %zu", TRY(root_inode.find("usr"))->inode_number());
TarStream::Entry entry; TarStream::Entry entry;
while (TRY(g_initrd.read_next_entry(entry))) while (TRY(g_initrd.read_next_entry(entry)))
{ {

View File

@ -1,53 +0,0 @@
#include "thread/Spinlock.h"
#include "Log.h"
#include "arch/CPU.h"
void Spinlock::lock()
{
int expected = 0;
while (!m_lock.compare_exchange_strong(expected, 1))
{
expected = 0;
CPU::pause();
}
}
bool Spinlock::try_lock()
{
int expected = 0;
return m_lock.compare_exchange_strong(expected, 1);
}
void Spinlock::unlock()
{
int expected = 1;
if (!m_lock.compare_exchange_strong(expected, 0))
{
kwarnln("Spinlock::unlock() called on an unlocked lock with value %d", expected);
}
}
ScopeLock::ScopeLock(Spinlock& lock) : m_lock(lock)
{
m_lock.lock();
}
ScopeLock::~ScopeLock()
{
m_lock.unlock();
}
const u32 RETRIES = 5000000;
SafeScopeLock::SafeScopeLock(Spinlock& lock) : m_lock(lock)
{
u32 tries_left = RETRIES;
while (!lock.try_lock() && --tries_left) { CPU::pause(); }
if (tries_left) m_success = true;
}
SafeScopeLock::~SafeScopeLock()
{
if (m_success) m_lock.unlock();
}

View File

@ -1,139 +0,0 @@
#pragma once
#include "Log.h"
#include "arch/CPU.h"
#include <luna/Atomic.h>
#include <luna/Option.h>
class Spinlock
{
public:
void lock();
void unlock();
bool try_lock();
bool is_locked() const
{
return m_lock.load() != 0;
}
private:
Atomic<int> m_lock { 0 };
};
class ScopeLock
{
public:
ScopeLock(Spinlock& lock);
~ScopeLock();
ScopeLock(const ScopeLock&) = delete;
ScopeLock(ScopeLock&&) = delete;
private:
Spinlock& m_lock;
};
class SafeScopeLock
{
public:
SafeScopeLock(Spinlock& lock);
~SafeScopeLock();
SafeScopeLock(const SafeScopeLock&) = delete;
SafeScopeLock(SafeScopeLock&&) = delete;
bool did_succeed() const
{
return m_success;
}
private:
Spinlock& m_lock;
bool m_success { false };
};
template <typename T> class LockedValue
{
struct LockedValueGuard
{
LockedValueGuard(LockedValue& value_ref) : m_value_ref(&value_ref)
{
}
LockedValueGuard(const LockedValueGuard& other) = delete;
LockedValueGuard(LockedValueGuard&& other)
{
m_value_ref = other.m_value_ref;
other.m_value_ref = nullptr;
}
~LockedValueGuard()
{
if (m_value_ref) m_value_ref->m_lock.unlock();
}
T& ref()
{
expect(m_value_ref, "LockedValueGuard::ref() called on a moved LockedValueGuard");
return m_value_ref->m_value;
}
void set(const T& other)
{
ref() = other;
}
T* operator->()
{
return &ref();
}
T& operator*()
{
return ref();
}
private:
LockedValue* m_value_ref;
};
public:
LockedValue() : m_value()
{
}
LockedValue(T value) : m_value(value)
{
}
#ifndef LOCKED_VALUE_DEBUG
LockedValueGuard lock()
{
m_lock.lock();
return { *this };
}
#else
LockedValueGuard lock()
{
if (m_lock.try_lock()) { return { *this }; }
kwarnln("Spinning on a locked LockedValue. This might lead to a deadlock...");
CPU::print_stack_trace();
m_lock.lock();
return { *this };
}
#endif
Option<LockedValueGuard> try_lock()
{
if (m_lock.try_lock()) { return { *this }; }
return {};
}
private:
T m_value;
Spinlock m_lock;
};

View File

@ -17,7 +17,6 @@ set(FREESTANDING_SOURCES
src/DebugLog.cpp src/DebugLog.cpp
src/Heap.cpp src/Heap.cpp
src/Spinlock.cpp src/Spinlock.cpp
src/UBSAN.cpp
) )
set(SOURCES set(SOURCES

View File

@ -22,6 +22,8 @@ extern "C"
// FIXME: Replace this invented function with strlcpy(). // FIXME: Replace this invented function with strlcpy().
void nullcpy(char* dest, const char* src, usize len); void nullcpy(char* dest, const char* src, usize len);
usize strlcpy(char* dest, const char* src, usize len);
[[deprecated]] char* strcpy(char* dst, const char* src); [[deprecated]] char* strcpy(char* dst, const char* src);
[[deprecated]] char* strcat(char* dst, const char* src); [[deprecated]] char* strcat(char* dst, const char* src);

View File

@ -0,0 +1,52 @@
#pragma once
#include <luna/CString.h>
#include <luna/Types.h>
template <usize Size> class StaticString
{
public:
StaticString() = default;
StaticString(const char* string)
{
adopt(string);
}
void adopt(const char* string)
{
usize length = strlcpy(m_buffer, string, sizeof(m_buffer));
if (length > Size) { m_length = Size; }
else
m_length = length;
}
StaticString<Size>& operator=(const char* string)
{
adopt(string);
return *this;
}
template <usize OSize> StaticString<Size>& operator=(const StaticString<OSize>& string)
{
if constexpr (OSize == Size)
{
if (this == &string) return *this;
}
adopt(string.chars());
return *this;
}
const char* chars() const
{
return m_buffer;
}
usize length() const
{
return m_length;
}
private:
char m_buffer[Size + 1];
usize m_length { 0 };
};

View File

@ -78,7 +78,7 @@ template <typename T> class Vector
resize(capacity).release_value(); resize(capacity).release_value();
} }
Result<void> try_append(T item) Result<void> try_append(T&& item)
{ {
if (m_capacity == m_size) TRY(resize(m_capacity + 8)); if (m_capacity == m_size) TRY(resize(m_capacity + 8));
@ -89,6 +89,11 @@ template <typename T> class Vector
return {}; return {};
} }
Result<void> try_append(const T& item)
{
return try_append(T(item));
}
Option<T> try_pop() Option<T> try_pop()
{ {
if (m_size == 0) return {}; if (m_size == 0) return {};

View File

@ -125,4 +125,15 @@ extern "C"
if (*str) return const_cast<char*>(str); if (*str) return const_cast<char*>(str);
return NULL; return NULL;
} }
usize strlcpy(char* dest, const char* src, usize len)
{
usize src_len = strlen(src);
usize copy_len = src_len;
if (len == 0) return src_len;
if (src_len >= (len - 1)) copy_len = len - 1;
memcpy(dest, src, copy_len);
dest[copy_len] = 0;
return src_len;
}
} }

View File

@ -10,4 +10,4 @@ mkdir -p $LUNA_BASE/usr/include
mkdir -p $LUNA_BASE/usr/include/luna mkdir -p $LUNA_BASE/usr/include/luna
cp --preserve=timestamps -RT libc/include/ $LUNA_BASE/usr/include cp --preserve=timestamps -RT libc/include/ $LUNA_BASE/usr/include
cp --preserve=timestamps -RT luna/include/luna/ $LUNA_BASE/usr/include/luna cp --preserve=timestamps -RT libluna/include/luna/ $LUNA_BASE/usr/include/luna