From e31425df3877636c098ec7426ebd2067920715cb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 24 Feb 2020 22:04:12 -0400 Subject: General: Recover Prometheus project from harddrive failure This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host Timing, Reworks the Kernel's Scheduler, Introduce Idle State and Suspended State, Recreates the bootmanager, Initializes Multicore system. --- src/core/arm/arm_interface.h | 5 +++- src/core/arm/cpu_interrupt_handler.cpp | 29 +++++++++++++++++++++++ src/core/arm/cpu_interrupt_handler.h | 39 +++++++++++++++++++++++++++++++ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 6 ++--- src/core/arm/dynarmic/arm_dynarmic_32.h | 4 +++- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 28 +++++++++------------- src/core/arm/dynarmic/arm_dynarmic_64.h | 4 +++- src/core/arm/unicorn/arm_unicorn.cpp | 14 +++++++---- src/core/arm/unicorn/arm_unicorn.h | 3 ++- 9 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 src/core/arm/cpu_interrupt_handler.cpp create mode 100644 src/core/arm/cpu_interrupt_handler.h (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index cb2e640e2..87a1c29cc 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -18,11 +18,13 @@ enum class VMAPermission : u8; namespace Core { class System; +class CPUInterruptHandler; /// Generic ARMv8 CPU interface class ARM_Interface : NonCopyable { public: - explicit ARM_Interface(System& system_) : system{system_} {} + explicit ARM_Interface(System& system_, CPUInterruptHandler& interrupt_handler) + : system{system_}, interrupt_handler{interrupt_handler} {} virtual ~ARM_Interface() = default; struct ThreadContext32 { @@ -175,6 +177,7 @@ public: protected: /// System context that this ARM interface is running under. System& system; + CPUInterruptHandler& interrupt_handler; }; } // namespace Core diff --git a/src/core/arm/cpu_interrupt_handler.cpp b/src/core/arm/cpu_interrupt_handler.cpp new file mode 100644 index 000000000..2f1a1a269 --- /dev/null +++ b/src/core/arm/cpu_interrupt_handler.cpp @@ -0,0 +1,29 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/thread.h" +#include "core/arm/cpu_interrupt_handler.h" + +namespace Core { + +CPUInterruptHandler::CPUInterruptHandler() : is_interrupted{} { + interrupt_event = std::make_unique(); +} + +CPUInterruptHandler::~CPUInterruptHandler() = default; + +void CPUInterruptHandler::SetInterrupt(bool is_interrupted_) { + if (is_interrupted_) { + interrupt_event->Set(); + } + this->is_interrupted = is_interrupted_; +} + +void CPUInterruptHandler::AwaitInterrupt() { + interrupt_event->Wait(); +} + +} // namespace Core diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h new file mode 100644 index 000000000..91c31a271 --- /dev/null +++ b/src/core/arm/cpu_interrupt_handler.h @@ -0,0 +1,39 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace Common { +class Event; +} + +namespace Core { + +class CPUInterruptHandler { +public: + CPUInterruptHandler(); + ~CPUInterruptHandler(); + + CPUInterruptHandler(const CPUInterruptHandler&) = delete; + CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete; + + CPUInterruptHandler(CPUInterruptHandler&&) = default; + CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default; + + constexpr bool IsInterrupted() const { + return is_interrupted; + } + + void SetInterrupt(bool is_interrupted); + + void AwaitInterrupt(); + +private: + bool is_interrupted{}; + std::unique_ptr interrupt_event; +}; + +} // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 4c8663d03..0b7aa6a69 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -114,9 +114,9 @@ void ARM_Dynarmic_32::Step() { jit->Step(); } -ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor, - std::size_t core_index) - : ARM_Interface{system}, cb(std::make_unique(*this)), +ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterruptHandler& interrupt_handler, + ExclusiveMonitor& exclusive_monitor, std::size_t core_index) + : ARM_Interface{system, interrupt_handler}, cb(std::make_unique(*this)), cp15(std::make_shared(*this)), core_index{core_index}, exclusive_monitor{dynamic_cast(exclusive_monitor)} {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index e5b92d7bb..1e7e17e64 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -21,6 +21,7 @@ class Memory; namespace Core { +class CPUInterruptHandler; class DynarmicCallbacks32; class DynarmicCP15; class DynarmicExclusiveMonitor; @@ -28,7 +29,8 @@ 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(System& system, CPUInterruptHandler& interrupt_handler, + ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic_32() override; void SetPC(u64 pc) override; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 5f5e36d94..5e316ffd4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/microprofile.h" #include "common/page_table.h" +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" #include "core/core.h" #include "core/core_manager.h" @@ -108,23 +109,16 @@ public: } 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; + /// We are using host timing, NOP } u64 GetTicksRemaining() override { - return std::max(parent.system.CoreTiming().GetDowncount(), s64{0}); + if (!parent.interrupt_handler.IsInterrupted()) { + return 1000ULL; + } + return 0ULL; } u64 GetCNTPCT() override { - return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks()); + return parent.system.CoreTiming().GetClockTicks(); } ARM_Dynarmic_64& parent; @@ -183,10 +177,10 @@ void ARM_Dynarmic_64::Step() { cb->InterpreterFallback(jit->GetPC(), 1); } -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, ARM_Unicorn::Arch::AArch64}, core_index{core_index}, +ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterruptHandler& interrupt_handler, + ExclusiveMonitor& exclusive_monitor, std::size_t core_index) + : ARM_Interface{system, interrupt_handler}, cb(std::make_unique(*this)), + inner_unicorn{system, interrupt_handler, ARM_Unicorn::Arch::AArch64}, core_index{core_index}, exclusive_monitor{dynamic_cast(exclusive_monitor)} {} ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 647cecaf0..9e94b58c2 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -22,12 +22,14 @@ class Memory; namespace Core { class DynarmicCallbacks64; +class CPUInterruptHandler; class DynarmicExclusiveMonitor; class System; class ARM_Dynarmic_64 final : public ARM_Interface { public: - ARM_Dynarmic_64(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); + ARM_Dynarmic_64(System& system, CPUInterruptHandler& interrupt_handler, + ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic_64() override; void SetPC(u64 pc) override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index e40e9626a..0393fe641 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -6,6 +6,7 @@ #include #include "common/assert.h" #include "common/microprofile.h" +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" @@ -62,7 +63,8 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si return false; } -ARM_Unicorn::ARM_Unicorn(System& system, Arch architecture) : ARM_Interface{system} { +ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture) + : ARM_Interface{system, interrupt_handler} { const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); @@ -160,8 +162,12 @@ void ARM_Unicorn::Run() { if (GDBStub::IsServerEnabled()) { ExecuteInstructions(std::max(4000000U, 0U)); } else { - ExecuteInstructions( - std::max(std::size_t(system.CoreTiming().GetDowncount()), std::size_t{0})); + while (true) { + if (interrupt_handler.IsInterrupted()) { + return; + } + ExecuteInstructions(10); + } } } @@ -183,8 +189,6 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data())); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size())); - - system.CoreTiming().AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) { uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 725c65085..0a4c087cd 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -11,6 +11,7 @@ namespace Core { +class CPUInterruptHandler; class System; class ARM_Unicorn final : public ARM_Interface { @@ -20,7 +21,7 @@ public: AArch64, // 64-bit ARM }; - explicit ARM_Unicorn(System& system, Arch architecture); + explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture); ~ARM_Unicorn() override; void SetPC(u64 pc) override; -- cgit v1.2.3 From 04e0f8776c26930d7dc8015e53914b11bf1929c1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 19:12:41 -0400 Subject: General: Add better safety for JIT use. --- src/core/arm/arm_interface.h | 10 ++++++++++ src/core/cpu_manager.cpp | 25 +++++++++++++++++++------ src/core/cpu_manager.h | 2 ++ src/core/hle/kernel/scheduler.cpp | 3 +++ src/core/hle/kernel/svc.cpp | 6 +++++- 5 files changed, 39 insertions(+), 7 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 87a1c29cc..be9f3703a 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -6,6 +6,7 @@ #include #include +#include #include "common/common_types.h" namespace Common { @@ -164,6 +165,14 @@ public: std::string name; }; + void Lock() { + guard.lock(); + } + + void Unlock() { + guard.unlock(); + } + std::vector GetBacktrace() const; /// fp (= r29) points to the last frame record. @@ -178,6 +187,7 @@ protected: /// System context that this ARM interface is running under. System& system; CPUInterruptHandler& interrupt_handler; + std::mutex guard; }; } // namespace Core diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 904aacd97..9a261968a 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -46,6 +46,11 @@ void CpuManager::GuestThreadFunction(void* cpu_manager_) { cpu_manager->RunGuestThread(); } +void CpuManager::GuestRewindFunction(void* cpu_manager_) { + CpuManager* cpu_manager = static_cast(cpu_manager_); + cpu_manager->RunGuestLoop(); +} + void CpuManager::IdleThreadFunction(void* cpu_manager_) { CpuManager* cpu_manager = static_cast(cpu_manager_); cpu_manager->RunIdleThread(); @@ -78,14 +83,22 @@ void CpuManager::RunGuestThread() { auto& sched = kernel.CurrentScheduler(); sched.OnThreadStart(); } + RunGuestLoop(); +} + +void CpuManager::RunGuestLoop() { + auto& kernel = system.Kernel(); + auto* thread = kernel.CurrentScheduler().GetCurrentThread(); + auto host_context = thread->GetHostContext(); + host_context->SetRewindPoint(std::function(GuestRewindFunction), this); + host_context.reset(); while (true) { - auto* physical_core = &kernel.CurrentPhysicalCore(); - while (!physical_core->IsInterrupted()) { - physical_core->Run(); - physical_core = &kernel.CurrentPhysicalCore(); + auto& physical_core = kernel.CurrentPhysicalCore(); + while (!physical_core.IsInterrupted()) { + physical_core.Run(); } - physical_core->ClearExclusive(); - auto& scheduler = physical_core->Scheduler(); + physical_core.ClearExclusive(); + auto& scheduler = physical_core.Scheduler(); scheduler.TryDoContextSwitch(); } } diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 8103ae857..e83ab20f9 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -42,10 +42,12 @@ public: private: static void GuestThreadFunction(void* cpu_manager); + static void GuestRewindFunction(void* cpu_manager); static void IdleThreadFunction(void* cpu_manager); static void SuspendThreadFunction(void* cpu_manager); void RunGuestThread(); + void RunGuestLoop(); void RunIdleThread(); void RunSuspendThread(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 758fa8188..727d2e6cc 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -581,6 +581,7 @@ void Scheduler::SwitchContextStep2() { if (new_thread) { new_thread->context_guard.lock(); + cpu_core.Lock(); ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), "Thread must be assigned to this core."); ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, @@ -601,6 +602,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); } } else { current_thread = nullptr; @@ -639,6 +641,7 @@ void Scheduler::SwitchContext() { } previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); + cpu_core.Unlock(); } std::shared_ptr old_context; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1e6c60d78..b535593c7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "common/microprofile.h" #include "common/string_util.h" @@ -2468,7 +2469,10 @@ void Call(Core::System& system, u32 immediate) { } auto& physical_core_2 = system.CurrentPhysicalCore(); if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { - physical_core.Stop(); + LOG_CRITICAL(Kernel_SVC, "Rewinding"); + auto* thread = physical_core_2.Scheduler().GetCurrentThread(); + auto* host_context = thread->GetHostContext().get(); + host_context->Rewind(); } } -- cgit v1.2.3 From a33fbaddec5d516328d7cd179114dcf0b93cfb69 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 14:56:05 -0400 Subject: Core: Correct rebase. --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 18 ++++++------------ src/core/hle/kernel/scheduler.cpp | 11 +++++------ 2 files changed, 11 insertions(+), 18 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 0b7aa6a69..30bf62ac1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -8,6 +8,7 @@ #include #include #include "common/microprofile.h" +#include "core/arm/cpu_interrupt_handler.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" @@ -72,20 +73,13 @@ public: } 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; + /// We are using host timing, NOP } u64 GetTicksRemaining() override { - return std::max(parent.system.CoreTiming().GetDowncount(), {}); + if (!parent.interrupt_handler.IsInterrupted()) { + return 1000ULL; + } + return 0ULL; } ARM_Dynarmic_32& parent; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index aa1f1a305..ae89e908f 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -552,8 +552,7 @@ void GlobalScheduler::Unlock() { EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } -Scheduler::Scheduler(Core::System& system, std::size_t core_id) - : system(system), core_id(core_id) { +Scheduler::Scheduler(Core::System& system, std::size_t core_id) : system(system), core_id(core_id) { switch_fiber = std::make_shared(std::function(OnSwitch), this); } @@ -601,9 +600,10 @@ void Scheduler::SwitchContextStep2() { // Load context of new thread Process* const previous_process = - previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; + previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; if (new_thread) { + auto& cpu_core = system.ArmInterface(core_id); new_thread->context_guard.lock(); cpu_core.Lock(); ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), @@ -619,7 +619,6 @@ void Scheduler::SwitchContextStep2() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); @@ -651,12 +650,12 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + auto& cpu_core = system.ArmInterface(core_id); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.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(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } if (previous_thread->GetStatus() == ThreadStatus::Running) { -- cgit v1.2.3 From 725bac14044b2645b9ce912d1b1e2c9c2a96818b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 13:27:27 -0400 Subject: Scheduler: Remove arm_interface lock and a few corrections. --- src/core/arm/arm_interface.h | 10 ---------- src/core/hle/kernel/scheduler.cpp | 10 +++------- 2 files changed, 3 insertions(+), 17 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index be9f3703a..87a1c29cc 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -6,7 +6,6 @@ #include #include -#include #include "common/common_types.h" namespace Common { @@ -165,14 +164,6 @@ public: std::string name; }; - void Lock() { - guard.lock(); - } - - void Unlock() { - guard.unlock(); - } - std::vector GetBacktrace() const; /// fp (= r29) points to the last frame record. @@ -187,7 +178,6 @@ protected: /// System context that this ARM interface is running under. System& system; CPUInterruptHandler& interrupt_handler; - std::mutex guard; }; } // namespace Core diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index a37b992ec..affc2fbed 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -463,9 +463,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit } if (thread->processor_id >= 0) { - // TODO(Blinkhawk): compare it with current thread running on current core, instead of - // checking running - if (thread->IsRunning()) { + if (thread == kernel.CurrentScheduler().GetCurrentThread()) { SchedulePrepend(thread->current_priority, static_cast(thread->processor_id), thread); } else { @@ -602,8 +600,6 @@ void Scheduler::SwitchContextStep2() { previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; if (new_thread) { - auto& cpu_core = system.ArmInterface(core_id); - cpu_core.Lock(); ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, "Thread must be runnable."); @@ -615,6 +611,7 @@ void Scheduler::SwitchContextStep2() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); @@ -646,8 +643,8 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { - auto& cpu_core = system.ArmInterface(core_id); if (!previous_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. @@ -659,7 +656,6 @@ void Scheduler::SwitchContext() { } previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); - cpu_core.Unlock(); } std::shared_ptr old_context; -- cgit v1.2.3 From cd1c38be8d15d3caf52f566a9e8dc20504c61068 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 18:59:42 -0400 Subject: ARM/Memory: Correct Exclusive Monitor and Implement Exclusive Memory Writes. --- src/common/CMakeLists.txt | 2 + src/common/atomic_ops.cpp | 70 ++++++++++++++++++++++ src/common/atomic_ops.h | 17 ++++++ src/core/arm/dynarmic/arm_dynarmic_64.cpp | 66 +++++++++++++++++---- src/core/arm/dynarmic/arm_dynarmic_64.h | 6 +- src/core/arm/exclusive_monitor.h | 6 +- src/core/hle/kernel/address_arbiter.cpp | 6 +- src/core/hle/kernel/mutex.cpp | 5 +- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/kernel/thread.cpp | 6 +- src/core/memory.cpp | 98 +++++++++++++++++++++++++++++++ src/core/memory.h | 65 ++++++++++++++++++++ 12 files changed, 325 insertions(+), 24 deletions(-) create mode 100644 src/common/atomic_ops.cpp create mode 100644 src/common/atomic_ops.h (limited to 'src/core/arm') diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 3cc17d0e9..d120c8d3d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -98,6 +98,8 @@ add_library(common STATIC algorithm.h alignment.h assert.h + atomic_ops.cpp + atomic_ops.h detached_tasks.cpp detached_tasks.h bit_field.h diff --git a/src/common/atomic_ops.cpp b/src/common/atomic_ops.cpp new file mode 100644 index 000000000..65cdfb4fd --- /dev/null +++ b/src/common/atomic_ops.cpp @@ -0,0 +1,70 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/atomic_ops.h" + +#if _MSC_VER +#include +#endif + +namespace Common { + +#if _MSC_VER + +bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) { + u8 result = _InterlockedCompareExchange8((char*)pointer, value, expected); + return result == expected; +} + +bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) { + u16 result = _InterlockedCompareExchange16((short*)pointer, value, expected); + return result == expected; +} + +bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) { + u32 result = _InterlockedCompareExchange((long*)pointer, value, expected); + return result == expected; +} + +bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) { + u64 result = _InterlockedCompareExchange64((__int64*)pointer, value, expected); + return result == expected; +} + +bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { + return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0], (__int64*)expected.data()) != 0; +} + + +#else + +bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) { + return __sync_bool_compare_and_swap (pointer, value, expected); +} + +bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) { + return __sync_bool_compare_and_swap (pointer, value, expected); +} + +bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) { + return __sync_bool_compare_and_swap (pointer, value, expected); +} + +bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) { + return __sync_bool_compare_and_swap (pointer, value, expected); +} + +bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { + unsigned __int128 value_a; + unsigned __int128 expected_a; + std::memcpy(&value_a, value.data(), sizeof(u128)); + std::memcpy(&expected_a, expected.data(), sizeof(u128)); + return __sync_bool_compare_and_swap ((unsigned __int128*)pointer, value_a, expected_a); +} + +#endif + +} // namespace Common diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h new file mode 100644 index 000000000..22cb3a402 --- /dev/null +++ b/src/common/atomic_ops.h @@ -0,0 +1,17 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace Common { + +bool AtomicCompareAndSwap(u8 volatile * pointer, u8 value, u8 expected); +bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected); +bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected); +bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected); +bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected); + +} // namespace Common diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 5e316ffd4..a22c22bf0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -66,6 +66,22 @@ public: memory.Write64(vaddr + 8, value[1]); } + bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { + return parent.system.Memory().WriteExclusive8(vaddr, value, expected); + } + bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { + return parent.system.Memory().WriteExclusive16(vaddr, value, expected); + } + bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { + return parent.system.Memory().WriteExclusive32(vaddr, value, expected); + } + bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { + return parent.system.Memory().WriteExclusive64(vaddr, value, expected); + } + bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { + return parent.system.Memory().WriteExclusive128(vaddr, value, expected); + } + 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)); @@ -284,9 +300,29 @@ DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std:: DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; -void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { - // Size doesn't actually matter. - monitor.Mark(core_index, addr, 16); +void DynarmicExclusiveMonitor::SetExclusive8(std::size_t core_index, VAddr addr) { + monitor.Mark(core_index, addr, 1, [&]() -> u8 { return memory.Read8(addr); }); +} + +void DynarmicExclusiveMonitor::SetExclusive16(std::size_t core_index, VAddr addr) { + monitor.Mark(core_index, addr, 2, [&]() -> u16 { return memory.Read16(addr); }); +} + +void DynarmicExclusiveMonitor::SetExclusive32(std::size_t core_index, VAddr addr) { + monitor.Mark(core_index, addr, 4, [&]() -> u32 { return memory.Read32(addr); }); +} + +void DynarmicExclusiveMonitor::SetExclusive64(std::size_t core_index, VAddr addr) { + monitor.Mark(core_index, addr, 8, [&]() -> u64 { return memory.Read64(addr); }); +} + +void DynarmicExclusiveMonitor::SetExclusive128(std::size_t core_index, VAddr addr) { + monitor.Mark(core_index, addr, 16, [&]() -> u128 { + u128 result; + result[0] = memory.Read64(addr); + result[1] = memory.Read64(addr + 8); + return result; + }); } void DynarmicExclusiveMonitor::ClearExclusive() { @@ -294,28 +330,32 @@ void DynarmicExclusiveMonitor::ClearExclusive() { } bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); }); + return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&](u8 expected) -> bool { + return memory.WriteExclusive8(vaddr, value, expected); + }); } bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 2, - [&] { memory.Write16(vaddr, value); }); + return monitor.DoExclusiveOperation(core_index, vaddr, 2, [&](u16 expected) -> bool { + return memory.WriteExclusive16(vaddr, value, expected); + }); } bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 4, - [&] { memory.Write32(vaddr, value); }); + return monitor.DoExclusiveOperation(core_index, vaddr, 4, [&](u32 expected) -> bool { + return memory.WriteExclusive32(vaddr, value, expected); + }); } bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 8, - [&] { memory.Write64(vaddr, value); }); + return monitor.DoExclusiveOperation(core_index, vaddr, 8, [&](u64 expected) -> bool { + return memory.WriteExclusive64(vaddr, value, expected); + }); } bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { - memory.Write64(vaddr + 0, value[0]); - memory.Write64(vaddr + 8, value[1]); + return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&](u128 expected) -> bool { + return memory.WriteExclusive128(vaddr, value, expected); }); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 9e94b58c2..3ead59f16 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -82,7 +82,11 @@ public: explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); ~DynarmicExclusiveMonitor() override; - void SetExclusive(std::size_t core_index, VAddr addr) override; + void SetExclusive8(std::size_t core_index, VAddr addr) override; + void SetExclusive16(std::size_t core_index, VAddr addr) override; + void SetExclusive32(std::size_t core_index, VAddr addr) override; + void SetExclusive64(std::size_t core_index, VAddr addr) override; + void SetExclusive128(std::size_t core_index, VAddr addr) override; void ClearExclusive() override; bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override; diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h index ccd73b80f..2ee312eee 100644 --- a/src/core/arm/exclusive_monitor.h +++ b/src/core/arm/exclusive_monitor.h @@ -18,7 +18,11 @@ class ExclusiveMonitor { public: virtual ~ExclusiveMonitor(); - virtual void SetExclusive(std::size_t core_index, VAddr addr) = 0; + virtual void SetExclusive8(std::size_t core_index, VAddr addr) = 0; + virtual void SetExclusive16(std::size_t core_index, VAddr addr) = 0; + virtual void SetExclusive32(std::size_t core_index, VAddr addr) = 0; + virtual void SetExclusive64(std::size_t core_index, VAddr addr) = 0; + virtual void SetExclusive128(std::size_t core_index, VAddr addr) = 0; virtual void ClearExclusive() = 0; virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0; diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ebabde921..07acabc1d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -90,7 +90,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 auto& monitor = system.Monitor(); u32 current_value; do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); current_value = memory.Read32(address); if (current_value != value) { @@ -120,7 +120,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a auto& monitor = system.Monitor(); s32 updated_value; do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); updated_value = memory.Read32(address); if (updated_value != value) { @@ -191,7 +191,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); current_value = static_cast(memory.Read32(address)); if (should_decrement) { decrement_value = current_value - 1; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index ebe3f6050..16c95782a 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/arm/exclusive_monitor.h" +#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -138,7 +139,7 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrResumeFromWait(); do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); return {RESULT_SUCCESS, new_owner}; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index da2f90a1d..371beed0d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1641,7 +1641,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ u32 update_val = 0; const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive(current_core, mutex_address); + monitor.SetExclusive32(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. mutex_val = memory.Read32(mutex_address); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b99e3b7a5..51cc5dcca 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -236,7 +236,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); } thread->host_context = - std::make_shared(std::move(thread_start_func), thread_start_parameter); + std::make_shared(std::move(thread_start_func), thread_start_parameter); return MakeResult>(std::move(thread)); } @@ -412,12 +412,12 @@ ResultCode Thread::SetActivity(ThreadActivity value) { } if (value == ThreadActivity::Paused) { - if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) != 0) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) != 0) { return ERR_INVALID_STATE; } AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); } else { - if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) == 0) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) == 0) { return ERR_INVALID_STATE; } RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 66634596d..4cb5d05e5 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -8,6 +8,7 @@ #include #include "common/assert.h" +#include "common/atomic_ops.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/page_table.h" @@ -176,6 +177,22 @@ struct Memory::Impl { } } + bool WriteExclusive8(const VAddr addr, const u8 data, const u8 expected) { + return WriteExclusive(addr, data, expected); + } + + bool WriteExclusive16(const VAddr addr, const u16 data, const u16 expected) { + return WriteExclusive(addr, data, expected); + } + + bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected) { + return WriteExclusive(addr, data, expected); + } + + bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected) { + return WriteExclusive(addr, data, expected); + } + std::string ReadCString(VAddr vaddr, std::size_t max_length) { std::string string; string.reserve(max_length); @@ -679,6 +696,67 @@ struct Memory::Impl { } } + template + bool WriteExclusive(const VAddr vaddr, const T data, const T expected) { + u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + // NOTE: Avoid adding any extra logic to this fast-path block + T volatile* pointer = reinterpret_cast(&page_pointer[vaddr]); + return Common::AtomicCompareAndSwap(pointer, data, expected); + } + + const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case Common::PageType::Unmapped: + LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, + static_cast(data), vaddr); + return true; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); + break; + case Common::PageType::RasterizerCachedMemory: { + u8* host_ptr{GetPointerFromVMA(vaddr)}; + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); + T volatile* pointer = reinterpret_cast(&host_ptr); + return Common::AtomicCompareAndSwap(pointer, data, expected); + break; + } + default: + UNREACHABLE(); + } + return true; + } + + bool WriteExclusive128(const VAddr vaddr, const u128 data, const u128 expected) { + u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + // NOTE: Avoid adding any extra logic to this fast-path block + u64 volatile* pointer = reinterpret_cast(&page_pointer[vaddr]); + return Common::AtomicCompareAndSwap(pointer, data, expected); + } + + const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case Common::PageType::Unmapped: + LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8, + static_cast(data[1]), static_cast(data[0]), vaddr); + return true; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); + break; + case Common::PageType::RasterizerCachedMemory: { + u8* host_ptr{GetPointerFromVMA(vaddr)}; + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(u128)); + u64 volatile* pointer = reinterpret_cast(&host_ptr); + return Common::AtomicCompareAndSwap(pointer, data, expected); + break; + } + default: + UNREACHABLE(); + } + return true; + } + Common::PageTable* current_page_table = nullptr; Core::System& system; }; @@ -761,6 +839,26 @@ void Memory::Write64(VAddr addr, u64 data) { impl->Write64(addr, data); } +bool Memory::WriteExclusive8(VAddr addr, u8 data, u8 expected) { + return impl->WriteExclusive8(addr, data, expected); +} + +bool Memory::WriteExclusive16(VAddr addr, u16 data, u16 expected) { + return impl->WriteExclusive16(addr, data, expected); +} + +bool Memory::WriteExclusive32(VAddr addr, u32 data, u32 expected) { + return impl->WriteExclusive32(addr, data, expected); +} + +bool Memory::WriteExclusive64(VAddr addr, u64 data, u64 expected) { + return impl->WriteExclusive64(addr, data, expected); +} + +bool Memory::WriteExclusive128(VAddr addr, u128 data, u128 expected) { + return impl->WriteExclusive128(addr, data, expected); +} + std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { return impl->ReadCString(vaddr, max_length); } diff --git a/src/core/memory.h b/src/core/memory.h index 93f0c1d6c..4a1cc63f4 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -244,6 +244,71 @@ public: */ void Write64(VAddr addr, u64 data); + /** + * Writes a 8-bit unsigned integer to the given virtual address in + * the current process' address space if and only if the address contains + * the expected value. This operation is atomic. + * + * @param addr The virtual address to write the 8-bit unsigned integer to. + * @param data The 8-bit unsigned integer to write to the given virtual address. + * @param expected The 8-bit unsigned integer to check against the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + bool WriteExclusive8(VAddr addr, u8 data, u8 expected); + + /** + * Writes a 16-bit unsigned integer to the given virtual address in + * the current process' address space if and only if the address contains + * the expected value. This operation is atomic. + * + * @param addr The virtual address to write the 16-bit unsigned integer to. + * @param data The 16-bit unsigned integer to write to the given virtual address. + * @param expected The 16-bit unsigned integer to check against the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + bool WriteExclusive16(VAddr addr, u16 data, u16 expected); + + /** + * Writes a 32-bit unsigned integer to the given virtual address in + * the current process' address space if and only if the address contains + * the expected value. This operation is atomic. + * + * @param addr The virtual address to write the 32-bit unsigned integer to. + * @param data The 32-bit unsigned integer to write to the given virtual address. + * @param expected The 32-bit unsigned integer to check against the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + bool WriteExclusive32(VAddr addr, u32 data, u32 expected); + + /** + * Writes a 64-bit unsigned integer to the given virtual address in + * the current process' address space if and only if the address contains + * the expected value. This operation is atomic. + * + * @param addr The virtual address to write the 64-bit unsigned integer to. + * @param data The 64-bit unsigned integer to write to the given virtual address. + * @param expected The 64-bit unsigned integer to check against the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + bool WriteExclusive64(VAddr addr, u64 data, u64 expected); + + /** + * Writes a 128-bit unsigned integer to the given virtual address in + * the current process' address space if and only if the address contains + * the expected value. This operation is atomic. + * + * @param addr The virtual address to write the 128-bit unsigned integer to. + * @param data The 128-bit unsigned integer to write to the given virtual address. + * @param expected The 128-bit unsigned integer to check against the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + bool WriteExclusive128(VAddr addr, u128 data, u128 expected); + /** * Reads a null-terminated string from the given virtual address. * This function will continually read characters until either: -- cgit v1.2.3 From 7020d498c5aef7c1180bfc57031cdd7fbfecdf0f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 12 Mar 2020 16:48:43 -0400 Subject: General: Fix microprofile on dynarmic/svc, fix wait tree showing which threads were running. --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 ---- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 5 +---- src/core/core.cpp | 15 +++++++++++++++ src/core/core.h | 6 ++++++ src/core/cpu_manager.cpp | 4 ++++ src/core/hle/kernel/kernel.cpp | 15 +++++++++++++++ src/core/hle/kernel/kernel.h | 4 ++++ src/core/hle/kernel/scheduler.cpp | 7 +++++++ src/core/hle/kernel/svc.cpp | 10 +++++++--- src/core/hle/kernel/thread.h | 18 ++++++++++++++++++ src/yuzu/debugger/wait_tree.cpp | 12 ++++++++++-- 11 files changed, 87 insertions(+), 13 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 30bf62ac1..618f02f30 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -7,7 +7,6 @@ #include #include #include -#include "common/microprofile.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" @@ -97,10 +96,7 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& 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(); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index a22c22bf0..84b872f0b 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -7,7 +7,6 @@ #include #include #include "common/logging/log.h" -#include "common/microprofile.h" #include "common/page_table.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" @@ -181,11 +180,9 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& return std::make_shared(config); } -MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_64, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); -void ARM_Dynarmic_64::Run() { - MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_64); +void ARM_Dynarmic_64::Run() { jit->Run(); } diff --git a/src/core/core.cpp b/src/core/core.cpp index fd1bdcaf0..032da7aa5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -8,6 +8,7 @@ #include "common/file_util.h" #include "common/logging/log.h" +#include "common/microprofile.h" #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" @@ -50,6 +51,8 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); + namespace Core { namespace { @@ -391,6 +394,8 @@ struct System::Impl { std::unique_ptr perf_stats; Core::FrameLimiter frame_limiter; + + std::array dynarmic_ticks{}; }; System::System() : impl{std::make_unique(*this)} {} @@ -736,4 +741,14 @@ void System::RegisterHostThread() { impl->kernel.RegisterHostThread(); } +void System::EnterDynarmicProfile() { + std::size_t core = impl->kernel.GetCurrentHostThreadID(); + impl->dynarmic_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(ARM_Jit_Dynarmic)); +} + +void System::ExitDynarmicProfile() { + std::size_t core = impl->kernel.GetCurrentHostThreadID(); + MicroProfileLeave(MICROPROFILE_TOKEN(ARM_Jit_Dynarmic), impl->dynarmic_ticks[core]); +} + } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 9a0dd1075..87df79d57 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -377,6 +377,12 @@ public: /// Register a host thread as an auxiliary thread. void RegisterHostThread(); + /// Enter Dynarmic Microprofile + void EnterDynarmicProfile(); + + /// Exit Dynarmic Microprofile + void ExitDynarmicProfile(); + private: System(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 95842aad1..9e2e6d49f 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -118,9 +118,11 @@ void CpuManager::MultiCoreRunGuestLoop() { host_context.reset(); while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); + system.EnterDynarmicProfile(); while (!physical_core.IsInterrupted()) { physical_core.Run(); } + system.ExitDynarmicProfile(); physical_core.ClearExclusive(); auto& scheduler = physical_core.Scheduler(); scheduler.TryDoContextSwitch(); @@ -216,6 +218,7 @@ void CpuManager::SingleCoreRunGuestLoop() { host_context.reset(); while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); + system.EnterDynarmicProfile(); while (!physical_core.IsInterrupted()) { physical_core.Run(); preemption_count++; @@ -224,6 +227,7 @@ void CpuManager::SingleCoreRunGuestLoop() { } } physical_core.ClearExclusive(); + system.ExitDynarmicProfile(); PreemptSingleCore(); auto& scheduler = kernel.Scheduler(current_core); scheduler.TryDoContextSwitch(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 24da4367e..d2f5f9bf2 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,6 +13,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" @@ -41,6 +42,8 @@ #include "core/hle/result.h" #include "core/memory.h" +MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); + namespace Kernel { /** @@ -408,6 +411,8 @@ struct KernelCore::Impl { bool is_multicore{}; std::thread::id single_core_thread_id{}; + std::array svc_ticks{}; + // System context Core::System& system; }; @@ -666,4 +671,14 @@ void KernelCore::ExceptionalExit() { Suspend(true); } +void KernelCore::EnterSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); +} + +void KernelCore::ExitSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 50eeb50ec..1eb6ede73 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -214,6 +214,10 @@ public: bool IsMulticore() const; + void EnterSVCProfile(); + + void ExitSVCProfile(); + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 25fc8a3e8..2ad380b17 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -354,7 +354,9 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, } if (must_context_switch) { auto& core_scheduler = kernel.CurrentScheduler(); + kernel.ExitSVCProfile(); core_scheduler.TryDoContextSwitch(); + kernel.EnterSVCProfile(); } } @@ -628,6 +630,7 @@ void Scheduler::Reload() { // Cancel any outstanding wakeup events for this thread thread->SetIsRunning(true); + thread->SetWasRunning(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); auto* const thread_owner_process = thread->GetOwnerProcess(); @@ -660,6 +663,7 @@ void Scheduler::SwitchContextStep2() { // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process && thread_owner_process != nullptr) { @@ -698,6 +702,9 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + if (new_thread != nullptr && new_thread->IsSuspendThread()) { + previous_thread->SetWasRunning(true); + } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d3d4e7bf9..9b9f9402e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2454,10 +2454,10 @@ static const FunctionDef* GetSVCInfo64(u32 func_num) { return &SVC_Table_64[func_num]; } -MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); - void Call(Core::System& system, u32 immediate) { - MICROPROFILE_SCOPE(Kernel_SVC); + system.ExitDynarmicProfile(); + auto& kernel = system.Kernel(); + kernel.EnterSVCProfile(); auto* thread = system.CurrentScheduler().GetCurrentThread(); thread->SetContinuousOnSVC(true); @@ -2474,10 +2474,14 @@ void Call(Core::System& system, u32 immediate) { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + kernel.ExitSVCProfile(); + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } + + system.EnterDynarmicProfile(); } } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 168828ab0..f42d7bd13 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -350,6 +350,22 @@ public: return (type & THREADTYPE_HLE) != 0; } + bool IsSuspendThread() const { + return (type & THREADTYPE_SUSPEND) != 0; + } + + bool IsIdleThread() const { + return (type & THREADTYPE_IDLE) != 0; + } + + bool WasRunning() const { + return was_running; + } + + void SetWasRunning(bool value) { + was_running = value; + } + std::shared_ptr GetHostContext() const; ThreadStatus GetStatus() const { @@ -684,6 +700,8 @@ private: bool will_be_terminated = false; + bool was_running = false; + std::string name; }; diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index ab7b18abe..fa091f457 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -209,7 +209,11 @@ QString WaitTreeThread::GetText() const { break; case Kernel::ThreadStatus::Ready: if (!thread.IsPaused()) { - status = tr("ready"); + if (thread.WasRunning()) { + status = tr("running"); + } else { + status = tr("ready"); + } } else { status = tr("paused"); } @@ -261,7 +265,11 @@ QColor WaitTreeThread::GetColor() const { return QColor(Qt::GlobalColor::darkGreen); case Kernel::ThreadStatus::Ready: if (!thread.IsPaused()) { - return QColor(Qt::GlobalColor::darkBlue); + if (thread.WasRunning()) { + return QColor(Qt::GlobalColor::darkGreen); + } else { + return QColor(Qt::GlobalColor::darkBlue); + } } else { return QColor(Qt::GlobalColor::lightGray); } -- cgit v1.2.3 From 25565dffd588006aace7530486e71ff318dc5550 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 15 Mar 2020 15:54:40 -0400 Subject: ARM: Addapt to new Exclusive Monitor Interface. --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 22 ++++++++++------------ src/core/arm/dynarmic/arm_dynarmic_64.h | 10 +++++----- src/core/arm/exclusive_monitor.h | 10 +++++----- src/core/hle/kernel/address_arbiter.cpp | 9 +++------ src/core/hle/kernel/svc.cpp | 4 +--- 5 files changed, 24 insertions(+), 31 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 84b872f0b..2e664cfa8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -180,8 +180,6 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& return std::make_shared(config); } - - void ARM_Dynarmic_64::Run() { jit->Run(); } @@ -297,24 +295,24 @@ DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std:: DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; -void DynarmicExclusiveMonitor::SetExclusive8(std::size_t core_index, VAddr addr) { - monitor.Mark(core_index, addr, 1, [&]() -> u8 { return memory.Read8(addr); }); +u8 DynarmicExclusiveMonitor::ExclusiveRead8(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u8 { return memory.Read8(addr); }); } -void DynarmicExclusiveMonitor::SetExclusive16(std::size_t core_index, VAddr addr) { - monitor.Mark(core_index, addr, 2, [&]() -> u16 { return memory.Read16(addr); }); +u16 DynarmicExclusiveMonitor::ExclusiveRead16(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u16 { return memory.Read16(addr); }); } -void DynarmicExclusiveMonitor::SetExclusive32(std::size_t core_index, VAddr addr) { - monitor.Mark(core_index, addr, 4, [&]() -> u32 { return memory.Read32(addr); }); +u32 DynarmicExclusiveMonitor::ExclusiveRead32(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u32 { return memory.Read32(addr); }); } -void DynarmicExclusiveMonitor::SetExclusive64(std::size_t core_index, VAddr addr) { - monitor.Mark(core_index, addr, 8, [&]() -> u64 { return memory.Read64(addr); }); +u64 DynarmicExclusiveMonitor::ExclusiveRead64(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u64 { return memory.Read64(addr); }); } -void DynarmicExclusiveMonitor::SetExclusive128(std::size_t core_index, VAddr addr) { - monitor.Mark(core_index, addr, 16, [&]() -> u128 { +u128 DynarmicExclusiveMonitor::ExclusiveRead128(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u128 { u128 result; result[0] = memory.Read64(addr); result[1] = memory.Read64(addr + 8); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 3ead59f16..5560578ad 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -82,11 +82,11 @@ public: explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); ~DynarmicExclusiveMonitor() override; - void SetExclusive8(std::size_t core_index, VAddr addr) override; - void SetExclusive16(std::size_t core_index, VAddr addr) override; - void SetExclusive32(std::size_t core_index, VAddr addr) override; - void SetExclusive64(std::size_t core_index, VAddr addr) override; - void SetExclusive128(std::size_t core_index, VAddr addr) override; + u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override; + u16 ExclusiveRead16(std::size_t core_index, VAddr addr) override; + u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override; + u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override; + u128 ExclusiveRead128(std::size_t core_index, VAddr addr) override; void ClearExclusive() override; bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override; diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h index 2ee312eee..62f6e6023 100644 --- a/src/core/arm/exclusive_monitor.h +++ b/src/core/arm/exclusive_monitor.h @@ -18,11 +18,11 @@ class ExclusiveMonitor { public: virtual ~ExclusiveMonitor(); - virtual void SetExclusive8(std::size_t core_index, VAddr addr) = 0; - virtual void SetExclusive16(std::size_t core_index, VAddr addr) = 0; - virtual void SetExclusive32(std::size_t core_index, VAddr addr) = 0; - virtual void SetExclusive64(std::size_t core_index, VAddr addr) = 0; - virtual void SetExclusive128(std::size_t core_index, VAddr addr) = 0; + virtual u8 ExclusiveRead8(std::size_t core_index, VAddr addr) = 0; + virtual u16 ExclusiveRead16(std::size_t core_index, VAddr addr) = 0; + virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0; + virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0; + virtual u128 ExclusiveRead128(std::size_t core_index, VAddr addr) = 0; virtual void ClearExclusive() = 0; virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0; diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index e8f22b598..4d2a9b35d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -80,8 +80,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 auto& monitor = system.Monitor(); u32 current_value; do { - monitor.SetExclusive32(current_core, address); - current_value = memory.Read32(address); + current_value = monitor.ExclusiveRead32(current_core, address); if (current_value != value) { return ERR_INVALID_STATE; @@ -110,8 +109,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a auto& monitor = system.Monitor(); s32 updated_value; do { - monitor.SetExclusive32(current_core, address); - updated_value = memory.Read32(address); + updated_value = monitor.ExclusiveRead32(current_core, address); if (updated_value != value) { return ERR_INVALID_STATE; @@ -186,8 +184,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); do { - monitor.SetExclusive32(current_core, address); - current_value = static_cast(memory.Read32(address)); + current_value = static_cast(monitor.ExclusiveRead32(current_core, address)); if (should_decrement) { decrement_value = current_value - 1; } else { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9b9f9402e..36e9c48f9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1653,10 +1653,8 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ u32 update_val = 0; const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive32(current_core, mutex_address); - // If the mutex is not yet acquired, acquire it. - mutex_val = memory.Read32(mutex_address); + mutex_val = monitor.ExclusiveRead32(current_core, mutex_address); if (mutex_val != 0) { update_val = mutex_val | Mutex::MutexHasWaitersFlag; -- cgit v1.2.3 From 87c49aa7be4b7277f8ae929058633827d339a052 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 20 Mar 2020 12:36:01 -0400 Subject: SVC/ARM: Correct svcSendSyncRequest and cache ticks on arm interface. --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 11 +++++++++-- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 12 ++++++++++-- src/core/hle/kernel/svc.cpp | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 618f02f30..c8a1ce6e7 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -72,17 +72,23 @@ public: } void AddTicks(u64 ticks) override { - /// We are using host timing, NOP + this->ticks -= ticks; } + u64 GetTicksRemaining() override { if (!parent.interrupt_handler.IsInterrupted()) { - return 1000ULL; + return std::max(ticks, 0); } return 0ULL; } + void ResetTicks() { + ticks = 1000LL; + } + ARM_Dynarmic_32& parent; std::size_t num_interpreted_instructions{}; + s64 ticks{}; }; std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, @@ -97,6 +103,7 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& } void ARM_Dynarmic_32::Run() { + cb->ResetTicks(); jit->Run(); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 2e664cfa8..547a6e07e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -124,22 +124,29 @@ public: } void AddTicks(u64 ticks) override { - /// We are using host timing, NOP + this->ticks -= ticks; } + u64 GetTicksRemaining() override { if (!parent.interrupt_handler.IsInterrupted()) { - return 1000ULL; + return std::max(ticks, 0); } return 0ULL; } + u64 GetCNTPCT() override { return parent.system.CoreTiming().GetClockTicks(); } + void ResetTicks() { + ticks = 1000LL; + } + ARM_Dynarmic_64& parent; std::size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; + s64 ticks{}; }; std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, @@ -181,6 +188,7 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& } void ARM_Dynarmic_64::Run() { + cb->ResetTicks(); jit->Run(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 36e9c48f9..f08745226 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -342,7 +342,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->InvokeHLECallback(SharedFrom(thread)); } - return RESULT_SUCCESS; + return thread->GetSignalingResult(); } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { -- cgit v1.2.3 From 7b18174eef70feb434f9319a57a6cfbe362730e3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 20 Mar 2020 14:05:47 -0400 Subject: ARM/WaitTree: Better track the CallStack for each thread. --- src/core/arm/arm_interface.cpp | 57 +++++++++++++++++++++++++++++++++++++++++ src/core/arm/arm_interface.h | 3 +++ src/yuzu/debugger/wait_tree.cpp | 25 ++++++++++-------- 3 files changed, 74 insertions(+), 11 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index d079a1bc8..d2295ed90 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -139,6 +139,63 @@ std::optional GetSymbolName(const Symbols& symbols, VAddr func_addr constexpr u64 SEGMENT_BASE = 0x7100000000ull; +std::vector ARM_Interface::GetBacktraceFromContext( + System& system, const ThreadContext64& ctx) { + std::vector out; + auto& memory = system.Memory(); + + auto fp = ctx.cpu_registers[29]; + auto lr = ctx.cpu_registers[30]; + while (true) { + out.push_back({"", 0, lr, 0}); + if (!fp) { + break; + } + lr = memory.Read64(fp + 8) - 4; + fp = memory.Read64(fp); + } + + std::map modules; + auto& loader{system.GetAppLoader()}; + if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { + return {}; + } + + std::map symbols; + for (const auto& module : modules) { + symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); + } + + for (auto& entry : out) { + VAddr base = 0; + for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { + const auto& module{*iter}; + if (entry.original_address >= module.first) { + entry.module = module.second; + base = module.first; + break; + } + } + + entry.offset = entry.original_address - base; + entry.address = SEGMENT_BASE + entry.offset; + + if (entry.module.empty()) + entry.module = "unknown"; + + const auto symbol_set = symbols.find(entry.module); + if (symbol_set != symbols.end()) { + const auto symbol = GetSymbolName(symbol_set->second, entry.offset); + if (symbol.has_value()) { + // TODO(DarkLordZach): Add demangling of symbol names. + entry.name = *symbol; + } + } + } + + return out; +} + std::vector ARM_Interface::GetBacktrace() const { std::vector out; auto& memory = system.Memory(); diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 87a1c29cc..e701ddf21 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -164,6 +164,9 @@ public: std::string name; }; + static std::vector GetBacktraceFromContext(System& system, + const ThreadContext64& ctx); + std::vector GetBacktrace() const; /// fp (= r29) points to the last frame record. diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index fa091f457..d2dbb259c 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -2,10 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include "yuzu/debugger/wait_tree.h" #include "yuzu/util/util.h" #include "common/assert.h" +#include "core/arm/arm_interface.h" #include "core/core.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/mutex.h" @@ -116,20 +119,20 @@ QString WaitTreeCallstack::GetText() const { std::vector> WaitTreeCallstack::GetChildren() const { std::vector> list; - constexpr std::size_t BaseRegister = 29; - auto& memory = Core::System::GetInstance().Memory(); - u64 base_pointer = thread.GetContext64().cpu_registers[BaseRegister]; + if (thread.IsHLEThread()) { + return list; + } - while (base_pointer != 0) { - const u64 lr = memory.Read64(base_pointer + sizeof(u64)); - if (lr == 0) { - break; - } + if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) { + return list; + } - list.push_back(std::make_unique( - tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'}))); + auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(Core::System::GetInstance(), thread.GetContext64()); - base_pointer = memory.Read64(base_pointer); + for (auto& entry : backtrace) { + std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, + entry.original_address, entry.offset, entry.name); + list.push_back(std::make_unique(QString::fromStdString(s))); } return list; -- cgit v1.2.3 From 534466754f381e90f5f6475a0c02031242a5c256 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 21 Mar 2020 12:23:13 -0400 Subject: X64 Clock: Reduce accuracy to be less or equal to guest accuracy. --- src/common/x64/native_clock.cpp | 3 ++- src/common/x64/native_clock.h | 5 +++++ src/core/arm/dynarmic/arm_dynarmic_64.cpp | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/core/arm') diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 926f92ff8..f1bc60fd2 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -62,7 +62,8 @@ u64 NativeClock::GetRTSC() { } accumulated_ticks += diff; rtsc_serialize.unlock(); - return accumulated_ticks; + /// The clock cannot be more precise than the guest timer, remove the lower bits + return accumulated_ticks & inaccuracy_mask; } void NativeClock::Pause(bool is_paused) { diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 3851f8fc2..e853094d2 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h @@ -31,6 +31,11 @@ public: private: u64 GetRTSC(); + /// value used to reduce the native clocks accuracy as some apss rely on + /// undefined behavior where the level of accuracy in the clock shouldn't + /// be higher. + static constexpr u64 inaccuracy_mask = ~(0x100 - 1); + SpinLock rtsc_serialize{}; u64 last_measure{}; u64 accumulated_ticks{}; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 547a6e07e..3f18dede2 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -184,6 +184,9 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& config.enable_fast_dispatch = false; } + // CNTPCT uses wall clock. + config.wall_clock_cntpct = true; + return std::make_shared(config); } -- cgit v1.2.3 From 1b82ccec2220a69711ba75cf51ee98cbcfe6a510 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 29 Feb 2020 13:58:50 -0400 Subject: Core: Refactor ARM Interface. --- src/core/arm/arm_interface.h | 9 ++++++--- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 6 +++--- src/core/arm/dynarmic/arm_dynarmic_32.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 13 ++++++++----- src/core/arm/dynarmic/arm_dynarmic_64.h | 2 +- src/core/arm/unicorn/arm_unicorn.cpp | 7 ++++--- src/core/arm/unicorn/arm_unicorn.h | 5 +++-- src/core/hle/kernel/kernel.cpp | 28 +++++++++++++++++++++++++++- src/core/hle/kernel/physical_core.cpp | 25 ++++++++----------------- src/core/hle/kernel/physical_core.h | 14 ++++++++------ 10 files changed, 69 insertions(+), 42 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index e701ddf21..dc9b2ff7b 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -7,6 +7,7 @@ #include #include #include "common/common_types.h" +#include "core/hardware_properties.h" namespace Common { struct PageTable; @@ -20,11 +21,13 @@ namespace Core { class System; class CPUInterruptHandler; +using CPUInterrupts = std::array; + /// Generic ARMv8 CPU interface class ARM_Interface : NonCopyable { public: - explicit ARM_Interface(System& system_, CPUInterruptHandler& interrupt_handler) - : system{system_}, interrupt_handler{interrupt_handler} {} + explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers) + : system{system_}, interrupt_handlers{interrupt_handlers} {} virtual ~ARM_Interface() = default; struct ThreadContext32 { @@ -180,7 +183,7 @@ public: protected: /// System context that this ARM interface is running under. System& system; - CPUInterruptHandler& interrupt_handler; + CPUInterrupts& interrupt_handlers; }; } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index c8a1ce6e7..f36c5f401 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -76,7 +76,7 @@ public: } u64 GetTicksRemaining() override { - if (!parent.interrupt_handler.IsInterrupted()) { + if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { return std::max(ticks, 0); } return 0ULL; @@ -111,9 +111,9 @@ void ARM_Dynarmic_32::Step() { jit->Step(); } -ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterruptHandler& interrupt_handler, +ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : ARM_Interface{system, interrupt_handler}, cb(std::make_unique(*this)), + : ARM_Interface{system, interrupt_handlers}, cb(std::make_unique(*this)), cp15(std::make_shared(*this)), core_index{core_index}, exclusive_monitor{dynamic_cast(exclusive_monitor)} {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 1e7e17e64..2dd9a4df0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -29,7 +29,7 @@ class System; class ARM_Dynarmic_32 final : public ARM_Interface { public: - ARM_Dynarmic_32(System& system, CPUInterruptHandler& interrupt_handler, + ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic_32() override; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 3f18dede2..8401ba631 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -128,7 +128,7 @@ public: } u64 GetTicksRemaining() override { - if (!parent.interrupt_handler.IsInterrupted()) { + if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { return std::max(ticks, 0); } return 0ULL; @@ -199,11 +199,14 @@ void ARM_Dynarmic_64::Step() { cb->InterpreterFallback(jit->GetPC(), 1); } -ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterruptHandler& interrupt_handler, +ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : ARM_Interface{system, interrupt_handler}, cb(std::make_unique(*this)), - inner_unicorn{system, interrupt_handler, ARM_Unicorn::Arch::AArch64}, core_index{core_index}, - exclusive_monitor{dynamic_cast(exclusive_monitor)} {} + : ARM_Interface{system, interrupt_handler}, + cb(std::make_unique(*this)), inner_unicorn{system, interrupt_handler, + ARM_Unicorn::Arch::AArch64, + core_index}, + core_index{core_index}, exclusive_monitor{ + dynamic_cast(exclusive_monitor)} {} ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 5560578ad..1c6791d4e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -28,7 +28,7 @@ class System; class ARM_Dynarmic_64 final : public ARM_Interface { public: - ARM_Dynarmic_64(System& system, CPUInterruptHandler& interrupt_handler, + ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic_64() override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 0393fe641..d81d1b5b0 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -63,8 +63,9 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si return false; } -ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture) - : ARM_Interface{system, interrupt_handler} { +ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, + std::size_t core_index) + : ARM_Interface{system, interrupt_handler}, core_index{core_index} { const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); @@ -163,7 +164,7 @@ void ARM_Unicorn::Run() { ExecuteInstructions(std::max(4000000U, 0U)); } else { while (true) { - if (interrupt_handler.IsInterrupted()) { + if (interrupt_handlers[core_index].IsInterrupted()) { return; } ExecuteInstructions(10); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 0a4c087cd..e3da368de 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -11,7 +11,6 @@ namespace Core { -class CPUInterruptHandler; class System; class ARM_Unicorn final : public ARM_Interface { @@ -21,7 +20,8 @@ public: AArch64, // 64-bit ARM }; - explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture); + explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, + std::size_t core_index); ~ARM_Unicorn() override; void SetPC(u64 pc) override; @@ -56,6 +56,7 @@ private: uc_engine* uc{}; GDBStub::BreakpointAddress last_bkpt{}; bool last_bkpt_hit = false; + std::size_t core_index; }; } // namespace Core diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index a19cd7a1f..e33ef5323 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include @@ -16,7 +17,9 @@ #include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -42,6 +45,11 @@ #include "core/hle/result.h" #include "core/memory.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif + MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -178,7 +186,20 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - cores.emplace_back(system, i, *exclusive_monitor); +#ifdef ARCHITECTURE_x86_64 + arm_interfaces_32[i] = + std::make_unique(system, interrupts, *exclusive_monitor, i); + arm_interfaces_64[i] = + std::make_unique(system, interrupts, *exclusive_monitor, i); +#else + arm_interfaces_32[i] = std::make_shared( + system, interrupts, ARM_Unicorn::Arch::AArch32, i); + arm_interfaces_64[i] = std::make_shared( + system, interrupts, ARM_Unicorn::Arch::AArch64, i); + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif + cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], + *arm_interfaces_64[i]); } } @@ -407,6 +428,11 @@ struct KernelCore::Impl { std::shared_ptr time_shared_mem; std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + std::array interrupts{}; + std::array, Core::Hardware::NUM_CPU_CORES> + arm_interfaces_32{}; + std::array, Core::Hardware::NUM_CPU_CORES> + arm_interfaces_64{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index ff14fcb42..9146b331d 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -21,21 +21,12 @@ namespace Kernel { PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor) - : interrupt_handler{}, core_index{id} { -#ifdef ARCHITECTURE_x86_64 - arm_interface_32 = std::make_unique(system, interrupt_handler, - exclusive_monitor, core_index); - arm_interface_64 = std::make_unique(system, interrupt_handler, - exclusive_monitor, core_index); -#else - using Core::ARM_Unicorn; - arm_interface_32 = - std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch32); - arm_interface_64 = - std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch64); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif + Core::ExclusiveMonitor& exclusive_monitor, + Core::CPUInterruptHandler& interrupt_handler, + Core::ARM_Interface& arm_interface32, + Core::ARM_Interface& arm_interface64) + : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, + arm_interface_64{arm_interface64} { scheduler = std::make_unique(system, core_index); guard = std::make_unique(); @@ -69,9 +60,9 @@ void PhysicalCore::Shutdown() { void PhysicalCore::SetIs64Bit(bool is_64_bit) { if (is_64_bit) { - arm_interface = arm_interface_64.get(); + arm_interface = &arm_interface_64; } else { - arm_interface = arm_interface_32.get(); + arm_interface = &arm_interface_32; } } diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index cd2e42fc3..2673d90f2 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { - class SpinLock; +class SpinLock; } namespace Kernel { @@ -27,7 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor); + PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, + Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, + Core::ARM_Interface& arm_interface64); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -92,13 +94,13 @@ public: void SetIs64Bit(bool is_64_bit); private: - Core::CPUInterruptHandler interrupt_handler; + Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - std::unique_ptr arm_interface_32; - std::unique_ptr arm_interface_64; + Core::ARM_Interface& arm_interface_32; + Core::ARM_Interface& arm_interface_64; std::unique_ptr scheduler; Core::ARM_Interface* arm_interface{}; - std::unique_ptr guard; + std::unique_ptr guard; }; } // namespace Kernel -- cgit v1.2.3 From 1567824d2da8e9b49b433f3d1d753d8ad84e65f9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 1 Mar 2020 12:14:17 -0400 Subject: General: Move ARM_Interface into Threads. --- src/core/arm/arm_interface.h | 2 ++ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 +++ src/core/arm/dynarmic/arm_dynarmic_32.h | 1 + src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 +++ src/core/arm/dynarmic/arm_dynarmic_64.h | 1 + src/core/arm/unicorn/arm_unicorn.cpp | 4 +++ src/core/arm/unicorn/arm_unicorn.h | 1 + src/core/core.cpp | 34 ++++++++---------- src/core/core_manager.cpp | 18 ++-------- src/core/cpu_manager.cpp | 30 ++++++++-------- src/core/hle/kernel/kernel.cpp | 59 +++++++++++-------------------- src/core/hle/kernel/kernel.h | 8 ++++- src/core/hle/kernel/physical_core.cpp | 37 +++---------------- src/core/hle/kernel/physical_core.h | 37 ++++--------------- src/core/hle/kernel/scheduler.cpp | 12 +++---- src/core/hle/kernel/svc.cpp | 11 ++---- src/core/hle/kernel/thread.cpp | 35 ++++++++++++++++++ src/core/hle/kernel/thread.h | 8 ++++- 18 files changed, 136 insertions(+), 170 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index dc9b2ff7b..e5c484336 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -148,6 +148,8 @@ public: */ virtual void SetTPIDR_EL0(u64 value) = 0; + virtual void ChangeProcessorId(std::size_t new_core_id) = 0; + virtual void SaveContext(ThreadContext32& ctx) = 0; virtual void SaveContext(ThreadContext64& ctx) = 0; virtual void LoadContext(const ThreadContext32& ctx) = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index f36c5f401..9c47c133c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -165,6 +165,10 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { cp15->uprw = static_cast(value); } +void ARM_Dynarmic_32::ChangeProcessorId(std::size_t new_core_id) { + // jit->ChangeProcessorId(new_core_id); +} + void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { Dynarmic::A32::Context context; jit->SaveContext(context); diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 2dd9a4df0..bea4933c8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -47,6 +47,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; + void ChangeProcessorId(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override; void SaveContext(ThreadContext64& ctx) override {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 8401ba631..03b3313cf 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -258,6 +258,10 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } +void ARM_Dynarmic_64::ChangeProcessorId(std::size_t new_core_id) { + jit->ChangeProcessorId(new_core_id); +} + void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 1c6791d4e..c26b47249 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -46,6 +46,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; + void ChangeProcessorId(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override {} void SaveContext(ThreadContext64& ctx) override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index d81d1b5b0..099229c8d 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -159,6 +159,10 @@ void ARM_Unicorn::SetTPIDR_EL0(u64 value) { CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value)); } +void ARM_Unicorn::ChangeProcessorId(std::size_t new_core_id) { + core_index = new_core_id; +} + void ARM_Unicorn::Run() { if (GDBStub::IsServerEnabled()) { ExecuteInstructions(std::max(4000000U, 0U)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index e3da368de..f09b24a85 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -36,6 +36,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; + void ChangeProcessorId(std::size_t new_core_id) override; void PrepareReschedule() override; void ClearExclusiveState() override; void ExecuteInstructions(std::size_t num_instructions); diff --git a/src/core/core.cpp b/src/core/core.cpp index 2ca9c0be5..40eea297e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -119,14 +119,6 @@ struct System::Impl { : kernel{system}, fs_controller{system}, memory{system}, cpu_manager{system}, reporter{system}, applet_manager{system} {} - Kernel::PhysicalCore& CurrentPhysicalCore() { - return kernel.CurrentPhysicalCore(); - } - - Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) { - return kernel.PhysicalCore(index); - } - ResultStatus Run() { status = ResultStatus::Success; @@ -443,7 +435,7 @@ bool System::IsPoweredOn() const { } void System::PrepareReschedule() { - impl->CurrentPhysicalCore().Stop(); + //impl->CurrentPhysicalCore().Stop(); } void System::PrepareReschedule(const u32 core_index) { @@ -463,11 +455,11 @@ const TelemetrySession& System::TelemetrySession() const { } ARM_Interface& System::CurrentArmInterface() { - return impl->CurrentPhysicalCore().ArmInterface(); + return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); } const ARM_Interface& System::CurrentArmInterface() const { - return impl->CurrentPhysicalCore().ArmInterface(); + return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); } std::size_t System::CurrentCoreIndex() const { @@ -477,27 +469,27 @@ std::size_t System::CurrentCoreIndex() const { } Kernel::Scheduler& System::CurrentScheduler() { - return impl->CurrentPhysicalCore().Scheduler(); + return impl->kernel.CurrentScheduler(); } const Kernel::Scheduler& System::CurrentScheduler() const { - return impl->CurrentPhysicalCore().Scheduler(); + return impl->kernel.CurrentScheduler(); } Kernel::PhysicalCore& System::CurrentPhysicalCore() { - return impl->CurrentPhysicalCore(); + return impl->kernel.CurrentPhysicalCore(); } const Kernel::PhysicalCore& System::CurrentPhysicalCore() const { - return impl->CurrentPhysicalCore(); + return impl->kernel.CurrentPhysicalCore(); } Kernel::Scheduler& System::Scheduler(std::size_t core_index) { - return impl->GetPhysicalCore(core_index).Scheduler(); + return impl->kernel.Scheduler(core_index); } const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { - return impl->GetPhysicalCore(core_index).Scheduler(); + return impl->kernel.Scheduler(core_index); } /// Gets the global scheduler @@ -527,11 +519,15 @@ const Kernel::Process* System::CurrentProcess() const { } ARM_Interface& System::ArmInterface(std::size_t core_index) { - return impl->GetPhysicalCore(core_index).ArmInterface(); + auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); + ASSERT(thread && !thread->IsHLEThread()); + return thread->ArmInterface(); } const ARM_Interface& System::ArmInterface(std::size_t core_index) const { - return impl->GetPhysicalCore(core_index).ArmInterface(); + auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); + ASSERT(thread && !thread->IsHLEThread()); + return thread->ArmInterface(); } ExclusiveMonitor& System::Monitor() { diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp index 45f0bb547..82d7acb40 100644 --- a/src/core/core_manager.cpp +++ b/src/core/core_manager.cpp @@ -28,21 +28,7 @@ CoreManager::CoreManager(System& system, std::size_t core_index) CoreManager::~CoreManager() = default; void CoreManager::RunLoop(bool tight_loop) { - Reschedule(); - - // If we don't have a currently active thread then don't execute instructions, - // instead advance to the next event and try to yield to the next thread - if (Kernel::GetCurrentThread() == nullptr) { - LOG_TRACE(Core, "Core-{} idling", core_index); - } else { - if (tight_loop) { - physical_core.Run(); - } else { - physical_core.Step(); - } - } - - Reschedule(); + /// Deprecated } void CoreManager::SingleStep() { @@ -50,7 +36,7 @@ void CoreManager::SingleStep() { } void CoreManager::PrepareReschedule() { - physical_core.Stop(); + //physical_core.Stop(); } void CoreManager::Reschedule() { diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 2aea95a25..2e9dc9dc3 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -129,18 +129,17 @@ void CpuManager::MultiCoreRunGuestThread() { void CpuManager::MultiCoreRunGuestLoop() { auto& kernel = system.Kernel(); auto* thread = kernel.CurrentScheduler().GetCurrentThread(); - auto host_context = thread->GetHostContext(); - host_context->SetRewindPoint(std::function(GuestRewindFunction), this); - host_context.reset(); while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); + auto* physical_core = &kernel.CurrentPhysicalCore(); + auto& arm_interface = thread->ArmInterface(); system.EnterDynarmicProfile(); - while (!physical_core.IsInterrupted()) { - physical_core.Run(); + while (!physical_core->IsInterrupted()) { + arm_interface.Run(); + physical_core = &kernel.CurrentPhysicalCore(); } system.ExitDynarmicProfile(); - physical_core.ClearExclusive(); - auto& scheduler = physical_core.Scheduler(); + arm_interface.ClearExclusiveState(); + auto& scheduler = kernel.CurrentScheduler(); scheduler.TryDoContextSwitch(); } } @@ -150,7 +149,7 @@ void CpuManager::MultiCoreRunIdleThread() { while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); physical_core.Idle(); - auto& scheduler = physical_core.Scheduler(); + auto& scheduler = kernel.CurrentScheduler(); scheduler.TryDoContextSwitch(); } } @@ -229,14 +228,13 @@ void CpuManager::SingleCoreRunGuestThread() { void CpuManager::SingleCoreRunGuestLoop() { auto& kernel = system.Kernel(); auto* thread = kernel.CurrentScheduler().GetCurrentThread(); - auto host_context = thread->GetHostContext(); - host_context->SetRewindPoint(std::function(GuestRewindFunction), this); - host_context.reset(); while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); + auto* physical_core = &kernel.CurrentPhysicalCore(); + auto& arm_interface = thread->ArmInterface(); system.EnterDynarmicProfile(); - while (!physical_core.IsInterrupted()) { - physical_core.Run(); + while (!physical_core->IsInterrupted()) { + arm_interface.Run(); + physical_core = &kernel.CurrentPhysicalCore(); preemption_count++; if (preemption_count % max_cycle_runs == 0) { break; @@ -246,7 +244,7 @@ void CpuManager::SingleCoreRunGuestLoop() { thread->SetPhantomMode(true); system.CoreTiming().Advance(); thread->SetPhantomMode(false); - physical_core.ClearExclusive(); + arm_interface.ClearExclusiveState(); PreemptSingleCore(); auto& scheduler = kernel.Scheduler(current_core); scheduler.TryDoContextSwitch(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e33ef5323..3feddd9ad 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -19,7 +19,6 @@ #include "core/arm/arm_interface.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" -#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -45,11 +44,6 @@ #include "core/hle/result.h" #include "core/memory.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif - MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -186,20 +180,8 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { -#ifdef ARCHITECTURE_x86_64 - arm_interfaces_32[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); - arm_interfaces_64[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); -#else - arm_interfaces_32[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch32, i); - arm_interfaces_64[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch64, i); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif - cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], - *arm_interfaces_64[i]); + schedulers[i] = std::make_unique(system, i); + cores.emplace_back(system, i, *schedulers[i], interrupts[i]); } } @@ -268,10 +250,6 @@ struct KernelCore::Impl { return; } - for (auto& core : cores) { - core.SetIs64Bit(process->Is64BitProcess()); - } - u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); @@ -429,10 +407,7 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_32{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_64{}; + std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; @@ -497,11 +472,11 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { } Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { @@ -525,11 +500,23 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { } Kernel::Scheduler& KernelCore::CurrentScheduler() { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; } const Kernel::Scheduler& KernelCore::CurrentScheduler() const { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; +} + +std::array& KernelCore::Interrupts() { + return impl->interrupts; +} + +const std::array& KernelCore::Interrupts() const { + return impl->interrupts; } Kernel::Synchronization& KernelCore::Synchronization() { @@ -557,15 +544,11 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { - PhysicalCore(i).ArmInterface().ClearInstructionCache(); - } + //TODO: Reimplement, this } void KernelCore::PrepareReschedule(std::size_t id) { - if (id < impl->global_scheduler.CpuCoresCount()) { - impl->cores[id].Stop(); - } + // TODO: Reimplement, this } void KernelCore::AddNamedPort(std::string name, std::shared_ptr port) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1eb6ede73..846056b85 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,15 +4,17 @@ #pragma once +#include #include #include #include #include +#include "core/hardware_properties.h" #include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/object.h" namespace Core { -struct EmuThreadHandle; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -144,6 +146,10 @@ public: const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + std::array& Interrupts(); + + const std::array& Interrupts() const; + void InvalidateAllInstructionCaches(); /// Adds a port to the named port table diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 9146b331d..c82c60a16 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -20,50 +20,21 @@ namespace Kernel { -PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, - Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64) - : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, - arm_interface_64{arm_interface64} { +PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler) + : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { - scheduler = std::make_unique(system, core_index); guard = std::make_unique(); } PhysicalCore::~PhysicalCore() = default; -void PhysicalCore::Run() { - arm_interface->Run(); -} - -void PhysicalCore::ClearExclusive() { - arm_interface->ClearExclusiveState(); -} - -void PhysicalCore::Step() { - arm_interface->Step(); -} - void PhysicalCore::Idle() { interrupt_handler.AwaitInterrupt(); } -void PhysicalCore::Stop() { - arm_interface->PrepareReschedule(); -} - void PhysicalCore::Shutdown() { - scheduler->Shutdown(); -} - -void PhysicalCore::SetIs64Bit(bool is_64_bit) { - if (is_64_bit) { - arm_interface = &arm_interface_64; - } else { - arm_interface = &arm_interface_32; - } + scheduler.Shutdown(); } void PhysicalCore::Interrupt() { diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 2673d90f2..751b994a7 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { -class SpinLock; + class SpinLock; } namespace Kernel { @@ -27,9 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64); + PhysicalCore(Core::System& system, std::size_t id, + Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -38,17 +38,7 @@ public: PhysicalCore(PhysicalCore&&) = default; PhysicalCore& operator=(PhysicalCore&&) = default; - /// Execute current jit state - void Run(); - /// Clear Exclusive state. - void ClearExclusive(); - /// Set this core in IdleState. void Idle(); - /// Execute a single instruction in current jit. - void Step(); - /// Stop JIT execution/exit - void Stop(); - /// Interrupt this physical core. void Interrupt(); @@ -63,14 +53,6 @@ public: // Shutdown this physical core. void Shutdown(); - Core::ARM_Interface& ArmInterface() { - return *arm_interface; - } - - const Core::ARM_Interface& ArmInterface() const { - return *arm_interface; - } - bool IsMainCore() const { return core_index == 0; } @@ -84,22 +66,17 @@ public: } Kernel::Scheduler& Scheduler() { - return *scheduler; + return scheduler; } const Kernel::Scheduler& Scheduler() const { - return *scheduler; + return scheduler; } - void SetIs64Bit(bool is_64_bit); - private: Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - Core::ARM_Interface& arm_interface_32; - Core::ARM_Interface& arm_interface_64; - std::unique_ptr scheduler; - Core::ARM_Interface* arm_interface{}; + Kernel::Scheduler& scheduler; std::unique_ptr guard; }; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 8d56b49ce..a5083ae7c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -681,15 +681,16 @@ void Scheduler::SwitchContextStep2() { new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); - if (previous_process != thread_owner_process && thread_owner_process != nullptr) { + if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = new_thread->ArmInterface(); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ChangeProcessorId(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -722,18 +723,15 @@ void Scheduler::SwitchContext() { } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + previous_thread->SetIsRunning(false); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } - if (previous_thread->GetStatus() == ThreadStatus::Running) { - previous_thread->SetStatus(ThreadStatus::Ready); - } - previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f08745226..599972211 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1533,7 +1533,9 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } if (is_redundant && !system.Kernel().IsMulticore()) { + system.Kernel().ExitSVCProfile(); system.GetCpuManager().PreemptSingleCore(); + system.Kernel().EnterSVCProfile(); } } @@ -2457,9 +2459,6 @@ void Call(Core::System& system, u32 immediate) { auto& kernel = system.Kernel(); kernel.EnterSVCProfile(); - auto* thread = system.CurrentScheduler().GetCurrentThread(); - thread->SetContinuousOnSVC(true); - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { @@ -2473,12 +2472,6 @@ void Call(Core::System& system, u32 immediate) { } kernel.ExitSVCProfile(); - - if (!thread->IsContinuousOnSVC()) { - auto* host_context = thread->GetHostContext().get(); - host_context->Rewind(); - } - system.EnterDynarmicProfile(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6f8e7a070..58b06aa9e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,13 @@ #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif +#include "core/arm/cpu_interrupt_handler.h" +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -232,7 +239,27 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context + thread->arm_interface.reset(); if ((type_flags & THREADTYPE_HLE) == 0) { +#ifdef ARCHITECTURE_x86_64 + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } else { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } + +#else + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + } else { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + } + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif ResetThreadContext32(thread->context_32, static_cast(stack_top), static_cast(entry_point), static_cast(arg)); ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); @@ -276,6 +303,14 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + command_header_offset; } +Core::ARM_Interface& Thread::ArmInterface() { + return *arm_interface; +} + +const Core::ARM_Interface& Thread::ArmInterface() const { + return *arm_interface; +} + void Thread::SetStatus(ThreadStatus new_status) { if (new_status == status) { return; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f998890c4..c08fc3a89 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -21,6 +21,7 @@ class Fiber; } namespace Core { +class ARM_Interface; class System; } // namespace Core @@ -271,6 +272,10 @@ public: void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); + Core::ARM_Interface& ArmInterface(); + + const Core::ARM_Interface& ArmInterface() const; + SynchronizationObject* GetSignalingObject() const { return signaling_object; } @@ -617,9 +622,10 @@ private: void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); + Common::SpinLock context_guard{}; ThreadContext32 context_32{}; ThreadContext64 context_64{}; - Common::SpinLock context_guard{}; + std::unique_ptr arm_interface{}; std::shared_ptr host_context{}; u64 thread_id = 0; -- cgit v1.2.3 From f5e32935ca9d1727624c86ca78aff91027caf819 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 28 Mar 2020 15:23:28 -0400 Subject: SingleCore: Use Cycle Timing instead of Host Timing. --- src/core/arm/arm_interface.h | 6 +++-- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 37 +++++++++++++++++++--------- src/core/arm/dynarmic/arm_dynarmic_32.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 39 +++++++++++++++++++---------- src/core/arm/dynarmic/arm_dynarmic_64.h | 2 +- src/core/arm/unicorn/arm_unicorn.cpp | 6 ++--- src/core/arm/unicorn/arm_unicorn.h | 4 +-- src/core/core_timing.cpp | 41 +++++++++++++++++++++++++------ src/core/core_timing.h | 14 ++++++++--- src/core/core_timing_util.cpp | 29 +++++++++++++++------- src/core/core_timing_util.h | 15 +++-------- src/core/cpu_manager.cpp | 18 +++++++------- src/core/cpu_manager.h | 2 +- src/core/hle/kernel/svc.cpp | 5 ++++ src/core/hle/kernel/thread.cpp | 12 ++++++--- 15 files changed, 152 insertions(+), 80 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index e5c484336..fbdce4134 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -26,8 +26,9 @@ using CPUInterrupts = std::arrayticks -= ticks; + if (parent.uses_wall_clock) { + return; + } + // 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::Hardware::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 { - if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return std::max(ticks, 0); + if (parent.uses_wall_clock) { + if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { + return std::max(1000U, 0); + } + return 0ULL; } - return 0ULL; - } - - void ResetTicks() { - ticks = 1000LL; + return std::max(parent.system.CoreTiming().GetDowncount(), 0LL); } ARM_Dynarmic_32& parent; std::size_t num_interpreted_instructions{}; - s64 ticks{}; }; std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, @@ -103,7 +115,6 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& } void ARM_Dynarmic_32::Run() { - cb->ResetTicks(); jit->Run(); } @@ -112,8 +123,10 @@ void ARM_Dynarmic_32::Step() { } ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, - ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : ARM_Interface{system, interrupt_handlers}, cb(std::make_unique(*this)), + bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, + std::size_t core_index) + : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, + cb(std::make_unique(*this)), cp15(std::make_shared(*this)), core_index{core_index}, exclusive_monitor{dynamic_cast(exclusive_monitor)} {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index bea4933c8..8afd15c8b 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -29,7 +29,7 @@ class System; class ARM_Dynarmic_32 final : public ARM_Interface { public: - ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, + ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic_32() override; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 03b3313cf..a518733b6 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -124,29 +124,41 @@ public: } void AddTicks(u64 ticks) override { - this->ticks -= ticks; + if (parent.uses_wall_clock) { + return; + } + // 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::Hardware::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 { - if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return std::max(ticks, 0); + if (parent.uses_wall_clock) { + if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { + return std::max(1000U, 0); + } + return 0ULL; } - return 0ULL; + return std::max(parent.system.CoreTiming().GetDowncount(), 0LL); } u64 GetCNTPCT() override { return parent.system.CoreTiming().GetClockTicks(); } - void ResetTicks() { - ticks = 1000LL; - } - ARM_Dynarmic_64& parent; std::size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; - s64 ticks{}; }; std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, @@ -185,13 +197,12 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& } // CNTPCT uses wall clock. - config.wall_clock_cntpct = true; + config.wall_clock_cntpct = uses_wall_clock; return std::make_shared(config); } void ARM_Dynarmic_64::Run() { - cb->ResetTicks(); jit->Run(); } @@ -200,9 +211,11 @@ void ARM_Dynarmic_64::Step() { } ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, - ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : ARM_Interface{system, interrupt_handler}, + bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, + std::size_t core_index) + : ARM_Interface{system, interrupt_handler, uses_wall_clock}, cb(std::make_unique(*this)), inner_unicorn{system, interrupt_handler, + uses_wall_clock, ARM_Unicorn::Arch::AArch64, core_index}, core_index{core_index}, exclusive_monitor{ diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index c26b47249..31ec16521 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -28,7 +28,7 @@ class System; class ARM_Dynarmic_64 final : public ARM_Interface { public: - ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, + ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); ~ARM_Dynarmic_64() override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 099229c8d..1cb71942b 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -63,9 +63,9 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si return false; } -ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, - std::size_t core_index) - : ARM_Interface{system, interrupt_handler}, core_index{core_index} { +ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, + bool uses_wall_clock, Arch architecture, std::size_t core_index) + : ARM_Interface{system, interrupt_handler, uses_wall_clock}, core_index{core_index} { const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index f09b24a85..a01751e65 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -20,8 +20,8 @@ public: AArch64, // 64-bit ARM }; - explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, - std::size_t core_index); + explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, + bool uses_wall_clock, Arch architecture, std::size_t core_index); ~ARM_Unicorn() override; void SetPC(u64 pc) override; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 189d4aa34..12e9e60a4 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -14,6 +14,8 @@ namespace Core::Timing { +constexpr u64 MAX_SLICE_LENGTH = 4000; + std::shared_ptr CreateEvent(std::string name, TimedCallback&& callback) { return std::make_shared(std::move(callback), std::move(name)); } @@ -53,6 +55,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) { void CoreTiming::Initialize(std::function&& on_thread_init_) { on_thread_init = std::move(on_thread_init_); event_fifo_id = 0; + ticks = 0; const auto empty_timed_callback = [](u64, s64) {}; ev_lost = CreateEvent("_lost_event", empty_timed_callback); if (is_multicore) { @@ -126,20 +129,36 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, u basic_lock.unlock(); } -void CoreTiming::AddTicks(std::size_t core_index, u64 ticks) { - ticks_count[core_index] += ticks; +void CoreTiming::AddTicks(u64 ticks) { + this->ticks += ticks; + downcount -= ticks; } -void CoreTiming::ResetTicks(std::size_t core_index) { - ticks_count[core_index] = 0; +void CoreTiming::Idle() { + if (!event_queue.empty()) { + u64 next_event_time = event_queue.front().time; + ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; + return; + } + ticks += 1000U; +} + +void CoreTiming::ResetTicks() { + downcount = MAX_SLICE_LENGTH; } u64 CoreTiming::GetCPUTicks() const { - return clock->GetCPUCycles(); + if (is_multicore) { + return clock->GetCPUCycles(); + } + return ticks; } u64 CoreTiming::GetClockTicks() const { - return clock->GetClockCycles(); + if (is_multicore) { + return clock->GetClockCycles(); + } + return CpuCyclesToClockCycles(ticks); } void CoreTiming::ClearPendingEvents() { @@ -217,11 +236,17 @@ void CoreTiming::ThreadLoop() { } std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { - return clock->GetTimeNS(); + if (is_multicore) { + return clock->GetTimeNS(); + } + return CyclesToNs(ticks); } std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { - return clock->GetTimeUS(); + if (is_multicore) { + return clock->GetTimeUS(); + } + return CyclesToUs(ticks); } } // namespace Core::Timing diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 03f9a5c76..ed5de9b97 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -98,9 +98,15 @@ public: /// We only permit one event of each type in the queue at a time. void RemoveEvent(const std::shared_ptr& event_type); - void AddTicks(std::size_t core_index, u64 ticks); + void AddTicks(u64 ticks); - void ResetTicks(std::size_t core_index); + void ResetTicks(); + + void Idle(); + + s64 GetDowncount() const { + return downcount; + } /// Returns current time in emulated CPU cycles u64 GetCPUTicks() const; @@ -154,7 +160,9 @@ private: bool is_multicore{}; - std::array, Core::Hardware::NUM_CPU_CORES> ticks_count{}; + /// Cycle timing + u64 ticks{}; + s64 downcount{}; }; /// Creates a core timing event with the given name and callback. diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index be34b26fe..aefc63663 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp @@ -38,15 +38,8 @@ s64 usToCycles(std::chrono::microseconds us) { } s64 nsToCycles(std::chrono::nanoseconds ns) { - if (static_cast(ns.count() / 1000000000) > MAX_VALUE_TO_MULTIPLY) { - LOG_ERROR(Core_Timing, "Integer overflow, use max value"); - return std::numeric_limits::max(); - } - if (static_cast(ns.count()) > MAX_VALUE_TO_MULTIPLY) { - LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000); - } - return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000; + const u128 temporal = Common::Multiply64Into128(ns.count(), Hardware::BASE_CLOCK_RATE); + return Common::Divide128On32(temporal, static_cast(1000000000)).first; } u64 msToClockCycles(std::chrono::milliseconds ns) { @@ -69,4 +62,22 @@ u64 CpuCyclesToClockCycles(u64 ticks) { return Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; } +std::chrono::milliseconds CyclesToMs(s64 cycles) { + const u128 temporal = Common::Multiply64Into128(cycles, 1000); + u64 ms = Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; + return std::chrono::milliseconds(ms); +} + +std::chrono::nanoseconds CyclesToNs(s64 cycles) { + const u128 temporal = Common::Multiply64Into128(cycles, 1000000000); + u64 ns = Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; + return std::chrono::nanoseconds(ns); +} + +std::chrono::microseconds CyclesToUs(s64 cycles) { + const u128 temporal = Common::Multiply64Into128(cycles, 1000000); + u64 us = Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; + return std::chrono::microseconds(us); +} + } // namespace Core::Timing diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index b3c58447d..2ed979e14 100644 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h @@ -16,18 +16,9 @@ s64 nsToCycles(std::chrono::nanoseconds ns); u64 msToClockCycles(std::chrono::milliseconds ns); u64 usToClockCycles(std::chrono::microseconds ns); u64 nsToClockCycles(std::chrono::nanoseconds ns); - -inline std::chrono::milliseconds CyclesToMs(s64 cycles) { - return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE); -} - -inline std::chrono::nanoseconds CyclesToNs(s64 cycles) { - return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE); -} - -inline std::chrono::microseconds CyclesToUs(s64 cycles) { - return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE); -} +std::chrono::milliseconds CyclesToMs(s64 cycles); +std::chrono::nanoseconds CyclesToNs(s64 cycles); +std::chrono::microseconds CyclesToUs(s64 cycles); u64 CpuCyclesToClockCycles(u64 ticks); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 2e9dc9dc3..604405060 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -232,13 +232,10 @@ void CpuManager::SingleCoreRunGuestLoop() { auto* physical_core = &kernel.CurrentPhysicalCore(); auto& arm_interface = thread->ArmInterface(); system.EnterDynarmicProfile(); - while (!physical_core->IsInterrupted()) { + if (!physical_core->IsInterrupted()) { + system.CoreTiming().ResetTicks(); arm_interface.Run(); physical_core = &kernel.CurrentPhysicalCore(); - preemption_count++; - if (preemption_count % max_cycle_runs == 0) { - break; - } } system.ExitDynarmicProfile(); thread->SetPhantomMode(true); @@ -255,7 +252,7 @@ void CpuManager::SingleCoreRunIdleThread() { auto& kernel = system.Kernel(); while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); - PreemptSingleCore(); + PreemptSingleCore(false); idle_count++; auto& scheduler = physical_core.Scheduler(); scheduler.TryDoContextSwitch(); @@ -279,12 +276,15 @@ void CpuManager::SingleCoreRunSuspendThread() { } } -void CpuManager::PreemptSingleCore() { - preemption_count = 0; +void CpuManager::PreemptSingleCore(bool from_running_enviroment) { std::size_t old_core = current_core; auto& scheduler = system.Kernel().Scheduler(old_core); Kernel::Thread* current_thread = scheduler.GetCurrentThread(); - if (idle_count >= 4) { + if (idle_count >= 4 || from_running_enviroment) { + if (!from_running_enviroment) { + system.CoreTiming().Idle(); + idle_count = 0; + } current_thread->SetPhantomMode(true); system.CoreTiming().Advance(); current_thread->SetPhantomMode(false); diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index e6b8612f0..ae55d6427 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -55,7 +55,7 @@ public: std::function GetSuspendThreadStartFunc(); void* GetStartFuncParamater(); - void PreemptSingleCore(); + void PreemptSingleCore(bool from_running_enviroment = true); std::size_t CurrentCore() const { return current_core.load(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 599972211..c47fa9167 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1534,6 +1534,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (is_redundant && !system.Kernel().IsMulticore()) { system.Kernel().ExitSVCProfile(); + system.CoreTiming().AddTicks(1000U); system.GetCpuManager().PreemptSingleCore(); system.Kernel().EnterSVCProfile(); } @@ -1762,6 +1763,10 @@ static u64 GetSystemTick(Core::System& system) { // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) const u64 result{system.CoreTiming().GetClockTicks()}; + if (!system.Kernel().IsMulticore()) { + core_timing.AddTicks(400U); + } + return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 65fedfc9b..d88039a16 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -246,19 +246,23 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy #ifdef ARCHITECTURE_x86_64 if (owner_process && !owner_process->Is64BitProcess()) { thread->arm_interface = std::make_unique( - system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), + processor_id); } else { thread->arm_interface = std::make_unique( - system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), + processor_id); } #else if (owner_process && !owner_process->Is64BitProcess()) { thread->arm_interface = std::make_shared( - system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32, + processor_id); } else { thread->arm_interface = std::make_shared( - system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64, + processor_id); } LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif -- cgit v1.2.3 From 48fa3b7a0f2054a836b0a8061e6b082c246b5ae0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 1 Apr 2020 17:28:49 -0400 Subject: General: Cleanup legacy code. --- src/core/CMakeLists.txt | 2 - src/core/arm/dynarmic/arm_dynarmic_32.cpp | 1 - src/core/arm/dynarmic/arm_dynarmic_64.cpp | 1 - src/core/core_manager.cpp | 51 ------ src/core/core_manager.h | 63 -------- src/core/gdbstub/gdbstub.cpp | 1 - src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 81 +--------- src/core/hle/kernel/kernel.h | 3 - src/core/hle/kernel/svc.cpp | 3 +- src/core/hle/kernel/synchronization_object.cpp | 64 -------- src/core/hle/kernel/synchronization_object.h | 15 -- src/core/hle/kernel/thread.cpp | 34 ---- src/core/hle/kernel/thread.h | 56 +------ src/core/hle/service/sm/sm.cpp | 2 +- src/core/host_timing.cpp | 206 ------------------------- src/core/host_timing.h | 160 ------------------- src/tests/core/core_timing.cpp | 1 + src/yuzu/debugger/wait_tree.cpp | 2 +- 19 files changed, 8 insertions(+), 740 deletions(-) delete mode 100644 src/core/core_manager.cpp delete mode 100644 src/core/core_manager.h delete mode 100644 src/core/host_timing.cpp delete mode 100644 src/core/host_timing.h (limited to 'src/core/arm') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 552094ddb..653b7620b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -17,8 +17,6 @@ add_library(core STATIC constants.h core.cpp core.h - core_manager.cpp - core_manager.h core_timing.cpp core_timing.h core_timing_util.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index c4aeedef9..c8adf2866 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -12,7 +12,6 @@ #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" diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index a518733b6..14b394368 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -11,7 +11,6 @@ #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" #include "core/core.h" -#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/gdbstub/gdbstub.h" diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp deleted file mode 100644 index 82d7acb40..000000000 --- a/src/core/core_manager.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "common/logging/log.h" -#include "core/arm/exclusive_monitor.h" -#include "core/arm/unicorn/arm_unicorn.h" -#include "core/core.h" -#include "core/core_manager.h" -#include "core/core_timing.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/scheduler.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/lock.h" -#include "core/settings.h" - -namespace Core { - -CoreManager::CoreManager(System& system, std::size_t core_index) - : global_scheduler{system.GlobalScheduler()}, physical_core{system.Kernel().PhysicalCore( - core_index)}, - core_timing{system.CoreTiming()}, core_index{core_index} {} - -CoreManager::~CoreManager() = default; - -void CoreManager::RunLoop(bool tight_loop) { - /// Deprecated -} - -void CoreManager::SingleStep() { - return RunLoop(false); -} - -void CoreManager::PrepareReschedule() { - //physical_core.Stop(); -} - -void CoreManager::Reschedule() { - // Lock the global kernel mutex when we manipulate the HLE state - std::lock_guard lock(HLE::g_hle_lock); - - // global_scheduler.SelectThread(core_index); - - physical_core.Scheduler().TryDoContextSwitch(); -} - -} // namespace Core diff --git a/src/core/core_manager.h b/src/core/core_manager.h deleted file mode 100644 index d525de00a..000000000 --- a/src/core/core_manager.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include "common/common_types.h" - -namespace Kernel { -class GlobalScheduler; -class PhysicalCore; -} // namespace Kernel - -namespace Core { -class System; -} - -namespace Core::Timing { -class CoreTiming; -} - -namespace Core::Memory { -class Memory; -} - -namespace Core { - -constexpr unsigned NUM_CPU_CORES{4}; - -class CoreManager { -public: - CoreManager(System& system, std::size_t core_index); - ~CoreManager(); - - void RunLoop(bool tight_loop = true); - - void SingleStep(); - - void PrepareReschedule(); - - bool IsMainCore() const { - return core_index == 0; - } - - std::size_t CoreIndex() const { - return core_index; - } - -private: - void Reschedule(); - - Kernel::GlobalScheduler& global_scheduler; - Kernel::PhysicalCore& physical_core; - Timing::CoreTiming& core_timing; - - std::atomic reschedule_pending = false; - std::size_t core_index; -}; - -} // namespace Core diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 70c0f8b80..79f22a403 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -35,7 +35,6 @@ #include "common/swap.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_manager.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 5498fd313..8aff2227a 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -34,7 +34,7 @@ ResultVal> ClientPort::Connect() { } // Wake the threads waiting on the ServerPort - server_port->WakeupAllWaitingThreads(); + server_port->Signal(); return MakeResult(std::move(client)); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1f230fc4a..dbb75416d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -48,72 +48,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { -/** - * Callback that will wake up the thread it was scheduled for - * @param thread_handle The handle of the thread that's been awoken - * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time - */ -static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) { - UNREACHABLE(); - const auto proper_handle = static_cast(thread_handle); - const auto& system = Core::System::GetInstance(); - - // Lock the global kernel mutex when we enter the kernel HLE. - std::lock_guard lock{HLE::g_hle_lock}; - - std::shared_ptr thread = - system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); - if (thread == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); - return; - } - - bool resume = true; - - if (thread->GetStatus() == ThreadStatus::WaitSynch || - thread->GetStatus() == ThreadStatus::WaitHLEEvent) { - // Remove the thread from each of its waiting objects' waitlists - for (const auto& object : thread->GetSynchronizationObjects()) { - object->RemoveWaitingThread(thread); - } - thread->ClearSynchronizationObjects(); - - // Invoke the wakeup callback before clearing the wait objects - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0); - } - } else if (thread->GetStatus() == ThreadStatus::WaitMutex || - thread->GetStatus() == ThreadStatus::WaitCondVar) { - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - if (thread->GetStatus() == ThreadStatus::WaitCondVar) { - thread->GetOwnerProcess()->RemoveConditionVariableThread(thread); - thread->SetCondVarWaitAddress(0); - } - - auto* const lock_owner = thread->GetLockOwner(); - // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance - // and don't have a lock owner unless SignalProcessWideKey was called first and the thread - // wasn't awakened due to the mutex already being acquired. - if (lock_owner != nullptr) { - lock_owner->RemoveMutexWaiter(thread); - } - } - - if (thread->GetStatus() == ThreadStatus::WaitArb) { - auto& address_arbiter = thread->GetOwnerProcess()->GetAddressArbiter(); - address_arbiter.HandleWakeupThread(thread); - } - - if (resume) { - if (thread->GetStatus() == ThreadStatus::WaitCondVar || - thread->GetStatus() == ThreadStatus::WaitArb) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - } - thread->ResumeFromWait(); - } -} - struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} @@ -129,7 +63,6 @@ struct KernelCore::Impl { InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); InitializeMemoryLayout(); - InitializeThreads(); InitializePreemption(kernel); InitializeSchedulers(); InitializeSuspendThreads(); @@ -161,7 +94,6 @@ struct KernelCore::Impl { system_resource_limit = nullptr; global_handle_table.Clear(); - thread_wakeup_event_type = nullptr; preemption_event = nullptr; global_scheduler.Shutdown(); @@ -210,11 +142,6 @@ struct KernelCore::Impl { } } - void InitializeThreads() { - thread_wakeup_event_type = - Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); - } - void InitializePreemption(KernelCore& kernel) { preemption_event = Core::Timing::CreateEvent( "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { @@ -376,7 +303,6 @@ struct KernelCore::Impl { std::shared_ptr system_resource_limit; - std::shared_ptr thread_wakeup_event_type; std::shared_ptr preemption_event; // This is the kernel's handle table or supervisor handle table which @@ -516,7 +442,8 @@ std::array& KernelCore return impl->interrupts; } -const std::array& KernelCore::Interrupts() const { +const std::array& KernelCore::Interrupts() + const { return impl->interrupts; } @@ -595,10 +522,6 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -const std::shared_ptr& KernelCore::ThreadWakeupCallbackEventType() const { - return impl->thread_wakeup_event_type; -} - Kernel::HandleTable& KernelCore::GlobalHandleTable() { return impl->global_handle_table; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 846056b85..49bd47e89 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -241,9 +241,6 @@ private: /// Creates a new thread ID, incrementing the internal thread ID counter. u64 CreateNewThreadID(); - /// Retrieves the event type used for thread wakeup callbacks. - const std::shared_ptr& ThreadWakeupCallbackEventType() const; - /// Provides a reference to the global handle table. Kernel::HandleTable& GlobalHandleTable(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dbd35580e..781032cd1 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -16,7 +16,6 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/cpu_manager.h" @@ -1909,7 +1908,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_COMBINATION; } - if (core < Core::NUM_CPU_CORES) { + if (core < Core::Hardware::NUM_CPU_CORES) { if ((affinity_mask & (1ULL << core)) == 0) { LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", core, diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index be9e09106..ba4d39157 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -38,70 +38,6 @@ void SynchronizationObject::RemoveWaitingThread(std::shared_ptr thread) waiting_threads.erase(itr); } -std::shared_ptr SynchronizationObject::GetHighestPriorityReadyThread() const { - Thread* candidate = nullptr; - u32 candidate_priority = THREADPRIO_LOWEST + 1; - - for (const auto& thread : waiting_threads) { - const ThreadStatus thread_status = thread->GetStatus(); - - // The list of waiting threads must not contain threads that are not waiting to be awakened. - ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || - thread_status == ThreadStatus::WaitHLEEvent, - "Inconsistent thread statuses in waiting_threads"); - - if (thread->GetPriority() >= candidate_priority) - continue; - - if (ShouldWait(thread.get())) - continue; - - candidate = thread.get(); - candidate_priority = thread->GetPriority(); - } - - return SharedFrom(candidate); -} - -void SynchronizationObject::WakeupWaitingThread(std::shared_ptr thread) { - ASSERT(!ShouldWait(thread.get())); - - if (!thread) { - return; - } - - if (thread->IsSleepingOnWait()) { - for (const auto& object : thread->GetSynchronizationObjects()) { - ASSERT(!object->ShouldWait(thread.get())); - object->Acquire(thread.get()); - } - } else { - Acquire(thread.get()); - } - - const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this)); - - thread->ClearSynchronizationObjects(); - - thread->CancelWakeupTimer(); - - bool resume = true; - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), - index); - } - if (resume) { - thread->ResumeFromWait(); - kernel.PrepareReschedule(thread->GetProcessorID()); - } -} - -void SynchronizationObject::WakeupAllWaitingThreads() { - while (auto thread = GetHighestPriorityReadyThread()) { - WakeupWaitingThread(thread); - } -} - void SynchronizationObject::ClearWaitingThreads() { waiting_threads.clear(); } diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index a35544ac1..f89b24204 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -50,21 +50,6 @@ public: */ void RemoveWaitingThread(std::shared_ptr thread); - /** - * Wake up all threads waiting on this object that can be awoken, in priority order, - * and set the synchronization result and output of the thread. - */ - void /* deprecated */ WakeupAllWaitingThreads(); - - /** - * Wakes up a single thread waiting on this object. - * @param thread Thread that is waiting on this object to wakeup. - */ - void WakeupWaitingThread(std::shared_ptr thread); - - /// Obtains the highest priority thread that is ready to run from this object's waiting list. - std::shared_ptr /* deprecated */ GetHighestPriorityReadyThread() const; - /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d88039a16..fba2a9c85 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,9 +56,6 @@ Thread::~Thread() = default; void Thread::Stop() { { SchedulerLock lock(kernel); - // Cancel any outstanding wakeup events for this thread - Core::System::GetInstance().CoreTiming().UnscheduleEvent( - kernel.ThreadWakeupCallbackEventType(), global_handle); SetStatus(ThreadStatus::Dead); Signal(); kernel.GlobalHandleTable().Close(global_handle); @@ -75,22 +72,6 @@ void Thread::Stop() { global_handle = 0; } -void Thread::WakeAfterDelay(s64 nanoseconds) { - // Don't schedule a wakeup if the thread wants to wait forever - if (nanoseconds == -1) - return; - - // This function might be called from any thread so we have to be cautious and use the - // thread-safe version of ScheduleEvent. - Core::System::GetInstance().CoreTiming().ScheduleEvent( - nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle); -} - -void Thread::CancelWakeupTimer() { - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - global_handle); -} - void Thread::ResumeFromWait() { SchedulerLock lock(kernel); switch (status) { @@ -284,14 +265,6 @@ void Thread::SetPriority(u32 priority) { UpdatePriority(); } -void Thread::SetWaitSynchronizationResult(ResultCode result) { - UNREACHABLE(); -} - -void Thread::SetWaitSynchronizationOutput(s32 output) { - UNREACHABLE(); -} - void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { signaling_object = object; signaling_result = result; @@ -425,13 +398,6 @@ bool Thread::AllSynchronizationObjectsReady() const { }); } -bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) { - ASSERT(wakeup_callback); - return wakeup_callback(reason, std::move(thread), std::move(object), index); -} - bool Thread::InvokeHLECallback(std::shared_ptr thread) { ASSERT(hle_callback); return hle_callback(std::move(thread)); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 61963148d..3ae0df6ef 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -128,9 +128,6 @@ public: using ThreadSynchronizationObjects = std::vector>; - using WakeupCallback = - std::function thread, - std::shared_ptr object, std::size_t index)>; using HLECallback = std::function thread)>; /** @@ -235,7 +232,7 @@ public: } /// Resumes a thread from waiting - void /* deprecated */ ResumeFromWait(); + void ResumeFromWait(); void OnWakeUp(); @@ -249,27 +246,6 @@ public: /// void CancelWait(); - /** - * Schedules an event to wake up the specified thread after the specified delay - * @param nanoseconds The time this thread will be allowed to sleep for - */ - void /* deprecated */ WakeAfterDelay(s64 nanoseconds); - - /// Cancel any outstanding wakeup events for this thread - void /* deprecated */ CancelWakeupTimer(); - - /** - * Sets the result after the thread awakens (from svcWaitSynchronization) - * @param result Value to set to the returned result - */ - void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result); - - /** - * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) - * @param output Value to set to the output parameter - */ - void /*deprecated*/ SetWaitSynchronizationOutput(s32 output); - void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); Core::ARM_Interface& ArmInterface(); @@ -330,11 +306,6 @@ public: */ VAddr GetCommandBufferAddress() const; - /// Returns whether this thread is waiting on objects from a WaitSynchronization call. - bool IsSleepingOnWait() const { - return status == ThreadStatus::WaitSynch; - } - ThreadContext32& GetContext32() { return context_32; } @@ -469,18 +440,10 @@ public: arb_wait_address = address; } - bool HasWakeupCallback() const { - return wakeup_callback != nullptr; - } - bool HasHLECallback() const { return hle_callback != nullptr; } - void SetWakeupCallback(WakeupCallback callback) { - wakeup_callback = std::move(callback); - } - void SetHLECallback(HLECallback callback) { hle_callback = std::move(callback); } @@ -501,22 +464,10 @@ public: return hle_object; } - void InvalidateWakeupCallback() { - SetWakeupCallback(nullptr); - } - void InvalidateHLECallback() { SetHLECallback(nullptr); } - /** - * Invokes the thread's wakeup callback. - * - * @pre A valid wakeup callback has been set. Violating this precondition - * will cause an assertion to trigger. - */ - bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index); bool InvokeHLECallback(std::shared_ptr thread); u32 GetIdealCore() const { @@ -698,11 +649,6 @@ private: /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle global_handle = 0; - /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread - /// was waiting via WaitSynchronization then the object will be the last object that became - /// available. In case of a timeout, the object will be nullptr. DEPRECATED - WakeupCallback wakeup_callback; - /// Callback for HLE Events HLECallback hle_callback; Handle hle_time_event; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 6ada13be4..d872de16c 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -142,7 +142,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { } // Wake the threads waiting on the ServerPort - server_port->WakeupAllWaitingThreads(); + server_port->Signal(); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; diff --git a/src/core/host_timing.cpp b/src/core/host_timing.cpp deleted file mode 100644 index 2f40de1a1..000000000 --- a/src/core/host_timing.cpp +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/host_timing.h" - -#include -#include -#include -#include - -#include "common/assert.h" -#include "core/core_timing_util.h" - -namespace Core::HostTiming { - -std::shared_ptr CreateEvent(std::string name, TimedCallback&& callback) { - return std::make_shared(std::move(callback), std::move(name)); -} - -struct CoreTiming::Event { - u64 time; - u64 fifo_order; - u64 userdata; - std::weak_ptr type; - - // Sort by time, unless the times are the same, in which case sort by - // the order added to the queue - friend bool operator>(const Event& left, const Event& right) { - return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order); - } - - friend bool operator<(const Event& left, const Event& right) { - return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order); - } -}; - -CoreTiming::CoreTiming() { - clock = - Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ); -} - -CoreTiming::~CoreTiming() = default; - -void CoreTiming::ThreadEntry(CoreTiming& instance) { - instance.ThreadLoop(); -} - -void CoreTiming::Initialize() { - event_fifo_id = 0; - const auto empty_timed_callback = [](u64, s64) {}; - ev_lost = CreateEvent("_lost_event", empty_timed_callback); - timer_thread = std::make_unique(ThreadEntry, std::ref(*this)); -} - -void CoreTiming::Shutdown() { - paused = true; - shutting_down = true; - event.Set(); - timer_thread->join(); - ClearPendingEvents(); - timer_thread.reset(); - has_started = false; -} - -void CoreTiming::Pause(bool is_paused) { - paused = is_paused; -} - -void CoreTiming::SyncPause(bool is_paused) { - if (is_paused == paused && paused_set == paused) { - return; - } - Pause(is_paused); - event.Set(); - while (paused_set != is_paused) - ; -} - -bool CoreTiming::IsRunning() const { - return !paused_set; -} - -bool CoreTiming::HasPendingEvents() const { - return !(wait_set && event_queue.empty()); -} - -void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr& event_type, - u64 userdata) { - basic_lock.lock(); - const u64 timeout = static_cast(GetGlobalTimeNs().count() + ns_into_future); - - event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); - - std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - basic_lock.unlock(); - event.Set(); -} - -void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, u64 userdata) { - basic_lock.lock(); - const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { - return e.type.lock().get() == event_type.get() && e.userdata == userdata; - }); - - // Removing random items breaks the invariant so we have to re-establish it. - if (itr != event_queue.end()) { - event_queue.erase(itr, event_queue.end()); - std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - } - basic_lock.unlock(); -} - -void CoreTiming::AddTicks(std::size_t core_index, u64 ticks) { - ticks_count[core_index] += ticks; -} - -void CoreTiming::ResetTicks(std::size_t core_index) { - ticks_count[core_index] = 0; -} - -u64 CoreTiming::GetCPUTicks() const { - return clock->GetCPUCycles(); -} - -u64 CoreTiming::GetClockTicks() const { - return clock->GetClockCycles(); -} - -void CoreTiming::ClearPendingEvents() { - event_queue.clear(); -} - -void CoreTiming::RemoveEvent(const std::shared_ptr& event_type) { - basic_lock.lock(); - - const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { - return e.type.lock().get() == event_type.get(); - }); - - // Removing random items breaks the invariant so we have to re-establish it. - if (itr != event_queue.end()) { - event_queue.erase(itr, event_queue.end()); - std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - } - basic_lock.unlock(); -} - -std::optional CoreTiming::Advance() { - advance_lock.lock(); - basic_lock.lock(); - global_timer = GetGlobalTimeNs().count(); - - while (!event_queue.empty() && event_queue.front().time <= global_timer) { - Event evt = std::move(event_queue.front()); - std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - event_queue.pop_back(); - basic_lock.unlock(); - - if (auto event_type{evt.type.lock()}) { - event_type->callback(evt.userdata, global_timer - evt.time); - } - - basic_lock.lock(); - } - - if (!event_queue.empty()) { - const u64 next_time = event_queue.front().time - global_timer; - basic_lock.unlock(); - advance_lock.unlock(); - return next_time; - } else { - basic_lock.unlock(); - advance_lock.unlock(); - return std::nullopt; - } -} - -void CoreTiming::ThreadLoop() { - has_started = true; - while (!shutting_down) { - while (!paused) { - paused_set = false; - const auto next_time = Advance(); - if (next_time) { - std::chrono::nanoseconds next_time_ns = std::chrono::nanoseconds(*next_time); - event.WaitFor(next_time_ns); - } else { - wait_set = true; - event.Wait(); - } - wait_set = false; - } - paused_set = true; - } -} - -std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { - return clock->GetTimeNS(); -} - -std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { - return clock->GetTimeUS(); -} - -} // namespace Core::HostTiming diff --git a/src/core/host_timing.h b/src/core/host_timing.h deleted file mode 100644 index be6b68d7c..000000000 --- a/src/core/host_timing.h +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common/common_types.h" -#include "common/spin_lock.h" -#include "common/thread.h" -#include "common/threadsafe_queue.h" -#include "common/wall_clock.h" -#include "core/hardware_properties.h" - -namespace Core::HostTiming { - -/// A callback that may be scheduled for a particular core timing event. -using TimedCallback = std::function; - -/// Contains the characteristics of a particular event. -struct EventType { - EventType(TimedCallback&& callback, std::string&& name) - : callback{std::move(callback)}, name{std::move(name)} {} - - /// The event's callback function. - TimedCallback callback; - /// A pointer to the name of the event. - const std::string name; -}; - -/** - * This is a system to schedule events into the emulated machine's future. Time is measured - * in main CPU clock cycles. - * - * To schedule an event, you first have to register its type. This is where you pass in the - * callback. You then schedule events using the type id you get back. - * - * The int cyclesLate that the callbacks get is how many cycles late it was. - * So to schedule a new event on a regular basis: - * inside callback: - * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") - */ -class CoreTiming { -public: - CoreTiming(); - ~CoreTiming(); - - CoreTiming(const CoreTiming&) = delete; - CoreTiming(CoreTiming&&) = delete; - - CoreTiming& operator=(const CoreTiming&) = delete; - CoreTiming& operator=(CoreTiming&&) = delete; - - /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is - /// required to end slice - 1 and start slice 0 before the first cycle of code is executed. - void Initialize(); - - /// Tears down all timing related functionality. - void Shutdown(); - - /// Pauses/Unpauses the execution of the timer thread. - void Pause(bool is_paused); - - /// Pauses/Unpauses the execution of the timer thread and waits until paused. - void SyncPause(bool is_paused); - - /// Checks if core timing is running. - bool IsRunning() const; - - /// Checks if the timer thread has started. - bool HasStarted() const { - return has_started; - } - - /// Checks if there are any pending time events. - bool HasPendingEvents() const; - - /// Schedules an event in core timing - void ScheduleEvent(s64 ns_into_future, const std::shared_ptr& event_type, - u64 userdata = 0); - - void UnscheduleEvent(const std::shared_ptr& event_type, u64 userdata); - - /// We only permit one event of each type in the queue at a time. - void RemoveEvent(const std::shared_ptr& event_type); - - void AddTicks(std::size_t core_index, u64 ticks); - - void ResetTicks(std::size_t core_index); - - /// Returns current time in emulated CPU cycles - u64 GetCPUTicks() const; - - /// Returns current time in emulated in Clock cycles - u64 GetClockTicks() const; - - /// Returns current time in microseconds. - std::chrono::microseconds GetGlobalTimeUs() const; - - /// Returns current time in nanoseconds. - std::chrono::nanoseconds GetGlobalTimeNs() const; - - /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. - std::optional Advance(); - -private: - struct Event; - - /// Clear all pending events. This should ONLY be done on exit. - void ClearPendingEvents(); - - static void ThreadEntry(CoreTiming& instance); - void ThreadLoop(); - - std::unique_ptr clock; - - u64 global_timer = 0; - - std::chrono::nanoseconds start_point; - - // The queue is a min-heap using std::make_heap/push_heap/pop_heap. - // We don't use std::priority_queue because we need to be able to serialize, unserialize and - // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't - // accomodated by the standard adaptor class. - std::vector event_queue; - u64 event_fifo_id = 0; - - std::shared_ptr ev_lost; - Common::Event event{}; - Common::SpinLock basic_lock{}; - Common::SpinLock advance_lock{}; - std::unique_ptr timer_thread; - std::atomic paused{}; - std::atomic paused_set{}; - std::atomic wait_set{}; - std::atomic shutting_down{}; - std::atomic has_started{}; - - std::array, Core::Hardware::NUM_CPU_CORES> ticks_count{}; -}; - -/// Creates a core timing event with the given name and callback. -/// -/// @param name The name of the core timing event to create. -/// @param callback The callback to execute for the event. -/// -/// @returns An EventType instance representing the created event. -/// -std::shared_ptr CreateEvent(std::string name, TimedCallback&& callback); - -} // namespace Core::HostTiming diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index 795f3da09..21a5840fb 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -39,6 +39,7 @@ u64 callbacks_done = 0; struct ScopeInit final { ScopeInit() { + core_timing.SetMulticore(true); core_timing.Initialize([]() {}); } ~ScopeInit() { diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index d2dbb259c..0226ae2e2 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -340,7 +340,7 @@ std::vector> WaitTreeThread::GetChildren() const { if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { list.push_back(std::make_unique(thread.GetSynchronizationObjects(), - thread.IsSleepingOnWait())); + thread.IsWaitingSync())); } list.push_back(std::make_unique(thread)); -- cgit v1.2.3 From 7b44187fd277a87cf33891c1fdc023dae87abfbc Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 3 Apr 2020 14:11:04 -0400 Subject: Dynarmic Interface: don't clear cache if JIT has not been created. --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 3 +++ src/core/arm/dynarmic/arm_dynarmic_64.cpp | 3 +++ 2 files changed, 6 insertions(+) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index c8adf2866..bd9c072d0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -200,6 +200,9 @@ void ARM_Dynarmic_32::PrepareReschedule() { } void ARM_Dynarmic_32::ClearInstructionCache() { + if (!jit) { + return; + } jit->ClearCache(); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 14b394368..99eb2ea4a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -301,6 +301,9 @@ void ARM_Dynarmic_64::PrepareReschedule() { } void ARM_Dynarmic_64::ClearInstructionCache() { + if (!jit) { + return; + } jit->ClearCache(); } -- cgit v1.2.3 From dda6147b0dc882c053fc02c987aa87140471649a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 28 Apr 2020 23:15:04 -0400 Subject: ARMInterface: Correct rebase errors. --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 ++-- src/core/arm/unicorn/arm_unicorn.cpp | 4 ++-- src/core/arm/unicorn/arm_unicorn.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 99eb2ea4a..226fd4915 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -212,8 +212,8 @@ void ARM_Dynarmic_64::Step() { ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : ARM_Interface{system, interrupt_handler, uses_wall_clock}, - cb(std::make_unique(*this)), inner_unicorn{system, interrupt_handler, + : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, + cb(std::make_unique(*this)), inner_unicorn{system, interrupt_handlers, uses_wall_clock, ARM_Unicorn::Arch::AArch64, core_index}, diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 1cb71942b..9f9690454 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -63,9 +63,9 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si return false; } -ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, +ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, Arch architecture, std::size_t core_index) - : ARM_Interface{system, interrupt_handler, uses_wall_clock}, core_index{core_index} { + : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} { const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index a01751e65..9b7d7f6c2 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -20,7 +20,7 @@ public: AArch64, // 64-bit ARM }; - explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, + explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, Arch architecture, std::size_t core_index); ~ARM_Unicorn() override; -- cgit v1.2.3 From 3714f2e471e06856499432761981760c557d2d90 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 2 May 2020 22:03:09 -0400 Subject: ARMInterface/Externals: Update dynarmic and fit to latest version. --- externals/dynarmic | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/arm') diff --git a/externals/dynarmic b/externals/dynarmic index e7166e8ba..f4922a97f 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit e7166e8ba74d7b9c85e87afc0aaf667e7e84cfe0 +Subproject commit f4922a97f6eb4b93decfbd80a881a7eac89d6890 diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 226fd4915..8095901d1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -195,7 +195,7 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& config.enable_fast_dispatch = false; } - // CNTPCT uses wall clock. + // Timing config.wall_clock_cntpct = uses_wall_clock; return std::make_shared(config); @@ -271,7 +271,7 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { } void ARM_Dynarmic_64::ChangeProcessorId(std::size_t new_core_id) { - jit->ChangeProcessorId(new_core_id); + jit->ChangeProcessorID(new_core_id); } void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { @@ -358,31 +358,31 @@ void DynarmicExclusiveMonitor::ClearExclusive() { } bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&](u8 expected) -> bool { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u8 expected) -> bool { return memory.WriteExclusive8(vaddr, value, expected); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 2, [&](u16 expected) -> bool { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u16 expected) -> bool { return memory.WriteExclusive16(vaddr, value, expected); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 4, [&](u32 expected) -> bool { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u32 expected) -> bool { return memory.WriteExclusive32(vaddr, value, expected); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 8, [&](u64 expected) -> bool { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u64 expected) -> bool { return memory.WriteExclusive64(vaddr, value, expected); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&](u128 expected) -> bool { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u128 expected) -> bool { return memory.WriteExclusive128(vaddr, value, expected); }); } -- cgit v1.2.3 From 467d43570e10b98fa33067352d35fe62ceb3cb9e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 May 2020 18:53:13 -0400 Subject: Clang Format. --- src/common/atomic_ops.cpp | 14 +++++++------- src/common/atomic_ops.h | 2 +- src/common/thread.cpp | 30 +++++++++++++++--------------- src/core/arm/unicorn/arm_unicorn.cpp | 4 ++-- src/core/arm/unicorn/arm_unicorn.h | 4 ++-- src/core/core.h | 2 -- src/core/hle/kernel/mutex.cpp | 11 +++++------ src/core/hle/kernel/mutex.h | 3 ++- src/core/hle/kernel/physical_core.h | 7 +++---- src/core/hle/kernel/server_session.cpp | 2 +- src/yuzu/bootmanager.cpp | 1 - src/yuzu/bootmanager.h | 3 ++- src/yuzu/debugger/wait_tree.cpp | 5 +++-- src/yuzu/main.cpp | 9 ++++++--- 14 files changed, 49 insertions(+), 48 deletions(-) (limited to 'src/core/arm') diff --git a/src/common/atomic_ops.cpp b/src/common/atomic_ops.cpp index 65cdfb4fd..6b2236114 100644 --- a/src/common/atomic_ops.cpp +++ b/src/common/atomic_ops.cpp @@ -35,26 +35,26 @@ bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) { } bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { - return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0], (__int64*)expected.data()) != 0; + return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0], + (__int64*)expected.data()) != 0; } - #else bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) { - return __sync_bool_compare_and_swap (pointer, value, expected); + return __sync_bool_compare_and_swap(pointer, value, expected); } bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) { - return __sync_bool_compare_and_swap (pointer, value, expected); + return __sync_bool_compare_and_swap(pointer, value, expected); } bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) { - return __sync_bool_compare_and_swap (pointer, value, expected); + return __sync_bool_compare_and_swap(pointer, value, expected); } bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) { - return __sync_bool_compare_and_swap (pointer, value, expected); + return __sync_bool_compare_and_swap(pointer, value, expected); } bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { @@ -62,7 +62,7 @@ bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { unsigned __int128 expected_a; std::memcpy(&value_a, value.data(), sizeof(u128)); std::memcpy(&expected_a, expected.data(), sizeof(u128)); - return __sync_bool_compare_and_swap ((unsigned __int128*)pointer, value_a, expected_a); + return __sync_bool_compare_and_swap((unsigned __int128*)pointer, value_a, expected_a); } #endif diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index 22cb3a402..e6181d521 100644 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h @@ -8,7 +8,7 @@ namespace Common { -bool AtomicCompareAndSwap(u8 volatile * pointer, u8 value, u8 expected); +bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected); bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected); bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected); bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected); diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 33c8437f5..8e5935e6a 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -31,21 +31,21 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) { auto handle = GetCurrentThread(); int windows_priority = 0; switch (new_priority) { - case ThreadPriority::Low: - windows_priority = THREAD_PRIORITY_BELOW_NORMAL; - break; - case ThreadPriority::Normal: - windows_priority = THREAD_PRIORITY_NORMAL; - break; - case ThreadPriority::High: - windows_priority = THREAD_PRIORITY_ABOVE_NORMAL; - break; - case ThreadPriority::VeryHigh: - windows_priority = THREAD_PRIORITY_HIGHEST; - break; - default: - windows_priority = THREAD_PRIORITY_NORMAL; - break; + case ThreadPriority::Low: + windows_priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case ThreadPriority::Normal: + windows_priority = THREAD_PRIORITY_NORMAL; + break; + case ThreadPriority::High: + windows_priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case ThreadPriority::VeryHigh: + windows_priority = THREAD_PRIORITY_HIGHEST; + break; + default: + windows_priority = THREAD_PRIORITY_NORMAL; + break; } SetThreadPriority(handle, windows_priority); } diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 9f9690454..35e8f42e8 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -63,8 +63,8 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si return false; } -ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, - bool uses_wall_clock, Arch architecture, std::size_t core_index) +ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, + Arch architecture, std::size_t core_index) : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} { const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 9b7d7f6c2..8ace8b86f 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -20,8 +20,8 @@ public: AArch64, // 64-bit ARM }; - explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, - bool uses_wall_clock, Arch architecture, std::size_t core_index); + explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, + Arch architecture, std::size_t core_index); ~ARM_Unicorn() override; void SetPC(u64 pc) override; diff --git a/src/core/core.h b/src/core/core.h index 87df79d57..d2d1fcc5b 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -148,8 +148,6 @@ public: */ ResultStatus Pause(); - - /** * Step the CPU one instruction * @return Result status, indicating whether or not the operation succeeded. diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 32dc1ffae..8f6c944d1 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,7 +9,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -126,11 +125,11 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, std::pair> Mutex::Unlock(std::shared_ptr owner, VAddr address) { - // The mutex address must be 4-byte aligned - if ((address % sizeof(u32)) != 0) { - LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); - return {ERR_INVALID_ADDRESS, nullptr}; - } + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); + return {ERR_INVALID_ADDRESS, nullptr}; + } auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address); if (new_owner == nullptr) { diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bce06ecea..3b81dc3df 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -29,7 +29,8 @@ public: Handle requesting_thread_handle); /// Unlocks a mutex for owner at address - std::pair> Unlock(std::shared_ptr owner, VAddr address); + std::pair> Unlock(std::shared_ptr owner, + VAddr address); /// Releases the mutex at the specified address. ResultCode Release(VAddr address); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 751b994a7..85f6dec05 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { - class SpinLock; +class SpinLock; } namespace Kernel { @@ -27,9 +27,8 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, - Kernel::Scheduler& scheduler, - Core::CPUInterruptHandler& interrupt_handler); + PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index e988a3f22..7b23a6889 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -17,9 +17,9 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" -#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 5f93bd432..4bfce48a4 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -71,7 +71,6 @@ void EmuThread::run() { gpu.ReleaseContext(); - // Holds whether the cpu was running during the last iteration, // so that the DebugModeLeft signal can be emitted before the // next execution step diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 768568b3e..6c59b4d5c 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -62,7 +62,8 @@ public: if (!running) { running_wait.Set(); /// Wait until effectively paused - while (running_guard); + while (running_guard) + ; } } diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 0226ae2e2..9bb0a0109 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -127,11 +127,12 @@ std::vector> WaitTreeCallstack::GetChildren() cons return list; } - auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(Core::System::GetInstance(), thread.GetContext64()); + auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(Core::System::GetInstance(), + thread.GetContext64()); for (auto& entry : backtrace) { std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, - entry.original_address, entry.offset, entry.name); + entry.original_address, entry.offset, entry.name); list.push_back(std::make_unique(QString::fromStdString(s))); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f1d9ec326..53790c89c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -534,7 +534,8 @@ void GMainWindow::InitializeWidgets() { if (emulation_running) { return; } - bool is_async = !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; + bool is_async = + !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; Settings::values.use_asynchronous_gpu_emulation = is_async; async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); Settings::Apply(); @@ -552,7 +553,8 @@ void GMainWindow::InitializeWidgets() { return; } Settings::values.use_multi_core = !Settings::values.use_multi_core; - bool is_async = Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; + bool is_async = + Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; Settings::values.use_asynchronous_gpu_emulation = is_async; async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); multicore_status_button->setChecked(Settings::values.use_multi_core); @@ -1958,7 +1960,8 @@ void GMainWindow::OnConfigure() { dock_status_button->setChecked(Settings::values.use_docked_mode); multicore_status_button->setChecked(Settings::values.use_multi_core); - Settings::values.use_asynchronous_gpu_emulation = Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; + Settings::values.use_asynchronous_gpu_emulation = + Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); #ifdef HAS_VULKAN -- cgit v1.2.3 From 0a8013d71eebf13864e73c94075ef969e76cb485 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 14 May 2020 14:48:50 -0400 Subject: ARMDynarmicInterface: Correct GCC Build Errors. --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 6 +++--- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index bd9c072d0..71d7e169a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -91,11 +91,11 @@ public: u64 GetTicksRemaining() override { if (parent.uses_wall_clock) { if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return std::max(1000U, 0); + return 1000U; } - return 0ULL; + return 0U; } - return std::max(parent.system.CoreTiming().GetDowncount(), 0LL); + return std::max(parent.system.CoreTiming().GetDowncount(), 0); } ARM_Dynarmic_32& parent; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 8095901d1..8e8f7ce0a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -143,11 +143,11 @@ public: u64 GetTicksRemaining() override { if (parent.uses_wall_clock) { if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return std::max(1000U, 0); + return 1000U; } - return 0ULL; + return 0U; } - return std::max(parent.system.CoreTiming().GetDowncount(), 0LL); + return std::max(parent.system.CoreTiming().GetDowncount(), 0); } u64 GetCNTPCT() override { -- cgit v1.2.3 From ec11918323bec287c8b71cea6baee193c417fb38 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 18 Jun 2020 17:47:44 -0400 Subject: ArmDynarmic32: Setup CNTPCT correctly --- src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/arm') diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index d43e4dd70..54556e0f9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp @@ -97,7 +97,7 @@ CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc const auto callback = static_cast( [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 { ARM_Dynarmic_32& parent = *(ARM_Dynarmic_32*)arg; - return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks()); + return parent.system.CoreTiming().GetClockTicks(); }); return Dynarmic::A32::Coprocessor::Callback{callback, (void*)&parent}; } -- cgit v1.2.3 From b8df61c642310aeab3118f2637d4447740b8fcd3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 18 Jun 2020 19:56:59 -0400 Subject: ARM: Update Dynarmic and Setup A32 according to latest interface. --- externals/dynarmic | 2 +- src/core/CMakeLists.txt | 8 +++ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 41 ++++++++++++- src/core/arm/dynarmic/arm_dynarmic_32.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 65 +-------------------- src/core/arm/dynarmic/arm_dynarmic_64.h | 25 -------- src/core/arm/dynarmic/arm_exclusive_monitor.cpp | 76 +++++++++++++++++++++++++ src/core/arm/dynarmic/arm_exclusive_monitor.h | 48 ++++++++++++++++ src/core/arm/exclusive_monitor.cpp | 2 +- 9 files changed, 175 insertions(+), 94 deletions(-) create mode 100644 src/core/arm/dynarmic/arm_exclusive_monitor.cpp create mode 100644 src/core/arm/dynarmic/arm_exclusive_monitor.h (limited to 'src/core/arm') diff --git a/externals/dynarmic b/externals/dynarmic index 3a50d444d..b759773b3 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit 3a50d444dcb66c868528dd12057f63dc623d09a5 +Subproject commit b759773b3b76c62200ecd4e097ec6ecfd825aacb diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 653b7620b..f87d67db5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -9,6 +9,14 @@ add_library(core STATIC arm/arm_interface.cpp arm/cpu_interrupt_handler.cpp arm/cpu_interrupt_handler.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 + arm/dynarmic/arm_exclusive_monitor.cpp + arm/dynarmic/arm_exclusive_monitor.h arm/exclusive_monitor.cpp arm/exclusive_monitor.h arm/unicorn/arm_unicorn.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 71d7e169a..5df4fc079 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -7,14 +7,17 @@ #include #include #include +#include "common/logging/log.h" +#include "common/page_table.h" #include "core/arm/cpu_interrupt_handler.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/arm/dynarmic/arm_exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/svc.h" #include "core/memory.h" +#include "core/settings.h" namespace Core { @@ -48,6 +51,19 @@ public: parent.system.Memory().Write64(vaddr, value); } + bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { + return parent.system.Memory().WriteExclusive8(vaddr, value, expected); + } + bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { + return parent.system.Memory().WriteExclusive16(vaddr, value, expected); + } + bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { + return parent.system.Memory().WriteExclusive32(vaddr, value, expected); + } + bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { + return parent.system.Memory().WriteExclusive64(vaddr, value, expected); + } + void InterpreterFallback(u32 pc, std::size_t num_instructions) override { UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc, MemoryReadCode(pc)); @@ -110,6 +126,27 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& // config.page_table = &page_table.pointers; config.coprocessors[15] = cp15; config.define_unpredictable_behaviour = true; + static constexpr std::size_t PAGE_BITS = 12; + static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS); + config.page_table = reinterpret_cast*>( + page_table.pointers.data()); + config.absolute_offset_page_table = true; + config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; + config.only_detect_misalignment_via_page_table_on_page_boundary = true; + + // Multi-process state + config.processor_id = core_index; + config.global_monitor = &exclusive_monitor.monitor; + + // Timing + config.wall_clock_cntpct = uses_wall_clock; + + // Optimizations + if (Settings::values.disable_cpu_opt) { + config.enable_optimizations = false; + config.enable_fast_dispatch = false; + } + return std::make_unique(config); } @@ -178,7 +215,7 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { } void ARM_Dynarmic_32::ChangeProcessorId(std::size_t new_core_id) { - // jit->ChangeProcessorId(new_core_id); + jit->ChangeProcessorID(new_core_id); } void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 8afd15c8b..d9c0bfede 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 8e8f7ce0a..35a99e28a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -10,6 +10,7 @@ #include "common/page_table.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" +#include "core/arm/dynarmic/arm_exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -323,68 +324,4 @@ void ARM_Dynarmic_64::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() = default; - -u8 DynarmicExclusiveMonitor::ExclusiveRead8(std::size_t core_index, VAddr addr) { - return monitor.ReadAndMark(core_index, addr, [&]() -> u8 { return memory.Read8(addr); }); -} - -u16 DynarmicExclusiveMonitor::ExclusiveRead16(std::size_t core_index, VAddr addr) { - return monitor.ReadAndMark(core_index, addr, [&]() -> u16 { return memory.Read16(addr); }); -} - -u32 DynarmicExclusiveMonitor::ExclusiveRead32(std::size_t core_index, VAddr addr) { - return monitor.ReadAndMark(core_index, addr, [&]() -> u32 { return memory.Read32(addr); }); -} - -u64 DynarmicExclusiveMonitor::ExclusiveRead64(std::size_t core_index, VAddr addr) { - return monitor.ReadAndMark(core_index, addr, [&]() -> u64 { return memory.Read64(addr); }); -} - -u128 DynarmicExclusiveMonitor::ExclusiveRead128(std::size_t core_index, VAddr addr) { - return monitor.ReadAndMark(core_index, addr, [&]() -> u128 { - u128 result; - result[0] = memory.Read64(addr); - result[1] = memory.Read64(addr + 8); - return result; - }); -} - -void DynarmicExclusiveMonitor::ClearExclusive() { - monitor.Clear(); -} - -bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, [&](u8 expected) -> bool { - return memory.WriteExclusive8(vaddr, value, expected); - }); -} - -bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, [&](u16 expected) -> bool { - return memory.WriteExclusive16(vaddr, value, expected); - }); -} - -bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, [&](u32 expected) -> bool { - return memory.WriteExclusive32(vaddr, value, expected); - }); -} - -bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, [&](u64 expected) -> bool { - return memory.WriteExclusive64(vaddr, value, expected); - }); -} - -bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, [&](u128 expected) -> bool { - return memory.WriteExclusive128(vaddr, value, expected); - }); -} - } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 31ec16521..c74fcbcea 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -8,7 +8,6 @@ #include #include -#include #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" @@ -78,28 +77,4 @@ private: DynarmicExclusiveMonitor& exclusive_monitor; }; -class DynarmicExclusiveMonitor final : public ExclusiveMonitor { -public: - explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); - ~DynarmicExclusiveMonitor() override; - - u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override; - u16 ExclusiveRead16(std::size_t core_index, VAddr addr) override; - u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override; - u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override; - u128 ExclusiveRead128(std::size_t core_index, VAddr addr) override; - void ClearExclusive() 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_64; - Dynarmic::A64::ExclusiveMonitor monitor; - Core::Memory::Memory& memory; -}; - } // namespace Core diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp new file mode 100644 index 000000000..4e209f6a5 --- /dev/null +++ b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp @@ -0,0 +1,76 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "core/arm/dynarmic/arm_exclusive_monitor.h" +#include "core/memory.h" + +namespace Core { + +DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count) + : monitor(core_count), memory{memory} {} + +DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; + +u8 DynarmicExclusiveMonitor::ExclusiveRead8(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u8 { return memory.Read8(addr); }); +} + +u16 DynarmicExclusiveMonitor::ExclusiveRead16(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u16 { return memory.Read16(addr); }); +} + +u32 DynarmicExclusiveMonitor::ExclusiveRead32(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u32 { return memory.Read32(addr); }); +} + +u64 DynarmicExclusiveMonitor::ExclusiveRead64(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u64 { return memory.Read64(addr); }); +} + +u128 DynarmicExclusiveMonitor::ExclusiveRead128(std::size_t core_index, VAddr addr) { + return monitor.ReadAndMark(core_index, addr, [&]() -> u128 { + u128 result; + result[0] = memory.Read64(addr); + result[1] = memory.Read64(addr + 8); + return result; + }); +} + +void DynarmicExclusiveMonitor::ClearExclusive() { + monitor.Clear(); +} + +bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u8 expected) -> bool { + return memory.WriteExclusive8(vaddr, value, expected); + }); +} + +bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u16 expected) -> bool { + return memory.WriteExclusive16(vaddr, value, expected); + }); +} + +bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u32 expected) -> bool { + return memory.WriteExclusive32(vaddr, value, expected); + }); +} + +bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u64 expected) -> bool { + return memory.WriteExclusive64(vaddr, value, expected); + }); +} + +bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { + return monitor.DoExclusiveOperation(core_index, vaddr, [&](u128 expected) -> bool { + return memory.WriteExclusive128(vaddr, value, expected); + }); +} + +} // namespace Core diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/arm_exclusive_monitor.h new file mode 100644 index 000000000..964f4a55d --- /dev/null +++ b/src/core/arm/dynarmic/arm_exclusive_monitor.h @@ -0,0 +1,48 @@ +// 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 "common/common_types.h" +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#include "core/arm/exclusive_monitor.h" + +namespace Core::Memory { +class Memory; +} + +namespace Core { + +class DynarmicExclusiveMonitor final : public ExclusiveMonitor { +public: + explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); + ~DynarmicExclusiveMonitor() override; + + u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override; + u16 ExclusiveRead16(std::size_t core_index, VAddr addr) override; + u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override; + u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override; + u128 ExclusiveRead128(std::size_t core_index, VAddr addr) override; + void ClearExclusive() 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_32; + friend class ARM_Dynarmic_64; + Dynarmic::ExclusiveMonitor monitor; + Core::Memory::Memory& memory; +}; + +} // namespace Core diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp index b32401e0b..d8cba369d 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_64.h" +#include "core/arm/dynarmic/arm_exclusive_monitor.h" #endif #include "core/arm/exclusive_monitor.h" #include "core/memory.h" -- cgit v1.2.3 From 4105f38022a525aab2e7d4288f121b4f0a0dd7b2 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Jun 2020 19:40:07 -0400 Subject: SVC: Implement 32-bits wrappers and update Dynarmic. --- externals/dynarmic | 2 +- src/core/arm/arm_interface.h | 5 +- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 8 +- src/core/hle/kernel/svc.cpp | 198 ++++++++++++++++++++++++++---- src/core/hle/kernel/svc_wrap.h | 105 +++++++++++++++- 5 files changed, 283 insertions(+), 35 deletions(-) (limited to 'src/core/arm') diff --git a/externals/dynarmic b/externals/dynarmic index b759773b3..4f967387c 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit b759773b3b76c62200ecd4e097ec6ecfd825aacb +Subproject commit 4f967387c07365b7ea35d2fa3e19b7df8872a09b diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index fbdce4134..0c1d6ac39 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -33,16 +33,15 @@ public: struct ThreadContext32 { std::array cpu_registers{}; + std::array extension_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); + static_assert(sizeof(ThreadContext32) == 0x150); struct ThreadContext64 { std::array cpu_registers{}; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 5df4fc079..cfda12098 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -222,13 +222,17 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { Dynarmic::A32::Context context; jit->SaveContext(context); ctx.cpu_registers = context.Regs(); + ctx.extension_registers = context.ExtRegs(); ctx.cpsr = context.Cpsr(); + ctx.fpscr = context.Fpscr(); } void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { Dynarmic::A32::Context context; context.Regs() = ctx.cpu_registers; + context.ExtRegs() = ctx.extension_registers; context.SetCpsr(ctx.cpsr); + context.SetFpscr(ctx.fpscr); jit->LoadContext(context); } @@ -243,7 +247,9 @@ void ARM_Dynarmic_32::ClearInstructionCache() { jit->ClearCache(); } -void ARM_Dynarmic_32::ClearExclusiveState() {} +void ARM_Dynarmic_32::ClearExclusiveState() { + jit->ClearExclusiveState(); +} void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, std::size_t new_address_space_size_in_bits) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1d47a2779..5db19dcf3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -254,6 +254,11 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr return page_table.Map(dst_addr, src_addr, size); } +static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { + return MapMemory(system, static_cast(dst_addr), static_cast(src_addr), + static_cast(size)); +} + /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -270,6 +275,11 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad return page_table.Unmap(dst_addr, src_addr, size); } +static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { + return UnmapMemory(system, static_cast(dst_addr), static_cast(src_addr), + static_cast(size)); +} + /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { @@ -417,6 +427,15 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return ERR_INVALID_HANDLE; } +static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, + Handle handle) { + u64 process_id{}; + const auto result = GetProcessId(system, &process_id, handle); + *process_id_low = static_cast(process_id); + *process_id_high = static_cast(process_id >> 32); + return result; +} + /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, u64 handle_count, s64 nano_seconds) { @@ -484,6 +503,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand return RESULT_SUCCESS; } +static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { + return CancelSynchronization(system, thread_handle); +} + /// Attempts to locks a mutex, creating it if it does not already exist static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_handle, VAddr mutex_addr, Handle requesting_thread_handle) { @@ -508,6 +531,12 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand requesting_thread_handle); } +static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle, + u32 mutex_addr, Handle requesting_thread_handle) { + return ArbitrateLock(system, holding_thread_handle, static_cast(mutex_addr), + requesting_thread_handle); +} + /// Unlock a mutex static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); @@ -527,6 +556,10 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { return current_process->GetMutex().Release(mutex_addr); } +static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) { + return ArbitrateUnlock(system, static_cast(mutex_addr)); +} + enum class BreakType : u32 { Panic = 0, AssertionFailed = 1, @@ -645,6 +678,10 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { } } +static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { + Break(system, reason, static_cast(info1), static_cast(info2)); +} + /// Used to output a message on a debug hardware unit - does nothing on a retail unit static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { if (len == 0) { @@ -973,6 +1010,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) return page_table.MapPhysicalMemory(addr, size); } +static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { + return MapPhysicalMemory(system, static_cast(addr), static_cast(size)); +} + /// Unmaps memory previously mapped via MapPhysicalMemory static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1023,6 +1064,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size return page_table.UnmapPhysicalMemory(addr, size); } +static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { + return UnmapPhysicalMemory(system, static_cast(addr), static_cast(size)); +} + /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); @@ -1055,6 +1100,10 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return thread->SetActivity(static_cast(activity)); } +static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { + return SetThreadActivity(system, handle, activity); +} + /// Gets the thread context static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); @@ -1096,6 +1145,10 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H return RESULT_SUCCESS; } +static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { + return GetThreadContext(system, static_cast(thread_context), handle); +} + /// Gets the priority for the specified thread static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { LOG_TRACE(Kernel_SVC, "called"); @@ -1228,6 +1281,12 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return shared_memory->Map(*current_process, addr, size, permission_type); } +static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, + u32 size, u32 permissions) { + return MapSharedMemory(system, shared_memory_handle, static_cast(addr), + static_cast(size), permissions); +} + static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { @@ -1426,6 +1485,10 @@ static void ExitProcess(Core::System& system) { system.CurrentScheduler().GetCurrentThread()->Stop(); } +static void ExitProcess32(Core::System& system) { + ExitProcess(system); +} + /// Creates a new thread static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, u32 priority, s32 processor_id) { @@ -1489,6 +1552,12 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return RESULT_SUCCESS; } +static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority, + u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { + return CreateThread(system, out_handle, static_cast(entry_point), static_cast(arg), + static_cast(stack_top), priority, processor_id); +} + /// Starts the thread for the provided handle static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); @@ -1506,6 +1575,10 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { return thread->Start(); } +static ResultCode StartThread32(Core::System& system, Handle thread_handle) { + return StartThread(system, thread_handle); +} + /// Called when a thread exits static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); @@ -1515,6 +1588,10 @@ static void ExitThread(Core::System& system) { current_thread->Stop(); } +static void ExitThread32(Core::System& system) { + ExitThread(system); +} + /// Sleep the current thread static void SleepThread(Core::System& system, s64 nanoseconds) { LOG_DEBUG(Kernel_SVC, "called nanoseconds={}", nanoseconds); @@ -1561,6 +1638,12 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } } +static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { + const s64 nanoseconds = static_cast(static_cast(nanoseconds_low) | + (static_cast(nanoseconds_high) << 32)); + SleepThread(system, nanoseconds); +} + /// Wait process wide key atomic static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_addr, VAddr condition_variable_addr, Handle thread_handle, @@ -1640,6 +1723,16 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return current_thread->GetSignalingResult(); } +static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr, + u32 condition_variable_addr, Handle thread_handle, + u32 nanoseconds_low, u32 nanoseconds_high) { + const s64 nanoseconds = + static_cast(nanoseconds_low | (static_cast(nanoseconds_high) << 32)); + return WaitProcessWideKeyAtomic(system, static_cast(mutex_addr), + static_cast(condition_variable_addr), thread_handle, + nanoseconds); +} + /// Signal process wide key static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_addr, s32 target) { LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", @@ -1741,6 +1834,12 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, return result; } +static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value, + u32 timeout_low, u32 timeout_high) { + s64 timeout = static_cast(timeout_low | (static_cast(timeout_high) << 32)); + return WaitForAddress(system, static_cast(address), type, value, timeout); +} + // Signals to an address (via Address Arbiter) static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value, s32 num_to_wake) { @@ -1764,6 +1863,11 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake); } +static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value, + s32 num_to_wake) { + return SignalToAddress(system, static_cast(address), type, value, num_to_wake); +} + static void KernelDebug([[maybe_unused]] Core::System& system, [[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1, [[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) { @@ -1791,6 +1895,12 @@ static u64 GetSystemTick(Core::System& system) { return result; } +static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { + u64 time = GetSystemTick(system); + *time_low = static_cast(time); + *time_high = static_cast(time >> 32); +} + /// Close a handle static ResultCode CloseHandle(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); @@ -1823,6 +1933,10 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode ResetSignal32(Core::System& system, Handle handle) { + return ResetSignal(system, handle); +} + /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, u32 permissions) { @@ -1897,6 +2011,15 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, return RESULT_SUCCESS; } +static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, + u32* mask_low, u32* mask_high) { + u64 mask{}; + const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); + *mask_high = static_cast(mask >> 32); + *mask_low = static_cast(mask); + return result; +} + static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, u64 affinity_mask) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", @@ -1988,6 +2111,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle return RESULT_SUCCESS; } +static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) { + return CreateEvent(system, write_handle, read_handle); +} + static ResultCode ClearEvent(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); @@ -2009,6 +2136,10 @@ static ResultCode ClearEvent(Core::System& system, Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode ClearEvent32(Core::System& system, Handle handle) { + return ClearEvent(system, handle); +} + static ResultCode SignalEvent(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); @@ -2024,6 +2155,10 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { return RESULT_SUCCESS; } +static ResultCode SignalEvent32(Core::System& system, Handle handle) { + return SignalEvent(system, handle); +} + static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); @@ -2209,6 +2344,15 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd return RESULT_SUCCESS; } +static ResultCode FlushProcessDataCache32(Core::System& system, Handle handle, u32 address, + u32 size) { + // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a nope + // as all emulation is done in the same cache level in host architecture, thus data cache + // does not need flushing. + LOG_DEBUG(Kernel_SVC, "called"); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(Core::System&); @@ -2224,56 +2368,56 @@ static const FunctionDef SVC_Table_32[] = { {0x01, SvcWrap32, "SetHeapSize32"}, {0x02, nullptr, "Unknown"}, {0x03, SvcWrap32, "SetMemoryAttribute32"}, - {0x04, nullptr, "MapMemory32"}, - {0x05, nullptr, "UnmapMemory32"}, + {0x04, SvcWrap32, "MapMemory32"}, + {0x05, SvcWrap32, "UnmapMemory32"}, {0x06, SvcWrap32, "QueryMemory32"}, - {0x07, nullptr, "ExitProcess32"}, - {0x08, nullptr, "CreateThread32"}, - {0x09, nullptr, "StartThread32"}, - {0x0a, nullptr, "ExitThread32"}, - {0x0b, nullptr, "SleepThread32"}, + {0x07, SvcWrap32, "ExitProcess32"}, + {0x08, SvcWrap32, "CreateThread32"}, + {0x09, SvcWrap32, "StartThread32"}, + {0x0a, SvcWrap32, "ExitThread32"}, + {0x0b, SvcWrap32, "SleepThread32"}, {0x0c, SvcWrap32, "GetThreadPriority32"}, {0x0d, SvcWrap32, "SetThreadPriority32"}, - {0x0e, nullptr, "GetThreadCoreMask32"}, + {0x0e, SvcWrap32, "GetThreadCoreMask32"}, {0x0f, SvcWrap32, "SetThreadCoreMask32"}, {0x10, SvcWrap32, "GetCurrentProcessorNumber32"}, - {0x11, nullptr, "SignalEvent32"}, - {0x12, nullptr, "ClearEvent32"}, - {0x13, nullptr, "MapSharedMemory32"}, + {0x11, SvcWrap32, "SignalEvent32"}, + {0x12, SvcWrap32, "ClearEvent32"}, + {0x13, SvcWrap32, "MapSharedMemory32"}, {0x14, nullptr, "UnmapSharedMemory32"}, {0x15, SvcWrap32, "CreateTransferMemory32"}, {0x16, SvcWrap32, "CloseHandle32"}, - {0x17, nullptr, "ResetSignal32"}, + {0x17, SvcWrap32, "ResetSignal32"}, {0x18, SvcWrap32, "WaitSynchronization32"}, - {0x19, nullptr, "CancelSynchronization32"}, - {0x1a, nullptr, "ArbitrateLock32"}, - {0x1b, nullptr, "ArbitrateUnlock32"}, - {0x1c, nullptr, "WaitProcessWideKeyAtomic32"}, + {0x19, SvcWrap32, "CancelSynchronization32"}, + {0x1a, SvcWrap32, "ArbitrateLock32"}, + {0x1b, SvcWrap32, "ArbitrateUnlock32"}, + {0x1c, SvcWrap32, "WaitProcessWideKeyAtomic32"}, {0x1d, SvcWrap32, "SignalProcessWideKey32"}, - {0x1e, nullptr, "GetSystemTick32"}, + {0x1e, SvcWrap32, "GetSystemTick32"}, {0x1f, SvcWrap32, "ConnectToNamedPort32"}, {0x20, nullptr, "Unknown"}, {0x21, SvcWrap32, "SendSyncRequest32"}, {0x22, nullptr, "SendSyncRequestWithUserBuffer32"}, {0x23, nullptr, "Unknown"}, - {0x24, nullptr, "GetProcessId32"}, + {0x24, SvcWrap32, "GetProcessId32"}, {0x25, SvcWrap32, "GetThreadId32"}, - {0x26, nullptr, "Break32"}, + {0x26, SvcWrap32, "Break32"}, {0x27, nullptr, "OutputDebugString32"}, {0x28, nullptr, "Unknown"}, {0x29, SvcWrap32, "GetInfo32"}, {0x2a, nullptr, "Unknown"}, {0x2b, nullptr, "Unknown"}, - {0x2c, nullptr, "MapPhysicalMemory32"}, - {0x2d, nullptr, "UnmapPhysicalMemory32"}, + {0x2c, SvcWrap32, "MapPhysicalMemory32"}, + {0x2d, SvcWrap32, "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"}, + {0x32, SvcWrap32, "SetThreadActivity32"}, + {0x33, SvcWrap32, "GetThreadContext32"}, + {0x34, SvcWrap32, "WaitForAddress32"}, + {0x35, SvcWrap32, "SignalToAddress32"}, {0x36, nullptr, "Unknown"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, @@ -2289,7 +2433,7 @@ static const FunctionDef SVC_Table_32[] = { {0x42, nullptr, "Unknown"}, {0x43, nullptr, "ReplyAndReceive32"}, {0x44, nullptr, "Unknown"}, - {0x45, nullptr, "CreateEvent32"}, + {0x45, SvcWrap32, "CreateEvent32"}, {0x46, nullptr, "Unknown"}, {0x47, nullptr, "Unknown"}, {0x48, nullptr, "Unknown"}, @@ -2315,7 +2459,7 @@ static const FunctionDef SVC_Table_32[] = { {0x5c, nullptr, "Unknown"}, {0x5d, nullptr, "Unknown"}, {0x5e, nullptr, "Unknown"}, - {0x5F, nullptr, "FlushProcessDataCache32"}, + {0x5F, SvcWrap32, "FlushProcessDataCache32"}, {0x60, nullptr, "Unknown"}, {0x61, nullptr, "Unknown"}, {0x62, nullptr, "Unknown"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index ba90c354f..0b6dd9df0 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -350,17 +350,48 @@ void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2)); } -// Used by QueryMemory32 +// Used by QueryMemory32, ArbitrateLock32 template void SvcWrap32(Core::System& system) { FuncReturn32(system, func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); } +// Used by Break32 +template +void SvcWrap32(Core::System& system) { + func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)); +} + +// Used by ExitProcess32, ExitThread32 +template +void SvcWrap32(Core::System& system) { + func(system); +} + // Used by GetCurrentProcessorNumber32 template void SvcWrap32(Core::System& system) { - FuncReturn(system, func(system)); + FuncReturn32(system, func(system)); +} + +// Used by SleepThread32 +template +void SvcWrap32(Core::System& system) { + func(system, Param32(system, 0), Param32(system, 1)); +} + +// Used by CreateThread32 +template +void SvcWrap32(Core::System& system) { + Handle param_1 = 0; + + const u32 retval = func(system, ¶m_1, Param32(system, 0), Param32(system, 1), + Param32(system, 2), Param32(system, 3), Param32(system, 4)) + .raw; + + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); } // Used by GetInfo32 @@ -399,6 +430,43 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by GetSystemTick32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + + func(system, ¶m_1, ¶m_2); + system.CurrentArmInterface().SetReg(0, param_1); + system.CurrentArmInterface().SetReg(1, param_2); +} + +// Used by CreateEvent32 +template +void SvcWrap32(Core::System& system) { + Handle param_1 = 0; + Handle param_2 = 0; + + const u32 retval = func(system, ¶m_1, ¶m_2).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + FuncReturn(system, retval); +} + +// Used by GetThreadId32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + u32 param_3 = 0; + + const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + system.CurrentArmInterface().SetReg(3, param_3); + FuncReturn(system, retval); +} + // Used by SignalProcessWideKey32 template void SvcWrap32(Core::System& system) { @@ -423,7 +491,38 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } -// Used by SendSyncRequest32 +// Used by WaitProcessWideKeyAtomic32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3)), + static_cast(Param(system, 4))) + .raw; + FuncReturn(system, retval); +} + +// Used by WaitForAddress32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = func(system, static_cast(Param(system, 0)), + static_cast(Param(system, 1)), static_cast(Param(system, 2)), + static_cast(Param(system, 3)), static_cast(Param(system, 4))) + .raw; + FuncReturn(system, retval); +} + +// Used by SignalToAddress32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + +// Used by SendSyncRequest32, ArbitrateUnlock32 template void SvcWrap32(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); -- cgit v1.2.3 From 2f8947583f2f0af4058600243d6c1d244e3c4890 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 27 Jun 2020 18:20:06 -0400 Subject: Core/Common: Address Feedback. --- src/common/fiber.cpp | 10 +++------- src/common/spin_lock.cpp | 6 +++--- src/common/spin_lock.h | 5 +++++ src/common/x64/native_clock.cpp | 4 ++-- src/core/arm/arm_interface.h | 2 +- src/core/arm/cpu_interrupt_handler.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 5 +++-- src/core/arm/dynarmic/arm_dynarmic_32.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 5 +++-- src/core/arm/dynarmic/arm_dynarmic_64.h | 2 +- src/core/arm/unicorn/arm_unicorn.cpp | 2 +- src/core/arm/unicorn/arm_unicorn.h | 2 +- src/core/core.cpp | 2 +- src/core/core.h | 4 ++-- src/core/core_timing.cpp | 28 ++++++++++++---------------- src/core/hle/kernel/kernel.cpp | 14 +++++--------- src/core/hle/kernel/physical_core.cpp | 4 ++++ src/core/hle/kernel/physical_core.h | 7 ++----- src/core/hle/kernel/scheduler.cpp | 4 ++-- src/core/hle/kernel/scheduler.h | 4 ++++ src/tests/common/fibers.cpp | 2 +- 21 files changed, 58 insertions(+), 58 deletions(-) (limited to 'src/core/arm') diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index f97ad433b..1c1d09ccb 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -54,9 +54,7 @@ Fiber::Fiber(std::function&& entry_point_func, void* start_paramete impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); } -Fiber::Fiber() { - impl = std::make_unique(); -} +Fiber::Fiber() : impl{std::make_unique()} {} Fiber::~Fiber() { if (released) { @@ -116,8 +114,8 @@ std::shared_ptr Fiber::ThreadToFiber() { struct Fiber::FiberImpl { alignas(64) std::array stack; - u8* stack_limit; alignas(64) std::array rewind_stack; + u8* stack_limit; u8* rewind_stack_limit; boost::context::detail::fcontext_t context; boost::context::detail::fcontext_t rewind_context; @@ -168,9 +166,7 @@ void Fiber::SetRewindPoint(std::function&& rewind_func, void* start rewind_parameter = start_parameter; } -Fiber::Fiber() { - impl = std::make_unique(); -} +Fiber::Fiber() : impl{std::make_unique()} {} Fiber::~Fiber() { if (released) { diff --git a/src/common/spin_lock.cpp b/src/common/spin_lock.cpp index c7b46aac6..c1524220f 100644 --- a/src/common/spin_lock.cpp +++ b/src/common/spin_lock.cpp @@ -20,7 +20,7 @@ namespace { -void thread_pause() { +void ThreadPause() { #if __x86_64__ _mm_pause(); #elif __aarch64__ && _MSC_VER @@ -30,13 +30,13 @@ void thread_pause() { #endif } -} // namespace +} // Anonymous namespace namespace Common { void SpinLock::lock() { while (lck.test_and_set(std::memory_order_acquire)) { - thread_pause(); + ThreadPause(); } } diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h index 70282a961..1df5528c4 100644 --- a/src/common/spin_lock.h +++ b/src/common/spin_lock.h @@ -8,6 +8,11 @@ namespace Common { +/** + * SpinLock class + * a lock similar to mutex that forces a thread to spin wait instead calling the + * supervisor. Should be used on short sequences of code. + */ class SpinLock { public: void lock(); diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index f1bc60fd2..424b39b1f 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #ifdef _MSC_VER @@ -52,7 +53,7 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequenc } u64 NativeClock::GetRTSC() { - rtsc_serialize.lock(); + std::scoped_lock scope{rtsc_serialize}; _mm_mfence(); const u64 current_measure = __rdtsc(); u64 diff = current_measure - last_measure; @@ -61,7 +62,6 @@ u64 NativeClock::GetRTSC() { last_measure = current_measure; } accumulated_ticks += diff; - rtsc_serialize.unlock(); /// The clock cannot be more precise than the guest timer, remove the lower bits return accumulated_ticks & inaccuracy_mask; } diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 0c1d6ac39..1f24051e4 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -148,7 +148,7 @@ public: */ virtual void SetTPIDR_EL0(u64 value) = 0; - virtual void ChangeProcessorId(std::size_t new_core_id) = 0; + virtual void ChangeProcessorID(std::size_t new_core_id) = 0; virtual void SaveContext(ThreadContext32& ctx) = 0; virtual void SaveContext(ThreadContext64& ctx) = 0; diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h index 91c31a271..3d062d326 100644 --- a/src/core/arm/cpu_interrupt_handler.h +++ b/src/core/arm/cpu_interrupt_handler.h @@ -23,7 +23,7 @@ public: CPUInterruptHandler(CPUInterruptHandler&&) = default; CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default; - constexpr bool IsInterrupted() const { + bool IsInterrupted() const { return is_interrupted; } diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index cfda12098..0d4ab95b7 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -107,7 +107,7 @@ public: u64 GetTicksRemaining() override { if (parent.uses_wall_clock) { if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return 1000U; + return minimum_run_cycles; } return 0U; } @@ -116,6 +116,7 @@ public: ARM_Dynarmic_32& parent; std::size_t num_interpreted_instructions{}; + static constexpr u64 minimum_run_cycles = 1000U; }; std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, @@ -214,7 +215,7 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { cp15->uprw = static_cast(value); } -void ARM_Dynarmic_32::ChangeProcessorId(std::size_t new_core_id) { +void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) { jit->ChangeProcessorID(new_core_id); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index d9c0bfede..2bab31b92 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -47,7 +47,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorId(std::size_t new_core_id) override; + void ChangeProcessorID(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override; void SaveContext(ThreadContext64& ctx) override {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 35a99e28a..790981034 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -144,7 +144,7 @@ public: u64 GetTicksRemaining() override { if (parent.uses_wall_clock) { if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return 1000U; + return minimum_run_cycles; } return 0U; } @@ -159,6 +159,7 @@ public: std::size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; + static constexpr u64 minimum_run_cycles = 1000U; }; std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, @@ -271,7 +272,7 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } -void ARM_Dynarmic_64::ChangeProcessorId(std::size_t new_core_id) { +void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) { jit->ChangeProcessorID(new_core_id); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index c74fcbcea..403c55961 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -45,7 +45,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorId(std::size_t new_core_id) override; + void ChangeProcessorID(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override {} void SaveContext(ThreadContext64& ctx) override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 35e8f42e8..1df3f3ed1 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -159,7 +159,7 @@ void ARM_Unicorn::SetTPIDR_EL0(u64 value) { CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value)); } -void ARM_Unicorn::ChangeProcessorId(std::size_t new_core_id) { +void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) { core_index = new_core_id; } diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 8ace8b86f..810aff311 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -36,7 +36,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorId(std::size_t new_core_id) override; + void ChangeProcessorID(std::size_t new_core_id) override; void PrepareReschedule() override; void ClearExclusiveState() override; void ExecuteInstructions(std::size_t num_instructions); diff --git a/src/core/core.cpp b/src/core/core.cpp index 8256ec0fc..1a243c515 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -443,7 +443,7 @@ bool System::IsPoweredOn() const { } void System::PrepareReschedule() { - // impl->CurrentPhysicalCore().Stop(); + // Deprecated, does nothing, kept for backward compatibility. } void System::PrepareReschedule(const u32 core_index) { diff --git a/src/core/core.h b/src/core/core.h index 133ecb8e1..5c6cfbffe 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -138,13 +138,13 @@ public: /** * Run the OS and Application - * This function will start emulation and run the competent devices + * This function will start emulation and run the relevant devices */ ResultStatus Run(); /** * Pause the OS and Application - * This function will pause emulation and stop the competent devices + * This function will pause emulation and stop the relevant devices */ ResultStatus Pause(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 1aa89a1cc..5c83c41a4 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -45,9 +45,9 @@ CoreTiming::CoreTiming() { CoreTiming::~CoreTiming() = default; void CoreTiming::ThreadEntry(CoreTiming& instance) { - std::string name = "yuzu:HostTiming"; - MicroProfileOnThreadCreate(name.c_str()); - Common::SetCurrentThreadName(name.c_str()); + constexpr char name[] = "yuzu:HostTiming"; + MicroProfileOnThreadCreate(name); + Common::SetCurrentThreadName(name); Common::SetCurrentThreadPriority(Common::ThreadPriority::VeryHigh); instance.on_thread_init(); instance.ThreadLoop(); @@ -108,18 +108,19 @@ bool CoreTiming::HasPendingEvents() const { void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr& event_type, u64 userdata) { - basic_lock.lock(); - const u64 timeout = static_cast(GetGlobalTimeNs().count() + ns_into_future); + { + std::scoped_lock scope{basic_lock}; + const u64 timeout = static_cast(GetGlobalTimeNs().count() + ns_into_future); - event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); + event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); - std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - basic_lock.unlock(); + std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + } event.Set(); } void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, u64 userdata) { - basic_lock.lock(); + std::scoped_lock scope{basic_lock}; const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { return e.type.lock().get() == event_type.get() && e.userdata == userdata; }); @@ -129,7 +130,6 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, u event_queue.erase(itr, event_queue.end()); std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); } - basic_lock.unlock(); } void CoreTiming::AddTicks(u64 ticks) { @@ -187,8 +187,8 @@ void CoreTiming::RemoveEvent(const std::shared_ptr& event_type) { } std::optional CoreTiming::Advance() { - advance_lock.lock(); - basic_lock.lock(); + std::scoped_lock advance_scope{advance_lock}; + std::scoped_lock basic_scope{basic_lock}; global_timer = GetGlobalTimeNs().count(); while (!event_queue.empty() && event_queue.front().time <= global_timer) { @@ -207,12 +207,8 @@ std::optional CoreTiming::Advance() { if (!event_queue.empty()) { const s64 next_time = event_queue.front().time - global_timer; - basic_lock.unlock(); - advance_lock.unlock(); return next_time; } else { - basic_lock.unlock(); - advance_lock.unlock(); return std::nullopt; } } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index dbb75416d..1f2af7a1b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -472,16 +472,12 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - if (!IsMulticore()) { - auto& threads = GlobalScheduler().GetThreadList(); - for (auto& thread : threads) { - if (!thread->IsHLEThread()) { - auto& arm_interface = thread->ArmInterface(); - arm_interface.ClearInstructionCache(); - } + auto& threads = GlobalScheduler().GetThreadList(); + for (auto& thread : threads) { + if (!thread->IsHLEThread()) { + auto& arm_interface = thread->ArmInterface(); + arm_interface.ClearInstructionCache(); } - } else { - UNIMPLEMENTED_MSG("Cache Invalidation unimplemented for multicore"); } } diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index c82c60a16..c6bbdb080 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -37,6 +37,10 @@ void PhysicalCore::Shutdown() { scheduler.Shutdown(); } +bool PhysicalCore::IsInterrupted() const { + return interrupt_handler.IsInterrupted(); +} + void PhysicalCore::Interrupt() { guard->lock(); interrupt_handler.SetInterrupt(true); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 85f6dec05..d7a7a951c 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -7,8 +7,6 @@ #include #include -#include "core/arm/cpu_interrupt_handler.h" - namespace Common { class SpinLock; } @@ -19,6 +17,7 @@ class Scheduler; namespace Core { class ARM_Interface; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -45,9 +44,7 @@ public: void ClearInterrupt(); /// Check if this core is interrupted - bool IsInterrupted() const { - return interrupt_handler.IsInterrupted(); - } + bool IsInterrupted() const; // Shutdown this physical core. void Shutdown(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 61b8a396a..2b12c0dbf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -658,7 +658,7 @@ void Scheduler::Reload() { cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -691,7 +691,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 348107160..b3b4b5169 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -240,6 +240,10 @@ public: return switch_fiber; } + const std::shared_ptr& ControlContext() const { + return switch_fiber; + } + private: friend class GlobalScheduler; diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp index 12536b6d8..4fd92428f 100644 --- a/src/tests/common/fibers.cpp +++ b/src/tests/common/fibers.cpp @@ -68,7 +68,7 @@ static void ThreadStart1(u32 id, TestControl1& test_control) { * doing all the work required. */ TEST_CASE("Fibers::Setup", "[common]") { - constexpr u32 num_threads = 7; + constexpr std::size_t num_threads = 7; TestControl1 test_control{}; test_control.thread_fibers.resize(num_threads); test_control.work_fibers.resize(num_threads); -- cgit v1.2.3