mirror of
https://github.com/yuzu-emu/yuzu-android
synced 2024-12-26 08:51:21 -08:00
Core: Refactor CPU Management.
This commit moves ARM Interface and Scheduler handling into the kernel.
This commit is contained in:
parent
ab89ced244
commit
4d6a86b03f
@ -158,6 +158,8 @@ add_library(core STATIC
|
|||||||
hle/kernel/mutex.h
|
hle/kernel/mutex.h
|
||||||
hle/kernel/object.cpp
|
hle/kernel/object.cpp
|
||||||
hle/kernel/object.h
|
hle/kernel/object.h
|
||||||
|
hle/kernel/physical_core.cpp
|
||||||
|
hle/kernel/physical_core.h
|
||||||
hle/kernel/process.cpp
|
hle/kernel/process.cpp
|
||||||
hle/kernel/process.h
|
hle/kernel/process.h
|
||||||
hle/kernel/process_capability.cpp
|
hle/kernel/process_capability.cpp
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "core/hardware_interrupt_manager.h"
|
#include "core/hardware_interrupt_manager.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
@ -119,6 +120,15 @@ struct System::Impl {
|
|||||||
return cpu_core_manager.GetCurrentCore();
|
return cpu_core_manager.GetCurrentCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kernel::PhysicalCore& CurrentPhysicalCore() {
|
||||||
|
const auto i = cpu_core_manager.GetCurrentCoreIndex();
|
||||||
|
return kernel.PhysicalCore(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) {
|
||||||
|
return kernel.PhysicalCore(index);
|
||||||
|
}
|
||||||
|
|
||||||
ResultStatus RunLoop(bool tight_loop) {
|
ResultStatus RunLoop(bool tight_loop) {
|
||||||
status = ResultStatus::Success;
|
status = ResultStatus::Success;
|
||||||
|
|
||||||
@ -131,8 +141,8 @@ struct System::Impl {
|
|||||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||||
|
|
||||||
core_timing.Initialize();
|
core_timing.Initialize();
|
||||||
cpu_core_manager.Initialize();
|
|
||||||
kernel.Initialize();
|
kernel.Initialize();
|
||||||
|
cpu_core_manager.Initialize();
|
||||||
|
|
||||||
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
|
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
std::chrono::system_clock::now().time_since_epoch());
|
std::chrono::system_clock::now().time_since_epoch());
|
||||||
@ -205,7 +215,6 @@ struct System::Impl {
|
|||||||
// Main process has been loaded and been made current.
|
// Main process has been loaded and been made current.
|
||||||
// Begin GPU and CPU execution.
|
// Begin GPU and CPU execution.
|
||||||
gpu_core->Start();
|
gpu_core->Start();
|
||||||
cpu_core_manager.StartThreads();
|
|
||||||
|
|
||||||
// Initialize cheat engine
|
// Initialize cheat engine
|
||||||
if (cheat_engine) {
|
if (cheat_engine) {
|
||||||
@ -394,7 +403,7 @@ System::ResultStatus System::SingleStep() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void System::InvalidateCpuInstructionCaches() {
|
void System::InvalidateCpuInstructionCaches() {
|
||||||
impl->cpu_core_manager.InvalidateAllInstructionCaches();
|
impl->kernel.InvalidateAllInstructionCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||||
@ -428,11 +437,11 @@ const TelemetrySession& System::TelemetrySession() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARM_Interface& System::CurrentArmInterface() {
|
ARM_Interface& System::CurrentArmInterface() {
|
||||||
return CurrentCpuCore().ArmInterface();
|
return impl->CurrentPhysicalCore().ArmInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ARM_Interface& System::CurrentArmInterface() const {
|
const ARM_Interface& System::CurrentArmInterface() const {
|
||||||
return CurrentCpuCore().ArmInterface();
|
return impl->CurrentPhysicalCore().ArmInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t System::CurrentCoreIndex() const {
|
std::size_t System::CurrentCoreIndex() const {
|
||||||
@ -440,19 +449,19 @@ std::size_t System::CurrentCoreIndex() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Scheduler& System::CurrentScheduler() {
|
Kernel::Scheduler& System::CurrentScheduler() {
|
||||||
return CurrentCpuCore().Scheduler();
|
return impl->CurrentPhysicalCore().Scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Kernel::Scheduler& System::CurrentScheduler() const {
|
const Kernel::Scheduler& System::CurrentScheduler() const {
|
||||||
return CurrentCpuCore().Scheduler();
|
return impl->CurrentPhysicalCore().Scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
|
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 {
|
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
|
/// Gets the global scheduler
|
||||||
@ -474,11 +483,11 @@ const Kernel::Process* System::CurrentProcess() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARM_Interface& System::ArmInterface(std::size_t core_index) {
|
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 {
|
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) {
|
Cpu& System::CpuCore(std::size_t core_index) {
|
||||||
@ -491,11 +500,11 @@ const Cpu& System::CpuCore(std::size_t core_index) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExclusiveMonitor& System::Monitor() {
|
ExclusiveMonitor& System::Monitor() {
|
||||||
return impl->cpu_core_manager.GetExclusiveMonitor();
|
return impl->kernel.GetExclusiveMonitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExclusiveMonitor& System::Monitor() const {
|
const ExclusiveMonitor& System::Monitor() const {
|
||||||
return impl->cpu_core_manager.GetExclusiveMonitor();
|
return impl->kernel.GetExclusiveMonitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::Memory& System::Memory() {
|
Memory::Memory& System::Memory() {
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_cpu.h"
|
#include "core/core_cpu.h"
|
||||||
#include "core/core_timing.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/scheduler.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
@ -21,68 +23,15 @@
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
void CpuBarrier::NotifyEnd() {
|
Cpu::Cpu(System& system, std::size_t core_index)
|
||||||
std::unique_lock lock{mutex};
|
: global_scheduler{system.GlobalScheduler()},
|
||||||
end = true;
|
physical_core{system.Kernel().PhysicalCore(core_index)}, core_timing{system.CoreTiming()},
|
||||||
condition.notify_all();
|
core_index{core_index} {
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
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) {
|
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();
|
Reschedule();
|
||||||
|
|
||||||
// If we don't have a currently active thread then don't execute instructions,
|
// If we don't have a currently active thread then don't execute instructions,
|
||||||
@ -92,12 +41,10 @@ void Cpu::RunLoop(bool tight_loop) {
|
|||||||
core_timing.Idle();
|
core_timing.Idle();
|
||||||
} else {
|
} else {
|
||||||
if (tight_loop) {
|
if (tight_loop) {
|
||||||
arm_interface->Run();
|
physical_core.Run();
|
||||||
} else {
|
} else {
|
||||||
arm_interface->Step();
|
physical_core.Step();
|
||||||
}
|
}
|
||||||
// We are stopping a run, exclusive state must be cleared
|
|
||||||
arm_interface->ClearExclusiveState();
|
|
||||||
}
|
}
|
||||||
core_timing.Advance();
|
core_timing.Advance();
|
||||||
|
|
||||||
@ -109,7 +56,7 @@ void Cpu::SingleStep() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::PrepareReschedule() {
|
void Cpu::PrepareReschedule() {
|
||||||
arm_interface->PrepareReschedule();
|
physical_core.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::Reschedule() {
|
void Cpu::Reschedule() {
|
||||||
@ -117,11 +64,8 @@ void Cpu::Reschedule() {
|
|||||||
std::lock_guard lock(HLE::g_hle_lock);
|
std::lock_guard lock(HLE::g_hle_lock);
|
||||||
|
|
||||||
global_scheduler.SelectThread(core_index);
|
global_scheduler.SelectThread(core_index);
|
||||||
scheduler->TryDoContextSwitch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cpu::Shutdown() {
|
physical_core.Scheduler().TryDoContextSwitch();
|
||||||
scheduler->Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class GlobalScheduler;
|
class GlobalScheduler;
|
||||||
class Scheduler;
|
class PhysicalCore;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -30,32 +30,11 @@ class Memory;
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class ARM_Interface;
|
|
||||||
class ExclusiveMonitor;
|
|
||||||
|
|
||||||
constexpr unsigned NUM_CPU_CORES{4};
|
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 {
|
class Cpu {
|
||||||
public:
|
public:
|
||||||
Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
|
Cpu(System& system, std::size_t core_index);
|
||||||
std::size_t core_index);
|
|
||||||
~Cpu();
|
~Cpu();
|
||||||
|
|
||||||
void RunLoop(bool tight_loop = true);
|
void RunLoop(bool tight_loop = true);
|
||||||
@ -64,22 +43,6 @@ public:
|
|||||||
|
|
||||||
void PrepareReschedule();
|
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 {
|
bool IsMainCore() const {
|
||||||
return core_index == 0;
|
return core_index == 0;
|
||||||
}
|
}
|
||||||
@ -88,29 +51,11 @@ public:
|
|||||||
return core_index;
|
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:
|
private:
|
||||||
void Reschedule();
|
void Reschedule();
|
||||||
|
|
||||||
std::unique_ptr<ARM_Interface> arm_interface;
|
|
||||||
CpuBarrier& cpu_barrier;
|
|
||||||
Kernel::GlobalScheduler& global_scheduler;
|
Kernel::GlobalScheduler& global_scheduler;
|
||||||
std::unique_ptr<Kernel::Scheduler> scheduler;
|
Kernel::PhysicalCore& physical_core;
|
||||||
Timing::CoreTiming& core_timing;
|
Timing::CoreTiming& core_timing;
|
||||||
|
|
||||||
std::atomic<bool> reschedule_pending = false;
|
std::atomic<bool> reschedule_pending = false;
|
||||||
|
@ -24,46 +24,16 @@ CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
|
|||||||
CpuCoreManager::~CpuCoreManager() = default;
|
CpuCoreManager::~CpuCoreManager() = default;
|
||||||
|
|
||||||
void CpuCoreManager::Initialize() {
|
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) {
|
for (std::size_t index = 0; index < cores.size(); ++index) {
|
||||||
cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
|
cores[index] = std::make_unique<Cpu>(system, 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() {
|
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) {
|
for (auto& cpu_core : cores) {
|
||||||
cpu_core->Shutdown();
|
|
||||||
cpu_core.reset();
|
cpu_core.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
exclusive_monitor.reset();
|
|
||||||
barrier.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cpu& CpuCoreManager::GetCore(std::size_t index) {
|
Cpu& CpuCoreManager::GetCore(std::size_t index) {
|
||||||
@ -74,42 +44,17 @@ const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
|
|||||||
return *cores.at(index);
|
return *cores.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
|
|
||||||
return *exclusive_monitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
|
|
||||||
return *exclusive_monitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cpu& CpuCoreManager::GetCurrentCore() {
|
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
|
// Otherwise, use single-threaded mode active_core variable
|
||||||
return *cores[active_core];
|
return *cores[active_core];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cpu& CpuCoreManager::GetCurrentCore() const {
|
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
|
// Otherwise, use single-threaded mode active_core variable
|
||||||
return *cores[active_core];
|
return *cores[active_core];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuCoreManager::RunLoop(bool tight_loop) {
|
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()) {
|
if (GDBStub::IsServerEnabled()) {
|
||||||
GDBStub::HandlePacket();
|
GDBStub::HandlePacket();
|
||||||
|
|
||||||
@ -143,10 +88,4 @@ void CpuCoreManager::RunLoop(bool tight_loop) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuCoreManager::InvalidateAllInstructionCaches() {
|
|
||||||
for (auto& cpu : cores) {
|
|
||||||
cpu->ArmInterface().ClearInstructionCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class Cpu;
|
class Cpu;
|
||||||
class CpuBarrier;
|
|
||||||
class ExclusiveMonitor;
|
|
||||||
class System;
|
class System;
|
||||||
|
|
||||||
class CpuCoreManager {
|
class CpuCoreManager {
|
||||||
@ -28,7 +26,6 @@ public:
|
|||||||
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
|
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void StartThreads();
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
Cpu& GetCore(std::size_t index);
|
Cpu& GetCore(std::size_t index);
|
||||||
@ -37,25 +34,18 @@ public:
|
|||||||
Cpu& GetCurrentCore();
|
Cpu& GetCurrentCore();
|
||||||
const Cpu& GetCurrentCore() const;
|
const Cpu& GetCurrentCore() const;
|
||||||
|
|
||||||
ExclusiveMonitor& GetExclusiveMonitor();
|
std::size_t GetCurrentCoreIndex() const {
|
||||||
const ExclusiveMonitor& GetExclusiveMonitor() const;
|
return active_core;
|
||||||
|
}
|
||||||
|
|
||||||
void RunLoop(bool tight_loop);
|
void RunLoop(bool tight_loop);
|
||||||
|
|
||||||
void InvalidateAllInstructionCaches();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::size_t NUM_CPU_CORES = 4;
|
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<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
|
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;
|
System& system;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,7 +9,11 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#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/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
@ -17,6 +21,7 @@
|
|||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
@ -98,6 +103,7 @@ struct KernelCore::Impl {
|
|||||||
void Initialize(KernelCore& kernel) {
|
void Initialize(KernelCore& kernel) {
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
|
||||||
|
InitializePhysicalCores(kernel);
|
||||||
InitializeSystemResourceLimit(kernel);
|
InitializeSystemResourceLimit(kernel);
|
||||||
InitializeThreads();
|
InitializeThreads();
|
||||||
InitializePreemption();
|
InitializePreemption();
|
||||||
@ -121,6 +127,20 @@ struct KernelCore::Impl {
|
|||||||
global_scheduler.Shutdown();
|
global_scheduler.Shutdown();
|
||||||
|
|
||||||
named_ports.clear();
|
named_ports.clear();
|
||||||
|
|
||||||
|
for (auto& core : cores) {
|
||||||
|
core.Shutdown();
|
||||||
|
}
|
||||||
|
cores.clear();
|
||||||
|
|
||||||
|
exclusive_monitor.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializePhysicalCores(KernelCore& kernel) {
|
||||||
|
exclusive_monitor = MakeExclusiveMonitor();
|
||||||
|
for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) {
|
||||||
|
cores.emplace_back(system, kernel, i, *exclusive_monitor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the default system resource limit
|
// Creates the default system resource limit
|
||||||
@ -136,6 +156,7 @@ struct KernelCore::Impl {
|
|||||||
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
|
ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InitializeThreads() {
|
void InitializeThreads() {
|
||||||
thread_wakeup_event_type =
|
thread_wakeup_event_type =
|
||||||
Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
||||||
@ -163,6 +184,16 @@ struct KernelCore::Impl {
|
|||||||
system.Memory().SetCurrentPageTable(*process);
|
system.Memory().SetCurrentPageTable(*process);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor() {
|
||||||
|
#ifdef ARCHITECTURE_x86_64
|
||||||
|
return std::make_unique<Core::DynarmicExclusiveMonitor>(system.Memory(),
|
||||||
|
global_scheduler.CpuCoresCount());
|
||||||
|
#else
|
||||||
|
// TODO(merry): Passthrough exclusive monitor
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
std::atomic<u32> next_object_id{0};
|
std::atomic<u32> next_object_id{0};
|
||||||
std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
|
std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
|
||||||
std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
|
std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
|
||||||
@ -186,6 +217,9 @@ struct KernelCore::Impl {
|
|||||||
/// the ConnectToPort SVC.
|
/// the ConnectToPort SVC.
|
||||||
NamedPortTable named_ports;
|
NamedPortTable named_ports;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||||
|
std::vector<Kernel::PhysicalCore> cores;
|
||||||
|
|
||||||
// System context
|
// System context
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
@ -240,6 +274,34 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
|
|||||||
return impl->global_scheduler;
|
return impl->global_scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
|
||||||
|
return impl->cores[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
|
||||||
|
return impl->cores[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
|
||||||
|
return *impl->exclusive_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
|
||||||
|
return *impl->exclusive_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::InvalidateAllInstructionCaches() {
|
||||||
|
for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) {
|
||||||
|
PhysicalCore(i).ArmInterface().ClearInstructionCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::PrepareReschedule(std::size_t id) {
|
||||||
|
if (id >= 0 && id < impl->global_scheduler.CpuCoresCount()) {
|
||||||
|
impl->cores[id].Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
|
void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
|
||||||
impl->named_ports.emplace(std::move(name), std::move(port));
|
impl->named_ports.emplace(std::move(name), std::move(port));
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
class ExclusiveMonitor;
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ class AddressArbiter;
|
|||||||
class ClientPort;
|
class ClientPort;
|
||||||
class GlobalScheduler;
|
class GlobalScheduler;
|
||||||
class HandleTable;
|
class HandleTable;
|
||||||
|
class PhysicalCore;
|
||||||
class Process;
|
class Process;
|
||||||
class ResourceLimit;
|
class ResourceLimit;
|
||||||
class Thread;
|
class Thread;
|
||||||
@ -84,6 +86,21 @@ public:
|
|||||||
/// Gets the sole instance of the global scheduler
|
/// Gets the sole instance of the global scheduler
|
||||||
const Kernel::GlobalScheduler& GlobalScheduler() const;
|
const Kernel::GlobalScheduler& GlobalScheduler() const;
|
||||||
|
|
||||||
|
/// Gets the an instance of the respective physical CPU core.
|
||||||
|
Kernel::PhysicalCore& PhysicalCore(std::size_t id);
|
||||||
|
|
||||||
|
/// Gets the an instance of the respective physical CPU core.
|
||||||
|
const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
|
||||||
|
|
||||||
|
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
||||||
|
void PrepareReschedule(std::size_t id);
|
||||||
|
|
||||||
|
Core::ExclusiveMonitor& GetExclusiveMonitor();
|
||||||
|
|
||||||
|
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
|
||||||
|
|
||||||
|
void InvalidateAllInstructionCaches();
|
||||||
|
|
||||||
/// Adds a port to the named port table
|
/// Adds a port to the named port table
|
||||||
void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
|
void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
|
||||||
|
|
||||||
|
@ -2,18 +2,48 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// 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/kernel.h"
|
||||||
|
#include "core/hle/kernel/physical_core.h"
|
||||||
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
PhysicalCore::PhysicalCore(KernelCore& kernel, std::size_t id, ExclusiveMonitor& exclusive_monitor)
|
PhysicalCore::PhysicalCore(Core::System& system, KernelCore& kernel, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor)
|
||||||
: core_index{id}, kernel{kernel} {
|
: core_index{id}, kernel{kernel} {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
|
arm_interface = std::make_unique<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index);
|
||||||
#else
|
#else
|
||||||
arm_interface = std::make_unique<ARM_Unicorn>(system);
|
arm_interface = std::make_unique<Core::ARM_Unicorn>(system);
|
||||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index);
|
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
} // namespace Kernel
|
||||||
|
@ -8,14 +8,17 @@ namespace Kernel {
|
|||||||
class Scheduler;
|
class Scheduler;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
class ARM_Interface;
|
class ARM_Interface;
|
||||||
class ExclusiveMonitor;
|
class ExclusiveMonitor;
|
||||||
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class PhysicalCore {
|
class PhysicalCore {
|
||||||
public:
|
public:
|
||||||
PhysicalCore(KernelCore& kernel, std::size_t id, ExclusiveMonitor& exclusive_monitor);
|
PhysicalCore(Core::System& system, KernelCore& kernel, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor);
|
||||||
|
|
||||||
/// Execute current jit state
|
/// Execute current jit state
|
||||||
void Run();
|
void Run();
|
||||||
@ -24,11 +27,14 @@ public:
|
|||||||
/// Stop JIT execution/exit
|
/// Stop JIT execution/exit
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
ARM_Interface& ArmInterface() {
|
// Shutdown this physical core.
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
Core::ARM_Interface& ArmInterface() {
|
||||||
return *arm_interface;
|
return *arm_interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ARM_Interface& ArmInterface() const {
|
const Core::ARM_Interface& ArmInterface() const {
|
||||||
return *arm_interface;
|
return *arm_interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,19 +50,19 @@ public:
|
|||||||
return core_index;
|
return core_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheduler& Scheduler() {
|
Kernel::Scheduler& Scheduler() {
|
||||||
return *scheduler;
|
return *scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Scheduler& Scheduler() const {
|
const Kernel::Scheduler& Scheduler() const {
|
||||||
return *scheduler;
|
return *scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t core_index;
|
std::size_t core_index;
|
||||||
std::unique_ptr<ARM_Interface> arm_interface;
|
|
||||||
std::unique_ptr<Kernel::Scheduler> scheduler;
|
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
}
|
std::unique_ptr<Core::ARM_Interface> arm_interface;
|
||||||
|
std::unique_ptr<Kernel::Scheduler> scheduler;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
Loading…
Reference in New Issue
Block a user