diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/ring_buffer.h | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_address_arbiter.cpp | 84 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 247 | ||||
| -rw-r--r-- | src/core/hle/service/lm/lm.cpp | 16 | ||||
| -rw-r--r-- | src/core/hle/service/ns/pl_u.cpp | 9 | ||||
| -rw-r--r-- | src/tests/common/ring_buffer.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/morton.cpp | 0 | ||||
| -rw-r--r-- | src/video_core/morton.h | 0 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 31 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | 26 |
12 files changed, 266 insertions, 182 deletions
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 138fa0131..4a8d09806 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h | |||
| @@ -19,15 +19,14 @@ namespace Common { | |||
| 19 | /// SPSC ring buffer | 19 | /// SPSC ring buffer |
| 20 | /// @tparam T Element type | 20 | /// @tparam T Element type |
| 21 | /// @tparam capacity Number of slots in ring buffer | 21 | /// @tparam capacity Number of slots in ring buffer |
| 22 | /// @tparam granularity Slot size in terms of number of elements | 22 | template <typename T, std::size_t capacity> |
| 23 | template <typename T, std::size_t capacity, std::size_t granularity = 1> | ||
| 24 | class RingBuffer { | 23 | class RingBuffer { |
| 25 | /// A "slot" is made of `granularity` elements of `T`. | 24 | /// A "slot" is made of a single `T`. |
| 26 | static constexpr std::size_t slot_size = granularity * sizeof(T); | 25 | static constexpr std::size_t slot_size = sizeof(T); |
| 27 | // T must be safely memcpy-able and have a trivial default constructor. | 26 | // T must be safely memcpy-able and have a trivial default constructor. |
| 28 | static_assert(std::is_trivial_v<T>); | 27 | static_assert(std::is_trivial_v<T>); |
| 29 | // Ensure capacity is sensible. | 28 | // Ensure capacity is sensible. |
| 30 | static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2 / granularity); | 29 | static_assert(capacity < std::numeric_limits<std::size_t>::max() / 2); |
| 31 | static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two"); | 30 | static_assert((capacity & (capacity - 1)) == 0, "capacity must be a power of two"); |
| 32 | // Ensure lock-free. | 31 | // Ensure lock-free. |
| 33 | static_assert(std::atomic_size_t::is_always_lock_free); | 32 | static_assert(std::atomic_size_t::is_always_lock_free); |
| @@ -47,7 +46,7 @@ public: | |||
| 47 | const std::size_t second_copy = push_count - first_copy; | 46 | const std::size_t second_copy = push_count - first_copy; |
| 48 | 47 | ||
| 49 | const char* in = static_cast<const char*>(new_slots); | 48 | const char* in = static_cast<const char*>(new_slots); |
| 50 | std::memcpy(m_data.data() + pos * granularity, in, first_copy * slot_size); | 49 | std::memcpy(m_data.data() + pos, in, first_copy * slot_size); |
| 51 | in += first_copy * slot_size; | 50 | in += first_copy * slot_size; |
| 52 | std::memcpy(m_data.data(), in, second_copy * slot_size); | 51 | std::memcpy(m_data.data(), in, second_copy * slot_size); |
| 53 | 52 | ||
| @@ -74,7 +73,7 @@ public: | |||
| 74 | const std::size_t second_copy = pop_count - first_copy; | 73 | const std::size_t second_copy = pop_count - first_copy; |
| 75 | 74 | ||
| 76 | char* out = static_cast<char*>(output); | 75 | char* out = static_cast<char*>(output); |
| 77 | std::memcpy(out, m_data.data() + pos * granularity, first_copy * slot_size); | 76 | std::memcpy(out, m_data.data() + pos, first_copy * slot_size); |
| 78 | out += first_copy * slot_size; | 77 | out += first_copy * slot_size; |
| 79 | std::memcpy(out, m_data.data(), second_copy * slot_size); | 78 | std::memcpy(out, m_data.data(), second_copy * slot_size); |
| 80 | 79 | ||
| @@ -84,9 +83,9 @@ public: | |||
| 84 | } | 83 | } |
| 85 | 84 | ||
| 86 | std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) { | 85 | std::vector<T> Pop(std::size_t max_slots = ~std::size_t(0)) { |
| 87 | std::vector<T> out(std::min(max_slots, capacity) * granularity); | 86 | std::vector<T> out(std::min(max_slots, capacity)); |
| 88 | const std::size_t count = Pop(out.data(), out.size() / granularity); | 87 | const std::size_t count = Pop(out.data(), out.size()); |
| 89 | out.resize(count * granularity); | 88 | out.resize(count); |
| 90 | return out; | 89 | return out; |
| 91 | } | 90 | } |
| 92 | 91 | ||
| @@ -113,7 +112,7 @@ private: | |||
| 113 | alignas(128) std::atomic_size_t m_write_index{0}; | 112 | alignas(128) std::atomic_size_t m_write_index{0}; |
| 114 | #endif | 113 | #endif |
| 115 | 114 | ||
| 116 | std::array<T, granularity * capacity> m_data; | 115 | std::array<T, capacity> m_data; |
| 117 | }; | 116 | }; |
| 118 | 117 | ||
| 119 | } // namespace Common | 118 | } // namespace Common |
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index f2f497dc4..d0e90fd60 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -118,9 +118,10 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 | |||
| 118 | 118 | ||
| 119 | // Check the userspace value. | 119 | // Check the userspace value. |
| 120 | s32 user_value{}; | 120 | s32 user_value{}; |
| 121 | R_UNLESS(UpdateIfEqual(system, std::addressof(user_value), addr, value, value + 1), | 121 | if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) { |
| 122 | Svc::ResultInvalidCurrentMemory); | 122 | LOG_ERROR(Kernel, "Invalid current memory!"); |
| 123 | 123 | return Svc::ResultInvalidCurrentMemory; | |
| 124 | } | ||
| 124 | if (user_value != value) { | 125 | if (user_value != value) { |
| 125 | return Svc::ResultInvalidState; | 126 | return Svc::ResultInvalidState; |
| 126 | } | 127 | } |
| @@ -146,61 +147,34 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 146 | // Perform signaling. | 147 | // Perform signaling. |
| 147 | s32 num_waiters{}; | 148 | s32 num_waiters{}; |
| 148 | { | 149 | { |
| 149 | KScopedSchedulerLock sl(kernel); | 150 | [[maybe_unused]] const KScopedSchedulerLock sl(kernel); |
| 150 | 151 | ||
| 151 | auto it = thread_tree.nfind_light({addr, -1}); | 152 | auto it = thread_tree.nfind_light({addr, -1}); |
| 152 | // Determine the updated value. | 153 | // Determine the updated value. |
| 153 | s32 new_value{}; | 154 | s32 new_value{}; |
| 154 | if (/*GetTargetFirmware() >= TargetFirmware_7_0_0*/ true) { | 155 | if (count <= 0) { |
| 155 | if (count <= 0) { | 156 | if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { |
| 156 | if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { | 157 | new_value = value - 2; |
| 157 | new_value = value - 2; | ||
| 158 | } else { | ||
| 159 | new_value = value + 1; | ||
| 160 | } | ||
| 161 | } else { | 158 | } else { |
| 162 | if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { | 159 | new_value = value + 1; |
| 163 | auto tmp_it = it; | ||
| 164 | s32 tmp_num_waiters{}; | ||
| 165 | while ((++tmp_it != thread_tree.end()) && | ||
| 166 | (tmp_it->GetAddressArbiterKey() == addr)) { | ||
| 167 | if ((tmp_num_waiters++) >= count) { | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | if (tmp_num_waiters < count) { | ||
| 173 | new_value = value - 1; | ||
| 174 | } else { | ||
| 175 | new_value = value; | ||
| 176 | } | ||
| 177 | } else { | ||
| 178 | new_value = value + 1; | ||
| 179 | } | ||
| 180 | } | 160 | } |
| 181 | } else { | 161 | } else { |
| 182 | if (count <= 0) { | 162 | if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { |
| 183 | if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { | ||
| 184 | new_value = value - 1; | ||
| 185 | } else { | ||
| 186 | new_value = value + 1; | ||
| 187 | } | ||
| 188 | } else { | ||
| 189 | auto tmp_it = it; | 163 | auto tmp_it = it; |
| 190 | s32 tmp_num_waiters{}; | 164 | s32 tmp_num_waiters{}; |
| 191 | while ((tmp_it != thread_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && | 165 | while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) { |
| 192 | (tmp_num_waiters < count + 1)) { | 166 | if (tmp_num_waiters++ >= count) { |
| 193 | ++tmp_num_waiters; | 167 | break; |
| 194 | ++tmp_it; | 168 | } |
| 195 | } | 169 | } |
| 196 | 170 | ||
| 197 | if (tmp_num_waiters == 0) { | 171 | if (tmp_num_waiters < count) { |
| 198 | new_value = value + 1; | ||
| 199 | } else if (tmp_num_waiters <= count) { | ||
| 200 | new_value = value - 1; | 172 | new_value = value - 1; |
| 201 | } else { | 173 | } else { |
| 202 | new_value = value; | 174 | new_value = value; |
| 203 | } | 175 | } |
| 176 | } else { | ||
| 177 | new_value = value + 1; | ||
| 204 | } | 178 | } |
| 205 | } | 179 | } |
| 206 | 180 | ||
| @@ -208,13 +182,15 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 208 | s32 user_value{}; | 182 | s32 user_value{}; |
| 209 | bool succeeded{}; | 183 | bool succeeded{}; |
| 210 | if (value != new_value) { | 184 | if (value != new_value) { |
| 211 | succeeded = UpdateIfEqual(system, std::addressof(user_value), addr, value, new_value); | 185 | succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value); |
| 212 | } else { | 186 | } else { |
| 213 | succeeded = ReadFromUser(system, std::addressof(user_value), addr); | 187 | succeeded = ReadFromUser(system, &user_value, addr); |
| 214 | } | 188 | } |
| 215 | 189 | ||
| 216 | R_UNLESS(succeeded, Svc::ResultInvalidCurrentMemory); | 190 | if (!succeeded) { |
| 217 | 191 | LOG_ERROR(Kernel, "Invalid current memory!"); | |
| 192 | return Svc::ResultInvalidCurrentMemory; | ||
| 193 | } | ||
| 218 | if (user_value != value) { | 194 | if (user_value != value) { |
| 219 | return Svc::ResultInvalidState; | 195 | return Svc::ResultInvalidState; |
| 220 | } | 196 | } |
| @@ -255,9 +231,9 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 255 | s32 user_value{}; | 231 | s32 user_value{}; |
| 256 | bool succeeded{}; | 232 | bool succeeded{}; |
| 257 | if (decrement) { | 233 | if (decrement) { |
| 258 | succeeded = DecrementIfLessThan(system, std::addressof(user_value), addr, value); | 234 | succeeded = DecrementIfLessThan(system, &user_value, addr, value); |
| 259 | } else { | 235 | } else { |
| 260 | succeeded = ReadFromUser(system, std::addressof(user_value), addr); | 236 | succeeded = ReadFromUser(system, &user_value, addr); |
| 261 | } | 237 | } |
| 262 | 238 | ||
| 263 | if (!succeeded) { | 239 | if (!succeeded) { |
| @@ -278,7 +254,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 278 | } | 254 | } |
| 279 | 255 | ||
| 280 | // Set the arbiter. | 256 | // Set the arbiter. |
| 281 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); | 257 | cur_thread->SetAddressArbiter(&thread_tree, addr); |
| 282 | thread_tree.insert(*cur_thread); | 258 | thread_tree.insert(*cur_thread); |
| 283 | cur_thread->SetState(ThreadState::Waiting); | 259 | cur_thread->SetState(ThreadState::Waiting); |
| 284 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | 260 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
| @@ -299,7 +275,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 299 | 275 | ||
| 300 | // Get the result. | 276 | // Get the result. |
| 301 | KSynchronizationObject* dummy{}; | 277 | KSynchronizationObject* dummy{}; |
| 302 | return cur_thread->GetWaitResult(std::addressof(dummy)); | 278 | return cur_thread->GetWaitResult(&dummy); |
| 303 | } | 279 | } |
| 304 | 280 | ||
| 305 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | 281 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
| @@ -320,7 +296,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 320 | 296 | ||
| 321 | // Read the value from userspace. | 297 | // Read the value from userspace. |
| 322 | s32 user_value{}; | 298 | s32 user_value{}; |
| 323 | if (!ReadFromUser(system, std::addressof(user_value), addr)) { | 299 | if (!ReadFromUser(system, &user_value, addr)) { |
| 324 | slp.CancelSleep(); | 300 | slp.CancelSleep(); |
| 325 | return Svc::ResultInvalidCurrentMemory; | 301 | return Svc::ResultInvalidCurrentMemory; |
| 326 | } | 302 | } |
| @@ -338,7 +314,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 338 | } | 314 | } |
| 339 | 315 | ||
| 340 | // Set the arbiter. | 316 | // Set the arbiter. |
| 341 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); | 317 | cur_thread->SetAddressArbiter(&thread_tree, addr); |
| 342 | thread_tree.insert(*cur_thread); | 318 | thread_tree.insert(*cur_thread); |
| 343 | cur_thread->SetState(ThreadState::Waiting); | 319 | cur_thread->SetState(ThreadState::Waiting); |
| 344 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | 320 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
| @@ -359,7 +335,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 359 | 335 | ||
| 360 | // Get the result. | 336 | // Get the result. |
| 361 | KSynchronizationObject* dummy{}; | 337 | KSynchronizationObject* dummy{}; |
| 362 | return cur_thread->GetWaitResult(std::addressof(dummy)); | 338 | return cur_thread->GetWaitResult(&dummy); |
| 363 | } | 339 | } |
| 364 | 340 | ||
| 365 | } // namespace Kernel | 341 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index edf208eff..26650a513 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -368,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t | |||
| 368 | // Get the thread from its handle. | 368 | // Get the thread from its handle. |
| 369 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 369 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 370 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 370 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 371 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 371 | if (!thread) { |
| 372 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 373 | return ResultInvalidHandle; | ||
| 374 | } | ||
| 372 | 375 | ||
| 373 | // Get the thread's id. | 376 | // Get the thread's id. |
| 374 | *out_thread_id = thread->GetThreadID(); | 377 | *out_thread_id = thread->GetThreadID(); |
| @@ -478,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand | |||
| 478 | // Get the thread from its handle. | 481 | // Get the thread from its handle. |
| 479 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 482 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 480 | std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 483 | std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 481 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 484 | if (!thread) { |
| 485 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 486 | return ResultInvalidHandle; | ||
| 487 | } | ||
| 482 | 488 | ||
| 483 | // Cancel the thread's wait. | 489 | // Cancel the thread's wait. |
| 484 | thread->WaitCancel(); | 490 | thread->WaitCancel(); |
| @@ -496,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd | |||
| 496 | thread_handle, address, tag); | 502 | thread_handle, address, tag); |
| 497 | 503 | ||
| 498 | // Validate the input address. | 504 | // Validate the input address. |
| 499 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 505 | if (Memory::IsKernelAddress(address)) { |
| 500 | R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); | 506 | LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})", |
| 507 | address); | ||
| 508 | return ResultInvalidCurrentMemory; | ||
| 509 | } | ||
| 510 | if (!Common::IsAligned(address, sizeof(u32))) { | ||
| 511 | LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); | ||
| 512 | return ResultInvalidAddress; | ||
| 513 | } | ||
| 501 | 514 | ||
| 502 | return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); | 515 | return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); |
| 503 | } | 516 | } |
| @@ -512,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) { | |||
| 512 | LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); | 525 | LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); |
| 513 | 526 | ||
| 514 | // Validate the input address. | 527 | // Validate the input address. |
| 515 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 528 | if (Memory::IsKernelAddress(address)) { |
| 516 | R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); | 529 | LOG_ERROR(Kernel_SVC, |
| 530 | "Attempting to arbitrate an unlock on a kernel address (address={:08X})", | ||
| 531 | address); | ||
| 532 | return ResultInvalidCurrentMemory; | ||
| 533 | } | ||
| 534 | if (!Common::IsAligned(address, sizeof(u32))) { | ||
| 535 | LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); | ||
| 536 | return ResultInvalidAddress; | ||
| 537 | } | ||
| 517 | 538 | ||
| 518 | return system.Kernel().CurrentProcess()->SignalToAddress(address); | 539 | return system.Kernel().CurrentProcess()->SignalToAddress(address); |
| 519 | } | 540 | } |
| @@ -1025,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size | |||
| 1025 | return UnmapPhysicalMemory(system, addr, size); | 1046 | return UnmapPhysicalMemory(system, addr, size); |
| 1026 | } | 1047 | } |
| 1027 | 1048 | ||
| 1028 | constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) { | ||
| 1029 | switch (thread_activity) { | ||
| 1030 | case Svc::ThreadActivity::Runnable: | ||
| 1031 | case Svc::ThreadActivity::Paused: | ||
| 1032 | return true; | ||
| 1033 | default: | ||
| 1034 | return false; | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /// Sets the thread activity | 1049 | /// Sets the thread activity |
| 1039 | static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, | 1050 | static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, |
| 1040 | Svc::ThreadActivity thread_activity) { | 1051 | ThreadActivity thread_activity) { |
| 1041 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, | 1052 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, |
| 1042 | thread_activity); | 1053 | thread_activity); |
| 1043 | 1054 | ||
| 1044 | // Validate the activity. | 1055 | // Validate the activity. |
| 1045 | R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); | 1056 | constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { |
| 1057 | return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; | ||
| 1058 | }; | ||
| 1059 | if (!IsValidThreadActivity(thread_activity)) { | ||
| 1060 | LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})", | ||
| 1061 | thread_activity); | ||
| 1062 | return ResultInvalidEnumValue; | ||
| 1063 | } | ||
| 1046 | 1064 | ||
| 1047 | // Get the thread from its handle. | 1065 | // Get the thread from its handle. |
| 1048 | auto& kernel = system.Kernel(); | 1066 | auto& kernel = system.Kernel(); |
| 1049 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 1067 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 1050 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1068 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1051 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1069 | if (!thread) { |
| 1070 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 1071 | return ResultInvalidHandle; | ||
| 1072 | } | ||
| 1052 | 1073 | ||
| 1053 | // Check that the activity is being set on a non-current thread for the current process. | 1074 | // Check that the activity is being set on a non-current thread for the current process. |
| 1054 | R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); | 1075 | if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { |
| 1055 | R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); | 1076 | LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); |
| 1077 | return ResultInvalidHandle; | ||
| 1078 | } | ||
| 1079 | if (thread.get() == GetCurrentThreadPointer(kernel)) { | ||
| 1080 | LOG_ERROR(Kernel_SVC, "Thread is busy"); | ||
| 1081 | return ResultBusy; | ||
| 1082 | } | ||
| 1056 | 1083 | ||
| 1057 | // Set the activity. | 1084 | // Set the activity. |
| 1058 | R_TRY(thread->SetActivity(thread_activity)); | 1085 | const auto set_result = thread->SetActivity(thread_activity); |
| 1086 | if (set_result.IsError()) { | ||
| 1087 | LOG_ERROR(Kernel_SVC, "Failed to set thread activity."); | ||
| 1088 | return set_result; | ||
| 1089 | } | ||
| 1059 | 1090 | ||
| 1060 | return RESULT_SUCCESS; | 1091 | return RESULT_SUCCESS; |
| 1061 | } | 1092 | } |
| @@ -1074,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand | |||
| 1074 | const auto* current_process = system.Kernel().CurrentProcess(); | 1105 | const auto* current_process = system.Kernel().CurrentProcess(); |
| 1075 | const std::shared_ptr<KThread> thread = | 1106 | const std::shared_ptr<KThread> thread = |
| 1076 | current_process->GetHandleTable().Get<KThread>(thread_handle); | 1107 | current_process->GetHandleTable().Get<KThread>(thread_handle); |
| 1077 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1108 | if (!thread) { |
| 1109 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle); | ||
| 1110 | return ResultInvalidHandle; | ||
| 1111 | } | ||
| 1078 | 1112 | ||
| 1079 | // Require the handle be to a non-current thread in the current process. | 1113 | // Require the handle be to a non-current thread in the current process. |
| 1080 | R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); | 1114 | if (thread->GetOwnerProcess() != current_process) { |
| 1081 | R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), | 1115 | LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); |
| 1082 | Svc::ResultBusy); | 1116 | return ResultInvalidHandle; |
| 1117 | } | ||
| 1118 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | ||
| 1119 | LOG_ERROR(Kernel_SVC, "Current thread is busy."); | ||
| 1120 | return ResultBusy; | ||
| 1121 | } | ||
| 1083 | 1122 | ||
| 1084 | // Get the thread context. | 1123 | // Get the thread context. |
| 1085 | std::vector<u8> context; | 1124 | std::vector<u8> context; |
| 1086 | R_TRY(thread->GetThreadContext3(context)); | 1125 | const auto context_result = thread->GetThreadContext3(context); |
| 1126 | if (context_result.IsError()) { | ||
| 1127 | LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", | ||
| 1128 | context_result.raw); | ||
| 1129 | return context_result; | ||
| 1130 | } | ||
| 1087 | 1131 | ||
| 1088 | // Copy the thread context to user space. | 1132 | // Copy the thread context to user space. |
| 1089 | system.Memory().WriteBlock(out_context, context.data(), context.size()); | 1133 | system.Memory().WriteBlock(out_context, context.data(), context.size()); |
| @@ -1102,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han | |||
| 1102 | // Get the thread from its handle. | 1146 | // Get the thread from its handle. |
| 1103 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1147 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1104 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); | 1148 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1105 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1149 | if (!thread) { |
| 1150 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle); | ||
| 1151 | return ResultInvalidHandle; | ||
| 1152 | } | ||
| 1106 | 1153 | ||
| 1107 | // Get the thread's priority. | 1154 | // Get the thread's priority. |
| 1108 | *out_priority = thread->GetPriority(); | 1155 | *out_priority = thread->GetPriority(); |
| @@ -1118,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri | |||
| 1118 | LOG_TRACE(Kernel_SVC, "called"); | 1165 | LOG_TRACE(Kernel_SVC, "called"); |
| 1119 | 1166 | ||
| 1120 | // Validate the priority. | 1167 | // Validate the priority. |
| 1121 | R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, | 1168 | if (HighestThreadPriority > priority || priority > LowestThreadPriority) { |
| 1122 | Svc::ResultInvalidPriority); | 1169 | LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); |
| 1170 | return ResultInvalidPriority; | ||
| 1171 | } | ||
| 1123 | 1172 | ||
| 1124 | // Get the thread from its handle. | 1173 | // Get the thread from its handle. |
| 1125 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1174 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1126 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); | 1175 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); |
| 1127 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1176 | if (!thread) { |
| 1177 | LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle); | ||
| 1178 | return ResultInvalidHandle; | ||
| 1179 | } | ||
| 1128 | 1180 | ||
| 1129 | // Set the thread priority. | 1181 | // Set the thread priority. |
| 1130 | thread->SetBasePriority(priority); | 1182 | thread->SetBasePriority(priority); |
| @@ -1440,17 +1492,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1440 | // Adjust core id, if it's the default magic. | 1492 | // Adjust core id, if it's the default magic. |
| 1441 | auto& kernel = system.Kernel(); | 1493 | auto& kernel = system.Kernel(); |
| 1442 | auto& process = *kernel.CurrentProcess(); | 1494 | auto& process = *kernel.CurrentProcess(); |
| 1443 | if (core_id == Svc::IdealCoreUseProcessValue) { | 1495 | if (core_id == IdealCoreUseProcessValue) { |
| 1444 | core_id = process.GetIdealCoreId(); | 1496 | core_id = process.GetIdealCoreId(); |
| 1445 | } | 1497 | } |
| 1446 | 1498 | ||
| 1447 | // Validate arguments. | 1499 | // Validate arguments. |
| 1448 | R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); | 1500 | if (!IsValidCoreId(core_id)) { |
| 1449 | R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); | 1501 | LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); |
| 1502 | return ResultInvalidCoreId; | ||
| 1503 | } | ||
| 1504 | if (((1ULL << core_id) & process.GetCoreMask()) == 0) { | ||
| 1505 | LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id); | ||
| 1506 | return ResultInvalidCoreId; | ||
| 1507 | } | ||
| 1450 | 1508 | ||
| 1451 | R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, | 1509 | if (HighestThreadPriority > priority || priority > LowestThreadPriority) { |
| 1452 | Svc::ResultInvalidPriority); | 1510 | LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority); |
| 1453 | R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); | 1511 | return ResultInvalidPriority; |
| 1512 | } | ||
| 1513 | if (!process.CheckThreadPriority(priority)) { | ||
| 1514 | LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority); | ||
| 1515 | return ResultInvalidPriority; | ||
| 1516 | } | ||
| 1454 | 1517 | ||
| 1455 | ASSERT(process.GetResourceLimit()->Reserve( | 1518 | ASSERT(process.GetResourceLimit()->Reserve( |
| 1456 | LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); | 1519 | LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); |
| @@ -1489,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { | |||
| 1489 | // Get the thread from its handle. | 1552 | // Get the thread from its handle. |
| 1490 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1553 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1491 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1554 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1492 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1555 | if (!thread) { |
| 1556 | LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); | ||
| 1557 | return ResultInvalidHandle; | ||
| 1558 | } | ||
| 1493 | 1559 | ||
| 1494 | // Try to start the thread. | 1560 | // Try to start the thread. |
| 1495 | R_TRY(thread->Run()); | 1561 | const auto run_result = thread->Run(); |
| 1562 | if (run_result.IsError()) { | ||
| 1563 | LOG_ERROR(Kernel_SVC, | ||
| 1564 | "Unable to successfuly start thread (thread handle={:08X}, result={})", | ||
| 1565 | thread_handle, run_result.raw); | ||
| 1566 | return run_result; | ||
| 1567 | } | ||
| 1496 | 1568 | ||
| 1497 | return RESULT_SUCCESS; | 1569 | return RESULT_SUCCESS; |
| 1498 | } | 1570 | } |
| @@ -1553,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address, | |||
| 1553 | cv_key, tag, timeout_ns); | 1625 | cv_key, tag, timeout_ns); |
| 1554 | 1626 | ||
| 1555 | // Validate input. | 1627 | // Validate input. |
| 1556 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 1628 | if (Memory::IsKernelAddress(address)) { |
| 1557 | R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); | 1629 | LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address); |
| 1630 | return ResultInvalidCurrentMemory; | ||
| 1631 | } | ||
| 1632 | if (!Common::IsAligned(address, sizeof(s32))) { | ||
| 1633 | LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address); | ||
| 1634 | return ResultInvalidAddress; | ||
| 1635 | } | ||
| 1558 | 1636 | ||
| 1559 | // Convert timeout from nanoseconds to ticks. | 1637 | // Convert timeout from nanoseconds to ticks. |
| 1560 | s64 timeout{}; | 1638 | s64 timeout{}; |
| @@ -1629,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit | |||
| 1629 | address, arb_type, value, timeout_ns); | 1707 | address, arb_type, value, timeout_ns); |
| 1630 | 1708 | ||
| 1631 | // Validate input. | 1709 | // Validate input. |
| 1632 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 1710 | if (Memory::IsKernelAddress(address)) { |
| 1633 | R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); | 1711 | LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address); |
| 1634 | R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); | 1712 | return ResultInvalidCurrentMemory; |
| 1713 | } | ||
| 1714 | if (!Common::IsAligned(address, sizeof(s32))) { | ||
| 1715 | LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address); | ||
| 1716 | return ResultInvalidAddress; | ||
| 1717 | } | ||
| 1718 | if (!IsValidArbitrationType(arb_type)) { | ||
| 1719 | LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type); | ||
| 1720 | return ResultInvalidEnumValue; | ||
| 1721 | } | ||
| 1635 | 1722 | ||
| 1636 | // Convert timeout from nanoseconds to ticks. | 1723 | // Convert timeout from nanoseconds to ticks. |
| 1637 | s64 timeout{}; | 1724 | s64 timeout{}; |
| @@ -1665,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign | |||
| 1665 | address, signal_type, value, count); | 1752 | address, signal_type, value, count); |
| 1666 | 1753 | ||
| 1667 | // Validate input. | 1754 | // Validate input. |
| 1668 | R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | 1755 | if (Memory::IsKernelAddress(address)) { |
| 1669 | R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); | 1756 | LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address); |
| 1670 | R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); | 1757 | return ResultInvalidCurrentMemory; |
| 1758 | } | ||
| 1759 | if (!Common::IsAligned(address, sizeof(s32))) { | ||
| 1760 | LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address); | ||
| 1761 | return ResultInvalidAddress; | ||
| 1762 | } | ||
| 1763 | if (!IsValidSignalType(signal_type)) { | ||
| 1764 | LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type); | ||
| 1765 | return ResultInvalidEnumValue; | ||
| 1766 | } | ||
| 1671 | 1767 | ||
| 1672 | return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, | 1768 | return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, |
| 1673 | count); | 1769 | count); |
| @@ -1815,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, | |||
| 1815 | // Get the thread from its handle. | 1911 | // Get the thread from its handle. |
| 1816 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1912 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1817 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1913 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1818 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1914 | if (!thread) { |
| 1915 | LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle); | ||
| 1916 | return ResultInvalidHandle; | ||
| 1917 | } | ||
| 1819 | 1918 | ||
| 1820 | // Get the core mask. | 1919 | // Get the core mask. |
| 1821 | R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); | 1920 | const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); |
| 1921 | if (result.IsError()) { | ||
| 1922 | LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw); | ||
| 1923 | return result; | ||
| 1924 | } | ||
| 1822 | 1925 | ||
| 1823 | return RESULT_SUCCESS; | 1926 | return RESULT_SUCCESS; |
| 1824 | } | 1927 | } |
| @@ -1846,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, | |||
| 1846 | } else { | 1949 | } else { |
| 1847 | // Validate the affinity mask. | 1950 | // Validate the affinity mask. |
| 1848 | const u64 process_core_mask = current_process.GetCoreMask(); | 1951 | const u64 process_core_mask = current_process.GetCoreMask(); |
| 1849 | R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, | 1952 | if ((affinity_mask | process_core_mask) != process_core_mask) { |
| 1850 | Svc::ResultInvalidCoreId); | 1953 | LOG_ERROR(Kernel_SVC, |
| 1851 | R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); | 1954 | "Affinity mask does match the process core mask (affinity mask={:016X}, core " |
| 1955 | "mask={:016X})", | ||
| 1956 | affinity_mask, process_core_mask); | ||
| 1957 | return ResultInvalidCoreId; | ||
| 1958 | } | ||
| 1959 | if (affinity_mask == 0) { | ||
| 1960 | LOG_ERROR(Kernel_SVC, "Affinity mask is zero."); | ||
| 1961 | return ResultInvalidCombination; | ||
| 1962 | } | ||
| 1852 | 1963 | ||
| 1853 | // Validate the core id. | 1964 | // Validate the core id. |
| 1854 | if (IsValidCoreId(core_id)) { | 1965 | if (IsValidCoreId(core_id)) { |
| 1855 | R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); | 1966 | if (((1ULL << core_id) & affinity_mask) == 0) { |
| 1967 | LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); | ||
| 1968 | return ResultInvalidCombination; | ||
| 1969 | } | ||
| 1856 | } else { | 1970 | } else { |
| 1857 | R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, | 1971 | if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { |
| 1858 | Svc::ResultInvalidCoreId); | 1972 | LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); |
| 1973 | return ResultInvalidCoreId; | ||
| 1974 | } | ||
| 1859 | } | 1975 | } |
| 1860 | } | 1976 | } |
| 1861 | 1977 | ||
| 1862 | // Get the thread from its handle. | 1978 | // Get the thread from its handle. |
| 1863 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1979 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1864 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); | 1980 | const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); |
| 1865 | R_UNLESS(thread, Svc::ResultInvalidHandle); | 1981 | if (!thread) { |
| 1982 | LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle); | ||
| 1983 | return ResultInvalidHandle; | ||
| 1984 | } | ||
| 1866 | 1985 | ||
| 1867 | // Set the core mask. | 1986 | // Set the core mask. |
| 1868 | R_TRY(thread->SetCoreMask(core_id, affinity_mask)); | 1987 | const auto set_result = thread->SetCoreMask(core_id, affinity_mask); |
| 1988 | if (set_result.IsError()) { | ||
| 1989 | LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw); | ||
| 1990 | return set_result; | ||
| 1991 | } | ||
| 1869 | 1992 | ||
| 1870 | return RESULT_SUCCESS; | 1993 | return RESULT_SUCCESS; |
| 1871 | } | 1994 | } |
| @@ -1884,7 +2007,10 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) { | |||
| 1884 | 2007 | ||
| 1885 | // Get the writable event. | 2008 | // Get the writable event. |
| 1886 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); | 2009 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); |
| 1887 | R_UNLESS(writable_event, Svc::ResultInvalidHandle); | 2010 | if (!writable_event) { |
| 2011 | LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle); | ||
| 2012 | return ResultInvalidHandle; | ||
| 2013 | } | ||
| 1888 | 2014 | ||
| 1889 | return writable_event->Signal(); | 2015 | return writable_event->Signal(); |
| 1890 | } | 2016 | } |
| @@ -1933,7 +2059,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o | |||
| 1933 | 2059 | ||
| 1934 | // Create a new event. | 2060 | // Create a new event. |
| 1935 | const auto event = KEvent::Create(kernel, "CreateEvent"); | 2061 | const auto event = KEvent::Create(kernel, "CreateEvent"); |
| 1936 | R_UNLESS(event != nullptr, Svc::ResultOutOfResource); | 2062 | if (!event) { |
| 2063 | LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached."); | ||
| 2064 | return ResultOutOfResource; | ||
| 2065 | } | ||
| 1937 | 2066 | ||
| 1938 | // Initialize the event. | 2067 | // Initialize the event. |
| 1939 | event->Initialize(); | 2068 | event->Initialize(); |
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 2a6d43d2a..7d7542fc2 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -143,17 +143,19 @@ private: | |||
| 143 | rb.Push(RESULT_SUCCESS); | 143 | rb.Push(RESULT_SUCCESS); |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | u32 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) { | 146 | u64 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) { |
| 147 | u32 result{}; | 147 | u64 result{}; |
| 148 | u32 shift{}; | 148 | u32 shift{}; |
| 149 | do { | 149 | |
| 150 | result |= (data[offset] & 0x7f) << shift; | 150 | for (std::size_t i = 0; i < sizeof(u64); i++) { |
| 151 | const auto v = data[offset]; | ||
| 152 | result |= (static_cast<u64>(v & 0x7f) << shift); | ||
| 151 | shift += 7; | 153 | shift += 7; |
| 152 | offset++; | 154 | offset++; |
| 153 | if (offset >= data.size()) { | 155 | if (offset >= data.size() || ((v & 0x80) == 0)) { |
| 154 | break; | 156 | break; |
| 155 | } | 157 | } |
| 156 | } while ((data[offset] & 0x80) != 0); | 158 | } |
| 157 | return result; | 159 | return result; |
| 158 | } | 160 | } |
| 159 | 161 | ||
| @@ -262,7 +264,7 @@ private: | |||
| 262 | 264 | ||
| 263 | switch (entry.severity) { | 265 | switch (entry.severity) { |
| 264 | case LogSeverity::Trace: | 266 | case LogSeverity::Trace: |
| 265 | LOG_DEBUG(Service_LM, "LogManager DEBUG ({}):\n{}", DestinationToString(destination), | 267 | LOG_DEBUG(Service_LM, "LogManager TRACE ({}):\n{}", DestinationToString(destination), |
| 266 | output_log); | 268 | output_log); |
| 267 | break; | 269 | break; |
| 268 | case LogSeverity::Info: | 270 | case LogSeverity::Info: |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 71c7587db..b6ac0a81a 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -65,13 +65,18 @@ static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMem | |||
| 65 | void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { | 65 | void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { |
| 66 | ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); | 66 | ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); |
| 67 | 67 | ||
| 68 | if (input.size() < 2) { | ||
| 69 | LOG_ERROR(Service_NS, "Input font is empty"); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | |||
| 68 | const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor | 73 | const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor |
| 69 | std::vector<u32> transformed_font(input.size()); | 74 | std::vector<u32> transformed_font(input.size()); |
| 70 | // TODO(ogniK): Figure out a better way to do this | 75 | // TODO(ogniK): Figure out a better way to do this |
| 71 | std::transform(input.begin(), input.end(), transformed_font.begin(), | 76 | std::transform(input.begin(), input.end(), transformed_font.begin(), |
| 72 | [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); | 77 | [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); |
| 73 | transformed_font[1] = Common::swap32(transformed_font[1]) ^ KEY; // "re-encrypt" the size | 78 | std::memcpy(output.data(), transformed_font.data() + 2, |
| 74 | std::memcpy(output.data(), transformed_font.data() + 2, transformed_font.size() * sizeof(u32)); | 79 | (transformed_font.size() - 2) * sizeof(u32)); |
| 75 | } | 80 | } |
| 76 | 81 | ||
| 77 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, | 82 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, |
diff --git a/src/tests/common/ring_buffer.cpp b/src/tests/common/ring_buffer.cpp index 54def22da..903626e4b 100644 --- a/src/tests/common/ring_buffer.cpp +++ b/src/tests/common/ring_buffer.cpp | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | namespace Common { | 14 | namespace Common { |
| 15 | 15 | ||
| 16 | TEST_CASE("RingBuffer: Basic Tests", "[common]") { | 16 | TEST_CASE("RingBuffer: Basic Tests", "[common]") { |
| 17 | RingBuffer<char, 4, 1> buf; | 17 | RingBuffer<char, 4> buf; |
| 18 | 18 | ||
| 19 | // Pushing values into a ring buffer with space should succeed. | 19 | // Pushing values into a ring buffer with space should succeed. |
| 20 | for (std::size_t i = 0; i < 4; i++) { | 20 | for (std::size_t i = 0; i < 4; i++) { |
| @@ -77,7 +77,7 @@ TEST_CASE("RingBuffer: Basic Tests", "[common]") { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | TEST_CASE("RingBuffer: Threaded Test", "[common]") { | 79 | TEST_CASE("RingBuffer: Threaded Test", "[common]") { |
| 80 | RingBuffer<char, 4, 2> buf; | 80 | RingBuffer<char, 8> buf; |
| 81 | const char seed = 42; | 81 | const char seed = 42; |
| 82 | const std::size_t count = 1000000; | 82 | const std::size_t count = 1000000; |
| 83 | std::size_t full = 0; | 83 | std::size_t full = 0; |
| @@ -92,8 +92,8 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") { | |||
| 92 | std::array<char, 2> value = {seed, seed}; | 92 | std::array<char, 2> value = {seed, seed}; |
| 93 | std::size_t i = 0; | 93 | std::size_t i = 0; |
| 94 | while (i < count) { | 94 | while (i < count) { |
| 95 | if (const std::size_t c = buf.Push(&value[0], 1); c > 0) { | 95 | if (const std::size_t c = buf.Push(&value[0], 2); c > 0) { |
| 96 | REQUIRE(c == 1U); | 96 | REQUIRE(c == 2U); |
| 97 | i++; | 97 | i++; |
| 98 | next_value(value); | 98 | next_value(value); |
| 99 | } else { | 99 | } else { |
| @@ -107,7 +107,7 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") { | |||
| 107 | std::array<char, 2> value = {seed, seed}; | 107 | std::array<char, 2> value = {seed, seed}; |
| 108 | std::size_t i = 0; | 108 | std::size_t i = 0; |
| 109 | while (i < count) { | 109 | while (i < count) { |
| 110 | if (const std::vector<char> v = buf.Pop(1); v.size() > 0) { | 110 | if (const std::vector<char> v = buf.Pop(2); v.size() > 0) { |
| 111 | REQUIRE(v.size() == 2U); | 111 | REQUIRE(v.size() == 2U); |
| 112 | REQUIRE(v[0] == value[0]); | 112 | REQUIRE(v[0] == value[0]); |
| 113 | REQUIRE(v[1] == value[1]); | 113 | REQUIRE(v[1] == value[1]); |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index bb1f8491f..2cf95937e 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -67,8 +67,6 @@ add_library(video_core STATIC | |||
| 67 | guest_driver.h | 67 | guest_driver.h |
| 68 | memory_manager.cpp | 68 | memory_manager.cpp |
| 69 | memory_manager.h | 69 | memory_manager.h |
| 70 | morton.cpp | ||
| 71 | morton.h | ||
| 72 | query_cache.h | 70 | query_cache.h |
| 73 | rasterizer_accelerated.cpp | 71 | rasterizer_accelerated.cpp |
| 74 | rasterizer_accelerated.h | 72 | rasterizer_accelerated.h |
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp deleted file mode 100644 index e69de29bb..000000000 --- a/src/video_core/morton.cpp +++ /dev/null | |||
diff --git a/src/video_core/morton.h b/src/video_core/morton.h deleted file mode 100644 index e69de29bb..000000000 --- a/src/video_core/morton.h +++ /dev/null | |||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index dd77a543c..21159e498 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -506,7 +506,7 @@ bool RendererOpenGL::Init() { | |||
| 506 | 506 | ||
| 507 | AddTelemetryFields(); | 507 | AddTelemetryFields(); |
| 508 | 508 | ||
| 509 | if (!GLAD_GL_VERSION_4_3) { | 509 | if (!GLAD_GL_VERSION_4_6) { |
| 510 | return false; | 510 | return false; |
| 511 | } | 511 | } |
| 512 | 512 | ||
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4528eb196..ffdf34a4a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -126,7 +126,7 @@ public: | |||
| 126 | /// Create the original context that should be shared from | 126 | /// Create the original context that should be shared from |
| 127 | explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { | 127 | explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { |
| 128 | QSurfaceFormat format; | 128 | QSurfaceFormat format; |
| 129 | format.setVersion(4, 3); | 129 | format.setVersion(4, 6); |
| 130 | format.setProfile(QSurfaceFormat::CompatibilityProfile); | 130 | format.setProfile(QSurfaceFormat::CompatibilityProfile); |
| 131 | format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); | 131 | format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); |
| 132 | if (Settings::values.renderer_debug) { | 132 | if (Settings::values.renderer_debug) { |
| @@ -651,10 +651,10 @@ bool GRenderWindow::LoadOpenGL() { | |||
| 651 | const QString renderer = | 651 | const QString renderer = |
| 652 | QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); | 652 | QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); |
| 653 | 653 | ||
| 654 | if (!GLAD_GL_VERSION_4_3) { | 654 | if (!GLAD_GL_VERSION_4_6) { |
| 655 | LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString()); | 655 | LOG_ERROR(Frontend, "GPU does not support OpenGL 4.6: {}", renderer.toStdString()); |
| 656 | QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"), | 656 | QMessageBox::warning(this, tr("Error while initializing OpenGL 4.6!"), |
| 657 | tr("Your GPU may not support OpenGL 4.3, or you do not have the " | 657 | tr("Your GPU may not support OpenGL 4.6, or you do not have the " |
| 658 | "latest graphics driver.<br><br>GL Renderer:<br>%1") | 658 | "latest graphics driver.<br><br>GL Renderer:<br>%1") |
| 659 | .arg(renderer)); | 659 | .arg(renderer)); |
| 660 | return false; | 660 | return false; |
| @@ -677,26 +677,13 @@ bool GRenderWindow::LoadOpenGL() { | |||
| 677 | QStringList GRenderWindow::GetUnsupportedGLExtensions() const { | 677 | QStringList GRenderWindow::GetUnsupportedGLExtensions() const { |
| 678 | QStringList unsupported_ext; | 678 | QStringList unsupported_ext; |
| 679 | 679 | ||
| 680 | if (!GLAD_GL_ARB_buffer_storage) | ||
| 681 | unsupported_ext.append(QStringLiteral("ARB_buffer_storage")); | ||
| 682 | if (!GLAD_GL_ARB_direct_state_access) | ||
| 683 | unsupported_ext.append(QStringLiteral("ARB_direct_state_access")); | ||
| 684 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 685 | unsupported_ext.append(QStringLiteral("ARB_vertex_type_10f_11f_11f_rev")); | ||
| 686 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 687 | unsupported_ext.append(QStringLiteral("ARB_texture_mirror_clamp_to_edge")); | ||
| 688 | if (!GLAD_GL_ARB_multi_bind) | ||
| 689 | unsupported_ext.append(QStringLiteral("ARB_multi_bind")); | ||
| 690 | if (!GLAD_GL_ARB_clip_control) | ||
| 691 | unsupported_ext.append(QStringLiteral("ARB_clip_control")); | ||
| 692 | |||
| 693 | // Extensions required to support some texture formats. | 680 | // Extensions required to support some texture formats. |
| 694 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 681 | if (!GLAD_GL_EXT_texture_compression_s3tc) { |
| 695 | unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); | 682 | unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); |
| 696 | if (!GLAD_GL_ARB_texture_compression_rgtc) | 683 | } |
| 684 | if (!GLAD_GL_ARB_texture_compression_rgtc) { | ||
| 697 | unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); | 685 | unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); |
| 698 | if (!GLAD_GL_ARB_depth_buffer_float) | 686 | } |
| 699 | unsupported_ext.append(QStringLiteral("ARB_depth_buffer_float")); | ||
| 700 | 687 | ||
| 701 | if (!unsupported_ext.empty()) { | 688 | if (!unsupported_ext.empty()) { |
| 702 | LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", | 689 | LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index a103b04bd..deddea9ee 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -59,29 +59,17 @@ private: | |||
| 59 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | 59 | bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { |
| 60 | std::vector<std::string_view> unsupported_ext; | 60 | std::vector<std::string_view> unsupported_ext; |
| 61 | 61 | ||
| 62 | if (!GLAD_GL_ARB_buffer_storage) | ||
| 63 | unsupported_ext.push_back("ARB_buffer_storage"); | ||
| 64 | if (!GLAD_GL_ARB_direct_state_access) | ||
| 65 | unsupported_ext.push_back("ARB_direct_state_access"); | ||
| 66 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | ||
| 67 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); | ||
| 68 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | ||
| 69 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | ||
| 70 | if (!GLAD_GL_ARB_multi_bind) | ||
| 71 | unsupported_ext.push_back("ARB_multi_bind"); | ||
| 72 | if (!GLAD_GL_ARB_clip_control) | ||
| 73 | unsupported_ext.push_back("ARB_clip_control"); | ||
| 74 | |||
| 75 | // Extensions required to support some texture formats. | 62 | // Extensions required to support some texture formats. |
| 76 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 63 | if (!GLAD_GL_EXT_texture_compression_s3tc) { |
| 77 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); | 64 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); |
| 78 | if (!GLAD_GL_ARB_texture_compression_rgtc) | 65 | } |
| 66 | if (!GLAD_GL_ARB_texture_compression_rgtc) { | ||
| 79 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); | 67 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); |
| 80 | if (!GLAD_GL_ARB_depth_buffer_float) | 68 | } |
| 81 | unsupported_ext.push_back("ARB_depth_buffer_float"); | ||
| 82 | 69 | ||
| 83 | for (const auto& extension : unsupported_ext) | 70 | for (const auto& extension : unsupported_ext) { |
| 84 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); | 71 | LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); |
| 72 | } | ||
| 85 | 73 | ||
| 86 | return unsupported_ext.empty(); | 74 | return unsupported_ext.empty(); |
| 87 | } | 75 | } |
| @@ -89,7 +77,7 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | |||
| 89 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) | 77 | EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) |
| 90 | : EmuWindow_SDL2{input_subsystem} { | 78 | : EmuWindow_SDL2{input_subsystem} { |
| 91 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | 79 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 92 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | 80 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); |
| 93 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); | 81 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); |
| 94 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | 82 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
| 95 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | 83 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); |