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