diff --git a/CMakeLists.txt b/CMakeLists.txt index 57ed4218..95b06e2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA src/core/PICA/shader_interpreter.cpp src/core/PICA/renderer_opengl.cpp ) set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp) -set(FS_SOURCE_FILES src/core/filesystem/archive_ncch.cpp) +set(FS_SOURCE_FILES src/core/fs/archive_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp) set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel/kernel.hpp @@ -74,6 +74,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/logger.hpp include/loader/ncch.hpp include/loader/ncsd.hpp include/io_file.hpp include/loader/lz77.hpp include/fs/archive_base.hpp include/fs/archive_ncch.hpp include/services/dsp.hpp include/services/cfg.hpp include/services/region_codes.hpp + include/fs/archive_save_data.hpp include/fs/archive_sdmc.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index 7692fc67..6d6d8cf3 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -56,6 +56,16 @@ struct FileSession { } }; +struct ArchiveSession { + ArchiveBase* archive = nullptr; + FSPath path; + bool isOpen; + + ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), isOpen(isOpen) { + path = filePath; + } +}; + class ArchiveBase { protected: using Result = u32; @@ -67,7 +77,7 @@ public: virtual u64 getFreeBytes() = 0; virtual bool openFile(const FSPath& path) = 0; - virtual ArchiveBase* openArchive(FSPath& path) = 0; + virtual ArchiveBase* openArchive(const FSPath& path) = 0; // Read size bytes from a file starting at offset "offset" into a certain buffer in memory // Returns the number of bytes read, or nullopt if the read failed diff --git a/include/fs/archive_ncch.hpp b/include/fs/archive_ncch.hpp index ade3c0e6..3b17331b 100644 --- a/include/fs/archive_ncch.hpp +++ b/include/fs/archive_ncch.hpp @@ -1,3 +1,4 @@ +#pragma once #include "archive_base.hpp" class SelfNCCHArchive : public ArchiveBase { @@ -9,6 +10,6 @@ public: const char* name() override { return "SelfNCCH"; } bool openFile(const FSPath& path) override; - ArchiveBase* openArchive(FSPath& path) override; + ArchiveBase* openArchive(const FSPath& path) override; std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override; }; \ No newline at end of file diff --git a/include/fs/archive_save_data.hpp b/include/fs/archive_save_data.hpp new file mode 100644 index 00000000..ef40a370 --- /dev/null +++ b/include/fs/archive_save_data.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "archive_base.hpp" + +class SaveDataArchive : public ArchiveBase { + +public: + SaveDataArchive(Memory& mem) : ArchiveBase(mem) {} + + u64 getFreeBytes() override { return 0; } + const char* name() override { return "SaveData"; } + + bool openFile(const FSPath& path) override; + ArchiveBase* openArchive(const FSPath& path) override; + std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override; +}; \ No newline at end of file diff --git a/include/fs/archive_sdmc.hpp b/include/fs/archive_sdmc.hpp new file mode 100644 index 00000000..e8a26b58 --- /dev/null +++ b/include/fs/archive_sdmc.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "archive_base.hpp" + +class SDMCArchive : public ArchiveBase { + +public: + SDMCArchive(Memory& mem) : ArchiveBase(mem) {} + + u64 getFreeBytes() override { return 0; } + const char* name() override { return "SDMC"; } + + bool openFile(const FSPath& path) override; + ArchiveBase* openArchive(const FSPath& path) override; + std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override; +}; \ No newline at end of file diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index aa56632a..c7fa3eb8 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -19,12 +19,11 @@ namespace SVCResult { BadThreadPriority = 0xE0E01BFD, PortNameTooLong = 0xE0E0181E, - }; } enum class KernelObjectType : u8 { - AddressArbiter, Event, File, Port, Process, ResourceLimit, Session, Thread, Dummy + AddressArbiter, Archive, Event, File, Port, Process, ResourceLimit, Session, Thread, Dummy }; enum class ResourceLimitCategory : int { @@ -49,9 +48,7 @@ enum class ArbitrationType { DecrementAndWaitIfLessTimeout = 4 }; -struct AddressArbiter { - -}; +struct AddressArbiter {}; struct ResourceLimits { Handle handle; @@ -132,6 +129,7 @@ struct Thread { static const char* kernelObjectTypeToString(KernelObjectType t) { switch (t) { case KernelObjectType::AddressArbiter: return "address arbiter"; + case KernelObjectType::Archive: return "archive"; case KernelObjectType::Event: return "event"; case KernelObjectType::File: return "file"; case KernelObjectType::Port: return "port"; diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 082d9110..d14ee4ec 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -1,5 +1,7 @@ #pragma once #include "fs/archive_ncch.hpp" +#include "fs/archive_save_data.hpp" +#include "fs/archive_sdmc.hpp" #include "helpers.hpp" #include "kernel_types.hpp" #include "logger.hpp" @@ -15,10 +17,14 @@ class FSService { MAKE_LOG_FUNCTION(log, fsLogger) + // The different filesystem archives (Save data, RomFS+ExeFS, etc) SelfNCCHArchive selfNcch; + SaveDataArchive saveData; + SDMCArchive sdmc; ArchiveBase* getArchiveFromID(u32 id); - std::optional openFile(ArchiveBase* archive, const FSPath& path); + std::optional openArchiveHandle(u32 archiveID, const FSPath& path); + std::optional openFileHandle(ArchiveBase* archive, const FSPath& path); // Service commands void initialize(u32 messagePointer); @@ -26,7 +32,7 @@ class FSService { void openFileDirectly(u32 messagePointer); public: - FSService(Memory& mem, Kernel& kernel) : mem(mem), selfNcch(mem), kernel(kernel) {} + FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), sdmc(mem), selfNcch(mem), kernel(kernel) {} void reset(); void handleSyncRequest(u32 messagePointer); }; \ No newline at end of file diff --git a/src/core/filesystem/archive_ncch.cpp b/src/core/fs/archive_ncch.cpp similarity index 95% rename from src/core/filesystem/archive_ncch.cpp rename to src/core/fs/archive_ncch.cpp index 4d72422e..86cf3cba 100644 --- a/src/core/filesystem/archive_ncch.cpp +++ b/src/core/fs/archive_ncch.cpp @@ -15,7 +15,7 @@ bool SelfNCCHArchive::openFile(const FSPath& path) { return true; } -ArchiveBase* SelfNCCHArchive::openArchive(FSPath& path) { +ArchiveBase* SelfNCCHArchive::openArchive(const FSPath& path) { if (path.type != PathType::Empty) { printf("Invalid path type for SelfNCCH archive: %d\n", path.type); return nullptr; diff --git a/src/core/fs/archive_save_data.cpp b/src/core/fs/archive_save_data.cpp new file mode 100644 index 00000000..ff114cfa --- /dev/null +++ b/src/core/fs/archive_save_data.cpp @@ -0,0 +1,17 @@ +#include "fs/archive_save_data.hpp" +#include + +bool SaveDataArchive::openFile(const FSPath& path) { + Helpers::panic("SaveDataArchive::OpenFile"); + return false; +} + +ArchiveBase* SaveDataArchive::openArchive(const FSPath& path) { + Helpers::panic("SaveDataArchive::OpenArchive"); + return nullptr; +} + +std::optional SaveDataArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) { + Helpers::panic("SaveDataArchive::ReadFile"); + return std::nullopt; +} \ No newline at end of file diff --git a/src/core/fs/archive_sdmc.cpp b/src/core/fs/archive_sdmc.cpp new file mode 100644 index 00000000..71506e81 --- /dev/null +++ b/src/core/fs/archive_sdmc.cpp @@ -0,0 +1,17 @@ +#include "fs/archive_sdmc.hpp" +#include + +bool SDMCArchive::openFile(const FSPath& path) { + printf("SDMCArchive::OpenFile: Failed"); + return false; +} + +ArchiveBase* SDMCArchive::openArchive(const FSPath& path) { + printf("SDMCArchive::OpenArchive: Failed"); + return nullptr; +} + +std::optional SDMCArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) { + printf("SDMCArchive::ReadFile: Failed"); + return std::nullopt; +} \ No newline at end of file diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index 70f58abe..7db8c3bf 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -150,6 +150,7 @@ void Kernel::sleepThread(s64 ns) { if (ns < 0) { Helpers::panic("Sleeping a thread for a negative amount of ns"); } else if (ns == 0) { // Used when we want to force a thread switch + // TODO: Does sleep(0) always switch to another thread, or can it return to the same one if it's the highest prio one? threads[currentThreadIndex].status = ThreadStatus::Ready; switchToNextThread(); } else { // If we're sleeping for > 0 ns diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 899137c3..54128c64 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -6,6 +6,8 @@ using namespace ELFIO; std::optional Memory::loadELF(std::ifstream& file) { + loadedCXI = std::nullopt; // ELF files don't have a CXI, so set this to null + elfio reader; if (!file.good() || !reader.load(file)) { printf("Woops failed to load ELF\n"); diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index e51ce948..90b299af 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -21,13 +21,15 @@ void FSService::reset() {} ArchiveBase* FSService::getArchiveFromID(u32 id) { switch (id) { case ArchiveID::SelfNCCH: return &selfNcch; + case ArchiveID::SaveData: return &saveData; + case ArchiveID::SDMC: return &sdmc; default: Helpers::panic("Unknown archive. ID: %d\n", id); return nullptr; } } -std::optional FSService::openFile(ArchiveBase* archive, const FSPath& path) { +std::optional FSService::openFileHandle(ArchiveBase* archive, const FSPath& path) { bool opened = archive->openFile(path); if (opened) { auto handle = kernel.makeObject(KernelObjectType::File); @@ -40,6 +42,27 @@ std::optional FSService::openFile(ArchiveBase* archive, const FSPath& pa } } +std::optional FSService::openArchiveHandle(u32 archiveID, const FSPath& path) { + ArchiveBase* archive = getArchiveFromID(archiveID); + + if (archive == nullptr) [[unlikely]] { + Helpers::panic("OpenArchive: Tried to open unknown archive %d.", archiveID); + return std::nullopt; + } + + bool opened = archive->openArchive(path); + if (opened) { + auto handle = kernel.makeObject(KernelObjectType::Archive); + auto& archiveObject = kernel.getObjects()[handle]; + archiveObject.data = new ArchiveSession(archive, path); + + return handle; + } + else { + return std::nullopt; + } +} + void FSService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { @@ -56,8 +79,22 @@ void FSService::initialize(u32 messagePointer) { } void FSService::openArchive(u32 messagePointer) { - log("FS::OpenArchive (failure)\n"); - mem.write32(messagePointer + 4, Result::Failure); + const u32 archiveID = mem.read32(messagePointer + 4); + const u32 archivePathType = mem.read32(messagePointer + 8); + const u32 archivePathSize = mem.read32(messagePointer + 12); + const u32 archivePathPointer = mem.read32(messagePointer + 20); + FSPath archivePath{ .type = archivePathType, .size = archivePathSize, .pointer = archivePathPointer }; + + log("FS::OpenArchive (archive ID = %d, archive path type = %d)\n", archiveID, archivePathType); + + std::optional handle = openArchiveHandle(archiveID, archivePath); + if (handle.has_value()) { + mem.write32(messagePointer + 4, Result::Success); + mem.write64(messagePointer + 8, handle.value()); + } else { + log("FS::OpenArchive: Failed to open archive with id = %d\n", archiveID); + mem.write32(messagePointer + 4, Result::Failure); + } } void FSService::openFileDirectly(u32 messagePointer) { @@ -86,7 +123,7 @@ void FSService::openFileDirectly(u32 messagePointer) { Helpers::panic("OpenFileDirectly: Failed to open archive with given path"); } - std::optional handle = openFile(archive, filePath); + std::optional handle = openFileHandle(archive, filePath); if (!handle.has_value()) { Helpers::panic("OpenFileDirectly: Failed to open file with given path"); } else {