From 693cad8e9b45cb61370bbc05e8e0022ea42044f9 Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Mon, 23 Jan 2023 20:31:03 -0500
Subject: [PATCH] kernel: split SetAddressKey into user and kernel variants

---
 src/core/hle/kernel/k_condition_variable.cpp |  2 +-
 src/core/hle/kernel/k_light_lock.cpp         |  2 +-
 src/core/hle/kernel/k_memory_layout.h        |  6 ++---
 src/core/hle/kernel/k_thread.cpp             |  8 +++----
 src/core/hle/kernel/k_thread.h               | 24 +++++++++++++++++---
 5 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 124149697b..0c6b20db3b 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -171,7 +171,7 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value)
         R_UNLESS(owner_thread != nullptr, ResultInvalidHandle);
 
         // Update the lock.
-        cur_thread->SetAddressKey(addr, value);
+        cur_thread->SetUserAddressKey(addr, value);
         owner_thread->AddWaiter(cur_thread);
 
         // Begin waiting.
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index 43185320d2..d791acbe32 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -68,7 +68,7 @@ bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
 
         // Add the current thread as a waiter on the owner.
         KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
-        cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
+        cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
         owner_thread->AddWaiter(cur_thread);
 
         // Begin waiting to hold the lock.
diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h
index fd6e1d3e6b..17fa1a6ed6 100644
--- a/src/core/hle/kernel/k_memory_layout.h
+++ b/src/core/hle/kernel/k_memory_layout.h
@@ -67,9 +67,9 @@ constexpr size_t KernelPageBufferAdditionalSize = 0x33C000;
 constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize +
                                            KernelSlabHeapSize + KernelPageBufferHeapSize;
 
-constexpr bool IsKernelAddressKey(VAddr key) {
-    return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
-}
+//! NB: Use KThread::GetAddressKeyIsKernel().
+//! See explanation for deviation of GetAddressKey.
+bool IsKernelAddressKey(VAddr key) = delete;
 
 constexpr bool IsKernelAddress(VAddr address) {
     return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 7c7c2459c9..84ff3c64b2 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -330,7 +330,7 @@ void KThread::Finalize() {
             KThread* const waiter = std::addressof(*it);
 
             // The thread shouldn't be a kernel waiter.
-            ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
+            ASSERT(!waiter->GetAddressKeyIsKernel());
 
             // Clear the lock owner.
             waiter->SetLockOwner(nullptr);
@@ -884,7 +884,7 @@ void KThread::AddWaiterImpl(KThread* thread) {
     }
 
     // Keep track of how many kernel waiters we have.
-    if (IsKernelAddressKey(thread->GetAddressKey())) {
+    if (thread->GetAddressKeyIsKernel()) {
         ASSERT((num_kernel_waiters++) >= 0);
         KScheduler::SetSchedulerUpdateNeeded(kernel);
     }
@@ -898,7 +898,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     // Keep track of how many kernel waiters we have.
-    if (IsKernelAddressKey(thread->GetAddressKey())) {
+    if (thread->GetAddressKeyIsKernel()) {
         ASSERT((num_kernel_waiters--) > 0);
         KScheduler::SetSchedulerUpdateNeeded(kernel);
     }
@@ -974,7 +974,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
             KThread* thread = std::addressof(*it);
 
             // Keep track of how many kernel waiters we have.
-            if (IsKernelAddressKey(thread->GetAddressKey())) {
+            if (thread->GetAddressKeyIsKernel()) {
                 ASSERT((num_kernel_waiters--) > 0);
                 KScheduler::SetSchedulerUpdateNeeded(kernel);
             }
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 083f4962d6..9d771de0e6 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -605,13 +605,30 @@ public:
         return address_key_value;
     }
 
-    void SetAddressKey(VAddr key) {
-        address_key = key;
+    [[nodiscard]] bool GetAddressKeyIsKernel() const {
+        return address_key_is_kernel;
     }
 
-    void SetAddressKey(VAddr key, u32 val) {
+    //! NB: intentional deviation from official kernel.
+    //
+    // Separate SetAddressKey into user and kernel versions
+    // to cope with arbitrary host pointers making their way
+    // into things.
+
+    void SetUserAddressKey(VAddr key) {
+        address_key = key;
+        address_key_is_kernel = false;
+    }
+
+    void SetUserAddressKey(VAddr key, u32 val) {
         address_key = key;
         address_key_value = val;
+        address_key_is_kernel = false;
+    }
+
+    void SetKernelAddressKey(VAddr key) {
+        address_key = key;
+        address_key_is_kernel = true;
     }
 
     void ClearWaitQueue() {
@@ -770,6 +787,7 @@ private:
     bool debug_attached{};
     s8 priority_inheritance_count{};
     bool resource_limit_release_hint{};
+    bool address_key_is_kernel{};
     StackParameters stack_parameters{};
     Common::SpinLock context_guard{};