From 2cb6106523a87ae78d3a6b92c34b3b1d2817415e Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 11 Apr 2021 12:49:51 -0700
Subject: [PATCH] hle: kernel: svc: Migrate GetThreadContext,
 GetThreadCoreMask.

---
 src/core/hle/kernel/svc.cpp | 61 +++++++++++++++++++++++++++++++++++--
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index fae4c7209..b83ee3e69 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -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;
 }