|
|
@@ -1100,7 +1100,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
|
|
|
LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
|
|
|
thread_handle);
|
|
|
|
|
|
- __debugbreak();
|
|
|
+ auto& kernel = system.Kernel();
|
|
|
+
|
|
|
+ // Get the thread from its handle.
|
|
|
+ KScopedAutoObject thread =
|
|
|
+ kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
|
|
+
|
|
|
+ // Require the handle be to a non-current thread in the current process.
|
|
|
+ const auto* current_process = kernel.CurrentProcess();
|
|
|
+ R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
|
|
|
+
|
|
|
+ // Verify that the thread isn't terminated.
|
|
|
+ R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
|
|
|
+
|
|
|
+ /// Check that the thread is not the current one.
|
|
|
+ /// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
|
|
|
+ R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
|
|
|
+
|
|
|
+ // Try to get the thread context until the thread isn't current on any core.
|
|
|
+ while (true) {
|
|
|
+ KScopedSchedulerLock sl{kernel};
|
|
|
+
|
|
|
+ // TODO(bunnei): Enforce that thread is suspended for debug here.
|
|
|
+
|
|
|
+ // If the thread's raw state isn't runnable, check if it's current on some core.
|
|
|
+ if (thread->GetRawState() != ThreadState::Runnable) {
|
|
|
+ bool current = false;
|
|
|
+ for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
|
|
|
+ if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) {
|
|
|
+ current = true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the thread is current, retry until it isn't.
|
|
|
+ if (current) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get the thread context.
|
|
|
+ std::vector<u8> context;
|
|
|
+ R_TRY(thread->GetThreadContext3(context));
|
|
|
+
|
|
|
+ // Copy the thread context to user space.
|
|
|
+ system.Memory().WriteBlock(out_context, context.data(), context.size());
|
|
|
+
|
|
|
+ return RESULT_SUCCESS;
|
|
|
+ }
|
|
|
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
@@ -1885,7 +1933,16 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u
|
|
|
|
|
|
static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
|
|
|
u64* out_affinity_mask) {
|
|
|
- __debugbreak();
|
|
|
+ LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
|
|
+
|
|
|
+ // Get the thread from its handle.
|
|
|
+ KScopedAutoObject thread =
|
|
|
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
|
|
|
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
|
|
|
+
|
|
|
+ // Get the core mask.
|
|
|
+ R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
|
|
|
+
|
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
|
|