summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/logging/backend.cpp50
-rw-r--r--src/common/logging/backend.h4
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/core.cpp5
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp147
-rw-r--r--src/core/hle/kernel/address_arbiter.h74
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/kernel/kernel.h26
-rw-r--r--src/core/hle/kernel/svc.cpp39
-rw-r--r--src/core/hle/kernel/thread.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp47
-rw-r--r--src/core/hle/kernel/vm_manager.h24
-rw-r--r--src/core/hle/service/audio/audout_u.cpp13
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/audio/errors.h15
-rw-r--r--src/core/memory.cpp6
-rw-r--r--src/tests/core/arm/arm_test_common.cpp6
-rw-r--r--src/video_core/engines/fermi_2d.cpp7
-rw-r--r--src/video_core/engines/fermi_2d.h2
-rw-r--r--src/video_core/engines/kepler_compute.cpp3
-rw-r--r--src/video_core/engines/kepler_compute.h3
-rw-r--r--src/video_core/engines/kepler_memory.h1
-rw-r--r--src/video_core/engines/maxwell_dma.cpp1
-rw-r--r--src/video_core/engines/maxwell_dma.h1
-rw-r--r--src/video_core/engines/shader_bytecode.h1
-rw-r--r--src/video_core/renderer_base.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h6
-rw-r--r--src/video_core/surface.cpp2
-rw-r--r--src/web_service/verify_login.h2
-rw-r--r--src/web_service/web_backend.cpp1
-rw-r--r--src/yuzu/debugger/wait_tree.cpp8
-rw-r--r--src/yuzu/debugger/wait_tree.h3
-rw-r--r--src/yuzu/main.cpp5
36 files changed, 326 insertions, 231 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index b369f199f..4462ff3fb 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -39,8 +39,10 @@ public:
39 Impl(Impl const&) = delete; 39 Impl(Impl const&) = delete;
40 const Impl& operator=(Impl const&) = delete; 40 const Impl& operator=(Impl const&) = delete;
41 41
42 void PushEntry(Entry e) { 42 void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
43 message_queue.Push(std::move(e)); 43 const char* function, std::string message) {
44 message_queue.Push(
45 CreateEntry(log_class, log_level, filename, line_num, function, std::move(message)));
44 } 46 }
45 47
46 void AddBackend(std::unique_ptr<Backend> backend) { 48 void AddBackend(std::unique_ptr<Backend> backend) {
@@ -108,11 +110,30 @@ private:
108 backend_thread.join(); 110 backend_thread.join();
109 } 111 }
110 112
113 Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
114 const char* function, std::string message) const {
115 using std::chrono::duration_cast;
116 using std::chrono::steady_clock;
117
118 Entry entry;
119 entry.timestamp =
120 duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
121 entry.log_class = log_class;
122 entry.log_level = log_level;
123 entry.filename = Common::TrimSourcePath(filename);
124 entry.line_num = line_nr;
125 entry.function = function;
126 entry.message = std::move(message);
127
128 return entry;
129 }
130
111 std::mutex writing_mutex; 131 std::mutex writing_mutex;
112 std::thread backend_thread; 132 std::thread backend_thread;
113 std::vector<std::unique_ptr<Backend>> backends; 133 std::vector<std::unique_ptr<Backend>> backends;
114 Common::MPSCQueue<Log::Entry> message_queue; 134 Common::MPSCQueue<Log::Entry> message_queue;
115 Filter filter; 135 Filter filter;
136 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
116}; 137};
117 138
118void ConsoleBackend::Write(const Entry& entry) { 139void ConsoleBackend::Write(const Entry& entry) {
@@ -271,25 +292,6 @@ const char* GetLevelName(Level log_level) {
271#undef LVL 292#undef LVL
272} 293}
273 294
274Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
275 const char* function, std::string message) {
276 using std::chrono::duration_cast;
277 using std::chrono::steady_clock;
278
279 static steady_clock::time_point time_origin = steady_clock::now();
280
281 Entry entry;
282 entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
283 entry.log_class = log_class;
284 entry.log_level = log_level;
285 entry.filename = Common::TrimSourcePath(filename);
286 entry.line_num = line_nr;
287 entry.function = function;
288 entry.message = std::move(message);
289
290 return entry;
291}
292
293void SetGlobalFilter(const Filter& filter) { 295void SetGlobalFilter(const Filter& filter) {
294 Impl::Instance().SetGlobalFilter(filter); 296 Impl::Instance().SetGlobalFilter(filter);
295} 297}
@@ -314,9 +316,7 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
314 if (!filter.CheckMessage(log_class, log_level)) 316 if (!filter.CheckMessage(log_class, log_level))
315 return; 317 return;
316 318
317 Entry entry = 319 instance.PushEntry(log_class, log_level, filename, line_num, function,
318 CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); 320 fmt::vformat(format, args));
319
320 instance.PushEntry(std::move(entry));
321} 321}
322} // namespace Log 322} // namespace Log
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index a31ee6968..fca0267a1 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -135,10 +135,6 @@ const char* GetLogClassName(Class log_class);
135 */ 135 */
136const char* GetLevelName(Level log_level); 136const char* GetLevelName(Level log_level);
137 137
138/// Creates a log entry by formatting the given source location, and message.
139Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
140 const char* function, std::string message);
141
142/** 138/**
143 * The global filter will prevent any messages from even being processed if they are filtered. Each 139 * The global filter will prevent any messages from even being processed if they are filtered. Each
144 * backend can have a filter, but if the level is lower than the global filter, the backend will 140 * backend can have a filter, but if the level is lower than the global filter, the backend will
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 988356c65..8ccb2d5f0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -217,6 +217,7 @@ add_library(core STATIC
217 hle/service/audio/audren_u.h 217 hle/service/audio/audren_u.h
218 hle/service/audio/codecctl.cpp 218 hle/service/audio/codecctl.cpp
219 hle/service/audio/codecctl.h 219 hle/service/audio/codecctl.h
220 hle/service/audio/errors.h
220 hle/service/audio/hwopus.cpp 221 hle/service/audio/hwopus.cpp
221 hle/service/audio/hwopus.h 222 hle/service/audio/hwopus.h
222 hle/service/bcat/bcat.cpp 223 hle/service/bcat/bcat.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 3f4e9c3a8..d741ef90d 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -78,6 +78,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
78 return vfs->OpenFile(path, FileSys::Mode::Read); 78 return vfs->OpenFile(path, FileSys::Mode::Read);
79} 79}
80struct System::Impl { 80struct System::Impl {
81 explicit Impl(System& system) : kernel{system} {}
81 82
82 Cpu& CurrentCpuCore() { 83 Cpu& CurrentCpuCore() {
83 return cpu_core_manager.GetCurrentCore(); 84 return cpu_core_manager.GetCurrentCore();
@@ -95,7 +96,7 @@ struct System::Impl {
95 LOG_DEBUG(HW_Memory, "initialized OK"); 96 LOG_DEBUG(HW_Memory, "initialized OK");
96 97
97 core_timing.Initialize(); 98 core_timing.Initialize();
98 kernel.Initialize(core_timing); 99 kernel.Initialize();
99 100
100 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 101 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
101 std::chrono::system_clock::now().time_since_epoch()); 102 std::chrono::system_clock::now().time_since_epoch());
@@ -265,7 +266,7 @@ struct System::Impl {
265 Core::FrameLimiter frame_limiter; 266 Core::FrameLimiter frame_limiter;
266}; 267};
267 268
268System::System() : impl{std::make_unique<Impl>()} {} 269System::System() : impl{std::make_unique<Impl>(*this)} {}
269System::~System() = default; 270System::~System() = default;
270 271
271Cpu& System::CurrentCpuCore() { 272Cpu& System::CurrentCpuCore() {
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index a250d088d..9780a7849 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/core_cpu.h" 11#include "core/core_cpu.h"
12#include "core/hle/kernel/address_arbiter.h"
12#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/object.h" 14#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
@@ -17,58 +18,16 @@
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18#include "core/memory.h" 19#include "core/memory.h"
19 20
20namespace Kernel::AddressArbiter { 21namespace Kernel {
21 22namespace {
22// Performs actual address waiting logic.
23static ResultCode WaitForAddress(VAddr address, s64 timeout) {
24 SharedPtr<Thread> current_thread = GetCurrentThread();
25 current_thread->SetArbiterWaitAddress(address);
26 current_thread->SetStatus(ThreadStatus::WaitArb);
27 current_thread->InvalidateWakeupCallback();
28
29 current_thread->WakeAfterDelay(timeout);
30
31 Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
32 return RESULT_TIMEOUT;
33}
34
35// Gets the threads waiting on an address.
36static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) {
37 const auto RetrieveWaitingThreads = [](std::size_t core_index,
38 std::vector<SharedPtr<Thread>>& waiting_threads,
39 VAddr arb_addr) {
40 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
41 const auto& thread_list = scheduler.GetThreadList();
42
43 for (const auto& thread : thread_list) {
44 if (thread->GetArbiterWaitAddress() == arb_addr)
45 waiting_threads.push_back(thread);
46 }
47 };
48
49 // Retrieve all threads that are waiting for this address.
50 std::vector<SharedPtr<Thread>> threads;
51 RetrieveWaitingThreads(0, threads, address);
52 RetrieveWaitingThreads(1, threads, address);
53 RetrieveWaitingThreads(2, threads, address);
54 RetrieveWaitingThreads(3, threads, address);
55
56 // Sort them by priority, such that the highest priority ones come first.
57 std::sort(threads.begin(), threads.end(),
58 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
59 return lhs->GetPriority() < rhs->GetPriority();
60 });
61
62 return threads;
63}
64
65// Wake up num_to_wake (or all) threads in a vector. 23// Wake up num_to_wake (or all) threads in a vector.
66static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { 24void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {
67 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process 25 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
68 // them all. 26 // them all.
69 std::size_t last = waiting_threads.size(); 27 std::size_t last = waiting_threads.size();
70 if (num_to_wake > 0) 28 if (num_to_wake > 0) {
71 last = num_to_wake; 29 last = num_to_wake;
30 }
72 31
73 // Signal the waiting threads. 32 // Signal the waiting threads.
74 for (std::size_t i = 0; i < last; i++) { 33 for (std::size_t i = 0; i < last; i++) {
@@ -78,42 +37,41 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
78 waiting_threads[i]->ResumeFromWait(); 37 waiting_threads[i]->ResumeFromWait();
79 } 38 }
80} 39}
40} // Anonymous namespace
81 41
82// Signals an address being waited on. 42AddressArbiter::AddressArbiter(Core::System& system) : system{system} {}
83ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { 43AddressArbiter::~AddressArbiter() = default;
84 std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
85 44
45ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) {
46 const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
86 WakeThreads(waiting_threads, num_to_wake); 47 WakeThreads(waiting_threads, num_to_wake);
87 return RESULT_SUCCESS; 48 return RESULT_SUCCESS;
88} 49}
89 50
90// Signals an address being waited on and increments its value if equal to the value argument. 51ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
91ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { 52 s32 num_to_wake) {
92 // Ensure that we can write to the address. 53 // Ensure that we can write to the address.
93 if (!Memory::IsValidVirtualAddress(address)) { 54 if (!Memory::IsValidVirtualAddress(address)) {
94 return ERR_INVALID_ADDRESS_STATE; 55 return ERR_INVALID_ADDRESS_STATE;
95 } 56 }
96 57
97 if (static_cast<s32>(Memory::Read32(address)) == value) { 58 if (static_cast<s32>(Memory::Read32(address)) != value) {
98 Memory::Write32(address, static_cast<u32>(value + 1));
99 } else {
100 return ERR_INVALID_STATE; 59 return ERR_INVALID_STATE;
101 } 60 }
102 61
62 Memory::Write32(address, static_cast<u32>(value + 1));
103 return SignalToAddress(address, num_to_wake); 63 return SignalToAddress(address, num_to_wake);
104} 64}
105 65
106// Signals an address being waited on and modifies its value based on waiting thread count if equal 66ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
107// to the value argument. 67 s32 num_to_wake) {
108ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
109 s32 num_to_wake) {
110 // Ensure that we can write to the address. 68 // Ensure that we can write to the address.
111 if (!Memory::IsValidVirtualAddress(address)) { 69 if (!Memory::IsValidVirtualAddress(address)) {
112 return ERR_INVALID_ADDRESS_STATE; 70 return ERR_INVALID_ADDRESS_STATE;
113 } 71 }
114 72
115 // Get threads waiting on the address. 73 // Get threads waiting on the address.
116 std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); 74 const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
117 75
118 // Determine the modified value depending on the waiting count. 76 // Determine the modified value depending on the waiting count.
119 s32 updated_value; 77 s32 updated_value;
@@ -125,31 +83,31 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
125 updated_value = value; 83 updated_value = value;
126 } 84 }
127 85
128 if (static_cast<s32>(Memory::Read32(address)) == value) { 86 if (static_cast<s32>(Memory::Read32(address)) != value) {
129 Memory::Write32(address, static_cast<u32>(updated_value));
130 } else {
131 return ERR_INVALID_STATE; 87 return ERR_INVALID_STATE;
132 } 88 }
133 89
90 Memory::Write32(address, static_cast<u32>(updated_value));
134 WakeThreads(waiting_threads, num_to_wake); 91 WakeThreads(waiting_threads, num_to_wake);
135 return RESULT_SUCCESS; 92 return RESULT_SUCCESS;
136} 93}
137 94
138// Waits on an address if the value passed is less than the argument value, optionally decrementing. 95ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
139ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { 96 bool should_decrement) {
140 // Ensure that we can read the address. 97 // Ensure that we can read the address.
141 if (!Memory::IsValidVirtualAddress(address)) { 98 if (!Memory::IsValidVirtualAddress(address)) {
142 return ERR_INVALID_ADDRESS_STATE; 99 return ERR_INVALID_ADDRESS_STATE;
143 } 100 }
144 101
145 s32 cur_value = static_cast<s32>(Memory::Read32(address)); 102 const s32 cur_value = static_cast<s32>(Memory::Read32(address));
146 if (cur_value < value) { 103 if (cur_value >= value) {
147 if (should_decrement) {
148 Memory::Write32(address, static_cast<u32>(cur_value - 1));
149 }
150 } else {
151 return ERR_INVALID_STATE; 104 return ERR_INVALID_STATE;
152 } 105 }
106
107 if (should_decrement) {
108 Memory::Write32(address, static_cast<u32>(cur_value - 1));
109 }
110
153 // Short-circuit without rescheduling, if timeout is zero. 111 // Short-circuit without rescheduling, if timeout is zero.
154 if (timeout == 0) { 112 if (timeout == 0) {
155 return RESULT_TIMEOUT; 113 return RESULT_TIMEOUT;
@@ -158,8 +116,7 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool
158 return WaitForAddress(address, timeout); 116 return WaitForAddress(address, timeout);
159} 117}
160 118
161// Waits on an address if the value passed is equal to the argument value. 119ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
162ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
163 // Ensure that we can read the address. 120 // Ensure that we can read the address.
164 if (!Memory::IsValidVirtualAddress(address)) { 121 if (!Memory::IsValidVirtualAddress(address)) {
165 return ERR_INVALID_ADDRESS_STATE; 122 return ERR_INVALID_ADDRESS_STATE;
@@ -175,4 +132,46 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
175 132
176 return WaitForAddress(address, timeout); 133 return WaitForAddress(address, timeout);
177} 134}
178} // namespace Kernel::AddressArbiter 135
136ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) {
137 SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread();
138 current_thread->SetArbiterWaitAddress(address);
139 current_thread->SetStatus(ThreadStatus::WaitArb);
140 current_thread->InvalidateWakeupCallback();
141
142 current_thread->WakeAfterDelay(timeout);
143
144 system.CpuCore(current_thread->GetProcessorID()).PrepareReschedule();
145 return RESULT_TIMEOUT;
146}
147
148std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const {
149 const auto RetrieveWaitingThreads = [this](std::size_t core_index,
150 std::vector<SharedPtr<Thread>>& waiting_threads,
151 VAddr arb_addr) {
152 const auto& scheduler = system.Scheduler(core_index);
153 const auto& thread_list = scheduler.GetThreadList();
154
155 for (const auto& thread : thread_list) {
156 if (thread->GetArbiterWaitAddress() == arb_addr) {
157 waiting_threads.push_back(thread);
158 }
159 }
160 };
161
162 // Retrieve all threads that are waiting for this address.
163 std::vector<SharedPtr<Thread>> threads;
164 RetrieveWaitingThreads(0, threads, address);
165 RetrieveWaitingThreads(1, threads, address);
166 RetrieveWaitingThreads(2, threads, address);
167 RetrieveWaitingThreads(3, threads, address);
168
169 // Sort them by priority, such that the highest priority ones come first.
170 std::sort(threads.begin(), threads.end(),
171 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
172 return lhs->GetPriority() < rhs->GetPriority();
173 });
174
175 return threads;
176}
177} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index b58f21bec..e0c36f2e3 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -5,28 +5,68 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/address_arbiter.h"
8 9
9union ResultCode; 10union ResultCode;
10 11
11namespace Kernel::AddressArbiter { 12namespace Core {
13class System;
14}
12 15
13enum class ArbitrationType { 16namespace Kernel {
14 WaitIfLessThan = 0,
15 DecrementAndWaitIfLessThan = 1,
16 WaitIfEqual = 2,
17};
18 17
19enum class SignalType { 18class Thread;
20 Signal = 0, 19
21 IncrementAndSignalIfEqual = 1, 20class AddressArbiter {
22 ModifyByWaitingCountAndSignalIfEqual = 2, 21public:
23}; 22 enum class ArbitrationType {
23 WaitIfLessThan = 0,
24 DecrementAndWaitIfLessThan = 1,
25 WaitIfEqual = 2,
26 };
27
28 enum class SignalType {
29 Signal = 0,
30 IncrementAndSignalIfEqual = 1,
31 ModifyByWaitingCountAndSignalIfEqual = 2,
32 };
33
34 explicit AddressArbiter(Core::System& system);
35 ~AddressArbiter();
36
37 AddressArbiter(const AddressArbiter&) = delete;
38 AddressArbiter& operator=(const AddressArbiter&) = delete;
39
40 AddressArbiter(AddressArbiter&&) = default;
41 AddressArbiter& operator=(AddressArbiter&&) = delete;
24 42
25ResultCode SignalToAddress(VAddr address, s32 num_to_wake); 43 /// Signals an address being waited on.
26ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); 44 ResultCode SignalToAddress(VAddr address, s32 num_to_wake);
27ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
28 45
29ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); 46 /// Signals an address being waited on and increments its value if equal to the value argument.
30ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); 47 ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
48
49 /// Signals an address being waited on and modifies its value based on waiting thread count if
50 /// equal to the value argument.
51 ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
52 s32 num_to_wake);
53
54 /// Waits on an address if the value passed is less than the argument value,
55 /// optionally decrementing.
56 ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
57 bool should_decrement);
58
59 /// Waits on an address if the value passed is equal to the argument value.
60 ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
61
62private:
63 // Waits on the given address with a timeout in nanoseconds
64 ResultCode WaitForAddress(VAddr address, s64 timeout);
65
66 // Gets the threads waiting on an address.
67 std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
68
69 Core::System& system;
70};
31 71
32} // namespace Kernel::AddressArbiter 72} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index dd749eed4..04ea9349e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -12,6 +12,7 @@
12 12
13#include "core/core.h" 13#include "core/core.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/hle/kernel/address_arbiter.h"
15#include "core/hle/kernel/client_port.h" 16#include "core/hle/kernel/client_port.h"
16#include "core/hle/kernel/handle_table.h" 17#include "core/hle/kernel/handle_table.h"
17#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
@@ -86,11 +87,13 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
86} 87}
87 88
88struct KernelCore::Impl { 89struct KernelCore::Impl {
89 void Initialize(KernelCore& kernel, Core::Timing::CoreTiming& core_timing) { 90 explicit Impl(Core::System& system) : address_arbiter{system}, system{system} {}
91
92 void Initialize(KernelCore& kernel) {
90 Shutdown(); 93 Shutdown();
91 94
92 InitializeSystemResourceLimit(kernel); 95 InitializeSystemResourceLimit(kernel);
93 InitializeThreads(core_timing); 96 InitializeThreads();
94 } 97 }
95 98
96 void Shutdown() { 99 void Shutdown() {
@@ -122,9 +125,9 @@ struct KernelCore::Impl {
122 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); 125 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
123 } 126 }
124 127
125 void InitializeThreads(Core::Timing::CoreTiming& core_timing) { 128 void InitializeThreads() {
126 thread_wakeup_event_type = 129 thread_wakeup_event_type =
127 core_timing.RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); 130 system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
128 } 131 }
129 132
130 std::atomic<u32> next_object_id{0}; 133 std::atomic<u32> next_object_id{0};
@@ -135,6 +138,8 @@ struct KernelCore::Impl {
135 std::vector<SharedPtr<Process>> process_list; 138 std::vector<SharedPtr<Process>> process_list;
136 Process* current_process = nullptr; 139 Process* current_process = nullptr;
137 140
141 Kernel::AddressArbiter address_arbiter;
142
138 SharedPtr<ResourceLimit> system_resource_limit; 143 SharedPtr<ResourceLimit> system_resource_limit;
139 144
140 Core::Timing::EventType* thread_wakeup_event_type = nullptr; 145 Core::Timing::EventType* thread_wakeup_event_type = nullptr;
@@ -145,15 +150,18 @@ struct KernelCore::Impl {
145 /// Map of named ports managed by the kernel, which can be retrieved using 150 /// Map of named ports managed by the kernel, which can be retrieved using
146 /// the ConnectToPort SVC. 151 /// the ConnectToPort SVC.
147 NamedPortTable named_ports; 152 NamedPortTable named_ports;
153
154 // System context
155 Core::System& system;
148}; 156};
149 157
150KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {} 158KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
151KernelCore::~KernelCore() { 159KernelCore::~KernelCore() {
152 Shutdown(); 160 Shutdown();
153} 161}
154 162
155void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) { 163void KernelCore::Initialize() {
156 impl->Initialize(*this, core_timing); 164 impl->Initialize(*this);
157} 165}
158 166
159void KernelCore::Shutdown() { 167void KernelCore::Shutdown() {
@@ -184,6 +192,14 @@ const Process* KernelCore::CurrentProcess() const {
184 return impl->current_process; 192 return impl->current_process;
185} 193}
186 194
195AddressArbiter& KernelCore::AddressArbiter() {
196 return impl->address_arbiter;
197}
198
199const AddressArbiter& KernelCore::AddressArbiter() const {
200 return impl->address_arbiter;
201}
202
187void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { 203void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
188 impl->named_ports.emplace(std::move(name), std::move(port)); 204 impl->named_ports.emplace(std::move(name), std::move(port));
189} 205}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 154bced42..4d292aca9 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,6 +11,10 @@
11template <typename T> 11template <typename T>
12class ResultVal; 12class ResultVal;
13 13
14namespace Core {
15class System;
16}
17
14namespace Core::Timing { 18namespace Core::Timing {
15class CoreTiming; 19class CoreTiming;
16struct EventType; 20struct EventType;
@@ -18,6 +22,7 @@ struct EventType;
18 22
19namespace Kernel { 23namespace Kernel {
20 24
25class AddressArbiter;
21class ClientPort; 26class ClientPort;
22class HandleTable; 27class HandleTable;
23class Process; 28class Process;
@@ -30,7 +35,14 @@ private:
30 using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>; 35 using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>;
31 36
32public: 37public:
33 KernelCore(); 38 /// Constructs an instance of the kernel using the given System
39 /// instance as a context for any necessary system-related state,
40 /// such as threads, CPU core state, etc.
41 ///
42 /// @post After execution of the constructor, the provided System
43 /// object *must* outlive the kernel instance itself.
44 ///
45 explicit KernelCore(Core::System& system);
34 ~KernelCore(); 46 ~KernelCore();
35 47
36 KernelCore(const KernelCore&) = delete; 48 KernelCore(const KernelCore&) = delete;
@@ -40,11 +52,7 @@ public:
40 KernelCore& operator=(KernelCore&&) = delete; 52 KernelCore& operator=(KernelCore&&) = delete;
41 53
42 /// Resets the kernel to a clean slate for use. 54 /// Resets the kernel to a clean slate for use.
43 /// 55 void Initialize();
44 /// @param core_timing CoreTiming instance used to create any necessary
45 /// kernel-specific callback events.
46 ///
47 void Initialize(Core::Timing::CoreTiming& core_timing);
48 56
49 /// Clears all resources in use by the kernel instance. 57 /// Clears all resources in use by the kernel instance.
50 void Shutdown(); 58 void Shutdown();
@@ -67,6 +75,12 @@ public:
67 /// Retrieves a const pointer to the current process. 75 /// Retrieves a const pointer to the current process.
68 const Process* CurrentProcess() const; 76 const Process* CurrentProcess() const;
69 77
78 /// Provides a reference to the kernel's address arbiter.
79 Kernel::AddressArbiter& AddressArbiter();
80
81 /// Provides a const reference to the kernel's address arbiter.
82 const Kernel::AddressArbiter& AddressArbiter() const;
83
70 /// Adds a port to the named port table 84 /// Adds a port to the named port table
71 void AddNamedPort(std::string name, SharedPtr<ClientPort> port); 85 void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
72 86
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c5d399bab..75b88a333 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -47,23 +47,6 @@ constexpr bool IsValidAddressRange(VAddr address, u64 size) {
47 return address + size > address; 47 return address + size > address;
48} 48}
49 49
50// Checks if a given address range lies within a larger address range.
51constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin,
52 VAddr address_range_end) {
53 const VAddr end_address = address + size - 1;
54 return address_range_begin <= address && end_address <= address_range_end - 1;
55}
56
57bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) {
58 return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(),
59 vm.GetAddressSpaceEndAddress());
60}
61
62bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
63 return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(),
64 vm.GetNewMapRegionEndAddress());
65}
66
67// 8 GiB 50// 8 GiB
68constexpr u64 MAIN_MEMORY_SIZE = 0x200000000; 51constexpr u64 MAIN_MEMORY_SIZE = 0x200000000;
69 52
@@ -105,14 +88,14 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add
105 return ERR_INVALID_ADDRESS_STATE; 88 return ERR_INVALID_ADDRESS_STATE;
106 } 89 }
107 90
108 if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { 91 if (!vm_manager.IsWithinAddressSpace(src_addr, size)) {
109 LOG_ERROR(Kernel_SVC, 92 LOG_ERROR(Kernel_SVC,
110 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", 93 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
111 src_addr, size); 94 src_addr, size);
112 return ERR_INVALID_ADDRESS_STATE; 95 return ERR_INVALID_ADDRESS_STATE;
113 } 96 }
114 97
115 if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { 98 if (!vm_manager.IsWithinNewMapRegion(dst_addr, size)) {
116 LOG_ERROR(Kernel_SVC, 99 LOG_ERROR(Kernel_SVC,
117 "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}", 100 "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}",
118 dst_addr, size); 101 dst_addr, size);
@@ -238,7 +221,7 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
238 auto* const current_process = Core::CurrentProcess(); 221 auto* const current_process = Core::CurrentProcess();
239 auto& vm_manager = current_process->VMManager(); 222 auto& vm_manager = current_process->VMManager();
240 223
241 if (!IsInsideAddressSpace(vm_manager, addr, size)) { 224 if (!vm_manager.IsWithinAddressSpace(addr, size)) {
242 LOG_ERROR(Kernel_SVC, 225 LOG_ERROR(Kernel_SVC,
243 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 226 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
244 size); 227 size);
@@ -299,7 +282,7 @@ static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attr
299 } 282 }
300 283
301 auto& vm_manager = Core::CurrentProcess()->VMManager(); 284 auto& vm_manager = Core::CurrentProcess()->VMManager();
302 if (!IsInsideAddressSpace(vm_manager, address, size)) { 285 if (!vm_manager.IsWithinAddressSpace(address, size)) {
303 LOG_ERROR(Kernel_SVC, 286 LOG_ERROR(Kernel_SVC,
304 "Given address (0x{:016X}) is outside the bounds of the address space.", address); 287 "Given address (0x{:016X}) is outside the bounds of the address space.", address);
305 return ERR_INVALID_ADDRESS_STATE; 288 return ERR_INVALID_ADDRESS_STATE;
@@ -1495,13 +1478,14 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
1495 return ERR_INVALID_ADDRESS; 1478 return ERR_INVALID_ADDRESS;
1496 } 1479 }
1497 1480
1481 auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();
1498 switch (static_cast<AddressArbiter::ArbitrationType>(type)) { 1482 switch (static_cast<AddressArbiter::ArbitrationType>(type)) {
1499 case AddressArbiter::ArbitrationType::WaitIfLessThan: 1483 case AddressArbiter::ArbitrationType::WaitIfLessThan:
1500 return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); 1484 return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false);
1501 case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: 1485 case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan:
1502 return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); 1486 return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true);
1503 case AddressArbiter::ArbitrationType::WaitIfEqual: 1487 case AddressArbiter::ArbitrationType::WaitIfEqual:
1504 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); 1488 return address_arbiter.WaitForAddressIfEqual(address, value, timeout);
1505 default: 1489 default:
1506 LOG_ERROR(Kernel_SVC, 1490 LOG_ERROR(Kernel_SVC,
1507 "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " 1491 "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan "
@@ -1526,13 +1510,14 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1526 return ERR_INVALID_ADDRESS; 1510 return ERR_INVALID_ADDRESS;
1527 } 1511 }
1528 1512
1513 auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();
1529 switch (static_cast<AddressArbiter::SignalType>(type)) { 1514 switch (static_cast<AddressArbiter::SignalType>(type)) {
1530 case AddressArbiter::SignalType::Signal: 1515 case AddressArbiter::SignalType::Signal:
1531 return AddressArbiter::SignalToAddress(address, num_to_wake); 1516 return address_arbiter.SignalToAddress(address, num_to_wake);
1532 case AddressArbiter::SignalType::IncrementAndSignalIfEqual: 1517 case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
1533 return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); 1518 return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
1534 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: 1519 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
1535 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, 1520 return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
1536 num_to_wake); 1521 num_to_wake);
1537 default: 1522 default:
1538 LOG_ERROR(Kernel_SVC, 1523 LOG_ERROR(Kernel_SVC,
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 6661e2130..eb54d6651 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -184,8 +184,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
184 return ERR_INVALID_PROCESSOR_ID; 184 return ERR_INVALID_PROCESSOR_ID;
185 } 185 }
186 186
187 // TODO(yuriks): Other checks, returning 0xD9001BEA
188
189 if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) { 187 if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
190 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); 188 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
191 // TODO (bunnei): Find the correct error code to use here 189 // TODO (bunnei): Find the correct error code to use here
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 10ad94aa6..05c59af34 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -17,8 +17,8 @@
17#include "core/memory_setup.h" 17#include "core/memory_setup.h"
18 18
19namespace Kernel { 19namespace Kernel {
20 20namespace {
21static const char* GetMemoryStateName(MemoryState state) { 21const char* GetMemoryStateName(MemoryState state) {
22 static constexpr const char* names[] = { 22 static constexpr const char* names[] = {
23 "Unmapped", "Io", 23 "Unmapped", "Io",
24 "Normal", "CodeStatic", 24 "Normal", "CodeStatic",
@@ -35,6 +35,14 @@ static const char* GetMemoryStateName(MemoryState state) {
35 return names[ToSvcMemoryState(state)]; 35 return names[ToSvcMemoryState(state)];
36} 36}
37 37
38// Checks if a given address range lies within a larger address range.
39constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin,
40 VAddr address_range_end) {
41 const VAddr end_address = address + size - 1;
42 return address_range_begin <= address && end_address <= address_range_end - 1;
43}
44} // Anonymous namespace
45
38bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { 46bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
39 ASSERT(base + size == next.base); 47 ASSERT(base + size == next.base);
40 if (permissions != next.permissions || state != next.state || attribute != next.attribute || 48 if (permissions != next.permissions || state != next.state || attribute != next.attribute ||
@@ -249,8 +257,7 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
249} 257}
250 258
251ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 259ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
252 if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || 260 if (!IsWithinHeapRegion(target, size)) {
253 target + size < target) {
254 return ERR_INVALID_ADDRESS; 261 return ERR_INVALID_ADDRESS;
255 } 262 }
256 263
@@ -285,8 +292,7 @@ ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission p
285} 292}
286 293
287ResultCode VMManager::HeapFree(VAddr target, u64 size) { 294ResultCode VMManager::HeapFree(VAddr target, u64 size) {
288 if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || 295 if (!IsWithinHeapRegion(target, size)) {
289 target + size < target) {
290 return ERR_INVALID_ADDRESS; 296 return ERR_INVALID_ADDRESS;
291 } 297 }
292 298
@@ -706,6 +712,11 @@ u64 VMManager::GetAddressSpaceWidth() const {
706 return address_space_width; 712 return address_space_width;
707} 713}
708 714
715bool VMManager::IsWithinAddressSpace(VAddr address, u64 size) const {
716 return IsInsideAddressRange(address, size, GetAddressSpaceBaseAddress(),
717 GetAddressSpaceEndAddress());
718}
719
709VAddr VMManager::GetASLRRegionBaseAddress() const { 720VAddr VMManager::GetASLRRegionBaseAddress() const {
710 return aslr_region_base; 721 return aslr_region_base;
711} 722}
@@ -750,6 +761,11 @@ u64 VMManager::GetCodeRegionSize() const {
750 return code_region_end - code_region_base; 761 return code_region_end - code_region_base;
751} 762}
752 763
764bool VMManager::IsWithinCodeRegion(VAddr address, u64 size) const {
765 return IsInsideAddressRange(address, size, GetCodeRegionBaseAddress(),
766 GetCodeRegionEndAddress());
767}
768
753VAddr VMManager::GetHeapRegionBaseAddress() const { 769VAddr VMManager::GetHeapRegionBaseAddress() const {
754 return heap_region_base; 770 return heap_region_base;
755} 771}
@@ -762,6 +778,11 @@ u64 VMManager::GetHeapRegionSize() const {
762 return heap_region_end - heap_region_base; 778 return heap_region_end - heap_region_base;
763} 779}
764 780
781bool VMManager::IsWithinHeapRegion(VAddr address, u64 size) const {
782 return IsInsideAddressRange(address, size, GetHeapRegionBaseAddress(),
783 GetHeapRegionEndAddress());
784}
785
765VAddr VMManager::GetMapRegionBaseAddress() const { 786VAddr VMManager::GetMapRegionBaseAddress() const {
766 return map_region_base; 787 return map_region_base;
767} 788}
@@ -774,6 +795,10 @@ u64 VMManager::GetMapRegionSize() const {
774 return map_region_end - map_region_base; 795 return map_region_end - map_region_base;
775} 796}
776 797
798bool VMManager::IsWithinMapRegion(VAddr address, u64 size) const {
799 return IsInsideAddressRange(address, size, GetMapRegionBaseAddress(), GetMapRegionEndAddress());
800}
801
777VAddr VMManager::GetNewMapRegionBaseAddress() const { 802VAddr VMManager::GetNewMapRegionBaseAddress() const {
778 return new_map_region_base; 803 return new_map_region_base;
779} 804}
@@ -786,6 +811,11 @@ u64 VMManager::GetNewMapRegionSize() const {
786 return new_map_region_end - new_map_region_base; 811 return new_map_region_end - new_map_region_base;
787} 812}
788 813
814bool VMManager::IsWithinNewMapRegion(VAddr address, u64 size) const {
815 return IsInsideAddressRange(address, size, GetNewMapRegionBaseAddress(),
816 GetNewMapRegionEndAddress());
817}
818
789VAddr VMManager::GetTLSIORegionBaseAddress() const { 819VAddr VMManager::GetTLSIORegionBaseAddress() const {
790 return tls_io_region_base; 820 return tls_io_region_base;
791} 821}
@@ -798,4 +828,9 @@ u64 VMManager::GetTLSIORegionSize() const {
798 return tls_io_region_end - tls_io_region_base; 828 return tls_io_region_end - tls_io_region_base;
799} 829}
800 830
831bool VMManager::IsWithinTLSIORegion(VAddr address, u64 size) const {
832 return IsInsideAddressRange(address, size, GetTLSIORegionBaseAddress(),
833 GetTLSIORegionEndAddress());
834}
835
801} // namespace Kernel 836} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 6091533bc..88e0b3c02 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -432,18 +432,21 @@ public:
432 /// Gets the address space width in bits. 432 /// Gets the address space width in bits.
433 u64 GetAddressSpaceWidth() const; 433 u64 GetAddressSpaceWidth() const;
434 434
435 /// Determines whether or not the given address range lies within the address space.
436 bool IsWithinAddressSpace(VAddr address, u64 size) const;
437
435 /// Gets the base address of the ASLR region. 438 /// Gets the base address of the ASLR region.
436 VAddr GetASLRRegionBaseAddress() const; 439 VAddr GetASLRRegionBaseAddress() const;
437 440
438 /// Gets the end address of the ASLR region. 441 /// Gets the end address of the ASLR region.
439 VAddr GetASLRRegionEndAddress() const; 442 VAddr GetASLRRegionEndAddress() const;
440 443
441 /// Determines whether or not the specified address range is within the ASLR region.
442 bool IsWithinASLRRegion(VAddr address, u64 size) const;
443
444 /// Gets the size of the ASLR region 444 /// Gets the size of the ASLR region
445 u64 GetASLRRegionSize() const; 445 u64 GetASLRRegionSize() const;
446 446
447 /// Determines whether or not the specified address range is within the ASLR region.
448 bool IsWithinASLRRegion(VAddr address, u64 size) const;
449
447 /// Gets the base address of the code region. 450 /// Gets the base address of the code region.
448 VAddr GetCodeRegionBaseAddress() const; 451 VAddr GetCodeRegionBaseAddress() const;
449 452
@@ -453,6 +456,9 @@ public:
453 /// Gets the total size of the code region in bytes. 456 /// Gets the total size of the code region in bytes.
454 u64 GetCodeRegionSize() const; 457 u64 GetCodeRegionSize() const;
455 458
459 /// Determines whether or not the specified range is within the code region.
460 bool IsWithinCodeRegion(VAddr address, u64 size) const;
461
456 /// Gets the base address of the heap region. 462 /// Gets the base address of the heap region.
457 VAddr GetHeapRegionBaseAddress() const; 463 VAddr GetHeapRegionBaseAddress() const;
458 464
@@ -462,6 +468,9 @@ public:
462 /// Gets the total size of the heap region in bytes. 468 /// Gets the total size of the heap region in bytes.
463 u64 GetHeapRegionSize() const; 469 u64 GetHeapRegionSize() const;
464 470
471 /// Determines whether or not the specified range is within the heap region.
472 bool IsWithinHeapRegion(VAddr address, u64 size) const;
473
465 /// Gets the base address of the map region. 474 /// Gets the base address of the map region.
466 VAddr GetMapRegionBaseAddress() const; 475 VAddr GetMapRegionBaseAddress() const;
467 476
@@ -471,6 +480,9 @@ public:
471 /// Gets the total size of the map region in bytes. 480 /// Gets the total size of the map region in bytes.
472 u64 GetMapRegionSize() const; 481 u64 GetMapRegionSize() const;
473 482
483 /// Determines whether or not the specified range is within the map region.
484 bool IsWithinMapRegion(VAddr address, u64 size) const;
485
474 /// Gets the base address of the new map region. 486 /// Gets the base address of the new map region.
475 VAddr GetNewMapRegionBaseAddress() const; 487 VAddr GetNewMapRegionBaseAddress() const;
476 488
@@ -480,6 +492,9 @@ public:
480 /// Gets the total size of the new map region in bytes. 492 /// Gets the total size of the new map region in bytes.
481 u64 GetNewMapRegionSize() const; 493 u64 GetNewMapRegionSize() const;
482 494
495 /// Determines whether or not the given address range is within the new map region
496 bool IsWithinNewMapRegion(VAddr address, u64 size) const;
497
483 /// Gets the base address of the TLS IO region. 498 /// Gets the base address of the TLS IO region.
484 VAddr GetTLSIORegionBaseAddress() const; 499 VAddr GetTLSIORegionBaseAddress() const;
485 500
@@ -489,6 +504,9 @@ public:
489 /// Gets the total size of the TLS IO region in bytes. 504 /// Gets the total size of the TLS IO region in bytes.
490 u64 GetTLSIORegionSize() const; 505 u64 GetTLSIORegionSize() const;
491 506
507 /// Determines if the given address range is within the TLS IO region.
508 bool IsWithinTLSIORegion(VAddr address, u64 size) const;
509
492 /// Each VMManager has its own page table, which is set as the main one when the owning process 510 /// Each VMManager has its own page table, which is set as the main one when the owning process
493 /// is scheduled. 511 /// is scheduled.
494 Memory::PageTable page_table; 512 Memory::PageTable page_table;
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 6831c0735..bbe813490 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -18,17 +18,11 @@
18#include "core/hle/kernel/readable_event.h" 18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h" 19#include "core/hle/kernel/writable_event.h"
20#include "core/hle/service/audio/audout_u.h" 20#include "core/hle/service/audio/audout_u.h"
21#include "core/hle/service/audio/errors.h"
21#include "core/memory.h" 22#include "core/memory.h"
22 23
23namespace Service::Audio { 24namespace Service::Audio {
24 25
25namespace ErrCodes {
26enum {
27 ErrorUnknown = 2,
28 BufferCountExceeded = 8,
29};
30}
31
32constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; 26constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
33constexpr int DefaultSampleRate{48000}; 27constexpr int DefaultSampleRate{48000};
34 28
@@ -100,7 +94,7 @@ private:
100 94
101 if (stream->IsPlaying()) { 95 if (stream->IsPlaying()) {
102 IPC::ResponseBuilder rb{ctx, 2}; 96 IPC::ResponseBuilder rb{ctx, 2};
103 rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown)); 97 rb.Push(ERR_OPERATION_FAILED);
104 return; 98 return;
105 } 99 }
106 100
@@ -143,7 +137,8 @@ private:
143 137
144 if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) { 138 if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
145 IPC::ResponseBuilder rb{ctx, 2}; 139 IPC::ResponseBuilder rb{ctx, 2};
146 rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded)); 140 rb.Push(ERR_BUFFER_COUNT_EXCEEDED);
141 return;
147 } 142 }
148 143
149 IPC::ResponseBuilder rb{ctx, 2}; 144 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index ea8f9d0bb..c9de10a24 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -17,6 +17,7 @@
17#include "core/hle/kernel/readable_event.h" 17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h" 18#include "core/hle/kernel/writable_event.h"
19#include "core/hle/service/audio/audren_u.h" 19#include "core/hle/service/audio/audren_u.h"
20#include "core/hle/service/audio/errors.h"
20 21
21namespace Service::Audio { 22namespace Service::Audio {
22 23
@@ -146,7 +147,7 @@ private:
146 // code in this case. 147 // code in this case.
147 148
148 IPC::ResponseBuilder rb{ctx, 2}; 149 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(ResultCode{ErrorModule::Audio, 201}); 150 rb.Push(ERR_NOT_SUPPORTED);
150 } 151 }
151 152
152 Kernel::EventPair system_event; 153 Kernel::EventPair system_event;
diff --git a/src/core/hle/service/audio/errors.h b/src/core/hle/service/audio/errors.h
new file mode 100644
index 000000000..6f8c09bcf
--- /dev/null
+++ b/src/core/hle/service/audio/errors.h
@@ -0,0 +1,15 @@
1// Copyright 2019 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 Service::Audio {
10
11constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::Audio, 2};
12constexpr ResultCode ERR_BUFFER_COUNT_EXCEEDED{ErrorModule::Audio, 8};
13constexpr ResultCode ERR_NOT_SUPPORTED{ErrorModule::Audio, 513};
14
15} // namespace Service::Audio
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index f809567b6..ec279cef8 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -171,9 +171,6 @@ T Read(const VAddr vaddr) {
171 return value; 171 return value;
172 } 172 }
173 173
174 // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
175 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
176
177 PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; 174 PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
178 switch (type) { 175 switch (type) {
179 case PageType::Unmapped: 176 case PageType::Unmapped:
@@ -204,9 +201,6 @@ void Write(const VAddr vaddr, const T data) {
204 return; 201 return;
205 } 202 }
206 203
207 // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
208 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
209
210 PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; 204 PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
211 switch (type) { 205 switch (type) {
212 case PageType::Unmapped: 206 case PageType::Unmapped:
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 9b8a44fa1..ea27ef90d 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -13,11 +13,11 @@
13namespace ArmTests { 13namespace ArmTests {
14 14
15TestEnvironment::TestEnvironment(bool mutable_memory_) 15TestEnvironment::TestEnvironment(bool mutable_memory_)
16 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { 16 : mutable_memory(mutable_memory_),
17 17 test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
18 auto process = Kernel::Process::Create(kernel, ""); 18 auto process = Kernel::Process::Create(kernel, "");
19 kernel.MakeCurrentProcess(process.get()); 19 kernel.MakeCurrentProcess(process.get());
20 page_table = &Core::CurrentProcess()->VMManager().page_table; 20 page_table = &process->VMManager().page_table;
21 21
22 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); 22 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
23 page_table->special_regions.clear(); 23 page_table->special_regions.clear();
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 540dcc52c..03b7ee5d8 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -2,12 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h" 5#include "common/assert.h"
6#include "core/memory.h" 6#include "common/logging/log.h"
7#include "common/math_util.h"
7#include "video_core/engines/fermi_2d.h" 8#include "video_core/engines/fermi_2d.h"
8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/rasterizer_interface.h" 9#include "video_core/rasterizer_interface.h"
10#include "video_core/textures/decoders.h"
11 10
12namespace Tegra::Engines { 11namespace Tegra::Engines {
13 12
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index c69f74cc5..80523e320 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/assert.h" 8#include <cstddef>
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 4ca856b6b..b1d950460 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -2,9 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/memory.h"
8#include "video_core/engines/kepler_compute.h" 7#include "video_core/engines/kepler_compute.h"
9#include "video_core/memory_manager.h" 8#include "video_core/memory_manager.h"
10 9
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index df0a32e0f..6575afd0f 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -5,8 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/assert.h" 8#include <cstddef>
9#include "common/bit_field.h"
10#include "common/common_funcs.h" 9#include "common/common_funcs.h"
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "video_core/gpu.h" 11#include "video_core/gpu.h"
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index f680c2ad9..9181e9d80 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstddef>
8#include "common/bit_field.h" 9#include "common/bit_field.h"
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 529a14ec7..0474c7ba3 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/memory.h" 8#include "core/memory.h"
8#include "video_core/engines/maxwell_3d.h" 9#include "video_core/engines/maxwell_3d.h"
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index cf75aeb12..34c369320 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstddef>
8#include "common/bit_field.h" 9#include "common/bit_field.h"
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 252592edd..c7eb15b6a 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -6,7 +6,6 @@
6 6
7#include <bitset> 7#include <bitset>
8#include <optional> 8#include <optional>
9#include <string>
10#include <tuple> 9#include <tuple>
11#include <vector> 10#include <vector>
12 11
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 94223f45f..919d1f2d4 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
5#include "core/frontend/emu_window.h" 6#include "core/frontend/emu_window.h"
6#include "core/settings.h" 7#include "core/settings.h"
7#include "video_core/renderer_base.h" 8#include "video_core/renderer_base.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index c8c1d6911..321d9dd3d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -739,22 +739,10 @@ void RasterizerOpenGL::DrawArrays() {
739 state.Apply(); 739 state.Apply();
740 740
741 res_cache.SignalPreDrawCall(); 741 res_cache.SignalPreDrawCall();
742
743 // Execute draw call
744 params.DispatchDraw(); 742 params.DispatchDraw();
745
746 res_cache.SignalPostDrawCall(); 743 res_cache.SignalPostDrawCall();
747 744
748 // Disable scissor test
749 state.viewports[0].scissor.enabled = false;
750
751 accelerate_draw = AccelDraw::Disabled; 745 accelerate_draw = AccelDraw::Disabled;
752
753 // Unbind textures for potential future use as framebuffer attachments
754 for (auto& texture_unit : state.texture_units) {
755 texture_unit.Unbind();
756 }
757 state.Apply();
758} 746}
759 747
760void RasterizerOpenGL::FlushAll() {} 748void RasterizerOpenGL::FlushAll() {}
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 219f08053..9419326a3 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -461,7 +461,7 @@ void OpenGLState::ApplyTextures() const {
461 461
462 if (has_delta) { 462 if (has_delta) {
463 glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), 463 glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
464 textures.data()); 464 textures.data() + first);
465 } 465 }
466} 466}
467 467
@@ -482,7 +482,7 @@ void OpenGLState::ApplySamplers() const {
482 } 482 }
483 if (has_delta) { 483 if (has_delta) {
484 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), 484 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
485 samplers.data()); 485 samplers.data() + first);
486 } 486 }
487} 487}
488 488
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 18b7b94a1..4a33a6c84 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -8,7 +8,7 @@
8#include <tuple> 8#include <tuple>
9 9
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "core/core.h" 11#include "common/assert.h"
12#include "core/memory.h" 12#include "core/memory.h"
13#include "video_core/renderer_vulkan/declarations.h" 13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_buffer_cache.h" 14#include "video_core/renderer_vulkan/vk_buffer_cache.h"
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 6cbe21202..d8e916f31 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -44,9 +44,9 @@ struct CachedBufferEntry final : public RasterizerCacheObject {
44 44
45class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { 45class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
46public: 46public:
47 explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, VideoCore::RasterizerInterface& rasterizer, 47 explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
48 const VKDevice& device, VKMemoryManager& memory_manager, 48 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
49 VKScheduler& scheduler, u64 size); 49 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size);
50 ~VKBufferCache(); 50 ~VKBufferCache();
51 51
52 /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been 52 /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 044ba116a..a7ac26d71 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -89,8 +89,6 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
89 89
90PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { 90PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
91 switch (format) { 91 switch (format) {
92 // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
93 // gamma.
94 case Tegra::RenderTargetFormat::RGBA8_SRGB: 92 case Tegra::RenderTargetFormat::RGBA8_SRGB:
95 return PixelFormat::RGBA8_SRGB; 93 return PixelFormat::RGBA8_SRGB;
96 case Tegra::RenderTargetFormat::RGBA8_UNORM: 94 case Tegra::RenderTargetFormat::RGBA8_UNORM:
diff --git a/src/web_service/verify_login.h b/src/web_service/verify_login.h
index 39db32dbb..821b345d7 100644
--- a/src/web_service/verify_login.h
+++ b/src/web_service/verify_login.h
@@ -4,8 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <functional>
8#include <future>
9#include <string> 7#include <string>
10 8
11namespace WebService { 9namespace WebService {
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index b7737b615..40da1a4e2 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -10,7 +10,6 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/web_result.h" 12#include "common/web_result.h"
13#include "core/settings.h"
14#include "web_service/web_backend.h" 13#include "web_service/web_backend.h"
15 14
16namespace WebService { 15namespace WebService {
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index f50225d5f..06ad74ffe 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -81,9 +81,8 @@ QString WaitTreeText::GetText() const {
81 return text; 81 return text;
82} 82}
83 83
84WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) { 84WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table)
85 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 85 : mutex_address(mutex_address) {
86
87 mutex_value = Memory::Read32(mutex_address); 86 mutex_value = Memory::Read32(mutex_address);
88 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask); 87 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
89 owner = handle_table.Get<Kernel::Thread>(owner_handle); 88 owner = handle_table.Get<Kernel::Thread>(owner_handle);
@@ -316,7 +315,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
316 315
317 const VAddr mutex_wait_address = thread.GetMutexWaitAddress(); 316 const VAddr mutex_wait_address = thread.GetMutexWaitAddress();
318 if (mutex_wait_address != 0) { 317 if (mutex_wait_address != 0) {
319 list.push_back(std::make_unique<WaitTreeMutexInfo>(mutex_wait_address)); 318 const auto& handle_table = thread.GetOwnerProcess()->GetHandleTable();
319 list.push_back(std::make_unique<WaitTreeMutexInfo>(mutex_wait_address, handle_table));
320 } else { 320 } else {
321 list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); 321 list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
322 } 322 }
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 365c3dbfe..62886609d 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -17,6 +17,7 @@
17class EmuThread; 17class EmuThread;
18 18
19namespace Kernel { 19namespace Kernel {
20class HandleTable;
20class ReadableEvent; 21class ReadableEvent;
21class WaitObject; 22class WaitObject;
22class Thread; 23class Thread;
@@ -72,7 +73,7 @@ public:
72class WaitTreeMutexInfo : public WaitTreeExpandableItem { 73class WaitTreeMutexInfo : public WaitTreeExpandableItem {
73 Q_OBJECT 74 Q_OBJECT
74public: 75public:
75 explicit WaitTreeMutexInfo(VAddr mutex_address); 76 explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table);
76 ~WaitTreeMutexInfo() override; 77 ~WaitTreeMutexInfo() override;
77 78
78 QString GetText() const override; 79 QString GetText() const override;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 62aafd1d7..0f5a14841 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -561,7 +561,10 @@ void GMainWindow::InitializeHotkeys() {
561 Settings::values.use_frame_limit = !Settings::values.use_frame_limit; 561 Settings::values.use_frame_limit = !Settings::values.use_frame_limit;
562 UpdateStatusBar(); 562 UpdateStatusBar();
563 }); 563 });
564 constexpr u16 SPEED_LIMIT_STEP = 5; 564 // TODO: Remove this comment/static whenever the next major release of
565 // MSVC occurs and we make it a requirement (see:
566 // https://developercommunity.visualstudio.com/content/problem/93922/constexprs-are-trying-to-be-captured-in-lambda-fun.html)
567 static constexpr u16 SPEED_LIMIT_STEP = 5;
565 connect(hotkey_registry.GetHotkey("Main Window", "Increase Speed Limit", this), 568 connect(hotkey_registry.GetHotkey("Main Window", "Increase Speed Limit", this),
566 &QShortcut::activated, this, [&] { 569 &QShortcut::activated, this, [&] {
567 if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) { 570 if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) {