diff options
| author | 2015-01-30 15:00:17 +0100 | |
|---|---|---|
| committer | 2015-01-30 15:00:17 +0100 | |
| commit | 28702cbfeb1fe21109f8b1efa189785594319b78 (patch) | |
| tree | 64e4b1ec43b7699fe1a6ab1be1c688b6d63c0d75 /src | |
| parent | Merge pull request #412 from purpasmart96/svc_table_cleanup (diff) | |
| parent | Kernel: Mark all appropriate kernel objects as "final" (diff) | |
| download | yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.gz yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.xz yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.zip | |
Merge pull request #503 from yuriks/kernel-lifetime4
Kernel Lifetime Reform Pt. 4
Diffstat (limited to 'src')
29 files changed, 728 insertions, 734 deletions
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index c2750a63c..229eb74c9 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -31,6 +31,10 @@ template<> struct CompileTimeAssert<true> {}; | |||
| 31 | 31 | ||
| 32 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | 32 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) |
| 33 | 33 | ||
| 34 | /// Textually concatenates two tokens. The double-expansion is required by the C preprocessor. | ||
| 35 | #define CONCAT2(x, y) DO_CONCAT2(x, y) | ||
| 36 | #define DO_CONCAT2(x, y) x ## y | ||
| 37 | |||
| 34 | #ifndef _MSC_VER | 38 | #ifndef _MSC_VER |
| 35 | 39 | ||
| 36 | #include <errno.h> | 40 | #include <errno.h> |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 263beaf0e..77dcbaa22 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_funcs.h" | ||
| 8 | |||
| 7 | namespace detail { | 9 | namespace detail { |
| 8 | template <typename Func> | 10 | template <typename Func> |
| 9 | struct ScopeExitHelper { | 11 | struct ScopeExitHelper { |
| @@ -34,4 +36,4 @@ namespace detail { | |||
| 34 | * } | 36 | * } |
| 35 | * \endcode | 37 | * \endcode |
| 36 | */ | 38 | */ |
| 37 | #define SCOPE_EXIT(body) auto scope_exit_helper_##__LINE__ = detail::ScopeExit([&]() body) | 39 | #define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) |
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index a2f51b41b..0b6b6f518 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -33,114 +33,105 @@ static inline void FuncReturn64(u64 res) { | |||
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 35 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 36 | // Function wrappers that return type s32 | 36 | // Function wrappers that return type ResultCode |
| 37 | 37 | ||
| 38 | template<s32 func(u32, u32, u32, u32)> void Wrap() { | 38 | template<ResultCode func(u32, u32, u32, u32)> void Wrap() { |
| 39 | FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3))); | 39 | FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | template<s32 func(u32, u32, u32, u32, u32)> void Wrap() { | 42 | template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ |
| 43 | FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4))); | ||
| 44 | } | ||
| 45 | |||
| 46 | template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ | ||
| 47 | u32 param_1 = 0; | 43 | u32 param_1 = 0; |
| 48 | u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | 44 | u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; |
| 49 | Core::g_app_core->SetReg(1, param_1); | 45 | Core::g_app_core->SetReg(1, param_1); |
| 50 | FuncReturn(retval); | 46 | FuncReturn(retval); |
| 51 | } | 47 | } |
| 52 | 48 | ||
| 53 | template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { | 49 | template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() { |
| 54 | s32 param_1 = 0; | 50 | s32 param_1 = 0; |
| 55 | s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), | 51 | s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), |
| 56 | (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))); | 52 | (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; |
| 57 | Core::g_app_core->SetReg(1, (u32)param_1); | 53 | Core::g_app_core->SetReg(1, (u32)param_1); |
| 58 | FuncReturn(retval); | 54 | FuncReturn(retval); |
| 59 | } | 55 | } |
| 60 | 56 | ||
| 61 | // TODO(bunnei): Is this correct? Probably not - Last parameter looks wrong for ArbitrateAddress | 57 | template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { |
| 62 | template<s32 func(u32, u32, u32, u32, s64)> void Wrap() { | 58 | FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw); |
| 63 | FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4)))); | ||
| 64 | } | 59 | } |
| 65 | 60 | ||
| 66 | template<s32 func(u32*)> void Wrap(){ | 61 | template<ResultCode func(u32*)> void Wrap(){ |
| 67 | u32 param_1 = 0; | 62 | u32 param_1 = 0; |
| 68 | u32 retval = func(¶m_1); | 63 | u32 retval = func(¶m_1).raw; |
| 69 | Core::g_app_core->SetReg(1, param_1); | 64 | Core::g_app_core->SetReg(1, param_1); |
| 70 | FuncReturn(retval); | 65 | FuncReturn(retval); |
| 71 | } | 66 | } |
| 72 | 67 | ||
| 73 | template<s32 func(u32, s64)> void Wrap() { | 68 | template<ResultCode func(u32, s64)> void Wrap() { |
| 74 | FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2)))); | 69 | FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); |
| 75 | } | 70 | } |
| 76 | 71 | ||
| 77 | template<s32 func(void*, void*, u32)> void Wrap(){ | 72 | template<ResultCode func(void*, void*, u32)> void Wrap(){ |
| 78 | FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2))); | 73 | FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw); |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | template<s32 func(s32*, u32)> void Wrap(){ | 76 | template<ResultCode func(s32*, u32)> void Wrap(){ |
| 82 | s32 param_1 = 0; | 77 | s32 param_1 = 0; |
| 83 | u32 retval = func(¶m_1, PARAM(1)); | 78 | u32 retval = func(¶m_1, PARAM(1)).raw; |
| 84 | Core::g_app_core->SetReg(1, param_1); | 79 | Core::g_app_core->SetReg(1, param_1); |
| 85 | FuncReturn(retval); | 80 | FuncReturn(retval); |
| 86 | } | 81 | } |
| 87 | 82 | ||
| 88 | template<s32 func(u32, s32)> void Wrap() { | 83 | template<ResultCode func(u32, s32)> void Wrap() { |
| 89 | FuncReturn(func(PARAM(0), (s32)PARAM(1))); | 84 | FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw); |
| 90 | } | 85 | } |
| 91 | 86 | ||
| 92 | template<s32 func(u32*, u32)> void Wrap(){ | 87 | template<ResultCode func(u32*, u32)> void Wrap(){ |
| 93 | u32 param_1 = 0; | 88 | u32 param_1 = 0; |
| 94 | u32 retval = func(¶m_1, PARAM(1)); | 89 | u32 retval = func(¶m_1, PARAM(1)).raw; |
| 95 | Core::g_app_core->SetReg(1, param_1); | 90 | Core::g_app_core->SetReg(1, param_1); |
| 96 | FuncReturn(retval); | 91 | FuncReturn(retval); |
| 97 | } | 92 | } |
| 98 | 93 | ||
| 99 | template<s32 func(u32)> void Wrap() { | 94 | template<ResultCode func(u32)> void Wrap() { |
| 100 | FuncReturn(func(PARAM(0))); | 95 | FuncReturn(func(PARAM(0)).raw); |
| 101 | } | ||
| 102 | |||
| 103 | template<s32 func(void*)> void Wrap() { | ||
| 104 | FuncReturn(func(Memory::GetPointer(PARAM(0)))); | ||
| 105 | } | 96 | } |
| 106 | 97 | ||
| 107 | template<s32 func(s64*, u32, void*, s32)> void Wrap(){ | 98 | template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){ |
| 108 | FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), | 99 | FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), |
| 109 | (s32)PARAM(3))); | 100 | (s32)PARAM(3)).raw); |
| 110 | } | 101 | } |
| 111 | 102 | ||
| 112 | template<s32 func(u32*, const char*)> void Wrap() { | 103 | template<ResultCode func(u32*, const char*)> void Wrap() { |
| 113 | u32 param_1 = 0; | 104 | u32 param_1 = 0; |
| 114 | u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))); | 105 | u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))).raw; |
| 115 | Core::g_app_core->SetReg(1, param_1); | 106 | Core::g_app_core->SetReg(1, param_1); |
| 116 | FuncReturn(retval); | 107 | FuncReturn(retval); |
| 117 | } | 108 | } |
| 118 | 109 | ||
| 119 | template<s32 func(u32*, s32, s32)> void Wrap() { | 110 | template<ResultCode func(u32*, s32, s32)> void Wrap() { |
| 120 | u32 param_1 = 0; | 111 | u32 param_1 = 0; |
| 121 | u32 retval = func(¶m_1, PARAM(1), PARAM(2)); | 112 | u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; |
| 122 | Core::g_app_core->SetReg(1, param_1); | 113 | Core::g_app_core->SetReg(1, param_1); |
| 123 | FuncReturn(retval); | 114 | FuncReturn(retval); |
| 124 | } | 115 | } |
| 125 | 116 | ||
| 126 | template<s32 func(s32*, u32, s32)> void Wrap() { | 117 | template<ResultCode func(s32*, u32, s32)> void Wrap() { |
| 127 | s32 param_1 = 0; | 118 | s32 param_1 = 0; |
| 128 | u32 retval = func(¶m_1, PARAM(1), PARAM(2)); | 119 | u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; |
| 129 | Core::g_app_core->SetReg(1, param_1); | 120 | Core::g_app_core->SetReg(1, param_1); |
| 130 | FuncReturn(retval); | 121 | FuncReturn(retval); |
| 131 | } | 122 | } |
| 132 | 123 | ||
| 133 | template<s32 func(u32*, u32, u32, u32, u32)> void Wrap() { | 124 | template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { |
| 134 | u32 param_1 = 0; | 125 | u32 param_1 = 0; |
| 135 | u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)); | 126 | u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; |
| 136 | Core::g_app_core->SetReg(1, param_1); | 127 | Core::g_app_core->SetReg(1, param_1); |
| 137 | FuncReturn(retval); | 128 | FuncReturn(retval); |
| 138 | } | 129 | } |
| 139 | 130 | ||
| 140 | template<s32 func(u32, s64, s64)> void Wrap() { | 131 | template<ResultCode func(u32, s64, s64)> void Wrap() { |
| 141 | s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2); | 132 | s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2); |
| 142 | s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1); | 133 | s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1); |
| 143 | FuncReturn(func(PARAM(0), param1, param2)); | 134 | FuncReturn(func(PARAM(0), param1, param2).raw); |
| 144 | } | 135 | } |
| 145 | 136 | ||
| 146 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 137 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 9e855b0bf..2d01e2ef5 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -15,26 +15,18 @@ | |||
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| 17 | 17 | ||
| 18 | class AddressArbiter : public Object { | 18 | ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { |
| 19 | public: | 19 | SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); |
| 20 | std::string GetTypeName() const override { return "Arbiter"; } | 20 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 21 | std::string GetName() const override { return name; } | 21 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter)); |
| 22 | 22 | ||
| 23 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | 23 | address_arbiter->name = std::move(name); |
| 24 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 25 | 24 | ||
| 26 | std::string name; ///< Name of address arbiter object (optional) | 25 | return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); |
| 27 | }; | 26 | } |
| 28 | |||
| 29 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 30 | |||
| 31 | /// Arbitrate an address | ||
| 32 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { | ||
| 33 | AddressArbiter* object = Kernel::g_handle_table.Get<AddressArbiter>(handle).get(); | ||
| 34 | |||
| 35 | if (object == nullptr) | ||
| 36 | return InvalidHandle(ErrorModule::Kernel); | ||
| 37 | 27 | ||
| 28 | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | ||
| 29 | u64 nanoseconds) { | ||
| 38 | switch (type) { | 30 | switch (type) { |
| 39 | 31 | ||
| 40 | // Signal thread(s) waiting for arbitrate address... | 32 | // Signal thread(s) waiting for arbitrate address... |
| @@ -92,20 +84,4 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 92 | return RESULT_SUCCESS; | 84 | return RESULT_SUCCESS; |
| 93 | } | 85 | } |
| 94 | 86 | ||
| 95 | /// Create an address arbiter | ||
| 96 | AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { | ||
| 97 | AddressArbiter* address_arbiter = new AddressArbiter; | ||
| 98 | // TOOD(yuriks): Fix error reporting | ||
| 99 | handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE); | ||
| 100 | address_arbiter->name = name; | ||
| 101 | return address_arbiter; | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Create an address arbiter | ||
| 105 | Handle CreateAddressArbiter(const std::string& name) { | ||
| 106 | Handle handle; | ||
| 107 | CreateAddressArbiter(handle, name); | ||
| 108 | return handle; | ||
| 109 | } | ||
| 110 | |||
| 111 | } // namespace Kernel | 87 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 3ffd465a2..638afff9e 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | namespace Kernel { | 19 | namespace Kernel { |
| 20 | 20 | ||
| 21 | /// Address arbitration types | ||
| 22 | enum class ArbitrationType : u32 { | 21 | enum class ArbitrationType : u32 { |
| 23 | Signal, | 22 | Signal, |
| 24 | WaitIfLessThan, | 23 | WaitIfLessThan, |
| @@ -27,10 +26,28 @@ enum class ArbitrationType : u32 { | |||
| 27 | DecrementAndWaitIfLessThanWithTimeout, | 26 | DecrementAndWaitIfLessThanWithTimeout, |
| 28 | }; | 27 | }; |
| 29 | 28 | ||
| 30 | /// Arbitrate an address | 29 | class AddressArbiter final : public Object { |
| 31 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds); | 30 | public: |
| 31 | /** | ||
| 32 | * Creates an address arbiter. | ||
| 33 | * | ||
| 34 | * @param name Optional name used for debugging. | ||
| 35 | * @returns The created AddressArbiter. | ||
| 36 | */ | ||
| 37 | static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); | ||
| 32 | 38 | ||
| 33 | /// Create an address arbiter | 39 | std::string GetTypeName() const override { return "Arbiter"; } |
| 34 | Handle CreateAddressArbiter(const std::string& name = "Unknown"); | 40 | std::string GetName() const override { return name; } |
| 41 | |||
| 42 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | ||
| 43 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 44 | |||
| 45 | std::string name; ///< Name of address arbiter object (optional) | ||
| 46 | |||
| 47 | ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); | ||
| 48 | |||
| 49 | private: | ||
| 50 | AddressArbiter() = default; | ||
| 51 | }; | ||
| 35 | 52 | ||
| 36 | } // namespace FileSys | 53 | } // namespace FileSys |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index a48125965..d9ad40c6a 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -14,78 +14,37 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | class Event : public WaitObject { | 17 | ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { |
| 18 | public: | 18 | SharedPtr<Event> evt(new Event); |
| 19 | std::string GetTypeName() const override { return "Event"; } | 19 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 20 | std::string GetName() const override { return name; } | 20 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt)); |
| 21 | |||
| 22 | static const HandleType HANDLE_TYPE = HandleType::Event; | ||
| 23 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 24 | |||
| 25 | ResetType intitial_reset_type; ///< ResetType specified at Event initialization | ||
| 26 | ResetType reset_type; ///< Current ResetType | ||
| 27 | |||
| 28 | bool signaled; ///< Whether the event has already been signaled | ||
| 29 | std::string name; ///< Name of event (optional) | ||
| 30 | |||
| 31 | bool ShouldWait() override { | ||
| 32 | return !signaled; | ||
| 33 | } | ||
| 34 | |||
| 35 | void Acquire() override { | ||
| 36 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 37 | |||
| 38 | // Release the event if it's not sticky... | ||
| 39 | if (reset_type != RESETTYPE_STICKY) | ||
| 40 | signaled = false; | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | |||
| 44 | ResultCode SignalEvent(const Handle handle) { | ||
| 45 | Event* evt = g_handle_table.Get<Event>(handle).get(); | ||
| 46 | if (evt == nullptr) | ||
| 47 | return InvalidHandle(ErrorModule::Kernel); | ||
| 48 | |||
| 49 | evt->signaled = true; | ||
| 50 | evt->WakeupAllWaitingThreads(); | ||
| 51 | |||
| 52 | return RESULT_SUCCESS; | ||
| 53 | } | ||
| 54 | |||
| 55 | ResultCode ClearEvent(Handle handle) { | ||
| 56 | Event* evt = g_handle_table.Get<Event>(handle).get(); | ||
| 57 | if (evt == nullptr) | ||
| 58 | return InvalidHandle(ErrorModule::Kernel); | ||
| 59 | 21 | ||
| 60 | evt->signaled = false; | 22 | evt->signaled = false; |
| 23 | evt->reset_type = evt->intitial_reset_type = reset_type; | ||
| 24 | evt->name = std::move(name); | ||
| 61 | 25 | ||
| 62 | return RESULT_SUCCESS; | 26 | return MakeResult<SharedPtr<Event>>(evt); |
| 63 | } | 27 | } |
| 64 | 28 | ||
| 65 | /** | 29 | bool Event::ShouldWait() { |
| 66 | * Creates an event | 30 | return !signaled; |
| 67 | * @param handle Reference to handle for the newly created mutex | 31 | } |
| 68 | * @param reset_type ResetType describing how to create event | ||
| 69 | * @param name Optional name of event | ||
| 70 | * @return Newly created Event object | ||
| 71 | */ | ||
| 72 | Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 73 | Event* evt = new Event; | ||
| 74 | 32 | ||
| 75 | // TOOD(yuriks): Fix error reporting | 33 | void Event::Acquire() { |
| 76 | handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); | 34 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |
| 77 | 35 | ||
| 78 | evt->signaled = false; | 36 | // Release the event if it's not sticky... |
| 79 | evt->reset_type = evt->intitial_reset_type = reset_type; | 37 | if (reset_type != RESETTYPE_STICKY) |
| 80 | evt->name = name; | 38 | signaled = false; |
| 39 | } | ||
| 81 | 40 | ||
| 82 | return evt; | 41 | void Event::Signal() { |
| 42 | signaled = true; | ||
| 43 | WakeupAllWaitingThreads(); | ||
| 83 | } | 44 | } |
| 84 | 45 | ||
| 85 | Handle CreateEvent(const ResetType reset_type, const std::string& name) { | 46 | void Event::Clear() { |
| 86 | Handle handle; | 47 | signaled = false; |
| 87 | Event* evt = CreateEvent(handle, reset_type, name); | ||
| 88 | return handle; | ||
| 89 | } | 48 | } |
| 90 | 49 | ||
| 91 | } // namespace | 50 | } // namespace |
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index c08b12ee1..2c3e6b14e 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h | |||
| @@ -11,26 +11,35 @@ | |||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | /** | 14 | class Event final : public WaitObject { |
| 15 | * Signals an event | 15 | public: |
| 16 | * @param handle Handle to event to signal | 16 | /** |
| 17 | * @return Result of operation, 0 on success, otherwise error code | 17 | * Creates an event |
| 18 | */ | 18 | * @param reset_type ResetType describing how to create event |
| 19 | ResultCode SignalEvent(const Handle handle); | 19 | * @param name Optional name of event |
| 20 | 20 | */ | |
| 21 | /** | 21 | static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); |
| 22 | * Clears an event | 22 | |
| 23 | * @param handle Handle to event to clear | 23 | std::string GetTypeName() const override { return "Event"; } |
| 24 | * @return Result of operation, 0 on success, otherwise error code | 24 | std::string GetName() const override { return name; } |
| 25 | */ | 25 | |
| 26 | ResultCode ClearEvent(Handle handle); | 26 | static const HandleType HANDLE_TYPE = HandleType::Event; |
| 27 | 27 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | |
| 28 | /** | 28 | |
| 29 | * Creates an event | 29 | ResetType intitial_reset_type; ///< ResetType specified at Event initialization |
| 30 | * @param reset_type ResetType describing how to create event | 30 | ResetType reset_type; ///< Current ResetType |
| 31 | * @param name Optional name of event | 31 | |
| 32 | * @return Handle to newly created Event object | 32 | bool signaled; ///< Whether the event has already been signaled |
| 33 | */ | 33 | std::string name; ///< Name of event (optional) |
| 34 | Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); | 34 | |
| 35 | bool ShouldWait() override; | ||
| 36 | void Acquire() override; | ||
| 37 | |||
| 38 | void Signal(); | ||
| 39 | void Clear(); | ||
| 40 | |||
| 41 | private: | ||
| 42 | Event() = default; | ||
| 43 | }; | ||
| 35 | 44 | ||
| 36 | } // namespace | 45 | } // namespace |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3828efbea..9860479ac 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -16,6 +16,11 @@ | |||
| 16 | typedef u32 Handle; | 16 | typedef u32 Handle; |
| 17 | typedef s32 Result; | 17 | typedef s32 Result; |
| 18 | 18 | ||
| 19 | // TODO: It would be nice to eventually replace these with strong types that prevent accidental | ||
| 20 | // conversion between each other. | ||
| 21 | typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. | ||
| 22 | typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. | ||
| 23 | |||
| 19 | const Handle INVALID_HANDLE = 0; | 24 | const Handle INVALID_HANDLE = 0; |
| 20 | 25 | ||
| 21 | namespace Kernel { | 26 | namespace Kernel { |
| @@ -26,7 +31,8 @@ class Thread; | |||
| 26 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | 31 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, |
| 27 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); | 32 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); |
| 28 | // TOOD: Verify code | 33 | // TOOD: Verify code |
| 29 | const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel); | 34 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, |
| 35 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 30 | 36 | ||
| 31 | enum KernelHandle : Handle { | 37 | enum KernelHandle : Handle { |
| 32 | CurrentThread = 0xFFFF8000, | 38 | CurrentThread = 0xFFFF8000, |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index cd05a1397..acf484659 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -13,59 +13,30 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Mutex : public WaitObject { | ||
| 17 | public: | ||
| 18 | std::string GetTypeName() const override { return "Mutex"; } | ||
| 19 | std::string GetName() const override { return name; } | ||
| 20 | |||
| 21 | static const HandleType HANDLE_TYPE = HandleType::Mutex; | ||
| 22 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 23 | |||
| 24 | bool initial_locked; ///< Initial lock state when mutex was created | ||
| 25 | bool locked; ///< Current locked state | ||
| 26 | std::string name; ///< Name of mutex (optional) | ||
| 27 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | ||
| 28 | |||
| 29 | bool ShouldWait() override; | ||
| 30 | void Acquire() override; | ||
| 31 | }; | ||
| 32 | |||
| 33 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 34 | |||
| 35 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | 16 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; |
| 36 | static MutexMap g_mutex_held_locks; | 17 | static MutexMap g_mutex_held_locks; |
| 37 | 18 | ||
| 38 | /** | 19 | /** |
| 39 | * Acquires the specified mutex for the specified thread | ||
| 40 | * @param mutex Mutex that is to be acquired | ||
| 41 | * @param thread Thread that will acquire the mutex | ||
| 42 | */ | ||
| 43 | void MutexAcquireLock(Mutex* mutex, Thread* thread) { | ||
| 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex)); | ||
| 45 | mutex->holding_thread = thread; | ||
| 46 | } | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Resumes a thread waiting for the specified mutex | 20 | * Resumes a thread waiting for the specified mutex |
| 50 | * @param mutex The mutex that some thread is waiting on | 21 | * @param mutex The mutex that some thread is waiting on |
| 51 | */ | 22 | */ |
| 52 | void ResumeWaitingThread(Mutex* mutex) { | 23 | static void ResumeWaitingThread(Mutex* mutex) { |
| 24 | // Reset mutex lock thread handle, nothing is waiting | ||
| 25 | mutex->locked = false; | ||
| 26 | mutex->holding_thread = nullptr; | ||
| 27 | |||
| 53 | // Find the next waiting thread for the mutex... | 28 | // Find the next waiting thread for the mutex... |
| 54 | auto next_thread = mutex->WakeupNextThread(); | 29 | auto next_thread = mutex->WakeupNextThread(); |
| 55 | if (next_thread != nullptr) { | 30 | if (next_thread != nullptr) { |
| 56 | MutexAcquireLock(mutex, next_thread); | 31 | mutex->Acquire(next_thread); |
| 57 | } else { | ||
| 58 | // Reset mutex lock thread handle, nothing is waiting | ||
| 59 | mutex->locked = false; | ||
| 60 | mutex->holding_thread = nullptr; | ||
| 61 | } | 32 | } |
| 62 | } | 33 | } |
| 63 | 34 | ||
| 64 | void ReleaseThreadMutexes(Thread* thread) { | 35 | void ReleaseThreadMutexes(Thread* thread) { |
| 65 | auto locked = g_mutex_held_locks.equal_range(thread); | 36 | auto locked_range = g_mutex_held_locks.equal_range(thread); |
| 66 | 37 | ||
| 67 | // Release every mutex that the thread holds, and resume execution on the waiting threads | 38 | // Release every mutex that the thread holds, and resume execution on the waiting threads |
| 68 | for (auto iter = locked.first; iter != locked.second; ++iter) { | 39 | for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { |
| 69 | ResumeWaitingThread(iter->second.get()); | 40 | ResumeWaitingThread(iter->second.get()); |
| 70 | } | 41 | } |
| 71 | 42 | ||
| @@ -73,72 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { | |||
| 73 | g_mutex_held_locks.erase(thread); | 44 | g_mutex_held_locks.erase(thread); |
| 74 | } | 45 | } |
| 75 | 46 | ||
| 76 | bool ReleaseMutex(Mutex* mutex) { | 47 | ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { |
| 77 | if (mutex->locked) { | 48 | SharedPtr<Mutex> mutex(new Mutex); |
| 78 | auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); | 49 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 79 | 50 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); | |
| 80 | for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { | ||
| 81 | if (iter->second == mutex) { | ||
| 82 | g_mutex_held_locks.erase(iter); | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | ResumeWaitingThread(mutex); | ||
| 88 | } | ||
| 89 | return true; | ||
| 90 | } | ||
| 91 | 51 | ||
| 92 | /** | 52 | mutex->initial_locked = initial_locked; |
| 93 | * Releases a mutex | 53 | mutex->locked = false; |
| 94 | * @param handle Handle to mutex to release | 54 | mutex->name = std::move(name); |
| 95 | */ | ||
| 96 | ResultCode ReleaseMutex(Handle handle) { | ||
| 97 | Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get(); | ||
| 98 | if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 99 | |||
| 100 | if (!ReleaseMutex(mutex)) { | ||
| 101 | // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure | ||
| 102 | // what error condition this is supposed to be signaling. | ||
| 103 | return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, | ||
| 104 | ErrorSummary::NothingHappened, ErrorLevel::Temporary); | ||
| 105 | } | ||
| 106 | return RESULT_SUCCESS; | ||
| 107 | } | ||
| 108 | |||
| 109 | /** | ||
| 110 | * Creates a mutex | ||
| 111 | * @param handle Reference to handle for the newly created mutex | ||
| 112 | * @param initial_locked Specifies if the mutex should be locked initially | ||
| 113 | * @param name Optional name of mutex | ||
| 114 | * @return Pointer to new Mutex object | ||
| 115 | */ | ||
| 116 | Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { | ||
| 117 | Mutex* mutex = new Mutex; | ||
| 118 | // TODO(yuriks): Fix error reporting | ||
| 119 | handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); | ||
| 120 | |||
| 121 | mutex->locked = mutex->initial_locked = initial_locked; | ||
| 122 | mutex->name = name; | ||
| 123 | mutex->holding_thread = nullptr; | 55 | mutex->holding_thread = nullptr; |
| 124 | 56 | ||
| 125 | // Acquire mutex with current thread if initialized as locked... | 57 | // Acquire mutex with current thread if initialized as locked... |
| 126 | if (mutex->locked) | 58 | if (initial_locked) |
| 127 | MutexAcquireLock(mutex, GetCurrentThread()); | 59 | mutex->Acquire(); |
| 128 | |||
| 129 | return mutex; | ||
| 130 | } | ||
| 131 | 60 | ||
| 132 | /** | 61 | return MakeResult<SharedPtr<Mutex>>(mutex); |
| 133 | * Creates a mutex | ||
| 134 | * @param initial_locked Specifies if the mutex should be locked initially | ||
| 135 | * @param name Optional name of mutex | ||
| 136 | * @return Handle to newly created object | ||
| 137 | */ | ||
| 138 | Handle CreateMutex(bool initial_locked, const std::string& name) { | ||
| 139 | Handle handle; | ||
| 140 | Mutex* mutex = CreateMutex(handle, initial_locked, name); | ||
| 141 | return handle; | ||
| 142 | } | 62 | } |
| 143 | 63 | ||
| 144 | bool Mutex::ShouldWait() { | 64 | bool Mutex::ShouldWait() { |
| @@ -146,9 +66,34 @@ bool Mutex::ShouldWait() { | |||
| 146 | } | 66 | } |
| 147 | 67 | ||
| 148 | void Mutex::Acquire() { | 68 | void Mutex::Acquire() { |
| 69 | Acquire(GetCurrentThread()); | ||
| 70 | } | ||
| 71 | |||
| 72 | void Mutex::Acquire(Thread* thread) { | ||
| 149 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | 73 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |
| 74 | if (locked) | ||
| 75 | return; | ||
| 76 | |||
| 150 | locked = true; | 77 | locked = true; |
| 151 | MutexAcquireLock(this, GetCurrentThread()); | 78 | |
| 79 | g_mutex_held_locks.insert(std::make_pair(thread, this)); | ||
| 80 | holding_thread = thread; | ||
| 81 | } | ||
| 82 | |||
| 83 | void Mutex::Release() { | ||
| 84 | if (!locked) | ||
| 85 | return; | ||
| 86 | |||
| 87 | auto locked_range = g_mutex_held_locks.equal_range(holding_thread); | ||
| 88 | |||
| 89 | for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) { | ||
| 90 | if (iter->second == this) { | ||
| 91 | g_mutex_held_locks.erase(iter); | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | ResumeWaitingThread(this); | ||
| 152 | } | 97 | } |
| 153 | 98 | ||
| 154 | } // namespace | 99 | } // namespace |
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bb8778c98..1e69528f1 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h | |||
| @@ -4,25 +4,51 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 10 | 12 | ||
| 11 | namespace Kernel { | 13 | namespace Kernel { |
| 12 | 14 | ||
| 13 | /** | 15 | class Thread; |
| 14 | * Releases a mutex | 16 | |
| 15 | * @param handle Handle to mutex to release | 17 | class Mutex final : public WaitObject { |
| 16 | */ | 18 | public: |
| 17 | ResultCode ReleaseMutex(Handle handle); | 19 | /** |
| 18 | 20 | * Creates a mutex. | |
| 19 | /** | 21 | * @param initial_locked Specifies if the mutex should be locked initially |
| 20 | * Creates a mutex | 22 | * @param name Optional name of mutex |
| 21 | * @param initial_locked Specifies if the mutex should be locked initially | 23 | * @return Pointer to new Mutex object |
| 22 | * @param name Optional name of mutex | 24 | */ |
| 23 | * @return Handle to newly created object | 25 | static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); |
| 24 | */ | 26 | |
| 25 | Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); | 27 | std::string GetTypeName() const override { return "Mutex"; } |
| 28 | std::string GetName() const override { return name; } | ||
| 29 | |||
| 30 | static const HandleType HANDLE_TYPE = HandleType::Mutex; | ||
| 31 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 32 | |||
| 33 | bool initial_locked; ///< Initial lock state when mutex was created | ||
| 34 | bool locked; ///< Current locked state | ||
| 35 | std::string name; ///< Name of mutex (optional) | ||
| 36 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | ||
| 37 | |||
| 38 | bool ShouldWait() override; | ||
| 39 | void Acquire() override; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Acquires the specified mutex for the specified thread | ||
| 43 | * @param mutex Mutex that is to be acquired | ||
| 44 | * @param thread Thread that will acquire the mutex | ||
| 45 | */ | ||
| 46 | void Acquire(Thread* thread); | ||
| 47 | void Release(); | ||
| 48 | |||
| 49 | private: | ||
| 50 | Mutex() = default; | ||
| 51 | }; | ||
| 26 | 52 | ||
| 27 | /** | 53 | /** |
| 28 | * Releases all the mutexes held by the specified thread | 54 | * Releases all the mutexes held by the specified thread |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 135d8fb2a..a9e406ef4 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <queue> | ||
| 6 | |||
| 7 | #include "common/common.h" | 5 | #include "common/common.h" |
| 8 | 6 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| @@ -12,69 +10,50 @@ | |||
| 12 | 10 | ||
| 13 | namespace Kernel { | 11 | namespace Kernel { |
| 14 | 12 | ||
| 15 | class Semaphore : public WaitObject { | 13 | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, |
| 16 | public: | 14 | std::string name) { |
| 17 | std::string GetTypeName() const override { return "Semaphore"; } | ||
| 18 | std::string GetName() const override { return name; } | ||
| 19 | |||
| 20 | static const HandleType HANDLE_TYPE = HandleType::Semaphore; | ||
| 21 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 22 | |||
| 23 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | ||
| 24 | s32 available_count; ///< Number of free slots left in the semaphore | ||
| 25 | std::string name; ///< Name of semaphore (optional) | ||
| 26 | |||
| 27 | bool ShouldWait() override { | ||
| 28 | return available_count <= 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | void Acquire() override { | ||
| 32 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 33 | --available_count; | ||
| 34 | } | ||
| 35 | }; | ||
| 36 | |||
| 37 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 38 | |||
| 39 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, | ||
| 40 | s32 max_count, const std::string& name) { | ||
| 41 | 15 | ||
| 42 | if (initial_count > max_count) | 16 | if (initial_count > max_count) |
| 43 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | 17 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, |
| 44 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | 18 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); |
| 45 | 19 | ||
| 46 | Semaphore* semaphore = new Semaphore; | 20 | SharedPtr<Semaphore> semaphore(new Semaphore); |
| 47 | // TOOD(yuriks): Fix error reporting | 21 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 48 | *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE); | 22 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore)); |
| 49 | 23 | ||
| 50 | // When the semaphore is created, some slots are reserved for other threads, | 24 | // When the semaphore is created, some slots are reserved for other threads, |
| 51 | // and the rest is reserved for the caller thread | 25 | // and the rest is reserved for the caller thread |
| 52 | semaphore->max_count = max_count; | 26 | semaphore->max_count = max_count; |
| 53 | semaphore->available_count = initial_count; | 27 | semaphore->available_count = initial_count; |
| 54 | semaphore->name = name; | 28 | semaphore->name = std::move(name); |
| 55 | 29 | ||
| 56 | return RESULT_SUCCESS; | 30 | return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); |
| 57 | } | 31 | } |
| 58 | 32 | ||
| 59 | ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | 33 | bool Semaphore::ShouldWait() { |
| 60 | Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get(); | 34 | return available_count <= 0; |
| 61 | if (semaphore == nullptr) | 35 | } |
| 62 | return InvalidHandle(ErrorModule::Kernel); | 36 | |
| 37 | void Semaphore::Acquire() { | ||
| 38 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 39 | --available_count; | ||
| 40 | } | ||
| 63 | 41 | ||
| 64 | if (semaphore->max_count - semaphore->available_count < release_count) | 42 | ResultVal<s32> Semaphore::Release(s32 release_count) { |
| 43 | if (max_count - available_count < release_count) | ||
| 65 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, | 44 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, |
| 66 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 45 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 67 | 46 | ||
| 68 | *count = semaphore->available_count; | 47 | s32 previous_count = available_count; |
| 69 | semaphore->available_count += release_count; | 48 | available_count += release_count; |
| 70 | 49 | ||
| 71 | // Notify some of the threads that the semaphore has been released | 50 | // Notify some of the threads that the semaphore has been released |
| 72 | // stop once the semaphore is full again or there are no more waiting threads | 51 | // stop once the semaphore is full again or there are no more waiting threads |
| 73 | while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { | 52 | while (!ShouldWait() && WakeupNextThread() != nullptr) { |
| 74 | semaphore->Acquire(); | 53 | Acquire(); |
| 75 | } | 54 | } |
| 76 | 55 | ||
| 77 | return RESULT_SUCCESS; | 56 | return MakeResult<s32>(previous_count); |
| 78 | } | 57 | } |
| 79 | 58 | ||
| 80 | } // namespace | 59 | } // namespace |
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 8644ecf0c..9bb404ab6 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h | |||
| @@ -4,29 +4,50 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <queue> | ||
| 8 | #include <string> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 10 | 13 | ||
| 11 | namespace Kernel { | 14 | namespace Kernel { |
| 12 | 15 | ||
| 13 | /** | 16 | class Semaphore final : public WaitObject { |
| 14 | * Creates a semaphore. | 17 | public: |
| 15 | * @param handle Pointer to the handle of the newly created object | 18 | /** |
| 16 | * @param initial_count Number of slots reserved for other threads | 19 | * Creates a semaphore. |
| 17 | * @param max_count Maximum number of slots the semaphore can have | 20 | * @param handle Pointer to the handle of the newly created object |
| 18 | * @param name Optional name of semaphore | 21 | * @param initial_count Number of slots reserved for other threads |
| 19 | * @return ResultCode of the error | 22 | * @param max_count Maximum number of slots the semaphore can have |
| 20 | */ | 23 | * @param name Optional name of semaphore |
| 21 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); | 24 | * @return The created semaphore |
| 22 | 25 | */ | |
| 23 | /** | 26 | static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, |
| 24 | * Releases a certain number of slots from a semaphore. | 27 | std::string name = "Unknown"); |
| 25 | * @param count The number of free slots the semaphore had before this call | 28 | |
| 26 | * @param handle The handle of the semaphore to release | 29 | std::string GetTypeName() const override { return "Semaphore"; } |
| 27 | * @param release_count The number of slots to release | 30 | std::string GetName() const override { return name; } |
| 28 | * @return ResultCode of the error | 31 | |
| 29 | */ | 32 | static const HandleType HANDLE_TYPE = HandleType::Semaphore; |
| 30 | ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count); | 33 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 34 | |||
| 35 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | ||
| 36 | s32 available_count; ///< Number of free slots left in the semaphore | ||
| 37 | std::string name; ///< Name of semaphore (optional) | ||
| 38 | |||
| 39 | bool ShouldWait() override; | ||
| 40 | void Acquire() override; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Releases a certain number of slots from a semaphore. | ||
| 44 | * @param release_count The number of slots to release | ||
| 45 | * @return The number of free slots the semaphore had before this call | ||
| 46 | */ | ||
| 47 | ResultVal<s32> Release(s32 release_count); | ||
| 48 | |||
| 49 | private: | ||
| 50 | Semaphore() = default; | ||
| 51 | }; | ||
| 31 | 52 | ||
| 32 | } // namespace | 53 | } // namespace |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 5368e4728..536d134b0 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -9,76 +9,39 @@ | |||
| 9 | 9 | ||
| 10 | namespace Kernel { | 10 | namespace Kernel { |
| 11 | 11 | ||
| 12 | class SharedMemory : public Object { | 12 | ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { |
| 13 | public: | 13 | SharedPtr<SharedMemory> shared_memory(new SharedMemory); |
| 14 | std::string GetTypeName() const override { return "SharedMemory"; } | ||
| 15 | 14 | ||
| 16 | static const HandleType HANDLE_TYPE = HandleType::SharedMemory; | 15 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 17 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 16 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); |
| 18 | 17 | ||
| 19 | u32 base_address; ///< Address of shared memory block in RAM | 18 | shared_memory->name = std::move(name); |
| 20 | MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) | 19 | return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); |
| 21 | MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) | ||
| 22 | std::string name; ///< Name of shared memory object (optional) | ||
| 23 | }; | ||
| 24 | |||
| 25 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Creates a shared memory object | ||
| 29 | * @param handle Handle of newly created shared memory object | ||
| 30 | * @param name Name of shared memory object | ||
| 31 | * @return Pointer to newly created shared memory object | ||
| 32 | */ | ||
| 33 | SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { | ||
| 34 | SharedMemory* shared_memory = new SharedMemory; | ||
| 35 | // TOOD(yuriks): Fix error reporting | ||
| 36 | handle = Kernel::g_handle_table.Create(shared_memory).ValueOr(INVALID_HANDLE); | ||
| 37 | shared_memory->name = name; | ||
| 38 | return shared_memory; | ||
| 39 | } | 20 | } |
| 40 | 21 | ||
| 41 | Handle CreateSharedMemory(const std::string& name) { | 22 | ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, |
| 42 | Handle handle; | 23 | MemoryPermission other_permissions) { |
| 43 | CreateSharedMemory(handle, name); | ||
| 44 | return handle; | ||
| 45 | } | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Maps a shared memory block to an address in system memory | ||
| 49 | * @param handle Shared memory block handle | ||
| 50 | * @param address Address in system memory to map shared memory block to | ||
| 51 | * @param permissions Memory block map permissions (specified by SVC field) | ||
| 52 | * @param other_permissions Memory block map other permissions (specified by SVC field) | ||
| 53 | * @return Result of operation, 0 on success, otherwise error code | ||
| 54 | */ | ||
| 55 | ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, | ||
| 56 | MemoryPermission other_permissions) { | ||
| 57 | 24 | ||
| 58 | if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { | 25 | if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { |
| 59 | LOG_ERROR(Kernel_SVC, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", | 26 | LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", |
| 60 | handle, address); | 27 | GetHandle(), address); |
| 28 | // TODO: Verify error code with hardware | ||
| 61 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | 29 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |
| 62 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 30 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 63 | } | 31 | } |
| 64 | SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); | ||
| 65 | if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 66 | 32 | ||
| 67 | shared_memory->base_address = address; | 33 | base_address = address; |
| 68 | shared_memory->permissions = permissions; | 34 | permissions = permissions; |
| 69 | shared_memory->other_permissions = other_permissions; | 35 | other_permissions = other_permissions; |
| 70 | 36 | ||
| 71 | return RESULT_SUCCESS; | 37 | return RESULT_SUCCESS; |
| 72 | } | 38 | } |
| 73 | 39 | ||
| 74 | ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { | 40 | ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { |
| 75 | SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); | 41 | if (base_address != 0) |
| 76 | if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); | 42 | return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); |
| 77 | |||
| 78 | if (0 != shared_memory->base_address) | ||
| 79 | return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); | ||
| 80 | 43 | ||
| 81 | LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle); | 44 | LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); |
| 82 | // TODO(yuriks): Verify error code. | 45 | // TODO(yuriks): Verify error code. |
| 83 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | 46 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |
| 84 | ErrorSummary::InvalidState, ErrorLevel::Permanent); | 47 | ErrorSummary::InvalidState, ErrorLevel::Permanent); |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index bb65c7ccd..f9ae23e93 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -23,29 +23,41 @@ enum class MemoryPermission : u32 { | |||
| 23 | DontCare = (1u << 28) | 23 | DontCare = (1u << 28) |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | /** | 26 | class SharedMemory final : public Object { |
| 27 | * Creates a shared memory object | 27 | public: |
| 28 | * @param name Optional name of shared memory object | 28 | /** |
| 29 | * @return Handle of newly created shared memory object | 29 | * Creates a shared memory object |
| 30 | */ | 30 | * @param name Optional object name, used only for debugging purposes. |
| 31 | Handle CreateSharedMemory(const std::string& name="Unknown"); | 31 | */ |
| 32 | 32 | static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); | |
| 33 | /** | 33 | |
| 34 | * Maps a shared memory block to an address in system memory | 34 | std::string GetTypeName() const override { return "SharedMemory"; } |
| 35 | * @param handle Shared memory block handle | 35 | |
| 36 | * @param address Address in system memory to map shared memory block to | 36 | static const HandleType HANDLE_TYPE = HandleType::SharedMemory; |
| 37 | * @param permissions Memory block map permissions (specified by SVC field) | 37 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 38 | * @param other_permissions Memory block map other permissions (specified by SVC field) | 38 | |
| 39 | */ | 39 | /** |
| 40 | ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, | 40 | * Maps a shared memory block to an address in system memory |
| 41 | MemoryPermission other_permissions); | 41 | * @param address Address in system memory to map shared memory block to |
| 42 | 42 | * @param permissions Memory block map permissions (specified by SVC field) | |
| 43 | /** | 43 | * @param other_permissions Memory block map other permissions (specified by SVC field) |
| 44 | * Gets a pointer to the shared memory block | 44 | */ |
| 45 | * @param handle Shared memory block handle | 45 | ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); |
| 46 | * @param offset Offset from the start of the shared memory block to get pointer | 46 | |
| 47 | * @return Pointer to the shared memory block from the specified offset | 47 | /** |
| 48 | */ | 48 | * Gets a pointer to the shared memory block |
| 49 | ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); | 49 | * @param offset Offset from the start of the shared memory block to get pointer |
| 50 | * @return Pointer to the shared memory block from the specified offset | ||
| 51 | */ | ||
| 52 | ResultVal<u8*> GetPointer(u32 offset = 0); | ||
| 53 | |||
| 54 | VAddr base_address; ///< Address of shared memory block in RAM | ||
| 55 | MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) | ||
| 56 | MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) | ||
| 57 | std::string name; ///< Name of shared memory object (optional) | ||
| 58 | |||
| 59 | private: | ||
| 60 | SharedMemory() = default; | ||
| 61 | }; | ||
| 50 | 62 | ||
| 51 | } // namespace | 63 | } // namespace |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 5fab1ab58..d6299364a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -40,7 +40,7 @@ enum ThreadStatus { | |||
| 40 | 40 | ||
| 41 | namespace Kernel { | 41 | namespace Kernel { |
| 42 | 42 | ||
| 43 | class Thread : public WaitObject { | 43 | class Thread final : public WaitObject { |
| 44 | public: | 44 | public: |
| 45 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | 45 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, |
| 46 | u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); | 46 | u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); |
| @@ -115,7 +115,6 @@ public: | |||
| 115 | bool idle = false; | 115 | bool idle = false; |
| 116 | 116 | ||
| 117 | private: | 117 | private: |
| 118 | |||
| 119 | Thread() = default; | 118 | Thread() = default; |
| 120 | }; | 119 | }; |
| 121 | 120 | ||
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index ec0b2c323..503a5d2ce 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -13,75 +13,54 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Timer : public WaitObject { | 16 | /// The event type of the generic timer callback event |
| 17 | public: | 17 | static int timer_callback_event_type = -1; |
| 18 | std::string GetTypeName() const override { return "Timer"; } | ||
| 19 | std::string GetName() const override { return name; } | ||
| 20 | |||
| 21 | static const HandleType HANDLE_TYPE = HandleType::Timer; | ||
| 22 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 23 | |||
| 24 | ResetType reset_type; ///< The ResetType of this timer | ||
| 25 | |||
| 26 | bool signaled; ///< Whether the timer has been signaled or not | ||
| 27 | std::string name; ///< Name of timer (optional) | ||
| 28 | |||
| 29 | u64 initial_delay; ///< The delay until the timer fires for the first time | ||
| 30 | u64 interval_delay; ///< The delay until the timer fires after the first time | ||
| 31 | |||
| 32 | bool ShouldWait() override { | ||
| 33 | return !signaled; | ||
| 34 | } | ||
| 35 | |||
| 36 | void Acquire() override { | ||
| 37 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Creates a timer. | ||
| 43 | * @param handle Reference to handle for the newly created timer | ||
| 44 | * @param reset_type ResetType describing how to create timer | ||
| 45 | * @param name Optional name of timer | ||
| 46 | * @return Newly created Timer object | ||
| 47 | */ | ||
| 48 | Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 49 | Timer* timer = new Timer; | ||
| 50 | 18 | ||
| 51 | handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); | 19 | ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { |
| 20 | SharedPtr<Timer> timer(new Timer); | ||
| 21 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) | ||
| 22 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer)); | ||
| 52 | 23 | ||
| 53 | timer->reset_type = reset_type; | 24 | timer->reset_type = reset_type; |
| 54 | timer->signaled = false; | 25 | timer->signaled = false; |
| 55 | timer->name = name; | 26 | timer->name = std::move(name); |
| 56 | timer->initial_delay = 0; | 27 | timer->initial_delay = 0; |
| 57 | timer->interval_delay = 0; | 28 | timer->interval_delay = 0; |
| 58 | return timer; | 29 | return MakeResult<SharedPtr<Timer>>(timer); |
| 59 | } | 30 | } |
| 60 | 31 | ||
| 61 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { | 32 | bool Timer::ShouldWait() { |
| 62 | CreateTimer(*handle, reset_type, name); | 33 | return !signaled; |
| 63 | return RESULT_SUCCESS; | ||
| 64 | } | 34 | } |
| 65 | 35 | ||
| 66 | ResultCode ClearTimer(Handle handle) { | 36 | void Timer::Acquire() { |
| 67 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | 37 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |
| 68 | 38 | } | |
| 69 | if (timer == nullptr) | ||
| 70 | return InvalidHandle(ErrorModule::Kernel); | ||
| 71 | 39 | ||
| 72 | timer->signaled = false; | 40 | void Timer::Set(s64 initial, s64 interval) { |
| 73 | return RESULT_SUCCESS; | 41 | initial_delay = initial; |
| 42 | interval_delay = interval; | ||
| 43 | |||
| 44 | u64 initial_microseconds = initial / 1000; | ||
| 45 | // TODO(yuriks): Figure out a replacement for GetHandle here | ||
| 46 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, | ||
| 47 | GetHandle()); | ||
| 74 | } | 48 | } |
| 75 | 49 | ||
| 76 | /// The event type of the generic timer callback event | 50 | void Timer::Cancel() { |
| 77 | static int TimerCallbackEventType = -1; | 51 | CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); |
| 52 | } | ||
| 53 | |||
| 54 | void Timer::Clear() { | ||
| 55 | signaled = false; | ||
| 56 | } | ||
| 78 | 57 | ||
| 79 | /// The timer callback event, called when a timer is fired | 58 | /// The timer callback event, called when a timer is fired |
| 80 | static void TimerCallback(u64 timer_handle, int cycles_late) { | 59 | static void TimerCallback(u64 timer_handle, int cycles_late) { |
| 81 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); | 60 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); |
| 82 | 61 | ||
| 83 | if (timer == nullptr) { | 62 | if (timer == nullptr) { |
| 84 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); | 63 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); |
| 85 | return; | 64 | return; |
| 86 | } | 65 | } |
| 87 | 66 | ||
| @@ -99,36 +78,12 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 99 | // Reschedule the timer with the interval delay | 78 | // Reschedule the timer with the interval delay |
| 100 | u64 interval_microseconds = timer->interval_delay / 1000; | 79 | u64 interval_microseconds = timer->interval_delay / 1000; |
| 101 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, | 80 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, |
| 102 | TimerCallbackEventType, timer_handle); | 81 | timer_callback_event_type, timer_handle); |
| 103 | } | 82 | } |
| 104 | } | 83 | } |
| 105 | 84 | ||
| 106 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { | ||
| 107 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 108 | |||
| 109 | if (timer == nullptr) | ||
| 110 | return InvalidHandle(ErrorModule::Kernel); | ||
| 111 | |||
| 112 | timer->initial_delay = initial; | ||
| 113 | timer->interval_delay = interval; | ||
| 114 | |||
| 115 | u64 initial_microseconds = initial / 1000; | ||
| 116 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); | ||
| 117 | return RESULT_SUCCESS; | ||
| 118 | } | ||
| 119 | |||
| 120 | ResultCode CancelTimer(Handle handle) { | ||
| 121 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 122 | |||
| 123 | if (timer == nullptr) | ||
| 124 | return InvalidHandle(ErrorModule::Kernel); | ||
| 125 | |||
| 126 | CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); | ||
| 127 | return RESULT_SUCCESS; | ||
| 128 | } | ||
| 129 | |||
| 130 | void TimersInit() { | 85 | void TimersInit() { |
| 131 | TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | 86 | timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); |
| 132 | } | 87 | } |
| 133 | 88 | ||
| 134 | void TimersShutdown() { | 89 | void TimersShutdown() { |
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index 8170e82d4..c45e79954 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h | |||
| @@ -11,37 +11,50 @@ | |||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | /** | 14 | class Timer final : public WaitObject { |
| 15 | * Cancels a timer | 15 | public: |
| 16 | * @param handle Handle of the timer to cancel | 16 | /** |
| 17 | */ | 17 | * Creates a timer |
| 18 | ResultCode CancelTimer(Handle handle); | 18 | * @param reset_type ResetType describing how to create the timer |
| 19 | 19 | * @param name Optional name of timer | |
| 20 | /** | 20 | * @return The created Timer |
| 21 | * Starts a timer with the specified initial delay and interval | 21 | */ |
| 22 | * @param handle Handle of the timer to start | 22 | static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); |
| 23 | * @param initial Delay until the timer is first fired | 23 | |
| 24 | * @param interval Delay until the timer is fired after the first time | 24 | std::string GetTypeName() const override { return "Timer"; } |
| 25 | */ | 25 | std::string GetName() const override { return name; } |
| 26 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval); | 26 | |
| 27 | 27 | static const HandleType HANDLE_TYPE = HandleType::Timer; | |
| 28 | /** | 28 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 29 | * Clears a timer | 29 | |
| 30 | * @param handle Handle of the timer to clear | 30 | ResetType reset_type; ///< The ResetType of this timer |
| 31 | */ | 31 | |
| 32 | ResultCode ClearTimer(Handle handle); | 32 | bool signaled; ///< Whether the timer has been signaled or not |
| 33 | 33 | std::string name; ///< Name of timer (optional) | |
| 34 | /** | 34 | |
| 35 | * Creates a timer | 35 | u64 initial_delay; ///< The delay until the timer fires for the first time |
| 36 | * @param handle Handle to the newly created Timer object | 36 | u64 interval_delay; ///< The delay until the timer fires after the first time |
| 37 | * @param reset_type ResetType describing how to create the timer | 37 | |
| 38 | * @param name Optional name of timer | 38 | bool ShouldWait() override; |
| 39 | * @return ResultCode of the error | 39 | void Acquire() override; |
| 40 | */ | 40 | |
| 41 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); | 41 | /** |
| 42 | * Starts the timer, with the specified initial delay and interval. | ||
| 43 | * @param initial Delay until the timer is first fired | ||
| 44 | * @param interval Delay until the timer is fired after the first time | ||
| 45 | */ | ||
| 46 | void Set(s64 initial, s64 interval); | ||
| 47 | |||
| 48 | void Cancel(); | ||
| 49 | void Clear(); | ||
| 50 | |||
| 51 | private: | ||
| 52 | Timer() = default; | ||
| 53 | }; | ||
| 42 | 54 | ||
| 43 | /// Initializes the required variables for timers | 55 | /// Initializes the required variables for timers |
| 44 | void TimersInit(); | 56 | void TimersInit(); |
| 45 | /// Tears down the timer variables | 57 | /// Tears down the timer variables |
| 46 | void TimersShutdown(); | 58 | void TimersShutdown(); |
| 59 | |||
| 47 | } // namespace | 60 | } // namespace |
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 82dcf5bba..948b9e38e 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -9,8 +9,9 @@ | |||
| 9 | #include <type_traits> | 9 | #include <type_traits> |
| 10 | #include <utility> | 10 | #include <utility> |
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/bit_field.h" | 12 | #include "common/bit_field.h" |
| 13 | #include "common/common_funcs.h" | ||
| 14 | #include "common/common_types.h" | ||
| 14 | 15 | ||
| 15 | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes | 16 | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes |
| 16 | 17 | ||
| @@ -226,11 +227,6 @@ inline ResultCode UnimplementedFunction(ErrorModule module) { | |||
| 226 | return ResultCode(ErrorDescription::NotImplemented, module, | 227 | return ResultCode(ErrorDescription::NotImplemented, module, |
| 227 | ErrorSummary::NotSupported, ErrorLevel::Permanent); | 228 | ErrorSummary::NotSupported, ErrorLevel::Permanent); |
| 228 | } | 229 | } |
| 229 | /// Returned when a function is passed an invalid handle. | ||
| 230 | inline ResultCode InvalidHandle(ErrorModule module) { | ||
| 231 | return ResultCode(ErrorDescription::InvalidHandle, module, | ||
| 232 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 233 | } | ||
| 234 | 230 | ||
| 235 | /** | 231 | /** |
| 236 | * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, | 232 | * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, |
| @@ -364,6 +360,17 @@ public: | |||
| 364 | return !empty() ? *GetPointer() : std::move(value); | 360 | return !empty() ? *GetPointer() : std::move(value); |
| 365 | } | 361 | } |
| 366 | 362 | ||
| 363 | /// Asserts that the result succeeded and returns a reference to it. | ||
| 364 | T& Unwrap() { | ||
| 365 | // TODO(yuriks): Should be a release assert | ||
| 366 | _assert_msg_(Common, Succeeded(), "Tried to Unwrap empty ResultVal"); | ||
| 367 | return **this; | ||
| 368 | } | ||
| 369 | |||
| 370 | T&& MoveFrom() { | ||
| 371 | return std::move(Unwrap()); | ||
| 372 | } | ||
| 373 | |||
| 367 | private: | 374 | private: |
| 368 | typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; | 375 | typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; |
| 369 | 376 | ||
| @@ -400,3 +407,15 @@ template <typename T, typename... Args> | |||
| 400 | ResultVal<T> MakeResult(Args&&... args) { | 407 | ResultVal<T> MakeResult(Args&&... args) { |
| 401 | return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); | 408 | return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); |
| 402 | } | 409 | } |
| 410 | |||
| 411 | /** | ||
| 412 | * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps | ||
| 413 | * the contained value and assigns it to `target`, which can be either an l-value expression or a | ||
| 414 | * variable declaration. If it fails the return code is returned from the current function. Thus it | ||
| 415 | * can be used to cascade errors out, achieving something akin to exception handling. | ||
| 416 | */ | ||
| 417 | #define CASCADE_RESULT(target, source) \ | ||
| 418 | auto CONCAT2(check_result_L, __LINE__) = source; \ | ||
| 419 | if (CONCAT2(check_result_L, __LINE__).Failed()) \ | ||
| 420 | return CONCAT2(check_result_L, __LINE__).Code(); \ | ||
| 421 | target = std::move(*CONCAT2(check_result_L, __LINE__)) | ||
diff --git a/src/core/hle/service/apt_s.cpp b/src/core/hle/service/apt_s.cpp index 31e6653ef..7ad428ee7 100644 --- a/src/core/hle/service/apt_s.cpp +++ b/src/core/hle/service/apt_s.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "core/hle/kernel/event.h" | 10 | #include "core/hle/kernel/event.h" |
| 11 | #include "core/hle/kernel/mutex.h" | 11 | #include "core/hle/kernel/mutex.h" |
| 12 | #include "core/hle/kernel/shared_memory.h" | 12 | #include "core/hle/kernel/shared_memory.h" |
| 13 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/service/apt_s.h" | 14 | #include "core/hle/service/apt_s.h" |
| 14 | 15 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp index 001b0d183..629b670ed 100644 --- a/src/core/hle/service/apt_u.cpp +++ b/src/core/hle/service/apt_u.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "core/hle/kernel/event.h" | 10 | #include "core/hle/kernel/event.h" |
| 11 | #include "core/hle/kernel/mutex.h" | 11 | #include "core/hle/kernel/mutex.h" |
| 12 | #include "core/hle/kernel/shared_memory.h" | 12 | #include "core/hle/kernel/shared_memory.h" |
| 13 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/service/apt_u.h" | 14 | #include "core/hle/service/apt_u.h" |
| 14 | 15 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -26,11 +27,11 @@ namespace APT_U { | |||
| 26 | static const VAddr SHARED_FONT_VADDR = 0x18000000; | 27 | static const VAddr SHARED_FONT_VADDR = 0x18000000; |
| 27 | 28 | ||
| 28 | /// Handle to shared memory region designated to for shared system font | 29 | /// Handle to shared memory region designated to for shared system font |
| 29 | static Handle shared_font_mem = 0; | 30 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; |
| 30 | 31 | ||
| 31 | static Handle lock_handle = 0; | 32 | static Kernel::SharedPtr<Kernel::Mutex> lock; |
| 32 | static Handle notification_event_handle = 0; ///< APT notification event handle | 33 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event |
| 33 | static Handle pause_event_handle = 0; ///< APT pause event handle | 34 | static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event |
| 34 | static std::vector<u8> shared_font; | 35 | static std::vector<u8> shared_font; |
| 35 | 36 | ||
| 36 | /// Signals used by APT functions | 37 | /// Signals used by APT functions |
| @@ -67,17 +68,19 @@ enum class AppID : u32 { | |||
| 67 | void Initialize(Service::Interface* self) { | 68 | void Initialize(Service::Interface* self) { |
| 68 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 69 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 69 | 70 | ||
| 70 | notification_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Notification"); | 71 | // TODO(bunnei): Check if these are created in Initialize or on APT process startup. |
| 71 | pause_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); | 72 | notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification").MoveFrom(); |
| 73 | pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause").MoveFrom(); | ||
| 72 | 74 | ||
| 73 | cmd_buff[3] = notification_event_handle; | 75 | cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); |
| 74 | cmd_buff[4] = pause_event_handle; | 76 | cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); |
| 75 | 77 | ||
| 76 | Kernel::ClearEvent(notification_event_handle); | 78 | // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. |
| 77 | Kernel::SignalEvent(pause_event_handle); // Fire start event | 79 | notification_event->Clear(); |
| 80 | pause_event->Signal(); // Fire start event | ||
| 78 | 81 | ||
| 79 | _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); | 82 | _assert_msg_(KERNEL, (nullptr != lock), "Cannot initialize without lock"); |
| 80 | Kernel::ReleaseMutex(lock_handle); | 83 | lock->Release(); |
| 81 | 84 | ||
| 82 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 85 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 83 | } | 86 | } |
| @@ -93,7 +96,7 @@ void NotifyToWait(Service::Interface* self) { | |||
| 93 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 96 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 94 | u32 app_id = cmd_buff[1]; | 97 | u32 app_id = cmd_buff[1]; |
| 95 | // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. | 98 | // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further. |
| 96 | Kernel::SignalEvent(pause_event_handle); | 99 | pause_event->Signal(); |
| 97 | 100 | ||
| 98 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 101 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 99 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | 102 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |
| @@ -103,11 +106,6 @@ void GetLockHandle(Service::Interface* self) { | |||
| 103 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 106 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 104 | u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field | 107 | u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field |
| 105 | 108 | ||
| 106 | if (0 == lock_handle) { | ||
| 107 | // TODO(bunnei): Verify if this is created here or at application boot? | ||
| 108 | lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); | ||
| 109 | Kernel::ReleaseMutex(lock_handle); | ||
| 110 | } | ||
| 111 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 109 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 112 | 110 | ||
| 113 | // Not sure what these parameters are used for, but retail apps check that they are 0 after | 111 | // Not sure what these parameters are used for, but retail apps check that they are 0 after |
| @@ -116,7 +114,7 @@ void GetLockHandle(Service::Interface* self) { | |||
| 116 | cmd_buff[3] = 0; | 114 | cmd_buff[3] = 0; |
| 117 | cmd_buff[4] = 0; | 115 | cmd_buff[4] = 0; |
| 118 | 116 | ||
| 119 | cmd_buff[5] = lock_handle; | 117 | cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); |
| 120 | LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); | 118 | LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); |
| 121 | } | 119 | } |
| 122 | 120 | ||
| @@ -354,7 +352,7 @@ void GetSharedFont(Service::Interface* self) { | |||
| 354 | cmd_buff[0] = 0x00440082; | 352 | cmd_buff[0] = 0x00440082; |
| 355 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 353 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 356 | cmd_buff[2] = SHARED_FONT_VADDR; | 354 | cmd_buff[2] = SHARED_FONT_VADDR; |
| 357 | cmd_buff[4] = shared_font_mem; | 355 | cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); |
| 358 | } else { | 356 | } else { |
| 359 | cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware) | 357 | cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware) |
| 360 | LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); | 358 | LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); |
| @@ -514,13 +512,13 @@ Interface::Interface() { | |||
| 514 | file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); | 512 | file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); |
| 515 | 513 | ||
| 516 | // Create shared font memory object | 514 | // Create shared font memory object |
| 517 | shared_font_mem = Kernel::CreateSharedMemory("APT_U:shared_font_mem"); | 515 | shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem").MoveFrom(); |
| 518 | } else { | 516 | } else { |
| 519 | LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); | 517 | LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); |
| 520 | shared_font_mem = 0; | 518 | shared_font_mem = nullptr; |
| 521 | } | 519 | } |
| 522 | 520 | ||
| 523 | lock_handle = 0; | 521 | lock = Kernel::Mutex::Create(false, "APT_U:Lock").MoveFrom(); |
| 524 | 522 | ||
| 525 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 523 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
| 526 | } | 524 | } |
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index d5e39ea4b..9a38be393 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp | |||
| @@ -13,8 +13,8 @@ | |||
| 13 | namespace DSP_DSP { | 13 | namespace DSP_DSP { |
| 14 | 14 | ||
| 15 | static u32 read_pipe_count = 0; | 15 | static u32 read_pipe_count = 0; |
| 16 | static Handle semaphore_event = 0; | 16 | static Kernel::SharedPtr<Kernel::Event> semaphore_event; |
| 17 | static Handle interrupt_event = 0; | 17 | static Kernel::SharedPtr<Kernel::Event> interrupt_event; |
| 18 | 18 | ||
| 19 | void SignalInterrupt() { | 19 | void SignalInterrupt() { |
| 20 | // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated | 20 | // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated |
| @@ -24,7 +24,7 @@ void SignalInterrupt() { | |||
| 24 | // DSP interrupts, and trigger them at the appropriate times. | 24 | // DSP interrupts, and trigger them at the appropriate times. |
| 25 | 25 | ||
| 26 | if (interrupt_event != 0) | 26 | if (interrupt_event != 0) |
| 27 | Kernel::SignalEvent(interrupt_event); | 27 | interrupt_event->Signal(); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | /** | 30 | /** |
| @@ -78,8 +78,8 @@ void LoadComponent(Service::Interface* self) { | |||
| 78 | void GetSemaphoreEventHandle(Service::Interface* self) { | 78 | void GetSemaphoreEventHandle(Service::Interface* self) { |
| 79 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 79 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 80 | 80 | ||
| 81 | cmd_buff[1] = 0; // No error | 81 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 82 | cmd_buff[3] = semaphore_event; // Event handle | 82 | cmd_buff[3] = Kernel::g_handle_table.Create(semaphore_event).MoveFrom(); // Event handle |
| 83 | 83 | ||
| 84 | LOG_WARNING(Service_DSP, "(STUBBED) called"); | 84 | LOG_WARNING(Service_DSP, "(STUBBED) called"); |
| 85 | } | 85 | } |
| @@ -96,9 +96,16 @@ void GetSemaphoreEventHandle(Service::Interface* self) { | |||
| 96 | void RegisterInterruptEvents(Service::Interface* self) { | 96 | void RegisterInterruptEvents(Service::Interface* self) { |
| 97 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 97 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 98 | 98 | ||
| 99 | interrupt_event = static_cast<Handle>(cmd_buff[4]); | 99 | auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); |
| 100 | if (evt != nullptr) { | ||
| 101 | interrupt_event = evt; | ||
| 102 | cmd_buff[1] = 0; // No error | ||
| 103 | } else { | ||
| 104 | LOG_ERROR(Service_DSP, "called with invalid handle=%08X", cmd_buff[4]); | ||
| 100 | 105 | ||
| 101 | cmd_buff[1] = 0; // No error | 106 | // TODO(yuriks): An error should be returned from SendSyncRequest, not in the cmdbuf |
| 107 | cmd_buff[1] = -1; | ||
| 108 | } | ||
| 102 | 109 | ||
| 103 | LOG_WARNING(Service_DSP, "(STUBBED) called"); | 110 | LOG_WARNING(Service_DSP, "(STUBBED) called"); |
| 104 | } | 111 | } |
| @@ -194,8 +201,9 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 194 | // Interface class | 201 | // Interface class |
| 195 | 202 | ||
| 196 | Interface::Interface() { | 203 | Interface::Interface() { |
| 197 | semaphore_event = Kernel::CreateEvent(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event"); | 204 | semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, |
| 198 | interrupt_event = 0; | 205 | "DSP_DSP::semaphore_event").MoveFrom(); |
| 206 | interrupt_event = nullptr; | ||
| 199 | read_pipe_count = 0; | 207 | read_pipe_count = 0; |
| 200 | 208 | ||
| 201 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 209 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 1bb4e4b23..6682f6590 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -43,6 +43,11 @@ const std::string SDCARD_ID = "00000000000000000000000000000000"; | |||
| 43 | namespace Service { | 43 | namespace Service { |
| 44 | namespace FS { | 44 | namespace FS { |
| 45 | 45 | ||
| 46 | // TODO: Verify code | ||
| 47 | /// Returned when a function is passed an invalid handle. | ||
| 48 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::FS, | ||
| 49 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 50 | |||
| 46 | // Command to access archive file | 51 | // Command to access archive file |
| 47 | enum class FileCommand : u32 { | 52 | enum class FileCommand : u32 { |
| 48 | Dummy1 = 0x000100C6, | 53 | Dummy1 = 0x000100C6, |
| @@ -280,7 +285,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi | |||
| 280 | 285 | ||
| 281 | ResultCode CloseArchive(ArchiveHandle handle) { | 286 | ResultCode CloseArchive(ArchiveHandle handle) { |
| 282 | if (handle_map.erase(handle) == 0) | 287 | if (handle_map.erase(handle) == 0) |
| 283 | return InvalidHandle(ErrorModule::FS); | 288 | return ERR_INVALID_HANDLE; |
| 284 | else | 289 | else |
| 285 | return RESULT_SUCCESS; | 290 | return RESULT_SUCCESS; |
| 286 | } | 291 | } |
| @@ -301,7 +306,7 @@ ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, Arc | |||
| 301 | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | 306 | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { |
| 302 | Archive* archive = GetArchive(archive_handle); | 307 | Archive* archive = GetArchive(archive_handle); |
| 303 | if (archive == nullptr) | 308 | if (archive == nullptr) |
| 304 | return InvalidHandle(ErrorModule::FS); | 309 | return ERR_INVALID_HANDLE; |
| 305 | 310 | ||
| 306 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); | 311 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); |
| 307 | if (backend == nullptr) { | 312 | if (backend == nullptr) { |
| @@ -318,7 +323,7 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy | |||
| 318 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 323 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 319 | Archive* archive = GetArchive(archive_handle); | 324 | Archive* archive = GetArchive(archive_handle); |
| 320 | if (archive == nullptr) | 325 | if (archive == nullptr) |
| 321 | return InvalidHandle(ErrorModule::FS); | 326 | return ERR_INVALID_HANDLE; |
| 322 | 327 | ||
| 323 | if (archive->backend->DeleteFile(path)) | 328 | if (archive->backend->DeleteFile(path)) |
| 324 | return RESULT_SUCCESS; | 329 | return RESULT_SUCCESS; |
| @@ -331,7 +336,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil | |||
| 331 | Archive* src_archive = GetArchive(src_archive_handle); | 336 | Archive* src_archive = GetArchive(src_archive_handle); |
| 332 | Archive* dest_archive = GetArchive(dest_archive_handle); | 337 | Archive* dest_archive = GetArchive(dest_archive_handle); |
| 333 | if (src_archive == nullptr || dest_archive == nullptr) | 338 | if (src_archive == nullptr || dest_archive == nullptr) |
| 334 | return InvalidHandle(ErrorModule::FS); | 339 | return ERR_INVALID_HANDLE; |
| 335 | 340 | ||
| 336 | if (src_archive == dest_archive) { | 341 | if (src_archive == dest_archive) { |
| 337 | if (src_archive->backend->RenameFile(src_path, dest_path)) | 342 | if (src_archive->backend->RenameFile(src_path, dest_path)) |
| @@ -350,7 +355,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil | |||
| 350 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 355 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 351 | Archive* archive = GetArchive(archive_handle); | 356 | Archive* archive = GetArchive(archive_handle); |
| 352 | if (archive == nullptr) | 357 | if (archive == nullptr) |
| 353 | return InvalidHandle(ErrorModule::FS); | 358 | return ERR_INVALID_HANDLE; |
| 354 | 359 | ||
| 355 | if (archive->backend->DeleteDirectory(path)) | 360 | if (archive->backend->DeleteDirectory(path)) |
| 356 | return RESULT_SUCCESS; | 361 | return RESULT_SUCCESS; |
| @@ -361,7 +366,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy | |||
| 361 | ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { | 366 | ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { |
| 362 | Archive* archive = GetArchive(archive_handle); | 367 | Archive* archive = GetArchive(archive_handle); |
| 363 | if (archive == nullptr) | 368 | if (archive == nullptr) |
| 364 | return InvalidHandle(ErrorModule::FS); | 369 | return ERR_INVALID_HANDLE; |
| 365 | 370 | ||
| 366 | return archive->backend->CreateFile(path, file_size); | 371 | return archive->backend->CreateFile(path, file_size); |
| 367 | } | 372 | } |
| @@ -369,7 +374,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path | |||
| 369 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 374 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 370 | Archive* archive = GetArchive(archive_handle); | 375 | Archive* archive = GetArchive(archive_handle); |
| 371 | if (archive == nullptr) | 376 | if (archive == nullptr) |
| 372 | return InvalidHandle(ErrorModule::FS); | 377 | return ERR_INVALID_HANDLE; |
| 373 | 378 | ||
| 374 | if (archive->backend->CreateDirectory(path)) | 379 | if (archive->backend->CreateDirectory(path)) |
| 375 | return RESULT_SUCCESS; | 380 | return RESULT_SUCCESS; |
| @@ -382,7 +387,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | |||
| 382 | Archive* src_archive = GetArchive(src_archive_handle); | 387 | Archive* src_archive = GetArchive(src_archive_handle); |
| 383 | Archive* dest_archive = GetArchive(dest_archive_handle); | 388 | Archive* dest_archive = GetArchive(dest_archive_handle); |
| 384 | if (src_archive == nullptr || dest_archive == nullptr) | 389 | if (src_archive == nullptr || dest_archive == nullptr) |
| 385 | return InvalidHandle(ErrorModule::FS); | 390 | return ERR_INVALID_HANDLE; |
| 386 | 391 | ||
| 387 | if (src_archive == dest_archive) { | 392 | if (src_archive == dest_archive) { |
| 388 | if (src_archive->backend->RenameDirectory(src_path, dest_path)) | 393 | if (src_archive->backend->RenameDirectory(src_path, dest_path)) |
| @@ -407,7 +412,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | |||
| 407 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 412 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 408 | Archive* archive = GetArchive(archive_handle); | 413 | Archive* archive = GetArchive(archive_handle); |
| 409 | if (archive == nullptr) | 414 | if (archive == nullptr) |
| 410 | return InvalidHandle(ErrorModule::FS); | 415 | return ERR_INVALID_HANDLE; |
| 411 | 416 | ||
| 412 | std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); | 417 | std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); |
| 413 | if (backend == nullptr) { | 418 | if (backend == nullptr) { |
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 4ca2b9bd0..5b91f17d2 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -22,13 +22,16 @@ GraphicsDebugger g_debugger; | |||
| 22 | 22 | ||
| 23 | namespace GSP_GPU { | 23 | namespace GSP_GPU { |
| 24 | 24 | ||
| 25 | Handle g_interrupt_event = 0; ///< Handle to event triggered when GSP interrupt has been signalled | 25 | /// Event triggered when GSP interrupt has been signalled |
| 26 | Handle g_shared_memory = 0; ///< Handle to GSP shared memorys | 26 | Kernel::SharedPtr<Kernel::Event> g_interrupt_event; |
| 27 | u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1 is arbitrary | 27 | /// GSP shared memoryings |
| 28 | Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory; | ||
| 29 | /// Thread index into interrupt relay queue, 1 is arbitrary | ||
| 30 | u32 g_thread_id = 1; | ||
| 28 | 31 | ||
| 29 | /// Gets a pointer to a thread command buffer in GSP shared memory | 32 | /// Gets a pointer to a thread command buffer in GSP shared memory |
| 30 | static inline u8* GetCommandBuffer(u32 thread_id) { | 33 | static inline u8* GetCommandBuffer(u32 thread_id) { |
| 31 | ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer))); | 34 | ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); |
| 32 | return ptr.ValueOr(nullptr); | 35 | return ptr.ValueOr(nullptr); |
| 33 | } | 36 | } |
| 34 | 37 | ||
| @@ -37,13 +40,13 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in | |||
| 37 | 40 | ||
| 38 | // For each thread there are two FrameBufferUpdate fields | 41 | // For each thread there are two FrameBufferUpdate fields |
| 39 | u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); | 42 | u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); |
| 40 | ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset); | 43 | ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset); |
| 41 | return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); | 44 | return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); |
| 42 | } | 45 | } |
| 43 | 46 | ||
| 44 | /// Gets a pointer to the interrupt relay queue for a given thread index | 47 | /// Gets a pointer to the interrupt relay queue for a given thread index |
| 45 | static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { | 48 | static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { |
| 46 | ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id); | 49 | ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); |
| 47 | return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); | 50 | return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); |
| 48 | } | 51 | } |
| 49 | 52 | ||
| @@ -181,16 +184,18 @@ static void FlushDataCache(Service::Interface* self) { | |||
| 181 | static void RegisterInterruptRelayQueue(Service::Interface* self) { | 184 | static void RegisterInterruptRelayQueue(Service::Interface* self) { |
| 182 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 185 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 183 | u32 flags = cmd_buff[1]; | 186 | u32 flags = cmd_buff[1]; |
| 184 | g_interrupt_event = cmd_buff[3]; | ||
| 185 | g_shared_memory = Kernel::CreateSharedMemory("GSPSharedMem"); | ||
| 186 | 187 | ||
| 187 | _assert_msg_(GSP, (g_interrupt_event != 0), "handle is not valid!"); | 188 | g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); |
| 189 | _assert_msg_(GSP, (g_interrupt_event != nullptr), "handle is not valid!"); | ||
| 190 | g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem").MoveFrom(); | ||
| 191 | |||
| 192 | Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); | ||
| 188 | 193 | ||
| 189 | cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init | 194 | cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init |
| 190 | cmd_buff[2] = g_thread_id++; // Thread ID | 195 | cmd_buff[2] = g_thread_id++; // Thread ID |
| 191 | cmd_buff[4] = g_shared_memory; // GSP shared memory | 196 | cmd_buff[4] = shmem_handle; // GSP shared memory |
| 192 | 197 | ||
| 193 | Kernel::SignalEvent(g_interrupt_event); // TODO(bunnei): Is this correct? | 198 | g_interrupt_event->Signal(); // TODO(bunnei): Is this correct? |
| 194 | } | 199 | } |
| 195 | 200 | ||
| 196 | /** | 201 | /** |
| @@ -204,7 +209,7 @@ void SignalInterrupt(InterruptId interrupt_id) { | |||
| 204 | LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); | 209 | LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); |
| 205 | return; | 210 | return; |
| 206 | } | 211 | } |
| 207 | if (0 == g_shared_memory) { | 212 | if (nullptr == g_shared_memory) { |
| 208 | LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); | 213 | LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); |
| 209 | return; | 214 | return; |
| 210 | } | 215 | } |
| @@ -232,7 +237,7 @@ void SignalInterrupt(InterruptId interrupt_id) { | |||
| 232 | info->is_dirty = false; | 237 | info->is_dirty = false; |
| 233 | } | 238 | } |
| 234 | } | 239 | } |
| 235 | Kernel::SignalEvent(g_interrupt_event); | 240 | g_interrupt_event->Signal(); |
| 236 | } | 241 | } |
| 237 | 242 | ||
| 238 | /// Executes the next GSP command | 243 | /// Executes the next GSP command |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5abcb2596..835055af4 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -12,13 +12,13 @@ | |||
| 12 | namespace Service { | 12 | namespace Service { |
| 13 | namespace HID { | 13 | namespace HID { |
| 14 | 14 | ||
| 15 | Handle g_shared_mem = 0; | 15 | Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem = nullptr; |
| 16 | 16 | ||
| 17 | Handle g_event_pad_or_touch_1 = 0; | 17 | Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; |
| 18 | Handle g_event_pad_or_touch_2 = 0; | 18 | Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; |
| 19 | Handle g_event_accelerometer = 0; | 19 | Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; |
| 20 | Handle g_event_gyroscope = 0; | 20 | Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; |
| 21 | Handle g_event_debug_pad = 0; | 21 | Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; |
| 22 | 22 | ||
| 23 | // Next Pad state update information | 23 | // Next Pad state update information |
| 24 | static PadState next_state = {{0}}; | 24 | static PadState next_state = {{0}}; |
| @@ -30,7 +30,7 @@ static s16 next_circle_y = 0; | |||
| 30 | * Gets a pointer to the PadData structure inside HID shared memory | 30 | * Gets a pointer to the PadData structure inside HID shared memory |
| 31 | */ | 31 | */ |
| 32 | static inline PadData* GetPadData() { | 32 | static inline PadData* GetPadData() { |
| 33 | return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(g_shared_mem, 0).ValueOr(nullptr)); | 33 | return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| @@ -115,19 +115,21 @@ void PadUpdateComplete() { | |||
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | // Signal both handles when there's an update to Pad or touch | 117 | // Signal both handles when there's an update to Pad or touch |
| 118 | Kernel::SignalEvent(g_event_pad_or_touch_1); | 118 | g_event_pad_or_touch_1->Signal(); |
| 119 | Kernel::SignalEvent(g_event_pad_or_touch_2); | 119 | g_event_pad_or_touch_2->Signal(); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | void HIDInit() { | 122 | void HIDInit() { |
| 123 | g_shared_mem = Kernel::CreateSharedMemory("HID:SharedMem"); // Create shared memory object | 123 | using namespace Kernel; |
| 124 | |||
| 125 | g_shared_mem = SharedMemory::Create("HID:SharedMem").MoveFrom(); | ||
| 124 | 126 | ||
| 125 | // Create event handles | 127 | // Create event handles |
| 126 | g_event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); | 128 | g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1").MoveFrom(); |
| 127 | g_event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); | 129 | g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2").MoveFrom(); |
| 128 | g_event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); | 130 | g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer").MoveFrom(); |
| 129 | g_event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventGyroscope"); | 131 | g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope").MoveFrom(); |
| 130 | g_event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventDebugPad"); | 132 | g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad").MoveFrom(); |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | void HIDShutdown() { | 135 | void HIDShutdown() { |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 73cdaa527..2116d2ca3 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -9,18 +9,23 @@ | |||
| 9 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 11 | 11 | ||
| 12 | namespace Kernel { | ||
| 13 | class SharedMemory; | ||
| 14 | class Event; | ||
| 15 | } | ||
| 16 | |||
| 12 | namespace Service { | 17 | namespace Service { |
| 13 | namespace HID { | 18 | namespace HID { |
| 14 | 19 | ||
| 15 | // Handle to shared memory region designated to HID_User service | 20 | // Handle to shared memory region designated to HID_User service |
| 16 | extern Handle g_shared_mem; | 21 | extern Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem; |
| 17 | 22 | ||
| 18 | // Event handles | 23 | // Event handles |
| 19 | extern Handle g_event_pad_or_touch_1; | 24 | extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; |
| 20 | extern Handle g_event_pad_or_touch_2; | 25 | extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; |
| 21 | extern Handle g_event_accelerometer; | 26 | extern Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; |
| 22 | extern Handle g_event_gyroscope; | 27 | extern Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; |
| 23 | extern Handle g_event_debug_pad; | 28 | extern Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; |
| 24 | 29 | ||
| 25 | /** | 30 | /** |
| 26 | * Structure of a Pad controller state. | 31 | * Structure of a Pad controller state. |
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index 3a6275707..5444aa5ee 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include "common/log.h" | 5 | #include "common/log.h" |
| 6 | 6 | ||
| 7 | #include "core/hle/hle.h" | 7 | #include "core/hle/hle.h" |
| 8 | #include "core/hle/kernel/event.h" | ||
| 9 | #include "core/hle/kernel/shared_memory.h" | ||
| 8 | #include "core/hle/service/hid/hid.h" | 10 | #include "core/hle/service/hid/hid.h" |
| 9 | #include "hid_user.h" | 11 | #include "hid_user.h" |
| 10 | 12 | ||
| @@ -46,12 +48,13 @@ void GetIPCHandles(Service::Interface* self) { | |||
| 46 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 48 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 47 | 49 | ||
| 48 | cmd_buff[1] = 0; // No error | 50 | cmd_buff[1] = 0; // No error |
| 49 | cmd_buff[3] = Service::HID::g_shared_mem; | 51 | // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) |
| 50 | cmd_buff[4] = Service::HID::g_event_pad_or_touch_1; | 52 | cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); |
| 51 | cmd_buff[5] = Service::HID::g_event_pad_or_touch_2; | 53 | cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); |
| 52 | cmd_buff[6] = Service::HID::g_event_accelerometer; | 54 | cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); |
| 53 | cmd_buff[7] = Service::HID::g_event_gyroscope; | 55 | cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); |
| 54 | cmd_buff[8] = Service::HID::g_event_debug_pad; | 56 | cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); |
| 57 | cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); | ||
| 55 | } | 58 | } |
| 56 | 59 | ||
| 57 | const Interface::FunctionInfo FunctionTable[] = { | 60 | const Interface::FunctionInfo FunctionTable[] = { |
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 082834cfe..aa0aac3bb 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace SRV { | 12 | namespace SRV { |
| 13 | 13 | ||
| 14 | static Handle g_event_handle = 0; | 14 | static Kernel::SharedPtr<Kernel::Event> event_handle; |
| 15 | 15 | ||
| 16 | static void Initialize(Service::Interface* self) { | 16 | static void Initialize(Service::Interface* self) { |
| 17 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 17 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| @@ -23,11 +23,11 @@ static void GetProcSemaphore(Service::Interface* self) { | |||
| 23 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 23 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 24 | 24 | ||
| 25 | // TODO(bunnei): Change to a semaphore once these have been implemented | 25 | // TODO(bunnei): Change to a semaphore once these have been implemented |
| 26 | g_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "SRV:Event"); | 26 | event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event").MoveFrom(); |
| 27 | Kernel::ClearEvent(g_event_handle); | 27 | event_handle->Clear(); |
| 28 | 28 | ||
| 29 | cmd_buff[1] = 0; // No error | 29 | cmd_buff[1] = 0; // No error |
| 30 | cmd_buff[3] = g_event_handle; | 30 | cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static void GetServiceHandle(Service::Interface* self) { | 33 | static void GetServiceHandle(Service::Interface* self) { |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 3d743f125..88813c2ce 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | // Namespace SVC | 26 | // Namespace SVC |
| 27 | 27 | ||
| 28 | using Kernel::SharedPtr; | 28 | using Kernel::SharedPtr; |
| 29 | using Kernel::ERR_INVALID_HANDLE; | ||
| 29 | 30 | ||
| 30 | namespace SVC { | 31 | namespace SVC { |
| 31 | 32 | ||
| @@ -38,7 +39,7 @@ enum ControlMemoryOperation { | |||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | /// Map application or GSP heap memory | 41 | /// Map application or GSP heap memory |
| 41 | static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | 42 | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { |
| 42 | LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", | 43 | LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", |
| 43 | operation, addr0, addr1, size, permissions); | 44 | operation, addr0, addr1, size, permissions); |
| 44 | 45 | ||
| @@ -58,35 +59,42 @@ static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, | |||
| 58 | default: | 59 | default: |
| 59 | LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); | 60 | LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); |
| 60 | } | 61 | } |
| 61 | return 0; | 62 | return RESULT_SUCCESS; |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | /// Maps a memory block to specified address | 65 | /// Maps a memory block to specified address |
| 65 | static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { | 66 | static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { |
| 67 | using Kernel::SharedMemory; | ||
| 68 | using Kernel::MemoryPermission; | ||
| 69 | |||
| 66 | LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", | 70 | LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", |
| 67 | handle, addr, permissions, other_permissions); | 71 | handle, addr, permissions, other_permissions); |
| 68 | 72 | ||
| 69 | Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions); | 73 | SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); |
| 74 | if (shared_memory == nullptr) | ||
| 75 | return ERR_INVALID_HANDLE; | ||
| 76 | |||
| 77 | MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); | ||
| 70 | switch (permissions_type) { | 78 | switch (permissions_type) { |
| 71 | case Kernel::MemoryPermission::Read: | 79 | case MemoryPermission::Read: |
| 72 | case Kernel::MemoryPermission::Write: | 80 | case MemoryPermission::Write: |
| 73 | case Kernel::MemoryPermission::ReadWrite: | 81 | case MemoryPermission::ReadWrite: |
| 74 | case Kernel::MemoryPermission::Execute: | 82 | case MemoryPermission::Execute: |
| 75 | case Kernel::MemoryPermission::ReadExecute: | 83 | case MemoryPermission::ReadExecute: |
| 76 | case Kernel::MemoryPermission::WriteExecute: | 84 | case MemoryPermission::WriteExecute: |
| 77 | case Kernel::MemoryPermission::ReadWriteExecute: | 85 | case MemoryPermission::ReadWriteExecute: |
| 78 | case Kernel::MemoryPermission::DontCare: | 86 | case MemoryPermission::DontCare: |
| 79 | Kernel::MapSharedMemory(handle, addr, permissions_type, | 87 | shared_memory->Map(addr, permissions_type, |
| 80 | static_cast<Kernel::MemoryPermission>(other_permissions)); | 88 | static_cast<MemoryPermission>(other_permissions)); |
| 81 | break; | 89 | break; |
| 82 | default: | 90 | default: |
| 83 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); | 91 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); |
| 84 | } | 92 | } |
| 85 | return 0; | 93 | return RESULT_SUCCESS; |
| 86 | } | 94 | } |
| 87 | 95 | ||
| 88 | /// Connect to an OS service given the port name, returns the handle to the port to out | 96 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 89 | static Result ConnectToPort(Handle* out, const char* port_name) { | 97 | static ResultCode ConnectToPort(Handle* out, const char* port_name) { |
| 90 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | 98 | Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |
| 91 | 99 | ||
| 92 | LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); | 100 | LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); |
| @@ -94,33 +102,33 @@ static Result ConnectToPort(Handle* out, const char* port_name) { | |||
| 94 | 102 | ||
| 95 | *out = service->GetHandle(); | 103 | *out = service->GetHandle(); |
| 96 | 104 | ||
| 97 | return 0; | 105 | return RESULT_SUCCESS; |
| 98 | } | 106 | } |
| 99 | 107 | ||
| 100 | /// Synchronize to an OS service | 108 | /// Synchronize to an OS service |
| 101 | static Result SendSyncRequest(Handle handle) { | 109 | static ResultCode SendSyncRequest(Handle handle) { |
| 102 | SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); | 110 | SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); |
| 103 | if (session == nullptr) { | 111 | if (session == nullptr) { |
| 104 | return InvalidHandle(ErrorModule::Kernel).raw; | 112 | return ERR_INVALID_HANDLE; |
| 105 | } | 113 | } |
| 106 | 114 | ||
| 107 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); | 115 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); |
| 108 | 116 | ||
| 109 | return session->SyncRequest().Code().raw; | 117 | return session->SyncRequest().Code(); |
| 110 | } | 118 | } |
| 111 | 119 | ||
| 112 | /// Close a handle | 120 | /// Close a handle |
| 113 | static Result CloseHandle(Handle handle) { | 121 | static ResultCode CloseHandle(Handle handle) { |
| 114 | // ImplementMe | 122 | // ImplementMe |
| 115 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); | 123 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); |
| 116 | return 0; | 124 | return RESULT_SUCCESS; |
| 117 | } | 125 | } |
| 118 | 126 | ||
| 119 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | 127 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds |
| 120 | static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | 128 | static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { |
| 121 | auto object = Kernel::g_handle_table.GetWaitObject(handle); | 129 | auto object = Kernel::g_handle_table.GetWaitObject(handle); |
| 122 | if (object == nullptr) | 130 | if (object == nullptr) |
| 123 | return InvalidHandle(ErrorModule::Kernel).raw; | 131 | return ERR_INVALID_HANDLE; |
| 124 | 132 | ||
| 125 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, | 133 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, |
| 126 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); | 134 | object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); |
| @@ -137,22 +145,22 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 137 | HLE::Reschedule(__func__); | 145 | HLE::Reschedule(__func__); |
| 138 | 146 | ||
| 139 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 147 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 140 | return RESULT_INVALID.raw; | 148 | return RESULT_INVALID; |
| 141 | } | 149 | } |
| 142 | 150 | ||
| 143 | object->Acquire(); | 151 | object->Acquire(); |
| 144 | 152 | ||
| 145 | return RESULT_SUCCESS.raw; | 153 | return RESULT_SUCCESS; |
| 146 | } | 154 | } |
| 147 | 155 | ||
| 148 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 156 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds |
| 149 | static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | 157 | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { |
| 150 | bool wait_thread = !wait_all; | 158 | bool wait_thread = !wait_all; |
| 151 | int handle_index = 0; | 159 | int handle_index = 0; |
| 152 | 160 | ||
| 153 | // Check if 'handles' is invalid | 161 | // Check if 'handles' is invalid |
| 154 | if (handles == nullptr) | 162 | if (handles == nullptr) |
| 155 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw; | 163 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 156 | 164 | ||
| 157 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If | 165 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If |
| 158 | // this happens, the running application will crash. | 166 | // this happens, the running application will crash. |
| @@ -160,7 +168,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 160 | 168 | ||
| 161 | // Check if 'handle_count' is invalid | 169 | // Check if 'handle_count' is invalid |
| 162 | if (handle_count < 0) | 170 | if (handle_count < 0) |
| 163 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; | 171 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); |
| 164 | 172 | ||
| 165 | // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if | 173 | // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if |
| 166 | // necessary | 174 | // necessary |
| @@ -169,7 +177,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 169 | for (int i = 0; i < handle_count; ++i) { | 177 | for (int i = 0; i < handle_count; ++i) { |
| 170 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); | 178 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); |
| 171 | if (object == nullptr) | 179 | if (object == nullptr) |
| 172 | return InvalidHandle(ErrorModule::Kernel).raw; | 180 | return ERR_INVALID_HANDLE; |
| 173 | 181 | ||
| 174 | // Check if the current thread should wait on this object... | 182 | // Check if the current thread should wait on this object... |
| 175 | if (object->ShouldWait()) { | 183 | if (object->ShouldWait()) { |
| @@ -213,7 +221,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 213 | HLE::Reschedule(__func__); | 221 | HLE::Reschedule(__func__); |
| 214 | 222 | ||
| 215 | // NOTE: output of this SVC will be set later depending on how the thread resumes | 223 | // NOTE: output of this SVC will be set later depending on how the thread resumes |
| 216 | return RESULT_INVALID.raw; | 224 | return RESULT_INVALID; |
| 217 | } | 225 | } |
| 218 | 226 | ||
| 219 | // Acquire objects if we did not wait... | 227 | // Acquire objects if we did not wait... |
| @@ -235,22 +243,32 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||
| 235 | // not seem to set it to any meaningful value. | 243 | // not seem to set it to any meaningful value. |
| 236 | *out = wait_all ? 0 : handle_index; | 244 | *out = wait_all ? 0 : handle_index; |
| 237 | 245 | ||
| 238 | return RESULT_SUCCESS.raw; | 246 | return RESULT_SUCCESS; |
| 239 | } | 247 | } |
| 240 | 248 | ||
| 241 | /// Create an address arbiter (to allocate access to shared resources) | 249 | /// Create an address arbiter (to allocate access to shared resources) |
| 242 | static Result CreateAddressArbiter(u32* arbiter) { | 250 | static ResultCode CreateAddressArbiter(Handle* out_handle) { |
| 243 | Handle handle = Kernel::CreateAddressArbiter(); | 251 | using Kernel::AddressArbiter; |
| 244 | *arbiter = handle; | 252 | |
| 245 | return 0; | 253 | CASCADE_RESULT(SharedPtr<AddressArbiter> arbiter, AddressArbiter::Create()); |
| 254 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); | ||
| 255 | LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); | ||
| 256 | return RESULT_SUCCESS; | ||
| 246 | } | 257 | } |
| 247 | 258 | ||
| 248 | /// Arbitrate address | 259 | /// Arbitrate address |
| 249 | static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { | 260 | static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { |
| 250 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter, | 261 | using Kernel::AddressArbiter; |
| 262 | |||
| 263 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, | ||
| 251 | address, type, value); | 264 | address, type, value); |
| 252 | return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), | 265 | |
| 253 | address, value, nanoseconds).raw; | 266 | SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle); |
| 267 | if (arbiter == nullptr) | ||
| 268 | return ERR_INVALID_HANDLE; | ||
| 269 | |||
| 270 | return arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), | ||
| 271 | address, value, nanoseconds); | ||
| 254 | } | 272 | } |
| 255 | 273 | ||
| 256 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 274 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |
| @@ -259,26 +277,26 @@ static void OutputDebugString(const char* string) { | |||
| 259 | } | 277 | } |
| 260 | 278 | ||
| 261 | /// Get resource limit | 279 | /// Get resource limit |
| 262 | static Result GetResourceLimit(Handle* resource_limit, Handle process) { | 280 | static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) { |
| 263 | // With regards to proceess values: | 281 | // With regards to proceess values: |
| 264 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for | 282 | // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for |
| 265 | // the current KThread. | 283 | // the current KThread. |
| 266 | *resource_limit = 0xDEADBEEF; | 284 | *resource_limit = 0xDEADBEEF; |
| 267 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); | 285 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); |
| 268 | return 0; | 286 | return RESULT_SUCCESS; |
| 269 | } | 287 | } |
| 270 | 288 | ||
| 271 | /// Get resource limit current values | 289 | /// Get resource limit current values |
| 272 | static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, | 290 | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, |
| 273 | s32 name_count) { | 291 | s32 name_count) { |
| 274 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", | 292 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", |
| 275 | resource_limit, names, name_count); | 293 | resource_limit, names, name_count); |
| 276 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now | 294 | Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now |
| 277 | return 0; | 295 | return RESULT_SUCCESS; |
| 278 | } | 296 | } |
| 279 | 297 | ||
| 280 | /// Creates a new thread | 298 | /// Creates a new thread |
| 281 | static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { | 299 | static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { |
| 282 | using Kernel::Thread; | 300 | using Kernel::Thread; |
| 283 | 301 | ||
| 284 | std::string name; | 302 | std::string name; |
| @@ -289,25 +307,20 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top | |||
| 289 | name = Common::StringFromFormat("unknown-%08x", entry_point); | 307 | name = Common::StringFromFormat("unknown-%08x", entry_point); |
| 290 | } | 308 | } |
| 291 | 309 | ||
| 292 | ResultVal<SharedPtr<Thread>> thread_res = Kernel::Thread::Create( | 310 | CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create( |
| 293 | name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE); | 311 | name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE)); |
| 294 | if (thread_res.Failed()) | 312 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); |
| 295 | return thread_res.Code().raw; | ||
| 296 | SharedPtr<Thread> thread = std::move(*thread_res); | ||
| 297 | |||
| 298 | // TODO(yuriks): Create new handle instead of using built-in | ||
| 299 | Core::g_app_core->SetReg(1, thread->GetHandle()); | ||
| 300 | 313 | ||
| 301 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | 314 | LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |
| 302 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, | 315 | "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, |
| 303 | name.c_str(), arg, stack_top, priority, processor_id, thread->GetHandle()); | 316 | name.c_str(), arg, stack_top, priority, processor_id, *out_handle); |
| 304 | 317 | ||
| 305 | if (THREADPROCESSORID_1 == processor_id) { | 318 | if (THREADPROCESSORID_1 == processor_id) { |
| 306 | LOG_WARNING(Kernel_SVC, | 319 | LOG_WARNING(Kernel_SVC, |
| 307 | "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); | 320 | "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); |
| 308 | } | 321 | } |
| 309 | 322 | ||
| 310 | return 0; | 323 | return RESULT_SUCCESS; |
| 311 | } | 324 | } |
| 312 | 325 | ||
| 313 | /// Called when a thread exits | 326 | /// Called when a thread exits |
| @@ -319,128 +332,192 @@ static void ExitThread() { | |||
| 319 | } | 332 | } |
| 320 | 333 | ||
| 321 | /// Gets the priority for the specified thread | 334 | /// Gets the priority for the specified thread |
| 322 | static Result GetThreadPriority(s32* priority, Handle handle) { | 335 | static ResultCode GetThreadPriority(s32* priority, Handle handle) { |
| 323 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 336 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 324 | if (thread == nullptr) | 337 | if (thread == nullptr) |
| 325 | return InvalidHandle(ErrorModule::Kernel).raw; | 338 | return ERR_INVALID_HANDLE; |
| 326 | 339 | ||
| 327 | *priority = thread->GetPriority(); | 340 | *priority = thread->GetPriority(); |
| 328 | return RESULT_SUCCESS.raw; | 341 | return RESULT_SUCCESS; |
| 329 | } | 342 | } |
| 330 | 343 | ||
| 331 | /// Sets the priority for the specified thread | 344 | /// Sets the priority for the specified thread |
| 332 | static Result SetThreadPriority(Handle handle, s32 priority) { | 345 | static ResultCode SetThreadPriority(Handle handle, s32 priority) { |
| 333 | SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 346 | SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 334 | if (thread == nullptr) | 347 | if (thread == nullptr) |
| 335 | return InvalidHandle(ErrorModule::Kernel).raw; | 348 | return ERR_INVALID_HANDLE; |
| 336 | 349 | ||
| 337 | thread->SetPriority(priority); | 350 | thread->SetPriority(priority); |
| 338 | return RESULT_SUCCESS.raw; | 351 | return RESULT_SUCCESS; |
| 339 | } | 352 | } |
| 340 | 353 | ||
| 341 | /// Create a mutex | 354 | /// Create a mutex |
| 342 | static Result CreateMutex(Handle* mutex, u32 initial_locked) { | 355 | static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { |
| 343 | *mutex = Kernel::CreateMutex((initial_locked != 0)); | 356 | using Kernel::Mutex; |
| 357 | |||
| 358 | CASCADE_RESULT(SharedPtr<Mutex> mutex, Mutex::Create(initial_locked != 0)); | ||
| 359 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); | ||
| 360 | |||
| 344 | LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", | 361 | LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", |
| 345 | initial_locked ? "true" : "false", *mutex); | 362 | initial_locked ? "true" : "false", *out_handle); |
| 346 | return 0; | 363 | return RESULT_SUCCESS; |
| 347 | } | 364 | } |
| 348 | 365 | ||
| 349 | /// Release a mutex | 366 | /// Release a mutex |
| 350 | static Result ReleaseMutex(Handle handle) { | 367 | static ResultCode ReleaseMutex(Handle handle) { |
| 368 | using Kernel::Mutex; | ||
| 369 | |||
| 351 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); | 370 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); |
| 352 | ResultCode res = Kernel::ReleaseMutex(handle); | 371 | |
| 353 | return res.raw; | 372 | SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle); |
| 373 | if (mutex == nullptr) | ||
| 374 | return ERR_INVALID_HANDLE; | ||
| 375 | |||
| 376 | mutex->Release(); | ||
| 377 | return RESULT_SUCCESS; | ||
| 354 | } | 378 | } |
| 355 | 379 | ||
| 356 | /// Get the ID for the specified thread. | 380 | /// Get the ID for the specified thread. |
| 357 | static Result GetThreadId(u32* thread_id, Handle handle) { | 381 | static ResultCode GetThreadId(u32* thread_id, Handle handle) { |
| 358 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); | 382 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); |
| 359 | 383 | ||
| 360 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 384 | const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| 361 | if (thread == nullptr) | 385 | if (thread == nullptr) |
| 362 | return InvalidHandle(ErrorModule::Kernel).raw; | 386 | return ERR_INVALID_HANDLE; |
| 363 | 387 | ||
| 364 | *thread_id = thread->GetThreadId(); | 388 | *thread_id = thread->GetThreadId(); |
| 365 | return RESULT_SUCCESS.raw; | 389 | return RESULT_SUCCESS; |
| 366 | } | 390 | } |
| 367 | 391 | ||
| 368 | /// Creates a semaphore | 392 | /// Creates a semaphore |
| 369 | static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) { | 393 | static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { |
| 370 | ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count); | 394 | using Kernel::Semaphore; |
| 395 | |||
| 396 | CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count)); | ||
| 397 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); | ||
| 398 | |||
| 371 | LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", | 399 | LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", |
| 372 | initial_count, max_count, *semaphore); | 400 | initial_count, max_count, *out_handle); |
| 373 | return res.raw; | 401 | return RESULT_SUCCESS; |
| 374 | } | 402 | } |
| 375 | 403 | ||
| 376 | /// Releases a certain number of slots in a semaphore | 404 | /// Releases a certain number of slots in a semaphore |
| 377 | static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) { | 405 | static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { |
| 378 | LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore); | 406 | using Kernel::Semaphore; |
| 379 | ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count); | 407 | |
| 380 | return res.raw; | 408 | LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle); |
| 409 | |||
| 410 | SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle); | ||
| 411 | if (semaphore == nullptr) | ||
| 412 | return ERR_INVALID_HANDLE; | ||
| 413 | |||
| 414 | CASCADE_RESULT(*count, semaphore->Release(release_count)); | ||
| 415 | return RESULT_SUCCESS; | ||
| 381 | } | 416 | } |
| 382 | 417 | ||
| 383 | /// Query memory | 418 | /// Query memory |
| 384 | static Result QueryMemory(void* info, void* out, u32 addr) { | 419 | static ResultCode QueryMemory(void* info, void* out, u32 addr) { |
| 385 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); | 420 | LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); |
| 386 | return 0; | 421 | return RESULT_SUCCESS; |
| 387 | } | 422 | } |
| 388 | 423 | ||
| 389 | /// Create an event | 424 | /// Create an event |
| 390 | static Result CreateEvent(Handle* evt, u32 reset_type) { | 425 | static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { |
| 391 | *evt = Kernel::CreateEvent((ResetType)reset_type); | 426 | CASCADE_RESULT(auto evt, Kernel::Event::Create(static_cast<ResetType>(reset_type))); |
| 427 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); | ||
| 428 | |||
| 392 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | 429 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |
| 393 | reset_type, *evt); | 430 | reset_type, *out_handle); |
| 394 | return 0; | 431 | return RESULT_SUCCESS; |
| 395 | } | 432 | } |
| 396 | 433 | ||
| 397 | /// Duplicates a kernel handle | 434 | /// Duplicates a kernel handle |
| 398 | static Result DuplicateHandle(Handle* out, Handle handle) { | 435 | static ResultCode DuplicateHandle(Handle* out, Handle handle) { |
| 399 | ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); | 436 | ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); |
| 400 | if (out_h.Succeeded()) { | 437 | if (out_h.Succeeded()) { |
| 401 | *out = *out_h; | 438 | *out = *out_h; |
| 402 | LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); | 439 | LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); |
| 403 | } | 440 | } |
| 404 | return out_h.Code().raw; | 441 | return out_h.Code(); |
| 405 | } | 442 | } |
| 406 | 443 | ||
| 407 | /// Signals an event | 444 | /// Signals an event |
| 408 | static Result SignalEvent(Handle evt) { | 445 | static ResultCode SignalEvent(Handle handle) { |
| 409 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); | 446 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); |
| 447 | |||
| 448 | auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||
| 449 | if (evt == nullptr) | ||
| 450 | return ERR_INVALID_HANDLE; | ||
| 451 | |||
| 452 | evt->Signal(); | ||
| 410 | HLE::Reschedule(__func__); | 453 | HLE::Reschedule(__func__); |
| 411 | return Kernel::SignalEvent(evt).raw; | 454 | return RESULT_SUCCESS; |
| 412 | } | 455 | } |
| 413 | 456 | ||
| 414 | /// Clears an event | 457 | /// Clears an event |
| 415 | static Result ClearEvent(Handle evt) { | 458 | static ResultCode ClearEvent(Handle handle) { |
| 416 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); | 459 | LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); |
| 417 | return Kernel::ClearEvent(evt).raw; | 460 | |
| 461 | auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||
| 462 | if (evt == nullptr) | ||
| 463 | return ERR_INVALID_HANDLE; | ||
| 464 | |||
| 465 | evt->Clear(); | ||
| 466 | return RESULT_SUCCESS; | ||
| 418 | } | 467 | } |
| 419 | 468 | ||
| 420 | /// Creates a timer | 469 | /// Creates a timer |
| 421 | static Result CreateTimer(Handle* handle, u32 reset_type) { | 470 | static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { |
| 422 | ResultCode res = Kernel::CreateTimer(handle, static_cast<ResetType>(reset_type)); | 471 | using Kernel::Timer; |
| 472 | |||
| 473 | CASCADE_RESULT(auto timer, Timer::Create(static_cast<ResetType>(reset_type))); | ||
| 474 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); | ||
| 475 | |||
| 423 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | 476 | LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |
| 424 | reset_type, *handle); | 477 | reset_type, *out_handle); |
| 425 | return res.raw; | 478 | return RESULT_SUCCESS; |
| 426 | } | 479 | } |
| 427 | 480 | ||
| 428 | /// Clears a timer | 481 | /// Clears a timer |
| 429 | static Result ClearTimer(Handle handle) { | 482 | static ResultCode ClearTimer(Handle handle) { |
| 483 | using Kernel::Timer; | ||
| 484 | |||
| 430 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 485 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 431 | return Kernel::ClearTimer(handle).raw; | 486 | |
| 487 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 488 | if (timer == nullptr) | ||
| 489 | return ERR_INVALID_HANDLE; | ||
| 490 | |||
| 491 | timer->Clear(); | ||
| 492 | return RESULT_SUCCESS; | ||
| 432 | } | 493 | } |
| 433 | 494 | ||
| 434 | /// Starts a timer | 495 | /// Starts a timer |
| 435 | static Result SetTimer(Handle handle, s64 initial, s64 interval) { | 496 | static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { |
| 497 | using Kernel::Timer; | ||
| 498 | |||
| 436 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 499 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 437 | return Kernel::SetTimer(handle, initial, interval).raw; | 500 | |
| 501 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 502 | if (timer == nullptr) | ||
| 503 | return ERR_INVALID_HANDLE; | ||
| 504 | |||
| 505 | timer->Set(initial, interval); | ||
| 506 | return RESULT_SUCCESS; | ||
| 438 | } | 507 | } |
| 439 | 508 | ||
| 440 | /// Cancels a timer | 509 | /// Cancels a timer |
| 441 | static Result CancelTimer(Handle handle) { | 510 | static ResultCode CancelTimer(Handle handle) { |
| 511 | using Kernel::Timer; | ||
| 512 | |||
| 442 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 513 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 443 | return Kernel::CancelTimer(handle).raw; | 514 | |
| 515 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 516 | if (timer == nullptr) | ||
| 517 | return ERR_INVALID_HANDLE; | ||
| 518 | |||
| 519 | timer->Cancel(); | ||
| 520 | return RESULT_SUCCESS; | ||
| 444 | } | 521 | } |
| 445 | 522 | ||
| 446 | /// Sleep the current thread | 523 | /// Sleep the current thread |
| @@ -462,15 +539,16 @@ static s64 GetSystemTick() { | |||
| 462 | } | 539 | } |
| 463 | 540 | ||
| 464 | /// Creates a memory block at the specified address with the specified permissions and size | 541 | /// Creates a memory block at the specified address with the specified permissions and size |
| 465 | static Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 my_permission, | 542 | static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, |
| 466 | u32 other_permission) { | 543 | u32 other_permission) { |
| 467 | 544 | using Kernel::SharedMemory; | |
| 468 | // TODO(Subv): Implement this function | 545 | // TODO(Subv): Implement this function |
| 469 | 546 | ||
| 470 | Handle shared_memory = Kernel::CreateSharedMemory(); | 547 | CASCADE_RESULT(auto shared_memory, SharedMemory::Create()); |
| 471 | *memblock = shared_memory; | 548 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); |
| 549 | |||
| 472 | LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); | 550 | LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); |
| 473 | return 0; | 551 | return RESULT_SUCCESS; |
| 474 | } | 552 | } |
| 475 | 553 | ||
| 476 | const HLE::FunctionDef SVC_Table[] = { | 554 | const HLE::FunctionDef SVC_Table[] = { |
diff --git a/src/core/mem_map.h b/src/core/mem_map.h index fad40ae0c..8f4f21fec 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h | |||
| @@ -7,12 +7,9 @@ | |||
| 7 | #include "common/common.h" | 7 | #include "common/common.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | 9 | ||
| 10 | namespace Memory { | 10 | #include "core/hle/kernel/kernel.h" |
| 11 | 11 | ||
| 12 | // TODO: It would be nice to eventually replace these with strong types that prevent accidental | 12 | namespace Memory { |
| 13 | // conversion between each other. | ||
| 14 | typedef u32 VAddr; ///< Represents a pointer in the ARM11 virtual address space. | ||
| 15 | typedef u32 PAddr; ///< Represents a pointer in the physical address space. | ||
| 16 | 13 | ||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 18 | 15 | ||
| @@ -190,7 +187,3 @@ VAddr PhysicalToVirtualAddress(PAddr addr); | |||
| 190 | PAddr VirtualToPhysicalAddress(VAddr addr); | 187 | PAddr VirtualToPhysicalAddress(VAddr addr); |
| 191 | 188 | ||
| 192 | } // namespace | 189 | } // namespace |
| 193 | |||
| 194 | // These are used often, so re-export then on the root namespace | ||
| 195 | using Memory::VAddr; | ||
| 196 | using Memory::PAddr; | ||