diff options
author | bunnei <bunneidev@gmail.com> | 2021-01-30 08:06:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-30 08:06:40 +0100 |
commit | a4526c4e1acb50808bbe205952101142288e1c60 (patch) | |
tree | 7109edf89606c43352da9de40d0e3a920a08b659 /src/core/hle/kernel/svc.cpp | |
parent | Merge pull request #5795 from ReinUsesLisp/bytes-to-map-end (diff) | |
parent | hle: kernel: KLightLock: Fix several bugs. (diff) | |
download | yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar.gz yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar.bz2 yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar.lz yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar.xz yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar.zst yuzu-a4526c4e1acb50808bbe205952101142288e1c60.zip |
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 439 |
1 files changed, 187 insertions, 252 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index cc8b661af..7fd514e9d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -29,6 +29,7 @@ #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/memory_layout.h" @@ -42,7 +43,6 @@ #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_types.h" #include "core/hle/kernel/svc_wrap.h" -#include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" @@ -351,7 +351,8 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); } - return thread->GetSignalingResult(); + KSynchronizationObject* dummy{}; + return thread->GetWaitResult(std::addressof(dummy)); } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { @@ -359,27 +360,26 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { } /// Get the ID for the specified thread. -static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) { +static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); + // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); - return ERR_INVALID_HANDLE; - } + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - *thread_id = thread->GetThreadID(); + // Get the thread's id. + *out_thread_id = thread->GetThreadID(); return RESULT_SUCCESS; } -static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high, - Handle thread_handle) { - u64 thread_id{}; - const ResultCode result{GetThreadId(system, &thread_id, thread_handle)}; +static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, + u32* out_thread_id_high, Handle thread_handle) { + u64 out_thread_id{}; + const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)}; - *thread_id_low = static_cast<u32>(thread_id >> 32); - *thread_id_high = static_cast<u32>(thread_id & std::numeric_limits<u32>::max()); + *out_thread_id_low = static_cast<u32>(out_thread_id >> 32); + *out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max()); return result; } @@ -395,7 +395,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return RESULT_SUCCESS; } - const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); if (thread) { const Process* const owner_process = thread->GetOwnerProcess(); if (!owner_process) { @@ -473,15 +473,13 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); + // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", - thread_handle); - return ERR_INVALID_HANDLE; - } + std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - thread->CancelWait(); + // Cancel the thread's wait. + thread->WaitCancel(); return RESULT_SUCCESS; } @@ -630,7 +628,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { handle_debug_buffer(info1, info2); auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); - const auto thread_processor_id = current_thread->GetProcessorID(); + const auto thread_processor_id = current_thread->GetActiveCore(); system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); } } @@ -872,7 +870,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ERR_INVALID_COMBINATION; } - const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>( + const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( static_cast<Handle>(handle)); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", @@ -888,7 +886,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); u64 out_ticks = 0; if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { - const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); + const u64 thread_ticks = current_thread->GetCpuTime(); out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { @@ -1025,129 +1023,109 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size return UnmapPhysicalMemory(system, addr, size); } -/// Sets the thread activity -static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); - if (activity > static_cast<u32>(ThreadActivity::Paused)) { - return ERR_INVALID_ENUM_VALUE; +constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) { + switch (thread_activity) { + case Svc::ThreadActivity::Runnable: + case Svc::ThreadActivity::Paused: + return true; + default: + return false; } +} - const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); - return ERR_INVALID_HANDLE; - } +/// Sets the thread activity +static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, + Svc::ThreadActivity thread_activity) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, + thread_activity); - if (thread->GetOwnerProcess() != current_process) { - LOG_ERROR(Kernel_SVC, - "The current process does not own the current thread, thread_handle={:08X} " - "thread_pid={}, " - "current_process_pid={}", - handle, thread->GetOwnerProcess()->GetProcessID(), - current_process->GetProcessID()); - return ERR_INVALID_HANDLE; - } + // Validate the activity. + R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); - if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { - LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); - return ERR_BUSY; - } + // Get the thread from its handle. + auto& kernel = system.Kernel(); + const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); + + // Check that the activity is being set on a non-current thread for the current process. + R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); + R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); + + // Set the activity. + R_TRY(thread->SetActivity(thread_activity)); - return thread->SetActivity(static_cast<ThreadActivity>(activity)); + return RESULT_SUCCESS; } -static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { - return SetThreadActivity(system, handle, activity); +static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle, + Svc::ThreadActivity thread_activity) { + return SetThreadActivity(system, thread_handle, thread_activity); } /// Gets the thread context -static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { - LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); +static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) { + LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, + thread_handle); + // Get the thread from its handle. const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); - return ERR_INVALID_HANDLE; - } + const std::shared_ptr<KThread> thread = + current_process->GetHandleTable().Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - if (thread->GetOwnerProcess() != current_process) { - LOG_ERROR(Kernel_SVC, - "The current process does not own the current thread, thread_handle={:08X} " - "thread_pid={}, " - "current_process_pid={}", - handle, thread->GetOwnerProcess()->GetProcessID(), - current_process->GetProcessID()); - return ERR_INVALID_HANDLE; - } + // Require the handle be to a non-current thread in the current process. + R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); + R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), + Svc::ResultBusy); - if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { - LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); - return ERR_BUSY; - } - - Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64(); - // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. - ctx.pstate &= 0xFF0FFE20; + // Get the thread context. + std::vector<u8> context; + R_TRY(thread->GetThreadContext3(context)); - // If 64-bit, we can just write the context registers directly and we're good. - // However, if 32-bit, we have to ensure some registers are zeroed out. - if (!current_process->Is64BitProcess()) { - std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0); - std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); - } + // Copy the thread context to user space. + system.Memory().WriteBlock(out_context, context.data(), context.size()); - system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx)); return RESULT_SUCCESS; } -static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { - return GetThreadContext(system, thread_context, handle); +static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) { + return GetThreadContext(system, out_context, thread_handle); } /// Gets the priority for the specified thread -static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { +static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) { LOG_TRACE(Kernel_SVC, "called"); + // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); - if (!thread) { - *priority = 0; - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); - return ERR_INVALID_HANDLE; - } + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - *priority = thread->GetPriority(); + // Get the thread's priority. + *out_priority = thread->GetPriority(); return RESULT_SUCCESS; } -static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) { - return GetThreadPriority(system, priority, handle); +static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) { + return GetThreadPriority(system, out_priority, handle); } /// Sets the priority for the specified thread static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { LOG_TRACE(Kernel_SVC, "called"); - if (priority > THREADPRIO_LOWEST) { - LOG_ERROR( - Kernel_SVC, - "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}", - THREADPRIO_LOWEST, priority, handle); - return ERR_INVALID_THREAD_PRIORITY; - } + // Validate the priority. + R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, + Svc::ResultInvalidPriority); - const auto* const current_process = system.Kernel().CurrentProcess(); - - std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); - return ERR_INVALID_HANDLE; - } + // Get the thread from its handle. + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); + // Set the thread priority. thread->SetBasePriority(priority); - return RESULT_SUCCESS; } @@ -1438,62 +1416,50 @@ static void ExitProcess(Core::System& system) { current_process->PrepareForTermination(); // Kill the current thread - system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop(); + system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit(); } static void ExitProcess32(Core::System& system) { ExitProcess(system); } +static constexpr bool IsValidCoreId(int32_t core_id) { + return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); +} + /// Creates a new thread static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, - VAddr stack_top, u32 priority, s32 processor_id) { + VAddr stack_bottom, u32 priority, s32 core_id) { LOG_DEBUG(Kernel_SVC, - "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, " - "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", - entry_point, arg, stack_top, priority, processor_id, *out_handle); + "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, " + "priority=0x{:08X}, core_id=0x{:08X}", + entry_point, arg, stack_bottom, priority, core_id); - auto* const current_process = system.Kernel().CurrentProcess(); - - if (processor_id == THREADPROCESSORID_IDEAL) { - // Set the target CPU to the one specified by the process. - processor_id = current_process->GetIdealCore(); - ASSERT(processor_id != THREADPROCESSORID_IDEAL); + // Adjust core id, if it's the default magic. + auto& kernel = system.Kernel(); + auto& process = *kernel.CurrentProcess(); + if (core_id == Svc::IdealCoreUseProcessValue) { + core_id = process.GetIdealCoreId(); } - if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) { - LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); - return ERR_INVALID_PROCESSOR_ID; - } + // Validate arguments. + R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); + R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); - const u64 core_mask = current_process->GetCoreMask(); - if ((core_mask | (1ULL << processor_id)) != core_mask) { - LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id); - return ERR_INVALID_PROCESSOR_ID; - } + R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, + Svc::ResultInvalidPriority); + R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); - if (priority > THREADPRIO_LOWEST) { - LOG_ERROR(Kernel_SVC, - "Invalid thread priority specified ({}). Must be within the range 0-64", - priority); - return ERR_INVALID_THREAD_PRIORITY; - } + ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1)); - if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) { - LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority); - return ERR_INVALID_THREAD_PRIORITY; + std::shared_ptr<KThread> thread; + { + KScopedLightLock lk{process.GetStateLock()}; + CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority, + arg, core_id, stack_bottom, &process)); } - auto& kernel = system.Kernel(); - - ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1)); - - ThreadType type = THREADTYPE_USER; - CASCADE_RESULT(std::shared_ptr<Thread> thread, - Thread::Create(system, type, "", entry_point, priority, arg, processor_id, - stack_top, current_process)); - - const auto new_thread_handle = current_process->GetHandleTable().Create(thread); + const auto new_thread_handle = process.GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", new_thread_handle.Code().raw); @@ -1517,17 +1483,15 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); + // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", - thread_handle); - return ERR_INVALID_HANDLE; - } + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - ASSERT(thread->GetState() == ThreadState::Initialized); + // Try to start the thread. + R_TRY(thread->Run()); - return thread->Start(); + return RESULT_SUCCESS; } static ResultCode StartThread32(Core::System& system, Handle thread_handle) { @@ -1540,7 +1504,7 @@ static void ExitThread(Core::System& system) { auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); - current_thread->Stop(); + current_thread->Exit(); } static void ExitThread32(Core::System& system) { @@ -1549,34 +1513,28 @@ static void ExitThread32(Core::System& system) { /// Sleep the current thread static void SleepThread(Core::System& system, s64 nanoseconds) { - LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); + auto& kernel = system.Kernel(); + const auto yield_type = static_cast<Svc::YieldType>(nanoseconds); - enum class SleepType : s64 { - YieldWithoutCoreMigration = 0, - YieldWithCoreMigration = -1, - YieldAndWaitForLoadBalancing = -2, - }; + LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); - auto& scheduler = *system.Kernel().CurrentScheduler(); - if (nanoseconds <= 0) { - switch (static_cast<SleepType>(nanoseconds)) { - case SleepType::YieldWithoutCoreMigration: { - scheduler.YieldWithoutCoreMigration(); - break; - } - case SleepType::YieldWithCoreMigration: { - scheduler.YieldWithCoreMigration(); - break; - } - case SleepType::YieldAndWaitForLoadBalancing: { - scheduler.YieldToAnyThread(); - break; - } - default: - UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); - } + // When the input tick is positive, sleep. + if (nanoseconds > 0) { + // Convert the timeout from nanoseconds to ticks. + // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... + + // Sleep. + // NOTE: Nintendo does not check the result of this sleep. + static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds)); + } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { + KScheduler::YieldWithoutCoreMigration(kernel); + } else if (yield_type == Svc::YieldType::WithCoreMigration) { + KScheduler::YieldWithCoreMigration(kernel); + } else if (yield_type == Svc::YieldType::ToAnyThread) { + KScheduler::YieldToAnyThread(kernel); } else { - scheduler.GetCurrentThread()->Sleep(nanoseconds); + // Nintendo does nothing at all if an otherwise invalid value is passed. + UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); } } @@ -1839,95 +1797,72 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u return CreateTransferMemory(system, handle, addr, size, permissions); } -static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, - u64* mask) { +static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, + u64* out_affinity_mask) { LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); + // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", - thread_handle); - *core = 0; - *mask = 0; - return ERR_INVALID_HANDLE; - } + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - *core = thread->GetIdealCore(); - *mask = thread->GetAffinityMask().GetAffinityMask(); + // Get the core mask. + R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); return RESULT_SUCCESS; } -static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, - u32* mask_low, u32* mask_high) { - u64 mask{}; - const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); - *mask_high = static_cast<u32>(mask >> 32); - *mask_low = static_cast<u32>(mask); +static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id, + u32* out_affinity_mask_low, u32* out_affinity_mask_high) { + u64 out_affinity_mask{}; + const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask); + *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32); + *out_affinity_mask_low = static_cast<u32>(out_affinity_mask); return result; } -static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, +static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, 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* const current_process = system.Kernel().CurrentProcess(); + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", + thread_handle, core_id, affinity_mask); - if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) { - const u8 ideal_cpu_core = current_process->GetIdealCore(); + const auto& current_process = *system.Kernel().CurrentProcess(); - ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL)); - - // Set the target CPU to the ideal core specified by the process. - core = ideal_cpu_core; - affinity_mask = 1ULL << core; + // Determine the core id/affinity mask. + if (core_id == Svc::IdealCoreUseProcessValue) { + core_id = current_process.GetIdealCoreId(); + affinity_mask = (1ULL << core_id); } 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::Hardware::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<u32>(THREADPROCESSORID_DONT_CARE) && - core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) { - LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core); - return ERR_INVALID_PROCESSOR_ID; + // Validate the affinity mask. + const u64 process_core_mask = current_process.GetCoreMask(); + R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, + Svc::ResultInvalidCoreId); + R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); + + // Validate the core id. + if (IsValidCoreId(core_id)) { + R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); + } else { + R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, + Svc::ResultInvalidCoreId); } } - const auto& handle_table = current_process->GetHandleTable(); - const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", - thread_handle); - return ERR_INVALID_HANDLE; - } + // Get the thread from its handle. + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); + R_UNLESS(thread, Svc::ResultInvalidHandle); - return thread->SetCoreAndAffinityMask(core, affinity_mask); + // Set the core mask. + R_TRY(thread->SetCoreMask(core_id, affinity_mask)); + + return RESULT_SUCCESS; } -static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, +static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id, u32 affinity_mask_low, u32 affinity_mask_high) { const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); - return SetThreadCoreMask(system, thread_handle, core, affinity_mask); + return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask); } static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { @@ -2491,7 +2426,7 @@ void Call(Core::System& system, u32 immediate) { kernel.EnterSVCProfile(); auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); - thread->SetContinuousOnSVC(true); + thread->SetIsCallingSvc(); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2507,7 +2442,7 @@ void Call(Core::System& system, u32 immediate) { kernel.ExitSVCProfile(); - if (!thread->IsContinuousOnSVC()) { + if (!thread->IsCallingSvc()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } |