diff options
Diffstat (limited to '')
44 files changed, 876 insertions, 657 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1a3647a67..d342cafe0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -15,14 +15,14 @@ add_library(core STATIC constants.h core.cpp core.h - core_cpu.cpp - core_cpu.h + core_manager.cpp + core_manager.h core_timing.cpp core_timing.h core_timing_util.cpp core_timing_util.h - cpu_core_manager.cpp - cpu_core_manager.h + cpu_manager.cpp + cpu_manager.h crypto/aes_util.cpp crypto/aes_util.h crypto/encryption_layer.cpp @@ -158,6 +158,8 @@ add_library(core STATIC hle/kernel/mutex.h hle/kernel/object.cpp hle/kernel/object.h + hle/kernel/physical_core.cpp + hle/kernel/physical_core.h hle/kernel/process.cpp hle/kernel/process.h hle/kernel/process_capability.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index e825c0526..791640a3a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -10,11 +10,12 @@ #include "common/microprofile.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/core.h" -#include "core/core_cpu.h" +#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" @@ -87,7 +88,7 @@ public: if (GDBStub::IsServerEnabled()) { parent.jit->HaltExecution(); parent.SetPC(pc); - Kernel::Thread* thread = Kernel::GetCurrentThread(); + Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread(); parent.SaveContext(thread->GetContext()); GDBStub::Break(); GDBStub::SendTrap(thread, 5); diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp index abd59ff4b..94570e520 100644 --- a/src/core/arm/exclusive_monitor.cpp +++ b/src/core/arm/exclusive_monitor.cpp @@ -2,10 +2,24 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic.h" +#endif #include "core/arm/exclusive_monitor.h" +#include "core/memory.h" namespace Core { ExclusiveMonitor::~ExclusiveMonitor() = default; +std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, + std::size_t num_cores) { +#ifdef ARCHITECTURE_x86_64 + return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores); +#else + // TODO(merry): Passthrough exclusive monitor + return nullptr; +#endif +} + } // namespace Core diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h index f59aca667..4ef418b90 100644 --- a/src/core/arm/exclusive_monitor.h +++ b/src/core/arm/exclusive_monitor.h @@ -4,8 +4,14 @@ #pragma once +#include <memory> + #include "common/common_types.h" +namespace Memory { +class Memory; +} + namespace Core { class ExclusiveMonitor { @@ -22,4 +28,7 @@ public: virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0; }; +std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, + std::size_t num_cores); + } // namespace Core diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 48182c99a..f99ad5802 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -9,6 +9,7 @@ #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/svc.h" namespace Core { @@ -177,7 +178,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } - Kernel::Thread* thread = Kernel::GetCurrentThread(); + Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread(); SaveContext(thread->GetContext()); if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) { last_bkpt_hit = false; diff --git a/src/core/core.cpp b/src/core/core.cpp index d697b80ef..0eb0c0dca 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -11,9 +11,9 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_cpu.h" +#include "core/core_manager.h" #include "core/core_timing.h" -#include "core/cpu_core_manager.h" +#include "core/cpu_manager.h" #include "core/file_sys/bis_factory.h" #include "core/file_sys/card_image.h" #include "core/file_sys/mode.h" @@ -28,6 +28,7 @@ #include "core/hardware_interrupt_manager.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" @@ -113,16 +114,25 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) : kernel{system}, fs_controller{system}, memory{system}, - cpu_core_manager{system}, reporter{system}, applet_manager{system} {} + cpu_manager{system}, reporter{system}, applet_manager{system} {} - Cpu& CurrentCpuCore() { - return cpu_core_manager.GetCurrentCore(); + CoreManager& CurrentCoreManager() { + return cpu_manager.GetCurrentCoreManager(); + } + + Kernel::PhysicalCore& CurrentPhysicalCore() { + const auto index = cpu_manager.GetActiveCoreIndex(); + return kernel.PhysicalCore(index); + } + + Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) { + return kernel.PhysicalCore(index); } ResultStatus RunLoop(bool tight_loop) { status = ResultStatus::Success; - cpu_core_manager.RunLoop(tight_loop); + cpu_manager.RunLoop(tight_loop); return status; } @@ -131,8 +141,8 @@ struct System::Impl { LOG_DEBUG(HW_Memory, "initialized OK"); core_timing.Initialize(); - cpu_core_manager.Initialize(); kernel.Initialize(); + cpu_manager.Initialize(); const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch()); @@ -205,7 +215,6 @@ struct System::Impl { // Main process has been loaded and been made current. // Begin GPU and CPU execution. gpu_core->Start(); - cpu_core_manager.StartThreads(); // Initialize cheat engine if (cheat_engine) { @@ -259,7 +268,9 @@ struct System::Impl { is_powered_on = false; exit_lock = false; - gpu_core->WaitIdle(); + if (gpu_core) { + gpu_core->WaitIdle(); + } // Shutdown emulation session renderer.reset(); @@ -272,7 +283,7 @@ struct System::Impl { gpu_core.reset(); // Close all CPU/threading state - cpu_core_manager.Shutdown(); + cpu_manager.Shutdown(); // Shutdown kernel and core timing kernel.Shutdown(); @@ -342,7 +353,7 @@ struct System::Impl { std::unique_ptr<Tegra::GPU> gpu_core; std::unique_ptr<Hardware::InterruptManager> interrupt_manager; Memory::Memory memory; - CpuCoreManager cpu_core_manager; + CpuManager cpu_manager; bool is_powered_on = false; bool exit_lock = false; @@ -377,12 +388,12 @@ struct System::Impl { System::System() : impl{std::make_unique<Impl>(*this)} {} System::~System() = default; -Cpu& System::CurrentCpuCore() { - return impl->CurrentCpuCore(); +CoreManager& System::CurrentCoreManager() { + return impl->CurrentCoreManager(); } -const Cpu& System::CurrentCpuCore() const { - return impl->CurrentCpuCore(); +const CoreManager& System::CurrentCoreManager() const { + return impl->CurrentCoreManager(); } System::ResultStatus System::RunLoop(bool tight_loop) { @@ -394,7 +405,7 @@ System::ResultStatus System::SingleStep() { } void System::InvalidateCpuInstructionCaches() { - impl->cpu_core_manager.InvalidateAllInstructionCaches(); + impl->kernel.InvalidateAllInstructionCaches(); } System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { @@ -406,13 +417,11 @@ bool System::IsPoweredOn() const { } void System::PrepareReschedule() { - CurrentCpuCore().PrepareReschedule(); + impl->CurrentPhysicalCore().Stop(); } void System::PrepareReschedule(const u32 core_index) { - if (core_index < GlobalScheduler().CpuCoresCount()) { - CpuCore(core_index).PrepareReschedule(); - } + impl->kernel.PrepareReschedule(core_index); } PerfStatsResults System::GetAndResetPerfStats() { @@ -428,31 +437,31 @@ const TelemetrySession& System::TelemetrySession() const { } ARM_Interface& System::CurrentArmInterface() { - return CurrentCpuCore().ArmInterface(); + return impl->CurrentPhysicalCore().ArmInterface(); } const ARM_Interface& System::CurrentArmInterface() const { - return CurrentCpuCore().ArmInterface(); + return impl->CurrentPhysicalCore().ArmInterface(); } std::size_t System::CurrentCoreIndex() const { - return CurrentCpuCore().CoreIndex(); + return impl->cpu_manager.GetActiveCoreIndex(); } Kernel::Scheduler& System::CurrentScheduler() { - return CurrentCpuCore().Scheduler(); + return impl->CurrentPhysicalCore().Scheduler(); } const Kernel::Scheduler& System::CurrentScheduler() const { - return CurrentCpuCore().Scheduler(); + return impl->CurrentPhysicalCore().Scheduler(); } Kernel::Scheduler& System::Scheduler(std::size_t core_index) { - return CpuCore(core_index).Scheduler(); + return impl->GetPhysicalCore(core_index).Scheduler(); } const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { - return CpuCore(core_index).Scheduler(); + return impl->GetPhysicalCore(core_index).Scheduler(); } /// Gets the global scheduler @@ -474,28 +483,28 @@ const Kernel::Process* System::CurrentProcess() const { } ARM_Interface& System::ArmInterface(std::size_t core_index) { - return CpuCore(core_index).ArmInterface(); + return impl->GetPhysicalCore(core_index).ArmInterface(); } const ARM_Interface& System::ArmInterface(std::size_t core_index) const { - return CpuCore(core_index).ArmInterface(); + return impl->GetPhysicalCore(core_index).ArmInterface(); } -Cpu& System::CpuCore(std::size_t core_index) { - return impl->cpu_core_manager.GetCore(core_index); +CoreManager& System::GetCoreManager(std::size_t core_index) { + return impl->cpu_manager.GetCoreManager(core_index); } -const Cpu& System::CpuCore(std::size_t core_index) const { +const CoreManager& System::GetCoreManager(std::size_t core_index) const { ASSERT(core_index < NUM_CPU_CORES); - return impl->cpu_core_manager.GetCore(core_index); + return impl->cpu_manager.GetCoreManager(core_index); } ExclusiveMonitor& System::Monitor() { - return impl->cpu_core_manager.GetExclusiveMonitor(); + return impl->kernel.GetExclusiveMonitor(); } const ExclusiveMonitor& System::Monitor() const { - return impl->cpu_core_manager.GetExclusiveMonitor(); + return impl->kernel.GetExclusiveMonitor(); } Memory::Memory& System::Memory() { diff --git a/src/core/core.h b/src/core/core.h index e240c5c58..e69d68fcf 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -93,7 +93,7 @@ class Memory; namespace Core { class ARM_Interface; -class Cpu; +class CoreManager; class ExclusiveMonitor; class FrameLimiter; class PerfStats; @@ -218,10 +218,10 @@ public: const ARM_Interface& ArmInterface(std::size_t core_index) const; /// Gets a CPU interface to the CPU core with the specified index - Cpu& CpuCore(std::size_t core_index); + CoreManager& GetCoreManager(std::size_t core_index); /// Gets a CPU interface to the CPU core with the specified index - const Cpu& CpuCore(std::size_t core_index) const; + const CoreManager& GetCoreManager(std::size_t core_index) const; /// Gets a reference to the exclusive monitor ExclusiveMonitor& Monitor(); @@ -364,10 +364,10 @@ private: System(); /// Returns the currently running CPU core - Cpu& CurrentCpuCore(); + CoreManager& CurrentCoreManager(); /// Returns the currently running CPU core - const Cpu& CurrentCpuCore() const; + const CoreManager& CurrentCoreManager() const; /** * Initialize the emulated system. diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp deleted file mode 100644 index 630cd4feb..000000000 --- a/src/core/core_cpu.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <condition_variable> -#include <mutex> - -#include "common/logging/log.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic.h" -#endif -#include "core/arm/exclusive_monitor.h" -#include "core/arm/unicorn/arm_unicorn.h" -#include "core/core.h" -#include "core/core_cpu.h" -#include "core/core_timing.h" -#include "core/hle/kernel/scheduler.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/lock.h" -#include "core/settings.h" - -namespace Core { - -void CpuBarrier::NotifyEnd() { - std::unique_lock lock{mutex}; - end = true; - condition.notify_all(); -} - -bool CpuBarrier::Rendezvous() { - if (!Settings::values.use_multi_core) { - // Meaningless when running in single-core mode - return true; - } - - if (!end) { - std::unique_lock lock{mutex}; - - --cores_waiting; - if (!cores_waiting) { - cores_waiting = NUM_CPU_CORES; - condition.notify_all(); - return true; - } - - condition.wait(lock); - return true; - } - - return false; -} - -Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, - std::size_t core_index) - : cpu_barrier{cpu_barrier}, global_scheduler{system.GlobalScheduler()}, - core_timing{system.CoreTiming()}, core_index{core_index} { -#ifdef ARCHITECTURE_x86_64 - arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index); -#else - arm_interface = std::make_unique<ARM_Unicorn>(system); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif - - scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index); -} - -Cpu::~Cpu() = default; - -std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor( - [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) { -#ifdef ARCHITECTURE_x86_64 - return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores); -#else - // TODO(merry): Passthrough exclusive monitor - return nullptr; -#endif -} - -void Cpu::RunLoop(bool tight_loop) { - // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step - if (!cpu_barrier.Rendezvous()) { - // If rendezvous failed, session has been killed - return; - } - - 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); - core_timing.Idle(); - } else { - if (tight_loop) { - arm_interface->Run(); - } else { - arm_interface->Step(); - } - // We are stopping a run, exclusive state must be cleared - arm_interface->ClearExclusiveState(); - } - core_timing.Advance(); - - Reschedule(); -} - -void Cpu::SingleStep() { - return RunLoop(false); -} - -void Cpu::PrepareReschedule() { - arm_interface->PrepareReschedule(); -} - -void Cpu::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); - scheduler->TryDoContextSwitch(); -} - -void Cpu::Shutdown() { - scheduler->Shutdown(); -} - -} // namespace Core diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h deleted file mode 100644 index 78f5021a2..000000000 --- a/src/core/core_cpu.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <atomic> -#include <condition_variable> -#include <cstddef> -#include <memory> -#include <mutex> -#include "common/common_types.h" - -namespace Kernel { -class GlobalScheduler; -class Scheduler; -} // namespace Kernel - -namespace Core { -class System; -} - -namespace Core::Timing { -class CoreTiming; -} - -namespace Memory { -class Memory; -} - -namespace Core { - -class ARM_Interface; -class ExclusiveMonitor; - -constexpr unsigned NUM_CPU_CORES{4}; - -class CpuBarrier { -public: - bool IsAlive() const { - return !end; - } - - void NotifyEnd(); - - bool Rendezvous(); - -private: - unsigned cores_waiting{NUM_CPU_CORES}; - std::mutex mutex; - std::condition_variable condition; - std::atomic<bool> end{}; -}; - -class Cpu { -public: - Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, - std::size_t core_index); - ~Cpu(); - - void RunLoop(bool tight_loop = true); - - void SingleStep(); - - void PrepareReschedule(); - - ARM_Interface& ArmInterface() { - return *arm_interface; - } - - const ARM_Interface& ArmInterface() const { - return *arm_interface; - } - - Kernel::Scheduler& Scheduler() { - return *scheduler; - } - - const Kernel::Scheduler& Scheduler() const { - return *scheduler; - } - - bool IsMainCore() const { - return core_index == 0; - } - - std::size_t CoreIndex() const { - return core_index; - } - - void Shutdown(); - - /** - * Creates an exclusive monitor to handle exclusive reads/writes. - * - * @param memory The current memory subsystem that the monitor may wish - * to keep track of. - * - * @param num_cores The number of cores to assume about the CPU. - * - * @returns The constructed exclusive monitor instance, or nullptr if the current - * CPU backend is unable to use an exclusive monitor. - */ - static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, - std::size_t num_cores); - -private: - void Reschedule(); - - std::unique_ptr<ARM_Interface> arm_interface; - CpuBarrier& cpu_barrier; - Kernel::GlobalScheduler& global_scheduler; - std::unique_ptr<Kernel::Scheduler> scheduler; - Timing::CoreTiming& core_timing; - - std::atomic<bool> reschedule_pending = false; - std::size_t core_index; -}; - -} // namespace Core diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp new file mode 100644 index 000000000..8eacf92dd --- /dev/null +++ b/src/core/core_manager.cpp @@ -0,0 +1,70 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <condition_variable> +#include <mutex> + +#include "common/logging/log.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic.h" +#endif +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" +#include "core/core.h" +#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) { + 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); + core_timing.Idle(); + } else { + if (tight_loop) { + physical_core.Run(); + } else { + physical_core.Step(); + } + } + core_timing.Advance(); + + Reschedule(); +} + +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 new file mode 100644 index 000000000..b14e723d7 --- /dev/null +++ b/src/core/core_manager.h @@ -0,0 +1,63 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> +#include <cstddef> +#include <memory> +#include "common/common_types.h" + +namespace Kernel { +class GlobalScheduler; +class PhysicalCore; +} // namespace Kernel + +namespace Core { +class System; +} + +namespace Core::Timing { +class CoreTiming; +} + +namespace 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<bool> reschedule_pending = false; + std::size_t core_index; +}; + +} // namespace Core diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp deleted file mode 100644 index f04a34133..000000000 --- a/src/core/cpu_core_manager.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/arm/exclusive_monitor.h" -#include "core/core.h" -#include "core/core_cpu.h" -#include "core/core_timing.h" -#include "core/cpu_core_manager.h" -#include "core/gdbstub/gdbstub.h" -#include "core/settings.h" - -namespace Core { -namespace { -void RunCpuCore(const System& system, Cpu& cpu_state) { - while (system.IsPoweredOn()) { - cpu_state.RunLoop(true); - } -} -} // Anonymous namespace - -CpuCoreManager::CpuCoreManager(System& system) : system{system} {} -CpuCoreManager::~CpuCoreManager() = default; - -void CpuCoreManager::Initialize() { - barrier = std::make_unique<CpuBarrier>(); - exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size()); - - for (std::size_t index = 0; index < cores.size(); ++index) { - cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); - } -} - -void CpuCoreManager::StartThreads() { - // Create threads for CPU cores 1-3, and build thread_to_cpu map - // CPU core 0 is run on the main thread - thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); - if (!Settings::values.use_multi_core) { - return; - } - - for (std::size_t index = 0; index < core_threads.size(); ++index) { - core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system), - std::ref(*cores[index + 1])); - thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get(); - } -} - -void CpuCoreManager::Shutdown() { - barrier->NotifyEnd(); - if (Settings::values.use_multi_core) { - for (auto& thread : core_threads) { - thread->join(); - thread.reset(); - } - } - - thread_to_cpu.clear(); - for (auto& cpu_core : cores) { - cpu_core->Shutdown(); - cpu_core.reset(); - } - - exclusive_monitor.reset(); - barrier.reset(); -} - -Cpu& CpuCoreManager::GetCore(std::size_t index) { - return *cores.at(index); -} - -const Cpu& CpuCoreManager::GetCore(std::size_t index) const { - return *cores.at(index); -} - -ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() { - return *exclusive_monitor; -} - -const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const { - return *exclusive_monitor; -} - -Cpu& CpuCoreManager::GetCurrentCore() { - if (Settings::values.use_multi_core) { - const auto& search = thread_to_cpu.find(std::this_thread::get_id()); - ASSERT(search != thread_to_cpu.end()); - ASSERT(search->second); - return *search->second; - } - - // Otherwise, use single-threaded mode active_core variable - return *cores[active_core]; -} - -const Cpu& CpuCoreManager::GetCurrentCore() const { - if (Settings::values.use_multi_core) { - const auto& search = thread_to_cpu.find(std::this_thread::get_id()); - ASSERT(search != thread_to_cpu.end()); - ASSERT(search->second); - return *search->second; - } - - // Otherwise, use single-threaded mode active_core variable - return *cores[active_core]; -} - -void CpuCoreManager::RunLoop(bool tight_loop) { - // Update thread_to_cpu in case Core 0 is run from a different host thread - thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); - - if (GDBStub::IsServerEnabled()) { - GDBStub::HandlePacket(); - - // If the loop is halted and we want to step, use a tiny (1) number of instructions to - // execute. Otherwise, get out of the loop function. - if (GDBStub::GetCpuHaltFlag()) { - if (GDBStub::GetCpuStepFlag()) { - tight_loop = false; - } else { - return; - } - } - } - - auto& core_timing = system.CoreTiming(); - core_timing.ResetRun(); - bool keep_running{}; - do { - keep_running = false; - for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { - core_timing.SwitchContext(active_core); - if (core_timing.CanCurrentContextRun()) { - cores[active_core]->RunLoop(tight_loop); - } - keep_running |= core_timing.CanCurrentContextRun(); - } - } while (keep_running); - - if (GDBStub::IsServerEnabled()) { - GDBStub::SetCpuStepFlag(false); - } -} - -void CpuCoreManager::InvalidateAllInstructionCaches() { - for (auto& cpu : cores) { - cpu->ArmInterface().ClearInstructionCache(); - } -} - -} // namespace Core diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h deleted file mode 100644 index 2cbbf8216..000000000 --- a/src/core/cpu_core_manager.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <map> -#include <memory> -#include <thread> - -namespace Core { - -class Cpu; -class CpuBarrier; -class ExclusiveMonitor; -class System; - -class CpuCoreManager { -public: - explicit CpuCoreManager(System& system); - CpuCoreManager(const CpuCoreManager&) = delete; - CpuCoreManager(CpuCoreManager&&) = delete; - - ~CpuCoreManager(); - - CpuCoreManager& operator=(const CpuCoreManager&) = delete; - CpuCoreManager& operator=(CpuCoreManager&&) = delete; - - void Initialize(); - void StartThreads(); - void Shutdown(); - - Cpu& GetCore(std::size_t index); - const Cpu& GetCore(std::size_t index) const; - - Cpu& GetCurrentCore(); - const Cpu& GetCurrentCore() const; - - ExclusiveMonitor& GetExclusiveMonitor(); - const ExclusiveMonitor& GetExclusiveMonitor() const; - - void RunLoop(bool tight_loop); - - void InvalidateAllInstructionCaches(); - -private: - static constexpr std::size_t NUM_CPU_CORES = 4; - - std::unique_ptr<ExclusiveMonitor> exclusive_monitor; - std::unique_ptr<CpuBarrier> barrier; - std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores; - std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads; - std::size_t active_core{}; ///< Active core, only used in single thread mode - - /// Map of guest threads to CPU cores - std::map<std::thread::id, Cpu*> thread_to_cpu; - - System& system; -}; - -} // namespace Core diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp new file mode 100644 index 000000000..70ddbdcca --- /dev/null +++ b/src/core/cpu_manager.cpp @@ -0,0 +1,81 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/exclusive_monitor.h" +#include "core/core.h" +#include "core/core_manager.h" +#include "core/core_timing.h" +#include "core/cpu_manager.h" +#include "core/gdbstub/gdbstub.h" + +namespace Core { + +CpuManager::CpuManager(System& system) : system{system} {} +CpuManager::~CpuManager() = default; + +void CpuManager::Initialize() { + for (std::size_t index = 0; index < core_managers.size(); ++index) { + core_managers[index] = std::make_unique<CoreManager>(system, index); + } +} + +void CpuManager::Shutdown() { + for (auto& cpu_core : core_managers) { + cpu_core.reset(); + } +} + +CoreManager& CpuManager::GetCoreManager(std::size_t index) { + return *core_managers.at(index); +} + +const CoreManager& CpuManager::GetCoreManager(std::size_t index) const { + return *core_managers.at(index); +} + +CoreManager& CpuManager::GetCurrentCoreManager() { + // Otherwise, use single-threaded mode active_core variable + return *core_managers[active_core]; +} + +const CoreManager& CpuManager::GetCurrentCoreManager() const { + // Otherwise, use single-threaded mode active_core variable + return *core_managers[active_core]; +} + +void CpuManager::RunLoop(bool tight_loop) { + if (GDBStub::IsServerEnabled()) { + GDBStub::HandlePacket(); + + // If the loop is halted and we want to step, use a tiny (1) number of instructions to + // execute. Otherwise, get out of the loop function. + if (GDBStub::GetCpuHaltFlag()) { + if (GDBStub::GetCpuStepFlag()) { + tight_loop = false; + } else { + return; + } + } + } + + auto& core_timing = system.CoreTiming(); + core_timing.ResetRun(); + bool keep_running{}; + do { + keep_running = false; + for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { + core_timing.SwitchContext(active_core); + if (core_timing.CanCurrentContextRun()) { + core_managers[active_core]->RunLoop(tight_loop); + } + keep_running |= core_timing.CanCurrentContextRun(); + } + } while (keep_running); + + if (GDBStub::IsServerEnabled()) { + GDBStub::SetCpuStepFlag(false); + } +} + +} // namespace Core diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h new file mode 100644 index 000000000..feb619e1b --- /dev/null +++ b/src/core/cpu_manager.h @@ -0,0 +1,50 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <memory> + +namespace Core { + +class CoreManager; +class System; + +class CpuManager { +public: + explicit CpuManager(System& system); + CpuManager(const CpuManager&) = delete; + CpuManager(CpuManager&&) = delete; + + ~CpuManager(); + + CpuManager& operator=(const CpuManager&) = delete; + CpuManager& operator=(CpuManager&&) = delete; + + void Initialize(); + void Shutdown(); + + CoreManager& GetCoreManager(std::size_t index); + const CoreManager& GetCoreManager(std::size_t index) const; + + CoreManager& GetCurrentCoreManager(); + const CoreManager& GetCurrentCoreManager() const; + + std::size_t GetActiveCoreIndex() const { + return active_core; + } + + void RunLoop(bool tight_loop); + +private: + static constexpr std::size_t NUM_CPU_CORES = 4; + + std::array<std::unique_ptr<CoreManager>, NUM_CPU_CORES> core_managers; + std::size_t active_core{}; ///< Active core, only used in single thread mode + + System& system; +}; + +} // namespace Core diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 4a9912641..3376eedc5 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -75,6 +75,13 @@ public: return nullptr; } + /// Returns if window is shown (not minimized) + virtual bool IsShown() const = 0; + + /// Retrieves Vulkan specific handlers from the window + virtual void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, + void* surface) const = 0; + /** * Signal that a touch pressed event has occurred (e.g. mouse click pressed) * @param framebuffer_x Framebuffer x-coordinate that was pressed diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 7c11d7546..2b098b7c6 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -15,6 +15,13 @@ namespace Input { +enum class AnalogDirection : u8 { + RIGHT, + LEFT, + UP, + DOWN, +}; + /// An abstract class template for an input device (a button, an analog input, etc.). template <typename StatusType> class InputDevice { @@ -23,6 +30,9 @@ public: virtual StatusType GetStatus() const { return {}; } + virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { + return {}; + } }; /// An abstract class template for a factory that can create input devices. diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 37cb28848..67e95999d 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -35,7 +35,7 @@ #include "common/swap.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_cpu.h" +#include "core/core_manager.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index db189c8e3..2ea3dcb61 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -8,7 +8,6 @@ #include "common/assert.h" #include "common/common_types.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/scheduler.h" diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 2db28dcf0..ab05788d7 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -284,13 +284,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { std::vector<u8> buffer; - const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; + const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && + BufferDescriptorA()[buffer_index].Size()}; auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_a) { + ASSERT_MSG(BufferDescriptorA().size() > buffer_index, + "BufferDescriptorA invalid buffer_index {}", buffer_index); buffer.resize(BufferDescriptorA()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); } else { + ASSERT_MSG(BufferDescriptorX().size() > buffer_index, + "BufferDescriptorX invalid buffer_index {}", buffer_index); buffer.resize(BufferDescriptorX()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); } @@ -305,7 +310,8 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, return 0; } - const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; + const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && + BufferDescriptorB()[buffer_index].Size()}; const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; if (size > buffer_size) { LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, @@ -315,8 +321,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_b) { + ASSERT_MSG(BufferDescriptorB().size() > buffer_index, + "BufferDescriptorB invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorB()[buffer_index].Size() >= size, + "BufferDescriptorB buffer_index {} is not large enough", buffer_index); memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { + ASSERT_MSG(BufferDescriptorC().size() > buffer_index, + "BufferDescriptorC invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorC()[buffer_index].Size() >= size, + "BufferDescriptorC buffer_index {} is not large enough", buffer_index); memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } @@ -324,15 +338,35 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, } std::size_t HLERequestContext::GetReadBufferSize(int buffer_index) const { - const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; - return is_buffer_a ? BufferDescriptorA()[buffer_index].Size() - : BufferDescriptorX()[buffer_index].Size(); + const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && + BufferDescriptorA()[buffer_index].Size()}; + if (is_buffer_a) { + ASSERT_MSG(BufferDescriptorA().size() > buffer_index, + "BufferDescriptorA invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorA()[buffer_index].Size() > 0, + "BufferDescriptorA buffer_index {} is empty", buffer_index); + return BufferDescriptorA()[buffer_index].Size(); + } else { + ASSERT_MSG(BufferDescriptorX().size() > buffer_index, + "BufferDescriptorX invalid buffer_index {}", buffer_index); + ASSERT_MSG(BufferDescriptorX()[buffer_index].Size() > 0, + "BufferDescriptorX buffer_index {} is empty", buffer_index); + return BufferDescriptorX()[buffer_index].Size(); + } } std::size_t HLERequestContext::GetWriteBufferSize(int buffer_index) const { - const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[buffer_index].Size()}; - return is_buffer_b ? BufferDescriptorB()[buffer_index].Size() - : BufferDescriptorC()[buffer_index].Size(); + const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && + BufferDescriptorB()[buffer_index].Size()}; + if (is_buffer_b) { + ASSERT_MSG(BufferDescriptorB().size() > buffer_index, + "BufferDescriptorB invalid buffer_index {}", buffer_index); + return BufferDescriptorB()[buffer_index].Size(); + } else { + ASSERT_MSG(BufferDescriptorC().size() > buffer_index, + "BufferDescriptorC invalid buffer_index {}", buffer_index); + return BufferDescriptorC()[buffer_index].Size(); + } } std::string HLERequestContext::Description() const { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1d0783bd3..edd4c4259 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -3,13 +3,15 @@ // Refer to the license.txt file included. #include <atomic> +#include <functional> #include <memory> #include <mutex> #include <utility> #include "common/assert.h" #include "common/logging/log.h" - +#include "core/arm/arm_interface.h" +#include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -17,6 +19,7 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/scheduler.h" @@ -98,6 +101,7 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { Shutdown(); + InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); InitializeThreads(); InitializePreemption(); @@ -121,6 +125,21 @@ struct KernelCore::Impl { global_scheduler.Shutdown(); named_ports.clear(); + + for (auto& core : cores) { + core.Shutdown(); + } + cores.clear(); + + exclusive_monitor.reset(); + } + + void InitializePhysicalCores() { + exclusive_monitor = + Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); + for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { + cores.emplace_back(system, i, *exclusive_monitor); + } } // Creates the default system resource limit @@ -186,6 +205,9 @@ struct KernelCore::Impl { /// the ConnectToPort SVC. NamedPortTable named_ports; + std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; + std::vector<Kernel::PhysicalCore> cores; + // System context Core::System& system; }; @@ -240,6 +262,34 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { return impl->global_scheduler; } +Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { + return impl->cores[id]; +} + +const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { + return impl->cores[id]; +} + +Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { + return *impl->exclusive_monitor; +} + +const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { + return *impl->exclusive_monitor; +} + +void KernelCore::InvalidateAllInstructionCaches() { + for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { + PhysicalCore(i).ArmInterface().ClearInstructionCache(); + } +} + +void KernelCore::PrepareReschedule(std::size_t id) { + if (id < impl->global_scheduler.CpuCoresCount()) { + impl->cores[id].Stop(); + } +} + void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { impl->named_ports.emplace(std::move(name), std::move(port)); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3bf0068ed..fccffaf3a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,8 +11,9 @@ #include "core/hle/kernel/object.h" namespace Core { +class ExclusiveMonitor; class System; -} +} // namespace Core namespace Core::Timing { class CoreTiming; @@ -25,6 +26,7 @@ class AddressArbiter; class ClientPort; class GlobalScheduler; class HandleTable; +class PhysicalCore; class Process; class ResourceLimit; class Thread; @@ -84,6 +86,21 @@ public: /// Gets the sole instance of the global scheduler const Kernel::GlobalScheduler& GlobalScheduler() const; + /// Gets the an instance of the respective physical CPU core. + Kernel::PhysicalCore& PhysicalCore(std::size_t id); + + /// Gets the an instance of the respective physical CPU core. + const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; + + /// Stops execution of 'id' core, in order to reschedule a new thread. + void PrepareReschedule(std::size_t id); + + Core::ExclusiveMonitor& GetExclusiveMonitor(); + + const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + + void InvalidateAllInstructionCaches(); + /// Adds a port to the named port table void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp new file mode 100644 index 000000000..9303dd273 --- /dev/null +++ b/src/core/hle/kernel/physical_core.cpp @@ -0,0 +1,51 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/arm/arm_interface.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic.h" +#endif +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" +#include "core/core.h" +#include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, + Core::ExclusiveMonitor& exclusive_monitor) + : core_index{id} { +#ifdef ARCHITECTURE_x86_64 + arm_interface = std::make_unique<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index); +#else + arm_interface = std::make_shared<Core::ARM_Unicorn>(system); + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif + + scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index); +} + +PhysicalCore::~PhysicalCore() = default; + +void PhysicalCore::Run() { + arm_interface->Run(); + arm_interface->ClearExclusiveState(); +} + +void PhysicalCore::Step() { + arm_interface->Step(); +} + +void PhysicalCore::Stop() { + arm_interface->PrepareReschedule(); +} + +void PhysicalCore::Shutdown() { + scheduler->Shutdown(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h new file mode 100644 index 000000000..4c32c0f1b --- /dev/null +++ b/src/core/hle/kernel/physical_core.h @@ -0,0 +1,77 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> +#include <memory> + +namespace Kernel { +class Scheduler; +} // namespace Kernel + +namespace Core { +class ARM_Interface; +class ExclusiveMonitor; +class System; +} // namespace Core + +namespace Kernel { + +class PhysicalCore { +public: + PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor); + ~PhysicalCore(); + + PhysicalCore(const PhysicalCore&) = delete; + PhysicalCore& operator=(const PhysicalCore&) = delete; + + PhysicalCore(PhysicalCore&&) = default; + PhysicalCore& operator=(PhysicalCore&&) = default; + + /// Execute current jit state + void Run(); + /// Execute a single instruction in current jit. + void Step(); + /// Stop JIT execution/exit + void Stop(); + + // 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; + } + + bool IsSystemCore() const { + return core_index == 3; + } + + std::size_t CoreIndex() const { + return core_index; + } + + Kernel::Scheduler& Scheduler() { + return *scheduler; + } + + const Kernel::Scheduler& Scheduler() const { + return *scheduler; + } + +private: + std::size_t core_index; + std::unique_ptr<Core::ARM_Interface> arm_interface; + std::unique_ptr<Kernel::Scheduler> scheduler; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d36fcd7d9..eb196a690 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -14,7 +14,6 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/core_timing.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dbcdb0b88..9cae5c73d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -15,7 +15,7 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_cpu.h" +#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/hle/kernel/address_arbiter.h" @@ -1863,10 +1863,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd } auto& kernel = system.Kernel(); - auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); + auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); + + if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { + return reserve_result; + } auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const auto result = handle_table.Create(std::move(transfer_mem_handle)); + const auto result{handle_table.Create(std::move(transfer_mem_handle))}; if (result.Failed()) { return result.Code(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e84e5ce0d..e965b5b04 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,7 +13,6 @@ #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/hle/kernel/errors.h" @@ -356,7 +355,7 @@ void Thread::SetActivity(ThreadActivity value) { // Set status if not waiting if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { SetStatus(ThreadStatus::Paused); - Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); + kernel.PrepareReschedule(processor_id); } } else if (status == ThreadStatus::Paused) { // Ready to reschedule diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index f0e73f57b..f2d3f8b49 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -8,15 +8,23 @@ #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/result.h" +#include "core/memory.h" namespace Kernel { -TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} -TransferMemory::~TransferMemory() = default; +TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory) + : Object{kernel}, memory{memory} {} -std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, - u64 size, MemoryPermission permissions) { - std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; +TransferMemory::~TransferMemory() { + // Release memory region when transfer memory is destroyed + Reset(); +} + +std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory, + VAddr base_address, u64 size, + MemoryPermission permissions) { + std::shared_ptr<TransferMemory> transfer_memory{ + std::make_shared<TransferMemory>(kernel, memory)}; transfer_memory->base_address = base_address; transfer_memory->memory_size = size; @@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr } const u8* TransferMemory::GetPointer() const { - return backing_block.get()->data(); + return memory.GetPointer(base_address); } u64 TransferMemory::GetSize() const { @@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p return RESULT_SUCCESS; } +ResultCode TransferMemory::Reserve() { + auto& vm_manager{owner_process->VMManager()}; + const auto check_range_result{vm_manager.CheckRangeState( + base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, + MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All, + VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, + MemoryAttribute::IpcAndDeviceMapped)}; + + if (check_range_result.Failed()) { + return check_range_result.Code(); + } + + auto [state_, permissions_, attribute] = *check_range_result; + + if (const auto result{vm_manager.ReprotectRange( + base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))}; + result.IsError()) { + return result; + } + + return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, + attribute | MemoryAttribute::Locked); +} + +ResultCode TransferMemory::Reset() { + auto& vm_manager{owner_process->VMManager()}; + if (const auto result{vm_manager.CheckRangeState( + base_address, memory_size, + MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, + MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None, + VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, + MemoryAttribute::IpcAndDeviceMapped)}; + result.Failed()) { + return result.Code(); + } + + if (const auto result{ + vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)}; + result.IsError()) { + return result; + } + + return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, + MemoryAttribute::None); +} + ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { if (memory_size != size) { return ERR_INVALID_SIZE; diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 0a6e15d18..6e388536a 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -11,6 +11,10 @@ union ResultCode; +namespace Memory { +class Memory; +} + namespace Kernel { class KernelCore; @@ -26,12 +30,13 @@ enum class MemoryPermission : u32; /// class TransferMemory final : public Object { public: - explicit TransferMemory(KernelCore& kernel); + explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory); ~TransferMemory() override; static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, + static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory, + VAddr base_address, u64 size, MemoryPermission permissions); TransferMemory(const TransferMemory&) = delete; @@ -80,6 +85,14 @@ public: /// ResultCode UnmapMemory(VAddr address, u64 size); + /// Reserves the region to be used for the transfer memory, called after the transfer memory is + /// created. + ResultCode Reserve(); + + /// Resets the region previously used for the transfer memory, called after the transfer memory + /// is closed. + ResultCode Reset(); + private: /// Memory block backing this instance. std::shared_ptr<PhysicalMemory> backing_block; @@ -98,6 +111,8 @@ private: /// Whether or not this transfer memory instance has mapped memory. bool is_mapped = false; + + Memory::Memory& memory; }; } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 0b3500fce..024c22901 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const { ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, MemoryAttribute attribute) { - constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; + constexpr auto ignore_mask = + MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked; constexpr auto attribute_mask = ~ignore_mask; const auto result = CheckRangeState( diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 850a7ebc3..90b4b006a 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -98,6 +98,8 @@ enum class MemoryAttribute : u32 { DeviceMapped = 4, /// Uncached memory Uncached = 8, + + IpcAndDeviceMapped = LockedForIPC | DeviceMapped, }; constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { @@ -654,6 +656,35 @@ public: /// is scheduled. Common::PageTable page_table{Memory::PAGE_BITS}; + using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; + + /// Checks if an address range adheres to the specified states provided. + /// + /// @param address The starting address of the address range. + /// @param size The size of the address range. + /// @param state_mask The memory state mask. + /// @param state The state to compare the individual VMA states against, + /// which is done in the form of: (vma.state & state_mask) != state. + /// @param permission_mask The memory permissions mask. + /// @param permissions The permission to compare the individual VMA permissions against, + /// which is done in the form of: + /// (vma.permission & permission_mask) != permission. + /// @param attribute_mask The memory attribute mask. + /// @param attribute The memory attributes to compare the individual VMA attributes + /// against, which is done in the form of: + /// (vma.attributes & attribute_mask) != attribute. + /// @param ignore_mask The memory attributes to ignore during the check. + /// + /// @returns If successful, returns a tuple containing the memory attributes + /// (with ignored bits specified by ignore_mask unset), memory permissions, and + /// memory state across the memory range. + /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. + /// + CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, + VMAPermission permission_mask, VMAPermission permissions, + MemoryAttribute attribute_mask, MemoryAttribute attribute, + MemoryAttribute ignore_mask) const; + private: using VMAIter = VMAMap::iterator; @@ -707,35 +738,6 @@ private: /// Clears out the page table void ClearPageTable(); - using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; - - /// Checks if an address range adheres to the specified states provided. - /// - /// @param address The starting address of the address range. - /// @param size The size of the address range. - /// @param state_mask The memory state mask. - /// @param state The state to compare the individual VMA states against, - /// which is done in the form of: (vma.state & state_mask) != state. - /// @param permission_mask The memory permissions mask. - /// @param permissions The permission to compare the individual VMA permissions against, - /// which is done in the form of: - /// (vma.permission & permission_mask) != permission. - /// @param attribute_mask The memory attribute mask. - /// @param attribute The memory attributes to compare the individual VMA attributes - /// against, which is done in the form of: - /// (vma.attributes & attribute_mask) != attribute. - /// @param ignore_mask The memory attributes to ignore during the check. - /// - /// @returns If successful, returns a tuple containing the memory attributes - /// (with ignored bits specified by ignore_mask unset), memory permissions, and - /// memory state across the memory range. - /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. - /// - CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, - VMAPermission permission_mask, VMAPermission permissions, - MemoryAttribute attribute_mask, MemoryAttribute attribute, - MemoryAttribute ignore_mask) const; - /// Gets the amount of memory currently mapped (state != Unmapped) in a range. ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 745f2c4e8..1838260fd 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -7,7 +7,6 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/core_cpu.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" @@ -51,17 +50,8 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { if (ShouldWait(thread.get())) continue; - // A thread is ready to run if it's either in ThreadStatus::WaitSynch - // and the rest of the objects it is waiting on are ready. - bool ready_to_run = true; - if (thread_status == ThreadStatus::WaitSynch) { - ready_to_run = thread->AllWaitObjectsReady(); - } - - if (ready_to_run) { - candidate = thread.get(); - candidate_priority = thread->GetPriority(); - } + candidate = thread.get(); + candidate_priority = thread->GetPriority(); } return SharedFrom(candidate); @@ -96,7 +86,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { } if (resume) { thread->ResumeFromWait(); - Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID()); + kernel.PrepareReschedule(thread->GetProcessorID()); } } diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 95aa5d23d..c1550013a 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -709,8 +709,34 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { apm_sys->SetCpuBoostMode(ctx); } -IStorage::IStorage(std::vector<u8> buffer) - : ServiceFramework("IStorage"), buffer(std::move(buffer)) { +IStorageImpl::~IStorageImpl() = default; + +class StorageDataImpl final : public IStorageImpl { +public: + explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {} + + std::vector<u8>& GetData() override { + return buffer; + } + + const std::vector<u8>& GetData() const override { + return buffer; + } + + std::size_t GetSize() const override { + return buffer.size(); + } + +private: + std::vector<u8> buffer; +}; + +IStorage::IStorage(std::vector<u8>&& buffer) + : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { + Register(); +} + +void IStorage::Register() { // clang-format off static const FunctionInfo functions[] = { {0, &IStorage::Open, "Open"}, @@ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer) IStorage::~IStorage() = default; -const std::vector<u8>& IStorage::GetData() const { - return buffer; +void IStorage::Open(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IStorageAccessor>(*this); } void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { @@ -825,17 +856,16 @@ private: void PopOutData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - const auto storage = applet->GetBroker().PopNormalDataToGame(); if (storage == nullptr) { LOG_ERROR(Service_AM, "storage is a nullptr. There is no data in the current normal channel"); - + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IStorage>(std::move(*storage)); } @@ -857,17 +887,16 @@ private: void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - const auto storage = applet->GetBroker().PopInteractiveDataToGame(); if (storage == nullptr) { LOG_ERROR(Service_AM, "storage is a nullptr. There is no data in the current interactive channel"); - + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface<IStorage>(std::move(*storage)); } @@ -891,15 +920,6 @@ private: std::shared_ptr<Applets::Applet> applet; }; -void IStorage::Open(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_AM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IStorageAccessor>(*this); -} - IStorageAccessor::IStorageAccessor(IStorage& storage) : ServiceFramework("IStorageAccessor"), backing(storage) { // clang-format off @@ -921,7 +941,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast<u64>(backing.buffer.size())); + rb.Push(static_cast<u64>(backing.GetSize())); } void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { @@ -932,17 +952,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); - if (data.size() > backing.buffer.size() - offset) { + if (data.size() > backing.GetSize() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", - backing.buffer.size(), data.size(), offset); + backing.GetSize(), data.size(), offset); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_SIZE_OUT_OF_BOUNDS); return; } - std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); + std::memcpy(backing.GetData().data() + offset, data.data(), data.size()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -956,16 +976,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); - if (size > backing.buffer.size() - offset) { + if (size > backing.GetSize() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", - backing.buffer.size(), size, offset); + backing.GetSize(), size, offset); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERR_SIZE_OUT_OF_BOUNDS); return; } - ctx.WriteBuffer(backing.buffer.data() + offset, size); + ctx.WriteBuffer(backing.GetData().data() + offset, size); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -1031,7 +1051,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex rp.SetCurrentOffset(3); const auto handle{rp.Pop<Kernel::Handle>()}; - const auto transfer_mem = + auto transfer_mem = system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); if (transfer_mem == nullptr) { @@ -1047,7 +1067,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); + rb.PushIpcInterface<IStorage>(std::move(memory)); } IApplicationFunctions::IApplicationFunctions(Core::System& system_) @@ -1189,13 +1209,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { u64 build_id{}; std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); - const auto data = - backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); - + auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); if (data.has_value()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<AM::IStorage>(*data); + rb.PushIpcInterface<IStorage>(std::move(*data)); launch_popped_application_specific = true; return; } @@ -1218,7 +1236,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); std::memcpy(buffer.data(), ¶ms, buffer.size()); - rb.PushIpcInterface<AM::IStorage>(buffer); + rb.PushIpcInterface<IStorage>(std::move(buffer)); launch_popped_account_preselect = true; return; } diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 448817be9..0b9a4332d 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -12,7 +12,8 @@ namespace Kernel { class KernelCore; -} +class TransferMemory; +} // namespace Kernel namespace Service::NVFlinger { class NVFlinger; @@ -188,19 +189,36 @@ private: std::shared_ptr<AppletMessageQueue> msg_queue; }; +class IStorageImpl { +public: + virtual ~IStorageImpl(); + virtual std::vector<u8>& GetData() = 0; + virtual const std::vector<u8>& GetData() const = 0; + virtual std::size_t GetSize() const = 0; +}; + class IStorage final : public ServiceFramework<IStorage> { public: - explicit IStorage(std::vector<u8> buffer); + explicit IStorage(std::vector<u8>&& buffer); ~IStorage() override; - const std::vector<u8>& GetData() const; + std::vector<u8>& GetData() { + return impl->GetData(); + } + + const std::vector<u8>& GetData() const { + return impl->GetData(); + } + + std::size_t GetSize() const { + return impl->GetSize(); + } private: + void Register(); void Open(Kernel::HLERequestContext& ctx); - std::vector<u8> buffer; - - friend class IStorageAccessor; + std::shared_ptr<IStorageImpl> impl; }; class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 92f995f8f..3e97ba218 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -56,6 +56,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { auto out = std::move(out_channel.front()); out_channel.pop_front(); + pop_out_data_event.writable->Clear(); return out; } @@ -74,6 +75,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { auto out = std::move(out_interactive_channel.front()); out_interactive_channel.pop_front(); + pop_interactive_out_data_event.writable->Clear(); return out; } diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index eab0d42c9..e6c4e8b87 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -186,7 +186,7 @@ void Error::Execute() { void Error::DisplayCompleted() { complete = true; - broker.PushNormalDataFromApplet(IStorage{{}}); + broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}}); broker.SignalStateChanged(); } diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 328438a1d..fe8400a15 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) { std::vector<u8> out(sizeof(Return)); std::memcpy(out.data(), &return_, sizeof(Return)); - broker.PushNormalDataFromApplet(IStorage{out}); + broker.PushNormalDataFromApplet(IStorage{std::move(out)}); broker.SignalStateChanged(); } @@ -198,7 +198,7 @@ void PhotoViewer::Execute() { } void PhotoViewer::ViewFinished() { - broker.PushNormalDataFromApplet(IStorage{{}}); + broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}}); broker.SignalStateChanged(); } diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 3eba696ca..91d00f72a 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() { void ProfileSelect::Execute() { if (complete) { - broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); return; } @@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { final_data = std::vector<u8>(sizeof(UserSelectionOutput)); std::memcpy(final_data.data(), &output, final_data.size()); - broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); broker.SignalStateChanged(); } diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 748559cd0..964c67202 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -102,7 +102,8 @@ void SoftwareKeyboard::ExecuteInteractive() { void SoftwareKeyboard::Execute() { if (complete) { - broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); + broker.SignalStateChanged(); return; } @@ -119,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); if (config.utf_8) { - const u64 size = text->size() + 8; + const u64 size = text->size() + sizeof(u64); const auto new_text = Common::UTF16ToUTF8(*text); std::memcpy(output_sub.data(), &size, sizeof(u64)); @@ -130,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { std::memcpy(output_main.data() + 4, new_text.data(), std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); } else { - const u64 size = text->size() * 2 + 8; + const u64 size = text->size() * 2 + sizeof(u64); std::memcpy(output_sub.data(), &size, sizeof(u64)); std::memcpy(output_sub.data() + 8, text->data(), std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); @@ -144,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { final_data = output_main; if (complete) { - broker.PushNormalDataFromApplet(IStorage{output_main}); + broker.PushNormalDataFromApplet(IStorage{std::move(output_main)}); broker.SignalStateChanged(); } else { - broker.PushInteractiveDataFromApplet(IStorage{output_sub}); + broker.PushInteractiveDataFromApplet(IStorage{std::move(output_sub)}); } } else { output_main[0] = 1; complete = true; - broker.PushNormalDataFromApplet(IStorage{output_main}); + broker.PushNormalDataFromApplet(IStorage{std::move(output_main)}); broker.SignalStateChanged(); } } diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 5546ef6e8..05d6b3a19 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -284,7 +284,7 @@ void WebBrowser::Finalize() { std::vector<u8> data(sizeof(WebCommonReturnValue)); std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); - broker.PushNormalDataFromApplet(IStorage{data}); + broker.PushNormalDataFromApplet(IStorage{std::move(data)}); broker.SignalStateChanged(); if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 4d952adc0..15c09f04c 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -250,6 +250,10 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { auto& rstick_entry = npad_pad_states[controller_idx].r_stick; const auto& button_state = buttons[controller_idx]; const auto& analog_state = sticks[controller_idx]; + const auto [stick_l_x_f, stick_l_y_f] = + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); using namespace Settings::NativeButton; pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); @@ -270,23 +274,32 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); - - pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); - pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l_stick_right.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::RIGHT)); + pad_state.l_stick_left.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::LEFT)); + pad_state.l_stick_up.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::UP)); + pad_state.l_stick_down.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( + Input::AnalogDirection::DOWN)); + + pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); + pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); + pad_state.r_stick_right.Assign( + analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); + pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); - const auto [stick_l_x_f, stick_l_y_f] = - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); - const auto [stick_r_x_f, stick_r_y_f] = - analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 5eb26caf8..8f1be0e48 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -50,16 +50,16 @@ private: IPC::RequestParser rp{ctx}; const auto process_id = rp.PopRaw<u64>(); - const auto data1 = ctx.ReadBuffer(0); - const auto data2 = ctx.ReadBuffer(1); + std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; + if (Type == Core::Reporter::PlayReportType::New) { + data.emplace_back(ctx.ReadBuffer(1)); + } - LOG_DEBUG(Service_PREPO, - "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}", - static_cast<u8>(Type), process_id, data1.size(), data2.size()); + LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}", + static_cast<u8>(Type), process_id, data[0].size()); const auto& reporter{system.GetReporter()}; - reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, - process_id); + reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -70,19 +70,19 @@ private: IPC::RequestParser rp{ctx}; const auto user_id = rp.PopRaw<u128>(); const auto process_id = rp.PopRaw<u64>(); - - const auto data1 = ctx.ReadBuffer(0); - const auto data2 = ctx.ReadBuffer(1); + std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; + if (Type == Core::Reporter::PlayReportType::New) { + data.emplace_back(ctx.ReadBuffer(1)); + } LOG_DEBUG( Service_PREPO, - "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}, " - "data2_size={:016X}", - static_cast<u8>(Type), user_id[1], user_id[0], process_id, data1.size(), data2.size()); + "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}", + static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size()); const auto& reporter{system.GetReporter()}; - reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2}, - process_id, user_id); + reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id, + user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/settings.h b/src/core/settings.h index 421e76f5f..e1a9a0ffa 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -371,6 +371,11 @@ enum class SDMCSize : u64 { S1TB = 0x10000000000ULL, }; +enum class RendererBackend { + OpenGL = 0, + Vulkan = 1, +}; + struct Values { // System bool use_docked_mode; @@ -419,6 +424,10 @@ struct Values { SDMCSize sdmc_size; // Renderer + RendererBackend renderer_backend; + bool renderer_debug; + int vulkan_device; + float resolution_factor; bool use_frame_limit; u16 frame_limit; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 320e8ad73..0e72d31cd 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -46,6 +46,16 @@ static u64 GenerateTelemetryId() { return telemetry_id; } +static const char* TranslateRenderer(Settings::RendererBackend backend) { + switch (backend) { + case Settings::RendererBackend::OpenGL: + return "OpenGL"; + case Settings::RendererBackend::Vulkan: + return "Vulkan"; + } + return "Unknown"; +} + u64 GetTelemetryId() { u64 telemetry_id{}; const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + @@ -169,7 +179,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { AddField(field_type, "Audio_SinkId", Settings::values.sink_id); AddField(field_type, "Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core); - AddField(field_type, "Renderer_Backend", "OpenGL"); + AddField(field_type, "Renderer_Backend", TranslateRenderer(Settings::values.renderer_backend)); AddField(field_type, "Renderer_ResolutionFactor", Settings::values.resolution_factor); AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit); AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit); |