diff options
| author | 2021-01-29 23:06:40 -0800 | |
|---|---|---|
| committer | 2021-01-29 23:06:40 -0800 | |
| 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.gz yuzu-a4526c4e1acb50808bbe205952101142288e1c60.tar.xz yuzu-a4526c4e1acb50808bbe205952101142288e1c60.zip | |
Merge pull request #5779 from bunnei/kthread-rewrite
Rewrite KThread to be more accurate
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -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 @@ | |||
| 29 | #include "core/hle/kernel/k_scheduler.h" | 29 | #include "core/hle/kernel/k_scheduler.h" |
| 30 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 30 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 31 | #include "core/hle/kernel/k_synchronization_object.h" | 31 | #include "core/hle/kernel/k_synchronization_object.h" |
| 32 | #include "core/hle/kernel/k_thread.h" | ||
| 32 | #include "core/hle/kernel/kernel.h" | 33 | #include "core/hle/kernel/kernel.h" |
| 33 | #include "core/hle/kernel/memory/memory_block.h" | 34 | #include "core/hle/kernel/memory/memory_block.h" |
| 34 | #include "core/hle/kernel/memory/memory_layout.h" | 35 | #include "core/hle/kernel/memory/memory_layout.h" |
| @@ -42,7 +43,6 @@ | |||
| 42 | #include "core/hle/kernel/svc_results.h" | 43 | #include "core/hle/kernel/svc_results.h" |
| 43 | #include "core/hle/kernel/svc_types.h" | 44 | #include "core/hle/kernel/svc_types.h" |
| 44 | #include "core/hle/kernel/svc_wrap.h" | 45 | #include "core/hle/kernel/svc_wrap.h" |
| 45 | #include "core/hle/kernel/thread.h" | ||
| 46 | #include "core/hle/kernel/time_manager.h" | 46 | #include "core/hle/kernel/time_manager.h" |
| 47 | #include "core/hle/kernel/transfer_memory.h" | 47 | #include "core/hle/kernel/transfer_memory.h" |
| 48 | #include "core/hle/kernel/writable_event.h" | 48 | #include "core/hle/kernel/writable_event.h" |
| @@ -351,7 +351,8 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 351 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); | 351 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | return thread->GetSignalingResult(); | 354 | KSynchronizationObject* dummy{}; |
| 355 | return thread->GetWaitResult(std::addressof(dummy)); | ||
| 355 | } | 356 | } |
| 356 | 357 | ||
| 357 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | 358 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { |
| @@ -359,27 +360,26 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | |||
| 359 | } | 360 | } |
| 360 | 361 | ||
| 361 | /// Get the ID for the specified thread. | 362 | /// Get the ID for the specified thread. |
| 362 | static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) { | 363 | static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { |
| 363 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 364 | LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 364 | 365 | ||
| 366 | // Get the thread from its handle. | ||
| 365 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 367 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 366 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 368 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 367 | if (!thread) { | 369 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 368 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); | ||
| 369 | return ERR_INVALID_HANDLE; | ||
| 370 | } | ||
| 371 | 370 | ||
| 372 | *thread_id = thread->GetThreadID(); | 371 | // Get the thread's id. |
| 372 | *out_thread_id = thread->GetThreadID(); | ||
| 373 | return RESULT_SUCCESS; | 373 | return RESULT_SUCCESS; |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high, | 376 | static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, |
| 377 | Handle thread_handle) { | 377 | u32* out_thread_id_high, Handle thread_handle) { |
| 378 | u64 thread_id{}; | 378 | u64 out_thread_id{}; |
| 379 | const ResultCode result{GetThreadId(system, &thread_id, thread_handle)}; | 379 | const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)}; |
| 380 | 380 | ||
| 381 | *thread_id_low = static_cast<u32>(thread_id >> 32); | 381 | *out_thread_id_low = static_cast<u32>(out_thread_id >> 32); |
| 382 | *thread_id_high = static_cast<u32>(thread_id & std::numeric_limits<u32>::max()); | 382 | *out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max()); |
| 383 | 383 | ||
| 384 | return result; | 384 | return result; |
| 385 | } | 385 | } |
| @@ -395,7 +395,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han | |||
| 395 | return RESULT_SUCCESS; | 395 | return RESULT_SUCCESS; |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); | 398 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 399 | if (thread) { | 399 | if (thread) { |
| 400 | const Process* const owner_process = thread->GetOwnerProcess(); | 400 | const Process* const owner_process = thread->GetOwnerProcess(); |
| 401 | if (!owner_process) { | 401 | if (!owner_process) { |
| @@ -473,15 +473,13 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u | |||
| 473 | static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { | 473 | static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { |
| 474 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); | 474 | LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); |
| 475 | 475 | ||
| 476 | // Get the thread from its handle. | ||
| 476 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 477 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 477 | std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 478 | std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 478 | if (!thread) { | 479 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 479 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 480 | thread_handle); | ||
| 481 | return ERR_INVALID_HANDLE; | ||
| 482 | } | ||
| 483 | 480 | ||
| 484 | thread->CancelWait(); | 481 | // Cancel the thread's wait. |
| 482 | thread->WaitCancel(); | ||
| 485 | return RESULT_SUCCESS; | 483 | return RESULT_SUCCESS; |
| 486 | } | 484 | } |
| 487 | 485 | ||
| @@ -630,7 +628,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { | |||
| 630 | handle_debug_buffer(info1, info2); | 628 | handle_debug_buffer(info1, info2); |
| 631 | 629 | ||
| 632 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 630 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 633 | const auto thread_processor_id = current_thread->GetProcessorID(); | 631 | const auto thread_processor_id = current_thread->GetActiveCore(); |
| 634 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); | 632 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); |
| 635 | } | 633 | } |
| 636 | } | 634 | } |
| @@ -872,7 +870,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 872 | return ERR_INVALID_COMBINATION; | 870 | return ERR_INVALID_COMBINATION; |
| 873 | } | 871 | } |
| 874 | 872 | ||
| 875 | const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>( | 873 | const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( |
| 876 | static_cast<Handle>(handle)); | 874 | static_cast<Handle>(handle)); |
| 877 | if (!thread) { | 875 | if (!thread) { |
| 878 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", | 876 | 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 | |||
| 888 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); | 886 | const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); |
| 889 | u64 out_ticks = 0; | 887 | u64 out_ticks = 0; |
| 890 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { | 888 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { |
| 891 | const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); | 889 | const u64 thread_ticks = current_thread->GetCpuTime(); |
| 892 | 890 | ||
| 893 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); | 891 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); |
| 894 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { | 892 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { |
| @@ -1025,129 +1023,109 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size | |||
| 1025 | return UnmapPhysicalMemory(system, addr, size); | 1023 | return UnmapPhysicalMemory(system, addr, size); |
| 1026 | } | 1024 | } |
| 1027 | 1025 | ||
| 1028 | /// Sets the thread activity | 1026 | constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) { |
| 1029 | static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { | 1027 | switch (thread_activity) { |
| 1030 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); | 1028 | case Svc::ThreadActivity::Runnable: |
| 1031 | if (activity > static_cast<u32>(ThreadActivity::Paused)) { | 1029 | case Svc::ThreadActivity::Paused: |
| 1032 | return ERR_INVALID_ENUM_VALUE; | 1030 | return true; |
| 1031 | default: | ||
| 1032 | return false; | ||
| 1033 | } | 1033 | } |
| 1034 | } | ||
| 1034 | 1035 | ||
| 1035 | const auto* current_process = system.Kernel().CurrentProcess(); | 1036 | /// Sets the thread activity |
| 1036 | const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 1037 | static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, |
| 1037 | if (!thread) { | 1038 | Svc::ThreadActivity thread_activity) { |
| 1038 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1039 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, |
| 1039 | return ERR_INVALID_HANDLE; | 1040 | thread_activity); |
| 1040 | } | ||
| 1041 | 1041 | ||
| 1042 | if (thread->GetOwnerProcess() != current_process) { | 1042 | // Validate the activity. |
| 1043 | LOG_ERROR(Kernel_SVC, | 1043 | R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); |
| 1044 | "The current process does not own the current thread, thread_handle={:08X} " | ||
| 1045 | "thread_pid={}, " | ||
| 1046 | "current_process_pid={}", | ||
| 1047 | handle, thread->GetOwnerProcess()->GetProcessID(), | ||
| 1048 | current_process->GetProcessID()); | ||
| 1049 | return ERR_INVALID_HANDLE; | ||
| 1050 | } | ||
| 1051 | 1044 | ||
| 1052 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | 1045 | // Get the thread from its handle. |
| 1053 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | 1046 | auto& kernel = system.Kernel(); |
| 1054 | return ERR_BUSY; | 1047 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 1055 | } | 1048 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1049 | R_UNLESS(thread, Svc::ResultInvalidHandle); | ||
| 1050 | |||
| 1051 | // Check that the activity is being set on a non-current thread for the current process. | ||
| 1052 | R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); | ||
| 1053 | R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); | ||
| 1054 | |||
| 1055 | // Set the activity. | ||
| 1056 | R_TRY(thread->SetActivity(thread_activity)); | ||
| 1056 | 1057 | ||
| 1057 | return thread->SetActivity(static_cast<ThreadActivity>(activity)); | 1058 | return RESULT_SUCCESS; |
| 1058 | } | 1059 | } |
| 1059 | 1060 | ||
| 1060 | static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { | 1061 | static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle, |
| 1061 | return SetThreadActivity(system, handle, activity); | 1062 | Svc::ThreadActivity thread_activity) { |
| 1063 | return SetThreadActivity(system, thread_handle, thread_activity); | ||
| 1062 | } | 1064 | } |
| 1063 | 1065 | ||
| 1064 | /// Gets the thread context | 1066 | /// Gets the thread context |
| 1065 | static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { | 1067 | static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) { |
| 1066 | LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); | 1068 | LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, |
| 1069 | thread_handle); | ||
| 1067 | 1070 | ||
| 1071 | // Get the thread from its handle. | ||
| 1068 | const auto* current_process = system.Kernel().CurrentProcess(); | 1072 | const auto* current_process = system.Kernel().CurrentProcess(); |
| 1069 | const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 1073 | const std::shared_ptr<KThread> thread = |
| 1070 | if (!thread) { | 1074 | current_process->GetHandleTable().Get<KThread>(thread_handle); |
| 1071 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1075 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1072 | return ERR_INVALID_HANDLE; | ||
| 1073 | } | ||
| 1074 | 1076 | ||
| 1075 | if (thread->GetOwnerProcess() != current_process) { | 1077 | // Require the handle be to a non-current thread in the current process. |
| 1076 | LOG_ERROR(Kernel_SVC, | 1078 | R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); |
| 1077 | "The current process does not own the current thread, thread_handle={:08X} " | 1079 | R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), |
| 1078 | "thread_pid={}, " | 1080 | Svc::ResultBusy); |
| 1079 | "current_process_pid={}", | ||
| 1080 | handle, thread->GetOwnerProcess()->GetProcessID(), | ||
| 1081 | current_process->GetProcessID()); | ||
| 1082 | return ERR_INVALID_HANDLE; | ||
| 1083 | } | ||
| 1084 | 1081 | ||
| 1085 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | 1082 | // Get the thread context. |
| 1086 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | 1083 | std::vector<u8> context; |
| 1087 | return ERR_BUSY; | 1084 | R_TRY(thread->GetThreadContext3(context)); |
| 1088 | } | ||
| 1089 | |||
| 1090 | Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64(); | ||
| 1091 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | ||
| 1092 | ctx.pstate &= 0xFF0FFE20; | ||
| 1093 | 1085 | ||
| 1094 | // If 64-bit, we can just write the context registers directly and we're good. | 1086 | // Copy the thread context to user space. |
| 1095 | // However, if 32-bit, we have to ensure some registers are zeroed out. | 1087 | system.Memory().WriteBlock(out_context, context.data(), context.size()); |
| 1096 | if (!current_process->Is64BitProcess()) { | ||
| 1097 | std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0); | ||
| 1098 | std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); | ||
| 1099 | } | ||
| 1100 | 1088 | ||
| 1101 | system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx)); | ||
| 1102 | return RESULT_SUCCESS; | 1089 | return RESULT_SUCCESS; |
| 1103 | } | 1090 | } |
| 1104 | 1091 | ||
| 1105 | static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { | 1092 | static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) { |
| 1106 | return GetThreadContext(system, thread_context, handle); | 1093 | return GetThreadContext(system, out_context, thread_handle); |
| 1107 | } | 1094 | } |
| 1108 | 1095 | ||
| 1109 | /// Gets the priority for the specified thread | 1096 | /// Gets the priority for the specified thread |
| 1110 | static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { | 1097 | static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) { |
| 1111 | LOG_TRACE(Kernel_SVC, "called"); | 1098 | LOG_TRACE(Kernel_SVC, "called"); |
| 1112 | 1099 | ||
| 1100 | // Get the thread from its handle. | ||
| 1113 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1101 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1114 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); | 1102 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1115 | if (!thread) { | 1103 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1116 | *priority = 0; | ||
| 1117 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 1118 | return ERR_INVALID_HANDLE; | ||
| 1119 | } | ||
| 1120 | 1104 | ||
| 1121 | *priority = thread->GetPriority(); | 1105 | // Get the thread's priority. |
| 1106 | *out_priority = thread->GetPriority(); | ||
| 1122 | return RESULT_SUCCESS; | 1107 | return RESULT_SUCCESS; |
| 1123 | } | 1108 | } |
| 1124 | 1109 | ||
| 1125 | static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) { | 1110 | static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) { |
| 1126 | return GetThreadPriority(system, priority, handle); | 1111 | return GetThreadPriority(system, out_priority, handle); |
| 1127 | } | 1112 | } |
| 1128 | 1113 | ||
| 1129 | /// Sets the priority for the specified thread | 1114 | /// Sets the priority for the specified thread |
| 1130 | static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { | 1115 | static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { |
| 1131 | LOG_TRACE(Kernel_SVC, "called"); | 1116 | LOG_TRACE(Kernel_SVC, "called"); |
| 1132 | 1117 | ||
| 1133 | if (priority > THREADPRIO_LOWEST) { | 1118 | // Validate the priority. |
| 1134 | LOG_ERROR( | 1119 | R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, |
| 1135 | Kernel_SVC, | 1120 | Svc::ResultInvalidPriority); |
| 1136 | "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}", | ||
| 1137 | THREADPRIO_LOWEST, priority, handle); | ||
| 1138 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 1139 | } | ||
| 1140 | 1121 | ||
| 1141 | const auto* const current_process = system.Kernel().CurrentProcess(); | 1122 | // Get the thread from its handle. |
| 1142 | 1123 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | |
| 1143 | std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 1124 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1144 | if (!thread) { | 1125 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1145 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 1146 | return ERR_INVALID_HANDLE; | ||
| 1147 | } | ||
| 1148 | 1126 | ||
| 1127 | // Set the thread priority. | ||
| 1149 | thread->SetBasePriority(priority); | 1128 | thread->SetBasePriority(priority); |
| 1150 | |||
| 1151 | return RESULT_SUCCESS; | 1129 | return RESULT_SUCCESS; |
| 1152 | } | 1130 | } |
| 1153 | 1131 | ||
| @@ -1438,62 +1416,50 @@ static void ExitProcess(Core::System& system) { | |||
| 1438 | current_process->PrepareForTermination(); | 1416 | current_process->PrepareForTermination(); |
| 1439 | 1417 | ||
| 1440 | // Kill the current thread | 1418 | // Kill the current thread |
| 1441 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop(); | 1419 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit(); |
| 1442 | } | 1420 | } |
| 1443 | 1421 | ||
| 1444 | static void ExitProcess32(Core::System& system) { | 1422 | static void ExitProcess32(Core::System& system) { |
| 1445 | ExitProcess(system); | 1423 | ExitProcess(system); |
| 1446 | } | 1424 | } |
| 1447 | 1425 | ||
| 1426 | static constexpr bool IsValidCoreId(int32_t core_id) { | ||
| 1427 | return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); | ||
| 1428 | } | ||
| 1429 | |||
| 1448 | /// Creates a new thread | 1430 | /// Creates a new thread |
| 1449 | static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, | 1431 | static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, |
| 1450 | VAddr stack_top, u32 priority, s32 processor_id) { | 1432 | VAddr stack_bottom, u32 priority, s32 core_id) { |
| 1451 | LOG_DEBUG(Kernel_SVC, | 1433 | LOG_DEBUG(Kernel_SVC, |
| 1452 | "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, " | 1434 | "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, " |
| 1453 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | 1435 | "priority=0x{:08X}, core_id=0x{:08X}", |
| 1454 | entry_point, arg, stack_top, priority, processor_id, *out_handle); | 1436 | entry_point, arg, stack_bottom, priority, core_id); |
| 1455 | 1437 | ||
| 1456 | auto* const current_process = system.Kernel().CurrentProcess(); | 1438 | // Adjust core id, if it's the default magic. |
| 1457 | 1439 | auto& kernel = system.Kernel(); | |
| 1458 | if (processor_id == THREADPROCESSORID_IDEAL) { | 1440 | auto& process = *kernel.CurrentProcess(); |
| 1459 | // Set the target CPU to the one specified by the process. | 1441 | if (core_id == Svc::IdealCoreUseProcessValue) { |
| 1460 | processor_id = current_process->GetIdealCore(); | 1442 | core_id = process.GetIdealCoreId(); |
| 1461 | ASSERT(processor_id != THREADPROCESSORID_IDEAL); | ||
| 1462 | } | 1443 | } |
| 1463 | 1444 | ||
| 1464 | if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) { | 1445 | // Validate arguments. |
| 1465 | LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); | 1446 | R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); |
| 1466 | return ERR_INVALID_PROCESSOR_ID; | 1447 | R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); |
| 1467 | } | ||
| 1468 | 1448 | ||
| 1469 | const u64 core_mask = current_process->GetCoreMask(); | 1449 | R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, |
| 1470 | if ((core_mask | (1ULL << processor_id)) != core_mask) { | 1450 | Svc::ResultInvalidPriority); |
| 1471 | LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id); | 1451 | R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); |
| 1472 | return ERR_INVALID_PROCESSOR_ID; | ||
| 1473 | } | ||
| 1474 | 1452 | ||
| 1475 | if (priority > THREADPRIO_LOWEST) { | 1453 | ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1)); |
| 1476 | LOG_ERROR(Kernel_SVC, | ||
| 1477 | "Invalid thread priority specified ({}). Must be within the range 0-64", | ||
| 1478 | priority); | ||
| 1479 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 1480 | } | ||
| 1481 | 1454 | ||
| 1482 | if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) { | 1455 | std::shared_ptr<KThread> thread; |
| 1483 | LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority); | 1456 | { |
| 1484 | return ERR_INVALID_THREAD_PRIORITY; | 1457 | KScopedLightLock lk{process.GetStateLock()}; |
| 1458 | CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority, | ||
| 1459 | arg, core_id, stack_bottom, &process)); | ||
| 1485 | } | 1460 | } |
| 1486 | 1461 | ||
| 1487 | auto& kernel = system.Kernel(); | 1462 | const auto new_thread_handle = process.GetHandleTable().Create(thread); |
| 1488 | |||
| 1489 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1)); | ||
| 1490 | |||
| 1491 | ThreadType type = THREADTYPE_USER; | ||
| 1492 | CASCADE_RESULT(std::shared_ptr<Thread> thread, | ||
| 1493 | Thread::Create(system, type, "", entry_point, priority, arg, processor_id, | ||
| 1494 | stack_top, current_process)); | ||
| 1495 | |||
| 1496 | const auto new_thread_handle = current_process->GetHandleTable().Create(thread); | ||
| 1497 | if (new_thread_handle.Failed()) { | 1463 | if (new_thread_handle.Failed()) { |
| 1498 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", | 1464 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", |
| 1499 | new_thread_handle.Code().raw); | 1465 | new_thread_handle.Code().raw); |
| @@ -1517,17 +1483,15 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p | |||
| 1517 | static ResultCode StartThread(Core::System& system, Handle thread_handle) { | 1483 | static ResultCode StartThread(Core::System& system, Handle thread_handle) { |
| 1518 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 1484 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 1519 | 1485 | ||
| 1486 | // Get the thread from its handle. | ||
| 1520 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1487 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1521 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1488 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1522 | if (!thread) { | 1489 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1523 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1524 | thread_handle); | ||
| 1525 | return ERR_INVALID_HANDLE; | ||
| 1526 | } | ||
| 1527 | 1490 | ||
| 1528 | ASSERT(thread->GetState() == ThreadState::Initialized); | 1491 | // Try to start the thread. |
| 1492 | R_TRY(thread->Run()); | ||
| 1529 | 1493 | ||
| 1530 | return thread->Start(); | 1494 | return RESULT_SUCCESS; |
| 1531 | } | 1495 | } |
| 1532 | 1496 | ||
| 1533 | static ResultCode StartThread32(Core::System& system, Handle thread_handle) { | 1497 | static ResultCode StartThread32(Core::System& system, Handle thread_handle) { |
| @@ -1540,7 +1504,7 @@ static void ExitThread(Core::System& system) { | |||
| 1540 | 1504 | ||
| 1541 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 1505 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 1542 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); | 1506 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); |
| 1543 | current_thread->Stop(); | 1507 | current_thread->Exit(); |
| 1544 | } | 1508 | } |
| 1545 | 1509 | ||
| 1546 | static void ExitThread32(Core::System& system) { | 1510 | static void ExitThread32(Core::System& system) { |
| @@ -1549,34 +1513,28 @@ static void ExitThread32(Core::System& system) { | |||
| 1549 | 1513 | ||
| 1550 | /// Sleep the current thread | 1514 | /// Sleep the current thread |
| 1551 | static void SleepThread(Core::System& system, s64 nanoseconds) { | 1515 | static void SleepThread(Core::System& system, s64 nanoseconds) { |
| 1552 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); | 1516 | auto& kernel = system.Kernel(); |
| 1517 | const auto yield_type = static_cast<Svc::YieldType>(nanoseconds); | ||
| 1553 | 1518 | ||
| 1554 | enum class SleepType : s64 { | 1519 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); |
| 1555 | YieldWithoutCoreMigration = 0, | ||
| 1556 | YieldWithCoreMigration = -1, | ||
| 1557 | YieldAndWaitForLoadBalancing = -2, | ||
| 1558 | }; | ||
| 1559 | 1520 | ||
| 1560 | auto& scheduler = *system.Kernel().CurrentScheduler(); | 1521 | // When the input tick is positive, sleep. |
| 1561 | if (nanoseconds <= 0) { | 1522 | if (nanoseconds > 0) { |
| 1562 | switch (static_cast<SleepType>(nanoseconds)) { | 1523 | // Convert the timeout from nanoseconds to ticks. |
| 1563 | case SleepType::YieldWithoutCoreMigration: { | 1524 | // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... |
| 1564 | scheduler.YieldWithoutCoreMigration(); | 1525 | |
| 1565 | break; | 1526 | // Sleep. |
| 1566 | } | 1527 | // NOTE: Nintendo does not check the result of this sleep. |
| 1567 | case SleepType::YieldWithCoreMigration: { | 1528 | static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds)); |
| 1568 | scheduler.YieldWithCoreMigration(); | 1529 | } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { |
| 1569 | break; | 1530 | KScheduler::YieldWithoutCoreMigration(kernel); |
| 1570 | } | 1531 | } else if (yield_type == Svc::YieldType::WithCoreMigration) { |
| 1571 | case SleepType::YieldAndWaitForLoadBalancing: { | 1532 | KScheduler::YieldWithCoreMigration(kernel); |
| 1572 | scheduler.YieldToAnyThread(); | 1533 | } else if (yield_type == Svc::YieldType::ToAnyThread) { |
| 1573 | break; | 1534 | KScheduler::YieldToAnyThread(kernel); |
| 1574 | } | ||
| 1575 | default: | ||
| 1576 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 1577 | } | ||
| 1578 | } else { | 1535 | } else { |
| 1579 | scheduler.GetCurrentThread()->Sleep(nanoseconds); | 1536 | // Nintendo does nothing at all if an otherwise invalid value is passed. |
| 1537 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 1580 | } | 1538 | } |
| 1581 | } | 1539 | } |
| 1582 | 1540 | ||
| @@ -1839,95 +1797,72 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u | |||
| 1839 | return CreateTransferMemory(system, handle, addr, size, permissions); | 1797 | return CreateTransferMemory(system, handle, addr, size, permissions); |
| 1840 | } | 1798 | } |
| 1841 | 1799 | ||
| 1842 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, | 1800 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, |
| 1843 | u64* mask) { | 1801 | u64* out_affinity_mask) { |
| 1844 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); | 1802 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); |
| 1845 | 1803 | ||
| 1804 | // Get the thread from its handle. | ||
| 1846 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1805 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1847 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1806 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1848 | if (!thread) { | 1807 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1849 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1850 | thread_handle); | ||
| 1851 | *core = 0; | ||
| 1852 | *mask = 0; | ||
| 1853 | return ERR_INVALID_HANDLE; | ||
| 1854 | } | ||
| 1855 | 1808 | ||
| 1856 | *core = thread->GetIdealCore(); | 1809 | // Get the core mask. |
| 1857 | *mask = thread->GetAffinityMask().GetAffinityMask(); | 1810 | R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); |
| 1858 | 1811 | ||
| 1859 | return RESULT_SUCCESS; | 1812 | return RESULT_SUCCESS; |
| 1860 | } | 1813 | } |
| 1861 | 1814 | ||
| 1862 | static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, | 1815 | static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id, |
| 1863 | u32* mask_low, u32* mask_high) { | 1816 | u32* out_affinity_mask_low, u32* out_affinity_mask_high) { |
| 1864 | u64 mask{}; | 1817 | u64 out_affinity_mask{}; |
| 1865 | const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); | 1818 | const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask); |
| 1866 | *mask_high = static_cast<u32>(mask >> 32); | 1819 | *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32); |
| 1867 | *mask_low = static_cast<u32>(mask); | 1820 | *out_affinity_mask_low = static_cast<u32>(out_affinity_mask); |
| 1868 | return result; | 1821 | return result; |
| 1869 | } | 1822 | } |
| 1870 | 1823 | ||
| 1871 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, | 1824 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, |
| 1872 | u64 affinity_mask) { | 1825 | u64 affinity_mask) { |
| 1873 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", | 1826 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", |
| 1874 | thread_handle, core, affinity_mask); | 1827 | thread_handle, core_id, affinity_mask); |
| 1875 | |||
| 1876 | const auto* const current_process = system.Kernel().CurrentProcess(); | ||
| 1877 | 1828 | ||
| 1878 | if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) { | 1829 | const auto& current_process = *system.Kernel().CurrentProcess(); |
| 1879 | const u8 ideal_cpu_core = current_process->GetIdealCore(); | ||
| 1880 | 1830 | ||
| 1881 | ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL)); | 1831 | // Determine the core id/affinity mask. |
| 1882 | 1832 | if (core_id == Svc::IdealCoreUseProcessValue) { | |
| 1883 | // Set the target CPU to the ideal core specified by the process. | 1833 | core_id = current_process.GetIdealCoreId(); |
| 1884 | core = ideal_cpu_core; | 1834 | affinity_mask = (1ULL << core_id); |
| 1885 | affinity_mask = 1ULL << core; | ||
| 1886 | } else { | 1835 | } else { |
| 1887 | const u64 core_mask = current_process->GetCoreMask(); | 1836 | // Validate the affinity mask. |
| 1888 | 1837 | const u64 process_core_mask = current_process.GetCoreMask(); | |
| 1889 | if ((core_mask | affinity_mask) != core_mask) { | 1838 | R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, |
| 1890 | LOG_ERROR( | 1839 | Svc::ResultInvalidCoreId); |
| 1891 | Kernel_SVC, | 1840 | R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); |
| 1892 | "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})", | 1841 | |
| 1893 | core_mask, affinity_mask); | 1842 | // Validate the core id. |
| 1894 | return ERR_INVALID_PROCESSOR_ID; | 1843 | if (IsValidCoreId(core_id)) { |
| 1895 | } | 1844 | R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); |
| 1896 | 1845 | } else { | |
| 1897 | if (affinity_mask == 0) { | 1846 | R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, |
| 1898 | LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero."); | 1847 | Svc::ResultInvalidCoreId); |
| 1899 | return ERR_INVALID_COMBINATION; | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | if (core < Core::Hardware::NUM_CPU_CORES) { | ||
| 1903 | if ((affinity_mask & (1ULL << core)) == 0) { | ||
| 1904 | LOG_ERROR(Kernel_SVC, | ||
| 1905 | "Core is not enabled for the current mask, core={}, mask={:016X}", core, | ||
| 1906 | affinity_mask); | ||
| 1907 | return ERR_INVALID_COMBINATION; | ||
| 1908 | } | ||
| 1909 | } else if (core != static_cast<u32>(THREADPROCESSORID_DONT_CARE) && | ||
| 1910 | core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) { | ||
| 1911 | LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core); | ||
| 1912 | return ERR_INVALID_PROCESSOR_ID; | ||
| 1913 | } | 1848 | } |
| 1914 | } | 1849 | } |
| 1915 | 1850 | ||
| 1916 | const auto& handle_table = current_process->GetHandleTable(); | 1851 | // Get the thread from its handle. |
| 1917 | const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1852 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1918 | if (!thread) { | 1853 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1919 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | 1854 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1920 | thread_handle); | ||
| 1921 | return ERR_INVALID_HANDLE; | ||
| 1922 | } | ||
| 1923 | 1855 | ||
| 1924 | return thread->SetCoreAndAffinityMask(core, affinity_mask); | 1856 | // Set the core mask. |
| 1857 | R_TRY(thread->SetCoreMask(core_id, affinity_mask)); | ||
| 1858 | |||
| 1859 | return RESULT_SUCCESS; | ||
| 1925 | } | 1860 | } |
| 1926 | 1861 | ||
| 1927 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, | 1862 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id, |
| 1928 | u32 affinity_mask_low, u32 affinity_mask_high) { | 1863 | u32 affinity_mask_low, u32 affinity_mask_high) { |
| 1929 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); | 1864 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); |
| 1930 | return SetThreadCoreMask(system, thread_handle, core, affinity_mask); | 1865 | return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask); |
| 1931 | } | 1866 | } |
| 1932 | 1867 | ||
| 1933 | static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { | 1868 | static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { |
| @@ -2491,7 +2426,7 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2491 | kernel.EnterSVCProfile(); | 2426 | kernel.EnterSVCProfile(); |
| 2492 | 2427 | ||
| 2493 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); | 2428 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 2494 | thread->SetContinuousOnSVC(true); | 2429 | thread->SetIsCallingSvc(); |
| 2495 | 2430 | ||
| 2496 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) | 2431 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) |
| 2497 | : GetSVCInfo32(immediate); | 2432 | : GetSVCInfo32(immediate); |
| @@ -2507,7 +2442,7 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2507 | 2442 | ||
| 2508 | kernel.ExitSVCProfile(); | 2443 | kernel.ExitSVCProfile(); |
| 2509 | 2444 | ||
| 2510 | if (!thread->IsContinuousOnSVC()) { | 2445 | if (!thread->IsCallingSvc()) { |
| 2511 | auto* host_context = thread->GetHostContext().get(); | 2446 | auto* host_context = thread->GetHostContext().get(); |
| 2512 | host_context->Rewind(); | 2447 | host_context->Rewind(); |
| 2513 | } | 2448 | } |