diff options
Diffstat (limited to 'src/core/hle/kernel')
22 files changed, 608 insertions, 408 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index c7b10ca7a..7ec62cf18 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -17,16 +17,16 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/time_manager.h" -#include "core/hle/kernel/writable_event.h" #include "core/memory.h" namespace Kernel { diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 9f764c79a..9a769781b 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -41,8 +41,8 @@ class KernelCore; class Process; class ServerSession; class KThread; -class ReadableEvent; -class WritableEvent; +class KReadableEvent; +class KWritableEvent; enum class ThreadWakeupReason; diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 1685d25bb..d0e90fd60 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -118,9 +118,13 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 // Check the userspace value. s32 user_value{}; - R_UNLESS(UpdateIfEqual(system, std::addressof(user_value), addr, value, value + 1), - Svc::ResultInvalidCurrentMemory); - R_UNLESS(user_value == value, Svc::ResultInvalidState); + if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) { + LOG_ERROR(Kernel, "Invalid current memory!"); + return Svc::ResultInvalidCurrentMemory; + } + if (user_value != value) { + return Svc::ResultInvalidState; + } auto it = thread_tree.nfind_light({addr, -1}); while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && @@ -143,61 +147,34 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 // Perform signaling. s32 num_waiters{}; { - KScopedSchedulerLock sl(kernel); + [[maybe_unused]] const KScopedSchedulerLock sl(kernel); auto it = thread_tree.nfind_light({addr, -1}); // Determine the updated value. s32 new_value{}; - if (/*GetTargetFirmware() >= TargetFirmware_7_0_0*/ true) { - if (count <= 0) { - if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { - new_value = value - 2; - } else { - new_value = value + 1; - } + if (count <= 0) { + if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { + new_value = value - 2; } else { - if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { - auto tmp_it = it; - s32 tmp_num_waiters{}; - while ((++tmp_it != thread_tree.end()) && - (tmp_it->GetAddressArbiterKey() == addr)) { - if ((tmp_num_waiters++) >= count) { - break; - } - } - - if (tmp_num_waiters < count) { - new_value = value - 1; - } else { - new_value = value; - } - } else { - new_value = value + 1; - } + new_value = value + 1; } } else { - if (count <= 0) { - if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { - new_value = value - 1; - } else { - new_value = value + 1; - } - } else { + if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { auto tmp_it = it; s32 tmp_num_waiters{}; - while ((tmp_it != thread_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && - (tmp_num_waiters < count + 1)) { - ++tmp_num_waiters; - ++tmp_it; + while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) { + if (tmp_num_waiters++ >= count) { + break; + } } - if (tmp_num_waiters == 0) { - new_value = value + 1; - } else if (tmp_num_waiters <= count) { + if (tmp_num_waiters < count) { new_value = value - 1; } else { new_value = value; } + } else { + new_value = value + 1; } } @@ -205,13 +182,18 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 s32 user_value{}; bool succeeded{}; if (value != new_value) { - succeeded = UpdateIfEqual(system, std::addressof(user_value), addr, value, new_value); + succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value); } else { - succeeded = ReadFromUser(system, std::addressof(user_value), addr); + succeeded = ReadFromUser(system, &user_value, addr); } - R_UNLESS(succeeded, Svc::ResultInvalidCurrentMemory); - R_UNLESS(user_value == value, Svc::ResultInvalidState); + if (!succeeded) { + LOG_ERROR(Kernel, "Invalid current memory!"); + return Svc::ResultInvalidCurrentMemory; + } + if (user_value != value) { + return Svc::ResultInvalidState; + } while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { @@ -249,9 +231,9 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement s32 user_value{}; bool succeeded{}; if (decrement) { - succeeded = DecrementIfLessThan(system, std::addressof(user_value), addr, value); + succeeded = DecrementIfLessThan(system, &user_value, addr, value); } else { - succeeded = ReadFromUser(system, std::addressof(user_value), addr); + succeeded = ReadFromUser(system, &user_value, addr); } if (!succeeded) { @@ -272,7 +254,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement } // Set the arbiter. - cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); + cur_thread->SetAddressArbiter(&thread_tree, addr); thread_tree.insert(*cur_thread); cur_thread->SetState(ThreadState::Waiting); cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); @@ -293,7 +275,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement // Get the result. KSynchronizationObject* dummy{}; - return cur_thread->GetWaitResult(std::addressof(dummy)); + return cur_thread->GetWaitResult(&dummy); } ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { @@ -314,7 +296,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // Read the value from userspace. s32 user_value{}; - if (!ReadFromUser(system, std::addressof(user_value), addr)) { + if (!ReadFromUser(system, &user_value, addr)) { slp.CancelSleep(); return Svc::ResultInvalidCurrentMemory; } @@ -332,7 +314,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { } // Set the arbiter. - cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); + cur_thread->SetAddressArbiter(&thread_tree, addr); thread_tree.insert(*cur_thread); cur_thread->SetState(ThreadState::Waiting); cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); @@ -353,7 +335,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // Get the result. KSynchronizationObject* dummy{}; - return cur_thread->GetWaitResult(std::addressof(dummy)); + return cur_thread->GetWaitResult(&dummy); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp new file mode 100644 index 000000000..bb2fa4ad5 --- /dev/null +++ b/src/core/hle/kernel/k_event.cpp @@ -0,0 +1,32 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_writable_event.h" + +namespace Kernel { + +KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {} + +KEvent::~KEvent() = default; + +std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) { + return std::make_shared<KEvent>(kernel, std::move(name)); +} + +void KEvent::Initialize() { + // Create our sub events. + readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable"); + writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable"); + + // Initialize our sub sessions. + readable_event->Initialize(this); + writable_event->Initialize(this); + + // Mark initialized. + initialized = true; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h new file mode 100644 index 000000000..2fb887129 --- /dev/null +++ b/src/core/hle/kernel/k_event.h @@ -0,0 +1,57 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/object.h" + +namespace Kernel { + +class KernelCore; +class KReadableEvent; +class KWritableEvent; + +class KEvent final : public Object { +public: + explicit KEvent(KernelCore& kernel, std::string&& name); + ~KEvent() override; + + static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name); + + void Initialize(); + + void Finalize() override {} + + std::string GetTypeName() const override { + return "KEvent"; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::Event; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + std::shared_ptr<KReadableEvent>& GetReadableEvent() { + return readable_event; + } + + std::shared_ptr<KWritableEvent>& GetWritableEvent() { + return writable_event; + } + + const std::shared_ptr<KReadableEvent>& GetReadableEvent() const { + return readable_event; + } + + const std::shared_ptr<KWritableEvent>& GetWritableEvent() const { + return writable_event; + } + +private: + std::shared_ptr<KReadableEvent> readable_event; + std::shared_ptr<KWritableEvent> writable_event; + bool initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index 13d628b85..4aa669d95 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h @@ -24,11 +24,11 @@ template <typename T> concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { { t.GetAffinityMask() } ->Common::ConvertibleTo<u64>; - {t.SetAffinityMask(std::declval<u64>())}; + {t.SetAffinityMask(0)}; - { t.GetAffinity(std::declval<int32_t>()) } + { t.GetAffinity(0) } ->std::same_as<bool>; - {t.SetAffinity(std::declval<int32_t>(), std::declval<bool>())}; + {t.SetAffinity(0, false)}; {t.SetAll()}; }; @@ -42,11 +42,11 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { ->std::same_as<T*>; { (typename T::QueueEntry()).GetPrev() } ->std::same_as<T*>; - { t.GetPriorityQueueEntry(std::declval<s32>()) } + { t.GetPriorityQueueEntry(0) } ->std::same_as<typename T::QueueEntry&>; {t.GetAffinityMask()}; - { typename std::remove_cvref<decltype(t.GetAffinityMask())>::type() } + { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } ->KPriorityQueueAffinityMask; { t.GetActiveCore() } @@ -55,17 +55,17 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { ->Common::ConvertibleTo<s32>; }; -template <typename Member, size_t _NumCores, int LowestPriority, int HighestPriority> +template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> requires KPriorityQueueMember<Member> class KPriorityQueue { public: - using AffinityMaskType = typename std::remove_cv_t< - typename std::remove_reference<decltype(std::declval<Member>().GetAffinityMask())>::type>; + using AffinityMaskType = std::remove_cv_t< + std::remove_reference_t<decltype(std::declval<Member>().GetAffinityMask())>>; static_assert(LowestPriority >= 0); static_assert(HighestPriority >= 0); static_assert(LowestPriority >= HighestPriority); static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1; - static constexpr size_t NumCores = _NumCores; + static constexpr size_t NumCores = NumCores_; static constexpr bool IsValidCore(s32 core) { return 0 <= core && core < static_cast<s32>(NumCores); diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp new file mode 100644 index 000000000..d8a42dbaf --- /dev/null +++ b/src/core/hle/kernel/k_readable_event.cpp @@ -0,0 +1,57 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/logging/log.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name) + : KSynchronizationObject{kernel, std::move(name)} {} +KReadableEvent::~KReadableEvent() = default; + +bool KReadableEvent::IsSignaled() const { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + return is_signaled; +} + +ResultCode KReadableEvent::Signal() { + KScopedSchedulerLock lk{kernel}; + + if (!is_signaled) { + is_signaled = true; + NotifyAvailable(); + } + + return RESULT_SUCCESS; +} + +ResultCode KReadableEvent::Clear() { + Reset(); + + return RESULT_SUCCESS; +} + +ResultCode KReadableEvent::Reset() { + KScopedSchedulerLock lk{kernel}; + + if (!is_signaled) { + return Svc::ResultInvalidState; + } + + is_signaled = false; + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h new file mode 100644 index 000000000..e6f0fd900 --- /dev/null +++ b/src/core/hle/kernel/k_readable_event.h @@ -0,0 +1,51 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KernelCore; +class KEvent; + +class KReadableEvent final : public KSynchronizationObject { +public: + explicit KReadableEvent(KernelCore& kernel, std::string&& name); + ~KReadableEvent() override; + + std::string GetTypeName() const override { + return "KReadableEvent"; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + KEvent* GetParent() const { + return parent; + } + + void Initialize(KEvent* parent_) { + is_signaled = false; + parent = parent_; + } + + bool IsSignaled() const override; + void Finalize() override {} + + ResultCode Signal(); + ResultCode Clear(); + ResultCode Reset(); + +private: + bool is_signaled{}; + KEvent* parent{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index a3b34f82f..140cc46a7 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -132,6 +132,9 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} +KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name) + : Object{kernel, std::move(name)} {} + KSynchronizationObject::~KSynchronizationObject() = default; void KSynchronizationObject::NotifyAvailable(ResultCode result) { diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index f65c71c28..5803718fd 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -33,6 +33,7 @@ public: protected: explicit KSynchronizationObject(KernelCore& kernel); + explicit KSynchronizationObject(KernelCore& kernel, std::string&& name); virtual ~KSynchronizationObject(); void NotifyAvailable(ResultCode result); diff --git a/src/core/hle/kernel/k_writable_event.cpp b/src/core/hle/kernel/k_writable_event.cpp new file mode 100644 index 000000000..25c52edb2 --- /dev/null +++ b/src/core/hle/kernel/k_writable_event.cpp @@ -0,0 +1,27 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_writable_event.h" + +namespace Kernel { + +KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name) + : Object{kernel, std::move(name)} {} +KWritableEvent::~KWritableEvent() = default; + +void KWritableEvent::Initialize(KEvent* parent_) { + parent = parent_; +} + +ResultCode KWritableEvent::Signal() { + return parent->GetReadableEvent()->Signal(); +} + +ResultCode KWritableEvent::Clear() { + return parent->GetReadableEvent()->Clear(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h new file mode 100644 index 000000000..518f5448d --- /dev/null +++ b/src/core/hle/kernel/k_writable_event.h @@ -0,0 +1,44 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KernelCore; +class KEvent; + +class KWritableEvent final : public Object { +public: + explicit KWritableEvent(KernelCore& kernel, std::string&& name); + ~KWritableEvent() override; + + std::string GetTypeName() const override { + return "KWritableEvent"; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + void Initialize(KEvent* parent_); + + void Finalize() override {} + + ResultCode Signal(); + ResultCode Clear(); + + KEvent* GetParent() const { + return parent; + } + +private: + KEvent* parent{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 2c571792b..d7f40c403 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -8,7 +8,10 @@ namespace Kernel { -Object::Object(KernelCore& kernel) : kernel{kernel}, object_id{kernel.CreateNewObjectID()} {} +Object::Object(KernelCore& kernel_) + : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {} +Object::Object(KernelCore& kernel_, std::string&& name_) + : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {} Object::~Object() = default; bool Object::IsWaitable() const { @@ -21,6 +24,7 @@ bool Object::IsWaitable() const { return true; case HandleType::Unknown: + case HandleType::Event: case HandleType::WritableEvent: case HandleType::SharedMemory: case HandleType::TransferMemory: diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index be7fcb5fb..501e58b33 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -18,6 +18,7 @@ using Handle = u32; enum class HandleType : u32 { Unknown, + Event, WritableEvent, ReadableEvent, SharedMemory, @@ -34,7 +35,8 @@ enum class HandleType : u32 { class Object : NonCopyable, public std::enable_shared_from_this<Object> { public: - explicit Object(KernelCore& kernel); + explicit Object(KernelCore& kernel_); + explicit Object(KernelCore& kernel_, std::string&& name_); virtual ~Object(); /// Returns a unique identifier for the object. For debugging purposes only. @@ -46,7 +48,7 @@ public: return "[BAD KERNEL OBJECT TYPE]"; } virtual std::string GetName() const { - return "[UNKNOWN KERNEL OBJECT]"; + return name; } virtual HandleType GetHandleType() const = 0; @@ -69,6 +71,7 @@ protected: private: std::atomic<u32> object_id{0}; + std::string name; }; template <typename T> diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index afdb27c54..2286b292d 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -23,6 +23,7 @@ #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/memory/slab_heap.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/svc_results.h" #include "core/hle/lock.h" #include "core/memory.h" #include "core/settings.h" @@ -241,18 +242,16 @@ void Process::UnregisterThread(const KThread* thread) { thread_list.remove(thread); } -ResultCode Process::ClearSignalState() { - KScopedSchedulerLock lock(system.Kernel()); - if (status == ProcessStatus::Exited) { - LOG_ERROR(Kernel, "called on a terminated process instance."); - return ERR_INVALID_STATE; - } +ResultCode Process::Reset() { + // Lock the process and the scheduler. + KScopedLightLock lk(state_lock); + KScopedSchedulerLock sl{kernel}; - if (!is_signaled) { - LOG_ERROR(Kernel, "called on a process instance that isn't signaled."); - return ERR_INVALID_STATE; - } + // Validate that we're in a state that we can reset. + R_UNLESS(status != ProcessStatus::Exited, Svc::ResultInvalidState); + R_UNLESS(is_signaled, Svc::ResultInvalidState); + // Clear signaled. is_signaled = false; return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index c8af76ce8..320b0f347 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -312,7 +312,7 @@ public: /// @pre The process must be in a signaled state. If this is called on a /// process instance that is not signaled, ERR_INVALID_STATE will be /// returned. - ResultCode ClearSignalState(); + ResultCode Reset(); /** * Loads process-specifics configuration info with metadata provided diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp deleted file mode 100644 index 596d01479..000000000 --- a/src/core/hle/kernel/readable_event.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/hle/kernel/errors.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/readable_event.h" - -namespace Kernel { - -ReadableEvent::ReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {} -ReadableEvent::~ReadableEvent() = default; - -void ReadableEvent::Signal() { - if (is_signaled) { - return; - } - - is_signaled = true; - NotifyAvailable(); -} - -bool ReadableEvent::IsSignaled() const { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - return is_signaled; -} - -void ReadableEvent::Clear() { - is_signaled = false; -} - -ResultCode ReadableEvent::Reset() { - KScopedSchedulerLock lock(kernel); - if (!is_signaled) { - LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", - GetObjectId(), GetTypeName(), GetName()); - return ERR_INVALID_STATE; - } - - Clear(); - - return RESULT_SUCCESS; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h deleted file mode 100644 index 2195710c2..000000000 --- a/src/core/hle/kernel/readable_event.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" - -union ResultCode; - -namespace Kernel { - -class KernelCore; -class WritableEvent; - -class ReadableEvent final : public KSynchronizationObject { - friend class WritableEvent; - -public: - ~ReadableEvent() override; - - std::string GetTypeName() const override { - return "ReadableEvent"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /// Unconditionally clears the readable event's state. - void Clear(); - - /// Clears the readable event's state if and only if it - /// has already been signaled. - /// - /// @pre The event must be in a signaled state. If this event - /// is in an unsignaled state and this function is called, - /// then ERR_INVALID_STATE will be returned. - ResultCode Reset(); - - void Signal(); - - bool IsSignaled() const override; - - void Finalize() override {} - -private: - explicit ReadableEvent(KernelCore& kernel); - - bool is_signaled{}; - std::string name; ///< Name of event (optional) -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 74eb90100..26650a513 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -14,6 +14,7 @@ #include "common/fiber.h" #include "common/logging/log.h" #include "common/microprofile.h" +#include "common/scope_exit.h" #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" @@ -26,18 +27,20 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/memory_layout.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_results.h" @@ -45,7 +48,6 @@ #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/transfer_memory.h" -#include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -366,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); + return ResultInvalidHandle; + } // Get the thread's id. *out_thread_id = thread->GetThreadID(); @@ -476,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); + return ResultInvalidHandle; + } // Cancel the thread's wait. thread->WaitCancel(); @@ -494,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd thread_handle, address, tag); // Validate the input address. - R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); - R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); + if (Memory::IsKernelAddress(address)) { + LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})", + address); + return ResultInvalidCurrentMemory; + } + if (!Common::IsAligned(address, sizeof(u32))) { + LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); + return ResultInvalidAddress; + } return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); } @@ -510,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) { LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); // Validate the input address. - R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); - R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); + if (Memory::IsKernelAddress(address)) { + LOG_ERROR(Kernel_SVC, + "Attempting to arbitrate an unlock on a kernel address (address={:08X})", + address); + return ResultInvalidCurrentMemory; + } + if (!Common::IsAligned(address, sizeof(u32))) { + LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); + return ResultInvalidAddress; + } return system.Kernel().CurrentProcess()->SignalToAddress(address); } @@ -1023,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size return UnmapPhysicalMemory(system, addr, size); } -constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) { - switch (thread_activity) { - case Svc::ThreadActivity::Runnable: - case Svc::ThreadActivity::Paused: - return true; - default: - return false; - } -} - /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, - Svc::ThreadActivity thread_activity) { + ThreadActivity thread_activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, thread_activity); // Validate the activity. - R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); + constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { + return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; + }; + if (!IsValidThreadActivity(thread_activity)) { + LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})", + thread_activity); + return ResultInvalidEnumValue; + } // Get the thread from its handle. auto& kernel = system.Kernel(); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); + return ResultInvalidHandle; + } // Check that the activity is being set on a non-current thread for the current process. - R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); - R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); + if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { + LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); + return ResultInvalidHandle; + } + if (thread.get() == GetCurrentThreadPointer(kernel)) { + LOG_ERROR(Kernel_SVC, "Thread is busy"); + return ResultBusy; + } // Set the activity. - R_TRY(thread->SetActivity(thread_activity)); + const auto set_result = thread->SetActivity(thread_activity); + if (set_result.IsError()) { + LOG_ERROR(Kernel_SVC, "Failed to set thread activity."); + return set_result; + } return RESULT_SUCCESS; } @@ -1072,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand const auto* current_process = system.Kernel().CurrentProcess(); const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle); + return ResultInvalidHandle; + } // Require the handle be to a non-current thread in the current process. - R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); - R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), - Svc::ResultBusy); + if (thread->GetOwnerProcess() != current_process) { + LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); + return ResultInvalidHandle; + } + if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { + LOG_ERROR(Kernel_SVC, "Current thread is busy."); + return ResultBusy; + } // Get the thread context. std::vector<u8> context; - R_TRY(thread->GetThreadContext3(context)); + const auto context_result = thread->GetThreadContext3(context); + if (context_result.IsError()) { + LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", + context_result.raw); + return context_result; + } // Copy the thread context to user space. system.Memory().WriteBlock(out_context, context.data(), context.size()); @@ -1100,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle); + return ResultInvalidHandle; + } // Get the thread's priority. *out_priority = thread->GetPriority(); @@ -1116,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri LOG_TRACE(Kernel_SVC, "called"); // Validate the priority. - R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, - Svc::ResultInvalidPriority); + if (HighestThreadPriority > priority || priority > LowestThreadPriority) { + LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); + return ResultInvalidPriority; + } // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle); + return ResultInvalidHandle; + } // Set the thread priority. thread->SetBasePriority(priority); @@ -1438,17 +1492,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e // Adjust core id, if it's the default magic. auto& kernel = system.Kernel(); auto& process = *kernel.CurrentProcess(); - if (core_id == Svc::IdealCoreUseProcessValue) { + if (core_id == IdealCoreUseProcessValue) { core_id = process.GetIdealCoreId(); } // Validate arguments. - R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); - R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); + if (!IsValidCoreId(core_id)) { + LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); + return ResultInvalidCoreId; + } + if (((1ULL << core_id) & process.GetCoreMask()) == 0) { + LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id); + return ResultInvalidCoreId; + } - R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, - Svc::ResultInvalidPriority); - R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); + if (HighestThreadPriority > priority || priority > LowestThreadPriority) { + LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority); + return ResultInvalidPriority; + } + if (!process.CheckThreadPriority(priority)) { + LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority); + return ResultInvalidPriority; + } ASSERT(process.GetResourceLimit()->Reserve( LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); @@ -1487,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); + return ResultInvalidHandle; + } // Try to start the thread. - R_TRY(thread->Run()); + const auto run_result = thread->Run(); + if (run_result.IsError()) { + LOG_ERROR(Kernel_SVC, + "Unable to successfuly start thread (thread handle={:08X}, result={})", + thread_handle, run_result.raw); + return run_result; + } return RESULT_SUCCESS; } @@ -1551,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address, cv_key, tag, timeout_ns); // Validate input. - R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); - R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); + if (Memory::IsKernelAddress(address)) { + LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address); + return ResultInvalidCurrentMemory; + } + if (!Common::IsAligned(address, sizeof(s32))) { + LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address); + return ResultInvalidAddress; + } // Convert timeout from nanoseconds to ticks. s64 timeout{}; @@ -1627,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit address, arb_type, value, timeout_ns); // Validate input. - R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); - R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); - R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); + if (Memory::IsKernelAddress(address)) { + LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address); + return ResultInvalidCurrentMemory; + } + if (!Common::IsAligned(address, sizeof(s32))) { + LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address); + return ResultInvalidAddress; + } + if (!IsValidArbitrationType(arb_type)) { + LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type); + return ResultInvalidEnumValue; + } // Convert timeout from nanoseconds to ticks. s64 timeout{}; @@ -1663,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign address, signal_type, value, count); // Validate input. - R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); - R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); - R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); + if (Memory::IsKernelAddress(address)) { + LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address); + return ResultInvalidCurrentMemory; + } + if (!Common::IsAligned(address, sizeof(s32))) { + LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address); + return ResultInvalidAddress; + } + if (!IsValidSignalType(signal_type)) { + LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type); + return ResultInvalidEnumValue; + } return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, count); @@ -1725,20 +1823,28 @@ static ResultCode CloseHandle32(Core::System& system, Handle handle) { static ResultCode ResetSignal(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); + // Get the current handle table. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto event = handle_table.Get<ReadableEvent>(handle); - if (event) { - return event->Reset(); + // Try to reset as readable event. + { + auto readable_event = handle_table.Get<KReadableEvent>(handle); + if (readable_event) { + return readable_event->Reset(); + } } - auto process = handle_table.Get<Process>(handle); - if (process) { - return process->ClearSignalState(); + // Try to reset as process. + { + auto process = handle_table.Get<Process>(handle); + if (process) { + return process->Reset(); + } } - LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle); - return ERR_INVALID_HANDLE; + LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle); + + return Svc::ResultInvalidHandle; } static ResultCode ResetSignal32(Core::System& system, Handle handle) { @@ -1805,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle); + return ResultInvalidHandle; + } // Get the core mask. - R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); + const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); + if (result.IsError()) { + LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw); + return result; + } return RESULT_SUCCESS; } @@ -1836,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, } else { // Validate the affinity mask. const u64 process_core_mask = current_process.GetCoreMask(); - R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, - Svc::ResultInvalidCoreId); - R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); + if ((affinity_mask | process_core_mask) != process_core_mask) { + LOG_ERROR(Kernel_SVC, + "Affinity mask does match the process core mask (affinity mask={:016X}, core " + "mask={:016X})", + affinity_mask, process_core_mask); + return ResultInvalidCoreId; + } + if (affinity_mask == 0) { + LOG_ERROR(Kernel_SVC, "Affinity mask is zero."); + return ResultInvalidCombination; + } // Validate the core id. if (IsValidCoreId(core_id)) { - R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); + if (((1ULL << core_id) & affinity_mask) == 0) { + LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); + return ResultInvalidCombination; + } } else { - R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, - Svc::ResultInvalidCoreId); + if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { + LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); + return ResultInvalidCoreId; + } } } // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle); + return ResultInvalidHandle; + } // Set the core mask. - R_TRY(thread->SetCoreMask(core_id, affinity_mask)); + const auto set_result = thread->SetCoreMask(core_id, affinity_mask); + if (set_result.IsError()) { + LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw); + return set_result; + } return RESULT_SUCCESS; } @@ -1866,80 +1999,98 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask); } -static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { - LOG_DEBUG(Kernel_SVC, "called"); - - auto& kernel = system.Kernel(); - const auto [readable_event, writable_event] = - WritableEvent::CreateEventPair(kernel, "CreateEvent"); +static ResultCode SignalEvent(Core::System& system, Handle event_handle) { + LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); - HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); - - const auto write_create_result = handle_table.Create(writable_event); - if (write_create_result.Failed()) { - return write_create_result.Code(); - } - *write_handle = *write_create_result; + // Get the current handle table. + const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const auto read_create_result = handle_table.Create(readable_event); - if (read_create_result.Failed()) { - handle_table.Close(*write_create_result); - return read_create_result.Code(); + // Get the writable event. + auto writable_event = handle_table.Get<KWritableEvent>(event_handle); + if (!writable_event) { + LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle); + return ResultInvalidHandle; } - *read_handle = *read_create_result; - LOG_DEBUG(Kernel_SVC, - "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}", - *write_create_result, *read_create_result); - return RESULT_SUCCESS; + return writable_event->Signal(); } -static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) { - return CreateEvent(system, write_handle, read_handle); +static ResultCode SignalEvent32(Core::System& system, Handle event_handle) { + return SignalEvent(system, event_handle); } -static ResultCode ClearEvent(Core::System& system, Handle handle) { - LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); +static ResultCode ClearEvent(Core::System& system, Handle event_handle) { + LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); + // Get the current handle table. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto writable_event = handle_table.Get<WritableEvent>(handle); - if (writable_event) { - writable_event->Clear(); - return RESULT_SUCCESS; + // Try to clear the writable event. + { + auto writable_event = handle_table.Get<KWritableEvent>(event_handle); + if (writable_event) { + return writable_event->Clear(); + } } - auto readable_event = handle_table.Get<ReadableEvent>(handle); - if (readable_event) { - readable_event->Clear(); - return RESULT_SUCCESS; + // Try to clear the readable event. + { + auto readable_event = handle_table.Get<KReadableEvent>(event_handle); + if (readable_event) { + return readable_event->Clear(); + } } - LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle); - return ERR_INVALID_HANDLE; + LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle); + + return Svc::ResultInvalidHandle; } -static ResultCode ClearEvent32(Core::System& system, Handle handle) { - return ClearEvent(system, handle); +static ResultCode ClearEvent32(Core::System& system, Handle event_handle) { + return ClearEvent(system, event_handle); } -static ResultCode SignalEvent(Core::System& system, Handle handle) { - LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); +static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) { + LOG_DEBUG(Kernel_SVC, "called"); + + // Get the kernel reference and handle table. + auto& kernel = system.Kernel(); + HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + // Create a new event. + const auto event = KEvent::Create(kernel, "CreateEvent"); + if (!event) { + LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached."); + return ResultOutOfResource; + } - HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto writable_event = handle_table.Get<WritableEvent>(handle); + // Initialize the event. + event->Initialize(); - if (!writable_event) { - LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle); - return ERR_INVALID_HANDLE; + // Add the writable event to the handle table. + const auto write_create_result = handle_table.Create(event->GetWritableEvent()); + if (write_create_result.Failed()) { + return write_create_result.Code(); + } + *out_write = *write_create_result; + + // Add the writable event to the handle table. + auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); + + // Add the readable event to the handle table. + const auto read_create_result = handle_table.Create(event->GetReadableEvent()); + if (read_create_result.Failed()) { + return read_create_result.Code(); } + *out_read = *read_create_result; - writable_event->Signal(); + // We succeeded. + handle_guard.Cancel(); return RESULT_SUCCESS; } -static ResultCode SignalEvent32(Core::System& system, Handle handle) { - return SignalEvent(system, handle); +static ResultCode CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) { + return CreateEvent(system, out_write, out_read); } static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index 7b897fbce..204cd989d 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -11,6 +11,7 @@ namespace Kernel::Svc { constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; +constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103}; constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112}; constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113}; diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp deleted file mode 100644 index 142212ee4..000000000 --- a/src/core/hle/kernel/writable_event.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include "common/assert.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/writable_event.h" - -namespace Kernel { - -WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {} -WritableEvent::~WritableEvent() = default; - -EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { - std::shared_ptr<WritableEvent> writable_event(new WritableEvent(kernel)); - std::shared_ptr<ReadableEvent> readable_event(new ReadableEvent(kernel)); - - writable_event->name = name + ":Writable"; - writable_event->readable = readable_event; - readable_event->name = name + ":Readable"; - - return {std::move(readable_event), std::move(writable_event)}; -} - -std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const { - return readable; -} - -void WritableEvent::Signal() { - readable->Signal(); -} - -void WritableEvent::Clear() { - readable->Clear(); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h deleted file mode 100644 index 467eb2c21..000000000 --- a/src/core/hle/kernel/writable_event.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> - -#include "core/hle/kernel/object.h" - -namespace Kernel { - -class KernelCore; -class ReadableEvent; -class WritableEvent; - -struct EventPair { - std::shared_ptr<ReadableEvent> readable; - std::shared_ptr<WritableEvent> writable; -}; - -class WritableEvent final : public Object { -public: - ~WritableEvent() override; - - /** - * Creates an event - * @param kernel The kernel instance to create this event under. - * @param name Optional name of event - */ - static EventPair CreateEventPair(KernelCore& kernel, std::string name = "Unknown"); - - std::string GetTypeName() const override { - return "WritableEvent"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - std::shared_ptr<ReadableEvent> GetReadableEvent() const; - - void Signal(); - void Clear(); - - void Finalize() override {} - -private: - explicit WritableEvent(KernelCore& kernel); - - std::shared_ptr<ReadableEvent> readable; - - std::string name; ///< Name of event (optional) -}; - -} // namespace Kernel |
