summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp173
-rw-r--r--src/core/hle/kernel/address_arbiter.h32
-rw-r--r--src/core/hle/kernel/errors.h12
-rw-r--r--src/core/hle/kernel/mutex.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp59
-rw-r--r--src/core/hle/kernel/svc_wrap.h14
-rw-r--r--src/core/hle/kernel/thread.cpp6
-rw-r--r--src/core/hle/kernel/thread.h4
-rw-r--r--src/core/memory.cpp4
-rw-r--r--src/core/memory.h7
-rw-r--r--src/yuzu/debugger/wait_tree.cpp4
12 files changed, 312 insertions, 9 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f09edb817..51e4088d2 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -40,6 +40,8 @@ add_library(core STATIC
40 hle/config_mem.h 40 hle/config_mem.h
41 hle/ipc.h 41 hle/ipc.h
42 hle/ipc_helpers.h 42 hle/ipc_helpers.h
43 hle/kernel/address_arbiter.cpp
44 hle/kernel/address_arbiter.h
43 hle/kernel/client_port.cpp 45 hle/kernel/client_port.cpp
44 hle/kernel/client_port.h 46 hle/kernel/client_port.h
45 hle/kernel/client_session.cpp 47 hle/kernel/client_session.cpp
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
new file mode 100644
index 000000000..e9c8369d7
--- /dev/null
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -0,0 +1,173 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8#include "core/core.h"
9#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/process.h"
12#include "core/hle/kernel/thread.h"
13#include "core/hle/lock.h"
14#include "core/memory.h"
15
16namespace Kernel {
17namespace AddressArbiter {
18
19// Performs actual address waiting logic.
20static ResultCode WaitForAddress(VAddr address, s64 timeout) {
21 SharedPtr<Thread> current_thread = GetCurrentThread();
22 current_thread->arb_wait_address = address;
23 current_thread->status = THREADSTATUS_WAIT_ARB;
24 current_thread->wakeup_callback = nullptr;
25
26 current_thread->WakeAfterDelay(timeout);
27
28 Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
29 return RESULT_TIMEOUT;
30}
31
32// Gets the threads waiting on an address.
33static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads,
34 VAddr address) {
35 auto RetrieveWaitingThreads =
36 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
37 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
38 auto& thread_list = scheduler->GetThreadList();
39
40 for (auto& thread : thread_list) {
41 if (thread->arb_wait_address == arb_addr)
42 waiting_threads.push_back(thread);
43 }
44 };
45
46 // Retrieve a list of all threads that are waiting for this address.
47 RetrieveWaitingThreads(0, waiting_threads, address);
48 RetrieveWaitingThreads(1, waiting_threads, address);
49 RetrieveWaitingThreads(2, waiting_threads, address);
50 RetrieveWaitingThreads(3, waiting_threads, address);
51 // Sort them by priority, such that the highest priority ones come first.
52 std::sort(waiting_threads.begin(), waiting_threads.end(),
53 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
54 return lhs->current_priority < rhs->current_priority;
55 });
56}
57
58// Wake up num_to_wake (or all) threads in a vector.
59static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {
60 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
61 // them all.
62 size_t last = waiting_threads.size();
63 if (num_to_wake > 0)
64 last = num_to_wake;
65
66 // Signal the waiting threads.
67 for (size_t i = 0; i < last; i++) {
68 ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB);
69 waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
70 waiting_threads[i]->arb_wait_address = 0;
71 waiting_threads[i]->ResumeFromWait();
72 }
73}
74
75// Signals an address being waited on.
76ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
77 // Get threads waiting on the address.
78 std::vector<SharedPtr<Thread>> waiting_threads;
79 GetThreadsWaitingOnAddress(waiting_threads, address);
80
81 WakeThreads(waiting_threads, num_to_wake);
82 return RESULT_SUCCESS;
83}
84
85// Signals an address being waited on and increments its value if equal to the value argument.
86ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) {
87 // Ensure that we can write to the address.
88 if (!Memory::IsValidVirtualAddress(address)) {
89 return ERR_INVALID_ADDRESS_STATE;
90 }
91
92 if (static_cast<s32>(Memory::Read32(address)) == value) {
93 Memory::Write32(address, static_cast<u32>(value + 1));
94 } else {
95 return ERR_INVALID_STATE;
96 }
97
98 return SignalToAddress(address, num_to_wake);
99}
100
101// Signals an address being waited on and modifies its value based on waiting thread count if equal
102// to the value argument.
103ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
104 s32 num_to_wake) {
105 // Ensure that we can write to the address.
106 if (!Memory::IsValidVirtualAddress(address)) {
107 return ERR_INVALID_ADDRESS_STATE;
108 }
109
110 // Get threads waiting on the address.
111 std::vector<SharedPtr<Thread>> waiting_threads;
112 GetThreadsWaitingOnAddress(waiting_threads, address);
113
114 // Determine the modified value depending on the waiting count.
115 s32 updated_value;
116 if (waiting_threads.size() == 0) {
117 updated_value = value - 1;
118 } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) {
119 updated_value = value + 1;
120 } else {
121 updated_value = value;
122 }
123
124 if (static_cast<s32>(Memory::Read32(address)) == value) {
125 Memory::Write32(address, static_cast<u32>(updated_value));
126 } else {
127 return ERR_INVALID_STATE;
128 }
129
130 WakeThreads(waiting_threads, num_to_wake);
131 return RESULT_SUCCESS;
132}
133
134// Waits on an address if the value passed is less than the argument value, optionally decrementing.
135ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) {
136 // Ensure that we can read the address.
137 if (!Memory::IsValidVirtualAddress(address)) {
138 return ERR_INVALID_ADDRESS_STATE;
139 }
140
141 s32 cur_value = static_cast<s32>(Memory::Read32(address));
142 if (cur_value < value) {
143 Memory::Write32(address, static_cast<u32>(cur_value - 1));
144 } else {
145 return ERR_INVALID_STATE;
146 }
147 // Short-circuit without rescheduling, if timeout is zero.
148 if (timeout == 0) {
149 return RESULT_TIMEOUT;
150 }
151
152 return WaitForAddress(address, timeout);
153}
154
155// Waits on an address if the value passed is equal to the argument value.
156ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
157 // Ensure that we can read the address.
158 if (!Memory::IsValidVirtualAddress(address)) {
159 return ERR_INVALID_ADDRESS_STATE;
160 }
161 // Only wait for the address if equal.
162 if (static_cast<s32>(Memory::Read32(address)) != value) {
163 return ERR_INVALID_STATE;
164 }
165 // Short-circuit without rescheduling, if timeout is zero.
166 if (timeout == 0) {
167 return RESULT_TIMEOUT;
168 }
169
170 return WaitForAddress(address, timeout);
171}
172} // namespace AddressArbiter
173} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
new file mode 100644
index 000000000..f20f3dbc0
--- /dev/null
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -0,0 +1,32 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/result.h"
8
9namespace Kernel {
10
11namespace AddressArbiter {
12enum class ArbitrationType {
13 WaitIfLessThan = 0,
14 DecrementAndWaitIfLessThan = 1,
15 WaitIfEqual = 2,
16};
17
18enum class SignalType {
19 Signal = 0,
20 IncrementAndSignalIfEqual = 1,
21 ModifyByWaitingCountAndSignalIfEqual = 2,
22};
23
24ResultCode SignalToAddress(VAddr address, s32 num_to_wake);
25ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
26ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
27
28ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement);
29ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
30} // namespace AddressArbiter
31
32} // namespace Kernel
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index e1b5430bf..221cb1bb5 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -20,13 +20,16 @@ enum {
20 MaxConnectionsReached = 52, 20 MaxConnectionsReached = 52,
21 21
22 // Confirmed Switch OS error codes 22 // Confirmed Switch OS error codes
23 MisalignedAddress = 102, 23 InvalidAddress = 102,
24 InvalidMemoryState = 106,
24 InvalidProcessorId = 113, 25 InvalidProcessorId = 113,
25 InvalidHandle = 114, 26 InvalidHandle = 114,
26 InvalidCombination = 116, 27 InvalidCombination = 116,
27 Timeout = 117, 28 Timeout = 117,
28 SynchronizationCanceled = 118, 29 SynchronizationCanceled = 118,
29 TooLarge = 119, 30 TooLarge = 119,
31 InvalidEnumValue = 120,
32 InvalidState = 125,
30}; 33};
31} 34}
32 35
@@ -39,14 +42,15 @@ constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1);
39constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1); 42constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1);
40constexpr ResultCode ERR_WRONG_PERMISSION(-1); 43constexpr ResultCode ERR_WRONG_PERMISSION(-1);
41constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); 44constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1);
42constexpr ResultCode ERR_INVALID_ENUM_VALUE(-1); 45constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue);
43constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1); 46constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1);
44constexpr ResultCode ERR_INVALID_COMBINATION(-1); 47constexpr ResultCode ERR_INVALID_COMBINATION(-1);
45constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1); 48constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1);
46constexpr ResultCode ERR_OUT_OF_MEMORY(-1); 49constexpr ResultCode ERR_OUT_OF_MEMORY(-1);
47constexpr ResultCode ERR_INVALID_ADDRESS(-1); 50constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
48constexpr ResultCode ERR_INVALID_ADDRESS_STATE(-1); 51constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
49constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 52constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
53constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
50constexpr ResultCode ERR_INVALID_POINTER(-1); 54constexpr ResultCode ERR_INVALID_POINTER(-1);
51constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); 55constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
52constexpr ResultCode ERR_NOT_AUTHORIZED(-1); 56constexpr ResultCode ERR_NOT_AUTHORIZED(-1);
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index bc144f3de..65560226d 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -59,7 +59,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
59 Handle requesting_thread_handle) { 59 Handle requesting_thread_handle) {
60 // The mutex address must be 4-byte aligned 60 // The mutex address must be 4-byte aligned
61 if ((address % sizeof(u32)) != 0) { 61 if ((address % sizeof(u32)) != 0) {
62 return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); 62 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
63 } 63 }
64 64
65 SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); 65 SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
@@ -97,7 +97,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
97ResultCode Mutex::Release(VAddr address) { 97ResultCode Mutex::Release(VAddr address) {
98 // The mutex address must be 4-byte aligned 98 // The mutex address must be 4-byte aligned
99 if ((address % sizeof(u32)) != 0) { 99 if ((address % sizeof(u32)) != 0) {
100 return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); 100 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
101 } 101 }
102 102
103 auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); 103 auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 69ba7b777..1a36e0d02 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -11,6 +11,7 @@
11#include "common/string_util.h" 11#include "common/string_util.h"
12#include "core/core.h" 12#include "core/core.h"
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/hle/kernel/address_arbiter.h"
14#include "core/hle/kernel/client_port.h" 15#include "core/hle/kernel/client_port.h"
15#include "core/hle/kernel/client_session.h" 16#include "core/hle/kernel/client_session.h"
16#include "core/hle/kernel/event.h" 17#include "core/hle/kernel/event.h"
@@ -580,7 +581,7 @@ static void SleepThread(s64 nanoseconds) {
580 Core::System::GetInstance().PrepareReschedule(); 581 Core::System::GetInstance().PrepareReschedule();
581} 582}
582 583
583/// Signal process wide key atomic 584/// Wait process wide key atomic
584static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, 585static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
585 Handle thread_handle, s64 nano_seconds) { 586 Handle thread_handle, s64 nano_seconds) {
586 NGLOG_TRACE( 587 NGLOG_TRACE(
@@ -689,6 +690,58 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
689 return RESULT_SUCCESS; 690 return RESULT_SUCCESS;
690} 691}
691 692
693// Wait for an address (via Address Arbiter)
694static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) {
695 NGLOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}",
696 address, type, value, timeout);
697 // If the passed address is a kernel virtual address, return invalid memory state.
698 if (Memory::IsKernelVirtualAddress(address)) {
699 return ERR_INVALID_ADDRESS_STATE;
700 }
701 // If the address is not properly aligned to 4 bytes, return invalid address.
702 if (address % sizeof(u32) != 0) {
703 return ERR_INVALID_ADDRESS;
704 }
705
706 switch (static_cast<AddressArbiter::ArbitrationType>(type)) {
707 case AddressArbiter::ArbitrationType::WaitIfLessThan:
708 return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false);
709 case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan:
710 return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true);
711 case AddressArbiter::ArbitrationType::WaitIfEqual:
712 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout);
713 default:
714 return ERR_INVALID_ENUM_VALUE;
715 }
716}
717
718// Signals to an address (via Address Arbiter)
719static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) {
720 NGLOG_WARNING(Kernel_SVC,
721 "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address,
722 type, value, num_to_wake);
723 // If the passed address is a kernel virtual address, return invalid memory state.
724 if (Memory::IsKernelVirtualAddress(address)) {
725 return ERR_INVALID_ADDRESS_STATE;
726 }
727 // If the address is not properly aligned to 4 bytes, return invalid address.
728 if (address % sizeof(u32) != 0) {
729 return ERR_INVALID_ADDRESS;
730 }
731
732 switch (static_cast<AddressArbiter::SignalType>(type)) {
733 case AddressArbiter::SignalType::Signal:
734 return AddressArbiter::SignalToAddress(address, num_to_wake);
735 case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
736 return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
737 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
738 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
739 num_to_wake);
740 default:
741 return ERR_INVALID_ENUM_VALUE;
742 }
743}
744
692/// This returns the total CPU ticks elapsed since the CPU was powered-on 745/// This returns the total CPU ticks elapsed since the CPU was powered-on
693static u64 GetSystemTick() { 746static u64 GetSystemTick() {
694 const u64 result{CoreTiming::GetTicks()}; 747 const u64 result{CoreTiming::GetTicks()};
@@ -861,8 +914,8 @@ static const FunctionDef SVC_Table[] = {
861 {0x31, nullptr, "GetResourceLimitCurrentValue"}, 914 {0x31, nullptr, "GetResourceLimitCurrentValue"},
862 {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, 915 {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
863 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, 916 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
864 {0x34, nullptr, "WaitForAddress"}, 917 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
865 {0x35, nullptr, "SignalToAddress"}, 918 {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"},
866 {0x36, nullptr, "Unknown"}, 919 {0x36, nullptr, "Unknown"},
867 {0x37, nullptr, "Unknown"}, 920 {0x37, nullptr, "Unknown"},
868 {0x38, nullptr, "Unknown"}, 921 {0x38, nullptr, "Unknown"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 40aa88cc1..79c3fe31b 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -179,6 +179,20 @@ void SvcWrap() {
179 FuncReturn(retval); 179 FuncReturn(retval);
180} 180}
181 181
182template <ResultCode func(u64, u32, s32, s64)>
183void SvcWrap() {
184 FuncReturn(
185 func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3))
186 .raw);
187}
188
189template <ResultCode func(u64, u32, s32, s32)>
190void SvcWrap() {
191 FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF),
192 (s32)(PARAM(3) & 0xFFFFFFFF))
193 .raw);
194}
195
182//////////////////////////////////////////////////////////////////////////////////////////////////// 196////////////////////////////////////////////////////////////////////////////////////////////////////
183// Function wrappers that return type u32 197// Function wrappers that return type u32
184 198
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index cffa7ca83..2f333ec34 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -140,6 +140,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
140 } 140 }
141 } 141 }
142 142
143 if (thread->arb_wait_address != 0) {
144 ASSERT(thread->status == THREADSTATUS_WAIT_ARB);
145 thread->arb_wait_address = 0;
146 }
147
143 if (resume) 148 if (resume)
144 thread->ResumeFromWait(); 149 thread->ResumeFromWait();
145} 150}
@@ -179,6 +184,7 @@ void Thread::ResumeFromWait() {
179 case THREADSTATUS_WAIT_SLEEP: 184 case THREADSTATUS_WAIT_SLEEP:
180 case THREADSTATUS_WAIT_IPC: 185 case THREADSTATUS_WAIT_IPC:
181 case THREADSTATUS_WAIT_MUTEX: 186 case THREADSTATUS_WAIT_MUTEX:
187 case THREADSTATUS_WAIT_ARB:
182 break; 188 break;
183 189
184 case THREADSTATUS_READY: 190 case THREADSTATUS_READY:
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 1d2da6d50..f1e759802 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -45,6 +45,7 @@ enum ThreadStatus {
45 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false 45 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
46 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true 46 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
47 THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc 47 THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc
48 THREADSTATUS_WAIT_ARB, ///< Waiting due to a SignalToAddress/WaitForAddress svc
48 THREADSTATUS_DORMANT, ///< Created but not yet made ready 49 THREADSTATUS_DORMANT, ///< Created but not yet made ready
49 THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated 50 THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
50}; 51};
@@ -230,6 +231,9 @@ public:
230 VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address 231 VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
231 Handle wait_handle; ///< The handle used to wait for the mutex. 232 Handle wait_handle; ///< The handle used to wait for the mutex.
232 233
234 // If waiting for an AddressArbiter, this is the address being waited on.
235 VAddr arb_wait_address{0};
236
233 std::string name; 237 std::string name;
234 238
235 /// Handle used by guest emulated application to access this thread 239 /// Handle used by guest emulated application to access this thread
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 3b81acd63..f070dee7d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -241,6 +241,10 @@ bool IsValidVirtualAddress(const VAddr vaddr) {
241 return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr); 241 return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr);
242} 242}
243 243
244bool IsKernelVirtualAddress(const VAddr vaddr) {
245 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
246}
247
244bool IsValidPhysicalAddress(const PAddr paddr) { 248bool IsValidPhysicalAddress(const PAddr paddr) {
245 return GetPhysicalPointer(paddr) != nullptr; 249 return GetPhysicalPointer(paddr) != nullptr;
246} 250}
diff --git a/src/core/memory.h b/src/core/memory.h
index 3f56a2c6a..8d5d017a4 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -188,6 +188,11 @@ enum : VAddr {
188 MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, 188 MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END,
189 MAP_REGION_SIZE = 0x1000000000, 189 MAP_REGION_SIZE = 0x1000000000,
190 MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, 190 MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE,
191
192 /// Kernel Virtual Address Range
193 KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
194 KERNEL_REGION_SIZE = 0x7FFFE00000,
195 KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
191}; 196};
192 197
193/// Currently active page table 198/// Currently active page table
@@ -197,6 +202,8 @@ PageTable* GetCurrentPageTable();
197/// Determines if the given VAddr is valid for the specified process. 202/// Determines if the given VAddr is valid for the specified process.
198bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr); 203bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr);
199bool IsValidVirtualAddress(const VAddr addr); 204bool IsValidVirtualAddress(const VAddr addr);
205/// Determines if the given VAddr is a kernel address
206bool IsKernelVirtualAddress(const VAddr addr);
200 207
201bool IsValidPhysicalAddress(const PAddr addr); 208bool IsValidPhysicalAddress(const PAddr addr);
202 209
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 017bef13c..7101b381e 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -213,6 +213,9 @@ QString WaitTreeThread::GetText() const {
213 case THREADSTATUS_WAIT_MUTEX: 213 case THREADSTATUS_WAIT_MUTEX:
214 status = tr("waiting for mutex"); 214 status = tr("waiting for mutex");
215 break; 215 break;
216 case THREADSTATUS_WAIT_ARB:
217 status = tr("waiting for address arbiter");
218 break;
216 case THREADSTATUS_DORMANT: 219 case THREADSTATUS_DORMANT:
217 status = tr("dormant"); 220 status = tr("dormant");
218 break; 221 break;
@@ -240,6 +243,7 @@ QColor WaitTreeThread::GetColor() const {
240 case THREADSTATUS_WAIT_SYNCH_ALL: 243 case THREADSTATUS_WAIT_SYNCH_ALL:
241 case THREADSTATUS_WAIT_SYNCH_ANY: 244 case THREADSTATUS_WAIT_SYNCH_ANY:
242 case THREADSTATUS_WAIT_MUTEX: 245 case THREADSTATUS_WAIT_MUTEX:
246 case THREADSTATUS_WAIT_ARB:
243 return QColor(Qt::GlobalColor::red); 247 return QColor(Qt::GlobalColor::red);
244 case THREADSTATUS_DORMANT: 248 case THREADSTATUS_DORMANT:
245 return QColor(Qt::GlobalColor::darkCyan); 249 return QColor(Qt::GlobalColor::darkCyan);