From 64facb403ed31d3cb6aa594711705b7ace32e932 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 1 Mar 2020 00:40:25 -0500 Subject: [PATCH 1/4] core: dynarmic: Add CP15 from Citra. --- src/core/CMakeLists.txt | 2 + src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | 80 +++++++++++ src/core/arm/dynarmic/arm_dynarmic_cp15.h | 152 ++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 src/core/arm/dynarmic/arm_dynarmic_cp15.cpp create mode 100644 src/core/arm/dynarmic/arm_dynarmic_cp15.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 54be7dc0c..df1e62d4f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -597,6 +597,8 @@ if (ARCHITECTURE_x86_64) target_sources(core PRIVATE arm/dynarmic/arm_dynarmic.cpp arm/dynarmic/arm_dynarmic.h + arm/dynarmic/arm_dynarmic_cp15.cpp + arm/dynarmic/arm_dynarmic_cp15.h ) target_link_libraries(core PRIVATE dynarmic) endif() diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp new file mode 100644 index 000000000..3fdcdebde --- /dev/null +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp @@ -0,0 +1,80 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/dynarmic/arm_dynarmic_cp15.h" + +using Callback = Dynarmic::A32::Coprocessor::Callback; +using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; +using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; + +std::optional DynarmicCP15::CompileInternalOperation(bool two, unsigned opc1, + CoprocReg CRd, CoprocReg CRn, + CoprocReg CRm, unsigned opc2) { + return {}; +} + +CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, + CoprocReg CRm, unsigned opc2) { + // TODO(merry): Privileged CP15 registers + + if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) { + // This is a dummy write, we ignore the value written here. + return &CP15[static_cast(CP15Register::CP15_FLUSH_PREFETCH_BUFFER)]; + } + + if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) { + switch (opc2) { + case 4: + // This is a dummy write, we ignore the value written here. + return &CP15[static_cast(CP15Register::CP15_DATA_SYNC_BARRIER)]; + case 5: + // This is a dummy write, we ignore the value written here. + return &CP15[static_cast(CP15Register::CP15_DATA_MEMORY_BARRIER)]; + default: + return {}; + } + } + + if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) { + return &CP15[static_cast(CP15Register::CP15_THREAD_UPRW)]; + } + + return {}; +} + +CallbackOrAccessTwoWords DynarmicCP15::CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) { + return {}; +} + +CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, + CoprocReg CRm, unsigned opc2) { + // TODO(merry): Privileged CP15 registers + + if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) { + switch (opc2) { + case 2: + return &CP15[static_cast(CP15Register::CP15_THREAD_UPRW)]; + case 3: + return &CP15[static_cast(CP15Register::CP15_THREAD_URO)]; + default: + return {}; + } + } + + return {}; +} + +CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { + return {}; +} + +std::optional DynarmicCP15::CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) { + return {}; +} + +std::optional DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) { + return {}; +} diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h new file mode 100644 index 000000000..07bcde5f9 --- /dev/null +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -0,0 +1,152 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include +#include "common/common_types.h" + +enum class CP15Register { + // c0 - Information registers + CP15_MAIN_ID, + CP15_CACHE_TYPE, + CP15_TCM_STATUS, + CP15_TLB_TYPE, + CP15_CPU_ID, + CP15_PROCESSOR_FEATURE_0, + CP15_PROCESSOR_FEATURE_1, + CP15_DEBUG_FEATURE_0, + CP15_AUXILIARY_FEATURE_0, + CP15_MEMORY_MODEL_FEATURE_0, + CP15_MEMORY_MODEL_FEATURE_1, + CP15_MEMORY_MODEL_FEATURE_2, + CP15_MEMORY_MODEL_FEATURE_3, + CP15_ISA_FEATURE_0, + CP15_ISA_FEATURE_1, + CP15_ISA_FEATURE_2, + CP15_ISA_FEATURE_3, + CP15_ISA_FEATURE_4, + + // c1 - Control registers + CP15_CONTROL, + CP15_AUXILIARY_CONTROL, + CP15_COPROCESSOR_ACCESS_CONTROL, + + // c2 - Translation table registers + CP15_TRANSLATION_BASE_TABLE_0, + CP15_TRANSLATION_BASE_TABLE_1, + CP15_TRANSLATION_BASE_CONTROL, + CP15_DOMAIN_ACCESS_CONTROL, + CP15_RESERVED, + + // c5 - Fault status registers + CP15_FAULT_STATUS, + CP15_INSTR_FAULT_STATUS, + CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, + CP15_INST_FSR, + + // c6 - Fault Address registers + CP15_FAULT_ADDRESS, + CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, + CP15_WFAR, + CP15_IFAR, + + // c7 - Cache operation registers + CP15_WAIT_FOR_INTERRUPT, + CP15_PHYS_ADDRESS, + CP15_INVALIDATE_INSTR_CACHE, + CP15_INVALIDATE_INSTR_CACHE_USING_MVA, + CP15_INVALIDATE_INSTR_CACHE_USING_INDEX, + CP15_FLUSH_PREFETCH_BUFFER, + CP15_FLUSH_BRANCH_TARGET_CACHE, + CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY, + CP15_INVALIDATE_DATA_CACHE, + CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA, + CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, + CP15_INVALIDATE_DATA_AND_INSTR_CACHE, + CP15_CLEAN_DATA_CACHE, + CP15_CLEAN_DATA_CACHE_LINE_USING_MVA, + CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX, + CP15_DATA_SYNC_BARRIER, + CP15_DATA_MEMORY_BARRIER, + CP15_CLEAN_AND_INVALIDATE_DATA_CACHE, + CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA, + CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, + + // c8 - TLB operations + CP15_INVALIDATE_ITLB, + CP15_INVALIDATE_ITLB_SINGLE_ENTRY, + CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH, + CP15_INVALIDATE_ITLB_ENTRY_ON_MVA, + CP15_INVALIDATE_DTLB, + CP15_INVALIDATE_DTLB_SINGLE_ENTRY, + CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH, + CP15_INVALIDATE_DTLB_ENTRY_ON_MVA, + CP15_INVALIDATE_UTLB, + CP15_INVALIDATE_UTLB_SINGLE_ENTRY, + CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH, + CP15_INVALIDATE_UTLB_ENTRY_ON_MVA, + + // c9 - Data cache lockdown register + CP15_DATA_CACHE_LOCKDOWN, + + // c10 - TLB/Memory map registers + CP15_TLB_LOCKDOWN, + CP15_PRIMARY_REGION_REMAP, + CP15_NORMAL_REGION_REMAP, + + // c13 - Thread related registers + CP15_PID, + CP15_CONTEXT_ID, + CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write + CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W) + CP15_THREAD_PRW, // Thread ID register - Privileged R/W only. + + // c15 - Performance and TLB lockdown registers + CP15_PERFORMANCE_MONITOR_CONTROL, + CP15_CYCLE_COUNTER, + CP15_COUNT_0, + CP15_COUNT_1, + CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY, + CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY, + CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS, + CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS, + CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE, + CP15_TLB_DEBUG_CONTROL, + + // Skyeye defined + CP15_TLB_FAULT_ADDR, + CP15_TLB_FAULT_STATUS, + + // Not an actual register. + // All registers should be defined above this. + CP15_REGISTER_COUNT, +}; + +class DynarmicCP15 final : public Dynarmic::A32::Coprocessor { +public: + using CoprocReg = Dynarmic::A32::CoprocReg; + + explicit DynarmicCP15(u32* cp15) : CP15(cp15){}; + + std::optional CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, + CoprocReg CRn, CoprocReg CRm, + unsigned opc2) override; + CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, + CoprocReg CRm, unsigned opc2) override; + CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) override; + CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, + unsigned opc2) override; + CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) override; + std::optional CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) override; + std::optional CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, + std::optional option) override; + +private: + u32* CP15{}; +}; From 6fc485a6079038356f3f840e12c366d488caabc6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 1 Mar 2020 00:42:40 -0500 Subject: [PATCH 2/4] core: loader: Remove check for 32-bit. --- src/core/loader/deconstructed_rom_directory.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index d19c3623c..53559e8b1 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -129,12 +129,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect } metadata.Print(); - const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; - if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit || - arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { - return {ResultStatus::Error32BitISA, {}}; - } - if (process.LoadFromMetadata(metadata).IsError()) { return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; } From c083ea7d7846ee40cfc889ed1d415f73ec78364c Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 1 Mar 2020 23:46:10 -0500 Subject: [PATCH 3/4] core: Implement separate A32/A64 ARM interfaces. --- src/core/CMakeLists.txt | 6 +- src/core/arm/arm_interface.h | 32 +-- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 208 ++++++++++++++++++ src/core/arm/dynarmic/arm_dynarmic_32.h | 77 +++++++ .../{arm_dynarmic.cpp => arm_dynarmic_64.cpp} | 74 +++---- .../{arm_dynarmic.h => arm_dynarmic_64.h} | 30 +-- src/core/arm/exclusive_monitor.cpp | 2 +- src/core/arm/unicorn/arm_unicorn.cpp | 8 +- src/core/arm/unicorn/arm_unicorn.h | 7 +- src/core/core_manager.cpp | 3 - src/core/gdbstub/gdbstub.cpp | 14 +- src/core/hle/kernel/kernel.cpp | 4 + src/core/hle/kernel/physical_core.cpp | 19 +- src/core/hle/kernel/physical_core.h | 6 +- src/core/hle/kernel/process.cpp | 3 +- src/core/hle/kernel/scheduler.cpp | 21 +- src/core/hle/kernel/scheduler.h | 3 +- src/core/hle/kernel/thread.cpp | 31 +-- src/core/hle/kernel/thread.h | 22 +- src/core/reporter.cpp | 2 +- src/yuzu/debugger/wait_tree.cpp | 4 +- 21 files changed, 454 insertions(+), 122 deletions(-) create mode 100644 src/core/arm/dynarmic/arm_dynarmic_32.cpp create mode 100644 src/core/arm/dynarmic/arm_dynarmic_32.h rename src/core/arm/dynarmic/{arm_dynarmic.cpp => arm_dynarmic_64.cpp} (81%) rename src/core/arm/dynarmic/{arm_dynarmic.h => arm_dynarmic_64.h} (74%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index df1e62d4f..b31a0328c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -595,8 +595,10 @@ endif() if (ARCHITECTURE_x86_64) target_sources(core PRIVATE - arm/dynarmic/arm_dynarmic.cpp - arm/dynarmic/arm_dynarmic.h + arm/dynarmic/arm_dynarmic_32.cpp + arm/dynarmic/arm_dynarmic_32.h + arm/dynarmic/arm_dynarmic_64.cpp + arm/dynarmic/arm_dynarmic_64.h arm/dynarmic/arm_dynarmic_cp15.cpp arm/dynarmic/arm_dynarmic_cp15.h ) diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 47b964eb7..57eae839e 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -25,7 +25,20 @@ public: explicit ARM_Interface(System& system_) : system{system_} {} virtual ~ARM_Interface() = default; - struct ThreadContext { + struct ThreadContext32 { + std::array cpu_registers; + u32 cpsr; + std::array padding; + std::array fprs; + u32 fpscr; + u32 fpexc; + u32 tpidr; + }; + // Internally within the kernel, it expects the AArch32 version of the + // thread context to be 344 bytes in size. + static_assert(sizeof(ThreadContext32) == 0x158); + + struct ThreadContext64 { std::array cpu_registers; u64 sp; u64 pc; @@ -38,7 +51,7 @@ public: }; // Internally within the kernel, it expects the AArch64 version of the // thread context to be 800 bytes in size. - static_assert(sizeof(ThreadContext) == 0x320); + static_assert(sizeof(ThreadContext64) == 0x320); /// Runs the CPU until an event happens virtual void Run() = 0; @@ -130,17 +143,10 @@ public: */ virtual void SetTPIDR_EL0(u64 value) = 0; - /** - * Saves the current CPU context - * @param ctx Thread context to save - */ - virtual void SaveContext(ThreadContext& ctx) = 0; - - /** - * Loads a CPU context - * @param ctx Thread context to load - */ - virtual void LoadContext(const ThreadContext& ctx) = 0; + virtual void SaveContext(ThreadContext32& ctx) = 0; + virtual void SaveContext(ThreadContext64& ctx) = 0; + virtual void LoadContext(const ThreadContext32& ctx) = 0; + virtual void LoadContext(const ThreadContext64& ctx) = 0; /// Clears the exclusive monitor's state. virtual void ClearExclusiveState() = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp new file mode 100644 index 000000000..187a972ac --- /dev/null +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -0,0 +1,208 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include "common/microprofile.h" +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#include "core/arm/dynarmic/arm_dynarmic_cp15.h" +#include "core/core.h" +#include "core/core_manager.h" +#include "core/core_timing.h" +#include "core/hle/kernel/svc.h" +#include "core/memory.h" + +namespace Core { + +class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { +public: + explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent) : parent(parent) {} + + u8 MemoryRead8(u32 vaddr) override { + return parent.system.Memory().Read8(vaddr); + } + u16 MemoryRead16(u32 vaddr) override { + return parent.system.Memory().Read16(vaddr); + } + u32 MemoryRead32(u32 vaddr) override { + return parent.system.Memory().Read32(vaddr); + } + u64 MemoryRead64(u32 vaddr) override { + return parent.system.Memory().Read64(vaddr); + } + + void MemoryWrite8(u32 vaddr, u8 value) override { + parent.system.Memory().Write8(vaddr, value); + } + void MemoryWrite16(u32 vaddr, u16 value) override { + parent.system.Memory().Write16(vaddr, value); + } + void MemoryWrite32(u32 vaddr, u32 value) override { + parent.system.Memory().Write32(vaddr, value); + } + void MemoryWrite64(u32 vaddr, u64 value) override { + parent.system.Memory().Write64(vaddr, value); + } + + void InterpreterFallback(u32 pc, std::size_t num_instructions) override { + UNIMPLEMENTED(); + } + + void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { + switch (exception) { + case Dynarmic::A32::Exception::UndefinedInstruction: + case Dynarmic::A32::Exception::UnpredictableInstruction: + break; + case Dynarmic::A32::Exception::Breakpoint: + break; + } + LOG_CRITICAL(HW_GPU, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", + static_cast(exception), pc, MemoryReadCode(pc)); + UNIMPLEMENTED(); + } + + void CallSVC(u32 swi) override { + Kernel::CallSVC(parent.system, swi); + } + + void AddTicks(u64 ticks) override { + // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a + // rough approximation of the amount of executed ticks in the system, it may be thrown off + // if not all cores are doing a similar amount of work. Instead of doing this, we should + // device a way so that timing is consistent across all cores without increasing the ticks 4 + // times. + u64 amortized_ticks = (ticks - num_interpreted_instructions) / Core::NUM_CPU_CORES; + // Always execute at least one tick. + amortized_ticks = std::max(amortized_ticks, 1); + + parent.system.CoreTiming().AddTicks(amortized_ticks); + num_interpreted_instructions = 0; + } + u64 GetTicksRemaining() override { + return std::max(parent.system.CoreTiming().GetDowncount(), {}); + } + + ARM_Dynarmic_32& parent; + std::size_t num_interpreted_instructions{}; + u64 tpidrro_el0{}; + u64 tpidr_el0{}; +}; + +std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, + std::size_t address_space_bits) const { + Dynarmic::A32::UserConfig config; + config.callbacks = cb.get(); + // TODO(bunnei): Implement page table for 32-bit + // config.page_table = &page_table.pointers; + config.coprocessors[15] = std::make_shared((u32*)&CP15_regs[0]); + config.define_unpredictable_behaviour = true; + return std::make_unique(config); +} + +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_32, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); + +void ARM_Dynarmic_32::Run() { + MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_32); + jit->Run(); +} + +void ARM_Dynarmic_32::Step() { + cb->InterpreterFallback(jit->Regs()[15], 1); +} + +ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor, + std::size_t core_index) + : ARM_Interface{system}, + cb(std::make_unique(*this)), core_index{core_index}, + exclusive_monitor{dynamic_cast(exclusive_monitor)} {} + +ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; + +void ARM_Dynarmic_32::SetPC(u64 pc) { + jit->Regs()[15] = static_cast(pc); +} + +u64 ARM_Dynarmic_32::GetPC() const { + return jit->Regs()[15]; +} + +u64 ARM_Dynarmic_32::GetReg(int index) const { + return jit->Regs()[index]; +} + +void ARM_Dynarmic_32::SetReg(int index, u64 value) { + jit->Regs()[index] = static_cast(value); +} + +u128 ARM_Dynarmic_32::GetVectorReg(int index) const { + return {}; +} + +void ARM_Dynarmic_32::SetVectorReg(int index, u128 value) {} + +u32 ARM_Dynarmic_32::GetPSTATE() const { + return jit->Cpsr(); +} + +void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) { + jit->SetCpsr(cpsr); +} + +u64 ARM_Dynarmic_32::GetTlsAddress() const { + return CP15_regs[static_cast(CP15Register::CP15_THREAD_URO)]; +} + +void ARM_Dynarmic_32::SetTlsAddress(VAddr address) { + CP15_regs[static_cast(CP15Register::CP15_THREAD_URO)] = static_cast(address); +} + +u64 ARM_Dynarmic_32::GetTPIDR_EL0() const { + return cb->tpidr_el0; +} + +void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { + cb->tpidr_el0 = value; +} + +void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { + Dynarmic::A32::Context context; + jit->SaveContext(context); + ctx.cpu_registers = context.Regs(); + ctx.cpsr = context.Cpsr(); +} + +void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { + Dynarmic::A32::Context context; + context.Regs() = ctx.cpu_registers; + context.SetCpsr(ctx.cpsr); + jit->LoadContext(context); +} + +void ARM_Dynarmic_32::PrepareReschedule() { + jit->HaltExecution(); +} + +void ARM_Dynarmic_32::ClearInstructionCache() { + jit->ClearCache(); +} + +void ARM_Dynarmic_32::ClearExclusiveState() {} + +void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, + std::size_t new_address_space_size_in_bits) { + auto key = std::make_pair(&page_table, new_address_space_size_in_bits); + auto iter = jit_cache.find(key); + if (iter != jit_cache.end()) { + jit = iter->second; + return; + } + jit = MakeJit(page_table, new_address_space_size_in_bits); + jit_cache.emplace(key, jit); +} + +} // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h new file mode 100644 index 000000000..143e46e4d --- /dev/null +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -0,0 +1,77 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include +#include +#include +#include "common/common_types.h" +#include "common/hash.h" +#include "core/arm/arm_interface.h" +#include "core/arm/exclusive_monitor.h" + +namespace Memory { +class Memory; +} + +namespace Core { + +class DynarmicCallbacks32; +class DynarmicExclusiveMonitor; +class System; + +class ARM_Dynarmic_32 final : public ARM_Interface { +public: + ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); + ~ARM_Dynarmic_32() override; + + void SetPC(u64 pc) override; + u64 GetPC() const override; + u64 GetReg(int index) const override; + void SetReg(int index, u64 value) 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; + VAddr GetTlsAddress() const override; + void SetTlsAddress(VAddr address) override; + void SetTPIDR_EL0(u64 value) override; + u64 GetTPIDR_EL0() const override; + + void SaveContext(ThreadContext32& ctx) override; + void SaveContext(ThreadContext64& ctx) override {} + void LoadContext(const ThreadContext32& ctx) override; + void LoadContext(const ThreadContext64& ctx) override {} + + void PrepareReschedule() override; + void ClearExclusiveState() override; + + void ClearInstructionCache() override; + void PageTableChanged(Common::PageTable& new_page_table, + std::size_t new_address_space_size_in_bits) override; + +private: + std::shared_ptr MakeJit(Common::PageTable& page_table, + std::size_t address_space_bits) const; + + using JitCacheKey = std::pair; + using JitCacheType = + std::unordered_map, Common::PairHash>; + + friend class DynarmicCallbacks32; + std::unique_ptr cb; + JitCacheType jit_cache; + std::shared_ptr jit; + std::size_t core_index; + DynarmicExclusiveMonitor& exclusive_monitor; + std::array CP15_regs{}; +}; + +} // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp similarity index 81% rename from src/core/arm/dynarmic/arm_dynarmic.cpp rename to src/core/arm/dynarmic/arm_dynarmic_64.cpp index 7c9d59ab8..a53a58ba0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -8,7 +8,7 @@ #include #include "common/logging/log.h" #include "common/microprofile.h" -#include "core/arm/dynarmic/arm_dynarmic.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" #include "core/core.h" #include "core/core_manager.h" #include "core/core_timing.h" @@ -25,9 +25,9 @@ namespace Core { using Vector = Dynarmic::A64::Vector; -class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks { +class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { public: - explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} + explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent) : parent(parent) {} u8 MemoryRead8(u64 vaddr) override { return parent.system.Memory().Read8(vaddr); @@ -68,7 +68,7 @@ public: LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, num_instructions, MemoryReadCode(pc)); - ARM_Interface::ThreadContext ctx; + ARM_Interface::ThreadContext64 ctx; parent.SaveContext(ctx); parent.inner_unicorn.LoadContext(ctx); parent.inner_unicorn.ExecuteInstructions(num_instructions); @@ -90,7 +90,7 @@ public: parent.jit->HaltExecution(); parent.SetPC(pc); Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread(); - parent.SaveContext(thread->GetContext()); + parent.SaveContext(thread->GetContext64()); GDBStub::Break(); GDBStub::SendTrap(thread, 5); return; @@ -126,14 +126,14 @@ public: return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks()); } - ARM_Dynarmic& parent; + ARM_Dynarmic_64& parent; std::size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; }; -std::shared_ptr ARM_Dynarmic::MakeJit(Common::PageTable& page_table, - std::size_t address_space_bits) const { +std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, + std::size_t address_space_bits) const { Dynarmic::A64::UserConfig config; // Callbacks @@ -162,76 +162,76 @@ std::shared_ptr ARM_Dynarmic::MakeJit(Common::PageTable& pag return std::make_shared(config); } -MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_64, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); -void ARM_Dynarmic::Run() { - MICROPROFILE_SCOPE(ARM_Jit_Dynarmic); +void ARM_Dynarmic_64::Run() { + MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_64); jit->Run(); } -void ARM_Dynarmic::Step() { +void ARM_Dynarmic_64::Step() { cb->InterpreterFallback(jit->GetPC(), 1); } -ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, - std::size_t core_index) +ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, ExclusiveMonitor& exclusive_monitor, + std::size_t core_index) : ARM_Interface{system}, - cb(std::make_unique(*this)), inner_unicorn{system}, + cb(std::make_unique(*this)), inner_unicorn{system}, core_index{core_index}, exclusive_monitor{ dynamic_cast(exclusive_monitor)} {} -ARM_Dynarmic::~ARM_Dynarmic() = default; +ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; -void ARM_Dynarmic::SetPC(u64 pc) { +void ARM_Dynarmic_64::SetPC(u64 pc) { jit->SetPC(pc); } -u64 ARM_Dynarmic::GetPC() const { +u64 ARM_Dynarmic_64::GetPC() const { return jit->GetPC(); } -u64 ARM_Dynarmic::GetReg(int index) const { +u64 ARM_Dynarmic_64::GetReg(int index) const { return jit->GetRegister(index); } -void ARM_Dynarmic::SetReg(int index, u64 value) { +void ARM_Dynarmic_64::SetReg(int index, u64 value) { jit->SetRegister(index, value); } -u128 ARM_Dynarmic::GetVectorReg(int index) const { +u128 ARM_Dynarmic_64::GetVectorReg(int index) const { return jit->GetVector(index); } -void ARM_Dynarmic::SetVectorReg(int index, u128 value) { +void ARM_Dynarmic_64::SetVectorReg(int index, u128 value) { jit->SetVector(index, value); } -u32 ARM_Dynarmic::GetPSTATE() const { +u32 ARM_Dynarmic_64::GetPSTATE() const { return jit->GetPstate(); } -void ARM_Dynarmic::SetPSTATE(u32 pstate) { +void ARM_Dynarmic_64::SetPSTATE(u32 pstate) { jit->SetPstate(pstate); } -u64 ARM_Dynarmic::GetTlsAddress() const { +u64 ARM_Dynarmic_64::GetTlsAddress() const { return cb->tpidrro_el0; } -void ARM_Dynarmic::SetTlsAddress(VAddr address) { +void ARM_Dynarmic_64::SetTlsAddress(VAddr address) { cb->tpidrro_el0 = address; } -u64 ARM_Dynarmic::GetTPIDR_EL0() const { +u64 ARM_Dynarmic_64::GetTPIDR_EL0() const { return cb->tpidr_el0; } -void ARM_Dynarmic::SetTPIDR_EL0(u64 value) { +void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } -void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { +void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); ctx.pc = jit->GetPC(); @@ -242,7 +242,7 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { ctx.tpidr = cb->tpidr_el0; } -void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { +void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { jit->SetRegisters(ctx.cpu_registers); jit->SetSP(ctx.sp); jit->SetPC(ctx.pc); @@ -253,20 +253,20 @@ void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { SetTPIDR_EL0(ctx.tpidr); } -void ARM_Dynarmic::PrepareReschedule() { +void ARM_Dynarmic_64::PrepareReschedule() { jit->HaltExecution(); } -void ARM_Dynarmic::ClearInstructionCache() { +void ARM_Dynarmic_64::ClearInstructionCache() { jit->ClearCache(); } -void ARM_Dynarmic::ClearExclusiveState() { +void ARM_Dynarmic_64::ClearExclusiveState() { jit->ClearExclusiveState(); } -void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table, - std::size_t new_address_space_size_in_bits) { +void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, + std::size_t new_address_space_size_in_bits) { auto key = std::make_pair(&page_table, new_address_space_size_in_bits); auto iter = jit_cache.find(key); if (iter != jit_cache.end()) { @@ -277,8 +277,8 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table, jit_cache.emplace(key, jit); } -DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count) - : monitor(core_count), memory{memory_} {} +DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count) + : monitor(core_count), memory{memory} {} DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic_64.h similarity index 74% rename from src/core/arm/dynarmic/arm_dynarmic.h rename to src/core/arm/dynarmic/arm_dynarmic_64.h index ffbb69d76..e71240a96 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -21,18 +21,14 @@ class Memory; namespace Core { -class ARM_Dynarmic_Callbacks; +class DynarmicCallbacks64; class DynarmicExclusiveMonitor; class System; -using JitCacheKey = std::pair; -using JitCacheType = - std::unordered_map, Common::PairHash>; - -class ARM_Dynarmic final : public ARM_Interface { +class ARM_Dynarmic_64 final : public ARM_Interface { public: - ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); - ~ARM_Dynarmic() override; + ARM_Dynarmic_64(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); + ~ARM_Dynarmic_64() override; void SetPC(u64 pc) override; u64 GetPC() const override; @@ -49,8 +45,10 @@ public: void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void SaveContext(ThreadContext& ctx) override; - void LoadContext(const ThreadContext& ctx) override; + void SaveContext(ThreadContext32& ctx) override {} + void SaveContext(ThreadContext64& ctx) override; + void LoadContext(const ThreadContext32& ctx) override {} + void LoadContext(const ThreadContext64& ctx) override; void PrepareReschedule() override; void ClearExclusiveState() override; @@ -63,8 +61,12 @@ private: std::shared_ptr MakeJit(Common::PageTable& page_table, std::size_t address_space_bits) const; - friend class ARM_Dynarmic_Callbacks; - std::unique_ptr cb; + using JitCacheKey = std::pair; + using JitCacheType = + std::unordered_map, Common::PairHash>; + + friend class DynarmicCallbacks64; + std::unique_ptr cb; JitCacheType jit_cache; std::shared_ptr jit; ARM_Unicorn inner_unicorn; @@ -75,7 +77,7 @@ private: class DynarmicExclusiveMonitor final : public ExclusiveMonitor { public: - explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count); + explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); ~DynarmicExclusiveMonitor() override; void SetExclusive(std::size_t core_index, VAddr addr) override; @@ -88,7 +90,7 @@ public: bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override; private: - friend class ARM_Dynarmic; + friend class ARM_Dynarmic_64; Dynarmic::A64::ExclusiveMonitor monitor; Memory::Memory& memory; }; diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp index 94570e520..b32401e0b 100644 --- a/src/core/arm/exclusive_monitor.cpp +++ b/src/core/arm/exclusive_monitor.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" #endif #include "core/arm/exclusive_monitor.h" #include "core/memory.h" diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index f99ad5802..8a9800a96 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -53,7 +53,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si void* user_data) { auto* const system = static_cast(user_data); - ARM_Interface::ThreadContext ctx{}; + ARM_Interface::ThreadContext64 ctx{}; system->CurrentArmInterface().SaveContext(ctx); ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr, ctx.pc, ctx.cpu_registers[30]); @@ -179,7 +179,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { } Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread(); - SaveContext(thread->GetContext()); + SaveContext(thread->GetContext64()); if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) { last_bkpt_hit = false; GDBStub::Break(); @@ -188,7 +188,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { } } -void ARM_Unicorn::SaveContext(ThreadContext& ctx) { +void ARM_Unicorn::SaveContext(ThreadContext64& ctx) { int uregs[32]; void* tregs[32]; @@ -215,7 +215,7 @@ void ARM_Unicorn::SaveContext(ThreadContext& ctx) { CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32)); } -void ARM_Unicorn::LoadContext(const ThreadContext& ctx) { +void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) { int uregs[32]; void* tregs[32]; diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 3c5b155f9..f30d13cb6 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -30,8 +30,6 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void SaveContext(ThreadContext& ctx) override; - void LoadContext(const ThreadContext& ctx) override; void PrepareReschedule() override; void ClearExclusiveState() override; void ExecuteInstructions(std::size_t num_instructions); @@ -41,6 +39,11 @@ public: void PageTableChanged(Common::PageTable&, std::size_t) override {} void RecordBreak(GDBStub::BreakpointAddress bkpt); + void SaveContext(ThreadContext32& ctx) override {} + void SaveContext(ThreadContext64& ctx) override; + void LoadContext(const ThreadContext32& ctx) override {} + void LoadContext(const ThreadContext64& ctx) override; + private: static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data); diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp index 8eacf92dd..b6b797c80 100644 --- a/src/core/core_manager.cpp +++ b/src/core/core_manager.cpp @@ -6,9 +6,6 @@ #include #include "common/logging/log.h" -#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.h" diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 67e95999d..e8d8871a7 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -217,7 +217,7 @@ static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) { return 0; } - const auto& thread_context = thread->GetContext(); + const auto& thread_context = thread->GetContext64(); if (id < SP_REGISTER) { return thread_context.cpu_registers[id]; @@ -239,7 +239,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) return; } - auto& thread_context = thread->GetContext(); + auto& thread_context = thread->GetContext64(); if (id < SP_REGISTER) { thread_context.cpu_registers[id] = val; @@ -259,7 +259,7 @@ static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) { return u128{0}; } - auto& thread_context = thread->GetContext(); + auto& thread_context = thread->GetContext64(); if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; @@ -275,7 +275,7 @@ static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) return; } - auto& thread_context = thread->GetContext(); + auto& thread_context = thread->GetContext64(); if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; @@ -916,7 +916,7 @@ static void WriteRegister() { // Update ARM context, skipping scheduler - no running threads at this point Core::System::GetInstance() .ArmInterface(current_core) - .LoadContext(current_thread->GetContext()); + .LoadContext(current_thread->GetContext64()); SendReply("OK"); } @@ -947,7 +947,7 @@ static void WriteRegisters() { // Update ARM context, skipping scheduler - no running threads at this point Core::System::GetInstance() .ArmInterface(current_core) - .LoadContext(current_thread->GetContext()); + .LoadContext(current_thread->GetContext64()); SendReply("OK"); } @@ -1019,7 +1019,7 @@ static void Step() { // Update ARM context, skipping scheduler - no running threads at this point Core::System::GetInstance() .ArmInterface(current_core) - .LoadContext(current_thread->GetContext()); + .LoadContext(current_thread->GetContext64()); } step_loop = true; halt_loop = true; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 9232f4d7e..e47f1deed 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -186,6 +186,10 @@ struct KernelCore::Impl { return; } + for (auto& core : cores) { + core.SetIs64Bit(process->Is64BitProcess()); + } + system.Memory().SetCurrentPageTable(*process); } diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 9303dd273..aa2787467 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -5,7 +5,8 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic.h" +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" #endif #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" @@ -20,13 +21,17 @@ PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor) : core_index{id} { #ifdef ARCHITECTURE_x86_64 - arm_interface = std::make_unique(system, exclusive_monitor, core_index); + arm_interface_32 = + std::make_unique(system, exclusive_monitor, core_index); + arm_interface_64 = + std::make_unique(system, exclusive_monitor, core_index); + #else arm_interface = std::make_shared(system); LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif - scheduler = std::make_unique(system, *arm_interface, core_index); + scheduler = std::make_unique(system, core_index); } PhysicalCore::~PhysicalCore() = default; @@ -48,4 +53,12 @@ void PhysicalCore::Shutdown() { scheduler->Shutdown(); } +void PhysicalCore::SetIs64Bit(bool is_64_bit) { + if (is_64_bit) { + arm_interface = arm_interface_64.get(); + } else { + arm_interface = arm_interface_32.get(); + } +} + } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 4c32c0f1b..3269166be 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -68,10 +68,14 @@ public: return *scheduler; } + void SetIs64Bit(bool is_64_bit); + private: std::size_t core_index; - std::unique_ptr arm_interface; + std::unique_ptr arm_interface_32; + std::unique_ptr arm_interface_64; std::unique_ptr scheduler; + Core::ARM_Interface* arm_interface{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 2fcb7326c..edc414d69 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -42,7 +42,8 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) { // Register 1 must be a handle to the main thread const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); - thread->GetContext().cpu_registers[1] = thread_handle; + thread->GetContext32().cpu_registers[1] = thread_handle; + thread->GetContext64().cpu_registers[1] = thread_handle; // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires thread->ResumeFromWait(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index c65f82fb7..1140c72a3 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -383,8 +383,8 @@ void GlobalScheduler::Unlock() { // TODO(Blinkhawk): Setup the interrupts and change context on current core. } -Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) - : system(system), cpu_core(cpu_core), core_id(core_id) {} +Scheduler::Scheduler(Core::System& system, std::size_t core_id) + : system{system}, core_id{core_id} {} Scheduler::~Scheduler() = default; @@ -422,9 +422,10 @@ void Scheduler::UnloadThread() { // Save context for previous thread if (previous_thread) { - cpu_core.SaveContext(previous_thread->GetContext()); + system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32()); + system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0()); if (previous_thread->GetStatus() == ThreadStatus::Running) { // This is only the case when a reschedule is triggered without the current thread @@ -451,9 +452,10 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { - cpu_core.SaveContext(previous_thread->GetContext()); + system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32()); + system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0()); if (previous_thread->GetStatus() == ThreadStatus::Running) { // This is only the case when a reschedule is triggered without the current thread @@ -481,9 +483,10 @@ void Scheduler::SwitchContext() { system.Kernel().MakeCurrentProcess(thread_owner_process); } - cpu_core.LoadContext(new_thread->GetContext()); - cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); - cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + system.ArmInterface(core_id).LoadContext(new_thread->GetContext32()); + system.ArmInterface(core_id).LoadContext(new_thread->GetContext64()); + system.ArmInterface(core_id).SetTlsAddress(new_thread->GetTLSAddress()); + system.ArmInterface(core_id).SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); } else { current_thread = nullptr; // Note: We do not reset the current process and current page table when idling because diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 1c93a838c..07df33f9c 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -181,7 +181,7 @@ private: class Scheduler final { public: - explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id); + explicit Scheduler(Core::System& system, std::size_t core_id); ~Scheduler(); /// Returns whether there are any threads that are ready to run. @@ -235,7 +235,6 @@ private: std::shared_ptr selected_thread = nullptr; Core::System& system; - Core::ARM_Interface& cpu_core; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; const std::size_t core_id; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bf850e0b2..83e956036 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -133,15 +133,16 @@ void Thread::CancelWait() { ResumeFromWait(); } -/** - * Resets a thread context, making it ready to be scheduled and run by the CPU - * @param context Thread context to reset - * @param stack_top Address of the top of the stack - * @param entry_point Address of entry point for execution - * @param arg User argument for thread - */ -static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAddr stack_top, - VAddr entry_point, u64 arg) { +static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, + u32 entry_point, u32 arg) { + context = {}; + context.cpu_registers[0] = arg; + context.cpu_registers[15] = entry_point; + context.cpu_registers[13] = stack_top; +} + +static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top, + VAddr entry_point, u64 arg) { context = {}; context.cpu_registers[0] = arg; context.pc = entry_point; @@ -198,9 +199,9 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->owner_process->RegisterThread(thread.get()); - // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used - // to initialize the context - ResetThreadContext(thread->context, stack_top, entry_point, arg); + ResetThreadContext32(thread->context_32, static_cast(stack_top), + static_cast(entry_point), static_cast(arg)); + ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); return MakeResult>(std::move(thread)); } @@ -213,11 +214,13 @@ void Thread::SetPriority(u32 priority) { } void Thread::SetWaitSynchronizationResult(ResultCode result) { - context.cpu_registers[0] = result.raw; + context_32.cpu_registers[0] = result.raw; + context_64.cpu_registers[0] = result.raw; } void Thread::SetWaitSynchronizationOutput(s32 output) { - context.cpu_registers[1] = output; + context_32.cpu_registers[1] = output; + context_64.cpu_registers[1] = output; } s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 129e7858a..23fdef8a4 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -102,7 +102,8 @@ public: using MutexWaitingThreads = std::vector>; - using ThreadContext = Core::ARM_Interface::ThreadContext; + using ThreadContext32 = Core::ARM_Interface::ThreadContext32; + using ThreadContext64 = Core::ARM_Interface::ThreadContext64; using ThreadSynchronizationObjects = std::vector>; @@ -273,12 +274,20 @@ public: return status == ThreadStatus::WaitSynch; } - ThreadContext& GetContext() { - return context; + ThreadContext32& GetContext32() { + return context_32; } - const ThreadContext& GetContext() const { - return context; + const ThreadContext32& GetContext32() const { + return context_32; + } + + ThreadContext64& GetContext64() { + return context_64; + } + + const ThreadContext64& GetContext64() const { + return context_64; } ThreadStatus GetStatus() const { @@ -466,7 +475,8 @@ private: void AdjustSchedulingOnPriority(u32 old_priority); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); - Core::ARM_Interface::ThreadContext context{}; + ThreadContext32 context_32{}; + ThreadContext64 context_64{}; u64 thread_id = 0; diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index f95eee3b1..85ac81ef7 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -111,7 +111,7 @@ json GetProcessorStateDataAuto(Core::System& system) { const auto& vm_manager{process->VMManager()}; auto& arm{system.CurrentArmInterface()}; - Core::ARM_Interface::ThreadContext context{}; + Core::ARM_Interface::ThreadContext64 context{}; arm.SaveContext(context); return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 3f1a94627..c1ea25fb8 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -116,7 +116,7 @@ std::vector> WaitTreeCallstack::GetChildren() cons constexpr std::size_t BaseRegister = 29; auto& memory = Core::System::GetInstance().Memory(); - u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister]; + u64 base_pointer = thread.GetContext64().cpu_registers[BaseRegister]; while (base_pointer != 0) { const u64 lr = memory.Read64(base_pointer + sizeof(u64)); @@ -240,7 +240,7 @@ QString WaitTreeThread::GetText() const { break; } - const auto& context = thread.GetContext(); + const auto& context = thread.GetContext64(); const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") .arg(context.pc, 8, 16, QLatin1Char{'0'}) .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); From dba112e51059f5e6107d02a0eb00513887d3b089 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 2 Mar 2020 00:06:41 -0500 Subject: [PATCH 4/4] core: hle: Implement separate A32/A64 SVC interfaces. --- src/core/hle/kernel/svc.cpp | 329 ++++++++++++++++++++++++++------- src/core/hle/kernel/svc_wrap.h | 158 +++++++++++----- 2 files changed, 380 insertions(+), 107 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index fd91779a3..4ffc113c2 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -187,6 +187,13 @@ static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_s return RESULT_SUCCESS; } +static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_size) { + VAddr temp_heap_addr{}; + const ResultCode result{SetHeapSize(system, &temp_heap_addr, heap_size)}; + *heap_addr = static_cast(temp_heap_addr); + return result; +} + static ResultCode SetMemoryPermission(Core::System& system, VAddr addr, u64 size, u32 prot) { LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot); @@ -371,6 +378,12 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, return RESULT_SUCCESS; } +static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, + u32 port_name_address) { + + return ConnectToNamedPort(system, out_handle, port_name_address); +} + /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); @@ -390,6 +403,10 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { return session->SendSyncRequest(SharedFrom(thread), system.Memory()); } +static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { + return SendSyncRequest(system, handle); +} + /// Get the ID for the specified thread. static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); @@ -405,6 +422,17 @@ static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle threa return RESULT_SUCCESS; } +static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high, + Handle thread_handle) { + u64 thread_id{}; + const ResultCode result{GetThreadId(system, &thread_id, thread_handle)}; + + *thread_id_low = static_cast(thread_id >> 32); + *thread_id_high = static_cast(thread_id & std::numeric_limits::max()); + + return result; +} + /// Gets the ID of the specified process or a specified thread's owning process. static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); @@ -479,6 +507,12 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr return result; } +static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, + s32 handle_count, u32 timeout_high, Handle* index) { + const s64 nano_seconds{(static_cast(timeout_high) << 32) | static_cast(timeout_low)}; + return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); +} + /// Resumes a thread waiting on WaitSynchronization static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); @@ -917,6 +951,18 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha } } +static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low, + u32 info_id, u32 handle, u32 sub_id_high) { + const u64 sub_id{static_cast(sub_id_low | (static_cast(sub_id_high) << 32))}; + u64 res_value{}; + + const ResultCode result{GetInfo(system, &res_value, info_id, handle, sub_id)}; + *result_high = static_cast(res_value >> 32); + *result_low = static_cast(res_value & std::numeric_limits::max()); + + return result; +} + /// Maps memory at a desired address static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); @@ -1058,7 +1104,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H return ERR_BUSY; } - Core::ARM_Interface::ThreadContext ctx = thread->GetContext(); + Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64(); // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. ctx.pstate &= 0xFF0FFE20; @@ -1088,6 +1134,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle return RESULT_SUCCESS; } +static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) { + return GetThreadPriority(system, priority, handle); +} + /// Sets the priority for the specified thread static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { LOG_TRACE(Kernel_SVC, "called"); @@ -1259,6 +1309,11 @@ static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address, query_address); } +static ResultCode QueryMemory32(Core::System& system, u32 memory_info_address, + u32 page_info_address, u32 query_address) { + return QueryMemory(system, memory_info_address, page_info_address, query_address); +} + static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, u64 src_address, u64 size) { LOG_DEBUG(Kernel_SVC, @@ -1675,6 +1730,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ } } +static void SignalProcessWideKey32(Core::System& system, u32 condition_variable_addr, s32 target) { + SignalProcessWideKey(system, condition_variable_addr, target); +} + // Wait for an address (via Address Arbiter) static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, s32 value, s64 timeout) { @@ -1760,6 +1819,10 @@ static ResultCode CloseHandle(Core::System& system, Handle handle) { return handle_table.Close(handle); } +static ResultCode CloseHandle32(Core::System& system, Handle handle) { + return CloseHandle(system, handle); +} + /// Clears the signaled state of an event or process. static ResultCode ResetSignal(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); @@ -2317,69 +2380,196 @@ struct FunctionDef { }; } // namespace -static const FunctionDef SVC_Table[] = { +static const FunctionDef SVC_Table_32[] = { {0x00, nullptr, "Unknown"}, - {0x01, SvcWrap, "SetHeapSize"}, - {0x02, SvcWrap, "SetMemoryPermission"}, - {0x03, SvcWrap, "SetMemoryAttribute"}, - {0x04, SvcWrap, "MapMemory"}, - {0x05, SvcWrap, "UnmapMemory"}, - {0x06, SvcWrap, "QueryMemory"}, - {0x07, SvcWrap, "ExitProcess"}, - {0x08, SvcWrap, "CreateThread"}, - {0x09, SvcWrap, "StartThread"}, - {0x0A, SvcWrap, "ExitThread"}, - {0x0B, SvcWrap, "SleepThread"}, - {0x0C, SvcWrap, "GetThreadPriority"}, - {0x0D, SvcWrap, "SetThreadPriority"}, - {0x0E, SvcWrap, "GetThreadCoreMask"}, - {0x0F, SvcWrap, "SetThreadCoreMask"}, - {0x10, SvcWrap, "GetCurrentProcessorNumber"}, - {0x11, SvcWrap, "SignalEvent"}, - {0x12, SvcWrap, "ClearEvent"}, - {0x13, SvcWrap, "MapSharedMemory"}, - {0x14, SvcWrap, "UnmapSharedMemory"}, - {0x15, SvcWrap, "CreateTransferMemory"}, - {0x16, SvcWrap, "CloseHandle"}, - {0x17, SvcWrap, "ResetSignal"}, - {0x18, SvcWrap, "WaitSynchronization"}, - {0x19, SvcWrap, "CancelSynchronization"}, - {0x1A, SvcWrap, "ArbitrateLock"}, - {0x1B, SvcWrap, "ArbitrateUnlock"}, - {0x1C, SvcWrap, "WaitProcessWideKeyAtomic"}, - {0x1D, SvcWrap, "SignalProcessWideKey"}, - {0x1E, SvcWrap, "GetSystemTick"}, - {0x1F, SvcWrap, "ConnectToNamedPort"}, + {0x01, SvcWrap32, "SetHeapSize32"}, + {0x02, nullptr, "Unknown"}, + {0x03, nullptr, "SetMemoryAttribute32"}, + {0x04, nullptr, "MapMemory32"}, + {0x05, nullptr, "UnmapMemory32"}, + {0x06, SvcWrap32, "QueryMemory32"}, + {0x07, nullptr, "ExitProcess32"}, + {0x08, nullptr, "CreateThread32"}, + {0x09, nullptr, "StartThread32"}, + {0x0a, nullptr, "ExitThread32"}, + {0x0b, nullptr, "SleepThread32"}, + {0x0c, SvcWrap32, "GetThreadPriority32"}, + {0x0d, nullptr, "SetThreadPriority32"}, + {0x0e, nullptr, "GetThreadCoreMask32"}, + {0x0f, nullptr, "SetThreadCoreMask32"}, + {0x10, nullptr, "GetCurrentProcessorNumber32"}, + {0x11, nullptr, "SignalEvent32"}, + {0x12, nullptr, "ClearEvent32"}, + {0x13, nullptr, "MapSharedMemory32"}, + {0x14, nullptr, "UnmapSharedMemory32"}, + {0x15, nullptr, "CreateTransferMemory32"}, + {0x16, SvcWrap32, "CloseHandle32"}, + {0x17, nullptr, "ResetSignal32"}, + {0x18, SvcWrap32, "WaitSynchronization32"}, + {0x19, nullptr, "CancelSynchronization32"}, + {0x1a, nullptr, "ArbitrateLock32"}, + {0x1b, nullptr, "ArbitrateUnlock32"}, + {0x1c, nullptr, "WaitProcessWideKeyAtomic32"}, + {0x1d, SvcWrap32, "SignalProcessWideKey32"}, + {0x1e, nullptr, "GetSystemTick32"}, + {0x1f, SvcWrap32, "ConnectToNamedPort32"}, + {0x20, nullptr, "Unknown"}, + {0x21, SvcWrap32, "SendSyncRequest32"}, + {0x22, nullptr, "SendSyncRequestWithUserBuffer32"}, + {0x23, nullptr, "Unknown"}, + {0x24, nullptr, "GetProcessId32"}, + {0x25, SvcWrap32, "GetThreadId32"}, + {0x26, nullptr, "Break32"}, + {0x27, nullptr, "OutputDebugString32"}, + {0x28, nullptr, "Unknown"}, + {0x29, SvcWrap32, "GetInfo32"}, + {0x2a, nullptr, "Unknown"}, + {0x2b, nullptr, "Unknown"}, + {0x2c, nullptr, "MapPhysicalMemory32"}, + {0x2d, nullptr, "UnmapPhysicalMemory32"}, + {0x2e, nullptr, "Unknown"}, + {0x2f, nullptr, "Unknown"}, + {0x30, nullptr, "Unknown"}, + {0x31, nullptr, "Unknown"}, + {0x32, nullptr, "SetThreadActivity32"}, + {0x33, nullptr, "GetThreadContext32"}, + {0x34, nullptr, "WaitForAddress32"}, + {0x35, nullptr, "SignalToAddress32"}, + {0x36, nullptr, "Unknown"}, + {0x37, nullptr, "Unknown"}, + {0x38, nullptr, "Unknown"}, + {0x39, nullptr, "Unknown"}, + {0x3a, nullptr, "Unknown"}, + {0x3b, nullptr, "Unknown"}, + {0x3c, nullptr, "Unknown"}, + {0x3d, nullptr, "Unknown"}, + {0x3e, nullptr, "Unknown"}, + {0x3f, nullptr, "Unknown"}, + {0x40, nullptr, "CreateSession32"}, + {0x41, nullptr, "AcceptSession32"}, + {0x42, nullptr, "Unknown"}, + {0x43, nullptr, "ReplyAndReceive32"}, + {0x44, nullptr, "Unknown"}, + {0x45, nullptr, "CreateEvent32"}, + {0x46, nullptr, "Unknown"}, + {0x47, nullptr, "Unknown"}, + {0x48, nullptr, "Unknown"}, + {0x49, nullptr, "Unknown"}, + {0x4a, nullptr, "Unknown"}, + {0x4b, nullptr, "Unknown"}, + {0x4c, nullptr, "Unknown"}, + {0x4d, nullptr, "Unknown"}, + {0x4e, nullptr, "Unknown"}, + {0x4f, nullptr, "Unknown"}, + {0x50, nullptr, "Unknown"}, + {0x51, nullptr, "Unknown"}, + {0x52, nullptr, "Unknown"}, + {0x53, nullptr, "Unknown"}, + {0x54, nullptr, "Unknown"}, + {0x55, nullptr, "Unknown"}, + {0x56, nullptr, "Unknown"}, + {0x57, nullptr, "Unknown"}, + {0x58, nullptr, "Unknown"}, + {0x59, nullptr, "Unknown"}, + {0x5a, nullptr, "Unknown"}, + {0x5b, nullptr, "Unknown"}, + {0x5c, nullptr, "Unknown"}, + {0x5d, nullptr, "Unknown"}, + {0x5e, nullptr, "Unknown"}, + {0x5F, nullptr, "FlushProcessDataCache32"}, + {0x60, nullptr, "Unknown"}, + {0x61, nullptr, "Unknown"}, + {0x62, nullptr, "Unknown"}, + {0x63, nullptr, "Unknown"}, + {0x64, nullptr, "Unknown"}, + {0x65, nullptr, "GetProcessList32"}, + {0x66, nullptr, "Unknown"}, + {0x67, nullptr, "Unknown"}, + {0x68, nullptr, "Unknown"}, + {0x69, nullptr, "Unknown"}, + {0x6A, nullptr, "Unknown"}, + {0x6B, nullptr, "Unknown"}, + {0x6C, nullptr, "Unknown"}, + {0x6D, nullptr, "Unknown"}, + {0x6E, nullptr, "Unknown"}, + {0x6f, nullptr, "GetSystemInfo32"}, + {0x70, nullptr, "CreatePort32"}, + {0x71, nullptr, "ManageNamedPort32"}, + {0x72, nullptr, "ConnectToPort32"}, + {0x73, nullptr, "SetProcessMemoryPermission32"}, + {0x74, nullptr, "Unknown"}, + {0x75, nullptr, "Unknown"}, + {0x76, nullptr, "Unknown"}, + {0x77, nullptr, "MapProcessCodeMemory32"}, + {0x78, nullptr, "UnmapProcessCodeMemory32"}, + {0x79, nullptr, "Unknown"}, + {0x7A, nullptr, "Unknown"}, + {0x7B, nullptr, "TerminateProcess32"}, +}; + +static const FunctionDef SVC_Table_64[] = { + {0x00, nullptr, "Unknown"}, + {0x01, SvcWrap64, "SetHeapSize"}, + {0x02, SvcWrap64, "SetMemoryPermission"}, + {0x03, SvcWrap64, "SetMemoryAttribute"}, + {0x04, SvcWrap64, "MapMemory"}, + {0x05, SvcWrap64, "UnmapMemory"}, + {0x06, SvcWrap64, "QueryMemory"}, + {0x07, SvcWrap64, "ExitProcess"}, + {0x08, SvcWrap64, "CreateThread"}, + {0x09, SvcWrap64, "StartThread"}, + {0x0A, SvcWrap64, "ExitThread"}, + {0x0B, SvcWrap64, "SleepThread"}, + {0x0C, SvcWrap64, "GetThreadPriority"}, + {0x0D, SvcWrap64, "SetThreadPriority"}, + {0x0E, SvcWrap64, "GetThreadCoreMask"}, + {0x0F, SvcWrap64, "SetThreadCoreMask"}, + {0x10, SvcWrap64, "GetCurrentProcessorNumber"}, + {0x11, SvcWrap64, "SignalEvent"}, + {0x12, SvcWrap64, "ClearEvent"}, + {0x13, SvcWrap64, "MapSharedMemory"}, + {0x14, SvcWrap64, "UnmapSharedMemory"}, + {0x15, SvcWrap64, "CreateTransferMemory"}, + {0x16, SvcWrap64, "CloseHandle"}, + {0x17, SvcWrap64, "ResetSignal"}, + {0x18, SvcWrap64, "WaitSynchronization"}, + {0x19, SvcWrap64, "CancelSynchronization"}, + {0x1A, SvcWrap64, "ArbitrateLock"}, + {0x1B, SvcWrap64, "ArbitrateUnlock"}, + {0x1C, SvcWrap64, "WaitProcessWideKeyAtomic"}, + {0x1D, SvcWrap64, "SignalProcessWideKey"}, + {0x1E, SvcWrap64, "GetSystemTick"}, + {0x1F, SvcWrap64, "ConnectToNamedPort"}, {0x20, nullptr, "SendSyncRequestLight"}, - {0x21, SvcWrap, "SendSyncRequest"}, + {0x21, SvcWrap64, "SendSyncRequest"}, {0x22, nullptr, "SendSyncRequestWithUserBuffer"}, {0x23, nullptr, "SendAsyncRequestWithUserBuffer"}, - {0x24, SvcWrap, "GetProcessId"}, - {0x25, SvcWrap, "GetThreadId"}, - {0x26, SvcWrap, "Break"}, - {0x27, SvcWrap, "OutputDebugString"}, + {0x24, SvcWrap64, "GetProcessId"}, + {0x25, SvcWrap64, "GetThreadId"}, + {0x26, SvcWrap64, "Break"}, + {0x27, SvcWrap64, "OutputDebugString"}, {0x28, nullptr, "ReturnFromException"}, - {0x29, SvcWrap, "GetInfo"}, + {0x29, SvcWrap64, "GetInfo"}, {0x2A, nullptr, "FlushEntireDataCache"}, {0x2B, nullptr, "FlushDataCache"}, - {0x2C, SvcWrap, "MapPhysicalMemory"}, - {0x2D, SvcWrap, "UnmapPhysicalMemory"}, + {0x2C, SvcWrap64, "MapPhysicalMemory"}, + {0x2D, SvcWrap64, "UnmapPhysicalMemory"}, {0x2E, nullptr, "GetFutureThreadInfo"}, {0x2F, nullptr, "GetLastThreadInfo"}, - {0x30, SvcWrap, "GetResourceLimitLimitValue"}, - {0x31, SvcWrap, "GetResourceLimitCurrentValue"}, - {0x32, SvcWrap, "SetThreadActivity"}, - {0x33, SvcWrap, "GetThreadContext"}, - {0x34, SvcWrap, "WaitForAddress"}, - {0x35, SvcWrap, "SignalToAddress"}, + {0x30, SvcWrap64, "GetResourceLimitLimitValue"}, + {0x31, SvcWrap64, "GetResourceLimitCurrentValue"}, + {0x32, SvcWrap64, "SetThreadActivity"}, + {0x33, SvcWrap64, "GetThreadContext"}, + {0x34, SvcWrap64, "WaitForAddress"}, + {0x35, SvcWrap64, "SignalToAddress"}, {0x36, nullptr, "SynchronizePreemptionState"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, {0x39, nullptr, "Unknown"}, {0x3A, nullptr, "Unknown"}, {0x3B, nullptr, "Unknown"}, - {0x3C, SvcWrap, "KernelDebug"}, - {0x3D, SvcWrap, "ChangeKernelTraceState"}, + {0x3C, SvcWrap64, "KernelDebug"}, + {0x3D, SvcWrap64, "ChangeKernelTraceState"}, {0x3E, nullptr, "Unknown"}, {0x3F, nullptr, "Unknown"}, {0x40, nullptr, "CreateSession"}, @@ -2387,7 +2577,7 @@ static const FunctionDef SVC_Table[] = { {0x42, nullptr, "ReplyAndReceiveLight"}, {0x43, nullptr, "ReplyAndReceive"}, {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, - {0x45, SvcWrap, "CreateEvent"}, + {0x45, SvcWrap64, "CreateEvent"}, {0x46, nullptr, "Unknown"}, {0x47, nullptr, "Unknown"}, {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, @@ -2398,9 +2588,9 @@ static const FunctionDef SVC_Table[] = { {0x4D, nullptr, "SleepSystem"}, {0x4E, nullptr, "ReadWriteRegister"}, {0x4F, nullptr, "SetProcessActivity"}, - {0x50, SvcWrap, "CreateSharedMemory"}, - {0x51, SvcWrap, "MapTransferMemory"}, - {0x52, SvcWrap, "UnmapTransferMemory"}, + {0x50, SvcWrap64, "CreateSharedMemory"}, + {0x51, SvcWrap64, "MapTransferMemory"}, + {0x52, SvcWrap64, "UnmapTransferMemory"}, {0x53, nullptr, "CreateInterruptEvent"}, {0x54, nullptr, "QueryPhysicalAddress"}, {0x55, nullptr, "QueryIoMapping"}, @@ -2419,8 +2609,8 @@ static const FunctionDef SVC_Table[] = { {0x62, nullptr, "TerminateDebugProcess"}, {0x63, nullptr, "GetDebugEvent"}, {0x64, nullptr, "ContinueDebugEvent"}, - {0x65, SvcWrap, "GetProcessList"}, - {0x66, SvcWrap, "GetThreadList"}, + {0x65, SvcWrap64, "GetProcessList"}, + {0x66, SvcWrap64, "GetThreadList"}, {0x67, nullptr, "GetDebugThreadContext"}, {0x68, nullptr, "SetDebugThreadContext"}, {0x69, nullptr, "QueryDebugProcessMemory"}, @@ -2436,24 +2626,32 @@ static const FunctionDef SVC_Table[] = { {0x73, nullptr, "SetProcessMemoryPermission"}, {0x74, nullptr, "MapProcessMemory"}, {0x75, nullptr, "UnmapProcessMemory"}, - {0x76, SvcWrap, "QueryProcessMemory"}, - {0x77, SvcWrap, "MapProcessCodeMemory"}, - {0x78, SvcWrap, "UnmapProcessCodeMemory"}, + {0x76, SvcWrap64, "QueryProcessMemory"}, + {0x77, SvcWrap64, "MapProcessCodeMemory"}, + {0x78, SvcWrap64, "UnmapProcessCodeMemory"}, {0x79, nullptr, "CreateProcess"}, {0x7A, nullptr, "StartProcess"}, {0x7B, nullptr, "TerminateProcess"}, - {0x7C, SvcWrap, "GetProcessInfo"}, - {0x7D, SvcWrap, "CreateResourceLimit"}, - {0x7E, SvcWrap, "SetResourceLimitLimitValue"}, + {0x7C, SvcWrap64, "GetProcessInfo"}, + {0x7D, SvcWrap64, "CreateResourceLimit"}, + {0x7E, SvcWrap64, "SetResourceLimitLimitValue"}, {0x7F, nullptr, "CallSecureMonitor"}, }; -static const FunctionDef* GetSVCInfo(u32 func_num) { - if (func_num >= std::size(SVC_Table)) { +static const FunctionDef* GetSVCInfo32(u32 func_num) { + if (func_num >= std::size(SVC_Table_32)) { LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); return nullptr; } - return &SVC_Table[func_num]; + return &SVC_Table_32[func_num]; +} + +static const FunctionDef* GetSVCInfo64(u32 func_num) { + if (func_num >= std::size(SVC_Table_64)) { + LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); + return nullptr; + } + return &SVC_Table_64[func_num]; } MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); @@ -2464,7 +2662,8 @@ void CallSVC(Core::System& system, u32 immediate) { // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard lock{HLE::g_hle_lock}; - const FunctionDef* info = GetSVCInfo(immediate); + const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) + : GetSVCInfo32(immediate); if (info) { if (info->func) { info->func(system); diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 29a2cfa9d..7d735e3fa 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -15,6 +15,10 @@ static inline u64 Param(const Core::System& system, int n) { return system.CurrentArmInterface().GetReg(n); } +static inline u32 Param32(const Core::System& system, int n) { + return static_cast(system.CurrentArmInterface().GetReg(n)); +} + /** * HLE a function return from the current ARM userland process * @param system System context @@ -24,40 +28,44 @@ static inline void FuncReturn(Core::System& system, u64 result) { system.CurrentArmInterface().SetReg(0, result); } +static inline void FuncReturn32(Core::System& system, u32 result) { + system.CurrentArmInterface().SetReg(0, (u64)result); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type ResultCode template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0)).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), Param(system, 1)).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn( system, func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2), Param(system, 3)) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param = 0; const u32 retval = func(system, ¶m).raw; system.CurrentArmInterface().SetReg(1, param); @@ -65,7 +73,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, static_cast(Param(system, 1))).raw; system.CurrentArmInterface().SetReg(1, param_1); @@ -73,7 +81,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; u32 param_2 = 0; const u32 retval = func(system, ¶m_1, ¶m_2).raw; @@ -86,7 +94,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1)).raw; system.CurrentArmInterface().SetReg(1, param_1); @@ -94,7 +102,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast(Param(system, 2))).raw; @@ -104,7 +112,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u64 param_1 = 0; const u32 retval = func(system, ¶m_1, static_cast(Param(system, 1))).raw; @@ -113,12 +121,12 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), static_cast(Param(system, 1))).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u64 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1)).raw; @@ -127,7 +135,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u64 param_1 = 0; const u32 retval = func(system, ¶m_1, static_cast(Param(system, 1)), static_cast(Param(system, 2))) @@ -138,19 +146,19 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1)).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), Param(system, 2)) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; u64 param_2 = 0; const ResultCode retval = func(system, static_cast(Param(system, 2)), ¶m_1, ¶m_2); @@ -161,54 +169,54 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), Param(system, 1), static_cast(Param(system, 2)), static_cast(Param(system, 3))) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), Param(system, 1), static_cast(Param(system, 2)), Param(system, 3)) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1), static_cast(Param(system, 2))) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn( system, func(system, Param(system, 0), Param(system, 1), static_cast(Param(system, 2))).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2), static_cast(Param(system, 3))) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn( system, func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2)).raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast(Param(system, 2)), static_cast(Param(system, 3))) @@ -219,14 +227,14 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), Param(system, 1), static_cast(Param(system, 2)), static_cast(Param(system, 3))) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u64 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw; @@ -236,7 +244,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3), static_cast(Param(system, 4)), static_cast(Param(system, 5))) @@ -247,7 +255,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), static_cast(Param(system, 3))) @@ -258,7 +266,7 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast(Param(system, 2)), static_cast(Param(system, 3))) @@ -269,14 +277,14 @@ void SvcWrap(Core::System& system) { } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), static_cast(Param(system, 1)), static_cast(Param(system, 2)), static_cast(Param(system, 3))) .raw); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, Param(system, 0), static_cast(Param(system, 1)), static_cast(Param(system, 2)), static_cast(Param(system, 3))) .raw); @@ -286,7 +294,7 @@ void SvcWrap(Core::System& system) { // Function wrappers that return type u32 template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system)); } @@ -294,7 +302,7 @@ void SvcWrap(Core::System& system) { // Function wrappers that return type u64 template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { FuncReturn(system, func(system)); } @@ -302,44 +310,110 @@ void SvcWrap(Core::System& system) { /// Function wrappers that return type void template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0))); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2), Param(system, 3)); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0))); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, Param(system, 0), static_cast(Param(system, 1))); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, Param(system, 0), Param(system, 1)); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, Param(system, 0), Param(system, 1), Param(system, 2)); } template -void SvcWrap(Core::System& system) { +void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2)); } +// Used by QueryMemory32 +template +void SvcWrap32(Core::System& system) { + FuncReturn32(system, + func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); +} + +// Used by GetInfo32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + + const u32 retval = func(system, ¶m_1, ¶m_2, Param32(system, 0), Param32(system, 1), + Param32(system, 2), Param32(system, 3)) + .raw; + + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + FuncReturn(system, retval); +} + +// Used by GetThreadPriority32, ConnectToNamedPort32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + const u32 retval = func(system, ¶m_1, Param32(system, 1)).raw; + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); +} + +// Used by GetThreadId32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + + const u32 retval = func(system, ¶m_1, ¶m_2, Param32(system, 1)).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + FuncReturn(system, retval); +} + +// Used by SignalProcessWideKey32 +template +void SvcWrap32(Core::System& system) { + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))); +} + +// Used by SendSyncRequest32 +template +void SvcWrap32(Core::System& system) { + FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); +} + +// Used by WaitSynchronization32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2), + Param32(system, 3), ¶m_1) + .raw; + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); +} + } // namespace Kernel