diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 5749221309..c0cc62f03a 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -52,7 +52,7 @@ static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) { static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value, void* user_data) { ARM_Interface::ThreadContext ctx{}; - Core::CPU().SaveContext(ctx); + Core::CurrentArmInterface().SaveContext(ctx); ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr, ctx.pc, ctx.cpu_registers[30]); return {}; diff --git a/src/core/core.h b/src/core/core.h index 21a0b074b8..3e0a7e6a7c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -108,20 +108,26 @@ public: PerfStats::Results GetAndResetPerfStats(); - /** - * Gets a reference to the emulated CPU. - * @returns A reference to the emulated CPU. - */ - ARM_Interface& CPU() { - return CurrentCpuCore().CPU(); + ARM_Interface& CurrentArmInterface() { + return CurrentCpuCore().ArmInterface(); + } + + ARM_Interface& ArmInterface(size_t core_index) { + ASSERT(core_index < NUM_CPU_CORES); + return cpu_cores[core_index]->ArmInterface(); } Tegra::GPU& GPU() { return *gpu_core; } - Kernel::Scheduler& Scheduler() { - return CurrentCpuCore().Scheduler(); + Kernel::Scheduler& CurrentScheduler() { + return *CurrentCpuCore().Scheduler(); + } + + const std::shared_ptr& Scheduler(size_t core_index) { + ASSERT(core_index < NUM_CPU_CORES); + return cpu_cores[core_index]->Scheduler(); } Kernel::SharedPtr& CurrentProcess() { @@ -198,8 +204,8 @@ private: std::map> thread_to_cpu; }; -inline ARM_Interface& CPU() { - return System::GetInstance().CPU(); +inline ARM_Interface& CurrentArmInterface() { + return System::GetInstance().CurrentArmInterface(); } inline TelemetrySession& Telemetry() { diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 6bdfdd7df6..a556f12e91 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -33,7 +33,7 @@ Cpu::Cpu(std::shared_ptr cpu_barrier, size_t core_index) arm_interface = std::make_shared(); } - scheduler = std::make_unique(arm_interface.get()); + scheduler = std::make_shared(arm_interface.get()); } void Cpu::RunLoop(bool tight_loop) { diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index e6ed698ccf..06784c4ab2 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -51,12 +51,16 @@ public: void PrepareReschedule(); - ARM_Interface& CPU() { + ARM_Interface& ArmInterface() { return *arm_interface; } - Kernel::Scheduler& Scheduler() { - return *scheduler; + const ARM_Interface& ArmInterface() const { + return *arm_interface; + } + + const std::shared_ptr& Scheduler() const { + return scheduler; } bool IsMainCore() const { @@ -68,7 +72,7 @@ private: std::shared_ptr arm_interface; std::shared_ptr cpu_barrier; - std::unique_ptr scheduler; + std::shared_ptr scheduler; bool reschedule_pending{}; size_t core_index; diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 46606b9922..6c5a40ba8c 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -598,11 +598,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, Core::CPU().GetReg(static_cast(id))); + LongToGdbHex(reply, Core::CurrentArmInterface().GetReg(static_cast(id))); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, Core::CPU().GetPC()); + LongToGdbHex(reply, Core::CurrentArmInterface().GetPC()); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, Core::CPU().GetCPSR()); + IntToGdbHex(reply, Core::CurrentArmInterface().GetCPSR()); } else { return SendReply("E01"); } @@ -618,16 +618,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, Core::CPU().GetReg(reg)); + LongToGdbHex(bufptr + reg * 16, Core::CurrentArmInterface().GetReg(reg)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, Core::CPU().GetPC()); + LongToGdbHex(bufptr, Core::CurrentArmInterface().GetPC()); bufptr += 16; - IntToGdbHex(bufptr, Core::CPU().GetCPSR()); + IntToGdbHex(bufptr, Core::CurrentArmInterface().GetCPSR()); bufptr += 8; @@ -646,11 +646,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - Core::CPU().SetReg(id, GdbHexToLong(buffer_ptr)); + Core::CurrentArmInterface().SetReg(id, GdbHexToLong(buffer_ptr)); } else if (id == PC_REGISTER) { - Core::CPU().SetPC(GdbHexToLong(buffer_ptr)); + Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr)); } else if (id == CPSR_REGISTER) { - Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr)); + Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr)); } else { return SendReply("E01"); } @@ -667,11 +667,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - Core::CPU().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16)); + Core::CurrentArmInterface().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16)); } else if (reg == PC_REGISTER) { - Core::CPU().SetPC(GdbHexToLong(buffer_ptr + i * 16)); + Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr + i * 16)); } else if (reg == CPSR_REGISTER) { - Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * 16)); + Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr + i * 16)); } else { UNIMPLEMENTED(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 72b5c05f28..520510b61b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -485,22 +485,28 @@ static void ExitProcess() { Core::CurrentProcess()->status = ProcessStatus::Exited; - // Stop all the process threads that are currently waiting for objects. - auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); - for (auto& thread : thread_list) { - if (thread->owner_process != Core::CurrentProcess()) - continue; + auto stop_threads = [](const std::vector>& thread_list) { + for (auto& thread : thread_list) { + if (thread->owner_process != Core::CurrentProcess()) + continue; - if (thread == GetCurrentThread()) - continue; + if (thread == GetCurrentThread()) + continue; - // TODO(Subv): When are the other running/ready threads terminated? - ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL, - "Exiting processes with non-waiting threads is currently unimplemented"); + // TODO(Subv): When are the other running/ready threads terminated? + ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || + thread->status == THREADSTATUS_WAIT_SYNCH_ALL, + "Exiting processes with non-waiting threads is currently unimplemented"); - thread->Stop(); - } + thread->Stop(); + } + }; + + auto& system = Core::System::GetInstance(); + stop_threads(system.Scheduler(0)->GetThreadList()); + stop_threads(system.Scheduler(1)->GetThreadList()); + stop_threads(system.Scheduler(2)->GetThreadList()); + stop_threads(system.Scheduler(3)->GetThreadList()); // Kill the current thread GetCurrentThread()->Stop(); @@ -530,14 +536,9 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V switch (processor_id) { case THREADPROCESSORID_0: - break; case THREADPROCESSORID_1: case THREADPROCESSORID_2: case THREADPROCESSORID_3: - // TODO(bunnei): Implement support for other processor IDs - NGLOG_ERROR(Kernel_SVC, - "Newly created thread must run in another thread ({}), unimplemented.", - processor_id); break; default: ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); @@ -576,7 +577,7 @@ static ResultCode StartThread(Handle thread_handle) { /// Called when a thread exits static void ExitThread() { - NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC()); + NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC()); ExitCurrentThread(); Core::System::GetInstance().PrepareReschedule(); @@ -588,7 +589,7 @@ static void SleepThread(s64 nanoseconds) { // Don't attempt to yield execution if there are no available threads to run, // this way we avoid a useless reschedule to the idle thread. - if (nanoseconds == 0 && !Core::System::GetInstance().Scheduler().HaveReadyThreads()) + if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads()) return; // Sleep current thread and check for next thread to schedule @@ -634,7 +635,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target condition_variable_addr, target); u32 processed = 0; - auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); + auto& thread_list = Core::System::GetInstance().CurrentScheduler().GetThreadList(); for (auto& thread : thread_list) { if (thread->condvar_wait_address != condition_variable_addr) diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index c86ad3e04e..40aa88cc1f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -13,14 +13,14 @@ namespace Kernel { -#define PARAM(n) Core::CPU().GetReg(n) +#define PARAM(n) Core::CurrentArmInterface().GetReg(n) /** * HLE a function return from the current ARM userland process * @param res Result to return */ static inline void FuncReturn(u64 res) { - Core::CPU().SetReg(0, res); + Core::CurrentArmInterface().SetReg(0, res); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -45,7 +45,7 @@ template void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, (u32)PARAM(1)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -53,7 +53,7 @@ template void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -66,7 +66,7 @@ template void SvcWrap() { u64 param_1 = 0; u32 retval = func(¶m_1, PARAM(1)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -85,8 +85,8 @@ void SvcWrap() { u32 param_1 = 0; u64 param_2 = 0; ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); - Core::CPU().SetReg(1, param_1); - Core::CPU().SetReg(2, param_2); + Core::CurrentArmInterface().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(2, param_2); FuncReturn(retval.raw); } @@ -120,7 +120,7 @@ template void SvcWrap() { u32 param_1 = 0; ResultCode retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)); - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval.raw); } @@ -133,7 +133,7 @@ template void SvcWrap() { u64 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -143,7 +143,7 @@ void SvcWrap() { u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF)) .raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -166,7 +166,7 @@ template void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -175,7 +175,7 @@ void SvcWrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw; - Core::CPU().SetReg(1, param_1); + Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1bd5d9ebf6..0a5441684c 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -64,7 +64,7 @@ void Thread::Stop() { // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) if (status == THREADSTATUS_READY) { - Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority); + scheduler->UnscheduleThread(this, current_priority); } status = THREADSTATUS_DEAD; @@ -92,7 +92,7 @@ void WaitCurrentThread_Sleep() { void ExitCurrentThread() { Thread* thread = GetCurrentThread(); thread->Stop(); - Core::System::GetInstance().Scheduler().RemoveThread(thread); + Core::System::GetInstance().CurrentScheduler().RemoveThread(thread); } /** @@ -188,7 +188,7 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; status = THREADSTATUS_READY; - Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority); + scheduler->ScheduleThread(this, current_priority); Core::System::GetInstance().PrepareReschedule(); } @@ -259,8 +259,6 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, SharedPtr thread(new Thread); - Core::System::GetInstance().Scheduler().AddThread(thread, priority); - thread->thread_id = NewThreadId(); thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; @@ -275,6 +273,8 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->name = std::move(name); thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); thread->owner_process = owner_process; + thread->scheduler = Core::System().GetInstance().Scheduler(static_cast(processor_id)); + thread->scheduler->AddThread(thread, priority); // Find the next available TLS index, and mark it as used auto& tls_slots = owner_process->tls_slots; @@ -337,7 +337,7 @@ void Thread::SetPriority(u32 priority) { } void Thread::BoostPriority(u32 priority) { - Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); + scheduler->SetThreadPriority(this, priority); current_priority = priority; } @@ -406,7 +406,7 @@ void Thread::UpdatePriority() { if (new_priority == current_priority) return; - Core::System::GetInstance().Scheduler().SetThreadPriority(this, new_priority); + scheduler->SetThreadPriority(this, new_priority); current_priority = new_priority; @@ -421,7 +421,7 @@ void Thread::UpdatePriority() { * Gets the current thread */ Thread* GetCurrentThread() { - return Core::System::GetInstance().Scheduler().GetCurrentThread(); + return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); } void ThreadingInit() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e0a3c09345..0a3bb11838 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -56,6 +57,7 @@ enum class ThreadWakeupReason { namespace Kernel { class Process; +class Scheduler; class Thread final : public WaitObject { public: @@ -240,6 +242,8 @@ public: // available. In case of a timeout, the object will be nullptr. std::function wakeup_callback; + std::shared_ptr scheduler; + private: Thread(); ~Thread() override; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 2f0044c113..676e5b2823 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -104,8 +104,15 @@ ResultVal VMManager::MapMemoryBlock(VAddr target, VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - Core::CPU().MapBackingMemory(target, size, block->data() + offset, - VMAPermission::ReadWriteExecute); + auto& system = Core::System::GetInstance(); + system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); + system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); + system.ArmInterface(2).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); + system.ArmInterface(3).MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); final_vma.type = VMAType::AllocatedMemoryBlock; final_vma.permissions = VMAPermission::ReadWrite; @@ -126,7 +133,11 @@ ResultVal VMManager::MapBackingMemory(VAddr target, u8* me VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - Core::CPU().MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + auto& system = Core::System::GetInstance(); + system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); + system.ArmInterface(3).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); final_vma.type = VMAType::BackingMemory; final_vma.permissions = VMAPermission::ReadWrite; @@ -184,7 +195,11 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) { ASSERT(FindVMA(target)->second.size >= size); - Core::CPU().UnmapMemory(target, size); + auto& system = Core::System::GetInstance(); + system.ArmInterface(0).UnmapMemory(target, size); + system.ArmInterface(1).UnmapMemory(target, size); + system.ArmInterface(2).UnmapMemory(target, size); + system.ArmInterface(3).UnmapMemory(target, size); return RESULT_SUCCESS; } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index db82114630..3b81acd631 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -28,8 +28,13 @@ static PageTable* current_page_table = nullptr; void SetCurrentPageTable(PageTable* page_table) { current_page_table = page_table; - if (Core::System::GetInstance().IsPoweredOn()) { - Core::CPU().PageTableChanged(); + + auto& system = Core::System::GetInstance(); + if (system.IsPoweredOn()) { + system.ArmInterface(0).PageTableChanged(); + system.ArmInterface(1).PageTableChanged(); + system.ArmInterface(2).PageTableChanged(); + system.ArmInterface(3).PageTableChanged(); } } diff --git a/src/yuzu/debugger/registers.cpp b/src/yuzu/debugger/registers.cpp index 06e2d1647d..178cc65a79 100644 --- a/src/yuzu/debugger/registers.cpp +++ b/src/yuzu/debugger/registers.cpp @@ -63,7 +63,7 @@ void RegistersWidget::OnDebugModeEntered() { for (int i = 0; i < core_registers->childCount(); ++i) core_registers->child(i)->setText( - 1, QString("0x%1").arg(Core::CPU().GetReg(i), 8, 16, QLatin1Char('0'))); + 1, QString("0x%1").arg(Core::CurrentArmInterface().GetReg(i), 8, 16, QLatin1Char('0'))); UpdateCPSRValues(); } @@ -122,7 +122,7 @@ void RegistersWidget::CreateCPSRChildren() { } void RegistersWidget::UpdateCPSRValues() { - const u32 cpsr_val = Core::CPU().GetCPSR(); + const u32 cpsr_val = Core::CurrentArmInterface().GetCPSR(); cpsr->setText(1, QString("0x%1").arg(cpsr_val, 8, 16, QLatin1Char('0'))); cpsr->child(0)->setText( diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index acc4c2e0be..f05c98cc37 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -51,7 +51,7 @@ std::size_t WaitTreeItem::Row() const { } std::vector> WaitTreeItem::MakeThreadItemList() { - const auto& threads = Core::System::GetInstance().Scheduler().GetThreadList(); + const auto& threads = Core::System::GetInstance().Scheduler(0)->GetThreadList(); std::vector> item_list; item_list.reserve(threads.size()); for (std::size_t i = 0; i < threads.size(); ++i) {