mirror of
https://github.com/yuzu-emu/yuzu-mainline.git
synced 2024-12-25 08:05:34 +00:00
Merge pull request #503 from yuriks/kernel-lifetime4
Kernel Lifetime Reform Pt. 4
This commit is contained in:
commit
28702cbfeb
|
@ -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…
Reference in a new issue