diff options
| author | 2021-01-20 13:42:27 -0800 | |
|---|---|---|
| committer | 2021-01-28 21:42:26 -0800 | |
| commit | cdd14b03e5c8e29bc6cd11bbde0ef726d2f166ce (patch) | |
| tree | 987f6cb5d3f1955dc88f5ac2c1d5c1329d787fc4 /src/core/hle/kernel/svc.cpp | |
| parent | kernel: svc_types: Add ThreadActivity. (diff) | |
| download | yuzu-cdd14b03e5c8e29bc6cd11bbde0ef726d2f166ce.tar.gz yuzu-cdd14b03e5c8e29bc6cd11bbde0ef726d2f166ce.tar.xz yuzu-cdd14b03e5c8e29bc6cd11bbde0ef726d2f166ce.zip | |
hle: kernel: Recode implementation of KThread to be more accurate.
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 355 |
1 files changed, 152 insertions, 203 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2512bfd98..dbef854f8 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -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<KThread> thread = handle_table.Get<KThread>(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 | } |
| @@ -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<KThread> thread = handle_table.Get<KThread>(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 | } |
| @@ -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,127 +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<KThread> thread = current_process->GetHandleTable().Get<KThread>(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<KThread> thread = current_process->GetHandleTable().Get<KThread>(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 | 1085 | ||
| 1090 | Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64(); | 1086 | // Copy the thread context to user space. |
| 1091 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | 1087 | system.Memory().WriteBlock(out_context, context.data(), context.size()); |
| 1092 | ctx.pstate &= 0xFF0FFE20; | ||
| 1093 | 1088 | ||
| 1094 | // If 64-bit, we can just write the context registers directly and we're good. | ||
| 1095 | // However, if 32-bit, we have to ensure some registers are zeroed out. | ||
| 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 | |||
| 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<KThread> thread = handle_table.Get<KThread>(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 > Svc::LowestThreadPriority) { | 1118 | // Validate the priority. |
| 1134 | LOG_ERROR(Kernel_SVC, "An invalid priority was specified {} for thread_handle={:08X}", | 1119 | R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, |
| 1135 | priority, handle); | 1120 | Svc::ResultInvalidPriority); |
| 1136 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | const auto* const current_process = system.Kernel().CurrentProcess(); | ||
| 1140 | 1121 | ||
| 1141 | std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle); | 1122 | // Get the thread from its handle. |
| 1142 | if (!thread) { | 1123 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1143 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | 1124 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1144 | return ERR_INVALID_HANDLE; | 1125 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1145 | } | ||
| 1146 | 1126 | ||
| 1127 | // Set the thread priority. | ||
| 1147 | thread->SetBasePriority(priority); | 1128 | thread->SetBasePriority(priority); |
| 1148 | |||
| 1149 | return RESULT_SUCCESS; | 1129 | return RESULT_SUCCESS; |
| 1150 | } | 1130 | } |
| 1151 | 1131 | ||
| @@ -1436,7 +1416,7 @@ static void ExitProcess(Core::System& system) { | |||
| 1436 | current_process->PrepareForTermination(); | 1416 | current_process->PrepareForTermination(); |
| 1437 | 1417 | ||
| 1438 | // Kill the current thread | 1418 | // Kill the current thread |
| 1439 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop(); | 1419 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit(); |
| 1440 | } | 1420 | } |
| 1441 | 1421 | ||
| 1442 | static void ExitProcess32(Core::System& system) { | 1422 | static void ExitProcess32(Core::System& system) { |
| @@ -1500,17 +1480,15 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p | |||
| 1500 | static ResultCode StartThread(Core::System& system, Handle thread_handle) { | 1480 | static ResultCode StartThread(Core::System& system, Handle thread_handle) { |
| 1501 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); | 1481 | LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); |
| 1502 | 1482 | ||
| 1483 | // Get the thread from its handle. | ||
| 1503 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1484 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1504 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1485 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1505 | if (!thread) { | 1486 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1506 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1507 | thread_handle); | ||
| 1508 | return ERR_INVALID_HANDLE; | ||
| 1509 | } | ||
| 1510 | 1487 | ||
| 1511 | ASSERT(thread->GetState() == ThreadState::Initialized); | 1488 | // Try to start the thread. |
| 1489 | R_TRY(thread->Run()); | ||
| 1512 | 1490 | ||
| 1513 | return thread->Start(); | 1491 | return RESULT_SUCCESS; |
| 1514 | } | 1492 | } |
| 1515 | 1493 | ||
| 1516 | static ResultCode StartThread32(Core::System& system, Handle thread_handle) { | 1494 | static ResultCode StartThread32(Core::System& system, Handle thread_handle) { |
| @@ -1523,7 +1501,7 @@ static void ExitThread(Core::System& system) { | |||
| 1523 | 1501 | ||
| 1524 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 1502 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 1525 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); | 1503 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); |
| 1526 | current_thread->Stop(); | 1504 | current_thread->Exit(); |
| 1527 | } | 1505 | } |
| 1528 | 1506 | ||
| 1529 | static void ExitThread32(Core::System& system) { | 1507 | static void ExitThread32(Core::System& system) { |
| @@ -1532,34 +1510,28 @@ static void ExitThread32(Core::System& system) { | |||
| 1532 | 1510 | ||
| 1533 | /// Sleep the current thread | 1511 | /// Sleep the current thread |
| 1534 | static void SleepThread(Core::System& system, s64 nanoseconds) { | 1512 | static void SleepThread(Core::System& system, s64 nanoseconds) { |
| 1535 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); | 1513 | auto& kernel = system.Kernel(); |
| 1514 | const auto yield_type = static_cast<Svc::YieldType>(nanoseconds); | ||
| 1536 | 1515 | ||
| 1537 | enum class SleepType : s64 { | 1516 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); |
| 1538 | YieldWithoutCoreMigration = 0, | ||
| 1539 | YieldWithCoreMigration = -1, | ||
| 1540 | YieldAndWaitForLoadBalancing = -2, | ||
| 1541 | }; | ||
| 1542 | 1517 | ||
| 1543 | auto& scheduler = *system.Kernel().CurrentScheduler(); | 1518 | // When the input tick is positive, sleep. |
| 1544 | if (nanoseconds <= 0) { | 1519 | if (nanoseconds > 0) { |
| 1545 | switch (static_cast<SleepType>(nanoseconds)) { | 1520 | // Convert the timeout from nanoseconds to ticks. |
| 1546 | case SleepType::YieldWithoutCoreMigration: { | 1521 | // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... |
| 1547 | scheduler.YieldWithoutCoreMigration(); | 1522 | |
| 1548 | break; | 1523 | // Sleep. |
| 1549 | } | 1524 | // NOTE: Nintendo does not check the result of this sleep. |
| 1550 | case SleepType::YieldWithCoreMigration: { | 1525 | static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds)); |
| 1551 | scheduler.YieldWithCoreMigration(); | 1526 | } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { |
| 1552 | break; | 1527 | KScheduler::YieldWithoutCoreMigration(kernel); |
| 1553 | } | 1528 | } else if (yield_type == Svc::YieldType::WithCoreMigration) { |
| 1554 | case SleepType::YieldAndWaitForLoadBalancing: { | 1529 | KScheduler::YieldWithCoreMigration(kernel); |
| 1555 | scheduler.YieldToAnyThread(); | 1530 | } else if (yield_type == Svc::YieldType::ToAnyThread) { |
| 1556 | break; | 1531 | KScheduler::YieldToAnyThread(kernel); |
| 1557 | } | ||
| 1558 | default: | ||
| 1559 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 1560 | } | ||
| 1561 | } else { | 1532 | } else { |
| 1562 | scheduler.GetCurrentThread()->Sleep(nanoseconds); | 1533 | // Nintendo does nothing at all if an otherwise invalid value is passed. |
| 1534 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | ||
| 1563 | } | 1535 | } |
| 1564 | } | 1536 | } |
| 1565 | 1537 | ||
| @@ -1822,95 +1794,72 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u | |||
| 1822 | return CreateTransferMemory(system, handle, addr, size, permissions); | 1794 | return CreateTransferMemory(system, handle, addr, size, permissions); |
| 1823 | } | 1795 | } |
| 1824 | 1796 | ||
| 1825 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, | 1797 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, |
| 1826 | u64* mask) { | 1798 | u64* out_affinity_mask) { |
| 1827 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); | 1799 | LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); |
| 1828 | 1800 | ||
| 1801 | // Get the thread from its handle. | ||
| 1829 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1802 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1830 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1803 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1831 | if (!thread) { | 1804 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1832 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1833 | thread_handle); | ||
| 1834 | *core = 0; | ||
| 1835 | *mask = 0; | ||
| 1836 | return ERR_INVALID_HANDLE; | ||
| 1837 | } | ||
| 1838 | 1805 | ||
| 1839 | *core = thread->GetIdealCore(); | 1806 | // Get the core mask. |
| 1840 | *mask = thread->GetAffinityMask().GetAffinityMask(); | 1807 | R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); |
| 1841 | 1808 | ||
| 1842 | return RESULT_SUCCESS; | 1809 | return RESULT_SUCCESS; |
| 1843 | } | 1810 | } |
| 1844 | 1811 | ||
| 1845 | static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, | 1812 | static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id, |
| 1846 | u32* mask_low, u32* mask_high) { | 1813 | u32* out_affinity_mask_low, u32* out_affinity_mask_high) { |
| 1847 | u64 mask{}; | 1814 | u64 out_affinity_mask{}; |
| 1848 | const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); | 1815 | const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask); |
| 1849 | *mask_high = static_cast<u32>(mask >> 32); | 1816 | *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32); |
| 1850 | *mask_low = static_cast<u32>(mask); | 1817 | *out_affinity_mask_low = static_cast<u32>(out_affinity_mask); |
| 1851 | return result; | 1818 | return result; |
| 1852 | } | 1819 | } |
| 1853 | 1820 | ||
| 1854 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, | 1821 | static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, |
| 1855 | u64 affinity_mask) { | 1822 | u64 affinity_mask) { |
| 1856 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", | 1823 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", |
| 1857 | thread_handle, core, affinity_mask); | 1824 | thread_handle, core_id, affinity_mask); |
| 1858 | |||
| 1859 | const auto* const current_process = system.Kernel().CurrentProcess(); | ||
| 1860 | 1825 | ||
| 1861 | if (core == static_cast<u32>(Svc::IdealCoreUseProcessValue)) { | 1826 | const auto& current_process = *system.Kernel().CurrentProcess(); |
| 1862 | const u8 ideal_cpu_core = current_process->GetIdealCoreId(); | ||
| 1863 | 1827 | ||
| 1864 | ASSERT(ideal_cpu_core != static_cast<u8>(Svc::IdealCoreUseProcessValue)); | 1828 | // Determine the core id/affinity mask. |
| 1865 | 1829 | if (core_id == Svc::IdealCoreUseProcessValue) { | |
| 1866 | // Set the target CPU to the ideal core specified by the process. | 1830 | core_id = current_process.GetIdealCoreId(); |
| 1867 | core = ideal_cpu_core; | 1831 | affinity_mask = (1ULL << core_id); |
| 1868 | affinity_mask = 1ULL << core; | ||
| 1869 | } else { | 1832 | } else { |
| 1870 | const u64 core_mask = current_process->GetCoreMask(); | 1833 | // Validate the affinity mask. |
| 1871 | 1834 | const u64 process_core_mask = current_process.GetCoreMask(); | |
| 1872 | if ((core_mask | affinity_mask) != core_mask) { | 1835 | R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, |
| 1873 | LOG_ERROR( | 1836 | Svc::ResultInvalidCoreId); |
| 1874 | Kernel_SVC, | 1837 | R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); |
| 1875 | "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})", | 1838 | |
| 1876 | core_mask, affinity_mask); | 1839 | // Validate the core id. |
| 1877 | return ERR_INVALID_PROCESSOR_ID; | 1840 | if (IsValidCoreId(core_id)) { |
| 1878 | } | 1841 | R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); |
| 1879 | 1842 | } else { | |
| 1880 | if (affinity_mask == 0) { | 1843 | R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, |
| 1881 | LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero."); | 1844 | Svc::ResultInvalidCoreId); |
| 1882 | return ERR_INVALID_COMBINATION; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | if (core < Core::Hardware::NUM_CPU_CORES) { | ||
| 1886 | if ((affinity_mask & (1ULL << core)) == 0) { | ||
| 1887 | LOG_ERROR(Kernel_SVC, | ||
| 1888 | "Core is not enabled for the current mask, core={}, mask={:016X}", core, | ||
| 1889 | affinity_mask); | ||
| 1890 | return ERR_INVALID_COMBINATION; | ||
| 1891 | } | ||
| 1892 | } else if (core != static_cast<u32>(Svc::IdealCoreDontCare) && | ||
| 1893 | core != static_cast<u32>(Svc::IdealCoreNoUpdate)) { | ||
| 1894 | LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core); | ||
| 1895 | return ERR_INVALID_PROCESSOR_ID; | ||
| 1896 | } | 1845 | } |
| 1897 | } | 1846 | } |
| 1898 | 1847 | ||
| 1899 | const auto& handle_table = current_process->GetHandleTable(); | 1848 | // Get the thread from its handle. |
| 1849 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||
| 1900 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1850 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1901 | if (!thread) { | 1851 | R_UNLESS(thread, Svc::ResultInvalidHandle); |
| 1902 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1903 | thread_handle); | ||
| 1904 | return ERR_INVALID_HANDLE; | ||
| 1905 | } | ||
| 1906 | 1852 | ||
| 1907 | return thread->SetCoreAndAffinityMask(core, affinity_mask); | 1853 | // Set the core mask. |
| 1854 | R_TRY(thread->SetCoreMask(core_id, affinity_mask)); | ||
| 1855 | |||
| 1856 | return RESULT_SUCCESS; | ||
| 1908 | } | 1857 | } |
| 1909 | 1858 | ||
| 1910 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, | 1859 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id, |
| 1911 | u32 affinity_mask_low, u32 affinity_mask_high) { | 1860 | u32 affinity_mask_low, u32 affinity_mask_high) { |
| 1912 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); | 1861 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); |
| 1913 | return SetThreadCoreMask(system, thread_handle, core, affinity_mask); | 1862 | return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask); |
| 1914 | } | 1863 | } |
| 1915 | 1864 | ||
| 1916 | static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { | 1865 | static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { |
| @@ -2474,7 +2423,7 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2474 | kernel.EnterSVCProfile(); | 2423 | kernel.EnterSVCProfile(); |
| 2475 | 2424 | ||
| 2476 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); | 2425 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 2477 | thread->SetContinuousOnSVC(true); | 2426 | thread->SetIsCallingSvc(); |
| 2478 | 2427 | ||
| 2479 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) | 2428 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) |
| 2480 | : GetSVCInfo32(immediate); | 2429 | : GetSVCInfo32(immediate); |
| @@ -2490,7 +2439,7 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2490 | 2439 | ||
| 2491 | kernel.ExitSVCProfile(); | 2440 | kernel.ExitSVCProfile(); |
| 2492 | 2441 | ||
| 2493 | if (!thread->IsContinuousOnSVC()) { | 2442 | if (!thread->IsCallingSvc()) { |
| 2494 | auto* host_context = thread->GetHostContext().get(); | 2443 | auto* host_context = thread->GetHostContext().get(); |
| 2495 | host_context->Rewind(); | 2444 | host_context->Rewind(); |
| 2496 | } | 2445 | } |