summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt16
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp8
-rw-r--r--src/core/arm/exclusive_monitor.cpp14
-rw-r--r--src/core/arm/exclusive_monitor.h9
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp3
-rw-r--r--src/core/core.cpp79
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/core_cpu.cpp127
-rw-r--r--src/core/core_cpu.h120
-rw-r--r--src/core/core_manager.cpp70
-rw-r--r--src/core/core_manager.h63
-rw-r--r--src/core/core_timing.cpp3
-rw-r--r--src/core/core_timing_util.cpp18
-rw-r--r--src/core/core_timing_util.h12
-rw-r--r--src/core/cpu_core_manager.cpp152
-rw-r--r--src/core/cpu_core_manager.h62
-rw-r--r--src/core/cpu_manager.cpp81
-rw-r--r--src/core/cpu_manager.h49
-rw-r--r--src/core/frontend/emu_window.h7
-rw-r--r--src/core/frontend/framebuffer_layout.cpp21
-rw-r--r--src/core/frontend/framebuffer_layout.h15
-rw-r--r--src/core/frontend/input.h10
-rw-r--r--src/core/gdbstub/gdbstub.cpp2
-rw-r--r--src/core/hardware_properties.h45
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp54
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/client_session.cpp7
-rw-r--r--src/core/hle/kernel/client_session.h6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp70
-rw-r--r--src/core/hle/kernel/kernel.cpp69
-rw-r--r--src/core/hle/kernel/kernel.h26
-rw-r--r--src/core/hle/kernel/physical_core.cpp51
-rw-r--r--src/core/hle/kernel/physical_core.h77
-rw-r--r--src/core/hle/kernel/process.cpp4
-rw-r--r--src/core/hle/kernel/process.h8
-rw-r--r--src/core/hle/kernel/readable_event.cpp16
-rw-r--r--src/core/hle/kernel/readable_event.h10
-rw-r--r--src/core/hle/kernel/scheduler.cpp13
-rw-r--r--src/core/hle/kernel/scheduler.h13
-rw-r--r--src/core/hle/kernel/server_port.cpp6
-rw-r--r--src/core/hle/kernel/server_port.h6
-rw-r--r--src/core/hle/kernel/server_session.cpp12
-rw-r--r--src/core/hle/kernel/server_session.h6
-rw-r--r--src/core/hle/kernel/session.cpp7
-rw-r--r--src/core/hle/kernel/session.h6
-rw-r--r--src/core/hle/kernel/svc.cpp82
-rw-r--r--src/core/hle/kernel/synchronization.cpp87
-rw-r--r--src/core/hle/kernel/synchronization.h44
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp (renamed from src/core/hle/kernel/wait_object.cpp)44
-rw-r--r--src/core/hle/kernel/synchronization_object.h (renamed from src/core/hle/kernel/wait_object.h)23
-rw-r--r--src/core/hle/kernel/thread.cpp44
-rw-r--r--src/core/hle/kernel/thread.h23
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp66
-rw-r--r--src/core/hle/kernel/transfer_memory.h19
-rw-r--r--src/core/hle/kernel/vm_manager.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.h60
-rw-r--r--src/core/hle/kernel/writable_event.cpp3
-rw-r--r--src/core/hle/service/am/am.cpp92
-rw-r--r--src/core/hle/service/am/am.h30
-rw-r--r--src/core/hle/service/am/applets/applets.cpp26
-rw-r--r--src/core/hle/service/am/applets/applets.h24
-rw-r--r--src/core/hle/service/am/applets/error.cpp2
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp14
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp4
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp13
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp6
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp4
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp7
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp39
-rw-r--r--src/core/hle/service/hid/hid.cpp7
-rw-r--r--src/core/hle/service/ldn/ldn.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h8
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp7
-rw-r--r--src/core/hle/service/prepo/prepo.cpp30
-rw-r--r--src/core/hle/service/sockets/bsd.cpp48
-rw-r--r--src/core/hle/service/sockets/bsd.h4
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.cpp3
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.cpp3
-rw-r--r--src/core/hle/service/time/time.cpp3
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp3
-rw-r--r--src/core/loader/nso.cpp11
-rw-r--r--src/core/loader/nso.h2
-rw-r--r--src/core/memory/cheat_engine.cpp3
-rw-r--r--src/core/settings.h13
-rw-r--r--src/core/telemetry_session.cpp12
-rw-r--r--src/core/tools/freezer.cpp3
89 files changed, 1479 insertions, 945 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1a3647a67..26612e692 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
@@ -179,14 +181,16 @@ add_library(core STATIC
hle/kernel/svc.cpp
hle/kernel/svc.h
hle/kernel/svc_wrap.h
+ hle/kernel/synchronization_object.cpp
+ hle/kernel/synchronization_object.h
+ hle/kernel/synchronization.cpp
+ hle/kernel/synchronization.h
hle/kernel/thread.cpp
hle/kernel/thread.h
hle/kernel/transfer_memory.cpp
hle/kernel/transfer_memory.h
hle/kernel/vm_manager.cpp
hle/kernel/vm_manager.h
- hle/kernel/wait_object.cpp
- hle/kernel/wait_object.h
hle/kernel/writable_event.cpp
hle/kernel/writable_event.h
hle/lock.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index e825c0526..29eaf74e5 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -10,11 +10,13 @@
#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/hardware_properties.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 +89,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);
@@ -152,7 +154,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& pag
config.tpidr_el0 = &cb->tpidr_el0;
config.dczid_el0 = 4;
config.ctr_el0 = 0x8444c004;
- config.cntfrq_el0 = Timing::CNTFREQ;
+ config.cntfrq_el0 = Hardware::CNTFREQ;
// Unpredictable instructions
config.define_unpredictable_behaviour = true;
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/core_timing.cpp b/src/core/core_timing.cpp
index aa09fa453..46d4178c4 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -12,6 +12,7 @@
#include "common/assert.h"
#include "common/thread.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
namespace Core::Timing {
@@ -215,7 +216,7 @@ void CoreTiming::Idle() {
}
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
- return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
+ return std::chrono::microseconds{GetTicks() * 1000000 / Hardware::BASE_CLOCK_RATE};
}
s64 CoreTiming::GetDowncount() const {
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index a10472a95..de50d3b14 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -11,7 +11,7 @@
namespace Core::Timing {
-constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
+constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / Hardware::BASE_CLOCK_RATE;
s64 msToCycles(std::chrono::milliseconds ms) {
if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) {
@@ -20,9 +20,9 @@ s64 msToCycles(std::chrono::milliseconds ms) {
}
if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
- return BASE_CLOCK_RATE * (ms.count() / 1000);
+ return Hardware::BASE_CLOCK_RATE * (ms.count() / 1000);
}
- return (BASE_CLOCK_RATE * ms.count()) / 1000;
+ return (Hardware::BASE_CLOCK_RATE * ms.count()) / 1000;
}
s64 usToCycles(std::chrono::microseconds us) {
@@ -32,9 +32,9 @@ s64 usToCycles(std::chrono::microseconds us) {
}
if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
- return BASE_CLOCK_RATE * (us.count() / 1000000);
+ return Hardware::BASE_CLOCK_RATE * (us.count() / 1000000);
}
- return (BASE_CLOCK_RATE * us.count()) / 1000000;
+ return (Hardware::BASE_CLOCK_RATE * us.count()) / 1000000;
}
s64 nsToCycles(std::chrono::nanoseconds ns) {
@@ -44,14 +44,14 @@ s64 nsToCycles(std::chrono::nanoseconds ns) {
}
if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) {
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
- return BASE_CLOCK_RATE * (ns.count() / 1000000000);
+ return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000);
}
- return (BASE_CLOCK_RATE * ns.count()) / 1000000000;
+ return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000;
}
u64 CpuCyclesToClockCycles(u64 ticks) {
- const u128 temporal = Common::Multiply64Into128(ticks, CNTFREQ);
- return Common::Divide128On32(temporal, static_cast<u32>(BASE_CLOCK_RATE)).first;
+ const u128 temporal = Common::Multiply64Into128(ticks, Hardware::CNTFREQ);
+ return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
}
} // namespace Core::Timing
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index cdd84d70f..addc72b19 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -6,28 +6,24 @@
#include <chrono>
#include "common/common_types.h"
+#include "core/hardware_properties.h"
namespace Core::Timing {
-// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
-// The exact value used is of course unverified.
-constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked
-constexpr u64 CNTFREQ = 19200000; // Value from fusee.
-
s64 msToCycles(std::chrono::milliseconds ms);
s64 usToCycles(std::chrono::microseconds us);
s64 nsToCycles(std::chrono::nanoseconds ns);
inline std::chrono::milliseconds CyclesToMs(s64 cycles) {
- return std::chrono::milliseconds(cycles * 1000 / BASE_CLOCK_RATE);
+ return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE);
}
inline std::chrono::nanoseconds CyclesToNs(s64 cycles) {
- return std::chrono::nanoseconds(cycles * 1000000000 / BASE_CLOCK_RATE);
+ return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE);
}
inline std::chrono::microseconds CyclesToUs(s64 cycles) {
- return std::chrono::microseconds(cycles * 1000000 / BASE_CLOCK_RATE);
+ return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE);
}
u64 CpuCyclesToClockCycles(u64 ticks);
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..97554d1bb
--- /dev/null
+++ b/src/core/cpu_manager.h
@@ -0,0 +1,49 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include "core/hardware_properties.h"
+
+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:
+ std::array<std::unique_ptr<CoreManager>, Hardware::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/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index d6d2cf3f0..2dc795d56 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -27,9 +27,9 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
// so just calculate them both even if the other isn't showing.
FramebufferLayout res{width, height};
- const float emulation_aspect_ratio{static_cast<float>(ScreenUndocked::Height) /
- ScreenUndocked::Width};
- const auto window_aspect_ratio = static_cast<float>(height) / width;
+ const float window_aspect_ratio = static_cast<float>(height) / width;
+ const float emulation_aspect_ratio = EmulationAspectRatio(
+ static_cast<AspectRatio>(Settings::values.aspect_ratio), window_aspect_ratio);
const Common::Rectangle<u32> screen_window_area{0, 0, width, height};
Common::Rectangle<u32> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);
@@ -58,4 +58,19 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
return DefaultFrameLayout(width, height);
}
+float EmulationAspectRatio(AspectRatio aspect, float window_aspect_ratio) {
+ switch (aspect) {
+ case AspectRatio::Default:
+ return static_cast<float>(ScreenUndocked::Height) / ScreenUndocked::Width;
+ case AspectRatio::R4_3:
+ return 3.0f / 4.0f;
+ case AspectRatio::R21_9:
+ return 9.0f / 21.0f;
+ case AspectRatio::StretchToWindow:
+ return window_aspect_ratio;
+ default:
+ return static_cast<float>(ScreenUndocked::Height) / ScreenUndocked::Width;
+ }
+}
+
} // namespace Layout
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index d2370adde..1d39c1faf 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -18,6 +18,13 @@ enum ScreenDocked : u32 {
HeightDocked = 1080,
};
+enum class AspectRatio {
+ Default,
+ R4_3,
+ R21_9,
+ StretchToWindow,
+};
+
/// Describes the layout of the window framebuffer
struct FramebufferLayout {
u32 width{ScreenUndocked::Width};
@@ -48,4 +55,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height);
*/
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale);
+/**
+ * Convenience method to determine emulation aspect ratio
+ * @param aspect Represents the index of aspect ratio stored in Settings::values.aspect_ratio
+ * @param window_aspect_ratio Current window aspect ratio
+ * @return Emulation render window aspect ratio
+ */
+float EmulationAspectRatio(AspectRatio aspect, float window_aspect_ratio);
+
} // namespace Layout
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/hardware_properties.h b/src/core/hardware_properties.h
new file mode 100644
index 000000000..213461b6a
--- /dev/null
+++ b/src/core/hardware_properties.h
@@ -0,0 +1,45 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <tuple>
+
+#include "common/common_types.h"
+
+namespace Core {
+
+namespace Hardware {
+
+// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
+// The exact value used is of course unverified.
+constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked
+constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
+constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
+
+} // namespace Hardware
+
+struct EmuThreadHandle {
+ u32 host_handle;
+ u32 guest_handle;
+
+ u64 GetRaw() const {
+ return (static_cast<u64>(host_handle) << 32) | guest_handle;
+ }
+
+ bool operator==(const EmuThreadHandle& rhs) const {
+ return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle);
+ }
+
+ bool operator!=(const EmuThreadHandle& rhs) const {
+ return !operator==(rhs);
+ }
+
+ static constexpr EmuThreadHandle InvalidHandle() {
+ constexpr u32 invalid_handle = 0xFFFFFFFF;
+ return {invalid_handle, invalid_handle};
+ }
+};
+
+} // namespace Core
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index db189c8e3..8475b698c 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"
@@ -202,42 +201,39 @@ void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) {
const VAddr arb_addr = thread->GetArbiterWaitAddress();
std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- const std::shared_ptr<Thread>& current_thread = *it;
- if (current_thread->GetPriority() >= thread->GetPriority()) {
- thread_list.insert(it, thread);
- return;
- }
- ++it;
+
+ const auto iter =
+ std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) {
+ return entry->GetPriority() >= thread->GetPriority();
+ });
+
+ if (iter == thread_list.cend()) {
+ thread_list.push_back(std::move(thread));
+ } else {
+ thread_list.insert(iter, std::move(thread));
}
- thread_list.push_back(std::move(thread));
}
void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) {
const VAddr arb_addr = thread->GetArbiterWaitAddress();
std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- const std::shared_ptr<Thread>& current_thread = *it;
- if (current_thread.get() == thread.get()) {
- thread_list.erase(it);
- return;
- }
- ++it;
- }
- UNREACHABLE();
+
+ const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(),
+ [&thread](const auto& entry) { return thread == entry; });
+
+ ASSERT(iter != thread_list.cend());
+
+ thread_list.erase(iter);
}
-std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) {
- std::vector<std::shared_ptr<Thread>> result;
- std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[address];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- std::shared_ptr<Thread> current_thread = *it;
- result.push_back(std::move(current_thread));
- ++it;
+std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(
+ VAddr address) const {
+ const auto iter = arb_threads.find(address);
+ if (iter == arb_threads.cend()) {
+ return {};
}
- return result;
+
+ const std::list<std::shared_ptr<Thread>>& thread_list = iter->second;
+ return {thread_list.cbegin(), thread_list.cend()};
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 386983e54..f958eee5a 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -86,7 +86,7 @@ private:
void RemoveThread(std::shared_ptr<Thread> thread);
// Gets the threads waiting on an address.
- std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address);
+ std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
/// List of threads waiting for a address arbiter
std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> arb_threads;
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 4669a14ad..6d66276bc 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -12,7 +12,7 @@
namespace Kernel {
-ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {}
+ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
ClientSession::~ClientSession() {
// This destructor will be called automatically when the last ClientSession handle is closed by
@@ -31,6 +31,11 @@ void ClientSession::Acquire(Thread* thread) {
UNIMPLEMENTED();
}
+bool ClientSession::IsSignaled() const {
+ UNIMPLEMENTED();
+ return true;
+}
+
ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
std::shared_ptr<Session> parent,
std::string name) {
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index b4289a9a8..d15b09554 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -7,7 +7,7 @@
#include <memory>
#include <string>
-#include "core/hle/kernel/wait_object.h"
+#include "core/hle/kernel/synchronization_object.h"
#include "core/hle/result.h"
union ResultCode;
@@ -22,7 +22,7 @@ class KernelCore;
class Session;
class Thread;
-class ClientSession final : public WaitObject {
+class ClientSession final : public SynchronizationObject {
public:
explicit ClientSession(KernelCore& kernel);
~ClientSession() override;
@@ -48,6 +48,8 @@ public:
void Acquire(Thread* thread) override;
+ bool IsSignaled() const override;
+
private:
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
std::shared_ptr<Session> parent,
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 2db28dcf0..c558a2f33 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -47,15 +47,15 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
const std::string& reason, u64 timeout, WakeupCallback&& callback,
std::shared_ptr<WritableEvent> writable_event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
- thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason,
- std::shared_ptr<Thread> thread,
- std::shared_ptr<WaitObject> object,
- std::size_t index) mutable -> bool {
- ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
- callback(thread, context, reason);
- context.WriteToOutgoingCommandBuffer(*thread);
- return true;
- });
+ thread->SetWakeupCallback(
+ [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+ std::shared_ptr<SynchronizationObject> object,
+ std::size_t index) mutable -> bool {
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
+ callback(thread, context, reason);
+ context.WriteToOutgoingCommandBuffer(*thread);
+ return true;
+ });
auto& kernel = Core::System::GetInstance().Kernel();
if (!writable_event) {
@@ -67,7 +67,7 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
const auto readable_event{writable_event->GetReadableEvent()};
writable_event->Clear();
thread->SetStatus(ThreadStatus::WaitHLEEvent);
- thread->SetWaitObjects({readable_event});
+ thread->SetSynchronizationObjects({readable_event});
readable_event->AddWaitingThread(thread);
if (timeout > 0) {
@@ -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..4eb1d8703 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,9 +19,11 @@
#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"
+#include "core/hle/kernel/synchronization.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
@@ -51,10 +55,10 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
if (thread->GetStatus() == ThreadStatus::WaitSynch ||
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
// Remove the thread from each of its waiting objects' waitlists
- for (const auto& object : thread->GetWaitObjects()) {
+ for (const auto& object : thread->GetSynchronizationObjects()) {
object->RemoveWaitingThread(thread);
}
- thread->ClearWaitObjects();
+ thread->ClearSynchronizationObjects();
// Invoke the wakeup callback before clearing the wait objects
if (thread->HasWakeupCallback()) {
@@ -93,11 +97,13 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
}
struct KernelCore::Impl {
- explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {}
+ explicit Impl(Core::System& system)
+ : system{system}, global_scheduler{system}, synchronization{system} {}
void Initialize(KernelCore& kernel) {
Shutdown();
+ InitializePhysicalCores();
InitializeSystemResourceLimit(kernel);
InitializeThreads();
InitializePreemption();
@@ -121,6 +127,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
@@ -172,6 +193,7 @@ struct KernelCore::Impl {
std::vector<std::shared_ptr<Process>> process_list;
Process* current_process = nullptr;
Kernel::GlobalScheduler global_scheduler;
+ Kernel::Synchronization synchronization;
std::shared_ptr<ResourceLimit> system_resource_limit;
@@ -186,6 +208,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 +265,42 @@ 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];
+}
+
+Kernel::Synchronization& KernelCore::Synchronization() {
+ return impl->synchronization;
+}
+
+const Kernel::Synchronization& KernelCore::Synchronization() const {
+ return impl->synchronization;
+}
+
+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..1eede3063 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,8 +26,10 @@ class AddressArbiter;
class ClientPort;
class GlobalScheduler;
class HandleTable;
+class PhysicalCore;
class Process;
class ResourceLimit;
+class Synchronization;
class Thread;
/// Represents a single instance of the kernel.
@@ -84,6 +87,27 @@ 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;
+
+ /// Gets the an instance of the Synchronization Interface.
+ Kernel::Synchronization& Synchronization();
+
+ /// Gets the an instance of the Synchronization Interface.
+ const Kernel::Synchronization& Synchronization() 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/process.cpp b/src/core/hle/kernel/process.cpp
index b9035a0be..2fcb7326c 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -337,7 +337,7 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
}
Process::Process(Core::System& system)
- : WaitObject{system.Kernel()}, vm_manager{system},
+ : SynchronizationObject{system.Kernel()}, vm_manager{system},
address_arbiter{system}, mutex{system}, system{system} {}
Process::~Process() = default;
@@ -357,7 +357,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
status = new_status;
is_signaled = true;
- WakeupAllWaitingThreads();
+ Signal();
}
void Process::AllocateMainThreadStack(u64 stack_size) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 3483fa19d..4887132a7 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -15,8 +15,8 @@
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process_capability.h"
+#include "core/hle/kernel/synchronization_object.h"
#include "core/hle/kernel/vm_manager.h"
-#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
namespace Core {
@@ -60,7 +60,7 @@ enum class ProcessStatus {
DebugBreak,
};
-class Process final : public WaitObject {
+class Process final : public SynchronizationObject {
public:
explicit Process(Core::System& system);
~Process() override;
@@ -359,10 +359,6 @@ private:
/// specified by metadata provided to the process during loading.
bool is_64bit_process = true;
- /// Whether or not this process is signaled. This occurs
- /// upon the process changing to a different state.
- bool is_signaled = false;
-
/// Total running time for the process in ticks.
u64 total_process_running_time_ticks = 0;
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index d8ac97aa1..9d3d3a81b 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -11,30 +11,30 @@
namespace Kernel {
-ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
+ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {}
ReadableEvent::~ReadableEvent() = default;
bool ReadableEvent::ShouldWait(const Thread* thread) const {
- return !signaled;
+ return !is_signaled;
}
void ReadableEvent::Acquire(Thread* thread) {
- ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
+ ASSERT_MSG(IsSignaled(), "object unavailable!");
}
void ReadableEvent::Signal() {
- if (!signaled) {
- signaled = true;
- WakeupAllWaitingThreads();
+ if (!is_signaled) {
+ is_signaled = true;
+ SynchronizationObject::Signal();
};
}
void ReadableEvent::Clear() {
- signaled = false;
+ is_signaled = false;
}
ResultCode ReadableEvent::Reset() {
- if (!signaled) {
+ if (!is_signaled) {
return ERR_INVALID_STATE;
}
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
index 11ff71c3a..3264dd066 100644
--- a/src/core/hle/kernel/readable_event.h
+++ b/src/core/hle/kernel/readable_event.h
@@ -5,7 +5,7 @@
#pragma once
#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/wait_object.h"
+#include "core/hle/kernel/synchronization_object.h"
union ResultCode;
@@ -14,7 +14,7 @@ namespace Kernel {
class KernelCore;
class WritableEvent;
-class ReadableEvent final : public WaitObject {
+class ReadableEvent final : public SynchronizationObject {
friend class WritableEvent;
public:
@@ -46,13 +46,11 @@ public:
/// then ERR_INVALID_STATE will be returned.
ResultCode Reset();
+ void Signal() override;
+
private:
explicit ReadableEvent(KernelCore& kernel);
- void Signal();
-
- bool signaled{};
-
std::string name; ///< Name of event (optional)
};
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index d36fcd7d9..86f1421bf 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"
@@ -125,8 +124,8 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) {
"Thread yielding without being in front");
scheduled_queue[core_id].yield(priority);
- std::array<Thread*, NUM_CPU_CORES> current_threads;
- for (u32 i = 0; i < NUM_CPU_CORES; i++) {
+ std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
+ for (std::size_t i = 0; i < current_threads.size(); i++) {
current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
}
@@ -178,8 +177,8 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
// function...
if (scheduled_queue[core_id].empty()) {
// Here, "current_threads" is calculated after the ""yield"", unlike yield -1
- std::array<Thread*, NUM_CPU_CORES> current_threads;
- for (u32 i = 0; i < NUM_CPU_CORES; i++) {
+ std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
+ for (std::size_t i = 0; i < current_threads.size(); i++) {
current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
}
for (auto& thread : suggested_queue[core_id]) {
@@ -209,7 +208,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
}
void GlobalScheduler::PreemptThreads() {
- for (std::size_t core_id = 0; core_id < NUM_CPU_CORES; core_id++) {
+ for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
const u32 priority = preemption_priorities[core_id];
if (scheduled_queue[core_id].size(priority) > 0) {
@@ -350,7 +349,7 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread,
}
void GlobalScheduler::Shutdown() {
- for (std::size_t core = 0; core < NUM_CPU_CORES; core++) {
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
scheduled_queue[core].clear();
suggested_queue[core].clear();
}
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 14b77960a..96db049cb 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -10,6 +10,7 @@
#include "common/common_types.h"
#include "common/multi_level_queue.h"
+#include "core/hardware_properties.h"
#include "core/hle/kernel/thread.h"
namespace Core {
@@ -23,8 +24,6 @@ class Process;
class GlobalScheduler final {
public:
- static constexpr u32 NUM_CPU_CORES = 4;
-
explicit GlobalScheduler(Core::System& system);
~GlobalScheduler();
@@ -125,7 +124,7 @@ public:
void PreemptThreads();
u32 CpuCoresCount() const {
- return NUM_CPU_CORES;
+ return Core::Hardware::NUM_CPU_CORES;
}
void SetReselectionPending() {
@@ -149,13 +148,15 @@ private:
bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner);
static constexpr u32 min_regular_priority = 2;
- std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue;
- std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue;
+ std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
+ scheduled_queue;
+ std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
+ suggested_queue;
std::atomic<bool> is_reselection_pending{false};
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
// ordered from Core 0 to Core 3.
- std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
+ std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
/// Lists all thread ids that aren't deleted/etc.
std::vector<std::shared_ptr<Thread>> thread_list;
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index a4ccfa35e..a549ae9d7 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -13,7 +13,7 @@
namespace Kernel {
-ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {}
+ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {}
ServerPort::~ServerPort() = default;
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
@@ -39,6 +39,10 @@ void ServerPort::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
}
+bool ServerPort::IsSignaled() const {
+ return !pending_sessions.empty();
+}
+
ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
std::string name) {
std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 8be8a75ea..41b191b86 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -10,7 +10,7 @@
#include <vector>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/wait_object.h"
+#include "core/hle/kernel/synchronization_object.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -20,7 +20,7 @@ class KernelCore;
class ServerSession;
class SessionRequestHandler;
-class ServerPort final : public WaitObject {
+class ServerPort final : public SynchronizationObject {
public:
explicit ServerPort(KernelCore& kernel);
~ServerPort() override;
@@ -82,6 +82,8 @@ public:
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
+ bool IsSignaled() const override;
+
private:
/// ServerSessions waiting to be accepted by the port
std::vector<std::shared_ptr<ServerSession>> pending_sessions;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 7825e1ec4..4604e35c5 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -24,7 +24,7 @@
namespace Kernel {
-ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
+ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
ServerSession::~ServerSession() = default;
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
@@ -50,6 +50,16 @@ bool ServerSession::ShouldWait(const Thread* thread) const {
return pending_requesting_threads.empty() || currently_handling != nullptr;
}
+bool ServerSession::IsSignaled() const {
+ // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
+ if (!parent->Client()) {
+ return true;
+ }
+
+ // Wait if we have no pending requests, or if we're currently handling a request.
+ return !pending_requesting_threads.empty() && currently_handling == nullptr;
+}
+
void ServerSession::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
// We are now handling a request, pop it from the stack.
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index d6e48109e..77e4f6721 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -10,7 +10,7 @@
#include <vector>
#include "common/threadsafe_queue.h"
-#include "core/hle/kernel/wait_object.h"
+#include "core/hle/kernel/synchronization_object.h"
#include "core/hle/result.h"
namespace Memory {
@@ -41,7 +41,7 @@ class Thread;
* After the server replies to the request, the response is marshalled back to the caller's
* TLS buffer and control is transferred back to it.
*/
-class ServerSession final : public WaitObject {
+class ServerSession final : public SynchronizationObject {
public:
explicit ServerSession(KernelCore& kernel);
~ServerSession() override;
@@ -73,6 +73,8 @@ public:
return parent.get();
}
+ bool IsSignaled() const override;
+
/**
* Sets the HLE handler for the session. This handler will be called to service IPC requests
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index dee6e2b72..e4dd53e24 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -9,7 +9,7 @@
namespace Kernel {
-Session::Session(KernelCore& kernel) : WaitObject{kernel} {}
+Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {}
Session::~Session() = default;
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
@@ -29,6 +29,11 @@ bool Session::ShouldWait(const Thread* thread) const {
return {};
}
+bool Session::IsSignaled() const {
+ UNIMPLEMENTED();
+ return true;
+}
+
void Session::Acquire(Thread* thread) {
UNIMPLEMENTED();
}
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 15a5ac15f..7cd9c0d77 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -8,7 +8,7 @@
#include <string>
#include <utility>
-#include "core/hle/kernel/wait_object.h"
+#include "core/hle/kernel/synchronization_object.h"
namespace Kernel {
@@ -19,7 +19,7 @@ class ServerSession;
* Parent structure to link the client and server endpoints of a session with their associated
* client port.
*/
-class Session final : public WaitObject {
+class Session final : public SynchronizationObject {
public:
explicit Session(KernelCore& kernel);
~Session() override;
@@ -39,6 +39,8 @@ public:
bool ShouldWait(const Thread* thread) const override;
+ bool IsSignaled() const override;
+
void Acquire(Thread* thread) override;
std::shared_ptr<ClientSession> Client() {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index dbcdb0b88..fd91779a3 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"
@@ -32,6 +32,7 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_wrap.h"
+#include "core/hle/kernel/synchronization.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/kernel/writable_event.h"
@@ -433,22 +434,6 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
return ERR_INVALID_HANDLE;
}
-/// Default thread wakeup callback for WaitSynchronization
-static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
- std::shared_ptr<WaitObject> object, std::size_t index) {
- ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
-
- if (reason == ThreadWakeupReason::Timeout) {
- thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
- return true;
- }
-
- ASSERT(reason == ThreadWakeupReason::Signal);
- thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
- thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
- return true;
-};
-
/// 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) {
@@ -472,14 +457,14 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
}
auto* const thread = system.CurrentScheduler().GetCurrentThread();
-
- using ObjectPtr = Thread::ThreadWaitObjects::value_type;
- Thread::ThreadWaitObjects objects(handle_count);
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+ auto& kernel = system.Kernel();
+ using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type;
+ Thread::ThreadSynchronizationObjects objects(handle_count);
+ const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
for (u64 i = 0; i < handle_count; ++i) {
const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
- const auto object = handle_table.Get<WaitObject>(handle);
+ const auto object = handle_table.Get<SynchronizationObject>(handle);
if (object == nullptr) {
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
@@ -488,47 +473,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
objects[i] = object;
}
-
- // Find the first object that is acquirable in the provided list of objects
- auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
- return !object->ShouldWait(thread);
- });
-
- if (itr != objects.end()) {
- // We found a ready object, acquire it and set the result value
- WaitObject* object = itr->get();
- object->Acquire(thread);
- *index = static_cast<s32>(std::distance(objects.begin(), itr));
- return RESULT_SUCCESS;
- }
-
- // No objects were ready to be acquired, prepare to suspend the thread.
-
- // If a timeout value of 0 was provided, just return the Timeout error code instead of
- // suspending the thread.
- if (nano_seconds == 0) {
- return RESULT_TIMEOUT;
- }
-
- if (thread->IsSyncCancelled()) {
- thread->SetSyncCancelled(false);
- return ERR_SYNCHRONIZATION_CANCELED;
- }
-
- for (auto& object : objects) {
- object->AddWaitingThread(SharedFrom(thread));
- }
-
- thread->SetWaitObjects(std::move(objects));
- thread->SetStatus(ThreadStatus::WaitSynch);
-
- // Create an event to wake the thread up after the specified nanosecond delay has passed
- thread->WakeAfterDelay(nano_seconds);
- thread->SetWakeupCallback(DefaultThreadWakeupCallback);
-
- system.PrepareReschedule(thread->GetProcessorID());
-
- return RESULT_TIMEOUT;
+ auto& synchronization = kernel.Synchronization();
+ const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds);
+ *index = handle_result;
+ return result;
}
/// Resumes a thread waiting on WaitSynchronization
@@ -1863,10 +1811,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/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
new file mode 100644
index 000000000..dc37fad1a
--- /dev/null
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -0,0 +1,87 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/synchronization.h"
+#include "core/hle/kernel/synchronization_object.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+/// Default thread wakeup callback for WaitSynchronization
+static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+ std::shared_ptr<SynchronizationObject> object,
+ std::size_t index) {
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
+
+ if (reason == ThreadWakeupReason::Timeout) {
+ thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
+ return true;
+ }
+
+ ASSERT(reason == ThreadWakeupReason::Signal);
+ thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
+ thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
+ return true;
+}
+
+Synchronization::Synchronization(Core::System& system) : system{system} {}
+
+void Synchronization::SignalObject(SynchronizationObject& obj) const {
+ if (obj.IsSignaled()) {
+ obj.WakeupAllWaitingThreads();
+ }
+}
+
+std::pair<ResultCode, Handle> Synchronization::WaitFor(
+ std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
+ auto* const thread = system.CurrentScheduler().GetCurrentThread();
+ // Find the first object that is acquirable in the provided list of objects
+ const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(),
+ [thread](const std::shared_ptr<SynchronizationObject>& object) {
+ return object->IsSignaled();
+ });
+
+ if (itr != sync_objects.end()) {
+ // We found a ready object, acquire it and set the result value
+ SynchronizationObject* object = itr->get();
+ object->Acquire(thread);
+ const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
+ return {RESULT_SUCCESS, index};
+ }
+
+ // No objects were ready to be acquired, prepare to suspend the thread.
+
+ // If a timeout value of 0 was provided, just return the Timeout error code instead of
+ // suspending the thread.
+ if (nano_seconds == 0) {
+ return {RESULT_TIMEOUT, InvalidHandle};
+ }
+
+ if (thread->IsSyncCancelled()) {
+ thread->SetSyncCancelled(false);
+ return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
+ }
+
+ for (auto& object : sync_objects) {
+ object->AddWaitingThread(SharedFrom(thread));
+ }
+
+ thread->SetSynchronizationObjects(std::move(sync_objects));
+ thread->SetStatus(ThreadStatus::WaitSynch);
+
+ // Create an event to wake the thread up after the specified nanosecond delay has passed
+ thread->WakeAfterDelay(nano_seconds);
+ thread->SetWakeupCallback(DefaultThreadWakeupCallback);
+
+ system.PrepareReschedule(thread->GetProcessorID());
+
+ return {RESULT_TIMEOUT, InvalidHandle};
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h
new file mode 100644
index 000000000..379f4b1d3
--- /dev/null
+++ b/src/core/hle/kernel/synchronization.h
@@ -0,0 +1,44 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "core/hle/kernel/object.h"
+#include "core/hle/result.h"
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Kernel {
+
+class SynchronizationObject;
+
+/**
+ * The 'Synchronization' class is an interface for handling synchronization methods
+ * used by Synchronization objects and synchronization SVCs. This centralizes processing of
+ * such
+ */
+class Synchronization {
+public:
+ explicit Synchronization(Core::System& system);
+
+ /// Signals a synchronization object, waking up all its waiting threads
+ void SignalObject(SynchronizationObject& obj) const;
+
+ /// Tries to see if waiting for any of the sync_objects is necessary, if not
+ /// it returns Success and the handle index of the signaled sync object. In
+ /// case not, the current thread will be locked and wait for nano_seconds or
+ /// for a synchronization object to signal.
+ std::pair<ResultCode, Handle> WaitFor(
+ std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds);
+
+private:
+ Core::System& system;
+};
+} // namespace Kernel
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/synchronization_object.cpp
index 745f2c4e8..43f3eef18 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/synchronization_object.cpp
@@ -7,24 +7,29 @@
#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"
+#include "core/hle/kernel/synchronization.h"
+#include "core/hle/kernel/synchronization_object.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
-WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {}
-WaitObject::~WaitObject() = default;
+SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
+SynchronizationObject::~SynchronizationObject() = default;
-void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
+void SynchronizationObject::Signal() {
+ kernel.Synchronization().SignalObject(*this);
+}
+
+void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
if (itr == waiting_threads.end())
waiting_threads.push_back(std::move(thread));
}
-void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
+void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
// If a thread passed multiple handles to the same object,
// the kernel might attempt to remove the thread from the object's
@@ -33,7 +38,7 @@ void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
waiting_threads.erase(itr);
}
-std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
+std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
Thread* candidate = nullptr;
u32 candidate_priority = THREADPRIO_LOWEST + 1;
@@ -51,23 +56,14 @@ 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);
}
-void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
+void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
ASSERT(!ShouldWait(thread.get()));
if (!thread) {
@@ -75,7 +71,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
}
if (thread->IsSleepingOnWait()) {
- for (const auto& object : thread->GetWaitObjects()) {
+ for (const auto& object : thread->GetSynchronizationObjects()) {
ASSERT(!object->ShouldWait(thread.get()));
object->Acquire(thread.get());
}
@@ -83,9 +79,9 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
Acquire(thread.get());
}
- const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this));
+ const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
- thread->ClearWaitObjects();
+ thread->ClearSynchronizationObjects();
thread->CancelWakeupTimer();
@@ -96,17 +92,17 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
}
if (resume) {
thread->ResumeFromWait();
- Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID());
+ kernel.PrepareReschedule(thread->GetProcessorID());
}
}
-void WaitObject::WakeupAllWaitingThreads() {
+void SynchronizationObject::WakeupAllWaitingThreads() {
while (auto thread = GetHighestPriorityReadyThread()) {
WakeupWaitingThread(thread);
}
}
-const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const {
+const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
return waiting_threads;
}
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/synchronization_object.h
index 9a17958a4..741c31faf 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/synchronization_object.h
@@ -15,10 +15,10 @@ class KernelCore;
class Thread;
/// Class that represents a Kernel object that a thread can be waiting on
-class WaitObject : public Object {
+class SynchronizationObject : public Object {
public:
- explicit WaitObject(KernelCore& kernel);
- ~WaitObject() override;
+ explicit SynchronizationObject(KernelCore& kernel);
+ ~SynchronizationObject() override;
/**
* Check if the specified thread should wait until the object is available
@@ -30,6 +30,13 @@ public:
/// Acquire/lock the object for the specified thread if it is available
virtual void Acquire(Thread* thread) = 0;
+ /// Signal this object
+ virtual void Signal();
+
+ virtual bool IsSignaled() const {
+ return is_signaled;
+ }
+
/**
* Add a thread to wait on this object
* @param thread Pointer to thread to add
@@ -60,16 +67,20 @@ public:
/// Get a const reference to the waiting threads list for debug use
const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
+protected:
+ bool is_signaled{}; // Tells if this sync object is signalled;
+
private:
/// Threads waiting for this object to become available
std::vector<std::shared_ptr<Thread>> waiting_threads;
};
-// Specialization of DynamicObjectCast for WaitObjects
+// Specialization of DynamicObjectCast for SynchronizationObjects
template <>
-inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) {
+inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>(
+ std::shared_ptr<Object> object) {
if (object != nullptr && object->IsWaitable()) {
- return std::static_pointer_cast<WaitObject>(object);
+ return std::static_pointer_cast<SynchronizationObject>(object);
}
return nullptr;
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index e84e5ce0d..ae5f2c8bd 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,9 +13,9 @@
#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/hardware_properties.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
@@ -32,11 +32,15 @@ bool Thread::ShouldWait(const Thread* thread) const {
return status != ThreadStatus::Dead;
}
+bool Thread::IsSignaled() const {
+ return status == ThreadStatus::Dead;
+}
+
void Thread::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
}
-Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {}
+Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {}
Thread::~Thread() = default;
void Thread::Stop() {
@@ -46,7 +50,7 @@ void Thread::Stop() {
kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
callback_handle = 0;
SetStatus(ThreadStatus::Dead);
- WakeupAllWaitingThreads();
+ Signal();
// Clean up any dangling references in objects that this thread was waiting for
for (auto& wait_object : wait_objects) {
@@ -216,7 +220,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output;
}
-s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const {
+s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const {
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
@@ -337,14 +341,16 @@ void Thread::ChangeCore(u32 core, u64 mask) {
SetCoreAndAffinityMask(core, mask);
}
-bool Thread::AllWaitObjectsReady() const {
- return std::none_of(
- wait_objects.begin(), wait_objects.end(),
- [this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); });
+bool Thread::AllSynchronizationObjectsReady() const {
+ return std::none_of(wait_objects.begin(), wait_objects.end(),
+ [this](const std::shared_ptr<SynchronizationObject>& object) {
+ return object->ShouldWait(this);
+ });
}
bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
- std::shared_ptr<WaitObject> object, std::size_t index) {
+ std::shared_ptr<SynchronizationObject> object,
+ std::size_t index) {
ASSERT(wakeup_callback);
return wakeup_callback(reason, std::move(thread), std::move(object), index);
}
@@ -356,7 +362,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
@@ -426,7 +432,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
const s32 old_core = processor_id;
if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) {
if (static_cast<s32>(ideal_core) < 0) {
- processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES);
+ processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES);
} else {
processor_id = ideal_core;
}
@@ -450,7 +456,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this);
}
- for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
+ for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
scheduler.Unsuggest(current_priority, core, this);
}
@@ -461,7 +467,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this);
}
- for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
+ for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
scheduler.Suggest(current_priority, core, this);
}
@@ -475,12 +481,12 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) {
return;
}
- auto& scheduler = Core::System::GetInstance().GlobalScheduler();
+ auto& scheduler = kernel.GlobalScheduler();
if (processor_id >= 0) {
scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
}
- for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
+ for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
scheduler.Unsuggest(old_priority, core, this);
}
@@ -497,7 +503,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
}
}
- for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
+ for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
scheduler.Suggest(current_priority, core, this);
}
@@ -507,13 +513,13 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
}
void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
- auto& scheduler = Core::System::GetInstance().GlobalScheduler();
+ auto& scheduler = kernel.GlobalScheduler();
if (GetSchedulingStatus() != ThreadSchedStatus::Runnable ||
current_priority >= THREADPRIO_COUNT) {
return;
}
- for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
+ for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (((old_affinity_mask >> core) & 1) != 0) {
if (core == static_cast<u32>(old_core)) {
scheduler.Unschedule(current_priority, core, this);
@@ -523,7 +529,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
}
}
- for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
+ for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (((affinity_mask >> core) & 1) != 0) {
if (core == static_cast<u32>(processor_id)) {
scheduler.Schedule(current_priority, core, this);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 3bcf9e137..7a4916318 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -11,7 +11,7 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/wait_object.h"
+#include "core/hle/kernel/synchronization_object.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -95,7 +95,7 @@ enum class ThreadSchedMasks : u32 {
ForcePauseMask = 0x0070,
};
-class Thread final : public WaitObject {
+class Thread final : public SynchronizationObject {
public:
explicit Thread(KernelCore& kernel);
~Thread() override;
@@ -104,11 +104,11 @@ public:
using ThreadContext = Core::ARM_Interface::ThreadContext;
- using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>;
+ using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>;
using WakeupCallback =
std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
- std::shared_ptr<WaitObject> object, std::size_t index)>;
+ std::shared_ptr<SynchronizationObject> object, std::size_t index)>;
/**
* Creates and returns a new thread. The new thread is immediately scheduled
@@ -146,6 +146,7 @@ public:
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
+ bool IsSignaled() const override;
/**
* Gets the thread's current priority
@@ -233,7 +234,7 @@ public:
*
* @param object Object to query the index of.
*/
- s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const;
+ s32 GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const;
/**
* Stops a thread, invalidating it from further use
@@ -314,15 +315,15 @@ public:
return owner_process;
}
- const ThreadWaitObjects& GetWaitObjects() const {
+ const ThreadSynchronizationObjects& GetSynchronizationObjects() const {
return wait_objects;
}
- void SetWaitObjects(ThreadWaitObjects objects) {
+ void SetSynchronizationObjects(ThreadSynchronizationObjects objects) {
wait_objects = std::move(objects);
}
- void ClearWaitObjects() {
+ void ClearSynchronizationObjects() {
for (const auto& waiting_object : wait_objects) {
waiting_object->RemoveWaitingThread(SharedFrom(this));
}
@@ -330,7 +331,7 @@ public:
}
/// Determines whether all the objects this thread is waiting on are ready.
- bool AllWaitObjectsReady() const;
+ bool AllSynchronizationObjectsReady() const;
const MutexWaitingThreads& GetMutexWaitingThreads() const {
return wait_mutex_threads;
@@ -395,7 +396,7 @@ public:
* will cause an assertion to trigger.
*/
bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
- std::shared_ptr<WaitObject> object, std::size_t index);
+ std::shared_ptr<SynchronizationObject> object, std::size_t index);
u32 GetIdealCore() const {
return ideal_core;
@@ -494,7 +495,7 @@ private:
/// Objects that the thread is waiting on, in the same order as they were
/// passed to WaitSynchronization.
- ThreadWaitObjects wait_objects;
+ ThreadSynchronizationObjects wait_objects;
/// List of threads that are waiting for a mutex that is held by this thread.
MutexWaitingThreads wait_mutex_threads;
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/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
index c9332e3e1..fc2f7c424 100644
--- a/src/core/hle/kernel/writable_event.cpp
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -22,7 +22,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
writable_event->name = name + ":Writable";
writable_event->readable = readable_event;
readable_event->name = name + ":Readable";
- readable_event->signaled = false;
return {std::move(readable_event), std::move(writable_event)};
}
@@ -40,7 +39,7 @@ void WritableEvent::Clear() {
}
bool WritableEvent::IsSignaled() const {
- return readable->signaled;
+ return readable->IsSignaled();
}
} // namespace Kernel
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 95aa5d23d..cc978713b 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) {
@@ -816,7 +847,7 @@ private:
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
- applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
+ applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -825,26 +856,25 @@ 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));
+ rb.PushIpcInterface<IStorage>(std::move(storage));
}
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
- applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
+ applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>());
ASSERT(applet->IsInitialized());
applet->ExecuteInteractive();
@@ -857,19 +887,18 @@ 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));
+ rb.PushIpcInterface<IStorage>(std::move(storage));
}
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
@@ -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(), &params, 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..c3261f3e6 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -50,16 +50,17 @@ AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() co
return {std::move(out_normal), std::move(out_interactive)};
}
-std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
+std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
if (out_channel.empty())
return nullptr;
auto out = std::move(out_channel.front());
out_channel.pop_front();
+ pop_out_data_event.writable->Clear();
return out;
}
-std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
+std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
if (in_channel.empty())
return nullptr;
@@ -68,16 +69,17 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
return out;
}
-std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
+std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
if (out_interactive_channel.empty())
return nullptr;
auto out = std::move(out_interactive_channel.front());
out_interactive_channel.pop_front();
+ pop_interactive_out_data_event.writable->Clear();
return out;
}
-std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
+std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
if (in_interactive_channel.empty())
return nullptr;
@@ -86,21 +88,21 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
return out;
}
-void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
- in_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
+ in_channel.emplace_back(std::move(storage));
}
-void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
- out_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
+ out_channel.emplace_back(std::move(storage));
pop_out_data_event.writable->Signal();
}
-void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
- in_interactive_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
+ in_interactive_channel.emplace_back(std::move(storage));
}
-void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
- out_interactive_channel.push_back(std::make_unique<IStorage>(storage));
+void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
+ out_interactive_channel.emplace_back(std::move(storage));
pop_interactive_out_data_event.writable->Signal();
}
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 16e61fc6f..e75be86a2 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -72,17 +72,17 @@ public:
// Retrieves but does not pop the data sent to applet.
RawChannelData PeekDataToAppletForDebug() const;
- std::unique_ptr<IStorage> PopNormalDataToGame();
- std::unique_ptr<IStorage> PopNormalDataToApplet();
+ std::shared_ptr<IStorage> PopNormalDataToGame();
+ std::shared_ptr<IStorage> PopNormalDataToApplet();
- std::unique_ptr<IStorage> PopInteractiveDataToGame();
- std::unique_ptr<IStorage> PopInteractiveDataToApplet();
+ std::shared_ptr<IStorage> PopInteractiveDataToGame();
+ std::shared_ptr<IStorage> PopInteractiveDataToApplet();
- void PushNormalDataFromGame(IStorage storage);
- void PushNormalDataFromApplet(IStorage storage);
+ void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
+ void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
- void PushInteractiveDataFromGame(IStorage storage);
- void PushInteractiveDataFromApplet(IStorage storage);
+ void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
+ void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
void SignalStateChanged() const;
@@ -94,16 +94,16 @@ private:
// Queues are named from applet's perspective
// PopNormalDataToApplet and PushNormalDataFromGame
- std::deque<std::unique_ptr<IStorage>> in_channel;
+ std::deque<std::shared_ptr<IStorage>> in_channel;
// PopNormalDataToGame and PushNormalDataFromApplet
- std::deque<std::unique_ptr<IStorage>> out_channel;
+ std::deque<std::shared_ptr<IStorage>> out_channel;
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
- std::deque<std::unique_ptr<IStorage>> in_interactive_channel;
+ std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
- std::deque<std::unique_ptr<IStorage>> out_interactive_channel;
+ std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
Kernel::EventPair state_changed_event;
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index eab0d42c9..f12fd7f89 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(std::make_shared<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..104501ac5 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -20,7 +20,7 @@ namespace Service::AM::Applets {
constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
- std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
+ std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
@@ -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(std::make_shared<IStorage>(std::move(out)));
broker.SignalStateChanged();
}
@@ -198,7 +198,7 @@ void PhotoViewer::Execute() {
}
void PhotoViewer::ViewFinished() {
- broker.PushNormalDataFromApplet(IStorage{{}});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{}));
broker.SignalStateChanged();
}
@@ -234,8 +234,8 @@ void StubApplet::ExecuteInteractive() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "ExecuteInteractive");
- broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
- broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
broker.SignalStateChanged();
}
@@ -243,8 +243,8 @@ void StubApplet::Execute() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "Execute");
- broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
- broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000)));
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..70cc23552 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(std::make_shared<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(std::make_shared<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..54e63c138 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(std::make_shared<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(std::make_shared<IStorage>(std::move(output_main)));
broker.SignalStateChanged();
} else {
- broker.PushInteractiveDataFromApplet(IStorage{output_sub});
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub)));
}
} else {
output_main[0] = 1;
complete = true;
- broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.PushNormalDataFromApplet(std::make_shared<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..12443c910 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(std::make_shared<IStorage>(std::move(data)));
broker.SignalStateChanged();
if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index cb839e4a2..d19513cbb 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -170,8 +170,10 @@ public:
{3, nullptr, "SetContextForMultiStream"},
{4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
{5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
- {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
- {7, nullptr, "DecodeInterleavedForMultiStream"},
+ {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
+ {7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
+ {8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
+ {9, nullptr, "DecodeInterleavedForMultiStream"},
};
// clang-format on
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index 6f5ea095a..def3410cc 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -117,13 +117,13 @@ bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
}
bool NullBackend::Clear(u64 title_id) {
- LOG_DEBUG(Service_BCAT, "called, title_id={:016X}");
+ LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
return true;
}
void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
- LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id,
+ LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
Common::HexToString(passphrase));
}
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index 67e39a5c4..f589864ee 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -200,7 +200,8 @@ private:
DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds,
const std::string& content_type_name) {
if (client == nullptr) {
- client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT, timeout_seconds);
+ client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
+ client->set_timeout_sec(timeout_seconds);
}
httplib::Headers headers{
@@ -448,8 +449,8 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
std::map<std::string, EventStatus>& games) {
- httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT),
- static_cast<int>(TIMEOUT_SECONDS)};
+ httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
+ client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS));
httplib::Headers headers{
{std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 55d62fc5e..e6811d5b5 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -420,7 +420,7 @@ public:
return;
}
- IFile file(result.Unwrap());
+ auto file = std::make_shared<IFile>(result.Unwrap());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -445,7 +445,7 @@ public:
return;
}
- IDirectory directory(result.Unwrap());
+ auto directory = std::make_shared<IDirectory>(result.Unwrap());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -794,8 +794,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
- SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
+ auto filesystem = std::make_shared<IFileSystem>(
+ fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -846,7 +846,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
id = FileSys::StorageId::NandSystem;
}
- IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
+ auto filesystem =
+ std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -898,7 +899,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
return;
}
- IStorage storage(std::move(romfs.Unwrap()));
+ auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -937,7 +938,8 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
FileSys::PatchManager pm{title_id};
- IStorage storage(pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
+ auto storage = std::make_shared<IStorage>(
+ pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
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/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 89bf8b815..e6b56a9f9 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -10,6 +10,7 @@
#include "core/core_timing_util.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
+#include "core/hardware_properties.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
@@ -37,11 +38,11 @@ namespace Service::HID {
// Updating period for each HID device.
// TODO(ogniK): Find actual polling rate of hid
-constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66);
+constexpr s64 pad_update_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 66);
[[maybe_unused]] constexpr s64 accelerometer_update_ticks =
- static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
+ static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100);
[[maybe_unused]] constexpr s64 gyroscope_update_ticks =
- static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
+ static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100);
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system)
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index ed5059047..92adde6d4 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -129,12 +129,20 @@ public:
{304, nullptr, "Disconnect"},
{400, nullptr, "Initialize"},
{401, nullptr, "Finalize"},
- {402, nullptr, "SetOperationMode"},
+ {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+
};
// clang-format on
RegisterHandlers(functions);
}
+
+ void Initialize2(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+ // Result success seem make this services start network and continue.
+ // If we just pass result error then it will stop and maybe try again and again.
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_UNKNOWN);
+ }
};
class LDNS final : public ServiceFramework<LDNS> {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 6d8bca8bb..f1966ac0e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -44,6 +44,8 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
return GetWaitbase(input, output);
case IoctlCommand::IocChannelSetTimeoutCommand:
return ChannelSetTimeout(input, output);
+ case IoctlCommand::IocChannelSetTimeslice:
+ return ChannelSetTimeslice(input, output);
default:
break;
}
@@ -228,4 +230,14 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
+u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
+ IoctlSetTimeslice params{};
+ std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
+ LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
+
+ channel_timeslice = params.timeslice;
+
+ return 0;
+}
+
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index d056dd046..2ac74743f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -48,6 +48,7 @@ private:
IocAllocObjCtxCommand = 0xC0104809,
IocChannelGetWaitbaseCommand = 0xC0080003,
IocChannelSetTimeoutCommand = 0x40044803,
+ IocChannelSetTimeslice = 0xC004481D,
};
enum class CtxObjects : u32_le {
@@ -101,6 +102,11 @@ private:
static_assert(sizeof(IoctlChannelSetPriority) == 4,
"IoctlChannelSetPriority is incorrect size");
+ struct IoctlSetTimeslice {
+ u32_le timeslice;
+ };
+ static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
+
struct IoctlEventIdControl {
u32_le cmd; // 0=disable, 1=enable, 2=clear
u32_le id;
@@ -174,6 +180,7 @@ private:
u64_le user_data{};
IoctlZCullBind zcull_params{};
u32_le channel_priority{};
+ u32_le channel_timeslice{};
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
@@ -188,6 +195,7 @@ private:
const std::vector<u8>& input2, IoctlVersion version);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
std::shared_ptr<nvmap> nvmap_dev;
u32 assigned_syncpoints{};
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 62752e419..134152210 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -12,6 +12,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
@@ -26,8 +27,8 @@
namespace Service::NVFlinger {
-constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
-constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30);
+constexpr s64 frame_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60);
+constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 30);
NVFlinger::NVFlinger(Core::System& system) : system(system) {
displays.emplace_back(0, "Default", system);
@@ -222,7 +223,7 @@ void NVFlinger::Compose() {
s64 NVFlinger::GetNextTicks() const {
constexpr s64 max_hertz = 120LL;
- return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz;
+ return (Core::Hardware::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz;
}
} // namespace Service::NVFlinger
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/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 884ad173b..f67fab2f9 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -42,6 +42,26 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
+void BSD::Select(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0); // ret
+ rb.Push<u32>(0); // bsd errno
+}
+
+void BSD::Bind(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0); // ret
+ rb.Push<u32>(0); // bsd errno
+}
+
void BSD::Connect(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
@@ -52,6 +72,26 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
+void BSD::Listen(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0); // ret
+ rb.Push<u32>(0); // bsd errno
+}
+
+void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0); // ret
+ rb.Push<u32>(0); // bsd errno
+}
+
void BSD::SendTo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
@@ -80,7 +120,7 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
{2, &BSD::Socket, "Socket"},
{3, nullptr, "SocketExempt"},
{4, nullptr, "Open"},
- {5, nullptr, "Select"},
+ {5, &BSD::Select, "Select"},
{6, nullptr, "Poll"},
{7, nullptr, "Sysctl"},
{8, nullptr, "Recv"},
@@ -88,15 +128,15 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
{10, nullptr, "Send"},
{11, &BSD::SendTo, "SendTo"},
{12, nullptr, "Accept"},
- {13, nullptr, "Bind"},
+ {13, &BSD::Bind, "Bind"},
{14, &BSD::Connect, "Connect"},
{15, nullptr, "GetPeerName"},
{16, nullptr, "GetSockName"},
{17, nullptr, "GetSockOpt"},
- {18, nullptr, "Listen"},
+ {18, &BSD::Listen, "Listen"},
{19, nullptr, "Ioctl"},
{20, nullptr, "Fcntl"},
- {21, nullptr, "SetSockOpt"},
+ {21, &BSD::SetSockOpt, "SetSockOpt"},
{22, nullptr, "Shutdown"},
{23, nullptr, "ShutdownAllSockets"},
{24, nullptr, "Write"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 0fe0e65c6..3098e3baf 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -18,7 +18,11 @@ private:
void RegisterClient(Kernel::HLERequestContext& ctx);
void StartMonitoring(Kernel::HLERequestContext& ctx);
void Socket(Kernel::HLERequestContext& ctx);
+ void Select(Kernel::HLERequestContext& ctx);
+ void Bind(Kernel::HLERequestContext& ctx);
void Connect(Kernel::HLERequestContext& ctx);
+ void Listen(Kernel::HLERequestContext& ctx);
+ void SetSockOpt(Kernel::HLERequestContext& ctx);
void SendTo(Kernel::HLERequestContext& ctx);
void Close(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp
index ca1a783fc..1575f0b49 100644
--- a/src/core/hle/service/time/standard_steady_clock_core.cpp
+++ b/src/core/hle/service/time/standard_steady_clock_core.cpp
@@ -5,6 +5,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/service/time/standard_steady_clock_core.h"
namespace Service::Time::Clock {
@@ -12,7 +13,7 @@ namespace Service::Time::Clock {
TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
- Core::Timing::CNTFREQ)};
+ Core::Hardware::CNTFREQ)};
TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
index c77b98189..44d5bc651 100644
--- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp
+++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
@@ -5,6 +5,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/service/time/tick_based_steady_clock_core.h"
namespace Service::Time::Clock {
@@ -12,7 +13,7 @@ namespace Service::Time::Clock {
SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
- Core::Timing::CNTFREQ)};
+ Core::Hardware::CNTFREQ)};
return {ticks_time_span.ToSeconds(), GetClockSourceId()};
}
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 8ef4efcef..749b7be70 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -6,6 +6,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
@@ -233,7 +234,7 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
const auto ticks{Clock::TimeSpanType::FromTicks(
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
- Core::Timing::CNTFREQ)};
+ Core::Hardware::CNTFREQ)};
const s64 base_time_point{context.offset + current_time_point.time_point -
ticks.ToSeconds()};
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index 9b03191bf..fdaef233f 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -5,6 +5,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/steady_clock_core.h"
#include "core/hle/service/time/time_sharedmemory.h"
@@ -31,7 +32,7 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system,
Clock::TimeSpanType current_time_point) {
const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
- Core::Timing::CNTFREQ)};
+ Core::Hardware::CNTFREQ)};
const Clock::SteadyClockContext context{
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
clock_source_id};
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 515c5accb..044067a5b 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -97,7 +97,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
if (nso_header.IsSegmentCompressed(i)) {
data = DecompressSegment(data, nso_header.segments[i]);
}
- program_image.resize(nso_header.segments[i].location + data.size());
+ program_image.resize(nso_header.segments[i].location +
+ PageAlignSize(static_cast<u32>(data.size())));
std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(),
data.size());
codeset.segments[i].addr = nso_header.segments[i].location;
@@ -105,8 +106,12 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
}
- if (should_pass_arguments && !Settings::values.program_args.empty()) {
- const auto arg_data = Settings::values.program_args;
+ if (should_pass_arguments) {
+ std::vector<u8> arg_data{Settings::values.program_args.begin(),
+ Settings::values.program_args.end()};
+ if (arg_data.empty()) {
+ arg_data.resize(NSO_ARGUMENT_DEFAULT_SIZE);
+ }
codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
NSOArgumentHeader args_header{
NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 58cbe162d..d2d600cd9 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -56,6 +56,8 @@ static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
+// NOTE: Official software default argument state is unverified.
+constexpr u64 NSO_ARGUMENT_DEFAULT_SIZE = 1;
struct NSOArgumentHeader {
u32_le allocated_size;
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index d1e6bed93..4472500d2 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -9,6 +9,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
@@ -17,7 +18,7 @@
namespace Memory {
-constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12);
+constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 12);
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
diff --git a/src/core/settings.h b/src/core/settings.h
index 9c98a9287..f837d3fbc 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;
@@ -401,6 +406,9 @@ struct Values {
std::string motion_device;
TouchscreenInput touchscreen;
std::atomic_bool is_device_reload_pending{true};
+ std::string udp_input_address;
+ u16 udp_input_port;
+ u8 udp_pad_index;
// Core
bool use_multi_core;
@@ -416,7 +424,12 @@ struct Values {
SDMCSize sdmc_size;
// Renderer
+ RendererBackend renderer_backend;
+ bool renderer_debug;
+ int vulkan_device;
+
float resolution_factor;
+ int aspect_ratio;
bool use_frame_limit;
u16 frame_limit;
bool use_disk_shader_cache;
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);
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 55e0dbc49..1e060f009 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -7,13 +7,14 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
#include "core/memory.h"
#include "core/tools/freezer.h"
namespace Tools {
namespace {
-constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
+constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60);
u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
switch (width) {