From f3ce29bf2d415ccd5c783b30867a2548bb545145 Mon Sep 17 00:00:00 2001 From: offtkp Date: Fri, 28 Jul 2023 19:54:18 +0300 Subject: [PATCH] Add IVFC parser --- CMakeLists.txt | 4 ++- include/fs/ivfc.hpp | 22 ++++++++++++ include/fs/romfs.hpp | 13 ++++++++ src/core/fs/ivfc.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++ src/core/fs/romfs.cpp | 21 ++++++++++++ 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 include/fs/ivfc.hpp create mode 100644 include/fs/romfs.hpp create mode 100644 src/core/fs/ivfc.cpp create mode 100644 src/core/fs/romfs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 618b08d3..c5725ff0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,8 @@ set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp src/core/loader/lz77.cpp) set(FS_SOURCE_FILES src/core/fs/archive_self_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp - src/core/fs/archive_ext_save_data.cpp src/core/fs/archive_ncch.cpp + src/core/fs/archive_ext_save_data.cpp src/core/fs/archive_ncch.cpp src/core/fs/romfs.cpp + src/core/fs/ivfc.cpp ) set(RENDERER_SW_SOURCE_FILES src/core/renderer_sw/renderer_sw.cpp) @@ -156,6 +157,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/crypto/aes_engine.hpp include/metaprogramming.hpp include/PICA/pica_vertex.hpp include/config.hpp include/services/ir_user.hpp include/http_server.hpp include/cheats.hpp include/action_replay.hpp include/renderer_sw/renderer_sw.hpp include/compiler_builtins.hpp + include/fs/romfs.hpp include/fs/ivfc.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/fs/ivfc.hpp b/include/fs/ivfc.hpp new file mode 100644 index 00000000..b8d72380 --- /dev/null +++ b/include/fs/ivfc.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include "helpers.hpp" + +namespace IVFC { + + struct IVFCLevel { + u64 logicalOffset; + u64 size; + u64 blockSize; + }; + + struct IVFC { + u64 masterHashSize; + std::vector levels; + }; + + size_t parseIVFC(uintptr_t ivfcStart, IVFC& ivfc); + +} // namespace IVFC \ No newline at end of file diff --git a/include/fs/romfs.hpp b/include/fs/romfs.hpp new file mode 100644 index 00000000..4ce26c62 --- /dev/null +++ b/include/fs/romfs.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "helpers.hpp" +#include + +namespace RomFS { + + struct RomFSNode { + std::vector children; + }; + + RomFSNode parseRomFSTree(uintptr_t romFS, u64 romFSSize); + +} // namespace RomFS \ No newline at end of file diff --git a/src/core/fs/ivfc.cpp b/src/core/fs/ivfc.cpp new file mode 100644 index 00000000..db633550 --- /dev/null +++ b/src/core/fs/ivfc.cpp @@ -0,0 +1,78 @@ +#include "fs/ivfc.hpp" + +namespace IVFC { + + size_t parseIVFC(uintptr_t ivfcStart, IVFC& ivfc) { + uintptr_t ivfcPointer = ivfcStart; + std::string magicIVFC((char*)ivfcPointer, 4); + ivfcPointer += 4; + + if (magicIVFC != "IVFC") { + printf("Invalid IVFC magic: %s\n", magicIVFC.c_str()); + return 0; + } + + uint32_t magicIdentifier = *(u32*)ivfcPointer; + ivfcPointer += 4; + + // RomFS IVFC uses 0x10000, DISA/DIFF IVFC uses 0x20000 here + if (magicIdentifier != 0x10000 && magicIdentifier != 0x20000) { + printf("Invalid IVFC magic identifier: %08X\n", magicIdentifier); + return 0; + } + + if (magicIdentifier == 0x10000) { + ivfc.masterHashSize = *(u32*)ivfcPointer; + ivfcPointer += 4; + // RomFS IVFC uses 3 levels + ivfc.levels.resize(3); + } else { + ivfc.masterHashSize = *(u64*)ivfcPointer; + ivfcPointer += 8; + // DISA/DIFF IVFC uses 4 levels + ivfc.levels.resize(4); + } + + for (size_t i = 0; i < ivfc.levels.size(); i++) { + IVFCLevel level; + + level.logicalOffset = *(u64*)ivfcPointer; + ivfcPointer += 8; + + level.size = *(u64*)ivfcPointer; + ivfcPointer += 8; + + // This field is in log2 + level.blockSize = 1 << *(u32*)ivfcPointer; + ivfcPointer += 4; + + // Skip 4 reserved bytes + ivfcPointer += 4; + + ivfc.levels[i] = level; + } + + u64 ivfcDescriptorSize = *(u64*)ivfcPointer; + ivfcPointer += 8; + + uintptr_t ivfcActualSize = ivfcPointer - ivfcStart; + + // According to 3DBrew, this is usually the case but not guaranteed + if (ivfcActualSize != ivfcDescriptorSize) { + printf("IVFC descriptor size mismatch: %lx != %lx\n", ivfcActualSize, ivfcDescriptorSize); + } + + if (magicIdentifier == 0x10000 && ivfcActualSize != 0x5C) { + // This is always 0x5C bytes long + printf("Invalid IVFC size: %08x\n", (u32)ivfcActualSize); + return 0; + } else if (magicIdentifier == 0x20000 && ivfcActualSize != 0x78) { + // This is always 0x78 bytes long + printf("Invalid IVFC size: %08x\n", (u32)ivfcActualSize); + return 0; + } + + return ivfcActualSize; + } + +} // namespace IVFC \ No newline at end of file diff --git a/src/core/fs/romfs.cpp b/src/core/fs/romfs.cpp new file mode 100644 index 00000000..95c34264 --- /dev/null +++ b/src/core/fs/romfs.cpp @@ -0,0 +1,21 @@ +#include "fs/romfs.hpp" +#include "fs/ivfc.hpp" +#include + +namespace RomFS { + + RomFSNode parseRomFSTree(uintptr_t romFS, u64 romFSSize) { + RomFSNode root; + + IVFC::IVFC ivfc; + size_t ivfcSize = IVFC::parseIVFC((uintptr_t)romFS, ivfc); + + if (ivfcSize == 0) { + printf("Failed to parse IVFC\n"); + return {}; + } + + return root; + } + +} // namespace RomFS \ No newline at end of file