From d672c6e759c560dbeff04c1b92ce46bb7a2f8ed8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 15 Apr 2019 20:34:55 -0400 Subject: [PATCH] kernel/svc: Reorganize svcSetThreadCoreMask() Makes the code much nicer to follow in terms of behavior and control flow. It also fixes a few bugs in the implementation. Notably, the thread's owner process shouldn't be accessed in order to retrieve the core mask or ideal core. This should be done through the current running process. The only reason this bug wasn't encountered yet is because we currently only support running one process, and thus every owner process will be the current process. We also weren't checking against the process' CPU core mask to see if an allowed core is specified or not. With this out of the way, it'll be less noisy to implement proper handling of the affinity flags internally within the kernel thread instances. --- src/core/hle/kernel/svc.cpp | 83 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bb12f9ac7c..5ed00d451f 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1744,11 +1744,51 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, } static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, - u64 mask) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle, - mask, core); + u64 affinity_mask) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", + thread_handle, core, affinity_mask); - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + const auto* const current_process = system.Kernel().CurrentProcess(); + + if (core == static_cast(THREADPROCESSORID_IDEAL)) { + const u8 ideal_cpu_core = current_process->GetIdealCore(); + + ASSERT(ideal_cpu_core != static_cast(THREADPROCESSORID_IDEAL)); + + // Set the target CPU to the ideal core specified by the process. + core = ideal_cpu_core; + affinity_mask = 1ULL << core; + } else { + const u64 core_mask = current_process->GetCoreMask(); + + if ((core_mask | affinity_mask) != core_mask) { + LOG_ERROR( + Kernel_SVC, + "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})", + core_mask, affinity_mask); + return ERR_INVALID_PROCESSOR_ID; + } + + if (affinity_mask == 0) { + LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero."); + return ERR_INVALID_COMBINATION; + } + + if (core < Core::NUM_CPU_CORES) { + if ((affinity_mask & (1ULL << core)) == 0) { + LOG_ERROR(Kernel_SVC, + "Core is not enabled for the current mask, core={}, mask={:016X}", core, + affinity_mask); + return ERR_INVALID_COMBINATION; + } + } else if (core != static_cast(THREADPROCESSORID_DONT_CARE) && + core != static_cast(THREADPROCESSORID_DONT_UPDATE)) { + LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core); + return ERR_INVALID_PROCESSOR_ID; + } + } + + const auto& handle_table = current_process->GetHandleTable(); const SharedPtr thread = handle_table.Get(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", @@ -1756,40 +1796,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_HANDLE; } - if (core == static_cast(THREADPROCESSORID_IDEAL)) { - const u8 ideal_cpu_core = thread->GetOwnerProcess()->GetIdealCore(); - - ASSERT(ideal_cpu_core != static_cast(THREADPROCESSORID_IDEAL)); - - // Set the target CPU to the ideal core specified by the process. - core = ideal_cpu_core; - mask = 1ULL << core; - } - - if (mask == 0) { - LOG_ERROR(Kernel_SVC, "Mask is 0"); - return ERR_INVALID_COMBINATION; - } - - /// This value is used to only change the affinity mask without changing the current ideal core. - static constexpr u32 OnlyChangeMask = static_cast(-3); - - if (core == OnlyChangeMask) { - core = thread->GetIdealCore(); - } else if (core >= Core::NUM_CPU_CORES && core != static_cast(THREADPROCESSORID_DONT_UPDATE)) { - LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core); - return ERR_INVALID_PROCESSOR_ID; - } - - // Error out if the input core isn't enabled in the input mask. - if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { - LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", - core, mask); - return ERR_INVALID_COMBINATION; - } - - thread->ChangeCore(core, mask); - + thread->ChangeCore(core, affinity_mask); return RESULT_SUCCESS; }