From ed3599ce95279992830543aff768c80f4f46c6fb Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Fri, 3 May 2024 23:11:08 +0200 Subject: [PATCH] TarFs: janky tarfs for initramfs --- src/arch/x86/PS2Keyboard.cpp | 3 + src/arch/x86/kmain.cpp | 39 ++++----- src/iso/CMakeLists.txt | 7 +- src/iso/limine.cfg | 7 +- src/kernel/vfs/CMakeLists.txt | 1 + src/kernel/vfs/TarFs.cpp | 147 ++++++++++++++++++++++++++++++++++ src/kernel/vfs/TarFs.hpp | 79 ++++++++++++++++++ 7 files changed, 258 insertions(+), 25 deletions(-) create mode 100644 src/kernel/vfs/TarFs.cpp create mode 100644 src/kernel/vfs/TarFs.hpp diff --git a/src/arch/x86/PS2Keyboard.cpp b/src/arch/x86/PS2Keyboard.cpp index 2755a0f63..2083acacc 100644 --- a/src/arch/x86/PS2Keyboard.cpp +++ b/src/arch/x86/PS2Keyboard.cpp @@ -60,6 +60,9 @@ void PS2Keyboard::this_pooler() { case 0x34: r = 'g'; break; + case 0x4A: + r = '/'; + break; case 0x3C: r = 'u'; break; diff --git a/src/arch/x86/kmain.cpp b/src/arch/x86/kmain.cpp index 70c534af8..26c56ed47 100644 --- a/src/arch/x86/kmain.cpp +++ b/src/arch/x86/kmain.cpp @@ -32,6 +32,7 @@ #include #include +#include void templates_tester() { // GlobalTtyManager.all_tty_putstr("Testing templates\n"); @@ -53,31 +54,33 @@ void ktask_main() { (new Task(Task::TaskMode::TASKMODE_KERN, templates_tester, "templates_tester"))->start(); (new Task(Task::TaskMode::TASKMODE_KERN, templates_tester, "templates_tester2"))->start(); - VFSGlobals::mounts.add_mount(new MemFs(&VFSGlobals::root)); - (new Task(Task::TaskMode::TASKMODE_KERN, vfs_tester, "vfs_tester"))->start(); - Task *init; + // (new Task(Task::TaskMode::TASKMODE_KERN, vfs_tester, "vfs_tester"))->start(); for (int i = 0; i < saved_modules_size; i++) { auto &mod = saved_modules[i]; - VFSApi::touch(StrToPath(saved_modules_names[i])); - FDT::FD fd = VFSApi::open(StrToPath(saved_modules_names[i])); - File *f = VFSApi::get(fd); - f->write(static_cast(mod.address), mod.size); - - if (strcmp(saved_modules_names[i], "/init") == 0) { - Vector read_data(mod.size); - memcpy(read_data.begin(), mod.address, mod.size); - ElfParser elfParser(std::move(read_data)); - - init = new Task(Task::TaskMode::TASKMODE_USER, (void (*)()) elfParser.get_entrypoint(), saved_modules_names[i]); - if (!elfParser.copy_to(init)) - assert2(false, "Init couldn't be loaded!"); + if (strcmp(saved_modules_names[i], "/sysroot.tar") == 0) { + VFSGlobals::mounts.add_mount(new TarFs((char *) mod.address, mod.size, &VFSGlobals::root)); } - - VFSApi::close(fd); } GlobalTtyManager.all_tty_putstr("Setup finished \n"); GlobalTtyManager.all_tty_putstr("Starting init \n"); + + Task *init; + FDT::FD fd = VFSApi::open(StrToPath("/init")); + File *f = VFSApi::get(fd); + + { + Vector read_data(f->size()); + f->read(read_data.data(), f->size()); + ElfParser elfParser(std::move(read_data)); + + init = new Task(Task::TaskMode::TASKMODE_USER, (void (*)()) elfParser.get_entrypoint(), "/init"); + if (!elfParser.copy_to(init)) + assert2(false, "Init couldn't be loaded!"); + } + + VFSApi::close(fd); + init->start(); } diff --git a/src/iso/CMakeLists.txt b/src/iso/CMakeLists.txt index 9523de16d..4de9ea406 100644 --- a/src/iso/CMakeLists.txt +++ b/src/iso/CMakeLists.txt @@ -2,10 +2,13 @@ add_custom_target(iso_limine) add_custom_target(iso COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/isodir/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/initramfs/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/limine.cfg ${CMAKE_CURRENT_BINARY_DIR}/isodir/ COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${CMAKE_CURRENT_BINARY_DIR}/isodir/ficus.elf - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${CMAKE_CURRENT_BINARY_DIR}/isodir/init - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${CMAKE_CURRENT_BINARY_DIR}/isodir/hello2 + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${CMAKE_CURRENT_BINARY_DIR}/initramfs/init + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${CMAKE_CURRENT_BINARY_DIR}/initramfs/hello2 + # TODO: this might not work when there are special symbols in path... + COMMAND pax -wvf ${CMAKE_CURRENT_BINARY_DIR}/isodir/sysroot.tar -s ":^${CMAKE_CURRENT_BINARY_DIR}/initramfs/::" ${CMAKE_CURRENT_BINARY_DIR}/initramfs COMMAND xorriso -as mkisofs -b limine-bios-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot limine-uefi-cd.bin -efi-boot-part --efi-boot-image --protective-msdos-label ${CMAKE_CURRENT_BINARY_DIR}/isodir -o ${CMAKE_CURRENT_BINARY_DIR}/ficus.iso COMMAND ${tools}/limine/prefix/bin/limine bios-install ${CMAKE_CURRENT_BINARY_DIR}/ficus.iso VERBATIM diff --git a/src/iso/limine.cfg b/src/iso/limine.cfg index bc6bcece7..5570c55f9 100644 --- a/src/iso/limine.cfg +++ b/src/iso/limine.cfg @@ -8,9 +8,7 @@ TIMEOUT=1 # Path to the kernel to boot. boot:/// represents the partition on which limine.cfg is located. KERNEL_PATH=boot:///ficus.elf - - MODULE_PATH=boot:///init - MODULE_PATH=boot:///hello2 + MODULE_PATH=boot:///sysroot.tar # Same thing, but without KASLR. :ficus (KASLR off) @@ -20,5 +18,4 @@ TIMEOUT=1 KASLR=no KERNEL_PATH=boot:///ficus.elf - MODULE_PATH=boot:///init - MODULE_PATH=boot:///hello2 + MODULE_PATH=boot:///sysroot.tar diff --git a/src/kernel/vfs/CMakeLists.txt b/src/kernel/vfs/CMakeLists.txt index 6945a633b..cd41e916c 100644 --- a/src/kernel/vfs/CMakeLists.txt +++ b/src/kernel/vfs/CMakeLists.txt @@ -13,4 +13,5 @@ target_sources(kernel.elf PRIVATE File.cpp PipeFs.cpp TtyPipe.cpp + TarFs.cpp ) \ No newline at end of file diff --git a/src/kernel/vfs/TarFs.cpp b/src/kernel/vfs/TarFs.cpp new file mode 100644 index 000000000..f3fea96c8 --- /dev/null +++ b/src/kernel/vfs/TarFs.cpp @@ -0,0 +1,147 @@ +// +// Created by Stepan Usatiuk on 01.05.2024. +// + +#include "TarFs.hpp" + +#include + + +TarFs::TarFs(char *backing, size_t backing_size, NodeDir *mounted_on) : Filesystem(mounted_on), _backing((tar_header *) backing), _backing_size(backing_size) { + int i = 2; + + const tar_header *header = _backing; + + SkipListMap dir_map; + + dir_map.emplace("", 1); + _dir_map.emplace(1, Vector()); + + // FIXME: all this is extremely inefficient + // Also recheck that directories are handled correctly + while (true) { + if (header->filename[0] == '\0') + break; + unsigned int size = header_size(header); + + int new_ino = i++; + _off_map.emplace(new_ino, header); + + String pref = ""; + String name = ""; + + { + Path p = StrToPath(header->filename); + if (p.size() > 1) { + pref += p[0]; + for (int i = 1; i < p.size() - 1; i++) { + pref += "/"; + pref += p[i]; + } + } + name = p.back(); + } + + if (header->typeflag[0] == '5') { + String fullname; + if (pref.length() > 0) { + fullname += pref; + fullname += "/"; + } + fullname += name; + if (dir_map.find(fullname) == dir_map.end()) { + dir_map.emplace(fullname, new_ino); + _dir_map.emplace(new_ino, Vector()); + } + if (dir_map.find(pref) == dir_map.end()) { + int dir_ino = i++; + dir_map.emplace(pref, dir_ino); + _dir_map.emplace(dir_ino, Vector()); + } + auto p = dir_map.find(pref); + auto d = _dir_map.find(p->second); + d->second.emplace_back(name, new_ino); + } else if (header->typeflag[0] == '\0' || header->typeflag[0] == '0') { + if (dir_map.find(pref) == dir_map.end()) { + int dir_ino = i++; + dir_map.emplace(pref, dir_ino); + _dir_map.emplace(dir_ino, Vector()); + } + auto p = dir_map.find(pref); + auto d = _dir_map.find(p->second); + d->second.emplace_back(name, new_ino); + } else { + GlobalTtyManager.all_tty_putstr("Skipping tar: "); + GlobalTtyManager.all_tty_putstr(pref.c_str()); + GlobalTtyManager.all_tty_putstr("/"); + GlobalTtyManager.all_tty_putstr(name.c_str()); + GlobalTtyManager.all_tty_putstr("\n"); + } + + header = (const tar_header *) (((char *) (header)) + ((size / 512) + 1) * 512); + + if (size % 512) + header = (const tar_header *) (((char *) (header)) + 512); + } +} + +SharedPtr TarFs::root() { + return static_ptr_cast(get_node(1)); +} + +SharedPtr TarFs::get_node(ino_t inode) { + if (_dir_map.find(inode) != _dir_map.end()) { + return static_ptr_cast(TarFsNodeDir::create(this, inode)); + } else { + return static_ptr_cast(TarFsNodeFile::create(this, inode)); + } + assert(false); +} + +Vector TarFs::TarFsNodeDir::children() { + return static_cast(_fs)->_dir_map.find(_ino)->second; +} + +ino_t TarFs::TarFsNodeDir::mkdir(const String &name) { + return -1; +} +ino_t TarFs::TarFsNodeDir::mkfile(const String &name) { + return -1; +} + +int64_t TarFs::TarFsNodeFile::read(char *buf, size_t start, size_t num) { + TarFs *tar_fs = static_cast(_fs); + + if (auto entry = tar_fs->_off_map.find(_ino); entry != tar_fs->_off_map.end()) { + num = std::min(num, size() - start); + for (size_t i = 0; i < num; i++) { + buf[i] = (((char *) entry->second) + 512)[start + i]; + } + return num; + } + assert(false); +} + +int64_t TarFs::TarFsNodeFile::write(const char *buf, size_t start, size_t num) { + return -1; +} + +size_t TarFs::TarFsNodeFile::size() { + TarFs *tar_fs = static_cast(_fs); + + if (auto entry = tar_fs->_off_map.find(_ino); entry != tar_fs->_off_map.end()) { + return header_size(entry->second); + } + + assert(false); +} + +size_t TarFs::header_size(const tar_header *hdr) { + int size = 0; + + size_t count = 1; + for (int j = 11; j > 0; j--, count *= 8) + size += ((hdr->size[j - 1] - '0') * count); + + return size; +} diff --git a/src/kernel/vfs/TarFs.hpp b/src/kernel/vfs/TarFs.hpp new file mode 100644 index 000000000..503b77d16 --- /dev/null +++ b/src/kernel/vfs/TarFs.hpp @@ -0,0 +1,79 @@ +// +// Created by Stepan Usatiuk on 01.05.2024. +// + +#ifndef TARFS_HPP +#define TARFS_HPP + +#include + +class TarFs : public Filesystem { +public: + TarFs(char *backing, size_t backing_size, NodeDir *mounted_on); + ~TarFs() override = default; + + SharedPtr root() override; + SharedPtr get_node(ino_t inode) override; + + + struct TarFsNodeDir : public ::NodeDir { + public: + ~TarFsNodeDir() override = default; + + Vector children() override; + ino_t mkdir(const String &name) override; + ino_t mkfile(const String &name) override; + + static SharedPtr create(Filesystem *fs, ino_t id) { + auto shared = SharedPtr(new TarFsNodeDir(fs, id)); + shared->_self_weak = static_ptr_cast(shared); + return shared; + } + + private: + TarFsNodeDir(Filesystem *fs, ino_t id) : ::NodeDir(fs, id) {} + }; + + struct TarFsNodeFile : public ::NodeFile { + public: + ~TarFsNodeFile() override = default; + + int64_t read(char *buf, size_t start, size_t num) override; + int64_t write(const char *buf, size_t start, size_t num) override; + size_t size() override; + bool is_tty() override { return false; } + + static SharedPtr create(Filesystem *fs, ino_t id) { + auto shared = SharedPtr(new TarFsNodeFile(fs, id)); + shared->_self_weak = static_ptr_cast(shared); + return shared; + } + + private: + TarFsNodeFile(Filesystem *fs, ino_t id) : ::NodeFile(fs, id) {} + }; + +private: + struct tar_header { + char filename[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag[1]; + } __attribute__((packed)); + + const tar_header *_backing; + size_t _backing_size; + + SkipListMap _off_map; + SkipListMap> _dir_map; + // SkipListMap> _vnode_map; + + static size_t header_size(const tar_header *hdr); +}; + + +#endif //TARFS_HPP