diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index c2750a63c8..229eb74c96 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -31,6 +31,10 @@ template<> struct CompileTimeAssert {}; #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 #include diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 263beaf0ef..77dcbaa223 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h @@ -4,6 +4,8 @@ #pragma once +#include "common/common_funcs.h" + namespace detail { template struct ScopeExitHelper { @@ -34,4 +36,4 @@ namespace detail { * } * \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) diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index a2f51b41b3..0b6b6f5180 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -33,114 +33,105 @@ static inline void FuncReturn64(u64 res) { } //////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type s32 +// Function wrappers that return type ResultCode -template void Wrap() { - FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3))); +template void Wrap() { + FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw); } -template void Wrap() { - FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4))); -} - -template void Wrap(){ +template void Wrap(){ 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); FuncReturn(retval); } -template void Wrap() { +template void Wrap() { s32 param_1 = 0; 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); FuncReturn(retval); } -// TODO(bunnei): Is this correct? Probably not - Last parameter looks wrong for ArbitrateAddress -template void Wrap() { - FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4)))); +template void Wrap() { + FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw); } -template void Wrap(){ +template void Wrap(){ u32 param_1 = 0; - u32 retval = func(¶m_1); + u32 retval = func(¶m_1).raw; Core::g_app_core->SetReg(1, param_1); FuncReturn(retval); } -template void Wrap() { - FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2)))); +template void Wrap() { + FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); } -template void Wrap(){ - FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2))); +template void Wrap(){ + FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw); } -template void Wrap(){ +template void Wrap(){ 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); FuncReturn(retval); } -template void Wrap() { - FuncReturn(func(PARAM(0), (s32)PARAM(1))); +template void Wrap() { + FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw); } -template void Wrap(){ +template void Wrap(){ 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); FuncReturn(retval); } -template void Wrap() { - FuncReturn(func(PARAM(0))); +template void Wrap() { + FuncReturn(func(PARAM(0)).raw); } -template void Wrap() { - FuncReturn(func(Memory::GetPointer(PARAM(0)))); -} - -template void Wrap(){ +template void Wrap(){ FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), - (s32)PARAM(3))); + (s32)PARAM(3)).raw); } -template void Wrap() { +template void Wrap() { 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); FuncReturn(retval); } -template void Wrap() { +template void Wrap() { 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); FuncReturn(retval); } -template void Wrap() { +template void Wrap() { 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); FuncReturn(retval); } -template void Wrap() { +template void Wrap() { 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); FuncReturn(retval); } -template void Wrap() { +template void Wrap() { s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2); s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1); - FuncReturn(func(PARAM(0), param1, param2)); + FuncReturn(func(PARAM(0), param1, param2).raw); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 9e855b0bf2..2d01e2ef58 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -15,26 +15,18 @@ namespace Kernel { -class AddressArbiter : public Object { -public: - std::string GetTypeName() const override { return "Arbiter"; } - std::string GetName() const override { return name; } +ResultVal> AddressArbiter::Create(std::string name) { + SharedPtr address_arbiter(new AddressArbiter); + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter)); - static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; - HandleType GetHandleType() const override { return HANDLE_TYPE; } + address_arbiter->name = std::move(name); - std::string name; ///< Name of address arbiter object (optional) -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Arbitrate an address -ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { - AddressArbiter* object = Kernel::g_handle_table.Get(handle).get(); - - if (object == nullptr) - return InvalidHandle(ErrorModule::Kernel); + return MakeResult>(std::move(address_arbiter)); +} +ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, + u64 nanoseconds) { switch (type) { // Signal thread(s) waiting for arbitrate address... @@ -92,20 +84,4 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 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 diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 3ffd465a22..638afff9e5 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -18,7 +18,6 @@ namespace Kernel { -/// Address arbitration types enum class ArbitrationType : u32 { Signal, WaitIfLessThan, @@ -27,10 +26,28 @@ enum class ArbitrationType : u32 { DecrementAndWaitIfLessThanWithTimeout, }; -/// Arbitrate an address -ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds); +class AddressArbiter final : public Object { +public: + /** + * Creates an address arbiter. + * + * @param name Optional name used for debugging. + * @returns The created AddressArbiter. + */ + static ResultVal> Create(std::string name = "Unknown"); -/// Create an address arbiter -Handle CreateAddressArbiter(const std::string& name = "Unknown"); + std::string GetTypeName() const override { return "Arbiter"; } + 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 diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index a481259651..d9ad40c6a3 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -14,78 +14,37 @@ namespace Kernel { -class Event : public WaitObject { -public: - std::string GetTypeName() const override { return "Event"; } - std::string GetName() const override { return name; } - - 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(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(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); +ResultVal> Event::Create(ResetType reset_type, std::string name) { + SharedPtr evt(new Event); + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt)); evt->signaled = false; evt->reset_type = evt->intitial_reset_type = reset_type; - evt->name = name; + evt->name = std::move(name); - return evt; + return MakeResult>(evt); } -Handle CreateEvent(const ResetType reset_type, const std::string& name) { - Handle handle; - Event* evt = CreateEvent(handle, reset_type, name); - return handle; +bool Event::ShouldWait() { + return !signaled; +} + +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 diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index c08b12ee16..2c3e6b14e3 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -11,26 +11,35 @@ namespace Kernel { -/** - * Signals an event - * @param handle Handle to event to signal - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode SignalEvent(const Handle handle); +class Event final : public WaitObject { +public: + /** + * Creates an event + * @param reset_type ResetType describing how to create event + * @param name Optional name of event + */ + static ResultVal> Create(ResetType reset_type, std::string name = "Unknown"); -/** - * Clears an event - * @param handle Handle to event to clear - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode ClearEvent(Handle handle); + std::string GetTypeName() const override { return "Event"; } + std::string GetName() const override { return name; } -/** - * Creates an event - * @param reset_type ResetType describing how to create event - * @param name Optional name of event - * @return Handle to newly created Event object - */ -Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); + 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; + void Acquire() override; + + void Signal(); + void Clear(); + +private: + Event() = default; +}; } // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3828efbeaf..9860479ac7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -16,6 +16,11 @@ typedef u32 Handle; 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; namespace Kernel { @@ -26,7 +31,8 @@ class Thread; const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Temporary); // 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 { CurrentThread = 0xFFFF8000, diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index cd05a1397c..acf4846593 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -13,59 +13,30 @@ 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 holding_thread; ///< Thread that has acquired the mutex - - bool ShouldWait() override; - void Acquire() override; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - typedef std::multimap, SharedPtr> MutexMap; 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 * @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... auto next_thread = mutex->WakeupNextThread(); if (next_thread != nullptr) { - MutexAcquireLock(mutex, next_thread); - } else { - // Reset mutex lock thread handle, nothing is waiting - mutex->locked = false; - mutex->holding_thread = nullptr; + mutex->Acquire(next_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 - for (auto iter = locked.first; iter != locked.second; ++iter) { + for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { ResumeWaitingThread(iter->second.get()); } @@ -73,72 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { g_mutex_held_locks.erase(thread); } -bool ReleaseMutex(Mutex* mutex) { - if (mutex->locked) { - auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); +ResultVal> Mutex::Create(bool initial_locked, std::string name) { + SharedPtr mutex(new Mutex); + // 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) { - if (iter->second == mutex) { - g_mutex_held_locks.erase(iter); - 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(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->initial_locked = initial_locked; + mutex->locked = false; + mutex->name = std::move(name); mutex->holding_thread = nullptr; // Acquire mutex with current thread if initialized as locked... - if (mutex->locked) - MutexAcquireLock(mutex, GetCurrentThread()); + if (initial_locked) + mutex->Acquire(); - return 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; + return MakeResult>(mutex); } bool Mutex::ShouldWait() { @@ -146,9 +66,34 @@ bool Mutex::ShouldWait() { } void Mutex::Acquire() { + Acquire(GetCurrentThread()); +} + +void Mutex::Acquire(Thread* thread) { _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + if (locked) + return; + 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 diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bb8778c989..1e69528f1f 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -4,25 +4,51 @@ #pragma once +#include + #include "common/common_types.h" #include "core/hle/kernel/kernel.h" namespace Kernel { -/** - * Releases a mutex - * @param handle Handle to mutex to release - */ -ResultCode ReleaseMutex(Handle handle); +class Thread; -/** - * 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="Unknown"); +class Mutex final : public WaitObject { +public: + /** + * Creates a mutex. + * @param initial_locked Specifies if the mutex should be locked initially + * @param name Optional name of mutex + * @return Pointer to new Mutex object + */ + static ResultVal> 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 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 diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 135d8fb2a9..a9e406ef46 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include - #include "common/common.h" #include "core/hle/kernel/kernel.h" @@ -12,69 +10,50 @@ namespace Kernel { -class Semaphore : public WaitObject { -public: - 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) { +ResultVal> Semaphore::Create(s32 initial_count, s32 max_count, + std::string name) { if (initial_count > max_count) return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Permanent); - Semaphore* semaphore = new Semaphore; - // TOOD(yuriks): Fix error reporting - *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE); + SharedPtr semaphore(new Semaphore); + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore)); // When the semaphore is created, some slots are reserved for other threads, // and the rest is reserved for the caller thread semaphore->max_count = max_count; semaphore->available_count = initial_count; - semaphore->name = name; + semaphore->name = std::move(name); - return RESULT_SUCCESS; + return MakeResult>(std::move(semaphore)); } -ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { - Semaphore* semaphore = g_handle_table.Get(handle).get(); - if (semaphore == nullptr) - return InvalidHandle(ErrorModule::Kernel); +bool Semaphore::ShouldWait() { + return available_count <= 0; +} - if (semaphore->max_count - semaphore->available_count < release_count) +void Semaphore::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + --available_count; +} + +ResultVal Semaphore::Release(s32 release_count) { + if (max_count - available_count < release_count) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); - *count = semaphore->available_count; - semaphore->available_count += release_count; + s32 previous_count = available_count; + available_count += release_count; // 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 - while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { - semaphore->Acquire(); + while (!ShouldWait() && WakeupNextThread() != nullptr) { + Acquire(); } - return RESULT_SUCCESS; + return MakeResult(previous_count); } } // namespace diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 8644ecf0c0..9bb404ab67 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h @@ -4,29 +4,50 @@ #pragma once +#include +#include + #include "common/common_types.h" #include "core/hle/kernel/kernel.h" namespace Kernel { -/** - * Creates a semaphore. - * @param handle Pointer to the handle of the newly created object - * @param initial_count Number of slots reserved for other threads - * @param max_count Maximum number of slots the semaphore can have - * @param name Optional name of semaphore - * @return ResultCode of the error - */ -ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); +class Semaphore final : public WaitObject { +public: + /** + * Creates a semaphore. + * @param handle Pointer to the handle of the newly created object + * @param initial_count Number of slots reserved for other threads + * @param max_count Maximum number of slots the semaphore can have + * @param name Optional name of semaphore + * @return The created semaphore + */ + static ResultVal> Create(s32 initial_count, s32 max_count, + std::string name = "Unknown"); -/** - * Releases a certain number of slots from a semaphore. - * @param count The number of free slots the semaphore had before this call - * @param handle The handle of the semaphore to release - * @param release_count The number of slots to release - * @return ResultCode of the error - */ -ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count); + 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; + 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 Release(s32 release_count); + +private: + Semaphore() = default; +}; } // namespace diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 5368e47280..536d134b0f 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -9,76 +9,39 @@ namespace Kernel { -class SharedMemory : public Object { -public: - std::string GetTypeName() const override { return "SharedMemory"; } +ResultVal> SharedMemory::Create(std::string name) { + SharedPtr shared_memory(new SharedMemory); - static const HandleType HANDLE_TYPE = HandleType::SharedMemory; - HandleType GetHandleType() const override { return HANDLE_TYPE; } + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); - u32 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) -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * 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; + shared_memory->name = std::move(name); + return MakeResult>(std::move(shared_memory)); } -Handle CreateSharedMemory(const std::string& name) { - Handle handle; - 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) { +ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, + MemoryPermission other_permissions) { 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!", - handle, address); + LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", + GetHandle(), address); + // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } - SharedMemory* shared_memory = Kernel::g_handle_table.Get(handle).get(); - if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); - shared_memory->base_address = address; - shared_memory->permissions = permissions; - shared_memory->other_permissions = other_permissions; + base_address = address; + permissions = permissions; + other_permissions = other_permissions; return RESULT_SUCCESS; } -ResultVal GetSharedMemoryPointer(Handle handle, u32 offset) { - SharedMemory* shared_memory = Kernel::g_handle_table.Get(handle).get(); - if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); +ResultVal SharedMemory::GetPointer(u32 offset) { + if (base_address != 0) + return MakeResult(Memory::GetPointer(base_address + offset)); - if (0 != shared_memory->base_address) - return MakeResult(Memory::GetPointer(shared_memory->base_address + offset)); - - LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle); + LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); // TODO(yuriks): Verify error code. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidState, ErrorLevel::Permanent); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index bb65c7ccd6..f9ae23e93b 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -23,29 +23,41 @@ enum class MemoryPermission : u32 { DontCare = (1u << 28) }; -/** - * Creates a shared memory object - * @param name Optional name of shared memory object - * @return Handle of newly created shared memory object - */ -Handle CreateSharedMemory(const std::string& name="Unknown"); +class SharedMemory final : public Object { +public: + /** + * Creates a shared memory object + * @param name Optional object name, used only for debugging purposes. + */ + static ResultVal> Create(std::string name = "Unknown"); -/** - * 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); + std::string GetTypeName() const override { return "SharedMemory"; } -/** - * Gets a pointer to the shared memory block - * @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 - */ -ResultVal GetSharedMemoryPointer(Handle handle, u32 offset); + static const HandleType HANDLE_TYPE = HandleType::SharedMemory; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + /** + * Maps a shared memory block to an address in system memory + * @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 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 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 diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 5fab1ab588..d6299364ab 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -40,7 +40,7 @@ enum ThreadStatus { namespace Kernel { -class Thread : public WaitObject { +class Thread final : public WaitObject { public: static ResultVal> Create(std::string name, VAddr entry_point, s32 priority, u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); @@ -115,7 +115,6 @@ public: bool idle = false; private: - Thread() = default; }; diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index ec0b2c3239..503a5d2ce7 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -13,75 +13,54 @@ namespace Kernel { -class Timer : public WaitObject { -public: - std::string GetTypeName() const override { return "Timer"; } - std::string GetName() const override { return name; } +/// The event type of the generic timer callback event +static int timer_callback_event_type = -1; - static const HandleType HANDLE_TYPE = HandleType::Timer; - HandleType GetHandleType() const override { return HANDLE_TYPE; } - - ResetType reset_type; ///< The ResetType of this 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); +ResultVal> Timer::Create(ResetType reset_type, std::string name) { + SharedPtr timer(new Timer); + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer)); timer->reset_type = reset_type; timer->signaled = false; - timer->name = name; + timer->name = std::move(name); timer->initial_delay = 0; timer->interval_delay = 0; - return timer; + return MakeResult>(timer); } -ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { - CreateTimer(*handle, reset_type, name); - return RESULT_SUCCESS; +bool Timer::ShouldWait() { + return !signaled; } -ResultCode ClearTimer(Handle handle) { - SharedPtr timer = Kernel::g_handle_table.Get(handle); - - if (timer == nullptr) - return InvalidHandle(ErrorModule::Kernel); - - timer->signaled = false; - return RESULT_SUCCESS; +void Timer::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); } -/// The event type of the generic timer callback event -static int TimerCallbackEventType = -1; +void Timer::Set(s64 initial, s64 interval) { + 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 static void TimerCallback(u64 timer_handle, int cycles_late) { SharedPtr timer = Kernel::g_handle_table.Get(timer_handle); 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; } @@ -99,36 +78,12 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { // Reschedule the timer with the interval delay u64 interval_microseconds = timer->interval_delay / 1000; 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 = Kernel::g_handle_table.Get(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 = Kernel::g_handle_table.Get(handle); - - if (timer == nullptr) - return InvalidHandle(ErrorModule::Kernel); - - CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); - return RESULT_SUCCESS; -} - void TimersInit() { - TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); + timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); } void TimersShutdown() { diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index 8170e82d42..c45e799544 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -11,37 +11,50 @@ namespace Kernel { -/** - * Cancels a timer - * @param handle Handle of the timer to cancel - */ -ResultCode CancelTimer(Handle handle); +class Timer final : public WaitObject { +public: + /** + * Creates a timer + * @param reset_type ResetType describing how to create the timer + * @param name Optional name of timer + * @return The created Timer + */ + static ResultVal> Create(ResetType reset_type, std::string name = "Unknown"); -/** - * Starts a timer with the specified initial delay and interval - * @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); + std::string GetTypeName() const override { return "Timer"; } + std::string GetName() const override { return name; } -/** - * Clears a timer - * @param handle Handle of the timer to clear - */ -ResultCode ClearTimer(Handle handle); + static const HandleType HANDLE_TYPE = HandleType::Timer; + HandleType GetHandleType() const override { return HANDLE_TYPE; } -/** - * Creates a timer - * @param handle Handle to the newly created Timer object - * @param reset_type ResetType describing how to create the timer - * @param name Optional name of timer - * @return ResultCode of the error - */ -ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); + ResetType reset_type; ///< The ResetType of this 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; + 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 void TimersInit(); /// Tears down the timer variables void TimersShutdown(); + } // namespace diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 82dcf5bba7..948b9e38e8 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -9,8 +9,9 @@ #include #include -#include "common/common_types.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 @@ -226,11 +227,6 @@ inline ResultCode UnimplementedFunction(ErrorModule module) { return ResultCode(ErrorDescription::NotImplemented, module, 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, @@ -364,6 +360,17 @@ public: 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: typedef typename std::aligned_storage::value>::type StorageType; @@ -400,3 +407,15 @@ template ResultVal MakeResult(Args&&... args) { return ResultVal::WithCode(RESULT_SUCCESS, std::forward(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__)) diff --git a/src/core/hle/service/apt_s.cpp b/src/core/hle/service/apt_s.cpp index 31e6653ef1..7ad428ee7e 100644 --- a/src/core/hle/service/apt_s.cpp +++ b/src/core/hle/service/apt_s.cpp @@ -10,6 +10,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" #include "core/hle/service/apt_s.h" //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp index 001b0d1836..629b670eda 100644 --- a/src/core/hle/service/apt_u.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -10,6 +10,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" #include "core/hle/service/apt_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -26,11 +27,11 @@ namespace APT_U { static const VAddr SHARED_FONT_VADDR = 0x18000000; /// Handle to shared memory region designated to for shared system font -static Handle shared_font_mem = 0; +static Kernel::SharedPtr shared_font_mem; -static Handle lock_handle = 0; -static Handle notification_event_handle = 0; ///< APT notification event handle -static Handle pause_event_handle = 0; ///< APT pause event handle +static Kernel::SharedPtr lock; +static Kernel::SharedPtr notification_event; ///< APT notification event +static Kernel::SharedPtr pause_event = 0; ///< APT pause event static std::vector shared_font; /// Signals used by APT functions @@ -67,17 +68,19 @@ enum class AppID : u32 { void Initialize(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - notification_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Notification"); - pause_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); + // TODO(bunnei): Check if these are created in Initialize or on APT process startup. + 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[4] = pause_event_handle; + cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); - Kernel::ClearEvent(notification_event_handle); - Kernel::SignalEvent(pause_event_handle); // Fire start event + // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called. + notification_event->Clear(); + pause_event->Signal(); // Fire start event - _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); - Kernel::ReleaseMutex(lock_handle); + _assert_msg_(KERNEL, (nullptr != lock), "Cannot initialize without lock"); + lock->Release(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error } @@ -93,7 +96,7 @@ void NotifyToWait(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 app_id = cmd_buff[1]; // 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 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 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 // 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[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]); } @@ -354,7 +352,7 @@ void GetSharedFont(Service::Interface* self) { cmd_buff[0] = 0x00440082; cmd_buff[1] = RESULT_SUCCESS.raw; // No error 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 { 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); @@ -514,13 +512,13 @@ Interface::Interface() { file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); // 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 { 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)); } diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index d5e39ea4b2..9a38be3938 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -13,8 +13,8 @@ namespace DSP_DSP { static u32 read_pipe_count = 0; -static Handle semaphore_event = 0; -static Handle interrupt_event = 0; +static Kernel::SharedPtr semaphore_event; +static Kernel::SharedPtr interrupt_event; void SignalInterrupt() { // 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. 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) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[1] = 0; // No error - cmd_buff[3] = semaphore_event; // Event handle + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[3] = Kernel::g_handle_table.Create(semaphore_event).MoveFrom(); // Event handle LOG_WARNING(Service_DSP, "(STUBBED) called"); } @@ -96,9 +96,16 @@ void GetSemaphoreEventHandle(Service::Interface* self) { void RegisterInterruptEvents(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - interrupt_event = static_cast(cmd_buff[4]); + auto evt = Kernel::g_handle_table.Get(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"); } @@ -194,8 +201,9 @@ const Interface::FunctionInfo FunctionTable[] = { // Interface class Interface::Interface() { - semaphore_event = Kernel::CreateEvent(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event"); - interrupt_event = 0; + semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, + "DSP_DSP::semaphore_event").MoveFrom(); + interrupt_event = nullptr; read_pipe_count = 0; Register(FunctionTable, ARRAY_SIZE(FunctionTable)); diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 1bb4e4b230..6682f6590d 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -43,6 +43,11 @@ const std::string SDCARD_ID = "00000000000000000000000000000000"; namespace Service { 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 enum class FileCommand : u32 { Dummy1 = 0x000100C6, @@ -280,7 +285,7 @@ ResultVal OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi ResultCode CloseArchive(ArchiveHandle handle) { if (handle_map.erase(handle) == 0) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; else return RESULT_SUCCESS; } @@ -301,7 +306,7 @@ ResultCode CreateArchive(std::unique_ptr&& backend, Arc ResultVal OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; std::unique_ptr backend = archive->backend->OpenFile(path, mode); if (backend == nullptr) { @@ -318,7 +323,7 @@ ResultVal OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; if (archive->backend->DeleteFile(path)) return RESULT_SUCCESS; @@ -331,7 +336,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil Archive* src_archive = GetArchive(src_archive_handle); Archive* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; if (src_archive == dest_archive) { 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) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; if (archive->backend->DeleteDirectory(path)) 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) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; 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) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; if (archive->backend->CreateDirectory(path)) return RESULT_SUCCESS; @@ -382,7 +387,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons Archive* src_archive = GetArchive(src_archive_handle); Archive* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; if (src_archive == dest_archive) { if (src_archive->backend->RenameDirectory(src_path, dest_path)) @@ -407,7 +412,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons ResultVal OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { Archive* archive = GetArchive(archive_handle); if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); + return ERR_INVALID_HANDLE; std::unique_ptr backend = archive->backend->OpenDirectory(path); if (backend == nullptr) { diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 4ca2b9bd0f..5b91f17d27 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -22,13 +22,16 @@ GraphicsDebugger g_debugger; namespace GSP_GPU { -Handle g_interrupt_event = 0; ///< Handle to event triggered when GSP interrupt has been signalled -Handle g_shared_memory = 0; ///< Handle to GSP shared memorys -u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1 is arbitrary +/// Event triggered when GSP interrupt has been signalled +Kernel::SharedPtr g_interrupt_event; +/// GSP shared memoryings +Kernel::SharedPtr 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 static inline u8* GetCommandBuffer(u32 thread_id) { - ResultVal ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer))); + ResultVal ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); 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 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); - ResultVal ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset); + ResultVal ptr = g_shared_memory->GetPointer(offset); return reinterpret_cast(ptr.ValueOr(nullptr)); } /// Gets a pointer to the interrupt relay queue for a given thread index static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { - ResultVal ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id); + ResultVal ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id); return reinterpret_cast(ptr.ValueOr(nullptr)); } @@ -181,16 +184,18 @@ static void FlushDataCache(Service::Interface* self) { static void RegisterInterruptRelayQueue(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); 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(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[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!"); return; } - if (0 == g_shared_memory) { + if (nullptr == g_shared_memory) { LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); return; } @@ -232,7 +237,7 @@ void SignalInterrupt(InterruptId interrupt_id) { info->is_dirty = false; } } - Kernel::SignalEvent(g_interrupt_event); + g_interrupt_event->Signal(); } /// Executes the next GSP command diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5abcb2596c..835055af48 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -12,13 +12,13 @@ namespace Service { namespace HID { -Handle g_shared_mem = 0; +Kernel::SharedPtr g_shared_mem = nullptr; -Handle g_event_pad_or_touch_1 = 0; -Handle g_event_pad_or_touch_2 = 0; -Handle g_event_accelerometer = 0; -Handle g_event_gyroscope = 0; -Handle g_event_debug_pad = 0; +Kernel::SharedPtr g_event_pad_or_touch_1; +Kernel::SharedPtr g_event_pad_or_touch_2; +Kernel::SharedPtr g_event_accelerometer; +Kernel::SharedPtr g_event_gyroscope; +Kernel::SharedPtr g_event_debug_pad; // Next Pad state update information 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 */ static inline PadData* GetPadData() { - return reinterpret_cast(Kernel::GetSharedMemoryPointer(g_shared_mem, 0).ValueOr(nullptr)); + return reinterpret_cast(g_shared_mem->GetPointer().ValueOr(nullptr)); } /** @@ -115,19 +115,21 @@ void PadUpdateComplete() { } // Signal both handles when there's an update to Pad or touch - Kernel::SignalEvent(g_event_pad_or_touch_1); - Kernel::SignalEvent(g_event_pad_or_touch_2); + g_event_pad_or_touch_1->Signal(); + g_event_pad_or_touch_2->Signal(); } 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 - g_event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); - g_event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); - g_event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); - g_event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventGyroscope"); - g_event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID:EventDebugPad"); + g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1").MoveFrom(); + g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2").MoveFrom(); + g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer").MoveFrom(); + g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope").MoveFrom(); + g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad").MoveFrom(); } void HIDShutdown() { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 73cdaa527a..2116d2ca3f 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -9,18 +9,23 @@ #include "core/hle/kernel/kernel.h" #include "common/bit_field.h" +namespace Kernel { + class SharedMemory; + class Event; +} + namespace Service { namespace HID { // Handle to shared memory region designated to HID_User service -extern Handle g_shared_mem; +extern Kernel::SharedPtr g_shared_mem; // Event handles -extern Handle g_event_pad_or_touch_1; -extern Handle g_event_pad_or_touch_2; -extern Handle g_event_accelerometer; -extern Handle g_event_gyroscope; -extern Handle g_event_debug_pad; +extern Kernel::SharedPtr g_event_pad_or_touch_1; +extern Kernel::SharedPtr g_event_pad_or_touch_2; +extern Kernel::SharedPtr g_event_accelerometer; +extern Kernel::SharedPtr g_event_gyroscope; +extern Kernel::SharedPtr g_event_debug_pad; /** * Structure of a Pad controller state. diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index 3a62757074..5444aa5ee7 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -5,6 +5,8 @@ #include "common/log.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 "hid_user.h" @@ -46,12 +48,13 @@ void GetIPCHandles(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = 0; // No error - cmd_buff[3] = Service::HID::g_shared_mem; - cmd_buff[4] = Service::HID::g_event_pad_or_touch_1; - cmd_buff[5] = Service::HID::g_event_pad_or_touch_2; - cmd_buff[6] = Service::HID::g_event_accelerometer; - cmd_buff[7] = Service::HID::g_event_gyroscope; - cmd_buff[8] = Service::HID::g_event_debug_pad; + // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) + cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); + cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); + cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); + 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[] = { diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 082834cfe1..aa0aac3bb5 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -11,7 +11,7 @@ namespace SRV { -static Handle g_event_handle = 0; +static Kernel::SharedPtr event_handle; static void Initialize(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -23,11 +23,11 @@ static void GetProcSemaphore(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(bunnei): Change to a semaphore once these have been implemented - g_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "SRV:Event"); - Kernel::ClearEvent(g_event_handle); + event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event").MoveFrom(); + event_handle->Clear(); 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) { diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 3d743f1253..88813c2ce7 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -26,6 +26,7 @@ // Namespace SVC using Kernel::SharedPtr; +using Kernel::ERR_INVALID_HANDLE; namespace SVC { @@ -38,7 +39,7 @@ enum ControlMemoryOperation { }; /// 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", operation, addr0, addr1, size, permissions); @@ -58,35 +59,42 @@ static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, default: LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); } - return 0; + return RESULT_SUCCESS; } /// 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", handle, addr, permissions, other_permissions); - Kernel::MemoryPermission permissions_type = static_cast(permissions); + SharedPtr shared_memory = Kernel::g_handle_table.Get(handle); + if (shared_memory == nullptr) + return ERR_INVALID_HANDLE; + + MemoryPermission permissions_type = static_cast(permissions); switch (permissions_type) { - case Kernel::MemoryPermission::Read: - case Kernel::MemoryPermission::Write: - case Kernel::MemoryPermission::ReadWrite: - case Kernel::MemoryPermission::Execute: - case Kernel::MemoryPermission::ReadExecute: - case Kernel::MemoryPermission::WriteExecute: - case Kernel::MemoryPermission::ReadWriteExecute: - case Kernel::MemoryPermission::DontCare: - Kernel::MapSharedMemory(handle, addr, permissions_type, - static_cast(other_permissions)); + case MemoryPermission::Read: + case MemoryPermission::Write: + case MemoryPermission::ReadWrite: + case MemoryPermission::Execute: + case MemoryPermission::ReadExecute: + case MemoryPermission::WriteExecute: + case MemoryPermission::ReadWriteExecute: + case MemoryPermission::DontCare: + shared_memory->Map(addr, permissions_type, + static_cast(other_permissions)); break; default: 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 -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); 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(); - return 0; + return RESULT_SUCCESS; } /// Synchronize to an OS service -static Result SendSyncRequest(Handle handle) { +static ResultCode SendSyncRequest(Handle handle) { SharedPtr session = Kernel::g_handle_table.Get(handle); 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()); - return session->SyncRequest().Code().raw; + return session->SyncRequest().Code(); } /// Close a handle -static Result CloseHandle(Handle handle) { +static ResultCode CloseHandle(Handle handle) { // ImplementMe 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 -static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { +static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { auto object = Kernel::g_handle_table.GetWaitObject(handle); 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, 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__); // NOTE: output of this SVC will be set later depending on how the thread resumes - return RESULT_INVALID.raw; + return RESULT_INVALID; } object->Acquire(); - return RESULT_SUCCESS.raw; + return RESULT_SUCCESS; } /// 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; int handle_index = 0; // Check if 'handles' is invalid 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 // 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 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 // necessary @@ -169,7 +177,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); if (object == nullptr) - return InvalidHandle(ErrorModule::Kernel).raw; + return ERR_INVALID_HANDLE; // Check if the current thread should wait on this object... if (object->ShouldWait()) { @@ -213,7 +221,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, HLE::Reschedule(__func__); // 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... @@ -235,22 +243,32 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, // not seem to set it to any meaningful value. *out = wait_all ? 0 : handle_index; - return RESULT_SUCCESS.raw; + return RESULT_SUCCESS; } /// Create an address arbiter (to allocate access to shared resources) -static Result CreateAddressArbiter(u32* arbiter) { - Handle handle = Kernel::CreateAddressArbiter(); - *arbiter = handle; - return 0; +static ResultCode CreateAddressArbiter(Handle* out_handle) { + using Kernel::AddressArbiter; + + CASCADE_RESULT(SharedPtr 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 -static Result ArbitrateAddress(Handle arbiter, 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, +static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { + using Kernel::AddressArbiter; + + LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, address, type, value); - return Kernel::ArbitrateAddress(arbiter, static_cast(type), - address, value, nanoseconds).raw; + + SharedPtr arbiter = Kernel::g_handle_table.Get(handle); + if (arbiter == nullptr) + return ERR_INVALID_HANDLE; + + return arbiter->ArbitrateAddress(static_cast(type), + address, value, nanoseconds); } /// 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 -static Result GetResourceLimit(Handle* resource_limit, Handle process) { +static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) { // With regards to proceess values: // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for // the current KThread. *resource_limit = 0xDEADBEEF; LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); - return 0; + return RESULT_SUCCESS; } /// 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) { LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", resource_limit, names, name_count); 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 -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; 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); } - ResultVal> thread_res = Kernel::Thread::Create( - name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE); - if (thread_res.Failed()) - return thread_res.Code().raw; - SharedPtr thread = std::move(*thread_res); - - // TODO(yuriks): Create new handle instead of using built-in - Core::g_app_core->SetReg(1, thread->GetHandle()); + CASCADE_RESULT(SharedPtr thread, Kernel::Thread::Create( + name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE)); + CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); 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, - 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) { LOG_WARNING(Kernel_SVC, "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling"); } - return 0; + return RESULT_SUCCESS; } /// Called when a thread exits @@ -319,128 +332,192 @@ static void ExitThread() { } /// Gets the priority for the specified thread -static Result GetThreadPriority(s32* priority, Handle handle) { +static ResultCode GetThreadPriority(s32* priority, Handle handle) { const SharedPtr thread = Kernel::g_handle_table.Get(handle); if (thread == nullptr) - return InvalidHandle(ErrorModule::Kernel).raw; + return ERR_INVALID_HANDLE; *priority = thread->GetPriority(); - return RESULT_SUCCESS.raw; + return RESULT_SUCCESS; } /// Sets the priority for the specified thread -static Result SetThreadPriority(Handle handle, s32 priority) { +static ResultCode SetThreadPriority(Handle handle, s32 priority) { SharedPtr thread = Kernel::g_handle_table.Get(handle); if (thread == nullptr) - return InvalidHandle(ErrorModule::Kernel).raw; + return ERR_INVALID_HANDLE; thread->SetPriority(priority); - return RESULT_SUCCESS.raw; + return RESULT_SUCCESS; } /// Create a mutex -static Result CreateMutex(Handle* mutex, u32 initial_locked) { - *mutex = Kernel::CreateMutex((initial_locked != 0)); +static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { + using Kernel::Mutex; + + CASCADE_RESULT(SharedPtr 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", - initial_locked ? "true" : "false", *mutex); - return 0; + initial_locked ? "true" : "false", *out_handle); + return RESULT_SUCCESS; } /// 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); - ResultCode res = Kernel::ReleaseMutex(handle); - return res.raw; + + SharedPtr mutex = Kernel::g_handle_table.Get(handle); + if (mutex == nullptr) + return ERR_INVALID_HANDLE; + + mutex->Release(); + return RESULT_SUCCESS; } /// 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); const SharedPtr thread = Kernel::g_handle_table.Get(handle); if (thread == nullptr) - return InvalidHandle(ErrorModule::Kernel).raw; + return ERR_INVALID_HANDLE; *thread_id = thread->GetThreadId(); - return RESULT_SUCCESS.raw; + return RESULT_SUCCESS; } /// Creates a semaphore -static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) { - ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count); +static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { + using Kernel::Semaphore; + + CASCADE_RESULT(SharedPtr 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", - initial_count, max_count, *semaphore); - return res.raw; + initial_count, max_count, *out_handle); + return RESULT_SUCCESS; } /// Releases a certain number of slots in a semaphore -static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) { - LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore); - ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count); - return res.raw; +static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { + using Kernel::Semaphore; + + LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle); + + SharedPtr semaphore = Kernel::g_handle_table.Get(handle); + if (semaphore == nullptr) + return ERR_INVALID_HANDLE; + + CASCADE_RESULT(*count, semaphore->Release(release_count)); + return RESULT_SUCCESS; } /// 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); - return 0; + return RESULT_SUCCESS; } /// Create an event -static Result CreateEvent(Handle* evt, u32 reset_type) { - *evt = Kernel::CreateEvent((ResetType)reset_type); +static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { + CASCADE_RESULT(auto evt, Kernel::Event::Create(static_cast(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", - reset_type, *evt); - return 0; + reset_type, *out_handle); + return RESULT_SUCCESS; } /// Duplicates a kernel handle -static Result DuplicateHandle(Handle* out, Handle handle) { +static ResultCode DuplicateHandle(Handle* out, Handle handle) { ResultVal out_h = Kernel::g_handle_table.Duplicate(handle); if (out_h.Succeeded()) { *out = *out_h; LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); } - return out_h.Code().raw; + return out_h.Code(); } /// Signals an event -static Result SignalEvent(Handle evt) { - LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); +static ResultCode SignalEvent(Handle handle) { + LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); + + auto evt = Kernel::g_handle_table.Get(handle); + if (evt == nullptr) + return ERR_INVALID_HANDLE; + + evt->Signal(); HLE::Reschedule(__func__); - return Kernel::SignalEvent(evt).raw; + return RESULT_SUCCESS; } /// Clears an event -static Result ClearEvent(Handle evt) { - LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt); - return Kernel::ClearEvent(evt).raw; +static ResultCode ClearEvent(Handle handle) { + LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); + + auto evt = Kernel::g_handle_table.Get(handle); + if (evt == nullptr) + return ERR_INVALID_HANDLE; + + evt->Clear(); + return RESULT_SUCCESS; } /// Creates a timer -static Result CreateTimer(Handle* handle, u32 reset_type) { - ResultCode res = Kernel::CreateTimer(handle, static_cast(reset_type)); +static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { + using Kernel::Timer; + + CASCADE_RESULT(auto timer, Timer::Create(static_cast(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", - reset_type, *handle); - return res.raw; + reset_type, *out_handle); + return RESULT_SUCCESS; } /// 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); - return Kernel::ClearTimer(handle).raw; + + SharedPtr timer = Kernel::g_handle_table.Get(handle); + if (timer == nullptr) + return ERR_INVALID_HANDLE; + + timer->Clear(); + return RESULT_SUCCESS; } /// 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); - return Kernel::SetTimer(handle, initial, interval).raw; + + SharedPtr timer = Kernel::g_handle_table.Get(handle); + if (timer == nullptr) + return ERR_INVALID_HANDLE; + + timer->Set(initial, interval); + return RESULT_SUCCESS; } /// 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); - return Kernel::CancelTimer(handle).raw; + + SharedPtr timer = Kernel::g_handle_table.Get(handle); + if (timer == nullptr) + return ERR_INVALID_HANDLE; + + timer->Cancel(); + return RESULT_SUCCESS; } /// 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 -static Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 my_permission, - u32 other_permission) { - +static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, + u32 other_permission) { + using Kernel::SharedMemory; // TODO(Subv): Implement this function - Handle shared_memory = Kernel::CreateSharedMemory(); - *memblock = shared_memory; + CASCADE_RESULT(auto shared_memory, SharedMemory::Create()); + CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); + LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); - return 0; + return RESULT_SUCCESS; } const HLE::FunctionDef SVC_Table[] = { diff --git a/src/core/mem_map.h b/src/core/mem_map.h index fad40ae0ce..8f4f21fecf 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -7,12 +7,9 @@ #include "common/common.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 -// 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. +namespace Memory { //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -190,7 +187,3 @@ VAddr PhysicalToVirtualAddress(PAddr addr); PAddr VirtualToPhysicalAddress(VAddr addr); } // namespace - -// These are used often, so re-export then on the root namespace -using Memory::VAddr; -using Memory::PAddr;