mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2025-06-11 17:57:58 -05:00
core: refactor emulated cpu core activation
This commit is contained in:
@ -69,8 +69,16 @@ public:
|
||||
};
|
||||
|
||||
template <typename AddressType>
|
||||
void InvalidateInstructionCache(Core::System& system, AddressType addr, u64 size) {
|
||||
system.InvalidateCpuInstructionCacheRange(GetInteger(addr), size);
|
||||
void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size) {
|
||||
// TODO: lock the process list
|
||||
for (auto& process : kernel.GetProcessList()) {
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
auto* interface = process->GetArmInterface(i);
|
||||
if (interface) {
|
||||
interface->InvalidateCacheRange(GetInteger(addr), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
@ -1261,7 +1269,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
|
||||
bool reprotected_pages = false;
|
||||
SCOPE_EXIT({
|
||||
if (reprotected_pages && any_code_pages) {
|
||||
InvalidateInstructionCache(m_system, dst_address, size);
|
||||
InvalidateInstructionCache(m_kernel, dst_address, size);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1997,7 +2005,7 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s
|
||||
for (const auto& block : pg) {
|
||||
StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize());
|
||||
}
|
||||
InvalidateInstructionCache(m_system, addr, size);
|
||||
InvalidateInstructionCache(m_kernel, addr, size);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
@ -3239,7 +3247,7 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd
|
||||
R_TRY(PerformCopy());
|
||||
|
||||
// Invalidate the instruction cache, as this svc allows modifying executable pages.
|
||||
InvalidateInstructionCache(m_system, dst_address, size);
|
||||
InvalidateInstructionCache(m_kernel, dst_address, size);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
@ -13,6 +13,12 @@
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/k_worker_task_manager.h"
|
||||
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#ifdef HAS_NCE
|
||||
#include "core/arm/nce/arm_nce.h"
|
||||
#endif
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
namespace {
|
||||
@ -957,10 +963,8 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
|
||||
R_TRY(m_handle_table.Add(std::addressof(thread_handle), main_thread));
|
||||
|
||||
// Set the thread arguments.
|
||||
main_thread->GetContext32().cpu_registers[0] = 0;
|
||||
main_thread->GetContext64().cpu_registers[0] = 0;
|
||||
main_thread->GetContext32().cpu_registers[1] = thread_handle;
|
||||
main_thread->GetContext64().cpu_registers[1] = thread_handle;
|
||||
main_thread->GetContext().r[0] = 0;
|
||||
main_thread->GetContext().r[1] = thread_handle;
|
||||
|
||||
// Update our state.
|
||||
this->ChangeState((state == State::Created) ? State::Running : State::RunningAttached);
|
||||
@ -1199,6 +1203,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
||||
m_is_hbl = is_hbl;
|
||||
m_ideal_core_id = metadata.GetMainThreadCore();
|
||||
|
||||
// Set up emulation context.
|
||||
this->InitializeInterfaces();
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
@ -1227,6 +1234,31 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void KProcess::InitializeInterfaces() {
|
||||
this->GetMemory().SetCurrentPageTable(*this);
|
||||
|
||||
#ifdef HAS_NCE
|
||||
if (this->Is64Bit() && Settings::IsNceEnabled()) {
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (this->Is64Bit()) {
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
|
||||
m_kernel.System(), m_kernel.IsMulticore(), this,
|
||||
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
|
||||
m_kernel.System(), m_kernel.IsMulticore(), this,
|
||||
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) {
|
||||
const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) {
|
||||
return wp.type == DebugWatchpointType::None;
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/hle/kernel/code_set.h"
|
||||
#include "core/hle/kernel/k_address_arbiter.h"
|
||||
@ -106,6 +107,8 @@ private:
|
||||
bool m_is_suspended{};
|
||||
bool m_is_immortal{};
|
||||
bool m_is_handle_table_initialized{};
|
||||
std::array<std::unique_ptr<Core::ArmInterface>, Core::Hardware::NUM_CPU_CORES>
|
||||
m_arm_interfaces{};
|
||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{};
|
||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{};
|
||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_switch_counts{};
|
||||
@ -476,6 +479,10 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
Core::ArmInterface* GetArmInterface(size_t core_index) const {
|
||||
return m_arm_interfaces[core_index].get();
|
||||
}
|
||||
|
||||
public:
|
||||
// Attempts to insert a watchpoint into a free slot. Returns false if none are available.
|
||||
bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
|
||||
@ -493,6 +500,8 @@ public:
|
||||
|
||||
void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
||||
|
||||
void InitializeInterfaces();
|
||||
|
||||
Core::Memory::Memory& GetMemory() const;
|
||||
|
||||
public:
|
||||
|
@ -7,10 +7,6 @@
|
||||
#include "core/hle/kernel/k_scoped_lock.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
||||
namespace Core {
|
||||
class ARM_Interface;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KProcessPageTable {
|
||||
|
@ -494,12 +494,7 @@ void KScheduler::ScheduleImplFiber() {
|
||||
}
|
||||
|
||||
void KScheduler::Unload(KThread* thread) {
|
||||
auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
|
||||
cpu_core.SaveContext(thread->GetContext32());
|
||||
cpu_core.SaveContext(thread->GetContext64());
|
||||
// Save the TPIDR_EL0 system register in case it was modified.
|
||||
thread->SetTpidrEl0(cpu_core.GetTPIDR_EL0());
|
||||
cpu_core.ClearExclusiveState();
|
||||
m_kernel.PhysicalCore(m_core_id).SaveContext(thread);
|
||||
|
||||
// Check if the thread is terminated by checking the DPC flags.
|
||||
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
|
||||
@ -509,14 +504,7 @@ void KScheduler::Unload(KThread* thread) {
|
||||
}
|
||||
|
||||
void KScheduler::Reload(KThread* thread) {
|
||||
auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
|
||||
auto* process = thread->GetOwnerProcess();
|
||||
cpu_core.LoadContext(thread->GetContext32());
|
||||
cpu_core.LoadContext(thread->GetContext64());
|
||||
cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress()));
|
||||
cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0());
|
||||
cpu_core.LoadWatchpointArray(process ? &process->GetWatchpoints() : nullptr);
|
||||
cpu_core.ClearExclusiveState();
|
||||
m_kernel.PhysicalCore(m_core_id).LoadContext(thread);
|
||||
}
|
||||
|
||||
void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) {
|
||||
|
@ -41,24 +41,25 @@ namespace {
|
||||
|
||||
constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
|
||||
|
||||
static void ResetThreadContext32(Kernel::KThread::ThreadContext32& context, u32 stack_top,
|
||||
u32 entry_point, u32 arg) {
|
||||
context = {};
|
||||
context.cpu_registers[0] = arg;
|
||||
context.cpu_registers[15] = entry_point;
|
||||
context.cpu_registers[13] = stack_top;
|
||||
context.fpscr = 0;
|
||||
static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
|
||||
u64 arg) {
|
||||
ctx = {};
|
||||
ctx.r[0] = arg;
|
||||
ctx.r[15] = entry_point;
|
||||
ctx.r[13] = stack_top;
|
||||
ctx.fpcr = 0;
|
||||
ctx.fpsr = 0;
|
||||
}
|
||||
|
||||
static void ResetThreadContext64(Kernel::KThread::ThreadContext64& context, u64 stack_top,
|
||||
u64 entry_point, u64 arg) {
|
||||
context = {};
|
||||
context.cpu_registers[0] = arg;
|
||||
context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
|
||||
context.pc = entry_point;
|
||||
context.sp = stack_top;
|
||||
context.fpcr = 0;
|
||||
context.fpsr = 0;
|
||||
static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
|
||||
u64 arg) {
|
||||
ctx = {};
|
||||
ctx.r[0] = arg;
|
||||
ctx.r[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
|
||||
ctx.pc = entry_point;
|
||||
ctx.sp = stack_top;
|
||||
ctx.fpcr = 0;
|
||||
ctx.fpsr = 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -223,9 +224,11 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress
|
||||
}
|
||||
|
||||
// Initialize thread context.
|
||||
ResetThreadContext64(m_thread_context_64, GetInteger(user_stack_top), GetInteger(func), arg);
|
||||
ResetThreadContext32(m_thread_context_32, static_cast<u32>(GetInteger(user_stack_top)),
|
||||
static_cast<u32>(GetInteger(func)), static_cast<u32>(arg));
|
||||
if (m_parent != nullptr && !m_parent->Is64Bit()) {
|
||||
ResetThreadContext32(m_thread_context, GetInteger(user_stack_top), GetInteger(func), arg);
|
||||
} else {
|
||||
ResetThreadContext64(m_thread_context, GetInteger(user_stack_top), GetInteger(func), arg);
|
||||
}
|
||||
|
||||
// Setup the stack parameters.
|
||||
StackParameters& sp = this->GetStackParameters();
|
||||
@ -823,20 +826,7 @@ void KThread::CloneFpuStatus() {
|
||||
ASSERT(this->GetOwnerProcess() != nullptr);
|
||||
ASSERT(this->GetOwnerProcess() == GetCurrentProcessPointer(m_kernel));
|
||||
|
||||
if (this->GetOwnerProcess()->Is64Bit()) {
|
||||
// Clone FPSR and FPCR.
|
||||
ThreadContext64 cur_ctx{};
|
||||
m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx);
|
||||
|
||||
this->GetContext64().fpcr = cur_ctx.fpcr;
|
||||
this->GetContext64().fpsr = cur_ctx.fpsr;
|
||||
} else {
|
||||
// Clone FPSCR.
|
||||
ThreadContext32 cur_ctx{};
|
||||
m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx);
|
||||
|
||||
this->GetContext32().fpscr = cur_ctx.fpscr;
|
||||
}
|
||||
m_kernel.CurrentPhysicalCore().CloneFpuStatus(this);
|
||||
}
|
||||
|
||||
Result KThread::SetActivity(Svc::ThreadActivity activity) {
|
||||
@ -912,7 +902,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) {
|
||||
Result KThread::GetThreadContext3(Svc::ThreadContext* out) {
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk{m_activity_pause_lock};
|
||||
|
||||
@ -926,18 +916,16 @@ Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) {
|
||||
|
||||
// If we're not terminating, get the thread's user context.
|
||||
if (!this->IsTerminationRequested()) {
|
||||
*out = m_thread_context;
|
||||
|
||||
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||
constexpr u32 El0Aarch64PsrMask = 0xF0000000;
|
||||
constexpr u32 El0Aarch32PsrMask = 0xFE0FFE20;
|
||||
|
||||
if (m_parent->Is64Bit()) {
|
||||
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||
auto context = GetContext64();
|
||||
context.pstate &= 0xFF0FFE20;
|
||||
out.resize_destructive(sizeof(context));
|
||||
std::memcpy(out.data(), std::addressof(context), sizeof(context));
|
||||
out->pstate &= El0Aarch64PsrMask;
|
||||
} else {
|
||||
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||
auto context = GetContext32();
|
||||
context.cpsr &= 0xFF0FFE20;
|
||||
out.resize_destructive(sizeof(context));
|
||||
std::memcpy(out.data(), std::addressof(context), sizeof(context));
|
||||
out->pstate &= El0Aarch32PsrMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ namespace Core {
|
||||
namespace Memory {
|
||||
class Memory;
|
||||
}
|
||||
class ARM_Interface;
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
@ -137,8 +136,6 @@ public:
|
||||
~KThread() override;
|
||||
|
||||
public:
|
||||
using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
|
||||
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
|
||||
using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType;
|
||||
|
||||
/**
|
||||
@ -246,31 +243,22 @@ public:
|
||||
* @returns The value of the TPIDR_EL0 register.
|
||||
*/
|
||||
u64 GetTpidrEl0() const {
|
||||
return m_thread_context_64.tpidr;
|
||||
return m_thread_context.tpidr;
|
||||
}
|
||||
|
||||
/// Sets the value of the TPIDR_EL0 Read/Write system register for this thread.
|
||||
void SetTpidrEl0(u64 value) {
|
||||
m_thread_context_64.tpidr = value;
|
||||
m_thread_context_32.tpidr = static_cast<u32>(value);
|
||||
m_thread_context.tpidr = value;
|
||||
}
|
||||
|
||||
void CloneFpuStatus();
|
||||
|
||||
ThreadContext32& GetContext32() {
|
||||
return m_thread_context_32;
|
||||
Svc::ThreadContext& GetContext() {
|
||||
return m_thread_context;
|
||||
}
|
||||
|
||||
const ThreadContext32& GetContext32() const {
|
||||
return m_thread_context_32;
|
||||
}
|
||||
|
||||
ThreadContext64& GetContext64() {
|
||||
return m_thread_context_64;
|
||||
}
|
||||
|
||||
const ThreadContext64& GetContext64() const {
|
||||
return m_thread_context_64;
|
||||
const Svc::ThreadContext& GetContext() const {
|
||||
return m_thread_context;
|
||||
}
|
||||
|
||||
std::shared_ptr<Common::Fiber>& GetHostContext();
|
||||
@ -577,7 +565,7 @@ public:
|
||||
|
||||
void RemoveWaiter(KThread* thread);
|
||||
|
||||
Result GetThreadContext3(Common::ScratchBuffer<u8>& out);
|
||||
Result GetThreadContext3(Svc::ThreadContext* out);
|
||||
|
||||
KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) {
|
||||
return this->RemoveWaiterByKey(out_has_waiters, key, false);
|
||||
@ -734,8 +722,7 @@ private:
|
||||
std::function<void()>&& init_func);
|
||||
|
||||
// For core KThread implementation
|
||||
ThreadContext32 m_thread_context_32{};
|
||||
ThreadContext64 m_thread_context_64{};
|
||||
Svc::ThreadContext m_thread_context{};
|
||||
Common::IntrusiveListNode m_process_list_node;
|
||||
Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{};
|
||||
s32 m_priority{};
|
||||
|
@ -99,13 +99,6 @@ struct KernelCore::Impl {
|
||||
RegisterHostThread(nullptr);
|
||||
}
|
||||
|
||||
void InitializeCores() {
|
||||
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||
cores[core_id]->Initialize((*application_process).Is64Bit());
|
||||
system.ApplicationMemory().SetCurrentPageTable(*application_process, core_id);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminateApplicationProcess() {
|
||||
application_process.load()->Terminate();
|
||||
}
|
||||
@ -205,7 +198,7 @@ struct KernelCore::Impl {
|
||||
const s32 core{static_cast<s32>(i)};
|
||||
|
||||
schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
|
||||
cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]);
|
||||
cores[i] = std::make_unique<Kernel::PhysicalCore>(system.Kernel(), i);
|
||||
|
||||
auto* main_thread{Kernel::KThread::Create(system.Kernel())};
|
||||
main_thread->SetCurrentCore(core);
|
||||
@ -880,10 +873,6 @@ void KernelCore::Initialize() {
|
||||
impl->Initialize(*this);
|
||||
}
|
||||
|
||||
void KernelCore::InitializeCores() {
|
||||
impl->InitializeCores();
|
||||
}
|
||||
|
||||
void KernelCore::Shutdown() {
|
||||
impl->Shutdown();
|
||||
}
|
||||
@ -993,21 +982,6 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
|
||||
return *impl->global_object_list_container;
|
||||
}
|
||||
|
||||
void KernelCore::InvalidateAllInstructionCaches() {
|
||||
for (auto& physical_core : impl->cores) {
|
||||
physical_core->ArmInterface().ClearInstructionCache();
|
||||
}
|
||||
}
|
||||
|
||||
void KernelCore::InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size) {
|
||||
for (auto& physical_core : impl->cores) {
|
||||
if (!physical_core->IsInitialized()) {
|
||||
continue;
|
||||
}
|
||||
physical_core->ArmInterface().InvalidateCacheRange(GetInteger(addr), size);
|
||||
}
|
||||
}
|
||||
|
||||
void KernelCore::PrepareReschedule(std::size_t id) {
|
||||
// TODO: Reimplement, this
|
||||
}
|
||||
|
@ -104,9 +104,6 @@ public:
|
||||
/// Resets the kernel to a clean slate for use.
|
||||
void Initialize();
|
||||
|
||||
/// Initializes the CPU cores.
|
||||
void InitializeCores();
|
||||
|
||||
/// Clears all resources in use by the kernel instance.
|
||||
void Shutdown();
|
||||
|
||||
@ -181,10 +178,6 @@ public:
|
||||
|
||||
const KAutoObjectWithListContainer& ObjectListContainer() const;
|
||||
|
||||
void InvalidateAllInstructionCaches();
|
||||
|
||||
void InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size);
|
||||
|
||||
/// Registers all kernel objects with the global emulation state, this is purely for tracking
|
||||
/// leaks after emulation has been shutdown.
|
||||
void RegisterKernelObject(KAutoObject* object);
|
||||
|
@ -1,62 +1,206 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#ifdef HAS_NCE
|
||||
#include "core/arm/nce/arm_nce.h"
|
||||
#endif
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/debugger/debugger.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KScheduler& scheduler)
|
||||
: m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} {
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
|
||||
// an NCE interface or a 32-bit instance of Dynarmic. This should be abstracted out to a CPU
|
||||
// manager.
|
||||
auto& kernel = system.Kernel();
|
||||
m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
|
||||
system, kernel.IsMulticore(),
|
||||
reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
|
||||
m_core_index);
|
||||
#else
|
||||
#error Platform not supported yet.
|
||||
#endif
|
||||
PhysicalCore::PhysicalCore(KernelCore& kernel, std::size_t core_index)
|
||||
: m_kernel{kernel}, m_core_index{core_index} {
|
||||
m_is_single_core = !kernel.IsMulticore();
|
||||
}
|
||||
|
||||
PhysicalCore::~PhysicalCore() = default;
|
||||
|
||||
void PhysicalCore::Initialize(bool is_64_bit) {
|
||||
#if defined(HAS_NCE)
|
||||
if (Settings::IsNceEnabled()) {
|
||||
m_arm_interface = std::make_unique<Core::ARM_NCE>(m_system, m_system.Kernel().IsMulticore(),
|
||||
m_core_index);
|
||||
return;
|
||||
void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
||||
auto* process = thread->GetOwnerProcess();
|
||||
auto& system = m_kernel.System();
|
||||
auto* interface = process->GetArmInterface(m_core_index);
|
||||
|
||||
interface->Initialize();
|
||||
|
||||
const auto EnterContext = [&]() {
|
||||
system.EnterCPUProfile();
|
||||
|
||||
// Lock the core context.
|
||||
std::scoped_lock lk{m_guard};
|
||||
|
||||
// Check if we are already interrupted. If we are, we can just stop immediately.
|
||||
if (m_is_interrupted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark that we are running.
|
||||
m_arm_interface = interface;
|
||||
m_current_thread = thread;
|
||||
|
||||
// Acquire the lock on the thread parameters.
|
||||
// This allows us to force synchronization with Interrupt.
|
||||
interface->LockThread(thread);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto ExitContext = [&]() {
|
||||
// Unlock the thread.
|
||||
interface->UnlockThread(thread);
|
||||
|
||||
// Lock the core context.
|
||||
std::scoped_lock lk{m_guard};
|
||||
|
||||
// On exit, we no longer are running.
|
||||
m_arm_interface = nullptr;
|
||||
m_current_thread = nullptr;
|
||||
|
||||
system.ExitCPUProfile();
|
||||
};
|
||||
|
||||
while (true) {
|
||||
// If the thread is scheduled for termination, exit.
|
||||
if (thread->HasDpc() && thread->IsTerminationRequested()) {
|
||||
thread->Exit();
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep if a step was performed
|
||||
// and this thread has been scheduled again.
|
||||
if (thread->GetStepState() == StepState::StepPerformed) {
|
||||
system.GetDebugger().NotifyThreadStopped(thread);
|
||||
thread->RequestSuspend(SuspendType::Debug);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, run the thread.
|
||||
Core::HaltReason hr{};
|
||||
{
|
||||
// If we were interrupted, exit immediately.
|
||||
if (!EnterContext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->GetStepState() == StepState::StepPending) {
|
||||
hr = interface->StepThread(thread);
|
||||
|
||||
if (True(hr & Core::HaltReason::StepThread)) {
|
||||
thread->SetStepState(StepState::StepPerformed);
|
||||
}
|
||||
} else {
|
||||
hr = interface->RunThread(thread);
|
||||
}
|
||||
|
||||
ExitContext();
|
||||
}
|
||||
|
||||
// Determine why we stopped.
|
||||
const bool supervisor_call = True(hr & Core::HaltReason::SupervisorCall);
|
||||
const bool prefetch_abort = True(hr & Core::HaltReason::PrefetchAbort);
|
||||
const bool breakpoint = True(hr & Core::HaltReason::InstructionBreakpoint);
|
||||
const bool data_abort = True(hr & Core::HaltReason::DataAbort);
|
||||
const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
|
||||
|
||||
// Since scheduling may occur here, we cannot use any cached
|
||||
// state after returning from calls we make.
|
||||
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (breakpoint || prefetch_abort) {
|
||||
if (breakpoint) {
|
||||
interface->RewindBreakpointInstruction();
|
||||
}
|
||||
if (system.DebuggerEnabled()) {
|
||||
system.GetDebugger().NotifyThreadStopped(thread);
|
||||
} else {
|
||||
interface->LogBacktrace(process);
|
||||
}
|
||||
thread->RequestSuspend(SuspendType::Debug);
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep on data abort.
|
||||
if (data_abort) {
|
||||
if (system.DebuggerEnabled()) {
|
||||
system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint());
|
||||
}
|
||||
thread->RequestSuspend(SuspendType::Debug);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle system calls.
|
||||
if (supervisor_call) {
|
||||
// Perform call.
|
||||
Svc::Call(system, interface->GetSvcNumber());
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle external interrupt sources.
|
||||
if (interrupt || !m_is_single_core) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||
auto& kernel = m_system.Kernel();
|
||||
if (!is_64_bit) {
|
||||
// We already initialized a 64-bit core, replace with a 32-bit one.
|
||||
m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
|
||||
m_system, kernel.IsMulticore(),
|
||||
reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
|
||||
m_core_index);
|
||||
}
|
||||
#else
|
||||
#error Platform not supported yet.
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhysicalCore::Run() {
|
||||
m_arm_interface->Run();
|
||||
m_arm_interface->ClearExclusiveState();
|
||||
void PhysicalCore::LoadContext(const KThread* thread) {
|
||||
auto* const process = thread->GetOwnerProcess();
|
||||
if (!process) {
|
||||
// Kernel threads do not run on emulated CPU cores.
|
||||
return;
|
||||
}
|
||||
|
||||
auto* interface = process->GetArmInterface(m_core_index);
|
||||
if (interface) {
|
||||
interface->SetContext(thread->GetContext());
|
||||
interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
|
||||
interface->SetWatchpointArray(&process->GetWatchpoints());
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalCore::LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args) {
|
||||
process.GetArmInterface(m_core_index)->SetSvcArguments(args);
|
||||
}
|
||||
|
||||
void PhysicalCore::SaveContext(KThread* thread) const {
|
||||
auto* const process = thread->GetOwnerProcess();
|
||||
if (!process) {
|
||||
// Kernel threads do not run on emulated CPU cores.
|
||||
return;
|
||||
}
|
||||
|
||||
auto* interface = process->GetArmInterface(m_core_index);
|
||||
if (interface) {
|
||||
interface->GetContext(thread->GetContext());
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalCore::SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const {
|
||||
process.GetArmInterface(m_core_index)->GetSvcArguments(args);
|
||||
}
|
||||
|
||||
void PhysicalCore::CloneFpuStatus(KThread* dst) const {
|
||||
auto* process = dst->GetOwnerProcess();
|
||||
|
||||
Svc::ThreadContext ctx{};
|
||||
process->GetArmInterface(m_core_index)->GetContext(ctx);
|
||||
|
||||
dst->GetContext().fpcr = ctx.fpcr;
|
||||
dst->GetContext().fpsr = ctx.fpsr;
|
||||
}
|
||||
|
||||
void PhysicalCore::LogBacktrace() {
|
||||
auto* process = GetCurrentProcessPointer(m_kernel);
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* interface = process->GetArmInterface(m_core_index);
|
||||
if (interface) {
|
||||
interface->LogBacktrace(process);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalCore::Idle() {
|
||||
@ -69,16 +213,31 @@ bool PhysicalCore::IsInterrupted() const {
|
||||
}
|
||||
|
||||
void PhysicalCore::Interrupt() {
|
||||
std::unique_lock lk{m_guard};
|
||||
// Lock core context.
|
||||
std::scoped_lock lk{m_guard};
|
||||
|
||||
// Load members.
|
||||
auto* arm_interface = m_arm_interface;
|
||||
auto* thread = m_current_thread;
|
||||
|
||||
// Add interrupt flag.
|
||||
m_is_interrupted = true;
|
||||
m_arm_interface->SignalInterrupt();
|
||||
m_on_interrupt.notify_all();
|
||||
|
||||
// Interrupt ourselves.
|
||||
m_on_interrupt.notify_one();
|
||||
|
||||
// If there is no thread running, we are done.
|
||||
if (arm_interface == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Interrupt the CPU.
|
||||
arm_interface->SignalInterrupt(thread);
|
||||
}
|
||||
|
||||
void PhysicalCore::ClearInterrupt() {
|
||||
std::unique_lock lk{m_guard};
|
||||
std::scoped_lock lk{m_guard};
|
||||
m_is_interrupted = false;
|
||||
m_arm_interface->ClearInterrupt();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KScheduler;
|
||||
class KernelCore;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Core {
|
||||
@ -23,62 +23,55 @@ namespace Kernel {
|
||||
|
||||
class PhysicalCore {
|
||||
public:
|
||||
PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_);
|
||||
PhysicalCore(KernelCore& kernel, std::size_t core_index);
|
||||
~PhysicalCore();
|
||||
|
||||
YUZU_NON_COPYABLE(PhysicalCore);
|
||||
YUZU_NON_MOVEABLE(PhysicalCore);
|
||||
|
||||
/// Initialize the core for the specified parameters.
|
||||
void Initialize(bool is_64_bit);
|
||||
// Execute guest code running on the given thread.
|
||||
void RunThread(KThread* thread);
|
||||
|
||||
/// Execute current jit state
|
||||
void Run();
|
||||
// Copy context from thread to current core.
|
||||
void LoadContext(const KThread* thread);
|
||||
void LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args);
|
||||
|
||||
// Copy context from current core to thread.
|
||||
void SaveContext(KThread* thread) const;
|
||||
void SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const;
|
||||
|
||||
// Copy floating point status registers to the target thread.
|
||||
void CloneFpuStatus(KThread* dst) const;
|
||||
|
||||
// Log backtrace of current processor state.
|
||||
void LogBacktrace();
|
||||
|
||||
// Wait for an interrupt.
|
||||
void Idle();
|
||||
|
||||
/// Interrupt this physical core.
|
||||
// Interrupt this core.
|
||||
void Interrupt();
|
||||
|
||||
/// Clear this core's interrupt
|
||||
// Clear this core's interrupt.
|
||||
void ClearInterrupt();
|
||||
|
||||
/// Check if this core is interrupted
|
||||
// Check if this core is interrupted.
|
||||
bool IsInterrupted() const;
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_arm_interface != nullptr;
|
||||
}
|
||||
|
||||
Core::ARM_Interface& ArmInterface() {
|
||||
return *m_arm_interface;
|
||||
}
|
||||
|
||||
const Core::ARM_Interface& ArmInterface() const {
|
||||
return *m_arm_interface;
|
||||
}
|
||||
|
||||
std::size_t CoreIndex() const {
|
||||
return m_core_index;
|
||||
}
|
||||
|
||||
Kernel::KScheduler& Scheduler() {
|
||||
return m_scheduler;
|
||||
}
|
||||
|
||||
const Kernel::KScheduler& Scheduler() const {
|
||||
return m_scheduler;
|
||||
}
|
||||
|
||||
private:
|
||||
KernelCore& m_kernel;
|
||||
const std::size_t m_core_index;
|
||||
Core::System& m_system;
|
||||
Kernel::KScheduler& m_scheduler;
|
||||
|
||||
std::mutex m_guard;
|
||||
std::condition_variable m_on_interrupt;
|
||||
std::unique_ptr<Core::ARM_Interface> m_arm_interface;
|
||||
Core::ArmInterface* m_arm_interface{};
|
||||
KThread* m_current_thread{};
|
||||
bool m_is_interrupted{};
|
||||
bool m_is_single_core{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,8 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/result.h"
|
||||
@ -520,15 +522,15 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen
|
||||
void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
|
||||
|
||||
// Defined in svc_light_ipc.cpp.
|
||||
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
|
||||
void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
|
||||
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args);
|
||||
void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args);
|
||||
|
||||
void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
|
||||
void SvcWrap_SendSyncRequestLight64(Core::System& system);
|
||||
void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args);
|
||||
void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args);
|
||||
|
||||
// Defined in svc_secure_monitor_call.cpp.
|
||||
void SvcWrap_CallSecureMonitor64From32(Core::System& system);
|
||||
void SvcWrap_CallSecureMonitor64(Core::System& system);
|
||||
void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args);
|
||||
void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args);
|
||||
|
||||
// Perform a supervisor call by index.
|
||||
void Call(Core::System& system, u32 imm);
|
||||
|
@ -103,9 +103,7 @@ void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
|
||||
|
||||
handle_debug_buffer(info1, info2);
|
||||
|
||||
auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
|
||||
const auto thread_processor_id = current_thread->GetActiveCore();
|
||||
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
|
||||
system.CurrentPhysicalCore().LogBacktrace();
|
||||
}
|
||||
|
||||
const bool is_hbl = GetCurrentProcess(system.Kernel()).IsHbl();
|
||||
|
@ -37,37 +37,36 @@ Result ReplyAndReceiveLight64From32(Core::System& system, Handle session_handle,
|
||||
// Custom ABI implementation for light IPC.
|
||||
|
||||
template <typename F>
|
||||
static void SvcWrap_LightIpc(Core::System& system, F&& cb) {
|
||||
auto& core = system.CurrentArmInterface();
|
||||
std::array<u32, 7> arguments{};
|
||||
static void SvcWrap_LightIpc(Core::System& system, std::span<uint64_t, 8> args, F&& cb) {
|
||||
std::array<u32, 7> ipc_args{};
|
||||
|
||||
Handle session_handle = static_cast<Handle>(core.GetReg(0));
|
||||
Handle session_handle = static_cast<Handle>(args[0]);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
arguments[i] = static_cast<u32>(core.GetReg(i + 1));
|
||||
ipc_args[i] = static_cast<u32>(args[i + 1]);
|
||||
}
|
||||
|
||||
Result ret = cb(system, session_handle, arguments.data());
|
||||
Result ret = cb(system, session_handle, ipc_args.data());
|
||||
|
||||
core.SetReg(0, ret.raw);
|
||||
args[0] = ret.raw;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
core.SetReg(i + 1, arguments[i]);
|
||||
args[i + 1] = ipc_args[i];
|
||||
}
|
||||
}
|
||||
|
||||
void SvcWrap_SendSyncRequestLight64(Core::System& system) {
|
||||
SvcWrap_LightIpc(system, SendSyncRequestLight64);
|
||||
void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args) {
|
||||
SvcWrap_LightIpc(system, args, SendSyncRequestLight64);
|
||||
}
|
||||
|
||||
void SvcWrap_ReplyAndReceiveLight64(Core::System& system) {
|
||||
SvcWrap_LightIpc(system, ReplyAndReceiveLight64);
|
||||
void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args) {
|
||||
SvcWrap_LightIpc(system, args, ReplyAndReceiveLight64);
|
||||
}
|
||||
|
||||
void SvcWrap_SendSyncRequestLight64From32(Core::System& system) {
|
||||
SvcWrap_LightIpc(system, SendSyncRequestLight64From32);
|
||||
void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args) {
|
||||
SvcWrap_LightIpc(system, args, SendSyncRequestLight64From32);
|
||||
}
|
||||
|
||||
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system) {
|
||||
SvcWrap_LightIpc(system, ReplyAndReceiveLight64From32);
|
||||
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args) {
|
||||
SvcWrap_LightIpc(system, args, ReplyAndReceiveLight64From32);
|
||||
}
|
||||
|
||||
} // namespace Kernel::Svc
|
||||
|
@ -22,31 +22,29 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen
|
||||
|
||||
// Custom ABI for CallSecureMonitor.
|
||||
|
||||
void SvcWrap_CallSecureMonitor64(Core::System& system) {
|
||||
auto& core = system.CurrentPhysicalCore().ArmInterface();
|
||||
lp64::SecureMonitorArguments args{};
|
||||
void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args) {
|
||||
lp64::SecureMonitorArguments smc_args{};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
args.r[i] = core.GetReg(i);
|
||||
smc_args.r[i] = args[i];
|
||||
}
|
||||
|
||||
CallSecureMonitor64(system, std::addressof(args));
|
||||
CallSecureMonitor64(system, std::addressof(smc_args));
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
core.SetReg(i, args.r[i]);
|
||||
args[i] = smc_args.r[i];
|
||||
}
|
||||
}
|
||||
|
||||
void SvcWrap_CallSecureMonitor64From32(Core::System& system) {
|
||||
auto& core = system.CurrentPhysicalCore().ArmInterface();
|
||||
ilp32::SecureMonitorArguments args{};
|
||||
void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args) {
|
||||
ilp32::SecureMonitorArguments smc_args{};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
args.r[i] = static_cast<u32>(core.GetReg(i));
|
||||
smc_args.r[i] = static_cast<u32>(args[i]);
|
||||
}
|
||||
|
||||
CallSecureMonitor64From32(system, std::addressof(args));
|
||||
CallSecureMonitor64From32(system, std::addressof(smc_args));
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
core.SetReg(i, args.r[i]);
|
||||
args[i] = smc_args.r[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,8 +90,6 @@ Result StartThread(Core::System& system, Handle thread_handle) {
|
||||
|
||||
/// Called when a thread exits
|
||||
void ExitThread(Core::System& system) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
|
||||
|
||||
auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
|
||||
system.GlobalSchedulerContext().RemoveThread(current_thread);
|
||||
current_thread->Exit();
|
||||
@ -147,47 +145,19 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha
|
||||
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Require the handle be to a non-current thread in the current process.
|
||||
const auto* current_process = GetCurrentProcessPointer(kernel);
|
||||
R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
|
||||
R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(kernel), ResultInvalidHandle);
|
||||
R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultBusy);
|
||||
|
||||
// Verify that the thread isn't terminated.
|
||||
R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
|
||||
// Get the thread context.
|
||||
Svc::ThreadContext context{};
|
||||
R_TRY(thread->GetThreadContext3(std::addressof(context)));
|
||||
|
||||
/// Check that the thread is not the current one.
|
||||
/// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
|
||||
R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
|
||||
// Copy the thread context to user space.
|
||||
R_UNLESS(
|
||||
GetCurrentMemory(kernel).WriteBlock(out_context, std::addressof(context), sizeof(context)),
|
||||
ResultInvalidPointer);
|
||||
|
||||
// Try to get the thread context until the thread isn't current on any core.
|
||||
while (true) {
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
// TODO(bunnei): Enforce that thread is suspended for debug here.
|
||||
|
||||
// If the thread's raw state isn't runnable, check if it's current on some core.
|
||||
if (thread->GetRawState() != ThreadState::Runnable) {
|
||||
bool current = false;
|
||||
for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
|
||||
if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) {
|
||||
current = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the thread is current, retry until it isn't.
|
||||
if (current) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the thread context.
|
||||
static thread_local Common::ScratchBuffer<u8> context;
|
||||
R_TRY(thread->GetThreadContext3(context));
|
||||
|
||||
// Copy the thread context to user space.
|
||||
GetCurrentMemory(kernel).WriteBlock(out_context, context.data(), context.size());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/// Gets the priority for the specified thread
|
||||
|
@ -374,11 +374,11 @@ def get_registers(parse_result, bitness):
|
||||
|
||||
# Collects possibly multiple source registers into the named C++ value.
|
||||
def emit_gather(sources, name, type_name, reg_size):
|
||||
get_fn = f"GetReg{reg_size*8}"
|
||||
get_fn = f"GetArg{reg_size*8}"
|
||||
|
||||
if len(sources) == 1:
|
||||
s, = sources
|
||||
line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));"
|
||||
line = f"{name} = Convert<{type_name}>({get_fn}(args, {s}));"
|
||||
return [line]
|
||||
|
||||
var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
|
||||
@ -387,7 +387,7 @@ def emit_gather(sources, name, type_name, reg_size):
|
||||
]
|
||||
for i in range(0, len(sources)):
|
||||
lines.append(
|
||||
f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});")
|
||||
f"{name}_gather[{i}] = {get_fn}(args, {sources[i]});")
|
||||
|
||||
lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
|
||||
return lines
|
||||
@ -396,12 +396,12 @@ def emit_gather(sources, name, type_name, reg_size):
|
||||
# Produces one or more statements which assign the named C++ value
|
||||
# into possibly multiple registers.
|
||||
def emit_scatter(destinations, name, reg_size):
|
||||
set_fn = f"SetReg{reg_size*8}"
|
||||
set_fn = f"SetArg{reg_size*8}"
|
||||
reg_type = f"uint{reg_size*8}_t"
|
||||
|
||||
if len(destinations) == 1:
|
||||
d, = destinations
|
||||
line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));"
|
||||
line = f"{set_fn}(args, {d}, Convert<{reg_type}>({name}));"
|
||||
return [line]
|
||||
|
||||
var_type = f"std::array<{reg_type}, {len(destinations)}>"
|
||||
@ -411,7 +411,7 @@ def emit_scatter(destinations, name, reg_size):
|
||||
|
||||
for i in range(0, len(destinations)):
|
||||
lines.append(
|
||||
f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);")
|
||||
f"{set_fn}(args, {destinations[i]}, {name}_scatter[{i}]);")
|
||||
|
||||
return lines
|
||||
|
||||
@ -433,7 +433,7 @@ def emit_lines(lines, indent=' '):
|
||||
def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
|
||||
return_write, output_writes, input_reads = register_info
|
||||
lines = [
|
||||
f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{"
|
||||
f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system, std::span<uint64_t, 8> args) {{"
|
||||
]
|
||||
|
||||
# Get everything ready.
|
||||
@ -498,6 +498,8 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/result.h"
|
||||
@ -524,15 +526,15 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen
|
||||
void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
|
||||
|
||||
// Defined in svc_light_ipc.cpp.
|
||||
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
|
||||
void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
|
||||
void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args);
|
||||
void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args);
|
||||
|
||||
void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
|
||||
void SvcWrap_SendSyncRequestLight64(Core::System& system);
|
||||
void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args);
|
||||
void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args);
|
||||
|
||||
// Defined in svc_secure_monitor_call.cpp.
|
||||
void SvcWrap_CallSecureMonitor64From32(Core::System& system);
|
||||
void SvcWrap_CallSecureMonitor64(Core::System& system);
|
||||
void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args);
|
||||
void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args);
|
||||
|
||||
// Perform a supervisor call by index.
|
||||
void Call(Core::System& system, u32 imm);
|
||||
@ -550,20 +552,20 @@ PROLOGUE_CPP = """
|
||||
|
||||
namespace Kernel::Svc {
|
||||
|
||||
static uint32_t GetReg32(Core::System& system, int n) {
|
||||
return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n));
|
||||
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
|
||||
return static_cast<uint32_t>(args[n]);
|
||||
}
|
||||
|
||||
static void SetReg32(Core::System& system, int n, uint32_t result) {
|
||||
system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result));
|
||||
static void SetArg32(std::span<uint64_t, 8> args, int n, uint32_t result) {
|
||||
args[n] = result;
|
||||
}
|
||||
|
||||
static uint64_t GetReg64(Core::System& system, int n) {
|
||||
return system.CurrentArmInterface().GetReg(n);
|
||||
static uint64_t GetArg64(std::span<uint64_t, 8> args, int n) {
|
||||
return args[n];
|
||||
}
|
||||
|
||||
static void SetReg64(Core::System& system, int n, uint64_t result) {
|
||||
system.CurrentArmInterface().SetReg(n, result);
|
||||
static void SetArg64(std::span<uint64_t, 8> args, int n, uint64_t result) {
|
||||
args[n] = result;
|
||||
}
|
||||
|
||||
// Like bit_cast, but handles the case when the source and dest
|
||||
@ -590,15 +592,20 @@ EPILOGUE_CPP = """
|
||||
|
||||
void Call(Core::System& system, u32 imm) {
|
||||
auto& kernel = system.Kernel();
|
||||
auto& process = GetCurrentProcess(kernel);
|
||||
|
||||
std::array<uint64_t, 8> args;
|
||||
kernel.CurrentPhysicalCore().SaveSvcArguments(process, args);
|
||||
kernel.EnterSVCProfile();
|
||||
|
||||
if (GetCurrentProcess(system.Kernel()).Is64Bit()) {
|
||||
Call64(system, imm);
|
||||
if (process.Is64Bit()) {
|
||||
Call64(system, imm, args);
|
||||
} else {
|
||||
Call32(system, imm);
|
||||
Call32(system, imm, args);
|
||||
}
|
||||
|
||||
kernel.ExitSVCProfile();
|
||||
kernel.CurrentPhysicalCore().LoadSvcArguments(process, args);
|
||||
}
|
||||
|
||||
} // namespace Kernel::Svc
|
||||
@ -609,13 +616,13 @@ def emit_call(bitness, names, suffix):
|
||||
bit_size = REG_SIZES[bitness]*8
|
||||
indent = " "
|
||||
lines = [
|
||||
f"static void Call{bit_size}(Core::System& system, u32 imm) {{",
|
||||
f"static void Call{bit_size}(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {{",
|
||||
f"{indent}switch (static_cast<SvcId>(imm)) {{"
|
||||
]
|
||||
|
||||
for _, name in names:
|
||||
lines.append(f"{indent}case SvcId::{name}:")
|
||||
lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);")
|
||||
lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system, args);")
|
||||
|
||||
lines.append(f"{indent}default:")
|
||||
lines.append(
|
||||
|
Reference in New Issue
Block a user