mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #503 from yuriks/kernel-lifetime4
Kernel Lifetime Reform Pt. 4
This commit is contained in:
		
						commit
						28702cbfeb
					
				
					 29 changed files with 724 additions and 730 deletions
				
			
		|  | @ -31,6 +31,10 @@ template<> struct CompileTimeAssert<true> {}; | ||||||
| 
 | 
 | ||||||
| #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | ||||||
| 
 | 
 | ||||||
|  | /// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
 | ||||||
|  | #define CONCAT2(x, y) DO_CONCAT2(x, y) | ||||||
|  | #define DO_CONCAT2(x, y) x ## y | ||||||
|  | 
 | ||||||
| #ifndef _MSC_VER | #ifndef _MSC_VER | ||||||
| 
 | 
 | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  |  | ||||||
|  | @ -4,6 +4,8 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | 
 | ||||||
| namespace detail { | namespace detail { | ||||||
|     template <typename Func> |     template <typename Func> | ||||||
|     struct ScopeExitHelper { |     struct ScopeExitHelper { | ||||||
|  | @ -34,4 +36,4 @@ namespace detail { | ||||||
|  * } |  * } | ||||||
|  * \endcode |  * \endcode | ||||||
|  */ |  */ | ||||||
| #define SCOPE_EXIT(body) auto scope_exit_helper_##__LINE__ = detail::ScopeExit([&]() body) | #define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) | ||||||
|  |  | ||||||
|  | @ -33,114 +33,105 @@ static inline void FuncReturn64(u64 res) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Function wrappers that return type s32
 | // Function wrappers that return type ResultCode
 | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32, u32, u32, u32)> void Wrap() { | template<ResultCode func(u32, u32, u32, u32)> void Wrap() { | ||||||
|     FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3))); |     FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32, u32, u32, u32, u32)> void Wrap() { | template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ | ||||||
|     FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ |  | ||||||
|     u32 param_1 = 0; |     u32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |     u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { | template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() { | ||||||
|     s32 param_1 = 0; |     s32 param_1 = 0; | ||||||
|     s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), |     s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), | ||||||
|         (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))); |         (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; | ||||||
|     Core::g_app_core->SetReg(1, (u32)param_1); |     Core::g_app_core->SetReg(1, (u32)param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO(bunnei): Is this correct? Probably not - Last parameter looks wrong for ArbitrateAddress
 | template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { | ||||||
| template<s32 func(u32, u32, u32, u32, s64)> void Wrap() { |     FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw); | ||||||
|     FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4)))); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32*)> void Wrap(){ | template<ResultCode func(u32*)> void Wrap(){ | ||||||
|     u32 param_1 = 0; |     u32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1); |     u32 retval = func(¶m_1).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32, s64)> void Wrap() { | template<ResultCode func(u32, s64)> void Wrap() { | ||||||
|     FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2)))); |     FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(void*, void*, u32)> void Wrap(){ | template<ResultCode func(void*, void*, u32)> void Wrap(){ | ||||||
|     FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2))); |     FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(s32*, u32)> void Wrap(){ | template<ResultCode func(s32*, u32)> void Wrap(){ | ||||||
|     s32 param_1 = 0; |     s32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, PARAM(1)); |     u32 retval = func(¶m_1, PARAM(1)).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32, s32)> void Wrap() { | template<ResultCode func(u32, s32)> void Wrap() { | ||||||
|     FuncReturn(func(PARAM(0), (s32)PARAM(1))); |     FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32*, u32)> void Wrap(){ | template<ResultCode func(u32*, u32)> void Wrap(){ | ||||||
|     u32 param_1 = 0; |     u32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, PARAM(1)); |     u32 retval = func(¶m_1, PARAM(1)).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32)> void Wrap() { | template<ResultCode func(u32)> void Wrap() { | ||||||
|     FuncReturn(func(PARAM(0))); |     FuncReturn(func(PARAM(0)).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(void*)> void Wrap() { | template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){ | ||||||
|     FuncReturn(func(Memory::GetPointer(PARAM(0)))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<s32 func(s64*, u32, void*, s32)> void Wrap(){ |  | ||||||
|     FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), |     FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), | ||||||
|         (s32)PARAM(3))); |         (s32)PARAM(3)).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32*, const char*)> void Wrap() { | template<ResultCode func(u32*, const char*)> void Wrap() { | ||||||
|     u32 param_1 = 0; |     u32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))); |     u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32*, s32, s32)> void Wrap() { | template<ResultCode func(u32*, s32, s32)> void Wrap() { | ||||||
|     u32 param_1 = 0; |     u32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, PARAM(1), PARAM(2)); |     u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(s32*, u32, s32)> void Wrap() { | template<ResultCode func(s32*, u32, s32)> void Wrap() { | ||||||
|     s32 param_1 = 0; |     s32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, PARAM(1), PARAM(2)); |     u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32*, u32, u32, u32, u32)> void Wrap() { | template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { | ||||||
|     u32 param_1 = 0; |     u32 param_1 = 0; | ||||||
|     u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)); |     u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; | ||||||
|     Core::g_app_core->SetReg(1, param_1); |     Core::g_app_core->SetReg(1, param_1); | ||||||
|     FuncReturn(retval); |     FuncReturn(retval); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<s32 func(u32, s64, s64)> void Wrap() { | template<ResultCode func(u32, s64, s64)> void Wrap() { | ||||||
|     s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2); |     s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2); | ||||||
|     s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1); |     s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1); | ||||||
|     FuncReturn(func(PARAM(0), param1, param2)); |     FuncReturn(func(PARAM(0), param1, param2).raw); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
|  | @ -15,26 +15,18 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class AddressArbiter : public Object { | ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { | ||||||
| public: |     SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); | ||||||
|     std::string GetTypeName() const override { return "Arbiter"; } |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|     std::string GetName() const override { return name; } |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter)); | ||||||
| 
 | 
 | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; |     address_arbiter->name = std::move(name); | ||||||
|     HandleType GetHandleType() const override { return HANDLE_TYPE; } |  | ||||||
| 
 | 
 | ||||||
|     std::string name;   ///< Name of address arbiter object (optional)
 |     return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| /// Arbitrate an address
 |  | ||||||
| ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { |  | ||||||
|     AddressArbiter* object = Kernel::g_handle_table.Get<AddressArbiter>(handle).get(); |  | ||||||
| 
 |  | ||||||
|     if (object == nullptr) |  | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 | 
 | ||||||
|  | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | ||||||
|  |         u64 nanoseconds) { | ||||||
|     switch (type) { |     switch (type) { | ||||||
| 
 | 
 | ||||||
|     // Signal thread(s) waiting for arbitrate address...
 |     // Signal thread(s) waiting for arbitrate address...
 | ||||||
|  | @ -92,20 +84,4 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create an address arbiter
 |  | ||||||
| AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { |  | ||||||
|     AddressArbiter* address_arbiter = new AddressArbiter; |  | ||||||
|     // TOOD(yuriks): Fix error reporting
 |  | ||||||
|     handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE); |  | ||||||
|     address_arbiter->name = name; |  | ||||||
|     return address_arbiter; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Create an address arbiter
 |  | ||||||
| Handle CreateAddressArbiter(const std::string& name) { |  | ||||||
|     Handle handle; |  | ||||||
|     CreateAddressArbiter(handle, name); |  | ||||||
|     return handle; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace Kernel
 | } // namespace Kernel
 | ||||||
|  |  | ||||||
|  | @ -18,7 +18,6 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /// Address arbitration types
 |  | ||||||
| enum class ArbitrationType : u32 { | enum class ArbitrationType : u32 { | ||||||
|     Signal, |     Signal, | ||||||
|     WaitIfLessThan, |     WaitIfLessThan, | ||||||
|  | @ -27,10 +26,28 @@ enum class ArbitrationType : u32 { | ||||||
|     DecrementAndWaitIfLessThanWithTimeout, |     DecrementAndWaitIfLessThanWithTimeout, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Arbitrate an address
 | class AddressArbiter final : public Object { | ||||||
| ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds); | public: | ||||||
|  |     /**
 | ||||||
|  |      * Creates an address arbiter. | ||||||
|  |      * | ||||||
|  |      * @param name Optional name used for debugging. | ||||||
|  |      * @returns The created AddressArbiter. | ||||||
|  |      */ | ||||||
|  |     static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
| /// Create an address arbiter
 |     std::string GetTypeName() const override { return "Arbiter"; } | ||||||
| Handle CreateAddressArbiter(const std::string& name = "Unknown"); |     std::string GetName() const override { return name; } | ||||||
|  | 
 | ||||||
|  |     static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | ||||||
|  |     HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||||||
|  | 
 | ||||||
|  |     std::string name;   ///< Name of address arbiter object (optional)
 | ||||||
|  | 
 | ||||||
|  |     ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     AddressArbiter() = default; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  |  | ||||||
|  | @ -14,78 +14,37 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class Event : public WaitObject { | ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { | ||||||
| public: |     SharedPtr<Event> evt(new Event); | ||||||
|     std::string GetTypeName() const override { return "Event"; } |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|     std::string GetName() const override { return name; } |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt)); | ||||||
| 
 |  | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::Event; |  | ||||||
|     HandleType GetHandleType() const override { return HANDLE_TYPE; } |  | ||||||
| 
 |  | ||||||
|     ResetType intitial_reset_type;          ///< ResetType specified at Event initialization
 |  | ||||||
|     ResetType reset_type;                   ///< Current ResetType
 |  | ||||||
| 
 |  | ||||||
|     bool signaled;                          ///< Whether the event has already been signaled
 |  | ||||||
|     std::string name;                       ///< Name of event (optional)
 |  | ||||||
| 
 |  | ||||||
|     bool ShouldWait() override { |  | ||||||
|         return !signaled; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void Acquire() override { |  | ||||||
|         _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |  | ||||||
| 
 |  | ||||||
|         // Release the event if it's not sticky...
 |  | ||||||
|         if (reset_type != RESETTYPE_STICKY) |  | ||||||
|             signaled = false; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ResultCode SignalEvent(const Handle handle) { |  | ||||||
|     Event* evt = g_handle_table.Get<Event>(handle).get(); |  | ||||||
|     if (evt == nullptr) |  | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 |  | ||||||
|     evt->signaled = true; |  | ||||||
|     evt->WakeupAllWaitingThreads(); |  | ||||||
| 
 |  | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ResultCode ClearEvent(Handle handle) { |  | ||||||
|     Event* evt = g_handle_table.Get<Event>(handle).get(); |  | ||||||
|     if (evt == nullptr) |  | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 |  | ||||||
|     evt->signaled = false; |  | ||||||
| 
 |  | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Creates an event |  | ||||||
|  * @param handle Reference to handle for the newly created mutex |  | ||||||
|  * @param reset_type ResetType describing how to create event |  | ||||||
|  * @param name Optional name of event |  | ||||||
|  * @return Newly created Event object |  | ||||||
|  */ |  | ||||||
| Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { |  | ||||||
|     Event* evt = new Event; |  | ||||||
| 
 |  | ||||||
|     // TOOD(yuriks): Fix error reporting
 |  | ||||||
|     handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); |  | ||||||
| 
 | 
 | ||||||
|     evt->signaled = false; |     evt->signaled = false; | ||||||
|     evt->reset_type = evt->intitial_reset_type = reset_type; |     evt->reset_type = evt->intitial_reset_type = reset_type; | ||||||
|     evt->name = name; |     evt->name = std::move(name); | ||||||
| 
 | 
 | ||||||
|     return evt; |     return MakeResult<SharedPtr<Event>>(evt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Handle CreateEvent(const ResetType reset_type, const std::string& name) { | bool Event::ShouldWait() { | ||||||
|     Handle handle; |     return !signaled; | ||||||
|     Event* evt = CreateEvent(handle, reset_type, name); | } | ||||||
|     return handle; | 
 | ||||||
|  | void Event::Acquire() { | ||||||
|  |     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||||||
|  | 
 | ||||||
|  |     // Release the event if it's not sticky...
 | ||||||
|  |     if (reset_type != RESETTYPE_STICKY) | ||||||
|  |         signaled = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Event::Signal() { | ||||||
|  |     signaled = true; | ||||||
|  |     WakeupAllWaitingThreads(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Event::Clear() { | ||||||
|  |     signaled = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -11,26 +11,35 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /**
 | class Event final : public WaitObject { | ||||||
|  * Signals an event | public: | ||||||
|  * @param handle Handle to event to signal |     /**
 | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |      * Creates an event | ||||||
|  */ |      * @param reset_type ResetType describing how to create event | ||||||
| ResultCode SignalEvent(const Handle handle); |      * @param name Optional name of event | ||||||
|  |      */ | ||||||
|  |     static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
| /**
 |     std::string GetTypeName() const override { return "Event"; } | ||||||
|  * Clears an event |     std::string GetName() const override { return name; } | ||||||
|  * @param handle Handle to event to clear |  | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| ResultCode ClearEvent(Handle handle); |  | ||||||
| 
 | 
 | ||||||
| /**
 |     static const HandleType HANDLE_TYPE = HandleType::Event; | ||||||
|  * Creates an event |     HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||||||
|  * @param reset_type ResetType describing how to create event | 
 | ||||||
|  * @param name Optional name of event |     ResetType intitial_reset_type;          ///< ResetType specified at Event initialization
 | ||||||
|  * @return Handle to newly created Event object |     ResetType reset_type;                   ///< Current ResetType
 | ||||||
|  */ | 
 | ||||||
| Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); |     bool signaled;                          ///< Whether the event has already been signaled
 | ||||||
|  |     std::string name;                       ///< Name of event (optional)
 | ||||||
|  | 
 | ||||||
|  |     bool ShouldWait() override; | ||||||
|  |     void Acquire() override; | ||||||
|  | 
 | ||||||
|  |     void Signal(); | ||||||
|  |     void Clear(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Event() = default; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,11 @@ | ||||||
| typedef u32 Handle; | typedef u32 Handle; | ||||||
| typedef s32 Result; | typedef s32 Result; | ||||||
| 
 | 
 | ||||||
|  | // TODO: It would be nice to eventually replace these with strong types that prevent accidental
 | ||||||
|  | // conversion between each other.
 | ||||||
|  | typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
 | ||||||
|  | typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
 | ||||||
|  | 
 | ||||||
| const Handle INVALID_HANDLE = 0; | const Handle INVALID_HANDLE = 0; | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  | @ -26,7 +31,8 @@ class Thread; | ||||||
| const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | ||||||
|         ErrorSummary::OutOfResource, ErrorLevel::Temporary); |         ErrorSummary::OutOfResource, ErrorLevel::Temporary); | ||||||
| // TOOD: Verify code
 | // TOOD: Verify code
 | ||||||
| const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel); | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, | ||||||
|  |         ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
| 
 | 
 | ||||||
| enum KernelHandle : Handle { | enum KernelHandle : Handle { | ||||||
|     CurrentThread   = 0xFFFF8000, |     CurrentThread   = 0xFFFF8000, | ||||||
|  |  | ||||||
|  | @ -13,59 +13,30 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class Mutex : public WaitObject { |  | ||||||
| public: |  | ||||||
|     std::string GetTypeName() const override { return "Mutex"; } |  | ||||||
|     std::string GetName() const override { return name; } |  | ||||||
| 
 |  | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::Mutex; |  | ||||||
|     HandleType GetHandleType() const override { return HANDLE_TYPE; } |  | ||||||
| 
 |  | ||||||
|     bool initial_locked;                        ///< Initial lock state when mutex was created
 |  | ||||||
|     bool locked;                                ///< Current locked state
 |  | ||||||
|     std::string name;                           ///< Name of mutex (optional)
 |  | ||||||
|     SharedPtr<Thread> holding_thread;           ///< Thread that has acquired the mutex
 |  | ||||||
| 
 |  | ||||||
|     bool ShouldWait() override; |  | ||||||
|     void Acquire() override; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | ||||||
| static MutexMap g_mutex_held_locks; | static MutexMap g_mutex_held_locks; | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * Acquires the specified mutex for the specified thread |  | ||||||
|  * @param mutex Mutex that is to be acquired |  | ||||||
|  * @param thread Thread that will acquire the mutex |  | ||||||
|  */ |  | ||||||
| void MutexAcquireLock(Mutex* mutex, Thread* thread) { |  | ||||||
|     g_mutex_held_locks.insert(std::make_pair(thread, mutex)); |  | ||||||
|     mutex->holding_thread = thread; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Resumes a thread waiting for the specified mutex |  * Resumes a thread waiting for the specified mutex | ||||||
|  * @param mutex The mutex that some thread is waiting on |  * @param mutex The mutex that some thread is waiting on | ||||||
|  */ |  */ | ||||||
| void ResumeWaitingThread(Mutex* mutex) { | static void ResumeWaitingThread(Mutex* mutex) { | ||||||
|  |     // Reset mutex lock thread handle, nothing is waiting
 | ||||||
|  |     mutex->locked = false; | ||||||
|  |     mutex->holding_thread = nullptr; | ||||||
|  | 
 | ||||||
|     // Find the next waiting thread for the mutex...
 |     // Find the next waiting thread for the mutex...
 | ||||||
|     auto next_thread = mutex->WakeupNextThread(); |     auto next_thread = mutex->WakeupNextThread(); | ||||||
|     if (next_thread != nullptr) { |     if (next_thread != nullptr) { | ||||||
|         MutexAcquireLock(mutex, next_thread); |         mutex->Acquire(next_thread); | ||||||
|     } else { |  | ||||||
|         // Reset mutex lock thread handle, nothing is waiting
 |  | ||||||
|         mutex->locked = false; |  | ||||||
|         mutex->holding_thread = nullptr; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ReleaseThreadMutexes(Thread* thread) { | void ReleaseThreadMutexes(Thread* thread) { | ||||||
|     auto locked = g_mutex_held_locks.equal_range(thread); |     auto locked_range = g_mutex_held_locks.equal_range(thread); | ||||||
|      |      | ||||||
|     // Release every mutex that the thread holds, and resume execution on the waiting threads
 |     // Release every mutex that the thread holds, and resume execution on the waiting threads
 | ||||||
|     for (auto iter = locked.first; iter != locked.second; ++iter) { |     for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { | ||||||
|         ResumeWaitingThread(iter->second.get()); |         ResumeWaitingThread(iter->second.get()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -73,72 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { | ||||||
|     g_mutex_held_locks.erase(thread); |     g_mutex_held_locks.erase(thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ReleaseMutex(Mutex* mutex) { | ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { | ||||||
|     if (mutex->locked) { |     SharedPtr<Mutex> mutex(new Mutex); | ||||||
|         auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|  |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); | ||||||
| 
 | 
 | ||||||
|         for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { |     mutex->initial_locked = initial_locked; | ||||||
|             if (iter->second == mutex) { |     mutex->locked = false; | ||||||
|                 g_mutex_held_locks.erase(iter); |     mutex->name = std::move(name); | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         ResumeWaitingThread(mutex); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Releases a mutex |  | ||||||
|  * @param handle Handle to mutex to release |  | ||||||
|  */ |  | ||||||
| ResultCode ReleaseMutex(Handle handle) { |  | ||||||
|     Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get(); |  | ||||||
|     if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 |  | ||||||
|     if (!ReleaseMutex(mutex)) { |  | ||||||
|         // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
 |  | ||||||
|         // what error condition this is supposed to be signaling.
 |  | ||||||
|         return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, |  | ||||||
|                 ErrorSummary::NothingHappened, ErrorLevel::Temporary); |  | ||||||
|     } |  | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Creates a mutex |  | ||||||
|  * @param handle Reference to handle for the newly created mutex |  | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |  | ||||||
|  * @param name Optional name of mutex |  | ||||||
|  * @return Pointer to new Mutex object |  | ||||||
|  */ |  | ||||||
| Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { |  | ||||||
|     Mutex* mutex = new Mutex; |  | ||||||
|     // TODO(yuriks): Fix error reporting
 |  | ||||||
|     handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); |  | ||||||
| 
 |  | ||||||
|     mutex->locked = mutex->initial_locked = initial_locked; |  | ||||||
|     mutex->name = name; |  | ||||||
|     mutex->holding_thread = nullptr; |     mutex->holding_thread = nullptr; | ||||||
| 
 | 
 | ||||||
|     // Acquire mutex with current thread if initialized as locked...
 |     // Acquire mutex with current thread if initialized as locked...
 | ||||||
|     if (mutex->locked) |     if (initial_locked) | ||||||
|         MutexAcquireLock(mutex, GetCurrentThread()); |         mutex->Acquire(); | ||||||
| 
 | 
 | ||||||
|     return mutex; |     return MakeResult<SharedPtr<Mutex>>(mutex); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Creates a mutex |  | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |  | ||||||
|  * @param name Optional name of mutex |  | ||||||
|  * @return Handle to newly created object |  | ||||||
|  */ |  | ||||||
| Handle CreateMutex(bool initial_locked, const std::string& name) { |  | ||||||
|     Handle handle; |  | ||||||
|     Mutex* mutex = CreateMutex(handle, initial_locked, name); |  | ||||||
|     return handle; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Mutex::ShouldWait() { | bool Mutex::ShouldWait() { | ||||||
|  | @ -146,9 +66,34 @@ bool Mutex::ShouldWait() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Mutex::Acquire() { | void Mutex::Acquire() { | ||||||
|  |     Acquire(GetCurrentThread()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Mutex::Acquire(Thread* thread) { | ||||||
|     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||||||
|  |     if (locked) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|     locked = true; |     locked = true; | ||||||
|     MutexAcquireLock(this, GetCurrentThread()); | 
 | ||||||
|  |     g_mutex_held_locks.insert(std::make_pair(thread, this)); | ||||||
|  |     holding_thread = thread; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Mutex::Release() { | ||||||
|  |     if (!locked) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     auto locked_range = g_mutex_held_locks.equal_range(holding_thread); | ||||||
|  | 
 | ||||||
|  |     for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) { | ||||||
|  |         if (iter->second == this) { | ||||||
|  |             g_mutex_held_locks.erase(iter); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ResumeWaitingThread(this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -4,25 +4,51 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /**
 | class Thread; | ||||||
|  * Releases a mutex |  | ||||||
|  * @param handle Handle to mutex to release |  | ||||||
|  */ |  | ||||||
| ResultCode ReleaseMutex(Handle handle); |  | ||||||
| 
 | 
 | ||||||
| /**
 | class Mutex final : public WaitObject { | ||||||
|  * Creates a mutex | public: | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |     /**
 | ||||||
|  * @param name Optional name of mutex |      * Creates a mutex. | ||||||
|  * @return Handle to newly created object |      * @param initial_locked Specifies if the mutex should be locked initially | ||||||
|  */ |      * @param name Optional name of mutex | ||||||
| Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); |      * @return Pointer to new Mutex object | ||||||
|  |      */ | ||||||
|  |     static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); | ||||||
|  | 
 | ||||||
|  |     std::string GetTypeName() const override { return "Mutex"; } | ||||||
|  |     std::string GetName() const override { return name; } | ||||||
|  | 
 | ||||||
|  |     static const HandleType HANDLE_TYPE = HandleType::Mutex; | ||||||
|  |     HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||||||
|  | 
 | ||||||
|  |     bool initial_locked;                        ///< Initial lock state when mutex was created
 | ||||||
|  |     bool locked;                                ///< Current locked state
 | ||||||
|  |     std::string name;                           ///< Name of mutex (optional)
 | ||||||
|  |     SharedPtr<Thread> holding_thread;           ///< Thread that has acquired the mutex
 | ||||||
|  | 
 | ||||||
|  |     bool ShouldWait() override; | ||||||
|  |     void Acquire() override; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Acquires the specified mutex for the specified thread | ||||||
|  |     * @param mutex Mutex that is to be acquired | ||||||
|  |     * @param thread Thread that will acquire the mutex | ||||||
|  |     */ | ||||||
|  |     void Acquire(Thread* thread); | ||||||
|  |     void Release(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Mutex() = default; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Releases all the mutexes held by the specified thread |  * Releases all the mutexes held by the specified thread | ||||||
|  |  | ||||||
|  | @ -2,8 +2,6 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include <queue> |  | ||||||
| 
 |  | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
|  | @ -12,69 +10,50 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class Semaphore : public WaitObject { | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, | ||||||
| public: |         std::string name) { | ||||||
|     std::string GetTypeName() const override { return "Semaphore"; } |  | ||||||
|     std::string GetName() const override { return name; } |  | ||||||
| 
 |  | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::Semaphore; |  | ||||||
|     HandleType GetHandleType() const override { return HANDLE_TYPE; } |  | ||||||
| 
 |  | ||||||
|     s32 max_count;                              ///< Maximum number of simultaneous holders the semaphore can have
 |  | ||||||
|     s32 available_count;                        ///< Number of free slots left in the semaphore
 |  | ||||||
|     std::string name;                           ///< Name of semaphore (optional)
 |  | ||||||
| 
 |  | ||||||
|     bool ShouldWait() override { |  | ||||||
|         return available_count <= 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void Acquire() override { |  | ||||||
|         _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |  | ||||||
|         --available_count; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| ResultCode CreateSemaphore(Handle* handle, s32 initial_count,  |  | ||||||
|     s32 max_count, const std::string& name) { |  | ||||||
| 
 | 
 | ||||||
|     if (initial_count > max_count) |     if (initial_count > max_count) | ||||||
|         return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, |         return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | ||||||
|                           ErrorSummary::WrongArgument, ErrorLevel::Permanent); |                           ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||||||
| 
 | 
 | ||||||
|     Semaphore* semaphore = new Semaphore; |     SharedPtr<Semaphore> semaphore(new Semaphore); | ||||||
|     // TOOD(yuriks): Fix error reporting
 |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|     *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE); |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore)); | ||||||
| 
 | 
 | ||||||
|     // When the semaphore is created, some slots are reserved for other threads,
 |     // When the semaphore is created, some slots are reserved for other threads,
 | ||||||
|     // and the rest is reserved for the caller thread
 |     // and the rest is reserved for the caller thread
 | ||||||
|     semaphore->max_count = max_count; |     semaphore->max_count = max_count; | ||||||
|     semaphore->available_count = initial_count; |     semaphore->available_count = initial_count; | ||||||
|     semaphore->name = name; |     semaphore->name = std::move(name); | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS; |     return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | bool Semaphore::ShouldWait() { | ||||||
|     Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get(); |     return available_count <= 0; | ||||||
|     if (semaphore == nullptr) | } | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 | 
 | ||||||
|     if (semaphore->max_count - semaphore->available_count < release_count) | void Semaphore::Acquire() { | ||||||
|  |     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||||||
|  |     --available_count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultVal<s32> Semaphore::Release(s32 release_count) { | ||||||
|  |     if (max_count - available_count < release_count) | ||||||
|         return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,  |         return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,  | ||||||
|                           ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |                           ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
| 
 | 
 | ||||||
|     *count = semaphore->available_count; |     s32 previous_count = available_count; | ||||||
|     semaphore->available_count += release_count; |     available_count += release_count; | ||||||
| 
 | 
 | ||||||
|     // Notify some of the threads that the semaphore has been released
 |     // Notify some of the threads that the semaphore has been released
 | ||||||
|     // stop once the semaphore is full again or there are no more waiting threads
 |     // stop once the semaphore is full again or there are no more waiting threads
 | ||||||
|     while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { |     while (!ShouldWait() && WakeupNextThread() != nullptr) { | ||||||
|         semaphore->Acquire(); |         Acquire(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS; |     return MakeResult<s32>(previous_count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -4,29 +4,50 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <queue> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /**
 | class Semaphore final : public WaitObject { | ||||||
|  * Creates a semaphore. | public: | ||||||
|  * @param handle Pointer to the handle of the newly created object |     /**
 | ||||||
|  * @param initial_count Number of slots reserved for other threads |      * Creates a semaphore. | ||||||
|  * @param max_count Maximum number of slots the semaphore can have |      * @param handle Pointer to the handle of the newly created object | ||||||
|  * @param name Optional name of semaphore |      * @param initial_count Number of slots reserved for other threads | ||||||
|  * @return ResultCode of the error |      * @param max_count Maximum number of slots the semaphore can have | ||||||
|  */ |      * @param name Optional name of semaphore | ||||||
| ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); |      * @return The created semaphore | ||||||
|  |      */ | ||||||
|  |     static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, | ||||||
|  |             std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
| /**
 |     std::string GetTypeName() const override { return "Semaphore"; } | ||||||
|  * Releases a certain number of slots from a semaphore. |     std::string GetName() const override { return name; } | ||||||
|  * @param count The number of free slots the semaphore had before this call | 
 | ||||||
|  * @param handle The handle of the semaphore to release |     static const HandleType HANDLE_TYPE = HandleType::Semaphore; | ||||||
|  * @param release_count The number of slots to release |     HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||||||
|  * @return ResultCode of the error | 
 | ||||||
|  */ |     s32 max_count;                              ///< Maximum number of simultaneous holders the semaphore can have
 | ||||||
| ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count); |     s32 available_count;                        ///< Number of free slots left in the semaphore
 | ||||||
|  |     std::string name;                           ///< Name of semaphore (optional)
 | ||||||
|  | 
 | ||||||
|  |     bool ShouldWait() override; | ||||||
|  |     void Acquire() override; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Releases a certain number of slots from a semaphore. | ||||||
|  |      * @param release_count The number of slots to release | ||||||
|  |      * @return The number of free slots the semaphore had before this call | ||||||
|  |      */ | ||||||
|  |     ResultVal<s32> Release(s32 release_count); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Semaphore() = default; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -9,76 +9,39 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class SharedMemory : public Object { | ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { | ||||||
| public: |     SharedPtr<SharedMemory> shared_memory(new SharedMemory); | ||||||
|     std::string GetTypeName() const override { return "SharedMemory"; } |  | ||||||
| 
 | 
 | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::SharedMemory; |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|     HandleType GetHandleType() const override { return HANDLE_TYPE; } |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); | ||||||
| 
 | 
 | ||||||
|     u32 base_address;                   ///< Address of shared memory block in RAM
 |     shared_memory->name = std::move(name); | ||||||
|     MemoryPermission permissions;       ///< Permissions of shared memory block (SVC field)
 |     return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); | ||||||
|     MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field)
 |  | ||||||
|     std::string name;                   ///< Name of shared memory object (optional)
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Creates a shared memory object |  | ||||||
|  * @param handle Handle of newly created shared memory object |  | ||||||
|  * @param name Name of shared memory object |  | ||||||
|  * @return Pointer to newly created shared memory object |  | ||||||
|  */ |  | ||||||
| SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { |  | ||||||
|     SharedMemory* shared_memory = new SharedMemory; |  | ||||||
|     // TOOD(yuriks): Fix error reporting
 |  | ||||||
|     handle = Kernel::g_handle_table.Create(shared_memory).ValueOr(INVALID_HANDLE); |  | ||||||
|     shared_memory->name = name; |  | ||||||
|     return shared_memory; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Handle CreateSharedMemory(const std::string& name) { | ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, | ||||||
|     Handle handle; |         MemoryPermission other_permissions) { | ||||||
|     CreateSharedMemory(handle, name); |  | ||||||
|     return handle; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Maps a shared memory block to an address in system memory |  | ||||||
|  * @param handle Shared memory block handle |  | ||||||
|  * @param address Address in system memory to map shared memory block to |  | ||||||
|  * @param permissions Memory block map permissions (specified by SVC field) |  | ||||||
|  * @param other_permissions Memory block map other permissions (specified by SVC field) |  | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, |  | ||||||
|     MemoryPermission other_permissions) { |  | ||||||
| 
 | 
 | ||||||
|     if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { |     if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { | ||||||
|         LOG_ERROR(Kernel_SVC, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", |         LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", | ||||||
|             handle, address); |                 GetHandle(), address); | ||||||
|  |         // TODO: Verify error code with hardware
 | ||||||
|         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
|     } |     } | ||||||
|     SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); |  | ||||||
|     if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 | 
 | ||||||
|     shared_memory->base_address = address; |     base_address = address; | ||||||
|     shared_memory->permissions = permissions; |     permissions = permissions; | ||||||
|     shared_memory->other_permissions = other_permissions; |     other_permissions = other_permissions; | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { | ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { | ||||||
|     SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); |     if (base_address != 0) | ||||||
|     if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); |         return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); | ||||||
| 
 | 
 | ||||||
|     if (0 != shared_memory->base_address) |     LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); | ||||||
|         return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); |  | ||||||
| 
 |  | ||||||
|     LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle); |  | ||||||
|     // TODO(yuriks): Verify error code.
 |     // TODO(yuriks): Verify error code.
 | ||||||
|     return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |     return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|             ErrorSummary::InvalidState, ErrorLevel::Permanent); |             ErrorSummary::InvalidState, ErrorLevel::Permanent); | ||||||
|  |  | ||||||
|  | @ -23,29 +23,41 @@ enum class MemoryPermission : u32 { | ||||||
|     DontCare         = (1u << 28) |     DontCare         = (1u << 28) | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | class SharedMemory final : public Object { | ||||||
|  * Creates a shared memory object | public: | ||||||
|  * @param name Optional name of shared memory object |     /**
 | ||||||
|  * @return Handle of newly created shared memory object |      * Creates a shared memory object | ||||||
|  */ |      * @param name Optional object name, used only for debugging purposes. | ||||||
| Handle CreateSharedMemory(const std::string& name="Unknown"); |      */ | ||||||
|  |     static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
| /**
 |     std::string GetTypeName() const override { return "SharedMemory"; } | ||||||
|  * Maps a shared memory block to an address in system memory |  | ||||||
|  * @param handle Shared memory block handle |  | ||||||
|  * @param address Address in system memory to map shared memory block to |  | ||||||
|  * @param permissions Memory block map permissions (specified by SVC field) |  | ||||||
|  * @param other_permissions Memory block map other permissions (specified by SVC field) |  | ||||||
|  */ |  | ||||||
| ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, |  | ||||||
|     MemoryPermission other_permissions); |  | ||||||
| 
 | 
 | ||||||
| /**
 |     static const HandleType HANDLE_TYPE = HandleType::SharedMemory; | ||||||
|  * Gets a pointer to the shared memory block |     HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||||||
|  * @param handle Shared memory block handle | 
 | ||||||
|  * @param offset Offset from the start of the shared memory block to get pointer |     /**
 | ||||||
|  * @return Pointer to the shared memory block from the specified offset |      * Maps a shared memory block to an address in system memory | ||||||
|  */ |      * @param address Address in system memory to map shared memory block to | ||||||
| ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); |      * @param permissions Memory block map permissions (specified by SVC field) | ||||||
|  |      * @param other_permissions Memory block map other permissions (specified by SVC field) | ||||||
|  |      */ | ||||||
|  |     ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Gets a pointer to the shared memory block | ||||||
|  |     * @param offset Offset from the start of the shared memory block to get pointer | ||||||
|  |     * @return Pointer to the shared memory block from the specified offset | ||||||
|  |     */ | ||||||
|  |     ResultVal<u8*> GetPointer(u32 offset = 0); | ||||||
|  | 
 | ||||||
|  |     VAddr base_address;                   ///< Address of shared memory block in RAM
 | ||||||
|  |     MemoryPermission permissions;       ///< Permissions of shared memory block (SVC field)
 | ||||||
|  |     MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field)
 | ||||||
|  |     std::string name;                   ///< Name of shared memory object (optional)
 | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     SharedMemory() = default; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ enum ThreadStatus { | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class Thread : public WaitObject { | class Thread final : public WaitObject { | ||||||
| public: | public: | ||||||
|     static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, |     static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | ||||||
|         u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); |         u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); | ||||||
|  | @ -115,7 +115,6 @@ public: | ||||||
|     bool idle = false; |     bool idle = false; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 
 |  | ||||||
|     Thread() = default; |     Thread() = default; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,75 +13,54 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class Timer : public WaitObject { | /// The event type of the generic timer callback event
 | ||||||
| public: | static int timer_callback_event_type = -1; | ||||||
|     std::string GetTypeName() const override { return "Timer"; } |  | ||||||
|     std::string GetName() const override { return name; } |  | ||||||
| 
 | 
 | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::Timer; | ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { | ||||||
|     HandleType GetHandleType() const override { return HANDLE_TYPE; } |     SharedPtr<Timer> timer(new Timer); | ||||||
| 
 |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|     ResetType reset_type;                   ///< The ResetType of this timer
 |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer)); | ||||||
| 
 |  | ||||||
|     bool signaled;                          ///< Whether the timer has been signaled or not
 |  | ||||||
|     std::string name;                       ///< Name of timer (optional)
 |  | ||||||
| 
 |  | ||||||
|     u64 initial_delay;                      ///< The delay until the timer fires for the first time
 |  | ||||||
|     u64 interval_delay;                     ///< The delay until the timer fires after the first time
 |  | ||||||
| 
 |  | ||||||
|     bool ShouldWait() override { |  | ||||||
|         return !signaled; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void Acquire() override { |  | ||||||
|         _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Creates a timer. |  | ||||||
|  * @param handle Reference to handle for the newly created timer |  | ||||||
|  * @param reset_type ResetType describing how to create timer |  | ||||||
|  * @param name Optional name of timer |  | ||||||
|  * @return Newly created Timer object |  | ||||||
|  */ |  | ||||||
| Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { |  | ||||||
|     Timer* timer = new Timer; |  | ||||||
| 
 |  | ||||||
|     handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); |  | ||||||
| 
 | 
 | ||||||
|     timer->reset_type = reset_type; |     timer->reset_type = reset_type; | ||||||
|     timer->signaled = false; |     timer->signaled = false; | ||||||
|     timer->name = name; |     timer->name = std::move(name); | ||||||
|     timer->initial_delay = 0; |     timer->initial_delay = 0; | ||||||
|     timer->interval_delay = 0; |     timer->interval_delay = 0; | ||||||
|     return timer; |     return MakeResult<SharedPtr<Timer>>(timer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { | bool Timer::ShouldWait() { | ||||||
|     CreateTimer(*handle, reset_type, name); |     return !signaled; | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ClearTimer(Handle handle) { | void Timer::Acquire() { | ||||||
|     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); |     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||||||
|      |  | ||||||
|     if (timer == nullptr) |  | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 |  | ||||||
|     timer->signaled = false; |  | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// The event type of the generic timer callback event
 | void Timer::Set(s64 initial, s64 interval) { | ||||||
| static int TimerCallbackEventType = -1; |     initial_delay = initial; | ||||||
|  |     interval_delay = interval; | ||||||
|  | 
 | ||||||
|  |     u64 initial_microseconds = initial / 1000; | ||||||
|  |     // TODO(yuriks): Figure out a replacement for GetHandle here
 | ||||||
|  |     CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, | ||||||
|  |             GetHandle()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Timer::Cancel() { | ||||||
|  |     CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Timer::Clear() { | ||||||
|  |     signaled = false; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /// The timer callback event, called when a timer is fired
 | /// The timer callback event, called when a timer is fired
 | ||||||
| static void TimerCallback(u64 timer_handle, int cycles_late) { | static void TimerCallback(u64 timer_handle, int cycles_late) { | ||||||
|     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); |     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); | ||||||
| 
 | 
 | ||||||
|     if (timer == nullptr) { |     if (timer == nullptr) { | ||||||
|         LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); |         LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -99,36 +78,12 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | ||||||
|         // Reschedule the timer with the interval delay
 |         // Reschedule the timer with the interval delay
 | ||||||
|         u64 interval_microseconds = timer->interval_delay / 1000; |         u64 interval_microseconds = timer->interval_delay / 1000; | ||||||
|         CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,  |         CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,  | ||||||
|                 TimerCallbackEventType, timer_handle); |                 timer_callback_event_type, timer_handle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { |  | ||||||
|     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); |  | ||||||
| 
 |  | ||||||
|     if (timer == nullptr) |  | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 |  | ||||||
|     timer->initial_delay = initial; |  | ||||||
|     timer->interval_delay = interval; |  | ||||||
| 
 |  | ||||||
|     u64 initial_microseconds = initial / 1000; |  | ||||||
|     CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); |  | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ResultCode CancelTimer(Handle handle) { |  | ||||||
|     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); |  | ||||||
| 
 |  | ||||||
|     if (timer == nullptr) |  | ||||||
|         return InvalidHandle(ErrorModule::Kernel); |  | ||||||
| 
 |  | ||||||
|     CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); |  | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TimersInit() { | void TimersInit() { | ||||||
|     TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); |     timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TimersShutdown() { | void TimersShutdown() { | ||||||
|  |  | ||||||
|  | @ -11,37 +11,50 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /**
 | class Timer final : public WaitObject { | ||||||
|  * Cancels a timer | public: | ||||||
|  * @param handle Handle of the timer to cancel |     /**
 | ||||||
|  */ |      * Creates a timer | ||||||
| ResultCode CancelTimer(Handle handle); |      * @param reset_type ResetType describing how to create the timer | ||||||
|  |      * @param name Optional name of timer | ||||||
|  |      * @return The created Timer | ||||||
|  |      */ | ||||||
|  |     static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
| /**
 |     std::string GetTypeName() const override { return "Timer"; } | ||||||
|  * Starts a timer with the specified initial delay and interval |     std::string GetName() const override { return name; } | ||||||
|  * @param handle Handle of the timer to start |  | ||||||
|  * @param initial Delay until the timer is first fired |  | ||||||
|  * @param interval Delay until the timer is fired after the first time |  | ||||||
|  */ |  | ||||||
| ResultCode SetTimer(Handle handle, s64 initial, s64 interval); |  | ||||||
| 
 | 
 | ||||||
| /**
 |     static const HandleType HANDLE_TYPE = HandleType::Timer; | ||||||
|  * Clears a timer |     HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||||||
|  * @param handle Handle of the timer to clear |  | ||||||
|  */ |  | ||||||
| ResultCode ClearTimer(Handle handle); |  | ||||||
| 
 | 
 | ||||||
| /**
 |     ResetType reset_type;                   ///< The ResetType of this timer
 | ||||||
|  * Creates a timer | 
 | ||||||
|  * @param handle Handle to the newly created Timer object |     bool signaled;                          ///< Whether the timer has been signaled or not
 | ||||||
|  * @param reset_type ResetType describing how to create the timer |     std::string name;                       ///< Name of timer (optional)
 | ||||||
|  * @param name Optional name of timer | 
 | ||||||
|  * @return ResultCode of the error |     u64 initial_delay;                      ///< The delay until the timer fires for the first time
 | ||||||
|  */ |     u64 interval_delay;                     ///< The delay until the timer fires after the first time
 | ||||||
| ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); | 
 | ||||||
|  |     bool ShouldWait() override; | ||||||
|  |     void Acquire() override; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Starts the timer, with the specified initial delay and interval. | ||||||
|  |      * @param initial Delay until the timer is first fired | ||||||
|  |      * @param interval Delay until the timer is fired after the first time | ||||||
|  |      */ | ||||||
|  |     void Set(s64 initial, s64 interval); | ||||||
|  | 
 | ||||||
|  |     void Cancel(); | ||||||
|  |     void Clear(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Timer() = default; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| /// Initializes the required variables for timers
 | /// Initializes the required variables for timers
 | ||||||
| void TimersInit(); | void TimersInit(); | ||||||
| /// Tears down the timer variables
 | /// Tears down the timer variables
 | ||||||
| void TimersShutdown(); | void TimersShutdown(); | ||||||
|  | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -9,8 +9,9 @@ | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include "common/common_types.h" |  | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| // All the constants in this file come from http://3dbrew.org/wiki/Error_codes
 | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes
 | ||||||
| 
 | 
 | ||||||
|  | @ -226,11 +227,6 @@ inline ResultCode UnimplementedFunction(ErrorModule module) { | ||||||
|     return ResultCode(ErrorDescription::NotImplemented, module, |     return ResultCode(ErrorDescription::NotImplemented, module, | ||||||
|             ErrorSummary::NotSupported, ErrorLevel::Permanent); |             ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||||||
| } | } | ||||||
| /// Returned when a function is passed an invalid handle.
 |  | ||||||
| inline ResultCode InvalidHandle(ErrorModule module) { |  | ||||||
|     return ResultCode(ErrorDescription::InvalidHandle, module, |  | ||||||
|             ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, |  * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, | ||||||
|  | @ -364,6 +360,17 @@ public: | ||||||
|         return !empty() ? *GetPointer() : std::move(value); |         return !empty() ? *GetPointer() : std::move(value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Asserts that the result succeeded and returns a reference to it.
 | ||||||
|  |     T& Unwrap() { | ||||||
|  |         // TODO(yuriks): Should be a release assert
 | ||||||
|  |         _assert_msg_(Common, Succeeded(), "Tried to Unwrap empty ResultVal"); | ||||||
|  |         return **this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T&& MoveFrom() { | ||||||
|  |         return std::move(Unwrap()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; |     typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; | ||||||
| 
 | 
 | ||||||
|  | @ -400,3 +407,15 @@ template <typename T, typename... Args> | ||||||
| ResultVal<T> MakeResult(Args&&... args) { | ResultVal<T> MakeResult(Args&&... args) { | ||||||
|     return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); |     return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps | ||||||
|  |  * the contained value and assigns it to `target`, which can be either an l-value expression or a | ||||||
|  |  * variable declaration. If it fails the return code is returned from the current function. Thus it | ||||||
|  |  * can be used to cascade errors out, achieving something akin to exception handling. | ||||||
|  |  */ | ||||||
|  | #define CASCADE_RESULT(target, source) \ | ||||||
|  |         auto CONCAT2(check_result_L, __LINE__) = source; \ | ||||||
|  |         if (CONCAT2(check_result_L, __LINE__).Failed()) \ | ||||||
|  |             return CONCAT2(check_result_L, __LINE__).Code(); \ | ||||||
|  |         target = std::move(*CONCAT2(check_result_L, __LINE__)) | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #include "core/hle/kernel/event.h" | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/service/apt_s.h" | #include "core/hle/service/apt_s.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #include "core/hle/kernel/event.h" | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/service/apt_u.h" | #include "core/hle/service/apt_u.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | @ -26,11 +27,11 @@ namespace APT_U { | ||||||
| static const VAddr SHARED_FONT_VADDR = 0x18000000; | static const VAddr SHARED_FONT_VADDR = 0x18000000; | ||||||
| 
 | 
 | ||||||
| /// Handle to shared memory region designated to for shared system font
 | /// Handle to shared memory region designated to for shared system font
 | ||||||
| static Handle shared_font_mem = 0; | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | ||||||
| 
 | 
 | ||||||
| static Handle lock_handle = 0; | static Kernel::SharedPtr<Kernel::Mutex> lock; | ||||||
| static Handle notification_event_handle = 0; ///< APT notification event handle
 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
 | ||||||
| static Handle pause_event_handle = 0; ///< APT pause event handle
 | static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event
 | ||||||
| static std::vector<u8> shared_font; | static std::vector<u8> shared_font; | ||||||
| 
 | 
 | ||||||
| /// Signals used by APT functions
 | /// Signals used by APT functions
 | ||||||
|  | @ -67,17 +68,19 @@ enum class AppID : u32 { | ||||||
| void Initialize(Service::Interface* self) { | void Initialize(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     notification_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Notification"); |     // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
 | ||||||
|     pause_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); |     notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification").MoveFrom(); | ||||||
|  |     pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause").MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[3] = notification_event_handle; |     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); | ||||||
|     cmd_buff[4] = pause_event_handle; |     cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     Kernel::ClearEvent(notification_event_handle); |     // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called.
 | ||||||
|     Kernel::SignalEvent(pause_event_handle); // Fire start event
 |     notification_event->Clear(); | ||||||
|  |     pause_event->Signal(); // Fire start event
 | ||||||
| 
 | 
 | ||||||
|     _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); |     _assert_msg_(KERNEL, (nullptr != lock), "Cannot initialize without lock"); | ||||||
|     Kernel::ReleaseMutex(lock_handle); |     lock->Release(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| } | } | ||||||
|  | @ -93,7 +96,7 @@ void NotifyToWait(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = cmd_buff[1]; | ||||||
|     // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
 |     // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
 | ||||||
|     Kernel::SignalEvent(pause_event_handle); |     pause_event->Signal(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | ||||||
|  | @ -103,11 +106,6 @@ void GetLockHandle(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
 |     u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
 | ||||||
| 
 | 
 | ||||||
|     if (0 == lock_handle) { |  | ||||||
|         // TODO(bunnei): Verify if this is created here or at application boot?
 |  | ||||||
|         lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); |  | ||||||
|         Kernel::ReleaseMutex(lock_handle); |  | ||||||
|     } |  | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| 
 | 
 | ||||||
|     // Not sure what these parameters are used for, but retail apps check that they are 0 after
 |     // 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) { | ||||||
|     cmd_buff[3] = 0; |     cmd_buff[3] = 0; | ||||||
|     cmd_buff[4] = 0; |     cmd_buff[4] = 0; | ||||||
| 
 | 
 | ||||||
|     cmd_buff[5] = lock_handle; |     cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); | ||||||
|     LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); |     LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -354,7 +352,7 @@ void GetSharedFont(Service::Interface* self) { | ||||||
|         cmd_buff[0] = 0x00440082; |         cmd_buff[0] = 0x00440082; | ||||||
|         cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |         cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|         cmd_buff[2] = SHARED_FONT_VADDR; |         cmd_buff[2] = SHARED_FONT_VADDR; | ||||||
|         cmd_buff[4] = shared_font_mem; |         cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); | ||||||
|     } else { |     } else { | ||||||
|         cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
 |         cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
 | ||||||
|         LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); |         LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT); | ||||||
|  | @ -514,13 +512,13 @@ Interface::Interface() { | ||||||
|         file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); |         file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); | ||||||
| 
 | 
 | ||||||
|         // Create shared font memory object
 |         // Create shared font memory object
 | ||||||
|         shared_font_mem = Kernel::CreateSharedMemory("APT_U:shared_font_mem"); |         shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem").MoveFrom(); | ||||||
|     } else { |     } else { | ||||||
|         LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); |         LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); | ||||||
|         shared_font_mem = 0; |         shared_font_mem = nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lock_handle = 0; |     lock = Kernel::Mutex::Create(false, "APT_U:Lock").MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,8 +13,8 @@ | ||||||
| namespace DSP_DSP { | namespace DSP_DSP { | ||||||
| 
 | 
 | ||||||
| static u32 read_pipe_count    = 0; | static u32 read_pipe_count    = 0; | ||||||
| static Handle semaphore_event = 0; | static Kernel::SharedPtr<Kernel::Event> semaphore_event; | ||||||
| static Handle interrupt_event = 0; | static Kernel::SharedPtr<Kernel::Event> interrupt_event; | ||||||
| 
 | 
 | ||||||
| void SignalInterrupt() { | void SignalInterrupt() { | ||||||
|     // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated
 |     // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated
 | ||||||
|  | @ -24,7 +24,7 @@ void SignalInterrupt() { | ||||||
|     // DSP interrupts, and trigger them at the appropriate times.
 |     // DSP interrupts, and trigger them at the appropriate times.
 | ||||||
| 
 | 
 | ||||||
|     if (interrupt_event != 0) |     if (interrupt_event != 0) | ||||||
|         Kernel::SignalEvent(interrupt_event); |         interrupt_event->Signal(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -78,8 +78,8 @@ void LoadComponent(Service::Interface* self) { | ||||||
| void GetSemaphoreEventHandle(Service::Interface* self) { | void GetSemaphoreEventHandle(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     cmd_buff[3] = semaphore_event; // Event handle
 |     cmd_buff[3] = Kernel::g_handle_table.Create(semaphore_event).MoveFrom(); // Event handle
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_DSP, "(STUBBED) called"); |     LOG_WARNING(Service_DSP, "(STUBBED) called"); | ||||||
| } | } | ||||||
|  | @ -96,9 +96,16 @@ void GetSemaphoreEventHandle(Service::Interface* self) { | ||||||
| void RegisterInterruptEvents(Service::Interface* self) { | void RegisterInterruptEvents(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     interrupt_event = static_cast<Handle>(cmd_buff[4]); |     auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); | ||||||
|  |     if (evt != nullptr) { | ||||||
|  |         interrupt_event = evt; | ||||||
|  |         cmd_buff[1] = 0; // No error
 | ||||||
|  |     } else { | ||||||
|  |         LOG_ERROR(Service_DSP, "called with invalid handle=%08X", cmd_buff[4]); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0; // No error
 |         // TODO(yuriks): An error should be returned from SendSyncRequest, not in the cmdbuf
 | ||||||
|  |         cmd_buff[1] = -1; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_DSP, "(STUBBED) called"); |     LOG_WARNING(Service_DSP, "(STUBBED) called"); | ||||||
| } | } | ||||||
|  | @ -194,8 +201,9 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     semaphore_event = Kernel::CreateEvent(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event"); |     semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, | ||||||
|     interrupt_event = 0; |             "DSP_DSP::semaphore_event").MoveFrom(); | ||||||
|  |     interrupt_event = nullptr; | ||||||
|     read_pipe_count = 0; |     read_pipe_count = 0; | ||||||
| 
 | 
 | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||||||
|  |  | ||||||
|  | @ -43,6 +43,11 @@ const std::string SDCARD_ID = "00000000000000000000000000000000"; | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace FS { | namespace FS { | ||||||
| 
 | 
 | ||||||
|  | // TODO: Verify code
 | ||||||
|  | /// Returned when a function is passed an invalid handle.
 | ||||||
|  | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::FS, | ||||||
|  |         ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
|  | 
 | ||||||
| // Command to access archive file
 | // Command to access archive file
 | ||||||
| enum class FileCommand : u32 { | enum class FileCommand : u32 { | ||||||
|     Dummy1          = 0x000100C6, |     Dummy1          = 0x000100C6, | ||||||
|  | @ -280,7 +285,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi | ||||||
| 
 | 
 | ||||||
| ResultCode CloseArchive(ArchiveHandle handle) { | ResultCode CloseArchive(ArchiveHandle handle) { | ||||||
|     if (handle_map.erase(handle) == 0) |     if (handle_map.erase(handle) == 0) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
|     else |     else | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  | @ -301,7 +306,7 @@ ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, Arc | ||||||
| ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); |     std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); | ||||||
|     if (backend == nullptr) { |     if (backend == nullptr) { | ||||||
|  | @ -318,7 +323,7 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy | ||||||
| ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     if (archive->backend->DeleteFile(path)) |     if (archive->backend->DeleteFile(path)) | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|  | @ -331,7 +336,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil | ||||||
|     Archive* src_archive = GetArchive(src_archive_handle); |     Archive* src_archive = GetArchive(src_archive_handle); | ||||||
|     Archive* dest_archive = GetArchive(dest_archive_handle); |     Archive* dest_archive = GetArchive(dest_archive_handle); | ||||||
|     if (src_archive == nullptr || dest_archive == nullptr) |     if (src_archive == nullptr || dest_archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     if (src_archive == dest_archive) { |     if (src_archive == dest_archive) { | ||||||
|         if (src_archive->backend->RenameFile(src_path, dest_path)) |         if (src_archive->backend->RenameFile(src_path, dest_path)) | ||||||
|  | @ -350,7 +355,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil | ||||||
| ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     if (archive->backend->DeleteDirectory(path)) |     if (archive->backend->DeleteDirectory(path)) | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|  | @ -361,7 +366,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy | ||||||
| ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { | ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     return archive->backend->CreateFile(path, file_size); |     return archive->backend->CreateFile(path, file_size); | ||||||
| } | } | ||||||
|  | @ -369,7 +374,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path | ||||||
| ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     if (archive->backend->CreateDirectory(path)) |     if (archive->backend->CreateDirectory(path)) | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|  | @ -382,7 +387,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | ||||||
|     Archive* src_archive = GetArchive(src_archive_handle); |     Archive* src_archive = GetArchive(src_archive_handle); | ||||||
|     Archive* dest_archive = GetArchive(dest_archive_handle); |     Archive* dest_archive = GetArchive(dest_archive_handle); | ||||||
|     if (src_archive == nullptr || dest_archive == nullptr) |     if (src_archive == nullptr || dest_archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     if (src_archive == dest_archive) { |     if (src_archive == dest_archive) { | ||||||
|         if (src_archive->backend->RenameDirectory(src_path, dest_path)) |         if (src_archive->backend->RenameDirectory(src_path, dest_path)) | ||||||
|  | @ -407,7 +412,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | ||||||
| ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::FS); |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); |     std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); | ||||||
|     if (backend == nullptr) { |     if (backend == nullptr) { | ||||||
|  |  | ||||||
|  | @ -22,13 +22,16 @@ GraphicsDebugger g_debugger; | ||||||
| 
 | 
 | ||||||
| namespace GSP_GPU { | namespace GSP_GPU { | ||||||
| 
 | 
 | ||||||
| Handle g_interrupt_event = 0;   ///< Handle to event triggered when GSP interrupt has been signalled
 | /// Event triggered when GSP interrupt has been signalled
 | ||||||
| Handle g_shared_memory = 0;     ///< Handle to GSP shared memorys
 | Kernel::SharedPtr<Kernel::Event> g_interrupt_event; | ||||||
| u32 g_thread_id = 1;            ///< Thread index into interrupt relay queue, 1 is arbitrary
 | /// GSP shared memoryings
 | ||||||
|  | Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory; | ||||||
|  | /// Thread index into interrupt relay queue, 1 is arbitrary
 | ||||||
|  | u32 g_thread_id = 1; | ||||||
| 
 | 
 | ||||||
| /// Gets a pointer to a thread command buffer in GSP shared memory
 | /// Gets a pointer to a thread command buffer in GSP shared memory
 | ||||||
| static inline u8* GetCommandBuffer(u32 thread_id) { | static inline u8* GetCommandBuffer(u32 thread_id) { | ||||||
|     ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer))); |     ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); | ||||||
|     return ptr.ValueOr(nullptr); |     return ptr.ValueOr(nullptr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -37,13 +40,13 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in | ||||||
| 
 | 
 | ||||||
|     // For each thread there are two FrameBufferUpdate fields
 |     // For each thread there are two FrameBufferUpdate fields
 | ||||||
|     u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); |     u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); | ||||||
|     ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset); |     ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset); | ||||||
|     return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); |     return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Gets a pointer to the interrupt relay queue for a given thread index
 | /// Gets a pointer to the interrupt relay queue for a given thread index
 | ||||||
| static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { | static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { | ||||||
|     ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id); |     ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); | ||||||
|     return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); |     return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -181,16 +184,18 @@ static void FlushDataCache(Service::Interface* self) { | ||||||
| static void RegisterInterruptRelayQueue(Service::Interface* self) { | static void RegisterInterruptRelayQueue(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 flags = cmd_buff[1]; |     u32 flags = cmd_buff[1]; | ||||||
|     g_interrupt_event = cmd_buff[3]; |  | ||||||
|     g_shared_memory = Kernel::CreateSharedMemory("GSPSharedMem"); |  | ||||||
| 
 | 
 | ||||||
|     _assert_msg_(GSP, (g_interrupt_event != 0), "handle is not valid!"); |     g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); | ||||||
|  |     _assert_msg_(GSP, (g_interrupt_event != nullptr), "handle is not valid!"); | ||||||
|  |     g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem").MoveFrom(); | ||||||
|  | 
 | ||||||
|  |     Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
 |     cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
 | ||||||
|     cmd_buff[2] = g_thread_id++; // Thread ID
 |     cmd_buff[2] = g_thread_id++; // Thread ID
 | ||||||
|     cmd_buff[4] = g_shared_memory; // GSP shared memory
 |     cmd_buff[4] = shmem_handle; // GSP shared memory
 | ||||||
| 
 | 
 | ||||||
|     Kernel::SignalEvent(g_interrupt_event); // TODO(bunnei): Is this correct?
 |     g_interrupt_event->Signal(); // TODO(bunnei): Is this correct?
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -204,7 +209,7 @@ void SignalInterrupt(InterruptId interrupt_id) { | ||||||
|         LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); |         LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     if (0 == g_shared_memory) { |     if (nullptr == g_shared_memory) { | ||||||
|         LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); |         LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -232,7 +237,7 @@ void SignalInterrupt(InterruptId interrupt_id) { | ||||||
|             info->is_dirty = false; |             info->is_dirty = false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     Kernel::SignalEvent(g_interrupt_event); |     g_interrupt_event->Signal(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Executes the next GSP command
 | /// Executes the next GSP command
 | ||||||
|  |  | ||||||
|  | @ -12,13 +12,13 @@ | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace HID { | namespace HID { | ||||||
| 
 | 
 | ||||||
| Handle g_shared_mem = 0; | Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem = nullptr; | ||||||
| 
 | 
 | ||||||
| Handle g_event_pad_or_touch_1 = 0; | Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; | ||||||
| Handle g_event_pad_or_touch_2 = 0; | Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; | ||||||
| Handle g_event_accelerometer = 0; | Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; | ||||||
| Handle g_event_gyroscope = 0; | Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; | ||||||
| Handle g_event_debug_pad = 0; | Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; | ||||||
| 
 | 
 | ||||||
| // Next Pad state update information
 | // Next Pad state update information
 | ||||||
| static PadState next_state = {{0}}; | static PadState next_state = {{0}}; | ||||||
|  | @ -30,7 +30,7 @@ static s16 next_circle_y = 0; | ||||||
|  * Gets a pointer to the PadData structure inside HID shared memory |  * Gets a pointer to the PadData structure inside HID shared memory | ||||||
|  */ |  */ | ||||||
| static inline PadData* GetPadData() { | static inline PadData* GetPadData() { | ||||||
|     return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(g_shared_mem, 0).ValueOr(nullptr)); |     return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -115,19 +115,21 @@ void PadUpdateComplete() { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // Signal both handles when there's an update to Pad or touch
 |     // Signal both handles when there's an update to Pad or touch
 | ||||||
|     Kernel::SignalEvent(g_event_pad_or_touch_1); |     g_event_pad_or_touch_1->Signal(); | ||||||
|     Kernel::SignalEvent(g_event_pad_or_touch_2); |     g_event_pad_or_touch_2->Signal(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HIDInit() { | void HIDInit() { | ||||||
|     g_shared_mem = Kernel::CreateSharedMemory("HID:SharedMem"); // Create shared memory object
 |     using namespace Kernel; | ||||||
|  | 
 | ||||||
|  |     g_shared_mem = SharedMemory::Create("HID:SharedMem").MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     // Create event handles
 |     // Create event handles
 | ||||||
|     g_event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); |     g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1").MoveFrom(); | ||||||
|     g_event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); |     g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2").MoveFrom(); | ||||||
|     g_event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); |     g_event_accelerometer  = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer").MoveFrom(); | ||||||
|     g_event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventGyroscope"); |     g_event_gyroscope      = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope").MoveFrom(); | ||||||
|     g_event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventDebugPad"); |     g_event_debug_pad      = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad").MoveFrom(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HIDShutdown() { | void HIDShutdown() { | ||||||
|  |  | ||||||
|  | @ -9,18 +9,23 @@ | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| 
 | 
 | ||||||
|  | namespace Kernel { | ||||||
|  |     class SharedMemory; | ||||||
|  |     class Event; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace HID { | namespace HID { | ||||||
| 
 | 
 | ||||||
| // Handle to shared memory region designated to HID_User service
 | // Handle to shared memory region designated to HID_User service
 | ||||||
| extern Handle g_shared_mem; | extern Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem; | ||||||
| 
 | 
 | ||||||
| // Event handles
 | // Event handles
 | ||||||
| extern Handle g_event_pad_or_touch_1; | extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; | ||||||
| extern Handle g_event_pad_or_touch_2; | extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; | ||||||
| extern Handle g_event_accelerometer; | extern Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; | ||||||
| extern Handle g_event_gyroscope; | extern Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; | ||||||
| extern Handle g_event_debug_pad; | extern Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Structure of a Pad controller state. |  * Structure of a Pad controller state. | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ | ||||||
| #include "common/log.h" | #include "common/log.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
|  | #include "core/hle/kernel/shared_memory.h" | ||||||
| #include "core/hle/service/hid/hid.h" | #include "core/hle/service/hid/hid.h" | ||||||
| #include "hid_user.h" | #include "hid_user.h" | ||||||
| 
 | 
 | ||||||
|  | @ -46,12 +48,13 @@ void GetIPCHandles(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0; // No error
 |     cmd_buff[1] = 0; // No error
 | ||||||
|     cmd_buff[3] = Service::HID::g_shared_mem; |     // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling)
 | ||||||
|     cmd_buff[4] = Service::HID::g_event_pad_or_touch_1; |     cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); | ||||||
|     cmd_buff[5] = Service::HID::g_event_pad_or_touch_2; |     cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); | ||||||
|     cmd_buff[6] = Service::HID::g_event_accelerometer; |     cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); | ||||||
|     cmd_buff[7] = Service::HID::g_event_gyroscope; |     cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); | ||||||
|     cmd_buff[8] = Service::HID::g_event_debug_pad; |     cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); | ||||||
|  |     cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace SRV { | namespace SRV { | ||||||
| 
 | 
 | ||||||
| static Handle g_event_handle = 0; | static Kernel::SharedPtr<Kernel::Event> event_handle; | ||||||
| 
 | 
 | ||||||
| static void Initialize(Service::Interface* self) { | static void Initialize(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|  | @ -23,11 +23,11 @@ static void GetProcSemaphore(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     // TODO(bunnei): Change to a semaphore once these have been implemented
 |     // TODO(bunnei): Change to a semaphore once these have been implemented
 | ||||||
|     g_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "SRV:Event"); |     event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event").MoveFrom(); | ||||||
|     Kernel::ClearEvent(g_event_handle); |     event_handle->Clear(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0; // No error
 |     cmd_buff[1] = 0; // No error
 | ||||||
|     cmd_buff[3] = g_event_handle; |     cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void GetServiceHandle(Service::Interface* self) { | static void GetServiceHandle(Service::Interface* self) { | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ | ||||||
| // Namespace SVC
 | // Namespace SVC
 | ||||||
| 
 | 
 | ||||||
| using Kernel::SharedPtr; | using Kernel::SharedPtr; | ||||||
|  | using Kernel::ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
| namespace SVC { | namespace SVC { | ||||||
| 
 | 
 | ||||||
|  | @ -38,7 +39,7 @@ enum ControlMemoryOperation { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Map application or GSP heap memory
 | /// Map application or GSP heap memory
 | ||||||
| static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | ||||||
|     LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", |     LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", | ||||||
|         operation, addr0, addr1, size, permissions); |         operation, addr0, addr1, size, permissions); | ||||||
| 
 | 
 | ||||||
|  | @ -58,35 +59,42 @@ static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); |         LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Maps a memory block to specified address
 | /// Maps a memory block to specified address
 | ||||||
| static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { | static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { | ||||||
|  |     using Kernel::SharedMemory; | ||||||
|  |     using Kernel::MemoryPermission; | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", |     LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", | ||||||
|         handle, addr, permissions, other_permissions); |         handle, addr, permissions, other_permissions); | ||||||
| 
 | 
 | ||||||
|     Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions); |     SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); | ||||||
|  |     if (shared_memory == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); | ||||||
|     switch (permissions_type) { |     switch (permissions_type) { | ||||||
|     case Kernel::MemoryPermission::Read: |     case MemoryPermission::Read: | ||||||
|     case Kernel::MemoryPermission::Write: |     case MemoryPermission::Write: | ||||||
|     case Kernel::MemoryPermission::ReadWrite: |     case MemoryPermission::ReadWrite: | ||||||
|     case Kernel::MemoryPermission::Execute: |     case MemoryPermission::Execute: | ||||||
|     case Kernel::MemoryPermission::ReadExecute: |     case MemoryPermission::ReadExecute: | ||||||
|     case Kernel::MemoryPermission::WriteExecute: |     case MemoryPermission::WriteExecute: | ||||||
|     case Kernel::MemoryPermission::ReadWriteExecute: |     case MemoryPermission::ReadWriteExecute: | ||||||
|     case Kernel::MemoryPermission::DontCare: |     case MemoryPermission::DontCare: | ||||||
|         Kernel::MapSharedMemory(handle, addr, permissions_type, |         shared_memory->Map(addr, permissions_type, | ||||||
|             static_cast<Kernel::MemoryPermission>(other_permissions)); |                 static_cast<MemoryPermission>(other_permissions)); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); |         LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Connect to an OS service given the port name, returns the handle to the port to out
 | /// Connect to an OS service given the port name, returns the handle to the port to out
 | ||||||
| static Result ConnectToPort(Handle* out, const char* port_name) { | static ResultCode ConnectToPort(Handle* out, const char* port_name) { | ||||||
|     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); |     LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); | ||||||
|  | @ -94,33 +102,33 @@ static Result ConnectToPort(Handle* out, const char* port_name) { | ||||||
| 
 | 
 | ||||||
|     *out = service->GetHandle(); |     *out = service->GetHandle(); | ||||||
| 
 | 
 | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Synchronize to an OS service
 | /// Synchronize to an OS service
 | ||||||
| static Result SendSyncRequest(Handle handle) { | static ResultCode SendSyncRequest(Handle handle) { | ||||||
|     SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); |     SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); | ||||||
|     if (session == nullptr) { |     if (session == nullptr) { | ||||||
|         return InvalidHandle(ErrorModule::Kernel).raw; |         return ERR_INVALID_HANDLE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); |     LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); | ||||||
| 
 | 
 | ||||||
|     return session->SyncRequest().Code().raw; |     return session->SyncRequest().Code(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Close a handle
 | /// Close a handle
 | ||||||
| static Result CloseHandle(Handle handle) { | static ResultCode CloseHandle(Handle handle) { | ||||||
|     // ImplementMe
 |     // ImplementMe
 | ||||||
|     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); |     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | ||||||
| static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||||||
|     auto object = Kernel::g_handle_table.GetWaitObject(handle); |     auto object = Kernel::g_handle_table.GetWaitObject(handle); | ||||||
|     if (object == nullptr) |     if (object == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::Kernel).raw; |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, |     LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, | ||||||
|             object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); |             object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); | ||||||
|  | @ -137,22 +145,22 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||||||
|         HLE::Reschedule(__func__); |         HLE::Reschedule(__func__); | ||||||
| 
 | 
 | ||||||
|         // NOTE: output of this SVC will be set later depending on how the thread resumes
 |         // NOTE: output of this SVC will be set later depending on how the thread resumes
 | ||||||
|         return RESULT_INVALID.raw; |         return RESULT_INVALID; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     object->Acquire(); |     object->Acquire(); | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
 | ||||||
| static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { | ||||||
|     bool wait_thread = !wait_all; |     bool wait_thread = !wait_all; | ||||||
|     int handle_index = 0; |     int handle_index = 0; | ||||||
| 
 | 
 | ||||||
|     // Check if 'handles' is invalid
 |     // Check if 'handles' is invalid
 | ||||||
|     if (handles == nullptr) |     if (handles == nullptr) | ||||||
|         return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent).raw; |         return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
| 
 | 
 | ||||||
|     // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
 |     // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
 | ||||||
|     // this happens, the running application will crash.
 |     // this happens, the running application will crash.
 | ||||||
|  | @ -160,7 +168,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | ||||||
| 
 | 
 | ||||||
|     // Check if 'handle_count' is invalid
 |     // Check if 'handle_count' is invalid
 | ||||||
|     if (handle_count < 0) |     if (handle_count < 0) | ||||||
|         return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw; |         return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||||||
| 
 | 
 | ||||||
|     // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if
 |     // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if
 | ||||||
|     // necessary
 |     // necessary
 | ||||||
|  | @ -169,7 +177,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | ||||||
|         for (int i = 0; i < handle_count; ++i) { |         for (int i = 0; i < handle_count; ++i) { | ||||||
|             auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); |             auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); | ||||||
|             if (object == nullptr) |             if (object == nullptr) | ||||||
|                 return InvalidHandle(ErrorModule::Kernel).raw; |                 return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|             // Check if the current thread should wait on this object...
 |             // Check if the current thread should wait on this object...
 | ||||||
|             if (object->ShouldWait()) { |             if (object->ShouldWait()) { | ||||||
|  | @ -213,7 +221,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | ||||||
|         HLE::Reschedule(__func__); |         HLE::Reschedule(__func__); | ||||||
| 
 | 
 | ||||||
|         // NOTE: output of this SVC will be set later depending on how the thread resumes
 |         // NOTE: output of this SVC will be set later depending on how the thread resumes
 | ||||||
|         return RESULT_INVALID.raw; |         return RESULT_INVALID; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Acquire objects if we did not wait...
 |     // Acquire objects if we did not wait...
 | ||||||
|  | @ -235,22 +243,32 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | ||||||
|     // not seem to set it to any meaningful value.
 |     // not seem to set it to any meaningful value.
 | ||||||
|     *out = wait_all ? 0 : handle_index; |     *out = wait_all ? 0 : handle_index; | ||||||
| 
 | 
 | ||||||
|     return RESULT_SUCCESS.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create an address arbiter (to allocate access to shared resources)
 | /// Create an address arbiter (to allocate access to shared resources)
 | ||||||
| static Result CreateAddressArbiter(u32* arbiter) { | static ResultCode CreateAddressArbiter(Handle* out_handle) { | ||||||
|     Handle handle = Kernel::CreateAddressArbiter(); |     using Kernel::AddressArbiter; | ||||||
|     *arbiter = handle; | 
 | ||||||
|     return 0; |     CASCADE_RESULT(SharedPtr<AddressArbiter> arbiter, AddressArbiter::Create()); | ||||||
|  |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); | ||||||
|  |     LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Arbitrate address
 | /// Arbitrate address
 | ||||||
| static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { | static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { | ||||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter, |     using Kernel::AddressArbiter; | ||||||
|  | 
 | ||||||
|  |     LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, | ||||||
|         address, type, value); |         address, type, value); | ||||||
|     return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), | 
 | ||||||
|             address, value, nanoseconds).raw; |     SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle); | ||||||
|  |     if (arbiter == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     return arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), | ||||||
|  |             address, value, nanoseconds); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Used to output a message on a debug hardware unit - does nothing on a retail unit
 | /// 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) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get resource limit
 | /// Get resource limit
 | ||||||
| static Result GetResourceLimit(Handle* resource_limit, Handle process) { | static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) { | ||||||
|     // With regards to proceess values:
 |     // With regards to proceess values:
 | ||||||
|     // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
 |     // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
 | ||||||
|     // the current KThread.
 |     // the current KThread.
 | ||||||
|     *resource_limit = 0xDEADBEEF; |     *resource_limit = 0xDEADBEEF; | ||||||
|     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); |     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get resource limit current values
 | /// Get resource limit current values
 | ||||||
| static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, | static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, | ||||||
|     s32 name_count) { |     s32 name_count) { | ||||||
|     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", |     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", | ||||||
|         resource_limit, names, name_count); |         resource_limit, names, name_count); | ||||||
|     Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
 |     Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
 | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Creates a new thread
 | /// Creates a new thread
 | ||||||
| static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { | static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { | ||||||
|     using Kernel::Thread; |     using Kernel::Thread; | ||||||
| 
 | 
 | ||||||
|     std::string name; |     std::string name; | ||||||
|  | @ -289,25 +307,20 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top | ||||||
|         name = Common::StringFromFormat("unknown-%08x", entry_point); |         name = Common::StringFromFormat("unknown-%08x", entry_point); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     ResultVal<SharedPtr<Thread>> thread_res = Kernel::Thread::Create( |     CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create( | ||||||
|             name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE); |             name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE)); | ||||||
|     if (thread_res.Failed()) |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); | ||||||
|         return thread_res.Code().raw; |  | ||||||
|     SharedPtr<Thread> thread = std::move(*thread_res); |  | ||||||
| 
 |  | ||||||
|     // TODO(yuriks): Create new handle instead of using built-in
 |  | ||||||
|     Core::g_app_core->SetReg(1, thread->GetHandle()); |  | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " |     LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " | ||||||
|         "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, |         "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, | ||||||
|         name.c_str(), arg, stack_top, priority, processor_id, thread->GetHandle()); |         name.c_str(), arg, stack_top, priority, processor_id, *out_handle); | ||||||
| 
 | 
 | ||||||
|     if (THREADPROCESSORID_1 == processor_id) { |     if (THREADPROCESSORID_1 == processor_id) { | ||||||
|         LOG_WARNING(Kernel_SVC, |         LOG_WARNING(Kernel_SVC, | ||||||
|             "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); |             "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Called when a thread exits
 | /// Called when a thread exits
 | ||||||
|  | @ -319,128 +332,192 @@ static void ExitThread() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Gets the priority for the specified thread
 | /// Gets the priority for the specified thread
 | ||||||
| static Result GetThreadPriority(s32* priority, Handle handle) { | static ResultCode GetThreadPriority(s32* priority, Handle handle) { | ||||||
|     const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |     const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | ||||||
|     if (thread == nullptr) |     if (thread == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::Kernel).raw; |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     *priority = thread->GetPriority(); |     *priority = thread->GetPriority(); | ||||||
|     return RESULT_SUCCESS.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Sets the priority for the specified thread
 | /// Sets the priority for the specified thread
 | ||||||
| static Result SetThreadPriority(Handle handle, s32 priority) { | static ResultCode SetThreadPriority(Handle handle, s32 priority) { | ||||||
|     SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |     SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | ||||||
|     if (thread == nullptr) |     if (thread == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::Kernel).raw; |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     thread->SetPriority(priority); |     thread->SetPriority(priority); | ||||||
|     return RESULT_SUCCESS.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create a mutex
 | /// Create a mutex
 | ||||||
| static Result CreateMutex(Handle* mutex, u32 initial_locked) { | static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { | ||||||
|     *mutex = Kernel::CreateMutex((initial_locked != 0)); |     using Kernel::Mutex; | ||||||
|  | 
 | ||||||
|  |     CASCADE_RESULT(SharedPtr<Mutex> mutex, Mutex::Create(initial_locked != 0)); | ||||||
|  |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", | ||||||
|         initial_locked ? "true" : "false", *mutex); |         initial_locked ? "true" : "false", *out_handle); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Release a mutex
 | /// Release a mutex
 | ||||||
| static Result ReleaseMutex(Handle handle) { | static ResultCode ReleaseMutex(Handle handle) { | ||||||
|  |     using Kernel::Mutex; | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); | ||||||
|     ResultCode res = Kernel::ReleaseMutex(handle); | 
 | ||||||
|     return res.raw; |     SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle); | ||||||
|  |     if (mutex == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     mutex->Release(); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get the ID for the specified thread.
 | /// Get the ID for the specified thread.
 | ||||||
| static Result GetThreadId(u32* thread_id, Handle handle) { | static ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||||||
|     LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); | ||||||
| 
 | 
 | ||||||
|     const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |     const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | ||||||
|     if (thread == nullptr) |     if (thread == nullptr) | ||||||
|         return InvalidHandle(ErrorModule::Kernel).raw; |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
|     *thread_id = thread->GetThreadId(); |     *thread_id = thread->GetThreadId(); | ||||||
|     return RESULT_SUCCESS.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Creates a semaphore
 | /// Creates a semaphore
 | ||||||
| static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) { | static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { | ||||||
|     ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count); |     using Kernel::Semaphore; | ||||||
|  | 
 | ||||||
|  |     CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count)); | ||||||
|  |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", | ||||||
|         initial_count, max_count, *semaphore); |         initial_count, max_count, *out_handle); | ||||||
|     return res.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Releases a certain number of slots in a semaphore
 | /// Releases a certain number of slots in a semaphore
 | ||||||
| static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) { | static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | ||||||
|     LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore); |     using Kernel::Semaphore; | ||||||
|     ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count); | 
 | ||||||
|     return res.raw; |     LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle); | ||||||
|  | 
 | ||||||
|  |     SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle); | ||||||
|  |     if (semaphore == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     CASCADE_RESULT(*count, semaphore->Release(release_count)); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Query memory
 | /// Query memory
 | ||||||
| static Result QueryMemory(void* info, void* out, u32 addr) { | static ResultCode QueryMemory(void* info, void* out, u32 addr) { | ||||||
|     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); |     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create an event
 | /// Create an event
 | ||||||
| static Result CreateEvent(Handle* evt, u32 reset_type) { | static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { | ||||||
|     *evt = Kernel::CreateEvent((ResetType)reset_type); |     CASCADE_RESULT(auto evt, Kernel::Event::Create(static_cast<ResetType>(reset_type))); | ||||||
|  |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | ||||||
|         reset_type, *evt); |             reset_type, *out_handle); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Duplicates a kernel handle
 | /// Duplicates a kernel handle
 | ||||||
| static Result DuplicateHandle(Handle* out, Handle handle) { | static ResultCode DuplicateHandle(Handle* out, Handle handle) { | ||||||
|     ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); |     ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); | ||||||
|     if (out_h.Succeeded()) { |     if (out_h.Succeeded()) { | ||||||
|         *out = *out_h; |         *out = *out_h; | ||||||
|         LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); |         LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); | ||||||
|     } |     } | ||||||
|     return out_h.Code().raw; |     return out_h.Code(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Signals an event
 | /// Signals an event
 | ||||||
| static Result SignalEvent(Handle evt) { | static ResultCode SignalEvent(Handle handle) { | ||||||
|     LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); |     LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); | ||||||
|  | 
 | ||||||
|  |     auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||||||
|  |     if (evt == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     evt->Signal(); | ||||||
|     HLE::Reschedule(__func__); |     HLE::Reschedule(__func__); | ||||||
|     return Kernel::SignalEvent(evt).raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Clears an event
 | /// Clears an event
 | ||||||
| static Result ClearEvent(Handle evt) { | static ResultCode ClearEvent(Handle handle) { | ||||||
|     LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); |     LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); | ||||||
|     return Kernel::ClearEvent(evt).raw; | 
 | ||||||
|  |     auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||||||
|  |     if (evt == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     evt->Clear(); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Creates a timer
 | /// Creates a timer
 | ||||||
| static Result CreateTimer(Handle* handle, u32 reset_type) { | static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { | ||||||
|     ResultCode res = Kernel::CreateTimer(handle, static_cast<ResetType>(reset_type)); |     using Kernel::Timer; | ||||||
|  | 
 | ||||||
|  |     CASCADE_RESULT(auto timer, Timer::Create(static_cast<ResetType>(reset_type))); | ||||||
|  |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | ||||||
|         reset_type, *handle); |             reset_type, *out_handle); | ||||||
|     return res.raw; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Clears a timer
 | /// Clears a timer
 | ||||||
| static Result ClearTimer(Handle handle) { | static ResultCode ClearTimer(Handle handle) { | ||||||
|  |     using Kernel::Timer; | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | ||||||
|     return Kernel::ClearTimer(handle).raw; | 
 | ||||||
|  |     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||||||
|  |     if (timer == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     timer->Clear(); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Starts a timer
 | /// Starts a timer
 | ||||||
| static Result SetTimer(Handle handle, s64 initial, s64 interval) { | static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { | ||||||
|  |     using Kernel::Timer; | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | ||||||
|     return Kernel::SetTimer(handle, initial, interval).raw; | 
 | ||||||
|  |     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||||||
|  |     if (timer == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     timer->Set(initial, interval); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Cancels a timer
 | /// Cancels a timer
 | ||||||
| static Result CancelTimer(Handle handle) { | static ResultCode CancelTimer(Handle handle) { | ||||||
|  |     using Kernel::Timer; | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | ||||||
|     return Kernel::CancelTimer(handle).raw; | 
 | ||||||
|  |     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||||||
|  |     if (timer == nullptr) | ||||||
|  |         return ERR_INVALID_HANDLE; | ||||||
|  | 
 | ||||||
|  |     timer->Cancel(); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Sleep the current thread
 | /// Sleep the current thread
 | ||||||
|  | @ -462,15 +539,16 @@ static s64 GetSystemTick() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Creates a memory block at the specified address with the specified permissions and size
 | /// Creates a memory block at the specified address with the specified permissions and size
 | ||||||
| static Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 my_permission, | static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, | ||||||
|     u32 other_permission) { |         u32 other_permission) { | ||||||
| 
 |     using Kernel::SharedMemory; | ||||||
|     // TODO(Subv): Implement this function
 |     // TODO(Subv): Implement this function
 | ||||||
| 
 | 
 | ||||||
|     Handle shared_memory = Kernel::CreateSharedMemory(); |     CASCADE_RESULT(auto shared_memory, SharedMemory::Create()); | ||||||
|     *memblock = shared_memory; |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); | ||||||
|  | 
 | ||||||
|     LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); |     LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const HLE::FunctionDef SVC_Table[] = { | const HLE::FunctionDef SVC_Table[] = { | ||||||
|  |  | ||||||
|  | @ -7,12 +7,9 @@ | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| namespace Memory { | #include "core/hle/kernel/kernel.h" | ||||||
| 
 | 
 | ||||||
| // TODO: It would be nice to eventually replace these with strong types that prevent accidental
 | namespace Memory { | ||||||
| // conversion between each other.
 |  | ||||||
| typedef u32 VAddr; ///< Represents a pointer in the ARM11 virtual address space.
 |  | ||||||
| typedef u32 PAddr; ///< Represents a pointer in the physical address space.
 |  | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
|  | @ -190,7 +187,3 @@ VAddr PhysicalToVirtualAddress(PAddr addr); | ||||||
| PAddr VirtualToPhysicalAddress(VAddr addr); | PAddr VirtualToPhysicalAddress(VAddr addr); | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 |  | ||||||
| // These are used often, so re-export then on the root namespace
 |  | ||||||
| using Memory::VAddr; |  | ||||||
| using Memory::PAddr; |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue