diff options
Diffstat (limited to 'src/core')
270 files changed, 3408 insertions, 1061 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a74270a0f..26f727d96 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -35,8 +35,12 @@ add_library(core STATIC file_sys/mode.h file_sys/nca_metadata.cpp file_sys/nca_metadata.h + file_sys/nca_patch.cpp + file_sys/nca_patch.h file_sys/partition_filesystem.cpp file_sys/partition_filesystem.h + file_sys/patch_manager.cpp + file_sys/patch_manager.h file_sys/program_metadata.cpp file_sys/program_metadata.h file_sys/registered_cache.cpp @@ -49,6 +53,8 @@ add_library(core STATIC file_sys/savedata_factory.h file_sys/sdmc_factory.cpp file_sys/sdmc_factory.h + file_sys/submission_package.cpp + file_sys/submission_package.h file_sys/vfs.cpp file_sys/vfs.h file_sys/vfs_concat.cpp @@ -359,6 +365,8 @@ add_library(core STATIC loader/nro.h loader/nso.cpp loader/nso.h + loader/nsp.cpp + loader/nsp.h loader/xci.cpp loader/xci.h memory.cpp @@ -380,7 +388,7 @@ add_library(core STATIC create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn) +target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives) if (ARCHITECTURE_x86_64) target_sources(core PRIVATE diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index c368745b1..16d528994 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -6,11 +6,14 @@ #include <array> #include "common/common_types.h" -#include "core/hle/kernel/vm_manager.h" + +namespace Kernel { +enum class VMAPermission : u8; +} namespace Core { -/// Generic ARM11 CPU interface +/// Generic ARMv8 CPU interface class ARM_Interface : NonCopyable { public: virtual ~ARM_Interface() {} @@ -19,9 +22,9 @@ public: std::array<u64, 31> cpu_registers; u64 sp; u64 pc; - u64 cpsr; - std::array<u128, 32> fpu_registers; - u64 fpscr; + u64 pstate; + std::array<u128, 32> vector_registers; + u64 fpcr; }; /// Runs the CPU until an event happens @@ -31,11 +34,11 @@ public: virtual void Step() = 0; /// Maps a backing memory region for the CPU - virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, + virtual void MapBackingMemory(VAddr address, std::size_t size, u8* memory, Kernel::VMAPermission perms) = 0; /// Unmaps a region of memory that was previously mapped using MapBackingMemory - virtual void UnmapMemory(VAddr address, size_t size) = 0; + virtual void UnmapMemory(VAddr address, std::size_t size) = 0; /// Clear all instruction cache virtual void ClearInstructionCache() = 0; @@ -69,42 +72,50 @@ public: */ virtual void SetReg(int index, u64 value) = 0; - virtual u128 GetExtReg(int index) const = 0; - - virtual void SetExtReg(int index, u128 value) = 0; - /** - * Gets the value of a VFP register - * @param index Register index (0-31) - * @return Returns the value in the register + * Gets the value of a specified vector register. + * + * @param index The index of the vector register. + * @return the value within the vector register. */ - virtual u32 GetVFPReg(int index) const = 0; + virtual u128 GetVectorReg(int index) const = 0; /** - * Sets a VFP register to the given value - * @param index Register index (0-31) - * @param value Value to set register to + * Sets a given value into a vector register. + * + * @param index The index of the vector register. + * @param value The new value to place in the register. */ - virtual void SetVFPReg(int index, u32 value) = 0; + virtual void SetVectorReg(int index, u128 value) = 0; /** - * Get the current CPSR register - * @return Returns the value of the CPSR register + * Get the current PSTATE register + * @return Returns the value of the PSTATE register */ - virtual u32 GetCPSR() const = 0; + virtual u32 GetPSTATE() const = 0; /** - * Set the current CPSR register - * @param cpsr Value to set CPSR to + * Set the current PSTATE register + * @param pstate Value to set PSTATE to */ - virtual void SetCPSR(u32 cpsr) = 0; + virtual void SetPSTATE(u32 pstate) = 0; virtual VAddr GetTlsAddress() const = 0; virtual void SetTlsAddress(VAddr address) = 0; + /** + * Gets the value within the TPIDR_EL0 (read/write software thread ID) register. + * + * @return the value within the register. + */ virtual u64 GetTPIDR_EL0() const = 0; + /** + * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register. + * + * @param value The new value to place in the register. + */ virtual void SetTPIDR_EL0(u64 value) = 0; /** @@ -119,6 +130,7 @@ public: */ virtual void LoadContext(const ThreadContext& ctx) = 0; + /// Clears the exclusive monitor's state. virtual void ClearExclusiveState() = 0; /// Prepare core for thread reschedule (if needed to correctly handle state) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index de44ccebd..7be5a38de 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -7,12 +7,15 @@ #include <dynarmic/A64/a64.h> #include <dynarmic/A64/config.h> #include "common/logging/log.h" +#include "common/microprofile.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/core.h" #include "core/core_cpu.h" #include "core/core_timing.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" +#include "core/hle/kernel/vm_manager.h" #include "core/memory.h" namespace Core { @@ -57,7 +60,7 @@ public: Memory::Write64(vaddr + 8, value[1]); } - void InterpreterFallback(u64 pc, size_t num_instructions) override { + void InterpreterFallback(u64 pc, std::size_t num_instructions) override { LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, num_instructions, MemoryReadCode(pc)); @@ -78,9 +81,20 @@ public: case Dynarmic::A64::Exception::SendEventLocal: case Dynarmic::A64::Exception::Yield: return; + case Dynarmic::A64::Exception::Breakpoint: + if (GDBStub::IsServerEnabled()) { + parent.jit->HaltExecution(); + parent.SetPC(pc); + Kernel::Thread* thread = Kernel::GetCurrentThread(); + parent.SaveContext(thread->context); + GDBStub::Break(); + GDBStub::SendTrap(thread, 5); + return; + } + [[fallthrough]]; default: ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})", - static_cast<size_t>(exception), pc); + static_cast<std::size_t>(exception), pc); } } @@ -109,7 +123,7 @@ public: } ARM_Dynarmic& parent; - size_t num_interpreted_instructions = 0; + std::size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; }; @@ -143,7 +157,10 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { return std::make_unique<Dynarmic::A64::Jit>(config); } +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); + void ARM_Dynarmic::Run() { + MICROPROFILE_SCOPE(ARM_Jit_Dynarmic); ASSERT(Memory::GetCurrentPageTable() == current_page_table); jit->Run(); @@ -153,7 +170,8 @@ void ARM_Dynarmic::Step() { cb->InterpreterFallback(jit->GetPC(), 1); } -ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index) +ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, + std::size_t core_index) : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { ThreadContext ctx; @@ -164,12 +182,12 @@ ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, ARM_Dynarmic::~ARM_Dynarmic() = default; -void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory, +void ARM_Dynarmic::MapBackingMemory(u64 address, std::size_t size, u8* memory, Kernel::VMAPermission perms) { inner_unicorn.MapBackingMemory(address, size, memory, perms); } -void ARM_Dynarmic::UnmapMemory(u64 address, size_t size) { +void ARM_Dynarmic::UnmapMemory(u64 address, std::size_t size) { inner_unicorn.UnmapMemory(address, size); } @@ -189,29 +207,20 @@ void ARM_Dynarmic::SetReg(int index, u64 value) { jit->SetRegister(index, value); } -u128 ARM_Dynarmic::GetExtReg(int index) const { +u128 ARM_Dynarmic::GetVectorReg(int index) const { return jit->GetVector(index); } -void ARM_Dynarmic::SetExtReg(int index, u128 value) { +void ARM_Dynarmic::SetVectorReg(int index, u128 value) { jit->SetVector(index, value); } -u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const { - UNIMPLEMENTED(); - return {}; -} - -void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) { - UNIMPLEMENTED(); -} - -u32 ARM_Dynarmic::GetCPSR() const { +u32 ARM_Dynarmic::GetPSTATE() const { return jit->GetPstate(); } -void ARM_Dynarmic::SetCPSR(u32 cpsr) { - jit->SetPstate(cpsr); +void ARM_Dynarmic::SetPSTATE(u32 pstate) { + jit->SetPstate(pstate); } u64 ARM_Dynarmic::GetTlsAddress() const { @@ -234,18 +243,18 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); ctx.pc = jit->GetPC(); - ctx.cpsr = jit->GetPstate(); - ctx.fpu_registers = jit->GetVectors(); - ctx.fpscr = jit->GetFpcr(); + ctx.pstate = jit->GetPstate(); + ctx.vector_registers = jit->GetVectors(); + ctx.fpcr = jit->GetFpcr(); } void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { jit->SetRegisters(ctx.cpu_registers); jit->SetSP(ctx.sp); jit->SetPC(ctx.pc); - jit->SetPstate(static_cast<u32>(ctx.cpsr)); - jit->SetVectors(ctx.fpu_registers); - jit->SetFpcr(static_cast<u32>(ctx.fpscr)); + jit->SetPstate(static_cast<u32>(ctx.pstate)); + jit->SetVectors(ctx.vector_registers); + jit->SetFpcr(static_cast<u32>(ctx.fpcr)); } void ARM_Dynarmic::PrepareReschedule() { @@ -265,10 +274,10 @@ void ARM_Dynarmic::PageTableChanged() { current_page_table = Memory::GetCurrentPageTable(); } -DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(size_t core_count) : monitor(core_count) {} +DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; -void DynarmicExclusiveMonitor::SetExclusive(size_t core_index, VAddr addr) { +void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { // Size doesn't actually matter. monitor.Mark(core_index, addr, 16); } @@ -277,30 +286,30 @@ void DynarmicExclusiveMonitor::ClearExclusive() { monitor.Clear(); } -bool DynarmicExclusiveMonitor::ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { Memory::Write8(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 2, [&] { Memory::Write16(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 4, [&] { Memory::Write32(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 8, [&] { Memory::Write64(vaddr, value); }); } -bool DynarmicExclusiveMonitor::ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) { +bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { - Memory::Write64(vaddr, value[0]); - Memory::Write64(vaddr, value[1]); + Memory::Write64(vaddr + 0, value[0]); + Memory::Write64(vaddr + 8, value[1]); }); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 3bdfd8cd9..4ee92ee27 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -12,6 +12,10 @@ #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" +namespace Memory { +struct PageTable; +} + namespace Core { class ARM_Dynarmic_Callbacks; @@ -19,24 +23,22 @@ class DynarmicExclusiveMonitor; class ARM_Dynarmic final : public ARM_Interface { public: - ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index); + ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic(); - void MapBackingMemory(VAddr address, size_t size, u8* memory, + void MapBackingMemory(VAddr address, std::size_t size, u8* memory, Kernel::VMAPermission perms) override; - void UnmapMemory(u64 address, size_t size) override; + void UnmapMemory(u64 address, std::size_t size) override; void SetPC(u64 pc) override; u64 GetPC() const override; u64 GetReg(int index) const override; void SetReg(int index, u64 value) override; - u128 GetExtReg(int index) const override; - void SetExtReg(int index, u128 value) override; - u32 GetVFPReg(int index) const override; - void SetVFPReg(int index, u32 value) override; - u32 GetCPSR() const override; + u128 GetVectorReg(int index) const override; + void SetVectorReg(int index, u128 value) override; + u32 GetPSTATE() const override; + void SetPSTATE(u32 pstate) override; void Run() override; void Step() override; - void SetCPSR(u32 cpsr) override; VAddr GetTlsAddress() const override; void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; @@ -59,7 +61,7 @@ private: std::unique_ptr<Dynarmic::A64::Jit> jit; ARM_Unicorn inner_unicorn; - size_t core_index; + std::size_t core_index; std::shared_ptr<DynarmicExclusiveMonitor> exclusive_monitor; Memory::PageTable* current_page_table = nullptr; @@ -67,17 +69,17 @@ private: class DynarmicExclusiveMonitor final : public ExclusiveMonitor { public: - explicit DynarmicExclusiveMonitor(size_t core_count); + explicit DynarmicExclusiveMonitor(std::size_t core_count); ~DynarmicExclusiveMonitor(); - void SetExclusive(size_t core_index, VAddr addr) override; + void SetExclusive(std::size_t core_index, VAddr addr) override; void ClearExclusive() override; - bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) override; - bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) override; - bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) override; - bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) override; - bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) override; + bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override; + bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override; + bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) override; + bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) override; + bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override; private: friend class ARM_Dynarmic; diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h index 6f9b51573..f59aca667 100644 --- a/src/core/arm/exclusive_monitor.h +++ b/src/core/arm/exclusive_monitor.h @@ -12,14 +12,14 @@ class ExclusiveMonitor { public: virtual ~ExclusiveMonitor(); - virtual void SetExclusive(size_t core_index, VAddr addr) = 0; + virtual void SetExclusive(std::size_t core_index, VAddr addr) = 0; virtual void ClearExclusive() = 0; - virtual bool ExclusiveWrite8(size_t core_index, VAddr vaddr, u8 value) = 0; - virtual bool ExclusiveWrite16(size_t core_index, VAddr vaddr, u16 value) = 0; - virtual bool ExclusiveWrite32(size_t core_index, VAddr vaddr, u32 value) = 0; - virtual bool ExclusiveWrite64(size_t core_index, VAddr vaddr, u64 value) = 0; - virtual bool ExclusiveWrite128(size_t core_index, VAddr vaddr, u128 value) = 0; + virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0; + virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0; + virtual bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) = 0; + virtual bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) = 0; + virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0; }; } // namespace Core diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 307f12198..e218a0b15 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -90,12 +90,12 @@ ARM_Unicorn::~ARM_Unicorn() { CHECKED(uc_close(uc)); } -void ARM_Unicorn::MapBackingMemory(VAddr address, size_t size, u8* memory, +void ARM_Unicorn::MapBackingMemory(VAddr address, std::size_t size, u8* memory, Kernel::VMAPermission perms) { CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory)); } -void ARM_Unicorn::UnmapMemory(VAddr address, size_t size) { +void ARM_Unicorn::UnmapMemory(VAddr address, std::size_t size) { CHECKED(uc_mem_unmap(uc, address, size)); } @@ -131,33 +131,24 @@ void ARM_Unicorn::SetReg(int regn, u64 val) { CHECKED(uc_reg_write(uc, treg, &val)); } -u128 ARM_Unicorn::GetExtReg(int /*index*/) const { +u128 ARM_Unicorn::GetVectorReg(int /*index*/) const { UNIMPLEMENTED(); static constexpr u128 res{}; return res; } -void ARM_Unicorn::SetExtReg(int /*index*/, u128 /*value*/) { +void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) { UNIMPLEMENTED(); } -u32 ARM_Unicorn::GetVFPReg(int /*index*/) const { - UNIMPLEMENTED(); - return {}; -} - -void ARM_Unicorn::SetVFPReg(int /*index*/, u32 /*value*/) { - UNIMPLEMENTED(); -} - -u32 ARM_Unicorn::GetCPSR() const { +u32 ARM_Unicorn::GetPSTATE() const { u64 nzcv{}; CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv)); return static_cast<u32>(nzcv); } -void ARM_Unicorn::SetCPSR(u32 cpsr) { - u64 nzcv = cpsr; +void ARM_Unicorn::SetPSTATE(u32 pstate) { + u64 nzcv = pstate; CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv)); } @@ -193,10 +184,10 @@ void ARM_Unicorn::Step() { ExecuteInstructions(1); } -MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); +MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64)); void ARM_Unicorn::ExecuteInstructions(int num_instructions) { - MICROPROFILE_SCOPE(ARM_Jit); + MICROPROFILE_SCOPE(ARM_Jit_Unicorn); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { @@ -219,7 +210,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) { CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp)); CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc)); - CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.cpsr)); + CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate)); for (auto i = 0; i < 29; ++i) { uregs[i] = UC_ARM64_REG_X0 + i; @@ -234,7 +225,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) { for (int i = 0; i < 32; ++i) { uregs[i] = UC_ARM64_REG_Q0 + i; - tregs[i] = &ctx.fpu_registers[i]; + tregs[i] = &ctx.vector_registers[i]; } CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32)); @@ -246,7 +237,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) { CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp)); CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc)); - CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.cpsr)); + CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate)); for (int i = 0; i < 29; ++i) { uregs[i] = UC_ARM64_REG_X0 + i; @@ -261,7 +252,7 @@ void ARM_Unicorn::LoadContext(const ThreadContext& ctx) { for (auto i = 0; i < 32; ++i) { uregs[i] = UC_ARM64_REG_Q0 + i; - tregs[i] = (void*)&ctx.fpu_registers[i]; + tregs[i] = (void*)&ctx.vector_registers[i]; } CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index bd6b2f723..75761950b 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -15,19 +15,17 @@ class ARM_Unicorn final : public ARM_Interface { public: ARM_Unicorn(); ~ARM_Unicorn(); - void MapBackingMemory(VAddr address, size_t size, u8* memory, + void MapBackingMemory(VAddr address, std::size_t size, u8* memory, Kernel::VMAPermission perms) override; - void UnmapMemory(VAddr address, size_t size) override; + void UnmapMemory(VAddr address, std::size_t size) override; void SetPC(u64 pc) override; u64 GetPC() const override; u64 GetReg(int index) const override; void SetReg(int index, u64 value) override; - u128 GetExtReg(int index) const override; - void SetExtReg(int index, u128 value) override; - u32 GetVFPReg(int index) const override; - void SetVFPReg(int index, u32 value) override; - u32 GetCPSR() const override; - void SetCPSR(u32 cpsr) override; + u128 GetVectorReg(int index) const override; + void SetVectorReg(int index, u128 value) override; + u32 GetPSTATE() const override; + void SetPSTATE(u32 pstate) override; VAddr GetTlsAddress() const override; void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; diff --git a/src/core/core.cpp b/src/core/core.cpp index 2cfae18df..50f0a42fb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -14,6 +14,9 @@ #include "core/core.h" #include "core/core_cpu.h" #include "core/core_timing.h" +#include "core/file_sys/mode.h" +#include "core/file_sys/vfs_concat.h" +#include "core/file_sys/vfs_real.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" @@ -21,14 +24,11 @@ #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/hle/service/service.h" -#include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" #include "core/perf_stats.h" #include "core/settings.h" #include "core/telemetry_session.h" -#include "file_sys/vfs_concat.h" -#include "file_sys/vfs_real.h" #include "video_core/debug_utils/debug_utils.h" #include "video_core/gpu.h" #include "video_core/renderer_base.h" @@ -136,11 +136,11 @@ struct System::Impl { if (virtual_filesystem == nullptr) virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); - current_process = Kernel::Process::Create(kernel, "main"); + kernel.MakeCurrentProcess(Kernel::Process::Create(kernel, "main")); cpu_barrier = std::make_shared<CpuBarrier>(); cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); - for (size_t index = 0; index < cpu_cores.size(); ++index) { + for (std::size_t index = 0; index < cpu_cores.size(); ++index) { cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index); } @@ -161,7 +161,7 @@ struct System::Impl { // CPU core 0 is run on the main thread thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; if (Settings::values.use_multi_core) { - for (size_t index = 0; index < cpu_core_threads.size(); ++index) { + for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) { cpu_core_threads[index] = std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]); thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1]; @@ -202,7 +202,7 @@ struct System::Impl { return init_result; } - const Loader::ResultStatus load_result{app_loader->Load(current_process)}; + const Loader::ResultStatus load_result{app_loader->Load(kernel.CurrentProcess())}; if (load_result != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); Shutdown(); @@ -281,12 +281,11 @@ struct System::Impl { std::unique_ptr<VideoCore::RendererBase> renderer; std::unique_ptr<Tegra::GPU> gpu_core; std::shared_ptr<Tegra::DebugContext> debug_context; - Kernel::SharedPtr<Kernel::Process> current_process; std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor; std::shared_ptr<CpuBarrier> cpu_barrier; std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; - size_t active_core{}; ///< Active core, only used in single thread mode + std::size_t active_core{}; ///< Active core, only used in single thread mode /// Service manager std::shared_ptr<Service::SM::ServiceManager> service_manager; @@ -349,7 +348,7 @@ ARM_Interface& System::CurrentArmInterface() { return CurrentCpuCore().ArmInterface(); } -size_t System::CurrentCoreIndex() { +std::size_t System::CurrentCoreIndex() { return CurrentCpuCore().CoreIndex(); } @@ -357,21 +356,25 @@ Kernel::Scheduler& System::CurrentScheduler() { return *CurrentCpuCore().Scheduler(); } -const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) { +const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(std::size_t core_index) { ASSERT(core_index < NUM_CPU_CORES); return impl->cpu_cores[core_index]->Scheduler(); } Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() { - return impl->current_process; + return impl->kernel.CurrentProcess(); } -ARM_Interface& System::ArmInterface(size_t core_index) { +const Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() const { + return impl->kernel.CurrentProcess(); +} + +ARM_Interface& System::ArmInterface(std::size_t core_index) { ASSERT(core_index < NUM_CPU_CORES); return impl->cpu_cores[core_index]->ArmInterface(); } -Cpu& System::CpuCore(size_t core_index) { +Cpu& System::CpuCore(std::size_t core_index) { ASSERT(core_index < NUM_CPU_CORES); return *impl->cpu_cores[core_index]; } @@ -440,8 +443,8 @@ void System::SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) { impl->debug_context = std::move(context); } -std::shared_ptr<Tegra::DebugContext> System::GetGPUDebugContext() const { - return impl->debug_context; +Tegra::DebugContext* System::GetGPUDebugContext() const { + return impl->debug_context.get(); } void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) { diff --git a/src/core/core.h b/src/core/core.h index eee1fecc1..f9a3e97e3 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -145,16 +145,16 @@ public: ARM_Interface& CurrentArmInterface(); /// Gets the index of the currently running CPU core - size_t CurrentCoreIndex(); + std::size_t CurrentCoreIndex(); /// Gets the scheduler for the CPU core that is currently running Kernel::Scheduler& CurrentScheduler(); /// Gets an ARM interface to the CPU core with the specified index - ARM_Interface& ArmInterface(size_t core_index); + ARM_Interface& ArmInterface(std::size_t core_index); /// Gets a CPU interface to the CPU core with the specified index - Cpu& CpuCore(size_t core_index); + Cpu& CpuCore(std::size_t core_index); /// Gets the exclusive monitor ExclusiveMonitor& Monitor(); @@ -172,11 +172,14 @@ public: const VideoCore::RendererBase& Renderer() const; /// Gets the scheduler for the CPU core with the specified index - const std::shared_ptr<Kernel::Scheduler>& Scheduler(size_t core_index); + const std::shared_ptr<Kernel::Scheduler>& Scheduler(std::size_t core_index); - /// Gets the current process + /// Provides a reference to the current process Kernel::SharedPtr<Kernel::Process>& CurrentProcess(); + /// Provides a constant reference to the current process. + const Kernel::SharedPtr<Kernel::Process>& CurrentProcess() const; + /// Provides a reference to the kernel instance. Kernel::KernelCore& Kernel(); @@ -209,7 +212,7 @@ public: void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context); - std::shared_ptr<Tegra::DebugContext> GetGPUDebugContext() const; + Tegra::DebugContext* GetGPUDebugContext() const; void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs); diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index b042ee02b..21568ad50 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -9,6 +9,7 @@ #ifdef ARCHITECTURE_x86_64 #include "core/arm/dynarmic/arm_dynarmic.h" #endif +#include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core_cpu.h" #include "core/core_timing.h" @@ -49,7 +50,7 @@ bool CpuBarrier::Rendezvous() { } Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, - std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index) + std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index) : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} { if (Settings::values.use_cpu_jit) { @@ -66,7 +67,9 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get()); } -std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(size_t num_cores) { +Cpu::~Cpu() = default; + +std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { if (Settings::values.use_cpu_jit) { #ifdef ARCHITECTURE_x86_64 return std::make_shared<DynarmicExclusiveMonitor>(num_cores); diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index 40ed34b47..685532965 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -6,11 +6,10 @@ #include <atomic> #include <condition_variable> +#include <cstddef> #include <memory> #include <mutex> -#include <string> #include "common/common_types.h" -#include "core/arm/exclusive_monitor.h" namespace Kernel { class Scheduler; @@ -19,6 +18,7 @@ class Scheduler; namespace Core { class ARM_Interface; +class ExclusiveMonitor; constexpr unsigned NUM_CPU_CORES{4}; @@ -42,7 +42,8 @@ private: class Cpu { public: Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, - std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index); + std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index); + ~Cpu(); void RunLoop(bool tight_loop = true); @@ -66,11 +67,11 @@ public: return core_index == 0; } - size_t CoreIndex() const { + std::size_t CoreIndex() const { return core_index; } - static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(size_t num_cores); + static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores); private: void Reschedule(); @@ -80,7 +81,7 @@ private: std::shared_ptr<Kernel::Scheduler> scheduler; std::atomic<bool> reschedule_pending = false; - size_t core_index; + std::size_t core_index; }; } // namespace Core diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp index 72e4bed67..4be76bb43 100644 --- a/src/core/crypto/aes_util.cpp +++ b/src/core/crypto/aes_util.cpp @@ -10,9 +10,9 @@ namespace Core::Crypto { namespace { -std::vector<u8> CalculateNintendoTweak(size_t sector_id) { +std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) { std::vector<u8> out(0x10); - for (size_t i = 0xF; i <= 0xF; --i) { + for (std::size_t i = 0xF; i <= 0xF; --i) { out[i] = sector_id & 0xFF; sector_id >>= 8; } @@ -20,11 +20,14 @@ std::vector<u8> CalculateNintendoTweak(size_t sector_id) { } } // Anonymous namespace -static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), +static_assert(static_cast<std::size_t>(Mode::CTR) == + static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_CTR), "CTR has incorrect value."); -static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), +static_assert(static_cast<std::size_t>(Mode::ECB) == + static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_ECB), "ECB has incorrect value."); -static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), +static_assert(static_cast<std::size_t>(Mode::XTS) == + static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_XTS), "XTS has incorrect value."); // Structure to hide mbedtls types from header file @@ -33,7 +36,7 @@ struct CipherContext { mbedtls_cipher_context_t decryption_context; }; -template <typename Key, size_t KeySize> +template <typename Key, std::size_t KeySize> Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) : ctx(std::make_unique<CipherContext>()) { mbedtls_cipher_init(&ctx->encryption_context); @@ -54,26 +57,26 @@ Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) //"Failed to set key on mbedtls ciphers."); } -template <typename Key, size_t KeySize> +template <typename Key, std::size_t KeySize> AESCipher<Key, KeySize>::~AESCipher() { mbedtls_cipher_free(&ctx->encryption_context); mbedtls_cipher_free(&ctx->decryption_context); } -template <typename Key, size_t KeySize> +template <typename Key, std::size_t KeySize> void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) || mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0, "Failed to set IV on mbedtls ciphers."); } -template <typename Key, size_t KeySize> -void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) const { +template <typename Key, std::size_t KeySize> +void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const { auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context; mbedtls_cipher_reset(context); - size_t written = 0; + std::size_t written = 0; if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { mbedtls_cipher_update(context, src, size, dest, &written); if (written != size) { @@ -82,11 +85,25 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op } } else { const auto block_size = mbedtls_cipher_get_block_size(context); + if (size < block_size) { + std::vector<u8> block(block_size); + std::memcpy(block.data(), src, size); + Transcode(block.data(), block.size(), block.data(), op); + std::memcpy(dest, block.data(), size); + return; + } - for (size_t offset = 0; offset < size; offset += block_size) { - auto length = std::min<size_t>(block_size, size - offset); + for (std::size_t offset = 0; offset < size; offset += block_size) { + auto length = std::min<std::size_t>(block_size, size - offset); mbedtls_cipher_update(context, src + offset, length, dest + offset, &written); if (written != length) { + if (length < block_size) { + std::vector<u8> block(block_size); + std::memcpy(block.data(), src + offset, length); + Transcode(block.data(), block.size(), block.data(), op); + std::memcpy(dest + offset, block.data(), length); + return; + } LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", length, written); } @@ -96,12 +113,12 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op mbedtls_cipher_finish(context, nullptr, nullptr); } -template <typename Key, size_t KeySize> -void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, - size_t sector_size, Op op) { +template <typename Key, std::size_t KeySize> +void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8* dest, + std::size_t sector_id, std::size_t sector_size, Op op) { ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size."); - for (size_t i = 0; i < size; i += sector_size) { + for (std::size_t i = 0; i < size; i += sector_size) { SetIV(CalculateNintendoTweak(sector_id++)); Transcode<u8, u8>(src + i, sector_size, dest + i, op); } diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h index 8ce9d6612..edc4ab910 100644 --- a/src/core/crypto/aes_util.h +++ b/src/core/crypto/aes_util.h @@ -25,7 +25,7 @@ enum class Op { Decrypt, }; -template <typename Key, size_t KeySize = sizeof(Key)> +template <typename Key, std::size_t KeySize = sizeof(Key)> class AESCipher { static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8."); static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256."); @@ -38,25 +38,25 @@ public: void SetIV(std::vector<u8> iv); template <typename Source, typename Dest> - void Transcode(const Source* src, size_t size, Dest* dest, Op op) const { + void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const { static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>, "Transcode source and destination types must be trivially copyable."); Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op); } - void Transcode(const u8* src, size_t size, u8* dest, Op op) const; + void Transcode(const u8* src, std::size_t size, u8* dest, Op op) const; template <typename Source, typename Dest> - void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id, - size_t sector_size, Op op) { + void XTSTranscode(const Source* src, std::size_t size, Dest* dest, std::size_t sector_id, + std::size_t sector_size, Op op) { static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>, "XTSTranscode source and destination types must be trivially copyable."); XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, sector_size, op); } - void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, - Op op); + void XTSTranscode(const u8* src, std::size_t size, u8* dest, std::size_t sector_id, + std::size_t sector_size, Op op); private: std::unique_ptr<CipherContext> ctx; diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp index 3ea60dbd0..902841c77 100644 --- a/src/core/crypto/ctr_encryption_layer.cpp +++ b/src/core/crypto/ctr_encryption_layer.cpp @@ -8,11 +8,12 @@ namespace Core::Crypto { -CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) +CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, + std::size_t base_offset) : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), iv(16, 0) {} -size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { +std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { if (length == 0) return 0; @@ -21,14 +22,14 @@ size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { UpdateIV(base_offset + offset); std::vector<u8> raw = base->ReadBytes(length, offset); cipher.Transcode(raw.data(), raw.size(), data, Op::Decrypt); - return raw.size(); + return length; } // offset does not fall on block boundary (0x10) std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); UpdateIV(base_offset + offset - sector_offset); cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt); - size_t read = 0x10 - sector_offset; + std::size_t read = 0x10 - sector_offset; if (length + sector_offset < 0x10) { std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); @@ -43,9 +44,9 @@ void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) { iv.assign(iv_.cbegin(), iv_.cbegin() + length); } -void CTREncryptionLayer::UpdateIV(size_t offset) const { +void CTREncryptionLayer::UpdateIV(std::size_t offset) const { offset >>= 4; - for (size_t i = 0; i < 8; ++i) { + for (std::size_t i = 0; i < 8; ++i) { iv[16 - i - 1] = offset & 0xFF; offset >>= 8; } diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h index 11b8683c7..a7bf810f4 100644 --- a/src/core/crypto/ctr_encryption_layer.h +++ b/src/core/crypto/ctr_encryption_layer.h @@ -14,20 +14,20 @@ namespace Core::Crypto { // Sits on top of a VirtualFile and provides CTR-mode AES decription. class CTREncryptionLayer : public EncryptionLayer { public: - CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset); + CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset); - size_t Read(u8* data, size_t length, size_t offset) const override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; void SetIV(const std::vector<u8>& iv); private: - size_t base_offset; + std::size_t base_offset; // Must be mutable as operations modify cipher contexts. mutable AESCipher<Key128> cipher; mutable std::vector<u8> iv; - void UpdateIV(size_t offset) const; + void UpdateIV(std::size_t offset) const; }; } // namespace Core::Crypto diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp index 4204527e3..4c377d7d4 100644 --- a/src/core/crypto/encryption_layer.cpp +++ b/src/core/crypto/encryption_layer.cpp @@ -12,11 +12,11 @@ std::string EncryptionLayer::GetName() const { return base->GetName(); } -size_t EncryptionLayer::GetSize() const { +std::size_t EncryptionLayer::GetSize() const { return base->GetSize(); } -bool EncryptionLayer::Resize(size_t new_size) { +bool EncryptionLayer::Resize(std::size_t new_size) { return false; } @@ -32,7 +32,7 @@ bool EncryptionLayer::IsReadable() const { return true; } -size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) { +std::size_t EncryptionLayer::Write(const u8* data, std::size_t length, std::size_t offset) { return 0; } diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h index 7f05af9b4..53619cb38 100644 --- a/src/core/crypto/encryption_layer.h +++ b/src/core/crypto/encryption_layer.h @@ -15,15 +15,15 @@ class EncryptionLayer : public FileSys::VfsFile { public: explicit EncryptionLayer(FileSys::VirtualFile base); - size_t Read(u8* data, size_t length, size_t offset) const override = 0; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override = 0; std::string GetName() const override; - size_t GetSize() const override; - bool Resize(size_t new_size) override; + std::size_t GetSize() const override; + bool Resize(std::size_t new_size) override; std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override; bool IsWritable() const override; bool IsReadable() const override; - size_t Write(const u8* data, size_t length, size_t offset) override; + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; bool Rename(std::string_view name) override; protected: diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 0b6c07de8..bf3a70944 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -8,12 +8,15 @@ #include <locale> #include <sstream> #include <string_view> +#include <tuple> +#include <vector> #include "common/common_paths.h" #include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "core/crypto/aes_util.h" #include "core/crypto/key_manager.h" +#include "core/loader/loader.h" #include "core/settings.h" namespace Core::Crypto { @@ -51,7 +54,7 @@ boost::optional<Key128> DeriveSDSeed() { return boost::none; std::array<u8, 0x10> buffer{}; - size_t offset = 0; + std::size_t offset = 0; for (; offset + 0x10 < save_43.GetSize(); ++offset) { save_43.Seek(offset, SEEK_SET); save_43.ReadBytes(buffer.data(), buffer.size()); @@ -102,7 +105,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManag // Combine sources and seed for (auto& source : sd_key_sources) { - for (size_t i = 0; i < source.size(); ++i) + for (std::size_t i = 0; i < source.size(); ++i) source[i] ^= sd_seed[i & 0xF]; } @@ -204,7 +207,7 @@ Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const { return s256_keys.at({id, field1, field2}); } -template <size_t Size> +template <std::size_t Size> void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key) { const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); @@ -228,18 +231,28 @@ void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, } void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { - const auto iter = std::find_if( + if (s128_keys.find({id, field1, field2}) != s128_keys.end()) + return; + if (id == S128KeyType::Titlekey) { + Key128 rights_id; + std::memcpy(rights_id.data(), &field2, sizeof(u64)); + std::memcpy(rights_id.data() + sizeof(u64), &field1, sizeof(u64)); + WriteKeyToFile(true, Common::HexArrayToString(rights_id), key); + } + const auto iter2 = std::find_if( s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) { return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == std::tie(id, field1, field2); }); - if (iter != s128_file_id.end()) - WriteKeyToFile(id == S128KeyType::Titlekey, iter->first, key); + if (iter2 != s128_file_id.end()) + WriteKeyToFile(false, iter2->first, key); s128_keys[{id, field1, field2}] = key; } void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { + if (s256_keys.find({id, field1, field2}) != s256_keys.end()) + return; const auto iter = std::find_if( s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) { diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 7ca3e6cbc..978eec8dc 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -6,16 +6,19 @@ #include <array> #include <string> -#include <string_view> -#include <type_traits> -#include <vector> #include <boost/container/flat_map.hpp> +#include <boost/optional.hpp> #include <fmt/format.h> #include "common/common_types.h" -#include "core/loader/loader.h" + +namespace Loader { +enum class ResultStatus : u16; +} namespace Core::Crypto { +constexpr u64 TICKET_FILE_TITLEKEY_OFFSET = 0x180; + using Key128 = std::array<u8, 0x10>; using Key256 = std::array<u8, 0x20>; using SHA256Hash = std::array<u8, 0x20>; @@ -105,7 +108,7 @@ private: void LoadFromFile(const std::string& filename, bool is_title_keys); void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, const std::string& filename, bool title); - template <size_t Size> + template <std::size_t Size> void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key); static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; diff --git a/src/core/crypto/xts_encryption_layer.cpp b/src/core/crypto/xts_encryption_layer.cpp index c10832cfe..8f0ba4ee7 100644 --- a/src/core/crypto/xts_encryption_layer.cpp +++ b/src/core/crypto/xts_encryption_layer.cpp @@ -14,7 +14,7 @@ constexpr u64 XTS_SECTOR_SIZE = 0x4000; XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_) : EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {} -size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { +std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { if (length == 0) return 0; @@ -46,7 +46,7 @@ size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { block.resize(XTS_SECTOR_SIZE); cipher.XTSTranscode(block.data(), block.size(), block.data(), (offset - sector_offset) / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt); - const size_t read = XTS_SECTOR_SIZE - sector_offset; + const std::size_t read = XTS_SECTOR_SIZE - sector_offset; if (length + sector_offset < XTS_SECTOR_SIZE) { std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); diff --git a/src/core/crypto/xts_encryption_layer.h b/src/core/crypto/xts_encryption_layer.h index 7a1f1dc64..5f8f00fe7 100644 --- a/src/core/crypto/xts_encryption_layer.h +++ b/src/core/crypto/xts_encryption_layer.h @@ -15,7 +15,7 @@ class XTSEncryptionLayer : public EncryptionLayer { public: XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key); - size_t Read(u8* data, size_t length, size_t offset) const override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; private: // Must be mutable as operations modify cipher contexts. diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 08a7cea5a..205492897 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/file_sys/bis_factory.h" +#include "core/file_sys/registered_cache.h" namespace FileSys { @@ -13,6 +14,8 @@ BISFactory::BISFactory(VirtualDir nand_root_) usrnand_cache(std::make_shared<RegisteredCache>( GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {} +BISFactory::~BISFactory() = default; + std::shared_ptr<RegisteredCache> BISFactory::GetSystemNANDContents() const { return sysnand_cache; } diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index a970a5e2e..9523dd864 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h @@ -5,17 +5,20 @@ #pragma once #include <memory> -#include "core/loader/loader.h" -#include "registered_cache.h" + +#include "core/file_sys/vfs.h" namespace FileSys { +class RegisteredCache; + /// File system interface to the Built-In Storage /// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND /// registered caches. class BISFactory { public: explicit BISFactory(VirtualDir nand_root); + ~BISFactory(); std::shared_ptr<RegisteredCache> GetSystemNANDContents() const; std::shared_ptr<RegisteredCache> GetUserNANDContents() const; diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index d61a2ebe1..edfc1bbd4 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -9,7 +9,10 @@ #include "common/logging/log.h" #include "core/file_sys/card_image.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_metadata.h" #include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/submission_package.h" #include "core/file_sys/vfs_offset.h" #include "core/loader/loader.h" @@ -38,20 +41,25 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) { for (XCIPartition partition : {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { - auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]); + auto raw = main_hfs.GetFile(partition_names[static_cast<std::size_t>(partition)]); if (raw != nullptr) - partitions[static_cast<size_t>(partition)] = std::make_shared<PartitionFilesystem>(raw); + partitions[static_cast<std::size_t>(partition)] = + std::make_shared<PartitionFilesystem>(raw); } - program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; + secure_partition = std::make_shared<NSP>( + main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)])); - auto result = AddNCAFromPartition(XCIPartition::Secure); - if (result != Loader::ResultStatus::Success) { - status = result; - return; - } + const auto secure_ncas = secure_partition->GetNCAsCollapsed(); + std::copy(secure_ncas.begin(), secure_ncas.end(), std::back_inserter(ncas)); - result = AddNCAFromPartition(XCIPartition::Update); + program = + secure_partition->GetNCA(secure_partition->GetProgramTitleID(), ContentRecordType::Program); + program_nca_status = secure_partition->GetProgramStatus(secure_partition->GetProgramTitleID()); + if (program_nca_status == Loader::ResultStatus::ErrorNSPMissingProgramNCA) + program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; + + auto result = AddNCAFromPartition(XCIPartition::Update); if (result != Loader::ResultStatus::Success) { status = result; return; @@ -74,6 +82,8 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) { status = Loader::ResultStatus::Success; } +XCI::~XCI() = default; + Loader::ResultStatus XCI::GetStatus() const { return status; } @@ -83,7 +93,11 @@ Loader::ResultStatus XCI::GetProgramNCAStatus() const { } VirtualDir XCI::GetPartition(XCIPartition partition) const { - return partitions[static_cast<size_t>(partition)]; + return partitions[static_cast<std::size_t>(partition)]; +} + +std::shared_ptr<NSP> XCI::GetSecurePartitionNSP() const { + return secure_partition; } VirtualDir XCI::GetSecurePartition() const { @@ -102,6 +116,20 @@ VirtualDir XCI::GetLogoPartition() const { return GetPartition(XCIPartition::Logo); } +u64 XCI::GetProgramTitleID() const { + return secure_partition->GetProgramTitleID(); +} + +std::shared_ptr<NCA> XCI::GetProgramNCA() const { + return program; +} + +VirtualFile XCI::GetProgramNCAFile() const { + if (GetProgramNCA() == nullptr) + return nullptr; + return GetProgramNCA()->GetBaseFile(); +} + const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const { return ncas; } @@ -141,11 +169,11 @@ bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { } Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { - if (partitions[static_cast<size_t>(part)] == nullptr) { + if (partitions[static_cast<std::size_t>(part)] == nullptr) { return Loader::ResultStatus::ErrorXCIMissingPartition; } - for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) { + for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) { if (file->GetExtension() != "nca") continue; auto nca = std::make_shared<NCA>(file); @@ -160,7 +188,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { } else { const u16 error_id = static_cast<u16>(nca->GetStatus()); LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})", - partition_names[static_cast<size_t>(part)], nca->GetName(), error_id, + partition_names[static_cast<std::size_t>(part)], nca->GetName(), error_id, nca->GetStatus()); } } diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 54ab828d1..ce514dfa0 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -5,15 +5,22 @@ #pragma once #include <array> +#include <memory> #include <vector> #include "common/common_types.h" #include "common/swap.h" -#include "core/file_sys/content_archive.h" #include "core/file_sys/vfs.h" -#include "core/loader/loader.h" + +namespace Loader { +enum class ResultStatus : u16; +} namespace FileSys { +class NCA; +enum class NCAContentType : u8; +class NSP; + enum class GamecardSize : u8 { S_1GB = 0xFA, S_2GB = 0xF8, @@ -57,6 +64,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo }; class XCI : public ReadOnlyVfsDirectory { public: explicit XCI(VirtualFile file); + ~XCI() override; Loader::ResultStatus GetStatus() const; Loader::ResultStatus GetProgramNCAStatus() const; @@ -64,11 +72,16 @@ public: u8 GetFormatVersion() const; VirtualDir GetPartition(XCIPartition partition) const; + std::shared_ptr<NSP> GetSecurePartitionNSP() const; VirtualDir GetSecurePartition() const; VirtualDir GetNormalPartition() const; VirtualDir GetUpdatePartition() const; VirtualDir GetLogoPartition() const; + u64 GetProgramTitleID() const; + + std::shared_ptr<NCA> GetProgramNCA() const; + VirtualFile GetProgramNCAFile() const; const std::vector<std::shared_ptr<NCA>>& GetNCAs() const; std::shared_ptr<NCA> GetNCAByType(NCAContentType type) const; VirtualFile GetNCAFileByType(NCAContentType type) const; @@ -94,6 +107,8 @@ private: Loader::ResultStatus program_nca_status; std::vector<VirtualDir> partitions; + std::shared_ptr<NSP> secure_partition; + std::shared_ptr<NCA> program; std::vector<std::shared_ptr<NCA>> ncas; }; } // namespace FileSys diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index e8b5d6ece..aa1b3c17d 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -3,12 +3,17 @@ // Refer to the license.txt file included. #include <algorithm> +#include <cstring> #include <utility> + #include <boost/optional.hpp> + #include "common/logging/log.h" #include "core/crypto/aes_util.h" #include "core/crypto/ctr_encryption_layer.h" #include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_patch.h" +#include "core/file_sys/partition_filesystem.h" #include "core/file_sys/romfs.h" #include "core/file_sys/vfs_offset.h" #include "core/loader/loader.h" @@ -64,10 +69,31 @@ struct RomFSSuperblock { }; static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size."); +struct BKTRHeader { + u64_le offset; + u64_le size; + u32_le magic; + INSERT_PADDING_BYTES(0x4); + u32_le number_entries; + INSERT_PADDING_BYTES(0x4); +}; +static_assert(sizeof(BKTRHeader) == 0x20, "BKTRHeader has incorrect size."); + +struct BKTRSuperblock { + NCASectionHeaderBlock header_block; + IVFCHeader ivfc; + INSERT_PADDING_BYTES(0x18); + BKTRHeader relocation; + BKTRHeader subsection; + INSERT_PADDING_BYTES(0xC0); +}; +static_assert(sizeof(BKTRSuperblock) == 0x200, "BKTRSuperblock has incorrect size."); + union NCASectionHeader { NCASectionRaw raw; PFS0Superblock pfs0; RomFSSuperblock romfs; + BKTRSuperblock bktr; }; static_assert(sizeof(NCASectionHeader) == 0x200, "NCASectionHeader has incorrect size."); @@ -100,7 +126,7 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty Core::Crypto::Key128 out; if (type == NCASectionCryptoType::XTS) std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); - else if (type == NCASectionCryptoType::CTR) + else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin()); else LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}", @@ -150,6 +176,9 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting LOG_DEBUG(Crypto, "called with mode=NONE"); return in; case NCASectionCryptoType::CTR: + // During normal BKTR decryption, this entire function is skipped. This is for the metadata, + // which uses the same CTR as usual. + case NCASectionCryptoType::BKTR: LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); { boost::optional<Core::Crypto::Key128> key = boost::none; @@ -186,7 +215,9 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting } } -NCA::NCA(VirtualFile file_) : file(std::move(file_)) { +NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) + : file(std::move(file_)), + bktr_base_romfs(bktr_base_romfs_ ? std::move(bktr_base_romfs_) : nullptr) { status = Loader::ResultStatus::Success; if (file == nullptr) { @@ -261,22 +292,21 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { is_update = std::find_if(sections.begin(), sections.end(), [](const NCASectionHeader& header) { return header.raw.header.crypto_type == NCASectionCryptoType::BKTR; }) != sections.end(); + ivfc_offset = 0; for (std::ptrdiff_t i = 0; i < number_sections; ++i) { auto section = sections[i]; if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) { - const size_t romfs_offset = - header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER + - section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; - const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size; - auto dec = - Decrypt(section, std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset), - romfs_offset); - if (dec != nullptr) { - files.push_back(std::move(dec)); - romfs = files.back(); - } else { + const std::size_t base_offset = + header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER; + ivfc_offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; + const std::size_t romfs_offset = base_offset + ivfc_offset; + const std::size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size; + auto raw = std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset); + auto dec = Decrypt(section, raw, romfs_offset); + + if (dec == nullptr) { if (status != Loader::ResultStatus::Success) return; if (has_rights_id) @@ -285,6 +315,117 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey; return; } + + if (section.raw.header.crypto_type == NCASectionCryptoType::BKTR) { + if (section.bktr.relocation.magic != Common::MakeMagic('B', 'K', 'T', 'R') || + section.bktr.subsection.magic != Common::MakeMagic('B', 'K', 'T', 'R')) { + status = Loader::ResultStatus::ErrorBadBKTRHeader; + return; + } + + if (section.bktr.relocation.offset + section.bktr.relocation.size != + section.bktr.subsection.offset) { + status = Loader::ResultStatus::ErrorBKTRSubsectionNotAfterRelocation; + return; + } + + const u64 size = + MEDIA_OFFSET_MULTIPLIER * (header.section_tables[i].media_end_offset - + header.section_tables[i].media_offset); + if (section.bktr.subsection.offset + section.bktr.subsection.size != size) { + status = Loader::ResultStatus::ErrorBKTRSubsectionNotAtEnd; + return; + } + + const u64 offset = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; + RelocationBlock relocation_block{}; + if (dec->ReadObject(&relocation_block, section.bktr.relocation.offset - offset) != + sizeof(RelocationBlock)) { + status = Loader::ResultStatus::ErrorBadRelocationBlock; + return; + } + SubsectionBlock subsection_block{}; + if (dec->ReadObject(&subsection_block, section.bktr.subsection.offset - offset) != + sizeof(RelocationBlock)) { + status = Loader::ResultStatus::ErrorBadSubsectionBlock; + return; + } + + std::vector<RelocationBucketRaw> relocation_buckets_raw( + (section.bktr.relocation.size - sizeof(RelocationBlock)) / + sizeof(RelocationBucketRaw)); + if (dec->ReadBytes(relocation_buckets_raw.data(), + section.bktr.relocation.size - sizeof(RelocationBlock), + section.bktr.relocation.offset + sizeof(RelocationBlock) - + offset) != + section.bktr.relocation.size - sizeof(RelocationBlock)) { + status = Loader::ResultStatus::ErrorBadRelocationBuckets; + return; + } + + std::vector<SubsectionBucketRaw> subsection_buckets_raw( + (section.bktr.subsection.size - sizeof(SubsectionBlock)) / + sizeof(SubsectionBucketRaw)); + if (dec->ReadBytes(subsection_buckets_raw.data(), + section.bktr.subsection.size - sizeof(SubsectionBlock), + section.bktr.subsection.offset + sizeof(SubsectionBlock) - + offset) != + section.bktr.subsection.size - sizeof(SubsectionBlock)) { + status = Loader::ResultStatus::ErrorBadSubsectionBuckets; + return; + } + + std::vector<RelocationBucket> relocation_buckets(relocation_buckets_raw.size()); + std::transform(relocation_buckets_raw.begin(), relocation_buckets_raw.end(), + relocation_buckets.begin(), &ConvertRelocationBucketRaw); + std::vector<SubsectionBucket> subsection_buckets(subsection_buckets_raw.size()); + std::transform(subsection_buckets_raw.begin(), subsection_buckets_raw.end(), + subsection_buckets.begin(), &ConvertSubsectionBucketRaw); + + u32 ctr_low; + std::memcpy(&ctr_low, section.raw.section_ctr.data(), sizeof(ctr_low)); + subsection_buckets.back().entries.push_back( + {section.bktr.relocation.offset, {0}, ctr_low}); + subsection_buckets.back().entries.push_back({size, {0}, 0}); + + boost::optional<Core::Crypto::Key128> key = boost::none; + if (encrypted) { + if (has_rights_id) { + status = Loader::ResultStatus::Success; + key = GetTitlekey(); + if (key == boost::none) { + status = Loader::ResultStatus::ErrorMissingTitlekey; + return; + } + } else { + key = GetKeyAreaKey(NCASectionCryptoType::BKTR); + if (key == boost::none) { + status = Loader::ResultStatus::ErrorMissingKeyAreaKey; + return; + } + } + } + + if (bktr_base_romfs == nullptr) { + status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS; + return; + } + + auto bktr = std::make_shared<BKTR>( + bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset), + relocation_block, relocation_buckets, subsection_block, subsection_buckets, + encrypted, encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, + bktr_base_ivfc_offset, section.raw.section_ctr); + + // BKTR applies to entire IVFC, so make an offset version to level 6 + + files.push_back(std::make_shared<OffsetVfsFile>( + bktr, romfs_size, section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset)); + romfs = files.back(); + } else { + files.push_back(std::move(dec)); + romfs = files.back(); + } } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) { u64 offset = (static_cast<u64>(header.section_tables[i].media_offset) * MEDIA_OFFSET_MULTIPLIER) + @@ -300,6 +441,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { dirs.push_back(std::move(npfs)); if (IsDirectoryExeFS(dirs.back())) exefs = dirs.back(); + } else { + if (has_rights_id) + status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek; + else + status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey; + return; } } else { if (status != Loader::ResultStatus::Success) @@ -316,6 +463,8 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { status = Loader::ResultStatus::Success; } +NCA::~NCA() = default; + Loader::ResultStatus NCA::GetStatus() const { return status; } @@ -345,11 +494,15 @@ NCAContentType NCA::GetType() const { } u64 NCA::GetTitleId() const { - if (status != Loader::ResultStatus::Success) - return {}; + if (is_update || status == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) + return header.title_id | 0x800; return header.title_id; } +bool NCA::IsUpdate() const { + return is_update; +} + VirtualFile NCA::GetRomFS() const { return romfs; } @@ -362,8 +515,8 @@ VirtualFile NCA::GetBaseFile() const { return file; } -bool NCA::IsUpdate() const { - return is_update; +u64 NCA::GetBaseIVFCOffset() const { + return ivfc_offset; } bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index b961cfde7..f9f66cae9 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -12,10 +12,12 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "control_metadata.h" #include "core/crypto/key_manager.h" -#include "core/file_sys/partition_filesystem.h" -#include "core/loader/loader.h" +#include "core/file_sys/vfs.h" + +namespace Loader { +enum class ResultStatus : u16; +} namespace FileSys { @@ -77,7 +79,10 @@ bool IsValidNCA(const NCAHeader& header); // After construction, use GetStatus to determine if the file is valid and ready to be used. class NCA : public ReadOnlyVfsDirectory { public: - explicit NCA(VirtualFile file); + explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, + u64 bktr_base_ivfc_offset = 0); + ~NCA() override; + Loader::ResultStatus GetStatus() const; std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; @@ -87,13 +92,15 @@ public: NCAContentType GetType() const; u64 GetTitleId() const; + bool IsUpdate() const; VirtualFile GetRomFS() const; VirtualDir GetExeFS() const; VirtualFile GetBaseFile() const; - bool IsUpdate() const; + // Returns the base ivfc offset used in BKTR patching. + u64 GetBaseIVFCOffset() const; protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; @@ -110,14 +117,16 @@ private: VirtualFile romfs = nullptr; VirtualDir exefs = nullptr; VirtualFile file; + VirtualFile bktr_base_romfs; + u64 ivfc_offset; NCAHeader header{}; bool has_rights_id{}; - bool is_update{}; Loader::ResultStatus status{}; bool encrypted; + bool is_update; Core::Crypto::KeyManager keys; }; diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index ae21ad5b9..5b1177a03 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -8,6 +8,14 @@ namespace FileSys { +const std::array<const char*, 15> LANGUAGE_NAMES = { + "AmericanEnglish", "BritishEnglish", "Japanese", + "French", "German", "LatinAmericanSpanish", + "Spanish", "Italian", "Dutch", + "CanadianFrench", "Portugese", "Russian", + "Korean", "Taiwanese", "Chinese", +}; + std::string LanguageEntry::GetApplicationName() const { return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200); } @@ -20,8 +28,20 @@ NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) { file->ReadObject(raw.get()); } +NACP::~NACP() = default; + const LanguageEntry& NACP::GetLanguageEntry(Language language) const { - return raw->language_entries.at(static_cast<u8>(language)); + if (language != Language::Default) { + return raw->language_entries.at(static_cast<u8>(language)); + } + + for (const auto& language_entry : raw->language_entries) { + if (!language_entry.GetApplicationName().empty()) + return language_entry; + } + + // Fallback to English + return GetLanguageEntry(Language::AmericanEnglish); } std::string NACP::GetApplicationName(Language language) const { diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 8c2cc1a2a..43d6f0719 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -8,6 +8,8 @@ #include <memory> #include <string> #include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" #include "core/file_sys/vfs.h" namespace FileSys { @@ -60,23 +62,22 @@ enum class Language : u8 { Korean = 12, Taiwanese = 13, Chinese = 14, + + Default = 255, }; -static constexpr std::array<const char*, 15> LANGUAGE_NAMES = { - "AmericanEnglish", "BritishEnglish", "Japanese", - "French", "German", "LatinAmericanSpanish", - "Spanish", "Italian", "Dutch", - "CanadianFrench", "Portugese", "Russian", - "Korean", "Taiwanese", "Chinese"}; +extern const std::array<const char*, 15> LANGUAGE_NAMES; // A class representing the format used by NX metadata files, typically named Control.nacp. // These store application name, dev name, title id, and other miscellaneous data. class NACP { public: explicit NACP(VirtualFile file); - const LanguageEntry& GetLanguageEntry(Language language = Language::AmericanEnglish) const; - std::string GetApplicationName(Language language = Language::AmericanEnglish) const; - std::string GetDeveloperName(Language language = Language::AmericanEnglish) const; + ~NACP(); + + const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const; + std::string GetApplicationName(Language language = Language::Default) const; + std::string GetDeveloperName(Language language = Language::Default) const; u64 GetTitleId() const; std::string GetVersionString() const; diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 3759e743a..12bb90ec8 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h @@ -25,7 +25,7 @@ enum EntryType : u8 { struct Entry { Entry(std::string_view view, EntryType entry_type, u64 entry_size) : type{entry_type}, file_size{entry_size} { - const size_t copy_size = view.copy(filename, std::size(filename) - 1); + const std::size_t copy_size = view.copy(filename, std::size(filename) - 1); filename[copy_size] = '\0'; } diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp index 449244444..6f34b7836 100644 --- a/src/core/file_sys/nca_metadata.cpp +++ b/src/core/file_sys/nca_metadata.cpp @@ -3,20 +3,19 @@ // Refer to the license.txt file included. #include <cstring> -#include "common/common_funcs.h" +#include "common/common_types.h" #include "common/logging/log.h" #include "common/swap.h" -#include "content_archive.h" #include "core/file_sys/nca_metadata.h" namespace FileSys { bool operator>=(TitleType lhs, TitleType rhs) { - return static_cast<size_t>(lhs) >= static_cast<size_t>(rhs); + return static_cast<std::size_t>(lhs) >= static_cast<std::size_t>(rhs); } bool operator<=(TitleType lhs, TitleType rhs) { - return static_cast<size_t>(lhs) <= static_cast<size_t>(rhs); + return static_cast<std::size_t>(lhs) <= static_cast<std::size_t>(rhs); } CNMT::CNMT(VirtualFile file) { @@ -52,6 +51,8 @@ CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentReco : header(std::move(header)), opt_header(std::move(opt_header)), content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} +CNMT::~CNMT() = default; + u64 CNMT::GetTitleID() const { return header.title_id; } diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h index ce05b4c1d..a05d155f4 100644 --- a/src/core/file_sys/nca_metadata.h +++ b/src/core/file_sys/nca_metadata.h @@ -4,7 +4,6 @@ #pragma once -#include <cstring> #include <memory> #include <vector> #include "common/common_funcs.h" @@ -88,6 +87,7 @@ public: explicit CNMT(VirtualFile file); CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, std::vector<MetaRecord> meta_records); + ~CNMT(); u64 GetTitleID() const; u32 GetTitleVersion() const; diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp new file mode 100644 index 000000000..0090cc6c4 --- /dev/null +++ b/src/core/file_sys/nca_patch.cpp @@ -0,0 +1,210 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstddef> +#include <cstring> + +#include "common/assert.h" +#include "core/crypto/aes_util.h" +#include "core/file_sys/nca_patch.h" + +namespace FileSys { + +BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock relocation_, + std::vector<RelocationBucket> relocation_buckets_, SubsectionBlock subsection_, + std::vector<SubsectionBucket> subsection_buckets_, bool is_encrypted_, + Core::Crypto::Key128 key_, u64 base_offset_, u64 ivfc_offset_, + std::array<u8, 8> section_ctr_) + : relocation(relocation_), relocation_buckets(std::move(relocation_buckets_)), + subsection(subsection_), subsection_buckets(std::move(subsection_buckets_)), + base_romfs(std::move(base_romfs_)), bktr_romfs(std::move(bktr_romfs_)), + encrypted(is_encrypted_), key(key_), base_offset(base_offset_), ivfc_offset(ivfc_offset_), + section_ctr(section_ctr_) { + for (std::size_t i = 0; i < relocation.number_buckets - 1; ++i) { + relocation_buckets[i].entries.push_back({relocation.base_offsets[i + 1], 0, 0}); + } + + for (std::size_t i = 0; i < subsection.number_buckets - 1; ++i) { + subsection_buckets[i].entries.push_back({subsection_buckets[i + 1].entries[0].address_patch, + {0}, + subsection_buckets[i + 1].entries[0].ctr}); + } + + relocation_buckets.back().entries.push_back({relocation.size, 0, 0}); +} + +BKTR::~BKTR() = default; + +std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const { + // Read out of bounds. + if (offset >= relocation.size) + return 0; + const auto relocation = GetRelocationEntry(offset); + const auto section_offset = offset - relocation.address_patch + relocation.address_source; + const auto bktr_read = relocation.from_patch; + + const auto next_relocation = GetNextRelocationEntry(offset); + + if (offset + length > next_relocation.address_patch) { + const u64 partition = next_relocation.address_patch - offset; + return Read(data, partition, offset) + + Read(data + partition, length - partition, offset + partition); + } + + if (!bktr_read) { + ASSERT_MSG(section_offset >= ivfc_offset, "Offset calculation negative."); + return base_romfs->Read(data, length, section_offset - ivfc_offset); + } + + if (!encrypted) { + return bktr_romfs->Read(data, length, section_offset); + } + + const auto subsection = GetSubsectionEntry(section_offset); + Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR); + + // Calculate AES IV + std::vector<u8> iv(16); + auto subsection_ctr = subsection.ctr; + auto offset_iv = section_offset + base_offset; + for (std::size_t i = 0; i < section_ctr.size(); ++i) + iv[i] = section_ctr[0x8 - i - 1]; + offset_iv >>= 4; + for (std::size_t i = 0; i < sizeof(u64); ++i) { + iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF); + offset_iv >>= 8; + } + for (std::size_t i = 0; i < sizeof(u32); ++i) { + iv[0x7 - i] = static_cast<u8>(subsection_ctr & 0xFF); + subsection_ctr >>= 8; + } + cipher.SetIV(iv); + + const auto next_subsection = GetNextSubsectionEntry(section_offset); + + if (section_offset + length > next_subsection.address_patch) { + const u64 partition = next_subsection.address_patch - section_offset; + return Read(data, partition, offset) + + Read(data + partition, length - partition, offset + partition); + } + + const auto block_offset = section_offset & 0xF; + if (block_offset != 0) { + auto block = bktr_romfs->ReadBytes(0x10, section_offset & ~0xF); + cipher.Transcode(block.data(), block.size(), block.data(), Core::Crypto::Op::Decrypt); + if (length + block_offset < 0x10) { + std::memcpy(data, block.data() + block_offset, std::min(length, block.size())); + return std::min(length, block.size()); + } + + const auto read = 0x10 - block_offset; + std::memcpy(data, block.data() + block_offset, read); + return read + Read(data + read, length - read, offset + read); + } + + const auto raw_read = bktr_romfs->Read(data, length, section_offset); + cipher.Transcode(data, raw_read, data, Core::Crypto::Op::Decrypt); + return raw_read; +} + +template <bool Subsection, typename BlockType, typename BucketType> +std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block, + BucketType buckets) const { + if constexpr (Subsection) { + const auto last_bucket = buckets[block.number_buckets - 1]; + if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch) + return {block.number_buckets - 1, last_bucket.number_entries}; + } else { + ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block."); + } + + std::size_t bucket_id = std::count_if( + block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets, + [&offset](u64 base_offset) { return base_offset <= offset; }); + + const auto bucket = buckets[bucket_id]; + + if (bucket.number_entries == 1) + return {bucket_id, 0}; + + std::size_t low = 0; + std::size_t mid = 0; + std::size_t high = bucket.number_entries - 1; + while (low <= high) { + mid = (low + high) / 2; + if (bucket.entries[mid].address_patch > offset) { + high = mid - 1; + } else { + if (mid == bucket.number_entries - 1 || + bucket.entries[mid + 1].address_patch > offset) { + return {bucket_id, mid}; + } + + low = mid + 1; + } + } + + UNREACHABLE_MSG("Offset could not be found in BKTR block."); +} + +RelocationEntry BKTR::GetRelocationEntry(u64 offset) const { + const auto res = SearchBucketEntry<false>(offset, relocation, relocation_buckets); + return relocation_buckets[res.first].entries[res.second]; +} + +RelocationEntry BKTR::GetNextRelocationEntry(u64 offset) const { + const auto res = SearchBucketEntry<false>(offset, relocation, relocation_buckets); + const auto bucket = relocation_buckets[res.first]; + if (res.second + 1 < bucket.entries.size()) + return bucket.entries[res.second + 1]; + return relocation_buckets[res.first + 1].entries[0]; +} + +SubsectionEntry BKTR::GetSubsectionEntry(u64 offset) const { + const auto res = SearchBucketEntry<true>(offset, subsection, subsection_buckets); + return subsection_buckets[res.first].entries[res.second]; +} + +SubsectionEntry BKTR::GetNextSubsectionEntry(u64 offset) const { + const auto res = SearchBucketEntry<true>(offset, subsection, subsection_buckets); + const auto bucket = subsection_buckets[res.first]; + if (res.second + 1 < bucket.entries.size()) + return bucket.entries[res.second + 1]; + return subsection_buckets[res.first + 1].entries[0]; +} + +std::string BKTR::GetName() const { + return base_romfs->GetName(); +} + +std::size_t BKTR::GetSize() const { + return relocation.size; +} + +bool BKTR::Resize(std::size_t new_size) { + return false; +} + +std::shared_ptr<VfsDirectory> BKTR::GetContainingDirectory() const { + return base_romfs->GetContainingDirectory(); +} + +bool BKTR::IsWritable() const { + return false; +} + +bool BKTR::IsReadable() const { + return true; +} + +std::size_t BKTR::Write(const u8* data, std::size_t length, std::size_t offset) { + return 0; +} + +bool BKTR::Rename(std::string_view name) { + return base_romfs->Rename(name); +} + +} // namespace FileSys diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h new file mode 100644 index 000000000..8e64e8378 --- /dev/null +++ b/src/core/file_sys/nca_patch.h @@ -0,0 +1,150 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <memory> +#include <vector> + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/crypto/key_manager.h" + +namespace FileSys { + +#pragma pack(push, 1) +struct RelocationEntry { + u64_le address_patch; + u64_le address_source; + u32 from_patch; +}; +#pragma pack(pop) +static_assert(sizeof(RelocationEntry) == 0x14, "RelocationEntry has incorrect size."); + +struct RelocationBucketRaw { + INSERT_PADDING_BYTES(4); + u32_le number_entries; + u64_le end_offset; + std::array<RelocationEntry, 0x332> relocation_entries; + INSERT_PADDING_BYTES(8); +}; +static_assert(sizeof(RelocationBucketRaw) == 0x4000, "RelocationBucketRaw has incorrect size."); + +// Vector version of RelocationBucketRaw +struct RelocationBucket { + u32 number_entries; + u64 end_offset; + std::vector<RelocationEntry> entries; +}; + +struct RelocationBlock { + INSERT_PADDING_BYTES(4); + u32_le number_buckets; + u64_le size; + std::array<u64, 0x7FE> base_offsets; +}; +static_assert(sizeof(RelocationBlock) == 0x4000, "RelocationBlock has incorrect size."); + +struct SubsectionEntry { + u64_le address_patch; + INSERT_PADDING_BYTES(0x4); + u32_le ctr; +}; +static_assert(sizeof(SubsectionEntry) == 0x10, "SubsectionEntry has incorrect size."); + +struct SubsectionBucketRaw { + INSERT_PADDING_BYTES(4); + u32_le number_entries; + u64_le end_offset; + std::array<SubsectionEntry, 0x3FF> subsection_entries; +}; +static_assert(sizeof(SubsectionBucketRaw) == 0x4000, "SubsectionBucketRaw has incorrect size."); + +// Vector version of SubsectionBucketRaw +struct SubsectionBucket { + u32 number_entries; + u64 end_offset; + std::vector<SubsectionEntry> entries; +}; + +struct SubsectionBlock { + INSERT_PADDING_BYTES(4); + u32_le number_buckets; + u64_le size; + std::array<u64, 0x7FE> base_offsets; +}; +static_assert(sizeof(SubsectionBlock) == 0x4000, "SubsectionBlock has incorrect size."); + +inline RelocationBucket ConvertRelocationBucketRaw(RelocationBucketRaw raw) { + return {raw.number_entries, + raw.end_offset, + {raw.relocation_entries.begin(), raw.relocation_entries.begin() + raw.number_entries}}; +} + +inline SubsectionBucket ConvertSubsectionBucketRaw(SubsectionBucketRaw raw) { + return {raw.number_entries, + raw.end_offset, + {raw.subsection_entries.begin(), raw.subsection_entries.begin() + raw.number_entries}}; +} + +class BKTR : public VfsFile { +public: + BKTR(VirtualFile base_romfs, VirtualFile bktr_romfs, RelocationBlock relocation, + std::vector<RelocationBucket> relocation_buckets, SubsectionBlock subsection, + std::vector<SubsectionBucket> subsection_buckets, bool is_encrypted, + Core::Crypto::Key128 key, u64 base_offset, u64 ivfc_offset, std::array<u8, 8> section_ctr); + ~BKTR() override; + + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; + + std::string GetName() const override; + + std::size_t GetSize() const override; + + bool Resize(std::size_t new_size) override; + + std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; + + bool IsWritable() const override; + + bool IsReadable() const override; + + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; + + bool Rename(std::string_view name) override; + +private: + template <bool Subsection, typename BlockType, typename BucketType> + std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, BlockType block, + BucketType buckets) const; + + RelocationEntry GetRelocationEntry(u64 offset) const; + RelocationEntry GetNextRelocationEntry(u64 offset) const; + + SubsectionEntry GetSubsectionEntry(u64 offset) const; + SubsectionEntry GetNextSubsectionEntry(u64 offset) const; + + RelocationBlock relocation; + std::vector<RelocationBucket> relocation_buckets; + SubsectionBlock subsection; + std::vector<SubsectionBucket> subsection_buckets; + + // Should be the raw base romfs, decrypted. + VirtualFile base_romfs; + // Should be the raw BKTR romfs, (located at media_offset with size media_size). + VirtualFile bktr_romfs; + + bool encrypted; + Core::Crypto::Key128 key; + + // Base offset into NCA, used for IV calculation. + u64 base_offset; + // Distance between IVFC start and RomFS start, used for base reads + u64 ivfc_offset; + std::array<u8, 8> section_ctr; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index c377edc9c..5791c76ff 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -42,21 +42,21 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0'); - size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); - size_t metadata_size = + std::size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); + std::size_t metadata_size = sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; // Actually read in now... std::vector<u8> file_data = file->ReadBytes(metadata_size); - const size_t total_size = file_data.size(); + const std::size_t total_size = file_data.size(); if (total_size != metadata_size) { status = Loader::ResultStatus::ErrorIncorrectPFSFileSize; return; } - size_t entries_offset = sizeof(Header); - size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size); + std::size_t entries_offset = sizeof(Header); + std::size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size); content_offset = strtab_offset + pfs_header.strtab_size; for (u16 i = 0; i < pfs_header.num_entries; i++) { FSEntry entry; @@ -72,6 +72,8 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { status = Loader::ResultStatus::Success; } +PartitionFilesystem::~PartitionFilesystem() = default; + Loader::ResultStatus PartitionFilesystem::GetStatus() const { return status; } diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h index be7bc32a8..739c63a7f 100644 --- a/src/core/file_sys/partition_filesystem.h +++ b/src/core/file_sys/partition_filesystem.h @@ -25,6 +25,8 @@ namespace FileSys { class PartitionFilesystem : public ReadOnlyVfsDirectory { public: explicit PartitionFilesystem(std::shared_ptr<VfsFile> file); + ~PartitionFilesystem() override; + Loader::ResultStatus GetStatus() const; std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; @@ -79,7 +81,7 @@ private: Header pfs_header{}; bool is_hfs = false; - size_t content_offset = 0; + std::size_t content_offset = 0; std::vector<VirtualFile> pfs_files; std::vector<VirtualDir> pfs_dirs; diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp new file mode 100644 index 000000000..aebc69d52 --- /dev/null +++ b/src/core/file_sys/patch_manager.cpp @@ -0,0 +1,159 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> +#include <cstddef> + +#include "common/logging/log.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" + +namespace FileSys { + +constexpr u64 SINGLE_BYTE_MODULUS = 0x100; + +std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { + std::array<u8, sizeof(u32)> bytes{}; + bytes[0] = version % SINGLE_BYTE_MODULUS; + for (std::size_t i = 1; i < bytes.size(); ++i) { + version /= SINGLE_BYTE_MODULUS; + bytes[i] = version % SINGLE_BYTE_MODULUS; + } + + if (format == TitleVersionFormat::FourElements) + return fmt::format("v{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); + return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]); +} + +constexpr std::array<const char*, 1> PATCH_TYPE_NAMES{ + "Update", +}; + +std::string FormatPatchTypeName(PatchType type) { + return PATCH_TYPE_NAMES.at(static_cast<std::size_t>(type)); +} + +PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} + +PatchManager::~PatchManager() = default; + +VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { + LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id); + + if (exefs == nullptr) + return exefs; + + const auto installed = Service::FileSystem::GetUnionContents(); + + // Game Updates + const auto update_tid = GetUpdateTitleID(title_id); + const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); + if (update != nullptr) { + if (update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && + update->GetExeFS() != nullptr) { + LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", + FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); + exefs = update->GetExeFS(); + } + } + + return exefs; +} + +VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, + ContentRecordType type) const { + LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id, + static_cast<u8>(type)); + + if (romfs == nullptr) + return romfs; + + const auto installed = Service::FileSystem::GetUnionContents(); + + // Game Updates + const auto update_tid = GetUpdateTitleID(title_id); + const auto update = installed->GetEntryRaw(update_tid, type); + if (update != nullptr) { + const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); + if (new_nca->GetStatus() == Loader::ResultStatus::Success && + new_nca->GetRomFS() != nullptr) { + LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", + FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); + romfs = new_nca->GetRomFS(); + } + } + + return romfs; +} + +std::map<PatchType, std::string> PatchManager::GetPatchVersionNames() const { + std::map<PatchType, std::string> out; + const auto installed = Service::FileSystem::GetUnionContents(); + + const auto update_tid = GetUpdateTitleID(title_id); + PatchManager update{update_tid}; + auto [nacp, discard_icon_file] = update.GetControlMetadata(); + + if (nacp != nullptr) { + out[PatchType::Update] = nacp->GetVersionString(); + } else { + if (installed->HasEntry(update_tid, ContentRecordType::Program)) { + const auto meta_ver = installed->GetEntryVersion(update_tid); + if (meta_ver == boost::none || meta_ver.get() == 0) { + out[PatchType::Update] = ""; + } else { + out[PatchType::Update] = + FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements); + } + } + } + + return out; +} + +std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { + const auto& installed{Service::FileSystem::GetUnionContents()}; + + const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); + if (base_control_nca == nullptr) + return {}; + + return ParseControlNCA(base_control_nca); +} + +std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA( + const std::shared_ptr<NCA>& nca) const { + const auto base_romfs = nca->GetRomFS(); + if (base_romfs == nullptr) + return {}; + + const auto romfs = PatchRomFS(base_romfs, nca->GetBaseIVFCOffset(), ContentRecordType::Control); + if (romfs == nullptr) + return {}; + + const auto extracted = ExtractRomFS(romfs); + if (extracted == nullptr) + return {}; + + auto nacp_file = extracted->GetFile("control.nacp"); + if (nacp_file == nullptr) + nacp_file = extracted->GetFile("Control.nacp"); + + const auto nacp = nacp_file == nullptr ? nullptr : std::make_shared<NACP>(nacp_file); + + VirtualFile icon_file; + for (const auto& language : FileSys::LANGUAGE_NAMES) { + icon_file = extracted->GetFile("icon_" + std::string(language) + ".dat"); + if (icon_file != nullptr) + break; + } + + return {nacp, icon_file}; +} +} // namespace FileSys diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h new file mode 100644 index 000000000..209cab1dc --- /dev/null +++ b/src/core/file_sys/patch_manager.h @@ -0,0 +1,64 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include <memory> +#include <string> +#include "common/common_types.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/vfs.h" + +namespace FileSys { + +class NCA; +class NACP; + +enum class TitleVersionFormat : u8 { + ThreeElements, ///< vX.Y.Z + FourElements, ///< vX.Y.Z.W +}; + +std::string FormatTitleVersion(u32 version, + TitleVersionFormat format = TitleVersionFormat::ThreeElements); + +enum class PatchType { + Update, +}; + +std::string FormatPatchTypeName(PatchType type); + +// A centralized class to manage patches to games. +class PatchManager { +public: + explicit PatchManager(u64 title_id); + ~PatchManager(); + + // Currently tracked ExeFS patches: + // - Game Updates + VirtualDir PatchExeFS(VirtualDir exefs) const; + + // Currently tracked RomFS patches: + // - Game Updates + VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset, + ContentRecordType type = ContentRecordType::Program) const; + + // Returns a vector of pairs between patch names and patch versions. + // i.e. Update v80 will return {Update, 80} + std::map<PatchType, std::string> GetPatchVersionNames() const; + + // Given title_id of the program, attempts to get the control data of the update and parse it, + // falling back to the base control data. + std::pair<std::shared_ptr<NACP>, VirtualFile> GetControlMetadata() const; + + // Version of GetControlMetadata that takes an arbitrary NCA + std::pair<std::shared_ptr<NACP>, VirtualFile> ParseControlNCA( + const std::shared_ptr<NCA>& nca) const; + +private: + u64 title_id; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 279f987d4..02319ce0f 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -2,15 +2,22 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/file_util.h" +#include <cstddef> +#include <cstring> +#include <vector> + #include "common/logging/log.h" #include "core/file_sys/program_metadata.h" #include "core/loader/loader.h" namespace FileSys { +ProgramMetadata::ProgramMetadata() = default; + +ProgramMetadata::~ProgramMetadata() = default; + Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { - size_t total_size = static_cast<size_t>(file->GetSize()); + std::size_t total_size = static_cast<std::size_t>(file->GetSize()); if (total_size < sizeof(Header)) return Loader::ResultStatus::ErrorBadNPDMHeader; diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 74a91052b..1143e36c4 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h @@ -5,12 +5,10 @@ #pragma once #include <array> -#include <string> -#include <vector> #include "common/bit_field.h" #include "common/common_types.h" #include "common/swap.h" -#include "partition_filesystem.h" +#include "core/file_sys/vfs.h" namespace Loader { enum class ResultStatus : u16; @@ -38,6 +36,9 @@ enum class ProgramFilePermission : u64 { */ class ProgramMetadata { public: + ProgramMetadata(); + ~ProgramMetadata(); + Loader::ResultStatus Load(VirtualFile file); bool Is64BitProgram() const; diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index dacf8568b..dad7ae10b 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -5,13 +5,17 @@ #include <regex> #include <mbedtls/sha256.h> #include "common/assert.h" +#include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" -#include "core/crypto/encryption_layer.h" +#include "core/crypto/key_manager.h" #include "core/file_sys/card_image.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" +#include "core/file_sys/submission_package.h" #include "core/file_sys/vfs_concat.h" +#include "core/loader/loader.h" namespace FileSys { std::string RegisteredCacheEntry::DebugInfo() const { @@ -58,11 +62,11 @@ static std::string GetCNMTName(TitleType type, u64 title_id) { "" ///< Currently unknown 'DeltaTitle' }; - auto index = static_cast<size_t>(type); + auto index = static_cast<std::size_t>(type); // If the index is after the jump in TitleType, subtract it out. - if (index >= static_cast<size_t>(TitleType::Application)) { - index -= static_cast<size_t>(TitleType::Application) - - static_cast<size_t>(TitleType::FirmwarePackageB); + if (index >= static_cast<std::size_t>(TitleType::Application)) { + index -= static_cast<std::size_t>(TitleType::Application) - + static_cast<std::size_t>(TitleType::FirmwarePackageB); } return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); } @@ -101,7 +105,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, } else { std::vector<VirtualFile> concat; // Since the files are a two-digit hex number, max is FF. - for (size_t i = 0; i < 0x100; ++i) { + for (std::size_t i = 0; i < 0x100; ++i) { auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); if (next != nullptr) { concat.push_back(std::move(next)); @@ -276,6 +280,18 @@ VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const return GetEntryUnparsed(entry.title_id, entry.type); } +boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { + const auto meta_iter = meta.find(title_id); + if (meta_iter != meta.end()) + return meta_iter->second.GetTitleVersion(); + + const auto yuzu_meta_iter = yuzu_meta.find(title_id); + if (yuzu_meta_iter != yuzu_meta.end()) + return yuzu_meta_iter->second.GetTitleVersion(); + + return boost::none; +} + VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const { const auto id = GetNcaIDFromMetadata(title_id, type); if (id == boost::none) @@ -355,17 +371,21 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( return out; } -static std::shared_ptr<NCA> GetNCAFromXCIForID(std::shared_ptr<XCI> xci, const NcaID& id) { - const auto filename = fmt::format("{}.nca", Common::HexArrayToString(id, false)); - const auto iter = - std::find_if(xci->GetNCAs().begin(), xci->GetNCAs().end(), - [&filename](std::shared_ptr<NCA> nca) { return nca->GetName() == filename; }); - return iter == xci->GetNCAs().end() ? nullptr : *iter; +static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { + const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); + if (file == nullptr) + return nullptr; + return std::make_shared<NCA>(file); } InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, const VfsCopyFunction& copy) { - const auto& ncas = xci->GetNCAs(); + return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy); +} + +InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, + const VfsCopyFunction& copy) { + const auto& ncas = nsp->GetNCAsCollapsed(); const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { return nca->GetType() == NCAContentType::Meta; }); @@ -389,7 +409,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overw const auto cnmt_file = section0->GetFiles()[0]; const CNMT cnmt(cnmt_file); for (const auto& record : cnmt.GetContentRecords()) { - const auto nca = GetNCAFromXCIForID(xci, record.nca_id); + const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); if (nca == nullptr) return InstallResult::ErrorCopyFailed; const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); @@ -490,4 +510,107 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { kv.second.GetTitleID() == cnmt.GetTitleID(); }) != yuzu_meta.end(); } + +RegisteredCacheUnion::RegisteredCacheUnion(std::vector<std::shared_ptr<RegisteredCache>> caches) + : caches(std::move(caches)) {} + +void RegisteredCacheUnion::Refresh() { + for (const auto& c : caches) + c->Refresh(); +} + +bool RegisteredCacheUnion::HasEntry(u64 title_id, ContentRecordType type) const { + return std::any_of(caches.begin(), caches.end(), [title_id, type](const auto& cache) { + return cache->HasEntry(title_id, type); + }); +} + +bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const { + return HasEntry(entry.title_id, entry.type); +} + +boost::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const { + for (const auto& c : caches) { + const auto res = c->GetEntryVersion(title_id); + if (res != boost::none) + return res; + } + + return boost::none; +} + +VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const { + for (const auto& c : caches) { + const auto res = c->GetEntryUnparsed(title_id, type); + if (res != nullptr) + return res; + } + + return nullptr; +} + +VirtualFile RegisteredCacheUnion::GetEntryUnparsed(RegisteredCacheEntry entry) const { + return GetEntryUnparsed(entry.title_id, entry.type); +} + +VirtualFile RegisteredCacheUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const { + for (const auto& c : caches) { + const auto res = c->GetEntryRaw(title_id, type); + if (res != nullptr) + return res; + } + + return nullptr; +} + +VirtualFile RegisteredCacheUnion::GetEntryRaw(RegisteredCacheEntry entry) const { + return GetEntryRaw(entry.title_id, entry.type); +} + +std::shared_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const { + const auto raw = GetEntryRaw(title_id, type); + if (raw == nullptr) + return nullptr; + return std::make_shared<NCA>(raw); +} + +std::shared_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const { + return GetEntry(entry.title_id, entry.type); +} + +std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const { + std::vector<RegisteredCacheEntry> out; + for (const auto& c : caches) { + c->IterateAllMetadata<RegisteredCacheEntry>( + out, + [](const CNMT& c, const ContentRecord& r) { + return RegisteredCacheEntry{c.GetTitleID(), r.type}; + }, + [](const CNMT& c, const ContentRecord& r) { return true; }); + } + return out; +} + +std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter( + boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type, + boost::optional<u64> title_id) const { + std::vector<RegisteredCacheEntry> out; + for (const auto& c : caches) { + c->IterateAllMetadata<RegisteredCacheEntry>( + out, + [](const CNMT& c, const ContentRecord& r) { + return RegisteredCacheEntry{c.GetTitleID(), r.type}; + }, + [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) { + if (title_type != boost::none && title_type.get() != c.GetType()) + return false; + if (record_type != boost::none && record_type.get() != r.type) + return false; + if (title_id != boost::none && title_id.get() != c.GetTitleID()) + return false; + return true; + }); + } + return out; +} } // namespace FileSys diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 7b8955dfa..f487b0cf0 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -11,15 +11,19 @@ #include <string> #include <vector> #include <boost/container/flat_map.hpp> -#include "common/common_funcs.h" #include "common/common_types.h" -#include "content_archive.h" -#include "core/file_sys/nca_metadata.h" #include "core/file_sys/vfs.h" namespace FileSys { -class XCI; class CNMT; +class NCA; +class NSP; +class XCI; + +enum class ContentRecordType : u8; +enum class TitleType : u8; + +struct ContentRecord; using NcaID = std::array<u8, 0x10>; using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; @@ -39,6 +43,10 @@ struct RegisteredCacheEntry { std::string DebugInfo() const; }; +constexpr u64 GetUpdateTitleID(u64 base_title_id) { + return base_title_id | 0x800; +} + // boost flat_map requires operator< for O(log(n)) lookups. bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs); @@ -56,6 +64,8 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) * 4GB splitting can be ignored.) */ class RegisteredCache { + friend class RegisteredCacheUnion; + public: // Parsing function defines the conversion from raw file to NCA. If there are other steps // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom @@ -70,6 +80,8 @@ public: bool HasEntry(u64 title_id, ContentRecordType type) const; bool HasEntry(RegisteredCacheEntry entry) const; + boost::optional<u32> GetEntryVersion(u64 title_id) const; + VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const; VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const; @@ -86,10 +98,12 @@ public: boost::optional<ContentRecordType> record_type = boost::none, boost::optional<u64> title_id = boost::none) const; - // Raw copies all the ncas from the xci to the csache. Does some quick checks to make sure there - // is a meta NCA and all of them are accessible. + // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure + // there is a meta NCA and all of them are accessible. InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, const VfsCopyFunction& copy = &VfsRawCopy); + InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false, + const VfsCopyFunction& copy = &VfsRawCopy); // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a @@ -125,4 +139,36 @@ private: boost::container::flat_map<u64, CNMT> yuzu_meta; }; +// Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface. +class RegisteredCacheUnion { +public: + explicit RegisteredCacheUnion(std::vector<std::shared_ptr<RegisteredCache>> caches); + + void Refresh(); + + bool HasEntry(u64 title_id, ContentRecordType type) const; + bool HasEntry(RegisteredCacheEntry entry) const; + + boost::optional<u32> GetEntryVersion(u64 title_id) const; + + VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const; + VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const; + + VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const; + VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const; + + std::shared_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const; + std::shared_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; + + std::vector<RegisteredCacheEntry> ListEntries() const; + // If a parameter is not boost::none, it will be filtered for from all entries. + std::vector<RegisteredCacheEntry> ListEntriesFilter( + boost::optional<TitleType> title_type = boost::none, + boost::optional<ContentRecordType> record_type = boost::none, + boost::optional<u64> title_id = boost::none) const; + +private: + std::vector<std::shared_ptr<RegisteredCache>> caches; +}; + } // namespace FileSys diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index e490c8ace..9f6e41cdf 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp @@ -49,7 +49,7 @@ struct FileEntry { static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); template <typename Entry> -static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) { +static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { Entry entry{}; if (file->ReadObject(&entry, offset) != sizeof(Entry)) return {}; @@ -59,8 +59,8 @@ static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t of return {entry, string}; } -void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset, - std::shared_ptr<VectorVfsDirectory> parent) { +void ProcessFile(VirtualFile file, std::size_t file_offset, std::size_t data_offset, + u32 this_file_offset, std::shared_ptr<VectorVfsDirectory> parent) { while (true) { auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); @@ -74,8 +74,9 @@ void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 t } } -void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset, - u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) { +void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file_offset, + std::size_t data_offset, u32 this_dir_offset, + std::shared_ptr<VectorVfsDirectory> parent) { while (true) { auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); auto current = std::make_shared<VectorVfsDirectory>( diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 03a876d22..e54a7d7a9 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h @@ -6,6 +6,7 @@ #include <array> #include "common/common_funcs.h" +#include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/vfs.h" diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index eb4e6c865..3d1a3685e 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -2,11 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <algorithm> #include <memory> +#include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "core/core.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/nca_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/hle/kernel/process.h" @@ -20,10 +23,19 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) { if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) { LOG_ERROR(Service_FS, "Unable to read RomFS!"); } + + updatable = app_loader.IsRomFSUpdatable(); + ivfc_offset = app_loader.ReadRomFSIVFCOffset(); } +RomFSFactory::~RomFSFactory() = default; + ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { - return MakeResult<VirtualFile>(file); + if (!updatable) + return MakeResult<VirtualFile>(file); + + const PatchManager patch_manager(Core::CurrentProcess()->program_id); + return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); } ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h index f38ddc4f7..2cace8180 100644 --- a/src/core/file_sys/romfs_factory.h +++ b/src/core/file_sys/romfs_factory.h @@ -30,12 +30,15 @@ enum class StorageId : u8 { class RomFSFactory { public: explicit RomFSFactory(Loader::AppLoader& app_loader); + ~RomFSFactory(); ResultVal<VirtualFile> OpenCurrentProcess(); ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type); private: VirtualFile file; + bool updatable; + u64 ivfc_offset; }; } // namespace FileSys diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 952bd74b3..9b2c51bbd 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <memory> +#include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" @@ -19,6 +20,8 @@ std::string SaveDataDescriptor::DebugInfo() const { SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {} +SaveDataFactory::~SaveDataFactory() = default; + ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) { if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { if (meta.zero_1 != 0) { @@ -84,10 +87,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ switch (space) { case SaveDataSpaceId::NandSystem: - out = "/system/save/"; + out = "/system/"; break; case SaveDataSpaceId::NandUser: - out = "/user/save/"; + out = "/user/"; break; default: ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); @@ -95,9 +98,12 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ switch (type) { case SaveDataType::SystemSaveData: - return fmt::format("{}{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); + return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); case SaveDataType::SaveData: - return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], + return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], + title_id); + case SaveDataType::TemporaryStorage: + return fmt::format("{}temp/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], title_id); default: ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index c6f9549f0..d69ef6741 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -6,6 +6,7 @@ #include <memory> #include <string> +#include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/vfs.h" @@ -47,6 +48,7 @@ static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorr class SaveDataFactory { public: explicit SaveDataFactory(VirtualDir dir); + ~SaveDataFactory(); ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp new file mode 100644 index 000000000..11264878d --- /dev/null +++ b/src/core/file_sys/submission_package.cpp @@ -0,0 +1,245 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstring> +#include <string_view> + +#include <fmt/ostream.h> + +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "core/crypto/key_manager.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/submission_package.h" +#include "core/loader/loader.h" + +namespace FileSys { +NSP::NSP(VirtualFile file_) + : file(std::move(file_)), status{Loader::ResultStatus::Success}, + pfs(std::make_shared<PartitionFilesystem>(file)) { + if (pfs->GetStatus() != Loader::ResultStatus::Success) { + status = pfs->GetStatus(); + return; + } + + if (IsDirectoryExeFS(pfs)) { + extracted = true; + exefs = pfs; + + const auto& files = pfs->GetFiles(); + const auto romfs_iter = + std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { + return file->GetName().find(".romfs") != std::string::npos; + }); + if (romfs_iter != files.end()) + romfs = *romfs_iter; + return; + } + + extracted = false; + const auto files = pfs->GetFiles(); + + Core::Crypto::KeyManager keys; + for (const auto& ticket_file : files) { + if (ticket_file->GetExtension() == "tik") { + if (ticket_file == nullptr || + ticket_file->GetSize() < + Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) { + continue; + } + + Core::Crypto::Key128 key{}; + ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET); + std::string_view name_only(ticket_file->GetName()); + name_only.remove_suffix(4); + const auto rights_id_raw = Common::HexStringToArray<16>(name_only); + u128 rights_id; + std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128)); + keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); + } + } + + for (const auto& outer_file : files) { + if (outer_file->GetName().substr(outer_file->GetName().size() - 9) == ".cnmt.nca") { + const auto nca = std::make_shared<NCA>(outer_file); + if (nca->GetStatus() != Loader::ResultStatus::Success) { + program_status[nca->GetTitleId()] = nca->GetStatus(); + continue; + } + + const auto section0 = nca->GetSubdirectories()[0]; + + for (const auto& inner_file : section0->GetFiles()) { + if (inner_file->GetExtension() != "cnmt") + continue; + + const CNMT cnmt(inner_file); + auto& ncas_title = ncas[cnmt.GetTitleID()]; + + ncas_title[ContentRecordType::Meta] = nca; + for (const auto& rec : cnmt.GetContentRecords()) { + const auto id_string = Common::HexArrayToString(rec.nca_id, false); + const auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string)); + if (next_file == nullptr) { + LOG_WARNING(Service_FS, + "NCA with ID {}.nca is listed in content metadata, but cannot " + "be found in PFS. NSP appears to be corrupted.", + id_string); + continue; + } + + auto next_nca = std::make_shared<NCA>(next_file); + if (next_nca->GetType() == NCAContentType::Program) + program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); + if (next_nca->GetStatus() == Loader::ResultStatus::Success) + ncas_title[rec.type] = std::move(next_nca); + } + + break; + } + } + } +} + +NSP::~NSP() = default; + +Loader::ResultStatus NSP::GetStatus() const { + return status; +} + +Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const { + const auto iter = program_status.find(title_id); + if (iter == program_status.end()) + return Loader::ResultStatus::ErrorNSPMissingProgramNCA; + return iter->second; +} + +u64 NSP::GetFirstTitleID() const { + if (program_status.empty()) + return 0; + return program_status.begin()->first; +} + +u64 NSP::GetProgramTitleID() const { + const auto out = GetFirstTitleID(); + if ((out & 0x800) == 0) + return out; + + const auto ids = GetTitleIDs(); + const auto iter = + std::find_if(ids.begin(), ids.end(), [](u64 tid) { return (tid & 0x800) == 0; }); + return iter == ids.end() ? out : *iter; +} + +std::vector<u64> NSP::GetTitleIDs() const { + std::vector<u64> out; + out.reserve(ncas.size()); + for (const auto& kv : ncas) + out.push_back(kv.first); + return out; +} + +bool NSP::IsExtractedType() const { + return extracted; +} + +VirtualFile NSP::GetRomFS() const { + return romfs; +} + +VirtualDir NSP::GetExeFS() const { + return exefs; +} + +std::vector<std::shared_ptr<NCA>> NSP::GetNCAsCollapsed() const { + if (extracted) + LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); + std::vector<std::shared_ptr<NCA>> out; + for (const auto& map : ncas) { + for (const auto& inner_map : map.second) + out.push_back(inner_map.second); + } + return out; +} + +std::multimap<u64, std::shared_ptr<NCA>> NSP::GetNCAsByTitleID() const { + if (extracted) + LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); + std::multimap<u64, std::shared_ptr<NCA>> out; + for (const auto& map : ncas) { + for (const auto& inner_map : map.second) + out.emplace(map.first, inner_map.second); + } + return out; +} + +std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> NSP::GetNCAs() const { + return ncas; +} + +std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type) const { + if (extracted) + LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); + + const auto title_id_iter = ncas.find(title_id); + if (title_id_iter == ncas.end()) + return nullptr; + + const auto type_iter = title_id_iter->second.find(type); + if (type_iter == title_id_iter->second.end()) + return nullptr; + + return type_iter->second; +} + +VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type) const { + if (extracted) + LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); + const auto nca = GetNCA(title_id, type); + if (nca != nullptr) + return nca->GetBaseFile(); + return nullptr; +} + +std::vector<Core::Crypto::Key128> NSP::GetTitlekey() const { + if (extracted) + LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); + std::vector<Core::Crypto::Key128> out; + for (const auto& ticket_file : ticket_files) { + if (ticket_file == nullptr || + ticket_file->GetSize() < + Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) { + continue; + } + + out.emplace_back(); + ticket_file->Read(out.back().data(), out.back().size(), + Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET); + } + return out; +} + +std::vector<VirtualFile> NSP::GetFiles() const { + return pfs->GetFiles(); +} + +std::vector<VirtualDir> NSP::GetSubdirectories() const { + return pfs->GetSubdirectories(); +} + +std::string NSP::GetName() const { + return file->GetName(); +} + +VirtualDir NSP::GetParentDirectory() const { + return file->GetContainingDirectory(); +} + +bool NSP::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { + return false; +} +} // namespace FileSys diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h new file mode 100644 index 000000000..e85a2b76e --- /dev/null +++ b/src/core/file_sys/submission_package.h @@ -0,0 +1,76 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include <memory> +#include <vector> +#include "common/common_types.h" +#include "core/file_sys/vfs.h" + +namespace Loader { +enum class ResultStatus : u16; +} + +namespace FileSys { + +class NCA; +class PartitionFilesystem; + +enum class ContentRecordType : u8; + +class NSP : public ReadOnlyVfsDirectory { +public: + explicit NSP(VirtualFile file); + ~NSP() override; + + Loader::ResultStatus GetStatus() const; + Loader::ResultStatus GetProgramStatus(u64 title_id) const; + // Should only be used when one title id can be assured. + u64 GetFirstTitleID() const; + u64 GetProgramTitleID() const; + std::vector<u64> GetTitleIDs() const; + + bool IsExtractedType() const; + + // Common (Can be safely called on both types) + VirtualFile GetRomFS() const; + VirtualDir GetExeFS() const; + + // Type 0 Only (Collection of NCAs + Certificate + Ticket + Meta XML) + std::vector<std::shared_ptr<NCA>> GetNCAsCollapsed() const; + std::multimap<u64, std::shared_ptr<NCA>> GetNCAsByTitleID() const; + std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> GetNCAs() const; + std::shared_ptr<NCA> GetNCA(u64 title_id, ContentRecordType type) const; + VirtualFile GetNCAFile(u64 title_id, ContentRecordType type) const; + std::vector<Core::Crypto::Key128> GetTitlekey() const; + + std::vector<VirtualFile> GetFiles() const override; + + std::vector<VirtualDir> GetSubdirectories() const override; + + std::string GetName() const override; + + VirtualDir GetParentDirectory() const override; + +protected: + bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; + +private: + VirtualFile file; + + bool extracted; + Loader::ResultStatus status; + std::map<u64, Loader::ResultStatus> program_status; + + std::shared_ptr<PartitionFilesystem> pfs; + // Map title id -> {map type -> NCA} + std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas; + std::vector<VirtualFile> ticket_files; + + VirtualFile romfs; + VirtualDir exefs; +}; +} // namespace FileSys diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 146c839f4..d7b52abfd 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -167,18 +167,18 @@ std::string VfsFile::GetExtension() const { VfsDirectory::~VfsDirectory() = default; -boost::optional<u8> VfsFile::ReadByte(size_t offset) const { +boost::optional<u8> VfsFile::ReadByte(std::size_t offset) const { u8 out{}; - size_t size = Read(&out, 1, offset); + std::size_t size = Read(&out, 1, offset); if (size == 1) return out; return boost::none; } -std::vector<u8> VfsFile::ReadBytes(size_t size, size_t offset) const { +std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const { std::vector<u8> out(size); - size_t read_size = Read(out.data(), size, offset); + std::size_t read_size = Read(out.data(), size, offset); out.resize(read_size); return out; } @@ -187,11 +187,11 @@ std::vector<u8> VfsFile::ReadAllBytes() const { return ReadBytes(GetSize()); } -bool VfsFile::WriteByte(u8 data, size_t offset) { +bool VfsFile::WriteByte(u8 data, std::size_t offset) { return Write(&data, 1, offset) == 1; } -size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) { +std::size_t VfsFile::WriteBytes(const std::vector<u8>& data, std::size_t offset) { return Write(data.data(), data.size(), offset); } @@ -215,7 +215,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) co } auto dir = GetSubdirectory(vec[0]); - for (size_t component = 1; component < vec.size() - 1; ++component) { + for (std::size_t component = 1; component < vec.size() - 1; ++component) { if (dir == nullptr) { return nullptr; } @@ -249,7 +249,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_vie } auto dir = GetSubdirectory(vec[0]); - for (size_t component = 1; component < vec.size(); ++component) { + for (std::size_t component = 1; component < vec.size(); ++component) { if (dir == nullptr) { return nullptr; } @@ -286,7 +286,7 @@ bool VfsDirectory::IsRoot() const { return GetParentDirectory() == nullptr; } -size_t VfsDirectory::GetSize() const { +std::size_t VfsDirectory::GetSize() const { const auto& files = GetFiles(); const auto sum_sizes = [](const auto& range) { return std::accumulate(range.begin(), range.end(), 0ULL, @@ -434,13 +434,13 @@ bool ReadOnlyVfsDirectory::Rename(std::string_view name) { return false; } -bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size) { +bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t block_size) { if (file1->GetSize() != file2->GetSize()) return false; std::vector<u8> f1_v(block_size); std::vector<u8> f2_v(block_size); - for (size_t i = 0; i < file1->GetSize(); i += block_size) { + for (std::size_t i = 0; i < file1->GetSize(); i += block_size) { auto f1_vs = file1->Read(f1_v.data(), block_size, i); auto f2_vs = file2->Read(f2_v.data(), block_size, i); diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 5142a3e86..74489b452 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -92,9 +92,9 @@ public: // Retrieves the extension of the file name. virtual std::string GetExtension() const; // Retrieves the size of the file. - virtual size_t GetSize() const = 0; + virtual std::size_t GetSize() const = 0; // Resizes the file to new_size. Returns whether or not the operation was successful. - virtual bool Resize(size_t new_size) = 0; + virtual bool Resize(std::size_t new_size) = 0; // Gets a pointer to the directory containing this file, returning nullptr if there is none. virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0; @@ -105,15 +105,15 @@ public: // The primary method of reading from the file. Reads length bytes into data starting at offset // into file. Returns number of bytes successfully read. - virtual size_t Read(u8* data, size_t length, size_t offset = 0) const = 0; + virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0; // The primary method of writing to the file. Writes length bytes from data starting at offset // into file. Returns number of bytes successfully written. - virtual size_t Write(const u8* data, size_t length, size_t offset = 0) = 0; + virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0; // Reads exactly one byte at the offset provided, returning boost::none on error. - virtual boost::optional<u8> ReadByte(size_t offset = 0) const; + virtual boost::optional<u8> ReadByte(std::size_t offset = 0) const; // Reads size bytes starting at offset in file into a vector. - virtual std::vector<u8> ReadBytes(size_t size, size_t offset = 0) const; + virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const; // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(), // 0)' virtual std::vector<u8> ReadAllBytes() const; @@ -121,7 +121,7 @@ public: // Reads an array of type T, size number_elements starting at offset. // Returns the number of bytes (sizeof(T)*number_elements) read successfully. template <typename T> - size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const { + std::size_t ReadArray(T* data, std::size_t number_elements, std::size_t offset = 0) const { static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset); @@ -130,7 +130,7 @@ public: // Reads size bytes into the memory starting at data starting at offset into the file. // Returns the number of bytes read successfully. template <typename T> - size_t ReadBytes(T* data, size_t size, size_t offset = 0) const { + std::size_t ReadBytes(T* data, std::size_t size, std::size_t offset = 0) const { static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); return Read(reinterpret_cast<u8*>(data), size, offset); } @@ -138,22 +138,22 @@ public: // Reads one object of type T starting at offset in file. // Returns the number of bytes read successfully (sizeof(T)). template <typename T> - size_t ReadObject(T* data, size_t offset = 0) const { + std::size_t ReadObject(T* data, std::size_t offset = 0) const { static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); return Read(reinterpret_cast<u8*>(data), sizeof(T), offset); } // Writes exactly one byte to offset in file and retuns whether or not the byte was written // successfully. - virtual bool WriteByte(u8 data, size_t offset = 0); + virtual bool WriteByte(u8 data, std::size_t offset = 0); // Writes a vector of bytes to offset in file and returns the number of bytes successfully // written. - virtual size_t WriteBytes(const std::vector<u8>& data, size_t offset = 0); + virtual std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset = 0); // Writes an array of type T, size number_elements to offset in file. // Returns the number of bytes (sizeof(T)*number_elements) written successfully. template <typename T> - size_t WriteArray(const T* data, size_t number_elements, size_t offset = 0) { + std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) { static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); return Write(data, number_elements * sizeof(T), offset); } @@ -161,7 +161,7 @@ public: // Writes size bytes starting at memory location data to offset in file. // Returns the number of bytes written successfully. template <typename T> - size_t WriteBytes(const T* data, size_t size, size_t offset = 0) { + std::size_t WriteBytes(const T* data, std::size_t size, std::size_t offset = 0) { static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); return Write(reinterpret_cast<const u8*>(data), size, offset); } @@ -169,7 +169,7 @@ public: // Writes one object of type T to offset in file. // Returns the number of bytes written successfully (sizeof(T)). template <typename T> - size_t WriteObject(const T& data, size_t offset = 0) { + std::size_t WriteObject(const T& data, std::size_t offset = 0) { static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); return Write(&data, sizeof(T), offset); } @@ -221,7 +221,7 @@ public: // Returns the name of the directory. virtual std::string GetName() const = 0; // Returns the total size of all files and subdirectories in this directory. - virtual size_t GetSize() const; + virtual std::size_t GetSize() const; // Returns the parent directory of this directory. Returns nullptr if this directory is root or // has no parent. virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0; @@ -311,7 +311,7 @@ public: }; // Compare the two files, byte-for-byte, in increments specificed by block_size -bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x200); +bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t block_size = 0x200); // A method that copies the raw data between two different implementations of VirtualFile. If you // are using the same implementation, it is probably better to use the Copy method in the parent diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index e6bf586a3..dc7a279a9 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp @@ -20,13 +20,15 @@ VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) : name(std::move(name)) { - size_t next_offset = 0; + std::size_t next_offset = 0; for (const auto& file : files_) { files[next_offset] = file; next_offset += file->GetSize(); } } +ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; + std::string ConcatenatedVfsFile::GetName() const { if (files.empty()) return ""; @@ -35,13 +37,13 @@ std::string ConcatenatedVfsFile::GetName() const { return files.begin()->second->GetName(); } -size_t ConcatenatedVfsFile::GetSize() const { +std::size_t ConcatenatedVfsFile::GetSize() const { if (files.empty()) return 0; return files.rbegin()->first + files.rbegin()->second->GetSize(); } -bool ConcatenatedVfsFile::Resize(size_t new_size) { +bool ConcatenatedVfsFile::Resize(std::size_t new_size) { return false; } @@ -59,7 +61,7 @@ bool ConcatenatedVfsFile::IsReadable() const { return true; } -size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const { +std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { auto entry = files.end(); for (auto iter = files.begin(); iter != files.end(); ++iter) { if (iter->first > offset) { @@ -84,7 +86,7 @@ size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const { return entry->second->Read(data, length, offset - entry->first); } -size_t ConcatenatedVfsFile::Write(const u8* data, size_t length, size_t offset) { +std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { return 0; } diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index 686d32515..717d04bdc 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h @@ -22,14 +22,16 @@ class ConcatenatedVfsFile : public VfsFile { ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); public: + ~ConcatenatedVfsFile() override; + std::string GetName() const override; - size_t GetSize() const override; - bool Resize(size_t new_size) override; + std::size_t GetSize() const override; + bool Resize(std::size_t new_size) override; std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; bool IsWritable() const override; bool IsReadable() const override; - size_t Read(u8* data, size_t length, size_t offset) const override; - size_t Write(const u8* data, size_t length, size_t offset) override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; bool Rename(std::string_view name) override; private: diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index 847cde2f5..a4c6719a0 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp @@ -9,20 +9,22 @@ namespace FileSys { -OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_, +OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_, std::size_t offset_, std::string name_, VirtualDir parent_) : file(file_), offset(offset_), size(size_), name(std::move(name_)), parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {} +OffsetVfsFile::~OffsetVfsFile() = default; + std::string OffsetVfsFile::GetName() const { return name.empty() ? file->GetName() : name; } -size_t OffsetVfsFile::GetSize() const { +std::size_t OffsetVfsFile::GetSize() const { return size; } -bool OffsetVfsFile::Resize(size_t new_size) { +bool OffsetVfsFile::Resize(std::size_t new_size) { if (offset + new_size < file->GetSize()) { size = new_size; } else { @@ -47,22 +49,22 @@ bool OffsetVfsFile::IsReadable() const { return file->IsReadable(); } -size_t OffsetVfsFile::Read(u8* data, size_t length, size_t r_offset) const { +std::size_t OffsetVfsFile::Read(u8* data, std::size_t length, std::size_t r_offset) const { return file->Read(data, TrimToFit(length, r_offset), offset + r_offset); } -size_t OffsetVfsFile::Write(const u8* data, size_t length, size_t r_offset) { +std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t r_offset) { return file->Write(data, TrimToFit(length, r_offset), offset + r_offset); } -boost::optional<u8> OffsetVfsFile::ReadByte(size_t r_offset) const { +boost::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const { if (r_offset < size) return file->ReadByte(offset + r_offset); return boost::none; } -std::vector<u8> OffsetVfsFile::ReadBytes(size_t r_size, size_t r_offset) const { +std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const { return file->ReadBytes(TrimToFit(r_size, r_offset), offset + r_offset); } @@ -70,14 +72,14 @@ std::vector<u8> OffsetVfsFile::ReadAllBytes() const { return file->ReadBytes(size, offset); } -bool OffsetVfsFile::WriteByte(u8 data, size_t r_offset) { +bool OffsetVfsFile::WriteByte(u8 data, std::size_t r_offset) { if (r_offset < size) return file->WriteByte(data, offset + r_offset); return false; } -size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, size_t r_offset) { +std::size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, std::size_t r_offset) { return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset); } @@ -85,12 +87,12 @@ bool OffsetVfsFile::Rename(std::string_view name) { return file->Rename(name); } -size_t OffsetVfsFile::GetOffset() const { +std::size_t OffsetVfsFile::GetOffset() const { return offset; } -size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const { - return std::clamp(r_size, size_t{0}, size - r_offset); +std::size_t OffsetVfsFile::TrimToFit(std::size_t r_size, std::size_t r_offset) const { + return std::clamp(r_size, std::size_t{0}, size - r_offset); } } // namespace FileSys diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index cb92d1570..8062702a7 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -17,33 +17,34 @@ namespace FileSys { // the size of this wrapper. class OffsetVfsFile : public VfsFile { public: - OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0, + OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0, std::string new_name = "", VirtualDir new_parent = nullptr); + ~OffsetVfsFile() override; std::string GetName() const override; - size_t GetSize() const override; - bool Resize(size_t new_size) override; + std::size_t GetSize() const override; + bool Resize(std::size_t new_size) override; std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; bool IsWritable() const override; bool IsReadable() const override; - size_t Read(u8* data, size_t length, size_t offset) const override; - size_t Write(const u8* data, size_t length, size_t offset) override; - boost::optional<u8> ReadByte(size_t offset) const override; - std::vector<u8> ReadBytes(size_t size, size_t offset) const override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; + boost::optional<u8> ReadByte(std::size_t offset) const override; + std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override; std::vector<u8> ReadAllBytes() const override; - bool WriteByte(u8 data, size_t offset) override; - size_t WriteBytes(const std::vector<u8>& data, size_t offset) override; + bool WriteByte(u8 data, std::size_t offset) override; + std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override; bool Rename(std::string_view name) override; - size_t GetOffset() const; + std::size_t GetOffset() const; private: - size_t TrimToFit(size_t r_size, size_t r_offset) const; + std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const; std::shared_ptr<VfsFile> file; - size_t offset; - size_t size; + std::size_t offset; + std::size_t size; std::string name; VirtualDir parent; }; diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 2b8ac7103..5e242e20f 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -8,6 +8,7 @@ #include <utility> #include "common/assert.h" #include "common/common_paths.h" +#include "common/file_util.h" #include "common/logging/log.h" #include "core/file_sys/vfs_real.h" @@ -39,6 +40,7 @@ static std::string ModeFlagsToString(Mode mode) { } RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {} +RealVfsFilesystem::~RealVfsFilesystem() = default; std::string RealVfsFilesystem::GetName() const { return "Real"; @@ -219,15 +221,17 @@ RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOF parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), perms(perms_) {} +RealVfsFile::~RealVfsFile() = default; + std::string RealVfsFile::GetName() const { return path_components.back(); } -size_t RealVfsFile::GetSize() const { +std::size_t RealVfsFile::GetSize() const { return backing->GetSize(); } -bool RealVfsFile::Resize(size_t new_size) { +bool RealVfsFile::Resize(std::size_t new_size) { return backing->Resize(new_size); } @@ -243,13 +247,13 @@ bool RealVfsFile::IsReadable() const { return (perms & Mode::ReadWrite) != 0; } -size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { +std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { if (!backing->Seek(offset, SEEK_SET)) return 0; return backing->ReadBytes(data, length); } -size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { +std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { if (!backing->Seek(offset, SEEK_SET)) return 0; return backing->WriteBytes(data, length); @@ -312,6 +316,8 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& FileUtil::CreateDir(path); } +RealVfsDirectory::~RealVfsDirectory() = default; + std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const { const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); if (!FileUtil::Exists(full_path) || FileUtil::IsDirectory(full_path)) diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 989803d43..681c43e82 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -6,15 +6,19 @@ #include <string_view> #include <boost/container/flat_map.hpp> -#include "common/file_util.h" #include "core/file_sys/mode.h" #include "core/file_sys/vfs.h" +namespace FileUtil { +class IOFile; +} + namespace FileSys { class RealVfsFilesystem : public VfsFilesystem { public: RealVfsFilesystem(); + ~RealVfsFilesystem() override; std::string GetName() const override; bool IsReadable() const override; @@ -40,21 +44,23 @@ class RealVfsFile : public VfsFile { friend class RealVfsDirectory; friend class RealVfsFilesystem; - RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing, - const std::string& path, Mode perms = Mode::Read); - public: + ~RealVfsFile() override; + std::string GetName() const override; - size_t GetSize() const override; - bool Resize(size_t new_size) override; + std::size_t GetSize() const override; + bool Resize(std::size_t new_size) override; std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; bool IsWritable() const override; bool IsReadable() const override; - size_t Read(u8* data, size_t length, size_t offset) const override; - size_t Write(const u8* data, size_t length, size_t offset) override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; bool Rename(std::string_view name) override; private: + RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing, + const std::string& path, Mode perms = Mode::Read); + bool Close(); RealVfsFilesystem& base; @@ -70,9 +76,9 @@ private: class RealVfsDirectory : public VfsDirectory { friend class RealVfsFilesystem; - RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); - public: + ~RealVfsDirectory() override; + std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; @@ -97,6 +103,8 @@ protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; private: + RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); + template <typename T, typename R> std::vector<std::shared_ptr<R>> IterateEntries() const; diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index 98e7c4598..ec7f735b5 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp @@ -13,6 +13,8 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_, : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)), name(std::move(name_)) {} +VectorVfsDirectory::~VectorVfsDirectory() = default; + std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const { return files; } diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index 179f62e4b..cba44a7a6 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h @@ -15,6 +15,7 @@ public: explicit VectorVfsDirectory(std::vector<VirtualFile> files = {}, std::vector<VirtualDir> dirs = {}, std::string name = "", VirtualDir parent = nullptr); + ~VectorVfsDirectory() override; std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 552835738..b2b164368 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -10,6 +10,7 @@ #include <mbedtls/md.h> #include <mbedtls/sha256.h> #include "common/assert.h" +#include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "core/crypto/aes_util.h" @@ -24,14 +25,11 @@ namespace FileSys { constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000; template <typename SourceData, typename SourceKey, typename Destination> -static bool CalculateHMAC256(Destination* out, const SourceKey* key, size_t key_length, - const SourceData* data, size_t data_length) { +static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t key_length, + const SourceData* data, std::size_t data_length) { mbedtls_md_context_t context; mbedtls_md_init(&context); - const auto key_f = reinterpret_cast<const u8*>(key); - const std::vector<u8> key_v(key_f, key_f + key_length); - if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) || mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) || mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) || @@ -44,7 +42,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, size_t key_ return true; } -NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NAXHeader>()) { +NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { std::string path = FileUtil::SanitizePath(file->GetFullPath()); static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca", std::regex_constants::ECMAScript | @@ -64,13 +62,15 @@ NAX::NAX(VirtualFile file_) : file(std::move(file_)), header(std::make_unique<NA } NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) - : file(std::move(file_)), header(std::make_unique<NAXHeader>()) { + : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { Core::Crypto::SHA256Hash hash{}; mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0], Common::HexArrayToString(nca_id, false))); } +NAX::~NAX() = default; + Loader::ResultStatus NAX::Parse(std::string_view path) { if (file->ReadObject(header.get()) != sizeof(NAXHeader)) return Loader::ResultStatus::ErrorBadNAXHeader; @@ -90,7 +90,7 @@ Loader::ResultStatus NAX::Parse(std::string_view path) { const auto enc_keys = header->key_area; - size_t i = 0; + std::size_t i = 0; for (; i < sd_keys.size(); ++i) { std::array<Core::Crypto::Key128, 2> nax_keys{}; if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, std::string(path).c_str(), @@ -98,7 +98,7 @@ Loader::ResultStatus NAX::Parse(std::string_view path) { return Loader::ResultStatus::ErrorNAXKeyHMACFailed; } - for (size_t j = 0; j < nax_keys.size(); ++j) { + for (std::size_t j = 0; j < nax_keys.size(); ++j) { Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(nax_keys[j], Core::Crypto::Mode::ECB); cipher.Transcode(enc_keys[j].data(), 0x10, header->key_area[j].data(), @@ -137,9 +137,9 @@ VirtualFile NAX::GetDecrypted() const { return dec_file; } -std::shared_ptr<NCA> NAX::AsNCA() const { +std::unique_ptr<NCA> NAX::AsNCA() const { if (type == NAXContentType::NCA) - return std::make_shared<NCA>(GetDecrypted()); + return std::make_unique<NCA>(GetDecrypted()); return nullptr; } diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index 55d2154a6..8fedd8585 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h @@ -33,12 +33,13 @@ class NAX : public ReadOnlyVfsDirectory { public: explicit NAX(VirtualFile file); explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id); + ~NAX() override; Loader::ResultStatus GetStatus() const; VirtualFile GetDecrypted() const; - std::shared_ptr<NCA> AsNCA() const; + std::unique_ptr<NCA> AsNCA() const; NAXContentType GetContentType() const; @@ -60,7 +61,7 @@ private: VirtualFile file; Loader::ResultStatus status; - NAXContentType type; + NAXContentType type{}; VirtualFile dec_file; diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 332e5c3d0..0ecdd9f82 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -65,9 +65,9 @@ constexpr u32 MSG_WAITALL = 8; constexpr u32 LR_REGISTER = 30; constexpr u32 SP_REGISTER = 31; constexpr u32 PC_REGISTER = 32; -constexpr u32 CPSR_REGISTER = 33; +constexpr u32 PSTATE_REGISTER = 33; constexpr u32 UC_ARM64_REG_Q0 = 34; -constexpr u32 FPSCR_REGISTER = 66; +constexpr u32 FPCR_REGISTER = 66; // TODO/WiP - Used while working on support for FPU constexpr u32 TODO_DUMMY_REG_997 = 997; @@ -116,7 +116,7 @@ constexpr char target_xml[] = <reg name="pc" bitsize="64" type="code_ptr"/> - <flags id="cpsr_flags" size="4"> + <flags id="pstate_flags" size="4"> <field name="SP" start="0" end="0"/> <field name="" start="1" end="1"/> <field name="EL" start="2" end="3"/> @@ -135,7 +135,7 @@ constexpr char target_xml[] = <field name="Z" start="30" end="30"/> <field name="N" start="31" end="31"/> </flags> - <reg name="cpsr" bitsize="32" type="cpsr_flags"/> + <reg name="pstate" bitsize="32" type="pstate_flags"/> </feature> <feature name="org.gnu.gdb.aarch64.fpu"> </feature> @@ -227,10 +227,10 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) { return thread->context.sp; } else if (id == PC_REGISTER) { return thread->context.pc; - } else if (id == CPSR_REGISTER) { - return thread->context.cpsr; - } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; + } else if (id == PSTATE_REGISTER) { + return thread->context.pstate; + } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { + return thread->context.vector_registers[id - UC_ARM64_REG_Q0][0]; } else { return 0; } @@ -247,10 +247,10 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) thread->context.sp = val; } else if (id == PC_REGISTER) { thread->context.pc = val; - } else if (id == CPSR_REGISTER) { - thread->context.cpsr = val; - } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; + } else if (id == PSTATE_REGISTER) { + thread->context.pstate = val; + } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { + thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; } } @@ -292,7 +292,7 @@ static u8 NibbleToHex(u8 n) { * @param src Pointer to array of output hex string characters. * @param len Length of src array. */ -static u32 HexToInt(const u8* src, size_t len) { +static u32 HexToInt(const u8* src, std::size_t len) { u32 output = 0; while (len-- > 0) { output = (output << 4) | HexCharToValue(src[0]); @@ -307,7 +307,7 @@ static u32 HexToInt(const u8* src, size_t len) { * @param src Pointer to array of output hex string characters. * @param len Length of src array. */ -static u64 HexToLong(const u8* src, size_t len) { +static u64 HexToLong(const u8* src, std::size_t len) { u64 output = 0; while (len-- > 0) { output = (output << 4) | HexCharToValue(src[0]); @@ -323,7 +323,7 @@ static u64 HexToLong(const u8* src, size_t len) { * @param src Pointer to array of u8 bytes. * @param len Length of src array. */ -static void MemToGdbHex(u8* dest, const u8* src, size_t len) { +static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) { while (len-- > 0) { u8 tmp = *src++; *dest++ = NibbleToHex(tmp >> 4); @@ -338,7 +338,7 @@ static void MemToGdbHex(u8* dest, const u8* src, size_t len) { * @param src Pointer to array of output hex string characters. * @param len Length of src array. */ -static void GdbHexToMem(u8* dest, const u8* src, size_t len) { +static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) { while (len-- > 0) { *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]); src += 2; @@ -406,7 +406,7 @@ static u64 GdbHexToLong(const u8* src) { /// Read a byte from the gdb client. static u8 ReadByte() { u8 c; - size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); + std::size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); if (received_size != 1) { LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); Shutdown(); @@ -416,7 +416,7 @@ static u8 ReadByte() { } /// Calculate the checksum of the current command buffer. -static u8 CalculateChecksum(const u8* buffer, size_t length) { +static u8 CalculateChecksum(const u8* buffer, std::size_t length) { return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>())); } @@ -518,7 +518,7 @@ bool CheckBreakpoint(VAddr addr, BreakpointType type) { * @param packet Packet to be sent to client. */ static void SendPacket(const char packet) { - size_t sent_size = send(gdbserver_socket, &packet, 1, 0); + std::size_t sent_size = send(gdbserver_socket, &packet, 1, 0); if (sent_size != 1) { LOG_ERROR(Debug_GDBStub, "send failed"); } @@ -781,11 +781,11 @@ static void ReadRegister() { LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == PC_REGISTER) { LongToGdbHex(reply, RegRead(id, current_thread)); - } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)RegRead(id, current_thread)); - } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + } else if (id == PSTATE_REGISTER) { + IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); + } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { LongToGdbHex(reply, RegRead(id, current_thread)); - } else if (id == FPSCR_REGISTER) { + } else if (id == FPCR_REGISTER) { LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); } else { LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); @@ -811,7 +811,7 @@ static void ReadRegisters() { bufptr += 16; - IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); + IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread))); bufptr += 8; @@ -843,11 +843,11 @@ static void WriteRegister() { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == PC_REGISTER) { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); - } else if (id == CPSR_REGISTER) { + } else if (id == PSTATE_REGISTER) { RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); - } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); - } else if (id == FPSCR_REGISTER) { + } else if (id == FPCR_REGISTER) { RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); } else { RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); @@ -866,16 +866,16 @@ static void WriteRegisters() { if (command_buffer[0] != 'G') return SendReply("E01"); - for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { + for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); - } else if (reg == CPSR_REGISTER) { - RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); - } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { + } else if (reg == PSTATE_REGISTER) { + RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); - } else if (reg == FPSCR_REGISTER) { + } else if (reg == FPCR_REGISTER) { RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); @@ -995,7 +995,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { breakpoint.addr = addr; breakpoint.len = len; Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); - static constexpr std::array<u8, 4> btrap{{0xd4, 0x20, 0x7d, 0x0}}; + static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; Memory::WriteBlock(addr, btrap.data(), btrap.size()); Core::System::GetInstance().InvalidateCpuInstructionCaches(); p.insert({addr, breakpoint}); diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index eaa5395ac..419f45896 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -12,7 +12,7 @@ namespace IPC { /// Size of the command buffer area, in 32-bit words. -constexpr size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); +constexpr std::size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); // These errors are commonly returned by invalid IPC translations, so alias them here for // convenience. @@ -153,7 +153,7 @@ struct DataPayloadHeader { u32_le magic; INSERT_PADDING_WORDS(1); }; -static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadRequest size is incorrect"); +static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadHeader size is incorrect"); struct DomainMessageHeader { enum class CommandType : u32_le { diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 0f3ffdb60..a4bfe2eb0 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -152,8 +152,8 @@ public: } void ValidateHeader() { - const size_t num_domain_objects = context->NumDomainObjects(); - const size_t num_move_objects = context->NumMoveObjects(); + const std::size_t num_domain_objects = context->NumDomainObjects(); + const std::size_t num_move_objects = context->NumMoveObjects(); ASSERT_MSG(!num_domain_objects || !num_move_objects, "cannot move normal handles and domain objects"); ASSERT_MSG((index - datapayload_index) == normal_params_size, @@ -290,13 +290,6 @@ public: Skip(CommandIdSize, false); } - ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy, - u32 num_handles_to_move, - ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) const { - return ResponseBuilder{*context, normal_params_size, num_handles_to_copy, - num_handles_to_move, flags}; - } - template <typename T> T Pop(); @@ -329,10 +322,10 @@ public: T PopRaw(); template <typename T> - Kernel::SharedPtr<T> GetMoveObject(size_t index); + Kernel::SharedPtr<T> GetMoveObject(std::size_t index); template <typename T> - Kernel::SharedPtr<T> GetCopyObject(size_t index); + Kernel::SharedPtr<T> GetCopyObject(std::size_t index); template <class T> std::shared_ptr<T> PopIpcInterface() { @@ -406,12 +399,12 @@ void RequestParser::Pop(First& first_value, Other&... other_values) { } template <typename T> -Kernel::SharedPtr<T> RequestParser::GetMoveObject(size_t index) { +Kernel::SharedPtr<T> RequestParser::GetMoveObject(std::size_t index) { return context->GetMoveObject<T>(index); } template <typename T> -Kernel::SharedPtr<T> RequestParser::GetCopyObject(size_t index) { +Kernel::SharedPtr<T> RequestParser::GetCopyObject(std::size_t index) { return context->GetCopyObject<T>(index); } diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 6657accd5..93577591f 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -35,16 +35,17 @@ static ResultCode WaitForAddress(VAddr address, s64 timeout) { // Gets the threads waiting on an address. static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) { - const auto RetrieveWaitingThreads = - [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { - const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); - auto& thread_list = scheduler->GetThreadList(); - - for (auto& thread : thread_list) { - if (thread->arb_wait_address == arb_addr) - waiting_threads.push_back(thread); - } - }; + const auto RetrieveWaitingThreads = [](std::size_t core_index, + std::vector<SharedPtr<Thread>>& waiting_threads, + VAddr arb_addr) { + const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); + auto& thread_list = scheduler->GetThreadList(); + + for (auto& thread : thread_list) { + if (thread->arb_wait_address == arb_addr) + waiting_threads.push_back(thread); + } + }; // Retrieve all threads that are waiting for this address. std::vector<SharedPtr<Thread>> threads; @@ -66,12 +67,12 @@ static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. - size_t last = waiting_threads.size(); + std::size_t last = waiting_threads.size(); if (num_to_wake > 0) last = num_to_wake; // Signal the waiting threads. - for (size_t i = 0; i < last; i++) { + for (std::size_t i = 0; i < last; i++) { ASSERT(waiting_threads[i]->status == ThreadStatus::WaitArb); waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); waiting_threads[i]->arb_wait_address = 0; diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 4054d5db6..8c2be2681 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -17,10 +17,12 @@ enum { // Confirmed Switch OS error codes MaxConnectionsReached = 7, + InvalidSize = 101, InvalidAddress = 102, HandleTableFull = 105, InvalidMemoryState = 106, InvalidMemoryPermissions = 108, + InvalidThreadPriority = 112, InvalidProcessorId = 113, InvalidHandle = 114, InvalidCombination = 116, @@ -28,6 +30,7 @@ enum { SynchronizationCanceled = 118, TooLarge = 119, InvalidEnumValue = 120, + NoSuchEntry = 121, InvalidState = 125, ResourceLimitExceeded = 132, }; @@ -36,7 +39,7 @@ enum { // WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always // double check that the code matches before re-using the constant. -// TODO(bunnei): Replace these with correct errors for Switch OS +// TODO(bunnei): Replace -1 with correct errors for Switch OS constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); @@ -53,15 +56,17 @@ constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::In constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, ErrCodes::InvalidMemoryPermissions); constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); +constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); +constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); +constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, + ErrCodes::InvalidThreadPriority); constexpr ResultCode ERR_INVALID_POINTER(-1); constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); constexpr ResultCode ERR_NOT_AUTHORIZED(-1); /// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. constexpr ResultCode ERR_INVALID_HANDLE_OS(-1); -constexpr ResultCode ERR_NOT_FOUND(-1); -constexpr ResultCode ERR_OUT_OF_RANGE(-1); -constexpr ResultCode ERR_OUT_OF_RANGE_KERNEL(-1); +constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry); constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); /// Returned when Accept() is called on a port with no sessions to be accepted. constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1); diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 3a079b9a9..5ee5c05e3 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -65,7 +65,7 @@ ResultCode HandleTable::Close(Handle handle) { } bool HandleTable::IsValid(Handle handle) const { - size_t slot = GetSlot(handle); + std::size_t slot = GetSlot(handle); u16 generation = GetGeneration(handle); return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index cac928adb..9e2f33e8a 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -93,7 +93,7 @@ private: * This is the maximum limit of handles allowed per process in CTR-OS. It can be further * reduced by ExHeader values, but this is not emulated here. */ - static const size_t MAX_COUNT = 4096; + static const std::size_t MAX_COUNT = 4096; static u16 GetSlot(Handle handle) { return handle >> 15; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 7264be906..72fb9d250 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -42,9 +42,9 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, Kernel::SharedPtr<Kernel::Event> event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->wakeup_callback = - [context = *this, callback](ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, size_t index) mutable -> bool { + thread->wakeup_callback = [context = *this, callback]( + ThreadWakeupReason reason, SharedPtr<Thread> thread, + SharedPtr<WaitObject> object, std::size_t index) mutable -> bool { ASSERT(thread->status == ThreadStatus::WaitHLEEvent); callback(thread, context, reason); context.WriteToOutgoingCommandBuffer(*thread); @@ -199,8 +199,8 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb } // The data_size already includes the payload header, the padding and the domain header. - size_t size = data_payload_offset + command_header->data_size - - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; + std::size_t size = data_payload_offset + command_header->data_size - + sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; if (domain_message_header) size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); std::copy_n(src_cmdbuf, size, cmd_buf.begin()); @@ -217,8 +217,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) ParseCommandBuffer(cmd_buf.data(), false); // The data_size already includes the payload header, the padding and the domain header. - size_t size = data_payload_offset + command_header->data_size - - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; + std::size_t size = data_payload_offset + command_header->data_size - + sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; if (domain_message_header) size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); @@ -229,7 +229,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) "Handle descriptor bit set but no handles to translate"); // We write the translated handles at a specific offset in the command buffer, this space // was already reserved when writing the header. - size_t current_offset = + std::size_t current_offset = (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32); ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented"); @@ -258,7 +258,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) ASSERT(domain_message_header->num_objects == domain_objects.size()); // Write the domain objects to the command buffer, these go after the raw untranslated data. // TODO(Subv): This completely ignores C buffers. - size_t domain_offset = size - domain_message_header->num_objects; + std::size_t domain_offset = size - domain_message_header->num_objects; auto& request_handlers = server_session->domain_request_handlers; for (auto& object : domain_objects) { @@ -291,14 +291,15 @@ std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { return buffer; } -size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffer_index) const { +std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, + int buffer_index) const { if (size == 0) { LOG_WARNING(Core, "skip empty buffer write"); return 0; } const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; - const size_t buffer_size{GetWriteBufferSize(buffer_index)}; + const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; if (size > buffer_size) { LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, buffer_size); @@ -314,13 +315,13 @@ size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size, int buffe return size; } -size_t HLERequestContext::GetReadBufferSize(int buffer_index) const { +std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const { const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; return is_buffer_a ? BufferDescriptorA()[buffer_index].Size() : BufferDescriptorX()[buffer_index].Size(); } -size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const { +std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const { const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; return is_buffer_b ? BufferDescriptorB()[buffer_index].Size() : BufferDescriptorC()[buffer_index].Size(); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index f0d07f1b6..894479ee0 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -170,7 +170,7 @@ public: std::vector<u8> ReadBuffer(int buffer_index = 0) const; /// Helper function to write a buffer using the appropriate buffer descriptor - size_t WriteBuffer(const void* buffer, size_t size, int buffer_index = 0) const; + std::size_t WriteBuffer(const void* buffer, std::size_t size, int buffer_index = 0) const; /* Helper function to write a buffer using the appropriate buffer descriptor * @@ -182,7 +182,7 @@ public: */ template <typename ContiguousContainer, typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>> - size_t WriteBuffer(const ContiguousContainer& container, int buffer_index = 0) const { + std::size_t WriteBuffer(const ContiguousContainer& container, int buffer_index = 0) const { using ContiguousType = typename ContiguousContainer::value_type; static_assert(std::is_trivially_copyable_v<ContiguousType>, @@ -193,19 +193,19 @@ public: } /// Helper function to get the size of the input buffer - size_t GetReadBufferSize(int buffer_index = 0) const; + std::size_t GetReadBufferSize(int buffer_index = 0) const; /// Helper function to get the size of the output buffer - size_t GetWriteBufferSize(int buffer_index = 0) const; + std::size_t GetWriteBufferSize(int buffer_index = 0) const; template <typename T> - SharedPtr<T> GetCopyObject(size_t index) { + SharedPtr<T> GetCopyObject(std::size_t index) { ASSERT(index < copy_objects.size()); return DynamicObjectCast<T>(copy_objects[index]); } template <typename T> - SharedPtr<T> GetMoveObject(size_t index) { + SharedPtr<T> GetMoveObject(std::size_t index) { ASSERT(index < move_objects.size()); return DynamicObjectCast<T>(move_objects[index]); } @@ -223,7 +223,7 @@ public: } template <typename T> - std::shared_ptr<T> GetDomainRequestHandler(size_t index) const { + std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { return std::static_pointer_cast<T>(domain_request_handlers[index]); } @@ -240,15 +240,15 @@ public: domain_objects.clear(); } - size_t NumMoveObjects() const { + std::size_t NumMoveObjects() const { return move_objects.size(); } - size_t NumCopyObjects() const { + std::size_t NumCopyObjects() const { return copy_objects.size(); } - size_t NumDomainObjects() const { + std::size_t NumDomainObjects() const { return domain_objects.size(); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 615d7901a..3e0800a71 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,6 +13,7 @@ #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -115,6 +116,7 @@ struct KernelCore::Impl { next_thread_id = 1; process_list.clear(); + current_process.reset(); handle_table.Clear(); resource_limits.fill(nullptr); @@ -124,6 +126,8 @@ struct KernelCore::Impl { timer_callback_handle_table.Clear(); timer_callback_event_type = nullptr; + + named_ports.clear(); } void InitializeResourceLimits(KernelCore& kernel) { @@ -203,6 +207,7 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::vector<SharedPtr<Process>> process_list; + SharedPtr<Process> current_process; Kernel::HandleTable handle_table; std::array<SharedPtr<ResourceLimit>, 4> resource_limits; @@ -217,6 +222,10 @@ struct KernelCore::Impl { // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, // allowing us to simply use a pool index or similar. Kernel::HandleTable thread_wakeup_callback_handle_table; + + /// Map of named ports managed by the kernel, which can be retrieved using + /// the ConnectToPort SVC. + NamedPortTable named_ports; }; KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {} @@ -257,6 +266,35 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) { impl->process_list.push_back(std::move(process)); } +void KernelCore::MakeCurrentProcess(SharedPtr<Process> process) { + impl->current_process = std::move(process); +} + +SharedPtr<Process>& KernelCore::CurrentProcess() { + return impl->current_process; +} + +const SharedPtr<Process>& KernelCore::CurrentProcess() const { + return impl->current_process; +} + +void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { + impl->named_ports.emplace(std::move(name), std::move(port)); +} + +KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { + return impl->named_ports.find(name); +} + +KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort( + const std::string& name) const { + return impl->named_ports.find(name); +} + +bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { + return port != impl->named_ports.cend(); +} + u32 KernelCore::CreateNewObjectID() { return impl->next_object_id++; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 089e959ac..c0771ecf0 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,6 +4,8 @@ #pragma once +#include <string> +#include <unordered_map> #include "core/hle/kernel/object.h" template <typename T> @@ -15,6 +17,7 @@ struct EventType; namespace Kernel { +class ClientPort; class HandleTable; class Process; class ResourceLimit; @@ -25,6 +28,9 @@ enum class ResourceLimitCategory : u8; /// Represents a single instance of the kernel. class KernelCore { +private: + using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>; + public: KernelCore(); ~KernelCore(); @@ -59,6 +65,27 @@ public: /// Adds the given shared pointer to an internal list of active processes. void AppendNewProcess(SharedPtr<Process> process); + /// Makes the given process the new current process. + void MakeCurrentProcess(SharedPtr<Process> process); + + /// Retrieves a reference to the current process. + SharedPtr<Process>& CurrentProcess(); + + /// Retrieves a const reference to the current process. + const SharedPtr<Process>& CurrentProcess() const; + + /// Adds a port to the named port table + void AddNamedPort(std::string name, SharedPtr<ClientPort> port); + + /// Finds a port within the named port table with the given name. + NamedPortTable::iterator FindNamedPort(const std::string& name); + + /// Finds a port within the named port table with the given name. + NamedPortTable::const_iterator FindNamedPort(const std::string& name) const; + + /// Determines whether or not the given port is a valid named port. + bool IsValidNamedPort(NamedPortTable::const_iterator port) const; + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 36bf0b677..81675eac5 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/thread.h" #include "core/hle/result.h" +#include "core/memory.h" namespace Kernel { @@ -62,7 +63,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho Handle requesting_thread_handle) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { - return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); + return ERR_INVALID_ADDRESS; } SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); @@ -100,7 +101,7 @@ ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle ho ResultCode Mutex::Release(VAddr address) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { - return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); + return ERR_INVALID_ADDRESS; } auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b025e323f..914bbe0a1 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -40,8 +40,8 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { return process; } -void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { - for (size_t i = 0; i < len; ++i) { +void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { + for (std::size_t i = 0; i < len; ++i) { u32 descriptor = kernel_caps[i]; u32 type = descriptor >> 20; @@ -125,7 +125,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { vm_manager.LogLayout(); status = ProcessStatus::Running; - Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, this); + Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this); } void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { @@ -211,7 +211,7 @@ ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { "Shared memory exceeds bounds of mapped block"); const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; - size_t backing_block_offset = vma->second.offset + vma_offset; + std::size_t backing_block_offset = vma->second.offset + vma_offset; CASCADE_RESULT(auto new_vma, vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 1587d40c1..81538f70c 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -59,7 +59,7 @@ class ResourceLimit; struct CodeSet final : public Object { struct Segment { - size_t offset = 0; + std::size_t offset = 0; VAddr addr = 0; u32 size = 0; }; @@ -164,7 +164,7 @@ public: * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them * to this process. */ - void ParseKernelCaps(const u32* kernel_caps, size_t len); + void ParseKernelCaps(const u32* kernel_caps, std::size_t len); /** * Applies address space changes and launches the process main thread. diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 2c729afe3..2c06bb7ce 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -119,7 +119,7 @@ public: /// Backing memory for this shared memory block. std::shared_ptr<std::vector<u8>> backing_block; /// Offset into the backing block for this shared memory. - size_t backing_block_offset; + std::size_t backing_block_offset; /// Size of the memory block. Page-aligned. u64 size; /// Permission restrictions applied to the process which created the block. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5da71cff0..371fc439e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -35,10 +35,21 @@ #include "core/hle/service/service.h" namespace Kernel { +namespace { +constexpr bool Is4KBAligned(VAddr address) { + return (address & 0xFFF) == 0; +} +} // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); + + // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. + if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { + return ERR_INVALID_SIZE; + } + auto& process = *Core::CurrentProcess(); CASCADE_RESULT(*heap_addr, process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); @@ -56,6 +67,15 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); + + if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); } @@ -63,24 +83,36 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); + + if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); } /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { - if (!Memory::IsValidVirtualAddress(port_name_address)) + if (!Memory::IsValidVirtualAddress(port_name_address)) { return ERR_NOT_FOUND; + } static constexpr std::size_t PortNameMaxLength = 11; // Read 1 char beyond the max allowed port name to detect names that are too long. std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); - if (port_name.size() > PortNameMaxLength) + if (port_name.size() > PortNameMaxLength) { return ERR_PORT_NAME_TOO_LONG; + } LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); - auto it = Service::g_kernel_named_ports.find(port_name); - if (it == Service::g_kernel_named_ports.end()) { + auto& kernel = Core::System::GetInstance().Kernel(); + auto it = kernel.FindNamedPort(port_name); + if (!kernel.IsValidNamedPort(it)) { LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ERR_NOT_FOUND; } @@ -91,7 +123,6 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session - auto& kernel = Core::System::GetInstance().Kernel(); CASCADE_RESULT(*out_handle, kernel.HandleTable().Create(client_session)); return RESULT_SUCCESS; } @@ -144,7 +175,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { /// Default thread wakeup callback for WaitSynchronization static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, size_t index) { + SharedPtr<WaitObject> object, std::size_t index) { ASSERT(thread->status == ThreadStatus::WaitSynchAny); if (reason == ThreadWakeupReason::Timeout) { @@ -249,6 +280,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, "requesting_current_thread_handle=0x{:08X}", holding_thread_handle, mutex_addr, requesting_thread_handle); + if (Memory::IsKernelVirtualAddress(mutex_addr)) { + return ERR_INVALID_ADDRESS_STATE; + } + auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, requesting_thread_handle); @@ -258,6 +293,10 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, static ResultCode ArbitrateUnlock(VAddr mutex_addr) { LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); + if (Memory::IsKernelVirtualAddress(mutex_addr)) { + return ERR_INVALID_ADDRESS_STATE; + } + return Mutex::Release(mutex_addr); } @@ -271,7 +310,11 @@ static void Break(u64 reason, u64 info1, u64 info2) { } /// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(VAddr address, s32 len) { +static void OutputDebugString(VAddr address, u64 len) { + if (len == 0) { + return; + } + std::string str(len, '\0'); Memory::ReadBlock(address, str.data(), str.size()); LOG_DEBUG(Debug_Emulated, "{}", str); @@ -376,7 +419,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) { /// Sets the priority for the specified thread static ResultCode SetThreadPriority(Handle handle, u32 priority) { if (priority > THREADPRIO_LOWEST) { - return ERR_OUT_OF_RANGE; + return ERR_INVALID_THREAD_PRIORITY; } auto& kernel = Core::System::GetInstance().Kernel(); @@ -409,35 +452,43 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shared_memory_handle, addr, size, permissions); + if (!Is4KBAligned(addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + + const auto permissions_type = static_cast<MemoryPermission>(permissions); + if (permissions_type != MemoryPermission::Read && + permissions_type != MemoryPermission::ReadWrite) { + LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); + return ERR_INVALID_MEMORY_PERMISSIONS; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); if (!shared_memory) { return ERR_INVALID_HANDLE; } - MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); - switch (permissions_type) { - case MemoryPermission::Read: - case MemoryPermission::Write: - case MemoryPermission::ReadWrite: - case MemoryPermission::Execute: - case MemoryPermission::ReadExecute: - case MemoryPermission::WriteExecute: - case MemoryPermission::ReadWriteExecute: - case MemoryPermission::DontCare: - return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, - MemoryPermission::DontCare); - default: - LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); - } - - return RESULT_SUCCESS; + return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, + MemoryPermission::DontCare); } static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", shared_memory_handle, addr, size); + if (!Is4KBAligned(addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); @@ -518,10 +569,10 @@ static void ExitProcess() { /// Creates a new thread static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, u32 priority, s32 processor_id) { - std::string name = fmt::format("unknown-{:X}", entry_point); + std::string name = fmt::format("thread-{:X}", entry_point); if (priority > THREADPRIO_LOWEST) { - return ERR_OUT_OF_RANGE; + return ERR_INVALID_THREAD_PRIORITY; } SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; @@ -542,8 +593,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V case THREADPROCESSORID_3: break; default: - ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); - break; + LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); + return ERR_INVALID_PROCESSOR_ID; } auto& kernel = Core::System::GetInstance().Kernel(); @@ -641,16 +692,17 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", condition_variable_addr, target); - auto RetrieveWaitingThreads = - [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) { - const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); - auto& thread_list = scheduler->GetThreadList(); + auto RetrieveWaitingThreads = [](std::size_t core_index, + std::vector<SharedPtr<Thread>>& waiting_threads, + VAddr condvar_addr) { + const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); + auto& thread_list = scheduler->GetThreadList(); - for (auto& thread : thread_list) { - if (thread->condvar_wait_address == condvar_addr) - waiting_threads.push_back(thread); - } - }; + for (auto& thread : thread_list) { + if (thread->condvar_wait_address == condvar_addr) + waiting_threads.push_back(thread); + } + }; // Retrieve a list of all threads that are waiting for this condition variable. std::vector<SharedPtr<Thread>> waiting_threads; @@ -666,7 +718,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target // Only process up to 'target' threads, unless 'target' is -1, in which case process // them all. - size_t last = waiting_threads.size(); + std::size_t last = waiting_threads.size(); if (target != -1) last = target; @@ -674,12 +726,12 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target if (last > waiting_threads.size()) return RESULT_SUCCESS; - for (size_t index = 0; index < last; ++index) { + for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; ASSERT(thread->condvar_wait_address == condition_variable_addr); - size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); + std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); auto& monitor = Core::System::GetInstance().Monitor(); @@ -892,12 +944,28 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, local_permissions, remote_permissions); + // Size must be a multiple of 4KB and be less than or equal to + // approx. 8 GB (actually (1GB - 512B) * 8) + if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) { + return ERR_INVALID_SIZE; + } + + const auto local_perms = static_cast<MemoryPermission>(local_permissions); + if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { + return ERR_INVALID_MEMORY_PERMISSIONS; + } + + const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); + if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && + remote_perms != MemoryPermission::DontCare) { + return ERR_INVALID_MEMORY_PERMISSIONS; + } + auto& kernel = Core::System::GetInstance().Kernel(); auto& handle_table = kernel.HandleTable(); auto shared_mem_handle = SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, - static_cast<MemoryPermission>(local_permissions), - static_cast<MemoryPermission>(remote_permissions)); + local_perms, remote_perms); CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); return RESULT_SUCCESS; diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 79c3fe31b..fea9ba5ea 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -13,7 +13,9 @@ namespace Kernel { -#define PARAM(n) Core::CurrentArmInterface().GetReg(n) +static inline u64 Param(int n) { + return Core::CurrentArmInterface().GetReg(n); +} /** * HLE a function return from the current ARM userland process @@ -28,23 +30,23 @@ static inline void FuncReturn(u64 res) { template <ResultCode func(u64)> void SvcWrap() { - FuncReturn(func(PARAM(0)).raw); + FuncReturn(func(Param(0)).raw); } template <ResultCode func(u32)> void SvcWrap() { - FuncReturn(func((u32)PARAM(0)).raw); + FuncReturn(func((u32)Param(0)).raw); } template <ResultCode func(u32, u32)> void SvcWrap() { - FuncReturn(func((u32)PARAM(0), (u32)PARAM(1)).raw); + FuncReturn(func((u32)Param(0), (u32)Param(1)).raw); } template <ResultCode func(u32*, u32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, (u32)PARAM(1)).raw; + u32 retval = func(¶m_1, (u32)Param(1)).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -52,39 +54,39 @@ void SvcWrap() { template <ResultCode func(u32*, u64)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, PARAM(1)).raw; + u32 retval = func(¶m_1, Param(1)).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } template <ResultCode func(u64, s32)> void SvcWrap() { - FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw); + FuncReturn(func(Param(0), (s32)Param(1)).raw); } template <ResultCode func(u64*, u64)> void SvcWrap() { u64 param_1 = 0; - u32 retval = func(¶m_1, PARAM(1)).raw; + u32 retval = func(¶m_1, Param(1)).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } template <ResultCode func(u32, u64)> void SvcWrap() { - FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), PARAM(1)).raw); + FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw); } template <ResultCode func(u32, u32, u64)> void SvcWrap() { - FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), (u32)(PARAM(1) & 0xFFFFFFFF), PARAM(2)).raw); + FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw); } template <ResultCode func(u32, u32*, u64*)> void SvcWrap() { u32 param_1 = 0; u64 param_2 = 0; - ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); + ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); Core::CurrentArmInterface().SetReg(1, param_1); Core::CurrentArmInterface().SetReg(2, param_2); FuncReturn(retval.raw); @@ -93,46 +95,46 @@ void SvcWrap() { template <ResultCode func(u64, u64, u32, u32)> void SvcWrap() { FuncReturn( - func(PARAM(0), PARAM(1), (u32)(PARAM(3) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw); + func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw); } template <ResultCode func(u32, u64, u32)> void SvcWrap() { - FuncReturn(func((u32)PARAM(0), PARAM(1), (u32)PARAM(2)).raw); + FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw); } template <ResultCode func(u64, u64, u64)> void SvcWrap() { - FuncReturn(func(PARAM(0), PARAM(1), PARAM(2)).raw); + FuncReturn(func(Param(0), Param(1), Param(2)).raw); } template <ResultCode func(u32, u64, u64, u32)> void SvcWrap() { - FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw); + FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw); } template <ResultCode func(u32, u64, u64)> void SvcWrap() { - FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw); + FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw); } template <ResultCode func(u32*, u64, u64, s64)> void SvcWrap() { u32 param_1 = 0; - ResultCode retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)); + ResultCode retval = func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)); Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval.raw); } template <ResultCode func(u64, u64, u32, s64)> void SvcWrap() { - FuncReturn(func(PARAM(0), PARAM(1), (u32)PARAM(2), (s64)PARAM(3)).raw); + FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw); } template <ResultCode func(u64*, u64, u64, u64)> void SvcWrap() { u64 param_1 = 0; - u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3)).raw; + u32 retval = func(¶m_1, Param(1), Param(2), Param(3)).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -141,7 +143,7 @@ template <ResultCode func(u32*, u64, u64, u64, u32, s32)> void SvcWrap() { u32 param_1 = 0; u32 retval = - func(¶m_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF)) + func(¶m_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF)) .raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); @@ -151,13 +153,13 @@ template <ResultCode func(MemoryInfo*, PageInfo*, u64)> void SvcWrap() { MemoryInfo memory_info = {}; PageInfo page_info = {}; - u32 retval = func(&memory_info, &page_info, PARAM(2)).raw; + u32 retval = func(&memory_info, &page_info, Param(2)).raw; - Memory::Write64(PARAM(0), memory_info.base_address); - Memory::Write64(PARAM(0) + 8, memory_info.size); - Memory::Write32(PARAM(0) + 16, memory_info.type); - Memory::Write32(PARAM(0) + 20, memory_info.attributes); - Memory::Write32(PARAM(0) + 24, memory_info.permission); + Memory::Write64(Param(0), memory_info.base_address); + Memory::Write64(Param(0) + 8, memory_info.size); + Memory::Write32(Param(0) + 16, memory_info.type); + Memory::Write32(Param(0) + 20, memory_info.attributes); + Memory::Write32(Param(0) + 24, memory_info.permission); FuncReturn(retval); } @@ -165,7 +167,7 @@ void SvcWrap() { template <ResultCode func(u32*, u64, u64, u32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; + u32 retval = func(¶m_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -174,7 +176,7 @@ template <ResultCode func(Handle*, u64, u32, u32)> void SvcWrap() { u32 param_1 = 0; u32 retval = - func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; + func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -182,14 +184,14 @@ void SvcWrap() { template <ResultCode func(u64, u32, s32, s64)> void SvcWrap() { FuncReturn( - func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)) + func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)) .raw); } template <ResultCode func(u64, u32, s32, s32)> void SvcWrap() { - FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), - (s32)(PARAM(3) & 0xFFFFFFFF)) + FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), + (s32)(Param(3) & 0xFFFFFFFF)) .raw); } @@ -219,20 +221,17 @@ void SvcWrap() { template <void func(s64)> void SvcWrap() { - func((s64)PARAM(0)); + func((s64)Param(0)); } -template <void func(u64, s32 len)> +template <void func(u64, u64 len)> void SvcWrap() { - func(PARAM(0), (s32)(PARAM(1) & 0xFFFFFFFF)); + func(Param(0), Param(1)); } template <void func(u64, u64, u64)> void SvcWrap() { - func(PARAM(0), PARAM(1), PARAM(2)); + func(Param(0), Param(1), Param(2)); } -#undef PARAM -#undef FuncReturn - } // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3d10d9af2..c2d7535c9 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -217,8 +217,8 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd context.cpu_registers[0] = arg; context.pc = entry_point; context.sp = stack_top; - context.cpsr = 0; - context.fpscr = 0; + context.pstate = 0; + context.fpcr = 0; } ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, @@ -227,12 +227,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > THREADPRIO_LOWEST) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); - return ERR_OUT_OF_RANGE; + return ERR_INVALID_THREAD_PRIORITY; } if (processor_id > THREADPROCESSORID_MAX) { LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); - return ERR_OUT_OF_RANGE_KERNEL; + return ERR_INVALID_PROCESSOR_ID; } // TODO(yuriks): Other checks, returning 0xD9001BEA @@ -275,7 +275,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name available_slot = 0; // Use the first slot in the new page // Allocate some memory from the end of the linear heap for this region. - const size_t offset = thread->tls_memory->size(); + const std::size_t offset = thread->tls_memory->size(); thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0); auto& vm_manager = owner_process->vm_manager; @@ -311,13 +311,13 @@ void Thread::BoostPriority(u32 priority) { } SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, - SharedPtr<Process> owner_process) { + Process& owner_process) { // Setup page table so we can write to memory - SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); + SetCurrentPageTable(&owner_process.vm_manager.page_table); // Initialize new "main" thread auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, - Memory::STACK_AREA_VADDR_END, std::move(owner_process)); + Memory::STACK_AREA_VADDR_END, &owner_process); SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 20f50458b..91e9b79ec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -15,6 +15,12 @@ #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" +namespace Kernel { + +class KernelCore; +class Process; +class Scheduler; + enum ThreadPriority : u32 { THREADPRIO_HIGHEST = 0, ///< Highest thread priority THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps @@ -54,12 +60,6 @@ enum class ThreadWakeupReason { Timeout // The thread was woken up due to a wait timeout. }; -namespace Kernel { - -class KernelCore; -class Process; -class Scheduler; - class Thread final : public WaitObject { public: /** @@ -254,7 +254,7 @@ public: Handle callback_handle; using WakeupCallback = bool(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, size_t index); + SharedPtr<WaitObject> object, std::size_t index); // Callback that will be invoked when the thread is resumed from a waiting state. If the thread // was waiting via WaitSynchronizationN then the object will be the last object that became // available. In case of a timeout, the object will be nullptr. @@ -281,7 +281,7 @@ private: * @return A shared pointer to the main thread */ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, - SharedPtr<Process> owner_process); + Process& owner_process); /** * Gets the current thread diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 479cacb62..608cbd57b 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -86,7 +86,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, - size_t offset, u64 size, + std::size_t offset, u64 size, MemoryState state) { ASSERT(block != nullptr); ASSERT(offset + size <= block->size()); diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 98bd04bea..de75036c0 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -81,7 +81,7 @@ struct VirtualMemoryArea { /// Memory block backing this VMA. std::shared_ptr<std::vector<u8>> backing_block = nullptr; /// Offset into the backing_memory the mapping starts from. - size_t offset = 0; + std::size_t offset = 0; // Settings for type = BackingMemory /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed. @@ -147,7 +147,7 @@ public: * @param state MemoryState tag to attach to the VMA. */ ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, - size_t offset, u64 size, MemoryState state); + std::size_t offset, u64 size, MemoryState state); /** * Maps an unmanaged host memory pointer at a given address. diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index eef00b729..b190ceb98 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -81,7 +81,7 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { } } - size_t index = thread->GetWaitObjectIndex(this); + std::size_t index = thread->GetWaitObjectIndex(this); for (auto& object : thread->wait_objects) object->RemoveWaitingThread(thread.get()); diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 1502dbf55..e61748ca3 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -34,7 +34,7 @@ public: static const FunctionInfo functions[] = { {0, &IProfile::Get, "Get"}, {1, &IProfile::GetBase, "GetBase"}, - {10, nullptr, "GetImageSize"}, + {10, &IProfile::GetImageSize, "GetImageSize"}, {11, &IProfile::LoadImage, "LoadImage"}, }; RegisterHandlers(functions); @@ -93,6 +93,14 @@ private: rb.Push<u32>(jpeg_size); } + void GetImageSize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_ACC, "(STUBBED) called"); + constexpr u32 jpeg_size = 107; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(jpeg_size); + } + const ProfileManager& profile_manager; UUID user_id; ///< The user id this profile refers to. }; @@ -122,11 +130,10 @@ private: void GetAccountId(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_ACC, "(STUBBED) called"); - // TODO(Subv): Find out what this actually does and implement it. Stub it as an error for - // now since we do not implement NNID. Returning a bogus id here will cause games to send - // invalid IPC requests after ListOpenUsers is called. - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + // Should return a nintendo account ID + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u64>(1); } }; diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp index 9bd595a37..e84d9f7cf 100644 --- a/src/core/hle/service/acc/acc_aa.cpp +++ b/src/core/hle/service/acc/acc_aa.cpp @@ -18,4 +18,6 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_AA::~ACC_AA() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h index 2e08c781a..9edb0421b 100644 --- a/src/core/hle/service/acc/acc_aa.h +++ b/src/core/hle/service/acc/acc_aa.h @@ -12,6 +12,7 @@ class ACC_AA final : public Module::Interface { public: explicit ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_AA() override; }; } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 0218ee859..ad455c3a7 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -51,4 +51,6 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_SU::~ACC_SU() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h index 79a47d88d..fcced063a 100644 --- a/src/core/hle/service/acc/acc_su.h +++ b/src/core/hle/service/acc/acc_su.h @@ -6,14 +6,13 @@ #include "core/hle/service/acc/acc.h" -namespace Service { -namespace Account { +namespace Service::Account { class ACC_SU final : public Module::Interface { public: explicit ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_SU() override; }; -} // namespace Account -} // namespace Service +} // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 84a4d05b8..72d4adf35 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -31,4 +31,6 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_U0::~ACC_U0() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h index e8a114f99..a1290e0bd 100644 --- a/src/core/hle/service/acc/acc_u0.h +++ b/src/core/hle/service/acc/acc_u0.h @@ -12,6 +12,7 @@ class ACC_U0 final : public Module::Interface { public: explicit ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_U0() override; }; } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 495693949..d480f08e5 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -38,4 +38,6 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_U1::~ACC_U1() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h index a77520e6f..9e79daee3 100644 --- a/src/core/hle/service/acc/acc_u1.h +++ b/src/core/hle/service/acc/acc_u1.h @@ -12,6 +12,7 @@ class ACC_U1 final : public Module::Interface { public: explicit ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_U1() override; }; } // namespace Service::Account diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index e0b03d763..bcb3475db 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -25,13 +25,15 @@ const UUID& UUID::Generate() { ProfileManager::ProfileManager() { // TODO(ogniK): Create the default user we have for now until loading/saving users is added auto user_uuid = UUID{1, 0}; - CreateNewUser(user_uuid, Settings::values.username); + ASSERT(CreateNewUser(user_uuid, Settings::values.username).IsSuccess()); OpenUser(user_uuid); } +ProfileManager::~ProfileManager() = default; + /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the /// internal management of the users profiles -boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { +boost::optional<std::size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { if (user_count >= MAX_USERS) { return boost::none; } @@ -40,7 +42,7 @@ boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { } /// Deletes a specific profile based on it's profile index -bool ProfileManager::RemoveProfileAtIndex(size_t index) { +bool ProfileManager::RemoveProfileAtIndex(std::size_t index) { if (index >= MAX_USERS || index >= user_count) { return false; } @@ -89,7 +91,8 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern /// specifically by allowing an std::string for the username. This is required specifically since /// we're loading a string straight from the config ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) { - ProfileUsername username_output; + ProfileUsername username_output{}; + if (username.size() > username_output.size()) { std::copy_n(username.begin(), username_output.size(), username_output.begin()); } else { @@ -99,7 +102,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username) } /// Returns a users profile index based on their user id. -boost::optional<size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { +boost::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { if (!uuid) { return boost::none; } @@ -108,16 +111,17 @@ boost::optional<size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { if (iter == profiles.end()) { return boost::none; } - return static_cast<size_t>(std::distance(profiles.begin(), iter)); + return static_cast<std::size_t>(std::distance(profiles.begin(), iter)); } /// Returns a users profile index based on their profile -boost::optional<size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const { +boost::optional<std::size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) const { return GetUserIndex(user.user_uuid); } /// Returns the data structure used by the switch when GetProfileBase is called on acc:* -bool ProfileManager::GetProfileBase(boost::optional<size_t> index, ProfileBase& profile) const { +bool ProfileManager::GetProfileBase(boost::optional<std::size_t> index, + ProfileBase& profile) const { if (index == boost::none || index >= MAX_USERS) { return false; } @@ -141,14 +145,16 @@ bool ProfileManager::GetProfileBase(const ProfileInfo& user, ProfileBase& profil /// Returns the current user count on the system. We keep a variable which tracks the count so we /// don't have to loop the internal profile array every call. -size_t ProfileManager::GetUserCount() const { + +std::size_t ProfileManager::GetUserCount() const { return user_count; } /// Lists the current "opened" users on the system. Users are typically not open until they sign /// into something or pick a profile. As of right now users should all be open until qlaunch is /// booting -size_t ProfileManager::GetOpenUserCount() const { + +std::size_t ProfileManager::GetOpenUserCount() const { return std::count_if(profiles.begin(), profiles.end(), [](const ProfileInfo& p) { return p.is_open; }); } @@ -204,7 +210,7 @@ UUID ProfileManager::GetLastOpenedUser() const { } /// Return the users profile base and the unknown arbitary data. -bool ProfileManager::GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile, +bool ProfileManager::GetProfileBaseAndData(boost::optional<std::size_t> index, ProfileBase& profile, ProfileData& data) const { if (GetProfileBase(index, profile)) { data = profiles[index.get()].data; diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 52967844d..bffd4cf4d 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -12,8 +12,8 @@ #include "core/hle/result.h" namespace Service::Account { -constexpr size_t MAX_USERS = 8; -constexpr size_t MAX_DATA = 128; +constexpr std::size_t MAX_USERS = 8; +constexpr std::size_t MAX_DATA = 128; constexpr u128 INVALID_UUID{{0, 0}}; struct UUID { @@ -82,21 +82,23 @@ static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size"); class ProfileManager { public: ProfileManager(); // TODO(ogniK): Load from system save + ~ProfileManager(); + ResultCode AddUser(const ProfileInfo& user); ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username); ResultCode CreateNewUser(UUID uuid, const std::string& username); - boost::optional<size_t> GetUserIndex(const UUID& uuid) const; - boost::optional<size_t> GetUserIndex(const ProfileInfo& user) const; - bool GetProfileBase(boost::optional<size_t> index, ProfileBase& profile) const; + boost::optional<std::size_t> GetUserIndex(const UUID& uuid) const; + boost::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const; + bool GetProfileBase(boost::optional<std::size_t> index, ProfileBase& profile) const; bool GetProfileBase(UUID uuid, ProfileBase& profile) const; bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; - bool GetProfileBaseAndData(boost::optional<size_t> index, ProfileBase& profile, + bool GetProfileBaseAndData(boost::optional<std::size_t> index, ProfileBase& profile, ProfileData& data) const; bool GetProfileBaseAndData(UUID uuid, ProfileBase& profile, ProfileData& data) const; bool GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile, ProfileData& data) const; - size_t GetUserCount() const; - size_t GetOpenUserCount() const; + std::size_t GetUserCount() const; + std::size_t GetOpenUserCount() const; bool UserExists(UUID uuid) const; void OpenUser(UUID uuid); void CloseUser(UUID uuid); @@ -108,9 +110,9 @@ public: private: std::array<ProfileInfo, MAX_USERS> profiles{}; - size_t user_count = 0; - boost::optional<size_t> AddToProfiles(const ProfileInfo& profile); - bool RemoveProfileAtIndex(size_t index); + std::size_t user_count = 0; + boost::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); + bool RemoveProfileAtIndex(std::size_t index); UUID last_opened_user{INVALID_UUID}; }; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 818c03e0f..69bfce1c1 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -20,6 +20,7 @@ #include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/pm/pm.h" #include "core/hle/service/set/set.h" +#include "core/hle/service/vi/vi.h" #include "core/settings.h" namespace Service::AM { @@ -35,6 +36,8 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") { RegisterHandlers(functions); } +IWindowController::~IWindowController() = default; + void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; @@ -61,6 +64,8 @@ IAudioController::IAudioController() : ServiceFramework("IAudioController") { RegisterHandlers(functions); } +IAudioController::~IAudioController() = default; + void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -116,7 +121,10 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" RegisterHandlers(functions); } +IDisplayController::~IDisplayController() = default; + IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {} +IDebugFunctions::~IDebugFunctions() = default; ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { @@ -165,6 +173,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); } +ISelfController::~ISelfController() = default; + void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { // Takes 3 input u8s with each field located immediately after the previous u8, these are // bool flags. No output. @@ -325,7 +335,7 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter" {51, nullptr, "SetVrModeEnabled"}, {52, nullptr, "SwitchLcdBacklight"}, {55, nullptr, "IsInControllerFirmwareUpdateSection"}, - {60, nullptr, "GetDefaultDisplayResolution"}, + {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, {62, nullptr, "GetHdcpAuthenticationState"}, @@ -337,6 +347,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter" event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event"); } +ICommonStateGetter::~ICommonStateGetter() = default; + void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -382,6 +394,21 @@ void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLEReque LOG_WARNING(Service_AM, "(STUBBED) called"); } +void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + + if (Settings::values.use_docked_mode) { + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); + } else { + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); + rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); + } + + LOG_DEBUG(Service_AM, "called"); +} + void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { const bool use_docked_mode{Settings::values.use_docked_mode}; IPC::ResponseBuilder rb{ctx, 3}; @@ -435,7 +462,7 @@ private: std::memcpy(&buffer[offset], data.data(), data.size()); - IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_AM, "called, offset={}", offset); @@ -445,13 +472,13 @@ private: IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - const size_t size{ctx.GetWriteBufferSize()}; + const std::size_t size{ctx.GetWriteBufferSize()}; ASSERT(offset + size <= buffer.size()); ctx.WriteBuffer(buffer.data() + offset, size); - IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_AM, "called, offset={}", offset); @@ -541,7 +568,7 @@ private: IPC::RequestParser rp{ctx}; storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); - IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_AM, "called"); @@ -573,6 +600,8 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple RegisterHandlers(functions); } +ILibraryAppletCreator::~ILibraryAppletCreator() = default; + void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -587,7 +616,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { const u64 size{rp.Pop<u64>()}; std::vector<u8> buffer(size); - IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)}; + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); @@ -638,6 +667,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF RegisterHandlers(functions); } +IApplicationFunctions::~IApplicationFunctions() = default; + void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { constexpr std::array<u8, 0x88> data{{ 0xca, 0x97, 0x94, 0xc7, // Magic @@ -760,6 +791,8 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" RegisterHandlers(functions); } +IHomeMenuFunctions::~IHomeMenuFunctions() = default; + void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -783,6 +816,8 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat RegisterHandlers(functions); } +IGlobalStateController::~IGlobalStateController() = default; + IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { static const FunctionInfo functions[] = { {0, nullptr, "CreateApplication"}, @@ -793,6 +828,8 @@ IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreat RegisterHandlers(functions); } +IApplicationCreator::~IApplicationCreator() = default; + IProcessWindingController::IProcessWindingController() : ServiceFramework("IProcessWindingController") { static const FunctionInfo functions[] = { @@ -807,4 +844,6 @@ IProcessWindingController::IProcessWindingController() }; RegisterHandlers(functions); } + +IProcessWindingController::~IProcessWindingController() = default; } // namespace Service::AM diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 9e8bb4e43..b39b0d838 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -42,6 +42,7 @@ enum SystemLanguage { class IWindowController final : public ServiceFramework<IWindowController> { public: IWindowController(); + ~IWindowController() override; private: void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); @@ -51,6 +52,7 @@ private: class IAudioController final : public ServiceFramework<IAudioController> { public: IAudioController(); + ~IAudioController() override; private: void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx); @@ -63,16 +65,19 @@ private: class IDisplayController final : public ServiceFramework<IDisplayController> { public: IDisplayController(); + ~IDisplayController() override; }; class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { public: IDebugFunctions(); + ~IDebugFunctions() override; }; class ISelfController final : public ServiceFramework<ISelfController> { public: explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); + ~ISelfController() override; private: void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); @@ -98,6 +103,7 @@ private: class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { public: ICommonStateGetter(); + ~ICommonStateGetter() override; private: enum class FocusState : u8 { @@ -117,6 +123,7 @@ private: void GetOperationMode(Kernel::HLERequestContext& ctx); void GetPerformanceMode(Kernel::HLERequestContext& ctx); void GetBootMode(Kernel::HLERequestContext& ctx); + void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); Kernel::SharedPtr<Kernel::Event> event; }; @@ -124,6 +131,7 @@ private: class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { public: ILibraryAppletCreator(); + ~ILibraryAppletCreator() override; private: void CreateLibraryApplet(Kernel::HLERequestContext& ctx); @@ -133,6 +141,7 @@ private: class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { public: IApplicationFunctions(); + ~IApplicationFunctions() override; private: void PopLaunchParameter(Kernel::HLERequestContext& ctx); @@ -150,6 +159,7 @@ private: class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { public: IHomeMenuFunctions(); + ~IHomeMenuFunctions() override; private: void RequestToGetForeground(Kernel::HLERequestContext& ctx); @@ -158,16 +168,19 @@ private: class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { public: IGlobalStateController(); + ~IGlobalStateController() override; }; class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { public: IApplicationCreator(); + ~IApplicationCreator() override; }; class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { public: IProcessWindingController(); + ~IProcessWindingController() override; }; /// Registers all AM services with the specified service manager. diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 7cebc918a..4296c255e 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -222,4 +222,6 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) RegisterHandlers(functions); } +AppletAE::~AppletAE() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index bdc57b9bc..1ed77baa4 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -18,7 +18,7 @@ namespace AM { class AppletAE final : public ServiceFramework<AppletAE> { public: explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); - ~AppletAE() = default; + ~AppletAE() override; private: void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index beea7d19b..e45cf6e20 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -103,4 +103,6 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) RegisterHandlers(functions); } +AppletOE::~AppletOE() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index c52e2a322..60cfdfd9d 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -18,7 +18,7 @@ namespace AM { class AppletOE final : public ServiceFramework<AppletOE> { public: explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); - ~AppletOE() = default; + ~AppletOE() override; private: void OpenApplicationProxy(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp index af46e9494..0e3088bc8 100644 --- a/src/core/hle/service/am/idle.cpp +++ b/src/core/hle/service/am/idle.cpp @@ -21,4 +21,6 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { RegisterHandlers(functions); } +IdleSys::~IdleSys() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h index 1eb68d2c9..c44e856b1 100644 --- a/src/core/hle/service/am/idle.h +++ b/src/core/hle/service/am/idle.h @@ -11,6 +11,7 @@ namespace Service::AM { class IdleSys final : public ServiceFramework<IdleSys> { public: explicit IdleSys(); + ~IdleSys() override; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp index 447fe8669..1c37f849f 100644 --- a/src/core/hle/service/am/omm.cpp +++ b/src/core/hle/service/am/omm.cpp @@ -39,4 +39,6 @@ OMM::OMM() : ServiceFramework{"omm"} { RegisterHandlers(functions); } +OMM::~OMM() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h index 49e5d331c..59dc91b72 100644 --- a/src/core/hle/service/am/omm.h +++ b/src/core/hle/service/am/omm.h @@ -11,6 +11,7 @@ namespace Service::AM { class OMM final : public ServiceFramework<OMM> { public: explicit OMM(); + ~OMM() override; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp index a05d433d0..003ee8667 100644 --- a/src/core/hle/service/am/spsm.cpp +++ b/src/core/hle/service/am/spsm.cpp @@ -27,4 +27,6 @@ SPSM::SPSM() : ServiceFramework{"spsm"} { RegisterHandlers(functions); } +SPSM::~SPSM() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h index 57dde62e1..3a0b979fa 100644 --- a/src/core/hle/service/am/spsm.h +++ b/src/core/hle/service/am/spsm.h @@ -11,6 +11,7 @@ namespace Service::AM { class SPSM final : public ServiceFramework<SPSM> { public: explicit SPSM(); + ~SPSM() override; }; } // namespace Service::AM diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 6e7438580..d9eeac9ec 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -23,6 +23,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u") { RegisterHandlers(functions); } +AOC_U::~AOC_U() = default; + void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 17d48ef30..29ce8f488 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -11,7 +11,7 @@ namespace Service::AOC { class AOC_U final : public ServiceFramework<AOC_U> { public: AOC_U(); - ~AOC_U() = default; + ~AOC_U() override; private: void CountAddOnContent(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 4109cb7f7..f3c09bbb1 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -9,6 +9,9 @@ namespace Service::APM { +Module::Module() = default; +Module::~Module() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module_ = std::make_shared<Module>(); std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h index 90a80d51b..4d7d5bb7c 100644 --- a/src/core/hle/service/apm/apm.h +++ b/src/core/hle/service/apm/apm.h @@ -15,8 +15,8 @@ enum class PerformanceMode : u8 { class Module final { public: - Module() = default; - ~Module() = default; + Module(); + ~Module(); }; /// Registers all AM services with the specified service manager. diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index 4cd8132f5..c22bd3859 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp @@ -70,6 +70,8 @@ APM::APM(std::shared_ptr<Module> apm, const char* name) RegisterHandlers(functions); } +APM::~APM() = default; + void APM::OpenSession(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -93,6 +95,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { RegisterHandlers(functions); } +APM_Sys::~APM_Sys() = default; + void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index d14264ad7..773541aa4 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h @@ -11,7 +11,7 @@ namespace Service::APM { class APM final : public ServiceFramework<APM> { public: explicit APM(std::shared_ptr<Module> apm, const char* name); - ~APM() = default; + ~APM() override; private: void OpenSession(Kernel::HLERequestContext& ctx); @@ -22,6 +22,7 @@ private: class APM_Sys final : public ServiceFramework<APM_Sys> { public: explicit APM_Sys(); + ~APM_Sys() override; private: void GetPerformanceEvent(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 37c3fdcac..b6b71f966 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp @@ -42,4 +42,6 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} { RegisterHandlers(functions); } +AudCtl::~AudCtl() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h index ed837bdf2..9d2d9e83b 100644 --- a/src/core/hle/service/audio/audctl.h +++ b/src/core/hle/service/audio/audctl.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudCtl final : public ServiceFramework<AudCtl> { public: explicit AudCtl(); + ~AudCtl() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp index b08c21a20..8fff3e4b4 100644 --- a/src/core/hle/service/audio/auddbg.cpp +++ b/src/core/hle/service/audio/auddbg.cpp @@ -17,4 +17,6 @@ AudDbg::AudDbg(const char* name) : ServiceFramework{name} { RegisterHandlers(functions); } +AudDbg::~AudDbg() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h index a2f540b75..6689f4759 100644 --- a/src/core/hle/service/audio/auddbg.h +++ b/src/core/hle/service/audio/auddbg.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudDbg final : public ServiceFramework<AudDbg> { public: explicit AudDbg(const char* name); + ~AudDbg() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp index a70d5bca4..ddd12f35e 100644 --- a/src/core/hle/service/audio/audin_a.cpp +++ b/src/core/hle/service/audio/audin_a.cpp @@ -19,4 +19,6 @@ AudInA::AudInA() : ServiceFramework{"audin:a"} { RegisterHandlers(functions); } +AudInA::~AudInA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h index e4c75510f..e7623bc29 100644 --- a/src/core/hle/service/audio/audin_a.h +++ b/src/core/hle/service/audio/audin_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudInA final : public ServiceFramework<AudInA> { public: explicit AudInA(); + ~AudInA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index cbc49e55e..657010312 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -41,4 +41,6 @@ AudInU::AudInU() : ServiceFramework("audin:u") { RegisterHandlers(functions); } +AudInU::~AudInU() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h index 2e65efb5b..0538b9560 100644 --- a/src/core/hle/service/audio/audin_u.h +++ b/src/core/hle/service/audio/audin_u.h @@ -15,7 +15,7 @@ namespace Service::Audio { class AudInU final : public ServiceFramework<AudInU> { public: explicit AudInU(); - ~AudInU() = default; + ~AudInU() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 6b5e15633..128df7db5 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp @@ -15,6 +15,7 @@ #include "core/hle/service/audio/audren_u.h" #include "core/hle/service/audio/codecctl.h" #include "core/hle/service/audio/hwopus.h" +#include "core/hle/service/service.h" namespace Service::Audio { diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h index 95e5691f7..f5bd3bf5f 100644 --- a/src/core/hle/service/audio/audio.h +++ b/src/core/hle/service/audio/audio.h @@ -4,7 +4,9 @@ #pragma once -#include "core/hle/service/service.h" +namespace Service::SM { +class ServiceManager; +} namespace Service::Audio { diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp index bf8d40157..85febbca3 100644 --- a/src/core/hle/service/audio/audout_a.cpp +++ b/src/core/hle/service/audio/audout_a.cpp @@ -21,4 +21,6 @@ AudOutA::AudOutA() : ServiceFramework{"audout:a"} { RegisterHandlers(functions); } +AudOutA::~AudOutA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h index 91a069152..d65b66e8e 100644 --- a/src/core/hle/service/audio/audout_a.h +++ b/src/core/hle/service/audio/audout_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudOutA final : public ServiceFramework<AudOutA> { public: explicit AudOutA(); + ~AudOutA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 5f370bbdf..ff1edefbb 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -3,15 +3,20 @@ // Refer to the license.txt file included. #include <array> +#include <cstring> #include <vector> +#include "audio_core/audio_out.h" #include "audio_core/codec.h" +#include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/swap.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/audout_u.h" +#include "core/memory.h" namespace Service::Audio { @@ -25,6 +30,18 @@ enum { constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; constexpr int DefaultSampleRate{48000}; +struct AudoutParams { + s32_le sample_rate; + u16_le channel_count; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); + +enum class AudioState : u32 { + Started, + Stopped, +}; + class IAudioOut final : public ServiceFramework<IAudioOut> { public: IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) @@ -173,7 +190,7 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { ctx.WriteBuffer(DefaultDevice); - IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(1); // Amount of audio devices @@ -218,4 +235,6 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") { audio_core = std::make_unique<AudioCore::AudioOut>(); } +AudOutU::~AudOutU() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index fd491f65d..dcaf64708 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -4,33 +4,24 @@ #pragma once -#include "audio_core/audio_out.h" #include "core/hle/service/service.h" +namespace AudioCore { +class AudioOut; +} + namespace Kernel { class HLERequestContext; } namespace Service::Audio { -struct AudoutParams { - s32_le sample_rate; - u16_le channel_count; - INSERT_PADDING_BYTES(2); -}; -static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); - -enum class AudioState : u32 { - Started, - Stopped, -}; - class IAudioOut; class AudOutU final : public ServiceFramework<AudOutU> { public: AudOutU(); - ~AudOutU() = default; + ~AudOutU() override; private: std::shared_ptr<IAudioOut> audio_out_interface; diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp index 016eabf53..ce1bfb48d 100644 --- a/src/core/hle/service/audio/audrec_a.cpp +++ b/src/core/hle/service/audio/audrec_a.cpp @@ -17,4 +17,6 @@ AudRecA::AudRecA() : ServiceFramework{"audrec:a"} { RegisterHandlers(functions); } +AudRecA::~AudRecA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h index 9685047f2..384d24c69 100644 --- a/src/core/hle/service/audio/audrec_a.h +++ b/src/core/hle/service/audio/audrec_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudRecA final : public ServiceFramework<AudRecA> { public: explicit AudRecA(); + ~AudRecA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp index 74909415c..34974afa9 100644 --- a/src/core/hle/service/audio/audrec_u.cpp +++ b/src/core/hle/service/audio/audrec_u.cpp @@ -36,4 +36,6 @@ AudRecU::AudRecU() : ServiceFramework("audrec:u") { RegisterHandlers(functions); } +AudRecU::~AudRecU() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h index 46daa33a4..ca3d638e8 100644 --- a/src/core/hle/service/audio/audrec_u.h +++ b/src/core/hle/service/audio/audrec_u.h @@ -15,7 +15,7 @@ namespace Service::Audio { class AudRecU final : public ServiceFramework<AudRecU> { public: explicit AudRecU(); - ~AudRecU() = default; + ~AudRecU() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp index 616ff3dc4..edb66d985 100644 --- a/src/core/hle/service/audio/audren_a.cpp +++ b/src/core/hle/service/audio/audren_a.cpp @@ -23,4 +23,6 @@ AudRenA::AudRenA() : ServiceFramework{"audren:a"} { RegisterHandlers(functions); } +AudRenA::~AudRenA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h index 5ecf2e184..81fef0ffe 100644 --- a/src/core/hle/service/audio/audren_a.h +++ b/src/core/hle/service/audio/audren_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudRenA final : public ServiceFramework<AudRenA> { public: explicit AudRenA(); + ~AudRenA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 016db7c82..06ac6372d 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -2,12 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <array> +#include <memory> +#include "audio_core/audio_renderer.h" #include "common/alignment.h" +#include "common/common_funcs.h" #include "common/logging/log.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" @@ -135,7 +137,7 @@ private: constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; ctx.WriteBuffer(audio_interface); - IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(1); } @@ -149,7 +151,7 @@ private: auto file_buffer = ctx.ReadBuffer(); auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -160,7 +162,7 @@ private: constexpr std::array<char, 12> audio_interface{{"AudioDevice"}}; ctx.WriteBuffer(audio_interface); - IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(1); } @@ -198,6 +200,8 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { RegisterHandlers(functions); } +AudRenU::~AudRenU() = default; + void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 8600ac6e4..c6bc3a90a 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -4,7 +4,6 @@ #pragma once -#include "audio_core/audio_renderer.h" #include "core/hle/service/service.h" namespace Kernel { @@ -16,7 +15,7 @@ namespace Service::Audio { class AudRenU final : public ServiceFramework<AudRenU> { public: explicit AudRenU(); - ~AudRenU() = default; + ~AudRenU() override; private: void OpenAudioRenderer(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp index 212c8d448..c6864146d 100644 --- a/src/core/hle/service/audio/codecctl.cpp +++ b/src/core/hle/service/audio/codecctl.cpp @@ -28,4 +28,6 @@ CodecCtl::CodecCtl() : ServiceFramework("codecctl") { RegisterHandlers(functions); } +CodecCtl::~CodecCtl() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h index d9ac29b67..2fe75b6e2 100644 --- a/src/core/hle/service/audio/codecctl.h +++ b/src/core/hle/service/audio/codecctl.h @@ -15,7 +15,7 @@ namespace Service::Audio { class CodecCtl final : public ServiceFramework<CodecCtl> { public: explicit CodecCtl(); - ~CodecCtl() = default; + ~CodecCtl() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 371cd4997..fc6067e59 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -3,7 +3,12 @@ // Refer to the license.txt file included. #include <cstring> +#include <memory> +#include <vector> + #include <opus.h> + +#include "common/common_funcs.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -56,7 +61,7 @@ private: bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, std::vector<opus_int16>& output) { - size_t raw_output_sz = output.size() * sizeof(opus_int16); + std::size_t raw_output_sz = output.size() * sizeof(opus_int16); if (sizeof(OpusHeader) > input.size()) return false; OpusHeader hdr{}; @@ -91,7 +96,7 @@ private: u32 channel_count; }; -static size_t WorkerBufferSize(u32 channel_count) { +static std::size_t WorkerBufferSize(u32 channel_count) { ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); return opus_decoder_get_size(static_cast<int>(channel_count)); } @@ -124,7 +129,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { "Invalid sample rate"); ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); - size_t worker_sz = WorkerBufferSize(channel_count); + std::size_t worker_sz = WorkerBufferSize(channel_count); ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large"); std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ static_cast<OpusDecoder*>(operator new(worker_sz))}; @@ -151,4 +156,6 @@ HwOpus::HwOpus() : ServiceFramework("hwopus") { RegisterHandlers(functions); } +HwOpus::~HwOpus() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h index 5258d59f3..602ede8ba 100644 --- a/src/core/hle/service/audio/hwopus.h +++ b/src/core/hle/service/audio/hwopus.h @@ -11,7 +11,7 @@ namespace Service::Audio { class HwOpus final : public ServiceFramework<HwOpus> { public: explicit HwOpus(); - ~HwOpus() = default; + ~HwOpus() override; private: void OpenOpusDecoder(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 20ce692dc..179aa4949 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp @@ -13,4 +13,6 @@ BCAT::BCAT(std::shared_ptr<Module> module, const char* name) }; RegisterHandlers(functions); } + +BCAT::~BCAT() = default; } // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h index 6632996a0..802bd689a 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h @@ -11,6 +11,7 @@ namespace Service::BCAT { class BCAT final : public Module::Interface { public: explicit BCAT(std::shared_ptr<Module> module, const char* name); + ~BCAT() override; }; } // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 35e024c3d..6e7b795fb 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -42,6 +42,8 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h index 62f6f5f9d..f0d63cab0 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateBcatService(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 299b9474f..b436ce4e6 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -13,6 +13,8 @@ namespace Service::Fatal { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); u32 error_code = rp.Pop<u32>(); diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h index ca607e236..4d9a5be52 100644 --- a/src/core/hle/service/fatal/fatal.h +++ b/src/core/hle/service/fatal/fatal.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx); void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp index a5254ac2f..9e5f872ff 100644 --- a/src/core/hle/service/fatal/fatal_p.cpp +++ b/src/core/hle/service/fatal/fatal_p.cpp @@ -9,4 +9,6 @@ namespace Service::Fatal { Fatal_P::Fatal_P(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:p") {} +Fatal_P::~Fatal_P() = default; + } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h index bfd8c8b74..6e9c5979f 100644 --- a/src/core/hle/service/fatal/fatal_p.h +++ b/src/core/hle/service/fatal/fatal_p.h @@ -11,6 +11,7 @@ namespace Service::Fatal { class Fatal_P final : public Module::Interface { public: explicit Fatal_P(std::shared_ptr<Module> module); + ~Fatal_P() override; }; } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp index f0631329e..befc307cf 100644 --- a/src/core/hle/service/fatal/fatal_u.cpp +++ b/src/core/hle/service/fatal/fatal_u.cpp @@ -15,4 +15,6 @@ Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(m RegisterHandlers(functions); } +Fatal_U::~Fatal_U() = default; + } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h index 9b1a9e97a..72cb6d076 100644 --- a/src/core/hle/service/fatal/fatal_u.h +++ b/src/core/hle/service/fatal/fatal_u.h @@ -11,6 +11,7 @@ namespace Service::Fatal { class Fatal_U final : public Module::Interface { public: explicit Fatal_U(std::shared_ptr<Module> module); + ~Fatal_U() override; }; } // namespace Service::Fatal diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 881c39e31..d349ee686 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -10,6 +10,7 @@ #include "core/file_sys/bis_factory.h" #include "core/file_sys/errors.h" #include "core/file_sys/mode.h" +#include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" @@ -39,6 +40,8 @@ static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_) : backing(std::move(backing_)) {} +VfsDirectoryServiceWrapper::~VfsDirectoryServiceWrapper() = default; + std::string VfsDirectoryServiceWrapper::GetName() const { return backing->GetName(); } @@ -60,17 +63,20 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { std::string path(FileUtil::SanitizePath(path_)); - auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (path.empty()) { // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... return RESULT_SUCCESS; } - if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) + + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) { return FileSys::ERROR_PATH_NOT_FOUND; + } if (!dir->DeleteFile(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this return ResultCode(-1); } + return RESULT_SUCCESS; } @@ -191,7 +197,7 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s auto dir = GetDirectoryRelativeWrapped(backing, path); if (dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return FileSys::ERROR_PATH_NOT_FOUND; } return MakeResult(dir); } @@ -304,6 +310,12 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() { return sdmc_factory->Open(); } +std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { + return std::make_shared<FileSys::RegisteredCacheUnion>( + std::vector<std::shared_ptr<FileSys::RegisteredCache>>{ + GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); +} + std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() { LOG_TRACE(Service_FS, "Opening System NAND Contents"); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 9ba0e2eab..aab65a2b8 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -13,6 +13,7 @@ namespace FileSys { class BISFactory; class RegisteredCache; +class RegisteredCacheUnion; class RomFSFactory; class SaveDataFactory; class SDMCFactory; @@ -45,6 +46,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct); ResultVal<FileSys::VirtualDir> OpenSDMC(); +std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); + std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents(); std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents(); std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents(); @@ -61,6 +64,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::Virtu class VfsDirectoryServiceWrapper { public: explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing); + ~VfsDirectoryServiceWrapper(); /** * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp index 0ab9c2606..fb487d5bc 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.cpp +++ b/src/core/hle/service/filesystem/fsp_ldr.cpp @@ -19,4 +19,6 @@ FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} { RegisterHandlers(functions); } +FSP_LDR::~FSP_LDR() = default; + } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h index fa8e11b4c..8210b7729 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.h +++ b/src/core/hle/service/filesystem/fsp_ldr.h @@ -11,6 +11,7 @@ namespace Service::FileSystem { class FSP_LDR final : public ServiceFramework<FSP_LDR> { public: explicit FSP_LDR(); + ~FSP_LDR() override; }; } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp index 32b0ae454..378201610 100644 --- a/src/core/hle/service/filesystem/fsp_pr.cpp +++ b/src/core/hle/service/filesystem/fsp_pr.cpp @@ -20,4 +20,6 @@ FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} { RegisterHandlers(functions); } +FSP_PR::~FSP_PR() = default; + } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h index 62edcd08a..556ae5ce9 100644 --- a/src/core/hle/service/filesystem/fsp_pr.h +++ b/src/core/hle/service/filesystem/fsp_pr.h @@ -11,6 +11,7 @@ namespace Service::FileSystem { class FSP_PR final : public ServiceFramework<FSP_PR> { public: explicit FSP_PR(); + ~FSP_PR() override; }; } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 5759299fe..cabaf5a55 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -26,6 +26,17 @@ namespace Service::FileSystem { +enum class FileSystemType : u8 { + Invalid0 = 0, + Invalid1 = 1, + Logo = 2, + ContentControl = 3, + ContentManual = 4, + ContentMeta = 5, + ContentData = 6, + ApplicationPackage = 7, +}; + class IStorage final : public ServiceFramework<IStorage> { public: explicit IStorage(FileSys::VirtualFile backend_) @@ -420,7 +431,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {0, nullptr, "MountContent"}, {1, &FSP_SRV::Initialize, "Initialize"}, {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, - {7, nullptr, "OpenFileSystemWithPatch"}, + {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, {8, nullptr, "OpenFileSystemWithId"}, {9, nullptr, "OpenDataFileSystemByApplicationId"}, {11, nullptr, "OpenBisFileSystem"}, @@ -444,7 +455,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {34, nullptr, "GetCacheStorageSize"}, {51, &FSP_SRV::MountSaveData, "MountSaveData"}, {52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"}, - {53, nullptr, "OpenReadOnlySaveDataFileSystem"}, + {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, {58, nullptr, "ReadSaveDataFileSystemExtraData"}, {59, nullptr, "WriteSaveDataFileSystemExtraData"}, @@ -509,6 +520,8 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { RegisterHandlers(functions); } +FSP_SRV::~FSP_SRV() = default; + void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); @@ -516,6 +529,16 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto type = rp.PopRaw<FileSystemType>(); + const auto title_id = rp.PopRaw<u64>(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 0}; + rb.Push(ResultCode(-1)); +} + void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called"); @@ -563,6 +586,11 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); } +void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); + MountSaveData(ctx); +} + void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index f073ac523..4aa0358cb 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -16,13 +16,15 @@ namespace Service::FileSystem { class FSP_SRV final : public ServiceFramework<FSP_SRV> { public: explicit FSP_SRV(); - ~FSP_SRV() = default; + ~FSP_SRV() override; private: void Initialize(Kernel::HLERequestContext& ctx); + void OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx); void MountSdCard(Kernel::HLERequestContext& ctx); void CreateSaveData(Kernel::HLERequestContext& ctx); void MountSaveData(Kernel::HLERequestContext& ctx); + void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index f2b0e509a..d9225d624 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -118,6 +118,8 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager); diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index c1b36518a..e762840cb 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateFriendService(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 27c6a09e2..5a6840af5 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -16,4 +16,6 @@ Friend::Friend(std::shared_ptr<Module> module, const char* name) RegisterHandlers(functions); } +Friend::~Friend() = default; + } // namespace Service::Friend diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h index 89dae8471..1963def39 100644 --- a/src/core/hle/service/friend/interface.h +++ b/src/core/hle/service/friend/interface.h @@ -11,6 +11,7 @@ namespace Service::Friend { class Friend final : public Module::Interface { public: explicit Friend(std::shared_ptr<Module> module, const char* name); + ~Friend() override; }; } // namespace Service::Friend diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 0d31abe8b..7c6b0a4e6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <atomic> #include "common/logging/log.h" #include "core/core.h" #include "core/core_timing.h" @@ -78,7 +77,7 @@ private: SharedMemory mem{}; std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory)); - if (is_device_reload_pending.exchange(false)) + if (Settings::values.is_device_reload_pending.exchange(false)) LoadInputDevices(); // Set up controllers as neon red+blue Joy-Con attached to console @@ -90,7 +89,7 @@ private: controller_header.left_color_body = JOYCON_BODY_NEON_BLUE; controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE; - for (size_t controller = 0; controller < mem.controllers.size(); controller++) { + for (std::size_t controller = 0; controller < mem.controllers.size(); controller++) { for (auto& layout : mem.controllers[controller].layouts) { layout.header.num_entries = HID_NUM_ENTRIES; layout.header.max_entry_index = HID_NUM_ENTRIES - 1; @@ -267,7 +266,6 @@ private: CoreTiming::EventType* pad_update_event; // Stored input state info - std::atomic<bool> is_device_reload_pending{true}; std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> buttons; std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; @@ -315,7 +313,7 @@ public: {64, nullptr, "DeactivateJoySixAxisSensor"}, {65, nullptr, "GetJoySixAxisSensorLifoHandle"}, {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, - {67, nullptr, "StopSixAxisSensor"}, + {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, {68, nullptr, "IsSixAxisSensorFusionEnabled"}, {69, nullptr, "EnableSixAxisSensorFusion"}, {70, nullptr, "SetSixAxisSensorFusionParameters"}, @@ -331,7 +329,7 @@ public: {80, nullptr, "GetGyroscopeZeroDriftMode"}, {81, nullptr, "ResetGyroscopeZeroDriftMode"}, {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, - {91, nullptr, "ActivateGesture"}, + {91, &Hid::ActivateGesture, "ActivateGesture"}, {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, @@ -340,7 +338,7 @@ public: {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, {107, &Hid::DisconnectNpad, "DisconnectNpad"}, {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, - {109, nullptr, "ActivateNpadWithRevision"}, + {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, @@ -366,8 +364,8 @@ public: {208, nullptr, "GetActualVibrationGcErmCommand"}, {209, nullptr, "BeginPermitVibrationSession"}, {210, nullptr, "EndPermitVibrationSession"}, - {300, nullptr, "ActivateConsoleSixAxisSensor"}, - {301, nullptr, "StartConsoleSixAxisSensor"}, + {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, + {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, {302, nullptr, "StopConsoleSixAxisSensor"}, {303, nullptr, "ActivateSevenSixAxisSensor"}, {304, nullptr, "StartSevenSixAxisSensor"}, @@ -581,6 +579,36 @@ private: rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_HID, "(STUBBED) called"); } + + void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void ActivateGesture(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + + void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } }; class HidDbg final : public ServiceFramework<HidDbg> { @@ -797,7 +825,9 @@ public: } }; -void ReloadInputDevices() {} +void ReloadInputDevices() { + Settings::values.is_device_reload_pending.store(true); +} void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<Hid>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index aaf311912..e587ad0d8 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -33,6 +33,8 @@ IRS::IRS() : ServiceFramework{"irs"} { RegisterHandlers(functions); } +IRS::~IRS() = default; + IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { // clang-format off static const FunctionInfo functions[] = { @@ -46,4 +48,6 @@ IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { RegisterHandlers(functions); } +IRS_SYS::~IRS_SYS() = default; + } // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index a8be701c7..6fb16b45d 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -11,11 +11,13 @@ namespace Service::HID { class IRS final : public ServiceFramework<IRS> { public: explicit IRS(); + ~IRS() override; }; class IRS_SYS final : public ServiceFramework<IRS_SYS> { public: explicit IRS_SYS(); + ~IRS_SYS() override; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp index 49f733f60..c8e9125f6 100644 --- a/src/core/hle/service/hid/xcd.cpp +++ b/src/core/hle/service/hid/xcd.cpp @@ -34,4 +34,6 @@ XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} { RegisterHandlers(functions); } +XCD_SYS::~XCD_SYS() = default; + } // namespace Service::HID diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h index 232a044df..fd506d303 100644 --- a/src/core/hle/service/hid/xcd.h +++ b/src/core/hle/service/hid/xcd.h @@ -11,6 +11,7 @@ namespace Service::HID { class XCD_SYS final : public ServiceFramework<XCD_SYS> { public: explicit XCD_SYS(); + ~XCD_SYS() override; }; } // namespace Service::HID diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 098da2a41..c89157a4d 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -99,7 +99,7 @@ private: std::string thread; while (addr < end_addr) { const Field field{static_cast<Field>(Memory::Read8(addr++))}; - const size_t length{Memory::Read8(addr++)}; + const std::size_t length{Memory::Read8(addr++)}; if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { ++addr; diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 4f7543af5..f8d2127d9 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -14,6 +14,8 @@ namespace Service::NFP { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + class IUser final : public ServiceFramework<IUser> { public: IUser() : ServiceFramework("IUser") { diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 0cd7be3d5..77df343c4 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateUserInterface(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index b608fe693..784a87c1b 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -14,4 +14,6 @@ NFP_User::NFP_User(std::shared_ptr<Module> module) RegisterHandlers(functions); } +NFP_User::~NFP_User() = default; + } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 700043114..65d9aaf48 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h @@ -11,6 +11,7 @@ namespace Service::NFP { class NFP_User final : public Module::Interface { public: explicit NFP_User(std::shared_ptr<Module> module); + ~NFP_User() override; }; } // namespace Service::NFP diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index ed4f5f539..10611ed6a 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -31,7 +31,7 @@ public: {1, &IRequest::GetResult, "GetResult"}, {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"}, {3, &IRequest::Cancel, "Cancel"}, - {4, nullptr, "Submit"}, + {4, &IRequest::Submit, "Submit"}, {5, nullptr, "SetRequirement"}, {6, nullptr, "SetRequirementPreset"}, {8, nullptr, "SetPriority"}, @@ -61,6 +61,12 @@ public: } private: + void Submit(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + void GetRequestState(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; @@ -114,10 +120,11 @@ public: private: void GetClientId(Kernel::HLERequestContext& ctx) { + static constexpr u32 client_id = 1; LOG_WARNING(Service_NIFM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push<u64>(0); + rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid } void CreateScanRequest(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -141,10 +148,16 @@ private: rb.Push(RESULT_SUCCESS); } void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); + u128 uuid{}; + auto buffer = ctx.ReadBuffer(); + std::memcpy(&uuid, buffer.data() + 8, sizeof(u128)); + + IPC::ResponseBuilder rb{ctx, 6, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<INetworkProfile>(); + rb.PushRaw<u128>(uuid); LOG_DEBUG(Service_NIFM, "called"); } diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index bd05b0a70..c1737defa 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -2,6 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <chrono> +#include <ctime> +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" #include "core/hle/service/nim/nim.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" @@ -100,19 +104,111 @@ public: } }; +class IEnsureNetworkClockAvailabilityService final + : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { +public: + IEnsureNetworkClockAvailabilityService() + : ServiceFramework("IEnsureNetworkClockAvailabilityService") { + static const FunctionInfo functions[] = { + {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, + {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, + "GetFinishNotificationEvent"}, + {2, &IEnsureNetworkClockAvailabilityService::GetResult, "GetResult"}, + {3, &IEnsureNetworkClockAvailabilityService::Cancel, "Cancel"}, + {4, &IEnsureNetworkClockAvailabilityService::IsProcessing, "IsProcessing"}, + {5, &IEnsureNetworkClockAvailabilityService::GetServerTime, "GetServerTime"}, + }; + RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + finished_event = + Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "IEnsureNetworkClockAvailabilityService:FinishEvent"); + } + +private: + Kernel::SharedPtr<Kernel::Event> finished_event; + + void StartTask(Kernel::HLERequestContext& ctx) { + // No need to connect to the internet, just finish the task straight away. + finished_event->Signal(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_NIM, "called"); + } + + void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(finished_event); + LOG_DEBUG(Service_NIM, "called"); + } + + void GetResult(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_NIM, "called"); + } + + void Cancel(Kernel::HLERequestContext& ctx) { + finished_event->Clear(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_NIM, "called"); + } + + void IsProcessing(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u32>(0); // We instantly process the request + LOG_DEBUG(Service_NIM, "called"); + } + + void GetServerTime(Kernel::HLERequestContext& ctx) { + const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()) + .count()}; + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<s64>(server_time); + LOG_DEBUG(Service_NIM, "called"); + } +}; + class NTC final : public ServiceFramework<NTC> { public: explicit NTC() : ServiceFramework{"ntc"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "OpenEnsureNetworkClockAvailabilityService"}, - {100, nullptr, "SuspendAutonomicTimeCorrection"}, - {101, nullptr, "ResumeAutonomicTimeCorrection"}, + {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, + {100, &NTC::SuspendAutonomicTimeCorrection, "SuspendAutonomicTimeCorrection"}, + {101, &NTC::ResumeAutonomicTimeCorrection, "ResumeAutonomicTimeCorrection"}, }; // clang-format on RegisterHandlers(functions); } + +private: + void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); + LOG_DEBUG(Service_NIM, "called"); + } + + // TODO(ogniK): Do we need these? + void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_NIM, "(STUBBED) called"); + } + + void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_NIM, "(STUBBED) called"); + } }; void InstallInterfaces(SM::ServiceManager& sm) { diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 51638793d..1069d103f 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -2,12 +2,30 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> +#include <cstring> +#include <vector> + +#include <FontChineseSimplified.h> +#include <FontChineseTraditional.h> +#include <FontExtendedChineseSimplified.h> +#include <FontKorean.h> +#include <FontNintendoExtended.h> +#include <FontStandard.h> + +#include "common/assert.h" #include "common/common_paths.h" +#include "common/common_types.h" #include "common/file_util.h" +#include "common/logging/log.h" +#include "common/swap.h" #include "core/core.h" -#include "core/file_sys/bis_factory.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/pl_u.h" @@ -26,49 +44,41 @@ struct FontRegion { u32 size; }; -static constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ +constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), - std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf")}; + std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"), +}; -static constexpr std::array<const char*, 7> SHARED_FONTS_TTF{"FontStandard.ttf", - "FontChineseSimplified.ttf", - "FontExtendedChineseSimplified.ttf", - "FontChineseTraditional.ttf", - "FontKorean.ttf", - "FontNintendoExtended.ttf", - "FontNintendoExtended2.ttf"}; +constexpr std::array<const char*, 7> SHARED_FONTS_TTF{ + "FontStandard.ttf", + "FontChineseSimplified.ttf", + "FontExtendedChineseSimplified.ttf", + "FontChineseTraditional.ttf", + "FontKorean.ttf", + "FontNintendoExtended.ttf", + "FontNintendoExtended2.ttf", +}; // The below data is specific to shared font data dumped from Switch on f/w 2.2 // Virtual address and offsets/sizes likely will vary by dump -static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; -static constexpr u32 EXPECTED_RESULT{ - 0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be -static constexpr u32 EXPECTED_MAGIC{ - 0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be -static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; -static constexpr FontRegion EMPTY_REGION{0, 0}; -std::vector<FontRegion> - SHARED_FONT_REGIONS{}; // Automatically populated based on shared_fonts dump or system archives - -const FontRegion& GetSharedFontRegion(size_t index) { - if (index >= SHARED_FONT_REGIONS.size() || SHARED_FONT_REGIONS.empty()) { - // No font fallback - return EMPTY_REGION; - } - return SHARED_FONT_REGIONS.at(index); -} +constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; +constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be +constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be +constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; +constexpr FontRegion EMPTY_REGION{0, 0}; enum class LoadState : u32 { Loading = 0, Done = 1, }; -void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, size_t& offset) { +static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, + std::size_t& offset) { ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); @@ -85,7 +95,7 @@ void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, s } static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& output, - size_t& offset) { + std::size_t& offset) { ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT; std::memcpy(output.data() + offset, &EXPECTED_RESULT, sizeof(u32)); // Magic header @@ -95,28 +105,52 @@ static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& out offset += input.size() + (sizeof(u32) * 2); } +// Helper function to make BuildSharedFontsRawRegions a bit nicer static u32 GetU32Swapped(const u8* data) { u32 value; std::memcpy(&value, data, sizeof(value)); - return Common::swap32(value); // Helper function to make BuildSharedFontsRawRegions a bit nicer + return Common::swap32(value); } -void BuildSharedFontsRawRegions(const std::vector<u8>& input) { - unsigned cur_offset = 0; // As we can derive the xor key we can just populate the offsets based - // on the shared memory dump - for (size_t i = 0; i < SHARED_FONTS.size(); i++) { - // Out of shared fonts/Invalid font - if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) - break; - const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ - EXPECTED_MAGIC; // Derive key withing inverse xor - const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY; - SHARED_FONT_REGIONS.push_back(FontRegion{cur_offset + 8, SIZE}); - cur_offset += SIZE + 8; +struct PL_U::Impl { + const FontRegion& GetSharedFontRegion(std::size_t index) const { + if (index >= shared_font_regions.size() || shared_font_regions.empty()) { + // No font fallback + return EMPTY_REGION; + } + return shared_font_regions.at(index); } -} -PL_U::PL_U() : ServiceFramework("pl:u") { + void BuildSharedFontsRawRegions(const std::vector<u8>& input) { + // As we can derive the xor key we can just populate the offsets + // based on the shared memory dump + unsigned cur_offset = 0; + + for (std::size_t i = 0; i < SHARED_FONTS.size(); i++) { + // Out of shared fonts/invalid font + if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) { + break; + } + + // Derive key withing inverse xor + const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ EXPECTED_MAGIC; + const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY; + shared_font_regions.push_back(FontRegion{cur_offset + 8, SIZE}); + cur_offset += SIZE + 8; + } + } + + /// Handle to shared memory region designated for a shared font + Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; + + /// Backing memory for the shared font data + std::shared_ptr<std::vector<u8>> shared_font; + + // Automatically populated based on shared_fonts dump or system archives. + std::vector<FontRegion> shared_font_regions; +}; + +PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { static const FunctionInfo functions[] = { {0, &PL_U::RequestLoad, "RequestLoad"}, {1, &PL_U::GetLoadState, "GetLoadState"}, @@ -128,11 +162,11 @@ PL_U::PL_U() : ServiceFramework("pl:u") { RegisterHandlers(functions); // Attempt to load shared font data from disk const auto nand = FileSystem::GetSystemNANDContents(); - size_t offset = 0; + std::size_t offset = 0; // Rebuild shared fonts from data ncas if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), FileSys::ContentRecordType::Data)) { - shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); + impl->shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); for (auto font : SHARED_FONTS) { const auto nca = nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); @@ -168,12 +202,12 @@ PL_U::PL_U() : ServiceFramework("pl:u") { static_cast<u32>(offset + 8), static_cast<u32>((font_data_u32.size() * sizeof(u32)) - 8)}; // Font offset and size do not account for the header - DecryptSharedFont(font_data_u32, *shared_font, offset); - SHARED_FONT_REGIONS.push_back(region); + DecryptSharedFont(font_data_u32, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); } } else { - shared_font = std::make_shared<std::vector<u8>>( + impl->shared_font = std::make_shared<std::vector<u8>>( SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); @@ -197,8 +231,8 @@ PL_U::PL_U() : ServiceFramework("pl:u") { static_cast<u32>(offset + 8), static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account // for the header - EncryptSharedFont(ttf_bytes, *shared_font, offset); - SHARED_FONT_REGIONS.push_back(region); + EncryptSharedFont(ttf_bytes, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); } else { LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf); } @@ -213,14 +247,35 @@ PL_U::PL_U() : ServiceFramework("pl:u") { if (file.IsOpen()) { // Read shared font data ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); - file.ReadBytes(shared_font->data(), shared_font->size()); - BuildSharedFontsRawRegions(*shared_font); + file.ReadBytes(impl->shared_font->data(), impl->shared_font->size()); + impl->BuildSharedFontsRawRegions(*impl->shared_font); } else { - LOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath); + LOG_WARNING(Service_NS, + "Shared Font file missing. Loading open source replacement from memory"); + + // clang-format off + const std::vector<std::vector<u8>> open_source_shared_fonts_ttf = { + {std::begin(FontChineseSimplified), std::end(FontChineseSimplified)}, + {std::begin(FontChineseTraditional), std::end(FontChineseTraditional)}, + {std::begin(FontExtendedChineseSimplified), std::end(FontExtendedChineseSimplified)}, + {std::begin(FontKorean), std::end(FontKorean)}, + {std::begin(FontNintendoExtended), std::end(FontNintendoExtended)}, + {std::begin(FontStandard), std::end(FontStandard)}, + }; + // clang-format on + + for (const std::vector<u8>& font_ttf : open_source_shared_fonts_ttf) { + const FontRegion region{static_cast<u32>(offset + 8), + static_cast<u32>(font_ttf.size())}; + EncryptSharedFont(font_ttf, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); + } } } } +PL_U::~PL_U() = default; + void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 shared_font_type{rp.Pop<u32>()}; @@ -247,7 +302,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(GetSharedFontRegion(font_id).size); + rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); } void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { @@ -257,17 +312,18 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(GetSharedFontRegion(font_id).offset); + rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); } void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { // Map backing memory for the font data - Core::CurrentProcess()->vm_manager.MapMemoryBlock( - SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared); + Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, + SHARED_FONT_MEM_SIZE, + Kernel::MemoryState::Shared); // Create shared font memory object auto& kernel = Core::System::GetInstance().Kernel(); - shared_font_mem = Kernel::SharedMemory::Create( + impl->shared_font_mem = Kernel::SharedMemory::Create( kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, "PL_U:shared_font_mem"); @@ -275,7 +331,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NS, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(shared_font_mem); + rb.PushCopyObjects(impl->shared_font_mem); } void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { @@ -288,9 +344,9 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { std::vector<u32> font_sizes; // TODO(ogniK): Have actual priority order - for (size_t i = 0; i < SHARED_FONT_REGIONS.size(); i++) { + for (std::size_t i = 0; i < impl->shared_font_regions.size(); i++) { font_codes.push_back(static_cast<u32>(i)); - auto region = GetSharedFontRegion(i); + auto region = impl->GetSharedFontRegion(i); font_offsets.push_back(region.offset); font_sizes.push_back(region.size); } diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index fcc2acab7..253f26a2a 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h @@ -5,7 +5,6 @@ #pragma once #include <memory> -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/service.h" namespace Service::NS { @@ -13,7 +12,7 @@ namespace Service::NS { class PL_U final : public ServiceFramework<PL_U> { public: PL_U(); - ~PL_U() = default; + ~PL_U() override; private: void RequestLoad(Kernel::HLERequestContext& ctx); @@ -23,11 +22,8 @@ private: void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx); - /// Handle to shared memory region designated for a shared font - Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; - - /// Backing memory for the shared font data - std::shared_ptr<std::vector<u8>> shared_font; + struct Impl; + std::unique_ptr<Impl> impl; }; } // namespace Service::NS diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 0b37098e1..92acc57b1 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -13,6 +13,9 @@ namespace Service::Nvidia::Devices { +nvdisp_disp0::nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} +nvdisp_disp0 ::~nvdisp_disp0() = default; + u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6f0697b58..a45086e45 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -17,8 +17,8 @@ class nvmap; class nvdisp_disp0 final : public nvdevice { public: - explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} - ~nvdisp_disp0() = default; + explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev); + ~nvdisp_disp0(); u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 75487c4e8..d8b8037a8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -3,6 +3,8 @@ // Refer to the license.txt file included. #include <cstring> +#include <utility> + #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" @@ -14,6 +16,9 @@ namespace Service::Nvidia::Devices { +nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} +nvhost_as_gpu::~nvhost_as_gpu() = default; + u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); @@ -66,7 +71,7 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& } u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { - size_t num_entries = input.size() / sizeof(IoctlRemapEntry); + std::size_t num_entries = input.size() / sizeof(IoctlRemapEntry); LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 9f8999d9c..eb14b1da8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -6,7 +6,6 @@ #include <memory> #include <unordered_map> -#include <utility> #include <vector> #include "common/common_types.h" #include "common/swap.h" @@ -18,8 +17,8 @@ class nvmap; class nvhost_as_gpu final : public nvdevice { public: - explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} - ~nvhost_as_gpu() override = default; + explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev); + ~nvhost_as_gpu() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 5685eb2be..b39fb9ef9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -11,6 +11,9 @@ namespace Service::Nvidia::Devices { +nvhost_ctrl::nvhost_ctrl() = default; +nvhost_ctrl::~nvhost_ctrl() = default; + u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 6b496e9fe..6d0de2212 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_ctrl final : public nvdevice { public: - nvhost_ctrl() = default; - ~nvhost_ctrl() override = default; + nvhost_ctrl(); + ~nvhost_ctrl() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ae421247d..7a88ae029 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -9,6 +9,9 @@ namespace Service::Nvidia::Devices { +nvhost_ctrl_gpu::nvhost_ctrl_gpu() = default; +nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; + u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index f09113e67..3bbf028ad 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_ctrl_gpu final : public nvdevice { public: - nvhost_ctrl_gpu() = default; - ~nvhost_ctrl_gpu() override = default; + nvhost_ctrl_gpu(); + ~nvhost_ctrl_gpu() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 4cdf7f613..874d5e1c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -8,11 +8,15 @@ #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/memory.h" +#include "video_core/command_processor.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" namespace Service::Nvidia::Devices { +nvhost_gpu::nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} +nvhost_gpu::~nvhost_gpu() = default; + u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); @@ -134,17 +138,16 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags); - ASSERT_MSG(input.size() == - sizeof(IoctlSubmitGpfifo) + params.num_entries * sizeof(IoctlGpfifoEntry), + ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + + params.num_entries * sizeof(Tegra::CommandListHeader), "Incorrect input size"); - std::vector<IoctlGpfifoEntry> entries(params.num_entries); + std::vector<Tegra::CommandListHeader> entries(params.num_entries); std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], - params.num_entries * sizeof(IoctlGpfifoEntry)); - for (auto entry : entries) { - Tegra::GPUVAddr va_addr = entry.Address(); - Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz); - } + params.num_entries * sizeof(Tegra::CommandListHeader)); + + Core::System::GetInstance().GPU().ProcessCommandLists(entries); + params.fence_out.id = 0; params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); @@ -160,14 +163,12 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags); - std::vector<IoctlGpfifoEntry> entries(params.num_entries); + std::vector<Tegra::CommandListHeader> entries(params.num_entries); Memory::ReadBlock(params.address, entries.data(), - params.num_entries * sizeof(IoctlGpfifoEntry)); + params.num_entries * sizeof(Tegra::CommandListHeader)); + + Core::System::GetInstance().GPU().ProcessCommandLists(entries); - for (auto entry : entries) { - Tegra::GPUVAddr va_addr = entry.Address(); - Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz); - } params.fence_out.id = 0; params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 03b7356d0..62beb5c0c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -10,7 +10,6 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -#include "video_core/memory_manager.h" namespace Service::Nvidia::Devices { @@ -21,8 +20,8 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); class nvhost_gpu final : public nvdevice { public: - explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} - ~nvhost_gpu() override = default; + explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev); + ~nvhost_gpu() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; @@ -151,22 +150,6 @@ private: }; static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); - struct IoctlGpfifoEntry { - u32_le entry0; // gpu_va_lo - union { - u32_le entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F) - BitField<0, 8, u32_le> gpu_va_hi; - BitField<8, 2, u32_le> unk1; - BitField<10, 21, u32_le> sz; - BitField<31, 1, u32_le> unk2; - }; - - Tegra::GPUVAddr Address() const { - return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0; - } - }; - static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size"); - struct IoctlSubmitGpfifo { u64_le address; // pointer to gpfifo entry structs u32_le num_entries; // number of fence objects being submitted diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 364619e67..46dbbc37c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -10,6 +10,9 @@ namespace Service::Nvidia::Devices { +nvhost_nvdec::nvhost_nvdec() = default; +nvhost_nvdec::~nvhost_nvdec() = default; + u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 6ad74421b..0e7b284f8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_nvdec final : public nvdevice { public: - nvhost_nvdec() = default; - ~nvhost_nvdec() override = default; + nvhost_nvdec(); + ~nvhost_nvdec() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 51f01077b..c67f934f6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -10,6 +10,9 @@ namespace Service::Nvidia::Devices { +nvhost_nvjpg::nvhost_nvjpg() = default; +nvhost_nvjpg::~nvhost_nvjpg() = default; + u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 2b0eb43ee..89fd5e95e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_nvjpg final : public nvdevice { public: - nvhost_nvjpg() = default; - ~nvhost_nvjpg() override = default; + nvhost_nvjpg(); + ~nvhost_nvjpg() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index fcb488d50..727b9fee4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -10,6 +10,9 @@ namespace Service::Nvidia::Devices { +nvhost_vic::nvhost_vic() = default; +nvhost_vic::~nvhost_vic() = default; + u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index c7d681e52..fc24c3f9c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_vic final : public nvdevice { public: - nvhost_vic() = default; - ~nvhost_vic() override = default; + nvhost_vic(); + ~nvhost_vic() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index e9305bfb3..a2287cc1b 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -11,6 +11,9 @@ namespace Service::Nvidia::Devices { +nvmap::nvmap() = default; +nvmap::~nvmap() = default; + VAddr nvmap::GetObjectAddress(u32 handle) const { auto object = GetObject(handle); ASSERT(object); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index f2eec6409..396230c19 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -16,8 +16,8 @@ namespace Service::Nvidia::Devices { class nvmap final : public nvdevice { public: - nvmap() = default; - ~nvmap() override = default; + nvmap(); + ~nvmap() override; /// Returns the allocated address of an nvmap object given its handle. VAddr GetObjectAddress(u32 handle) const; diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 634ab9196..ac3859353 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -112,4 +112,6 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); } +NVDRV::~NVDRV() = default; + } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 1c3529bb6..d340893c2 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -14,7 +14,7 @@ namespace Service::Nvidia { class NVDRV final : public ServiceFramework<NVDRV> { public: NVDRV(std::shared_ptr<Module> nvdrv, const char* name); - ~NVDRV() = default; + ~NVDRV(); private: void Open(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 2de39822f..6e4b8f2c6 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -45,6 +45,8 @@ Module::Module() { devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(); } +Module::~Module() = default; + u32 Module::Open(const std::string& device_name) { ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", device_name); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 99eb1128a..53564f696 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -30,7 +30,7 @@ static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size"); class Module final { public: Module(); - ~Module() = default; + ~Module(); /// Returns a pointer to one of the available devices, identified by its name. template <typename T> diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index 0e8e21bad..b7b8b7a1b 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -16,6 +16,8 @@ NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { RegisterHandlers(functions); } +NVMEMP::~NVMEMP() = default; + void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h index dfdcabf4a..5a4dfc1f9 100644 --- a/src/core/hle/service/nvdrv/nvmemp.h +++ b/src/core/hle/service/nvdrv/nvmemp.h @@ -11,7 +11,7 @@ namespace Service::Nvidia { class NVMEMP final : public ServiceFramework<NVMEMP> { public: NVMEMP(); - ~NVMEMP() = default; + ~NVMEMP(); private: void Cmd0(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 8d8962276..fd98d541d 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -9,8 +9,7 @@ #include "core/core.h" #include "core/hle/service/nvflinger/buffer_queue.h" -namespace Service { -namespace NVFlinger { +namespace Service::NVFlinger { BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { auto& kernel = Core::System::GetInstance().Kernel(); @@ -18,6 +17,8 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); } +BufferQueue::~BufferQueue() = default; + void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { Buffer buffer{}; buffer.slot = slot; @@ -102,5 +103,4 @@ u32 BufferQueue::Query(QueryType type) { return 0; } -} // namespace NVFlinger -} // namespace Service +} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index db2e17c0c..50b767732 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -15,8 +15,7 @@ namespace CoreTiming { struct EventType; } -namespace Service { -namespace NVFlinger { +namespace Service::NVFlinger { struct IGBPBuffer { u32_le magic; @@ -46,7 +45,7 @@ public: }; BufferQueue(u32 id, u64 layer_id); - ~BufferQueue() = default; + ~BufferQueue(); enum class BufferTransformFlags : u32 { /// No transform flags are set @@ -98,5 +97,4 @@ private: Kernel::SharedPtr<Kernel::Event> buffer_wait_event; }; -} // namespace NVFlinger -} // namespace Service +} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 06040da6f..d47b6f659 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -23,7 +23,7 @@ namespace Service::NVFlinger { -constexpr size_t SCREEN_REFRESH_RATE = 60; +constexpr std::size_t SCREEN_REFRESH_RATE = 60; constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); NVFlinger::NVFlinger() { @@ -160,10 +160,13 @@ void NVFlinger::Compose() { } Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} +Layer::~Layer() = default; Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { auto& kernel = Core::System::GetInstance().Kernel(); vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); } +Display::~Display() = default; + } // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index f7112949f..3dc69e69b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -26,7 +26,7 @@ class BufferQueue; struct Layer { Layer(u64 id, std::shared_ptr<BufferQueue> queue); - ~Layer() = default; + ~Layer(); u64 id; std::shared_ptr<BufferQueue> buffer_queue; @@ -34,7 +34,7 @@ struct Layer { struct Display { Display(u64 id, std::string name); - ~Display() = default; + ~Display(); u64 id; std::string name; diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 6cc3b1992..4fd185f69 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp @@ -142,6 +142,8 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager); diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h index e7d492760..3e449110d 100644 --- a/src/core/hle/service/pctl/module.h +++ b/src/core/hle/service/pctl/module.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateService(Kernel::HLERequestContext& ctx); void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp index de2741d66..af9d1433a 100644 --- a/src/core/hle/service/pctl/pctl.cpp +++ b/src/core/hle/service/pctl/pctl.cpp @@ -14,4 +14,6 @@ PCTL::PCTL(std::shared_ptr<Module> module, const char* name) }; RegisterHandlers(functions); } + +PCTL::~PCTL() = default; } // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h index 8ddf69128..c33ea80b6 100644 --- a/src/core/hle/service/pctl/pctl.h +++ b/src/core/hle/service/pctl/pctl.h @@ -11,6 +11,7 @@ namespace Service::PCTL { class PCTL final : public Module::Interface { public: explicit PCTL(std::shared_ptr<Module> module, const char* name); + ~PCTL() override; }; } // namespace Service::PCTL diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 3c43b8d8c..6a9eccfb5 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -1,36 +1,47 @@ -#include <cinttypes> +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/service/prepo/prepo.h" +#include "core/hle/service/service.h" namespace Service::PlayReport { -PlayReport::PlayReport(const char* name) : ServiceFramework(name) { - static const FunctionInfo functions[] = { - {10100, nullptr, "SaveReport"}, - {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, - {10200, nullptr, "RequestImmediateTransmission"}, - {10300, nullptr, "GetTransmissionStatus"}, - {20100, nullptr, "SaveSystemReport"}, - {20200, nullptr, "SetOperationMode"}, - {20101, nullptr, "SaveSystemReportWithUser"}, - {30100, nullptr, "ClearStorage"}, - {40100, nullptr, "IsUserAgreementCheckEnabled"}, - {40101, nullptr, "SetUserAgreementCheckEnabled"}, - {90100, nullptr, "GetStorageUsage"}, - {90200, nullptr, "GetStatistics"}, - {90201, nullptr, "GetThroughputHistory"}, - {90300, nullptr, "GetLastUploadError"}, - }; - RegisterHandlers(functions); -}; -void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { - // TODO(ogniK): Do we want to add play report? - LOG_WARNING(Service_PREPO, "(STUBBED) called"); +class PlayReport final : public ServiceFramework<PlayReport> { +public: + explicit PlayReport(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {10100, nullptr, "SaveReport"}, + {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, + {10200, nullptr, "RequestImmediateTransmission"}, + {10300, nullptr, "GetTransmissionStatus"}, + {20100, nullptr, "SaveSystemReport"}, + {20200, nullptr, "SetOperationMode"}, + {20101, nullptr, "SaveSystemReportWithUser"}, + {30100, nullptr, "ClearStorage"}, + {40100, nullptr, "IsUserAgreementCheckEnabled"}, + {40101, nullptr, "SetUserAgreementCheckEnabled"}, + {90100, nullptr, "GetStorageUsage"}, + {90200, nullptr, "GetStatistics"}, + {90201, nullptr, "GetThroughputHistory"}, + {90300, nullptr, "GetLastUploadError"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void SaveReportWithUser(Kernel::HLERequestContext& ctx) { + // TODO(ogniK): Do we want to add play report? + LOG_WARNING(Service_PREPO, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } }; void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h index f5a6aba6d..0e7b01331 100644 --- a/src/core/hle/service/prepo/prepo.h +++ b/src/core/hle/service/prepo/prepo.h @@ -4,22 +4,12 @@ #pragma once -#include <memory> -#include <string> -#include "core/hle/kernel/event.h" -#include "core/hle/service/service.h" +namespace Service::SM { +class ServiceManager; +} namespace Service::PlayReport { -class PlayReport final : public ServiceFramework<PlayReport> { -public: - explicit PlayReport(const char* name); - ~PlayReport() = default; - -private: - void SaveReportWithUser(Kernel::HLERequestContext& ctx); -}; - void InstallInterfaces(SM::ServiceManager& service_manager); } // namespace Service::PlayReport diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 8fb907072..62f049660 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -12,6 +12,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/thread.h" @@ -49,6 +50,7 @@ #include "core/hle/service/nim/nim.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/pcie/pcie.h" #include "core/hle/service/pctl/pctl.h" #include "core/hle/service/pcv/pcv.h" @@ -57,7 +59,6 @@ #include "core/hle/service/psc/psc.h" #include "core/hle/service/service.h" #include "core/hle/service/set/settings.h" -#include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sockets/sockets.h" #include "core/hle/service/spl/module.h" @@ -73,8 +74,6 @@ using Kernel::SharedPtr; namespace Service { -std::unordered_map<std::string, SharedPtr<ClientPort>> g_kernel_named_ports; - /** * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. @@ -114,7 +113,7 @@ void ServiceFrameworkBase::InstallAsNamedPort() { std::tie(server_port, client_port) = ServerPort::CreatePortPair(kernel, max_sessions, service_name); server_port->SetHleHandler(shared_from_this()); - AddNamedPort(service_name, std::move(client_port)); + kernel.AddNamedPort(service_name, std::move(client_port)); } Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { @@ -130,9 +129,9 @@ Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { return client_port; } -void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, size_t n) { +void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { handlers.reserve(handlers.size() + n); - for (size_t i = 0; i < n; ++i) { + for (std::size_t i = 0; i < n; ++i) { // Usually this array is sorted by id already, so hint to insert at the end handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]); } @@ -197,11 +196,6 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co //////////////////////////////////////////////////////////////////////////////////////////////////// // Module interface -// TODO(yuriks): Move to kernel -void AddNamedPort(std::string name, SharedPtr<ClientPort> port) { - g_kernel_named_ports.emplace(std::move(name), std::move(port)); -} - /// Initialize ServiceManager void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it @@ -264,7 +258,6 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesys /// Shutdown ServiceManager void Shutdown() { - g_kernel_named_ports.clear(); LOG_DEBUG(Service, "shutdown OK"); } } // namespace Service diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index cd9c74f3d..2fc57a82e 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -6,7 +6,6 @@ #include <cstddef> #include <string> -#include <unordered_map> #include <boost/container/flat_map.hpp> #include "common/common_types.h" #include "core/hle/kernel/hle_ipc.h" @@ -89,7 +88,7 @@ private: ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); ~ServiceFrameworkBase(); - void RegisterHandlersBase(const FunctionInfoBase* functions, size_t n); + void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); /// Identifier string used to connect to the service. @@ -153,7 +152,7 @@ protected: : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} /// Registers handlers in the service. - template <size_t N> + template <std::size_t N> void RegisterHandlers(const FunctionInfo (&functions)[N]) { RegisterHandlers(functions, N); } @@ -162,7 +161,7 @@ protected: * Registers handlers in the service. Usually prefer using the other RegisterHandlers * overload in order to avoid needing to specify the array size. */ - void RegisterHandlers(const FunctionInfo* functions, size_t n) { + void RegisterHandlers(const FunctionInfo* functions, std::size_t n) { RegisterHandlersBase(functions, n); } @@ -187,10 +186,4 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, /// Shutdown ServiceManager void Shutdown(); -/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; - -/// Adds a port to the named port table -void AddNamedPort(std::string name, Kernel::SharedPtr<Kernel::ClientPort> port); - } // namespace Service diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 92b0640e8..9e5af7839 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -32,21 +32,21 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{ LanguageCode::ZH_HANT, }}; -constexpr size_t pre4_0_0_max_entries = 0xF; -constexpr size_t post4_0_0_max_entries = 0x40; +constexpr std::size_t pre4_0_0_max_entries = 0xF; +constexpr std::size_t post4_0_0_max_entries = 0x40; -LanguageCode GetLanguageCodeFromIndex(size_t index) { +LanguageCode GetLanguageCodeFromIndex(std::size_t index) { return available_language_codes.at(index); } -template <size_t size> +template <std::size_t size> static std::array<LanguageCode, size> MakeLanguageCodeSubset() { std::array<LanguageCode, size> arr; std::copy_n(available_language_codes.begin(), size, arr.begin()); return arr; } -static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, size_t max_size) { +static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); if (available_language_codes.size() > max_size) @@ -112,4 +112,6 @@ SET::SET() : ServiceFramework("set") { RegisterHandlers(functions); } +SET::~SET() = default; + } // namespace Service::Set diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 669e740b7..266f13e46 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -28,12 +28,12 @@ enum class LanguageCode : u64 { ZH_HANS = 0x00736E61482D687A, ZH_HANT = 0x00746E61482D687A, }; -LanguageCode GetLanguageCodeFromIndex(size_t idx); +LanguageCode GetLanguageCodeFromIndex(std::size_t idx); class SET final : public ServiceFramework<SET> { public: explicit SET(); - ~SET() = default; + ~SET() override; private: void GetLanguageCode(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp index 7066ef725..5af356d10 100644 --- a/src/core/hle/service/set/set_cal.cpp +++ b/src/core/hle/service/set/set_cal.cpp @@ -44,4 +44,6 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") { RegisterHandlers(functions); } +SET_CAL::~SET_CAL() = default; + } // namespace Service::Set diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h index bb50336aa..583036eac 100644 --- a/src/core/hle/service/set/set_cal.h +++ b/src/core/hle/service/set/set_cal.h @@ -11,7 +11,7 @@ namespace Service::Set { class SET_CAL final : public ServiceFramework<SET_CAL> { public: explicit SET_CAL(); - ~SET_CAL() = default; + ~SET_CAL(); }; } // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp index c9f938716..cac6af86d 100644 --- a/src/core/hle/service/set/set_fd.cpp +++ b/src/core/hle/service/set/set_fd.cpp @@ -20,4 +20,6 @@ SET_FD::SET_FD() : ServiceFramework("set:fd") { RegisterHandlers(functions); } +SET_FD::~SET_FD() = default; + } // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h index dbd850bc7..216e65f1f 100644 --- a/src/core/hle/service/set/set_fd.h +++ b/src/core/hle/service/set/set_fd.h @@ -11,7 +11,7 @@ namespace Service::Set { class SET_FD final : public ServiceFramework<SET_FD> { public: explicit SET_FD(); - ~SET_FD() = default; + ~SET_FD() override; }; } // namespace Service::Set diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 1cef73216..cdf328a26 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -57,4 +57,6 @@ Controller::Controller() : ServiceFramework("IpcController") { RegisterHandlers(functions); } +Controller::~Controller() = default; + } // namespace Service::SM diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h index a4de52cd2..dc66c9e37 100644 --- a/src/core/hle/service/sm/controller.h +++ b/src/core/hle/service/sm/controller.h @@ -11,7 +11,7 @@ namespace Service::SM { class Controller final : public ServiceFramework<Controller> { public: Controller(); - ~Controller() = default; + ~Controller() override; private: void ConvertSessionToDomain(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index b240d7eed..464e79d01 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -15,6 +15,11 @@ namespace Service::SM { +constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); +constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); +constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); + +ServiceManager::ServiceManager() = default; ServiceManager::~ServiceManager() = default; void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { @@ -23,10 +28,10 @@ void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { static ResultCode ValidateServiceName(const std::string& name) { if (name.size() <= 0 || name.size() > 8) { - return ERR_INVALID_NAME_SIZE; + return ERR_INVALID_NAME; } if (name.find('\0') != std::string::npos) { - return ERR_NAME_CONTAINS_NUL; + return ERR_INVALID_NAME; } return RESULT_SUCCESS; } @@ -103,7 +108,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { auto client_port = service_manager->GetServicePort(name); if (client_port.Failed()) { - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(client_port.Code()); LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); if (name.length() == 0) @@ -116,8 +121,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { ASSERT(session.Succeeded()); if (session.Succeeded()) { LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); - IPC::ResponseBuilder rb = - rp.MakeBuilder(2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(session.Code()); rb.PushMoveObjects(std::move(session).Unwrap()); } diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index e8ea62f08..da2c51082 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -36,16 +36,11 @@ private: std::shared_ptr<ServiceManager> service_manager; }; -constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(-1); -constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); -constexpr ResultCode ERR_INVALID_NAME_SIZE(-1); -constexpr ResultCode ERR_NAME_CONTAINS_NUL(-1); -constexpr ResultCode ERR_ALREADY_REGISTERED(-1); - class ServiceManager { public: static void InstallInterfaces(std::shared_ptr<ServiceManager> self); + ServiceManager(); ~ServiceManager(); ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 3211a8346..4342f3b2d 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -109,6 +109,8 @@ BSD::BSD(const char* name) : ServiceFramework(name) { RegisterHandlers(functions); } +BSD::~BSD() = default; + BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { // clang-format off static const FunctionInfo functions[] = { @@ -131,4 +133,6 @@ BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { RegisterHandlers(functions); } +BSDCFG::~BSDCFG() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index c1da59b24..0fe0e65c6 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -12,7 +12,7 @@ namespace Service::Sockets { class BSD final : public ServiceFramework<BSD> { public: explicit BSD(const char* name); - ~BSD() = default; + ~BSD() override; private: void RegisterClient(Kernel::HLERequestContext& ctx); @@ -29,6 +29,7 @@ private: class BSDCFG final : public ServiceFramework<BSDCFG> { public: explicit BSDCFG(); + ~BSDCFG() override; }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp index d53c25eec..abbeb4c50 100644 --- a/src/core/hle/service/sockets/ethc.cpp +++ b/src/core/hle/service/sockets/ethc.cpp @@ -21,6 +21,8 @@ ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} { RegisterHandlers(functions); } +ETHC_C::~ETHC_C() = default; + ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { // clang-format off static const FunctionInfo functions[] = { @@ -35,4 +37,6 @@ ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { RegisterHandlers(functions); } +ETHC_I::~ETHC_I() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h index 9a3c88100..da2c7f741 100644 --- a/src/core/hle/service/sockets/ethc.h +++ b/src/core/hle/service/sockets/ethc.h @@ -11,11 +11,13 @@ namespace Service::Sockets { class ETHC_C final : public ServiceFramework<ETHC_C> { public: explicit ETHC_C(); + ~ETHC_C() override; }; class ETHC_I final : public ServiceFramework<ETHC_I> { public: explicit ETHC_I(); + ~ETHC_I() override; }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index 8682dc2e0..e6d73065e 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp @@ -29,4 +29,6 @@ NSD::NSD(const char* name) : ServiceFramework(name) { RegisterHandlers(functions); } +NSD::~NSD() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h index 3b7edfc43..d842e3232 100644 --- a/src/core/hle/service/sockets/nsd.h +++ b/src/core/hle/service/sockets/nsd.h @@ -12,7 +12,7 @@ namespace Service::Sockets { class NSD final : public ServiceFramework<NSD> { public: explicit NSD(const char* name); - ~NSD() = default; + ~NSD() override; }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index d235c4cfd..13ab1d31e 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -34,4 +34,6 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { RegisterHandlers(functions); } +SFDNSRES::~SFDNSRES() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index 62c7e35bf..eda432903 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h @@ -12,7 +12,7 @@ namespace Service::Sockets { class SFDNSRES final : public ServiceFramework<SFDNSRES> { public: explicit SFDNSRES(); - ~SFDNSRES() = default; + ~SFDNSRES() override; private: void GetAddrInfo(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp index b9e6b799d..674928798 100644 --- a/src/core/hle/service/spl/csrng.cpp +++ b/src/core/hle/service/spl/csrng.cpp @@ -13,4 +13,6 @@ CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(modul RegisterHandlers(functions); } +CSRNG::~CSRNG() = default; + } // namespace Service::SPL diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h index 3f849b5a7..764d5ceb0 100644 --- a/src/core/hle/service/spl/csrng.h +++ b/src/core/hle/service/spl/csrng.h @@ -11,6 +11,7 @@ namespace Service::SPL { class CSRNG final : public Module::Interface { public: explicit CSRNG(std::shared_ptr<Module> module); + ~CSRNG() override; }; } // namespace Service::SPL diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 3f5a342a7..44a6717d0 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp @@ -16,10 +16,12 @@ namespace Service::SPL { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - size_t size = ctx.GetWriteBufferSize(); + std::size_t size = ctx.GetWriteBufferSize(); std::vector<u8> data(size); std::generate(data.begin(), data.end(), std::rand); diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h index f24d998e8..48fda6099 100644 --- a/src/core/hle/service/spl/module.h +++ b/src/core/hle/service/spl/module.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void GetRandomBytes(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp index bb1e03342..70cb41905 100644 --- a/src/core/hle/service/spl/spl.cpp +++ b/src/core/hle/service/spl/spl.cpp @@ -42,4 +42,6 @@ SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), RegisterHandlers(functions); } +SPL::~SPL() = default; + } // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h index 69c4c1747..3637d1623 100644 --- a/src/core/hle/service/spl/spl.h +++ b/src/core/hle/service/spl/spl.h @@ -11,6 +11,7 @@ namespace Service::SPL { class SPL final : public Module::Interface { public: explicit SPL(std::shared_ptr<Module> module); + ~SPL() override; }; } // namespace Service::SPL diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index 40aea6090..fe0a318ee 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" #include "core/hle/service/ssl/ssl.h" namespace Service::SSL { @@ -68,7 +71,7 @@ private: LOG_WARNING(Service_SSL, "(STUBBED) called"); IPC::RequestParser rp{ctx}; - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -81,36 +84,43 @@ private: } }; -void SSL::CreateContext(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_SSL, "(STUBBED) called"); +class SSL final : public ServiceFramework<SSL> { +public: + explicit SSL() : ServiceFramework{"ssl"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &SSL::CreateContext, "CreateContext"}, + {1, nullptr, "GetContextCount"}, + {2, nullptr, "GetCertificates"}, + {3, nullptr, "GetCertificateBufSize"}, + {4, nullptr, "DebugIoctl"}, + {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"}, + {6, nullptr, "FlushSessionCache"}, + }; + // clang-format on - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ISslContext>(); -} + RegisterHandlers(functions); + } -SSL::SSL() : ServiceFramework("ssl") { - static const FunctionInfo functions[] = { - {0, &SSL::CreateContext, "CreateContext"}, - {1, nullptr, "GetContextCount"}, - {2, nullptr, "GetCertificates"}, - {3, nullptr, "GetCertificateBufSize"}, - {4, nullptr, "DebugIoctl"}, - {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"}, - {6, nullptr, "FlushSessionCache"}, - }; - RegisterHandlers(functions); -} +private: + void CreateContext(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_SSL, "(STUBBED) called"); -void SSL::SetInterfaceVersion(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_SSL, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 unk1 = rp.Pop<u32>(); // Probably minor/major? - u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISslContext>(); + } - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} + void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_SSL, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u32 unk1 = rp.Pop<u32>(); // Probably minor/major? + u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } +}; void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<SSL>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/ssl/ssl.h b/src/core/hle/service/ssl/ssl.h index 8fef13022..5cb04c3b9 100644 --- a/src/core/hle/service/ssl/ssl.h +++ b/src/core/hle/service/ssl/ssl.h @@ -4,20 +4,12 @@ #pragma once -#include "core/hle/service/service.h" +namespace Service::SM { +class ServiceManager; +} namespace Service::SSL { -class SSL final : public ServiceFramework<SSL> { -public: - explicit SSL(); - ~SSL() = default; - -private: - void CreateContext(Kernel::HLERequestContext& ctx); - void SetInterfaceVersion(Kernel::HLERequestContext& ctx); -}; - /// Registers all SSL services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 048d5b077..18a5d71d5 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -29,4 +29,6 @@ Time::Time(std::shared_ptr<Module> time, const char* name) RegisterHandlers(functions); } +Time::~Time() = default; + } // namespace Service::Time diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h index 183a53db1..cd6b44dec 100644 --- a/src/core/hle/service/time/interface.h +++ b/src/core/hle/service/time/interface.h @@ -11,6 +11,7 @@ namespace Service::Time { class Time final : public Module::Interface { public: explicit Time(std::shared_ptr<Module> time, const char* name); + ~Time() override; }; } // namespace Service::Time diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 2172c681b..28fd8debc 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -210,6 +210,8 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) : ServiceFramework(name), time(std::move(time)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto time = std::make_shared<Module>(); std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager); diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 8dde28a94..5659ecad3 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -58,6 +58,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> time, const char* name); + ~Interface() override; void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 993f1e65a..2ee60f1ec 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -4,25 +4,28 @@ #include <algorithm> #include <array> +#include <cstring> #include <memory> #include <type_traits> #include <utility> #include <boost/optional.hpp> #include "common/alignment.h" +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/logging/log.h" #include "common/math_util.h" -#include "common/scope_exit.h" +#include "common/swap.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" +#include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" #include "core/hle/service/vi/vi_s.h" #include "core/hle/service/vi/vi_u.h" #include "core/settings.h" -#include "video_core/renderer_base.h" -#include "video_core/video_core.h" namespace Service::VI { @@ -38,7 +41,7 @@ static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); class Parcel { public: // This default size was chosen arbitrarily. - static constexpr size_t DefaultBufferSize = 0x40; + static constexpr std::size_t DefaultBufferSize = 0x40; Parcel() : buffer(DefaultBufferSize) {} explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {} virtual ~Parcel() = default; @@ -66,7 +69,7 @@ public: return val; } - std::vector<u8> ReadBlock(size_t length) { + std::vector<u8> ReadBlock(std::size_t length) { ASSERT(read_index + length <= buffer.size()); const u8* const begin = buffer.data() + read_index; const u8* const end = begin + length; @@ -156,8 +159,8 @@ private: static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); std::vector<u8> buffer; - size_t read_index = 0; - size_t write_index = 0; + std::size_t read_index = 0; + std::size_t write_index = 0; }; class NativeWindow : public Parcel { @@ -514,7 +517,7 @@ private: ctx.SleepClientThread( Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1, [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, - ThreadWakeupReason reason) { + Kernel::ThreadWakeupReason reason) { // Repeat TransactParcel DequeueBuffer when a buffer is available auto buffer_queue = nv_flinger->GetBufferQueue(id); boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); @@ -647,7 +650,7 @@ private: u64 layer_id = rp.Pop<u64>(); u64 z_value = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -655,7 +658,7 @@ private: IPC::RequestParser rp{ctx}; u64 layer_id = rp.Pop<u64>(); bool visibility = rp.Pop<bool>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, visibility); @@ -744,7 +747,7 @@ private: IPC::RequestParser rp{ctx}; u64 display = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -758,7 +761,7 @@ private: u64 layer_id = nv_flinger->CreateLayer(display); - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push(layer_id); } @@ -769,7 +772,7 @@ private: u32 stack = rp.Pop<u32>(); u64 layer_id = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -777,7 +780,7 @@ private: IPC::RequestParser rp{ctx}; u64 layer_id = rp.Pop<u64>(); bool visibility = rp.Pop<bool>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, visibility); @@ -834,7 +837,7 @@ private: ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(nv_flinger->OpenDisplay(name)); } @@ -844,7 +847,7 @@ private: IPC::RequestParser rp{ctx}; u64 display_id = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -853,7 +856,7 @@ private: IPC::RequestParser rp{ctx}; u64 display_id = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); if (Settings::values.use_docked_mode) { @@ -871,7 +874,7 @@ private: u32 scaling_mode = rp.Pop<u32>(); u64 unknown = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -879,7 +882,7 @@ private: IPC::RequestParser rp{ctx}; DisplayInfo display_info; ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(1); LOG_WARNING(Service_VI, "(STUBBED) called"); @@ -900,7 +903,7 @@ private: u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); NativeWindow native_window{buffer_queue_id}; - IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); } @@ -919,7 +922,7 @@ private: u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); NativeWindow native_window{buffer_queue_id}; - IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); rb.Push(layer_id); rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); @@ -931,7 +934,7 @@ private: IPC::RequestParser rp{ctx}; u64 layer_id = rp.Pop<u64>(); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -942,7 +945,7 @@ private: auto vsync_event = nv_flinger->GetVsyncEvent(display_id); - IPC::ResponseBuilder rb = rp.MakeBuilder(2, 1, 0); + IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(vsync_event); } @@ -984,6 +987,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} +Module::Interface::~Interface() = default; + void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_VI, "(STUBBED) called"); diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 92f5b6059..e3963502a 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -4,11 +4,10 @@ #pragma once -#include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/service.h" -namespace CoreTiming { -struct EventType; +namespace Service::NVFlinger { +class NVFlinger; } namespace Service::VI { @@ -26,6 +25,7 @@ public: public: explicit Interface(std::shared_ptr<Module> module, const char* name, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~Interface() override; void GetDisplayService(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index d47da565b..207c06b16 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -15,4 +15,6 @@ VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> RegisterHandlers(functions); } +VI_M::~VI_M() = default; + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 6abb9b3a3..487d58d50 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -11,6 +11,7 @@ namespace Service::VI { class VI_M final : public Module::Interface { public: explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~VI_M() override; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 8f82e797f..920e6a1f6 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp @@ -15,4 +15,6 @@ VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> RegisterHandlers(functions); } +VI_S::~VI_S() = default; + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 8f16f804f..bbc31148f 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h @@ -11,6 +11,7 @@ namespace Service::VI { class VI_S final : public Module::Interface { public: explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~VI_S() override; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index b84aed1d5..d81e410d6 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -14,4 +14,6 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> RegisterHandlers(functions); } +VI_U::~VI_U() = default; + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index e9b4f76b2..b92f28c92 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h @@ -11,6 +11,7 @@ namespace Service::VI { class VI_U final : public Module::Interface { public: explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~VI_U() override; }; } // namespace Service::VI diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 921b899e2..2b8f78136 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs_factory.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" @@ -21,10 +22,19 @@ namespace Loader { -AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_) - : AppLoader(std::move(file_)) { +AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, + bool override_update) + : AppLoader(std::move(file_)), override_update(override_update) { const auto dir = file->GetContainingDirectory(); + // Title ID + const auto npdm = dir->GetFile("main.npdm"); + if (npdm != nullptr) { + const auto res = metadata.Load(npdm); + if (res == ResultStatus::Success) + title_id = metadata.GetTitleID(); + } + // Icon FileSys::VirtualFile icon_file = nullptr; for (const auto& language : FileSys::LANGUAGE_NAMES) { @@ -61,14 +71,14 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys if (nacp_file != nullptr) { FileSys::NACP nacp(nacp_file); - title_id = nacp.GetTitleId(); name = nacp.GetApplicationName(); } } AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( - FileSys::VirtualDir directory) - : AppLoader(directory->GetFile("main")), dir(std::move(directory)) {} + FileSys::VirtualDir directory, bool override_update) + : AppLoader(directory->GetFile("main")), dir(std::move(directory)), + override_update(override_update) {} FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) { if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) { @@ -90,7 +100,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( dir = file->GetContainingDirectory(); } - const FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); + // Read meta to determine title ID + FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); if (npdm == nullptr) return ResultStatus::ErrorMissingNPDM; @@ -98,6 +109,21 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( if (result != ResultStatus::Success) { return result; } + + if (override_update) { + const FileSys::PatchManager patch_manager(metadata.GetTitleID()); + dir = patch_manager.PatchExeFS(dir); + } + + // Reread in case PatchExeFS affected the main.npdm + npdm = dir->GetFile("main.npdm"); + if (npdm == nullptr) + return ResultStatus::ErrorMissingNPDM; + + ResultStatus result2 = metadata.Load(npdm); + if (result2 != ResultStatus::Success) { + return result2; + } metadata.Print(); const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; @@ -159,8 +185,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buff } ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { - if (name.empty()) - return ResultStatus::ErrorNoControl; out_program_id = title_id; return ResultStatus::Success; } @@ -172,4 +196,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) return ResultStatus::Success; } +bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() const { + return false; +} + } // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index b20804f75..8a0dc1b1e 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -20,10 +20,12 @@ namespace Loader { */ class AppLoader_DeconstructedRomDirectory final : public AppLoader { public: - explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file); + explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file, + bool override_update = false); // Overload to accept exefs directory. Must contain 'main' and 'main.npdm' - explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory); + explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory, + bool override_update = false); /** * Returns the type of the file @@ -42,6 +44,7 @@ public: ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadTitle(std::string& title) override; + bool IsRomFSUpdatable() const override; private: FileSys::ProgramMetadata metadata; @@ -51,6 +54,7 @@ private: std::vector<u8> icon_data; std::string name; u64 title_id{}; + bool override_update; }; } // namespace Loader diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 120e1e133..0e2af20b4 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -300,7 +300,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { } std::vector<u8> program_image(total_image_size); - size_t current_image_position = 0; + std::size_t current_image_position = 0; auto& kernel = Core::System::GetInstance().Kernel(); SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, ""); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index c13fb49b8..f2a183ba1 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -5,9 +5,9 @@ #include <memory> #include <ostream> #include <string> +#include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" -#include "core/file_sys/vfs_real.h" #include "core/hle/kernel/process.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/elf.h" @@ -15,6 +15,7 @@ #include "core/loader/nca.h" #include "core/loader/nro.h" #include "core/loader/nso.h" +#include "core/loader/nsp.h" #include "core/loader/xci.h" namespace Loader { @@ -34,6 +35,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { CHECK_TYPE(NCA) CHECK_TYPE(XCI) CHECK_TYPE(NAX) + CHECK_TYPE(NSP) #undef CHECK_TYPE @@ -59,6 +61,8 @@ FileType GuessFromFilename(const std::string& name) { return FileType::NCA; if (extension == "xci") return FileType::XCI; + if (extension == "nsp") + return FileType::NSP; return FileType::Unknown; } @@ -77,6 +81,8 @@ std::string GetFileTypeString(FileType type) { return "XCI"; case FileType::NAX: return "NAX"; + case FileType::NSP: + return "NSP"; case FileType::DeconstructedRomDirectory: return "Directory"; case FileType::Error: @@ -87,7 +93,7 @@ std::string GetFileTypeString(FileType type) { return "unknown"; } -constexpr std::array<const char*, 49> RESULT_MESSAGES{ +constexpr std::array<const char*, 58> RESULT_MESSAGES{ "The operation completed successfully.", "The loader requested to load is already loaded.", "The operation is not implemented.", @@ -137,13 +143,25 @@ constexpr std::array<const char*, 49> RESULT_MESSAGES{ "The AES Key Generation Source could not be found.", "The SD Save Key Source could not be found.", "The SD NCA Key Source could not be found.", + "The NSP file is missing a Program-type NCA.", + "The BKTR-type NCA has a bad BKTR header.", + "The BKTR Subsection entry is not located immediately after the Relocation entry.", + "The BKTR Subsection entry is not at the end of the media block.", + "The BKTR-type NCA has a bad Relocation block.", + "The BKTR-type NCA has a bad Subsection block.", + "The BKTR-type NCA has a bad Relocation bucket.", + "The BKTR-type NCA has a bad Subsection bucket.", + "The BKTR-type NCA is missing the base RomFS.", }; std::ostream& operator<<(std::ostream& os, ResultStatus status) { - os << RESULT_MESSAGES.at(static_cast<size_t>(status)); + os << RESULT_MESSAGES.at(static_cast<std::size_t>(status)); return os; } +AppLoader::AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {} +AppLoader::~AppLoader() = default; + /** * Get a loader for a file with a specific type * @param file The file to load @@ -179,6 +197,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT case FileType::NAX: return std::make_unique<AppLoader_NAX>(std::move(file)); + // NX NSP (Nintendo Submission Package) file format + case FileType::NSP: + return std::make_unique<AppLoader_NSP>(std::move(file)); + // NX deconstructed ROM directory. case FileType::DeconstructedRomDirectory: return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 885fee84c..843c4bb91 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -4,7 +4,6 @@ #pragma once -#include <algorithm> #include <iosfwd> #include <memory> #include <string> @@ -12,7 +11,6 @@ #include <vector> #include <boost/optional.hpp> #include "common/common_types.h" -#include "common/file_util.h" #include "core/file_sys/vfs.h" #include "core/hle/kernel/object.h" @@ -31,6 +29,7 @@ enum class FileType { NSO, NRO, NCA, + NSP, XCI, NAX, DeconstructedRomDirectory, @@ -107,6 +106,15 @@ enum class ResultStatus : u16 { ErrorMissingAESKeyGenerationSource, ErrorMissingSDSaveKeySource, ErrorMissingSDNCAKeySource, + ErrorNSPMissingProgramNCA, + ErrorBadBKTRHeader, + ErrorBKTRSubsectionNotAfterRelocation, + ErrorBKTRSubsectionNotAtEnd, + ErrorBadRelocationBlock, + ErrorBadSubsectionBlock, + ErrorBadRelocationBuckets, + ErrorBadSubsectionBuckets, + ErrorMissingBKTRBaseRomFS, }; std::ostream& operator<<(std::ostream& os, ResultStatus status); @@ -114,8 +122,8 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status); /// Interface for loading an application class AppLoader : NonCopyable { public: - explicit AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {} - virtual ~AppLoader() {} + explicit AppLoader(FileSys::VirtualFile file); + virtual ~AppLoader(); /** * Returns the type of this file @@ -197,13 +205,22 @@ public: } /** - * Get the update RomFS of the application - * Since the RomFS can be huge, we return a file reference instead of copying to a buffer - * @param file The file containing the RomFS - * @return ResultStatus result of function + * Get whether or not updates can be applied to the RomFS. + * By default, this is true, however for formats where it cannot be guaranteed that the RomFS is + * the base game it should be set to false. + * @return bool whether or not updatable. */ - virtual ResultStatus ReadUpdateRomFS(FileSys::VirtualFile& file) { - return ResultStatus::ErrorNotImplemented; + virtual bool IsRomFSUpdatable() const { + return true; + } + + /** + * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS) + * data. Needed for bktr patching. + * @return IVFC offset for romfs. + */ + virtual u64 ReadRomFSIVFCOffset() const { + return 0; } /** diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index b46d81c02..5d4380684 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -11,6 +11,20 @@ #include "core/loader/nca.h" namespace Loader { +namespace { +FileType IdentifyTypeImpl(const FileSys::NAX& nax) { + if (nax.GetStatus() != ResultStatus::Success) { + return FileType::Error; + } + + const auto nca = nax.AsNCA(); + if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) { + return FileType::Error; + } + + return FileType::NAX; +} +} // Anonymous namespace AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)), @@ -19,14 +33,12 @@ AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) AppLoader_NAX::~AppLoader_NAX() = default; FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { - FileSys::NAX nax(file); - - if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr && - nax.AsNCA()->GetStatus() == ResultStatus::Success) { - return FileType::NAX; - } + const FileSys::NAX nax(file); + return IdentifyTypeImpl(nax); +} - return FileType::Error; +FileType AppLoader_NAX::GetFileType() { + return IdentifyTypeImpl(*nax); } ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index 4dbae2918..56605fe45 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h @@ -31,9 +31,7 @@ public: */ static FileType IdentifyType(const FileSys::VirtualFile& file); - FileType GetFileType() override { - return IdentifyType(file); - } + FileType GetFileType() override; ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index c036a8a1c..6aaffae59 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -48,7 +48,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) { if (exefs == nullptr) return ResultStatus::ErrorNoExeFS; - directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs); + directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true); const auto load_result = directory_loader->Load(process); if (load_result != ResultStatus::Success) @@ -71,6 +71,12 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { return ResultStatus::Success; } +u64 AppLoader_NCA::ReadRomFSIVFCOffset() const { + if (nca == nullptr) + return 0; + return nca->GetBaseIVFCOffset(); +} + ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) return ResultStatus::ErrorNotInitialized; diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 326f84857..10be197c4 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -37,6 +37,7 @@ public: ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + u64 ReadRomFSIVFCOffset() const override; ResultStatus ReadProgramId(u64& out_program_id) override; private: diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 77026b850..c49ec34ab 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -191,7 +191,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { process->svc_access_mask.set(); process->resource_limit = kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); - process->Run(base_addr, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); + process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); is_loaded = true; return ResultStatus::Success; @@ -232,4 +232,9 @@ ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { title = nacp->GetApplicationName(); return ResultStatus::Success; } + +bool AppLoader_NRO::IsRomFSUpdatable() const { + return false; +} + } // namespace Loader diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index bb01c9e25..96d2de305 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -39,6 +39,7 @@ public: ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; ResultStatus ReadTitle(std::string& title) override; + bool IsRomFSUpdatable() const override; private: bool LoadNro(FileSys::VirtualFile file, VAddr load_base); diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 082a95d40..3c6306818 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -157,7 +157,8 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { process->svc_access_mask.set(); process->resource_limit = kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); - process->Run(Memory::PROCESS_IMAGE_VADDR, THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); + process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT, + Memory::DEFAULT_STACK_SIZE); is_loaded = true; return ResultStatus::Success; diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp new file mode 100644 index 000000000..291a9876d --- /dev/null +++ b/src/core/loader/nsp.cpp @@ -0,0 +1,125 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <vector> + +#include "common/common_types.h" +#include "core/file_sys/card_image.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/submission_package.h" +#include "core/hle/kernel/process.h" +#include "core/loader/deconstructed_rom_directory.h" +#include "core/loader/nca.h" +#include "core/loader/nsp.h" + +namespace Loader { + +AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) + : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), + title_id(nsp->GetProgramTitleID()) { + + if (nsp->GetStatus() != ResultStatus::Success) + return; + if (nsp->IsExtractedType()) + return; + + const auto control_nca = + nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); + if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) + return; + + std::tie(nacp_file, icon_file) = + FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(control_nca); +} + +AppLoader_NSP::~AppLoader_NSP() = default; + +FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { + FileSys::NSP nsp(file); + + if (nsp.GetStatus() == ResultStatus::Success) { + // Extracted Type case + if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr && + FileSys::IsDirectoryExeFS(nsp.GetExeFS()) && nsp.GetRomFS() != nullptr) { + return FileType::NSP; + } + + // Non-Ectracted Type case + if (!nsp.IsExtractedType() && + nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr && + AppLoader_NCA::IdentifyType(nsp.GetNCAFile( + nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) { + return FileType::NSP; + } + } + + return FileType::Error; +} + +ResultStatus AppLoader_NSP::Load(Kernel::SharedPtr<Kernel::Process>& process) { + if (is_loaded) { + return ResultStatus::ErrorAlreadyLoaded; + } + + if (nsp->IsExtractedType()) { + secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); + } else { + if (title_id == 0) + return ResultStatus::ErrorNSPMissingProgramNCA; + + secondary_loader = std::make_unique<AppLoader_NCA>( + nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); + + if (nsp->GetStatus() != ResultStatus::Success) + return nsp->GetStatus(); + + if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) + return nsp->GetProgramStatus(title_id); + + if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { + if (!Core::Crypto::KeyManager::KeyFileExists(false)) + return ResultStatus::ErrorMissingProductionKeyFile; + return ResultStatus::ErrorNSPMissingProgramNCA; + } + } + + const auto result = secondary_loader->Load(process); + if (result != ResultStatus::Success) + return result; + + is_loaded = true; + + return ResultStatus::Success; +} + +ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& dir) { + return secondary_loader->ReadRomFS(dir); +} + +ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { + if (title_id == 0) + return ResultStatus::ErrorNotInitialized; + out_program_id = title_id; + return ResultStatus::Success; +} + +ResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) { + if (icon_file == nullptr) + return ResultStatus::ErrorNoControl; + buffer = icon_file->ReadAllBytes(); + return ResultStatus::Success; +} + +ResultStatus AppLoader_NSP::ReadTitle(std::string& title) { + if (nacp_file == nullptr) + return ResultStatus::ErrorNoControl; + title = nacp_file->GetApplicationName(); + return ResultStatus::Success; +} +} // namespace Loader diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h new file mode 100644 index 000000000..7ef810499 --- /dev/null +++ b/src/core/loader/nsp.h @@ -0,0 +1,54 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include "common/common_types.h" +#include "core/file_sys/vfs.h" +#include "core/loader/loader.h" + +namespace FileSys { +class NACP; +class NSP; +} // namespace FileSys + +namespace Loader { + +class AppLoader_NCA; + +/// Loads an XCI file +class AppLoader_NSP final : public AppLoader { +public: + explicit AppLoader_NSP(FileSys::VirtualFile file); + ~AppLoader_NSP() override; + + /** + * Returns the type of the file + * @param file std::shared_ptr<VfsFile> open file + * @return FileType found, or FileType::Error if this loader doesn't know it + */ + static FileType IdentifyType(const FileSys::VirtualFile& file); + + FileType GetFileType() override { + return IdentifyType(file); + } + + ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; + + ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadIcon(std::vector<u8>& buffer) override; + ResultStatus ReadTitle(std::string& title) override; + +private: + std::unique_ptr<FileSys::NSP> nsp; + std::unique_ptr<AppLoader> secondary_loader; + + FileSys::VirtualFile icon_file; + std::shared_ptr<FileSys::NACP> nacp_file; + u64 title_id; +}; + +} // namespace Loader diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 9dc4d1f35..16509229f 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -8,7 +8,9 @@ #include "core/file_sys/card_image.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/submission_package.h" #include "core/hle/kernel/process.h" #include "core/loader/nca.h" #include "core/loader/xci.h" @@ -17,25 +19,16 @@ namespace Loader { AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), - nca_loader(std::make_unique<AppLoader_NCA>( - xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { + nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { if (xci->GetStatus() != ResultStatus::Success) return; + const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) return; - const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); - if (romfs == nullptr) - return; - for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); - if (icon_file != nullptr) - break; - } - const auto nacp_raw = romfs->GetFile("control.nacp"); - if (nacp_raw == nullptr) - return; - nacp_file = std::make_shared<FileSys::NACP>(nacp_raw); + + std::tie(nacp_file, icon_file) = + FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(control_nca); } AppLoader_XCI::~AppLoader_XCI() = default; @@ -64,11 +57,11 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) { if (xci->GetProgramNCAStatus() != ResultStatus::Success) return xci->GetProgramNCAStatus(); - const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program); + const auto nca = xci->GetProgramNCA(); if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) return ResultStatus::ErrorMissingProductionKeyFile; - auto result = nca_loader->Load(process); + const auto result = nca_loader->Load(process); if (result != ResultStatus::Success) return result; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 0e4e0157c..316b46820 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -370,16 +370,16 @@ u64 Read64(const VAddr addr) { } void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, - const size_t size) { + const std::size_t size) { auto& page_table = process.vm_manager.page_table; - size_t remaining_size = size; - size_t page_index = src_addr >> PAGE_BITS; - size_t page_offset = src_addr & PAGE_MASK; + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; while (remaining_size > 0) { - const size_t copy_amount = - std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); switch (page_table.attributes[page_index]) { @@ -414,7 +414,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ } } -void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { +void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { ReadBlock(*Core::CurrentProcess(), src_addr, dest_buffer, size); } @@ -435,15 +435,15 @@ void Write64(const VAddr addr, const u64 data) { } void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, - const size_t size) { + const std::size_t size) { auto& page_table = process.vm_manager.page_table; - size_t remaining_size = size; - size_t page_index = dest_addr >> PAGE_BITS; - size_t page_offset = dest_addr & PAGE_MASK; + std::size_t remaining_size = size; + std::size_t page_index = dest_addr >> PAGE_BITS; + std::size_t page_offset = dest_addr & PAGE_MASK; while (remaining_size > 0) { - const size_t copy_amount = - std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); switch (page_table.attributes[page_index]) { @@ -477,19 +477,19 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi } } -void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { +void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size); } -void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size_t size) { +void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { auto& page_table = process.vm_manager.page_table; - size_t remaining_size = size; - size_t page_index = dest_addr >> PAGE_BITS; - size_t page_offset = dest_addr & PAGE_MASK; + std::size_t remaining_size = size; + std::size_t page_index = dest_addr >> PAGE_BITS; + std::size_t page_offset = dest_addr & PAGE_MASK; while (remaining_size > 0) { - const size_t copy_amount = - std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); switch (page_table.attributes[page_index]) { @@ -522,15 +522,16 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const size } } -void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, const size_t size) { +void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, + const std::size_t size) { auto& page_table = process.vm_manager.page_table; - size_t remaining_size = size; - size_t page_index = src_addr >> PAGE_BITS; - size_t page_offset = src_addr & PAGE_MASK; + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; while (remaining_size > 0) { - const size_t copy_amount = - std::min(static_cast<size_t>(PAGE_SIZE) - page_offset, remaining_size); + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); switch (page_table.attributes[page_index]) { @@ -565,7 +566,7 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, } } -void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) { +void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size); } diff --git a/src/core/memory.h b/src/core/memory.h index f06e04a75..2a27c0251 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -22,11 +22,11 @@ namespace Memory { * Page size used by the ARM architecture. This is the smallest granularity with which memory can * be mapped. */ -constexpr size_t PAGE_BITS = 12; +constexpr std::size_t PAGE_BITS = 12; constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; constexpr u64 PAGE_MASK = PAGE_SIZE - 1; -constexpr size_t ADDRESS_SPACE_BITS = 36; -constexpr size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS); +constexpr std::size_t ADDRESS_SPACE_BITS = 36; +constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS); enum class PageType : u8 { /// Page is unmapped and should cause an access error. @@ -154,13 +154,13 @@ void Write16(VAddr addr, u16 data); void Write32(VAddr addr, u32 data); void Write64(VAddr addr, u64 data); -void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, size_t size); -void ReadBlock(VAddr src_addr, void* dest_buffer, size_t size); +void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size); +void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, - size_t size); -void WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size); -void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, size_t size); -void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size); + std::size_t size); +void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); +void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); +void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); u8* GetPointer(VAddr vaddr); diff --git a/src/core/memory_hook.h b/src/core/memory_hook.h index e8ea19333..0269c7ff1 100644 --- a/src/core/memory_hook.h +++ b/src/core/memory_hook.h @@ -32,14 +32,14 @@ public: virtual boost::optional<u32> Read32(VAddr addr) = 0; virtual boost::optional<u64> Read64(VAddr addr) = 0; - virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, size_t size) = 0; + virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; virtual bool Write8(VAddr addr, u8 data) = 0; virtual bool Write16(VAddr addr, u16 data) = 0; virtual bool Write32(VAddr addr, u32 data) = 0; virtual bool Write64(VAddr addr, u64 data) = 0; - virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size) = 0; + virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0; }; using MemoryHookPointer = std::shared_ptr<MemoryHook>; diff --git a/src/core/settings.h b/src/core/settings.h index ed6f42471..0318d019c 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include <atomic> #include <string> #include "common/common_types.h" @@ -120,6 +121,7 @@ struct Values { std::array<std::string, NativeAnalog::NumAnalogs> analogs; std::string motion_device; std::string touch_device; + std::atomic_bool is_device_reload_pending{true}; // Core bool use_cpu_jit; @@ -127,6 +129,8 @@ struct Values { // Data Storage bool use_virtual_sd; + std::string nand_dir; + std::string sdmc_dir; // Renderer float resolution_factor; @@ -144,6 +148,7 @@ struct Values { // Audio std::string sink_id; + bool enable_audio_stretching; std::string audio_device_id; float volume; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 65571b948..b0df154ca 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -7,6 +7,8 @@ #include "common/file_util.h" #include "core/core.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" #include "core/settings.h" #include "core/telemetry_session.h" @@ -88,12 +90,28 @@ TelemetrySession::TelemetrySession() { std::chrono::system_clock::now().time_since_epoch()) .count()}; AddField(Telemetry::FieldType::Session, "Init_Time", init_time); - std::string program_name; - const Loader::ResultStatus res{System::GetInstance().GetAppLoader().ReadTitle(program_name)}; + + u64 program_id{}; + const Loader::ResultStatus res{System::GetInstance().GetAppLoader().ReadProgramId(program_id)}; if (res == Loader::ResultStatus::Success) { - AddField(Telemetry::FieldType::Session, "ProgramName", program_name); + AddField(Telemetry::FieldType::Session, "ProgramId", program_id); + + std::string name; + System::GetInstance().GetAppLoader().ReadTitle(name); + + if (name.empty()) { + auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); + if (nacp != nullptr) + name = nacp->GetApplicationName(); + } + + if (!name.empty()) + AddField(Telemetry::FieldType::Session, "ProgramName", name); } + AddField(Telemetry::FieldType::Session, "ProgramFormat", + static_cast<u8>(System::GetInstance().GetAppLoader().GetFileType())); + // Log application information Telemetry::AppendBuildInfo(field_collection); @@ -102,6 +120,9 @@ TelemetrySession::TelemetrySession() { Telemetry::AppendOSInfo(field_collection); // Log user configuration information + AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id); + AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching", + Settings::values.enable_audio_stretching); AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit); AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore", Settings::values.use_multi_core); diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp index af032f0c9..73cacb47f 100644 --- a/src/core/tracer/recorder.cpp +++ b/src/core/tracer/recorder.cpp @@ -76,7 +76,7 @@ void Recorder::Finish(const std::string& filename) { try { // Open file and write header FileUtil::IOFile file(filename, "wb"); - size_t written = file.WriteObject(header); + std::size_t written = file.WriteObject(header); if (written != 1 || file.Tell() != initial.gpu_registers) throw "Failed to write header"; |
