From 0c7827104f9cebbdf164f7cec551342b75eb1f49 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 14 Oct 2019 09:20:21 -0700 Subject: [PATCH] hipc: begin implementing domains. fixes ro + sm together --- .../sf/cmif/sf_cmif_domain_api.hpp | 2 +- .../sf/cmif/sf_cmif_domain_manager.hpp | 122 +++++++++++++ .../sf/cmif/sf_cmif_domain_service_object.hpp | 74 ++++++++ .../sf_hipc_server_domain_session_manager.hpp | 33 ++++ .../sf/hipc/sf_hipc_server_manager.hpp | 60 ++++++- .../hipc/sf_hipc_server_session_manager.hpp | 20 ++- .../source/sf/cmif/sf_cmif_domain_manager.cpp | 161 ++++++++++++++++++ .../sf/cmif/sf_cmif_service_dispatch.cpp | 4 +- .../sf_hipc_server_domain_session_manager.cpp | 95 +++++++++++ .../ro/source/impl/ro_service_impl.cpp | 3 +- 10 files changed, 557 insertions(+), 17 deletions(-) create mode 100644 stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp create mode 100644 stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp create mode 100644 stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp create mode 100644 stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp index f09993d05..d45e66c87 100644 --- a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp @@ -26,7 +26,7 @@ namespace sts::sf::cmif { constexpr void SetValue(u32 new_value) { this->value = new_value; } }; - static_assert(std::is_trivial::value, "DomainObjectId"); + static_assert(std::is_trivial::value && sizeof(DomainObjectId) == sizeof(u32), "DomainObjectId"); inline constexpr bool operator==(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value == rhs.value; diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp new file mode 100644 index 000000000..85a6e008e --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" +#include "sf_cmif_domain_api.hpp" +#include "sf_cmif_domain_service_object.hpp" + +namespace sts::sf::cmif { + + class ServerDomainManager { + NON_COPYABLE(ServerDomainManager); + NON_MOVEABLE(ServerDomainManager); + private: + class Domain; + + struct Entry { + NON_COPYABLE(Entry); + NON_MOVEABLE(Entry); + + util::IntrusiveListNode free_list_node; + util::IntrusiveListNode domain_list_node; + Domain *owner; + ServiceObjectHolder object; + + explicit Entry() : owner(nullptr) { /* ... */ } + }; + + class Domain final : public DomainServiceObject { + NON_COPYABLE(Domain); + NON_MOVEABLE(Domain); + private: + using EntryList = typename util::IntrusiveListMemberTraits<&Entry::domain_list_node>::ListType; + private: + ServerDomainManager *manager; + EntryList entries; + public: + explicit Domain(ServerDomainManager *m) : manager(m) { /* ... */ } + ~Domain(); + + virtual ServerDomainBase *GetServerDomain() override final { + return static_cast(this); + } + + virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) override final; + virtual Result AlterReservedIds(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) override final; + virtual void UnreserveIds(const DomainObjectId *ids, size_t count) override final; + virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) override final; + + virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) override final; + virtual ServiceObjectHolder GetObject(DomainObjectId id) override final; + }; + public: + using DomainEntryStorage = TYPED_STORAGE(Entry); + using DomainStorage = TYPED_STORAGE(Domain); + private: + class EntryManager { + private: + using EntryList = typename util::IntrusiveListMemberTraits<&Entry::free_list_node>::ListType; + private: + os::Mutex lock; + EntryList free_list; + Entry *entries; + size_t num_entries; + public: + EntryManager(DomainEntryStorage *entry_storage, size_t entry_count); + ~EntryManager(); + Entry *AllocateEntry(); + void FreeEntry(Entry *); + + void ReallocateEntries(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count); + + inline DomainObjectId GetId(Entry *e) { + const size_t index = e - this->entries; + STS_ASSERT(index < this->num_entries); + return DomainObjectId{ u32(index + 1) }; + } + + inline Entry *GetEntry(DomainObjectId id) { + if (id == InvalidDomainObjectId) { + return nullptr; + } + const size_t index = id.value - 1; + if (!(index < this->num_entries)) { + return nullptr; + } + return this->entries + index; + } + }; + private: + os::Mutex entry_owner_lock; + EntryManager entry_manager; + private: + virtual void *AllocateDomain() = 0; + virtual void FreeDomain(void *) = 0; + protected: + ServerDomainManager(DomainEntryStorage *entry_storage, size_t entry_count) : entry_manager(entry_storage, entry_count) { /* ... */ } + + inline DomainServiceObject *AllocateDomainServiceObject() { + void *storage = this->AllocateDomain(); + if (storage == nullptr) { + return nullptr; + } + return new (storage) Domain(this); + } + }; + + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp new file mode 100644 index 000000000..2de93fb87 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "sf_cmif_service_dispatch.hpp" +#include "sf_cmif_domain_api.hpp" +#include "sf_cmif_server_message_processor.hpp" + +namespace sts::sf::cmif { + + class DomainServiceObjectDispatchTable : public impl::ServiceDispatchTableBase { + private: + Result ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const; + public: + Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; + }; + + + class DomainServiceObjectProcessor : public ServerMessageProcessor { + private: + ServerMessageProcessor *impl_processor; + ServerDomainBase *domain; + public: + /* Used to enabled templated message processors. */ + virtual void SetImplementationProcessor(ServerMessageProcessor *impl) override final { + if (this->impl_processor == nullptr) { + this->impl_processor = impl; + } else { + this->impl_processor->SetImplementationProcessor(impl); + } + } + + virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const size_t headers_size) const override final; + virtual Result GetInObjects(ServiceObjectHolder *in_objects) const override final; + virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size, size_t &num_out_object_handles) override final; + virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size) override final; + virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) override final; + }; + + class DomainServiceObject : public IServiceObject, public ServerDomainBase { + public: + static constexpr inline DomainServiceObjectDispatchTable s_CmifServiceDispatchTable{}; + private: + virtual ServerDomainBase *GetServerDomain() = 0; + public: + /* TODO: Implement to use domain object processor. */ + }; + + template<> + struct ServiceDispatchTraits { + static_assert(std::is_base_of::value, "DomainServiceObject must derive from sf::IServiceObject"); + static_assert(!std::is_base_of::value, "DomainServiceObject must not derive from sf::IMitmServiceObject"); + using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); + + using DispatchTableType = DomainServiceObjectDispatchTable; + static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessage; + + static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl}; + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp new file mode 100644 index 000000000..f21f941ff --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "sf_hipc_server_session_manager.hpp" +#include "../cmif/sf_cmif_domain_manager.hpp" + +namespace sts::sf::hipc { + + class ServerDomainSessionManager : public ServerSessionManager, private cmif::ServerDomainManager { + protected: + using cmif::ServerDomainManager::DomainEntryStorage; + using cmif::ServerDomainManager::DomainStorage; + protected: + virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) override final; + public: + ServerDomainSessionManager(DomainEntryStorage *entry_storage, size_t entry_count) : ServerDomainManager(entry_storage, entry_count) { /* ... */ } + }; + +} diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp index 0d964069e..c0b818a40 100644 --- a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp @@ -15,7 +15,7 @@ */ #pragma once -#include "sf_hipc_server_session_manager.hpp" +#include "sf_hipc_server_domain_session_manager.hpp" namespace sts::sf::hipc { @@ -31,7 +31,7 @@ namespace sts::sf::hipc { template class ServerManager; - class ServerManagerBase : public ServerSessionManager { + class ServerManagerBase : public ServerDomainSessionManager { NON_COPYABLE(ServerManagerBase); NON_MOVEABLE(ServerManagerBase); private: @@ -40,6 +40,9 @@ namespace sts::sf::hipc { Session = 2, MitmServer = 3, }; + protected: + using ServerDomainSessionManager::DomainEntryStorage; + using ServerDomainSessionManager::DomainStorage; private: class ServerBase : public os::WaitableHolder { friend class ServerManagerBase; @@ -165,9 +168,10 @@ namespace sts::sf::hipc { virtual ServerBase *AllocateServer() = 0; virtual void DestroyServer(ServerBase *server) = 0; public: - ServerManagerBase() : ServerSessionManager(), - request_stop_event(false), request_stop_event_holder(&request_stop_event), - notify_event(false), notify_event_holder(¬ify_event) + ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count) : + ServerDomainSessionManager(entry_storage, entry_count), + request_stop_event(false), request_stop_event_holder(&request_stop_event), + notify_event(false), notify_event_holder(¬ify_event) { /* Link waitables. */ this->waitable_manager.LinkWaitableHolder(&this->request_stop_event_holder); @@ -221,6 +225,18 @@ namespace sts::sf::hipc { static_assert(MaxServers <= ServerSessionCountMax, "MaxServers can never be larger than ServerSessionCountMax (0x40)."); static_assert(MaxSessions <= ServerSessionCountMax, "MaxSessions can never be larger than ServerSessionCountMax (0x40)."); static_assert(MaxServers + MaxSessions <= ServerSessionCountMax, "MaxServers + MaxSessions can never be larger than ServerSessionCountMax (0x40)."); + private: + static constexpr inline bool DomainCountsValid = [] { + if constexpr (ManagerOptions::MaxDomains > 0) { + return ManagerOptions::MaxDomainObjects > 0; + } else { + return ManagerOptions::MaxDomainObjects == 0; + } + }(); + static_assert(DomainCountsValid, "Invalid Domain Counts"); + protected: + using ServerManagerBase::DomainEntryStorage; + using ServerManagerBase::DomainStorage; private: /* Resource storage. */ os::Mutex resource_mutex; @@ -233,7 +249,10 @@ namespace sts::sf::hipc { uintptr_t pointer_buffers_start; uintptr_t saved_messages_start; - /* TODO: Domain resources. */ + /* Domain resources. */ + DomainStorage domain_storages[ManagerOptions::MaxDomains]; + bool domain_allocated[ManagerOptions::MaxDomains]; + DomainEntryStorage domain_entry_storages[ManagerOptions::MaxDomainObjects]; private: constexpr inline size_t GetServerIndex(const ServerBase *server) const { const size_t i = server - GetPointer(this->server_storages[0]); @@ -288,6 +307,26 @@ namespace sts::sf::hipc { this->server_allocated[index] = false; } + virtual void *AllocateDomain() override final { + std::scoped_lock lk(this->resource_mutex); + for (size_t i = 0; i < ManagerOptions::MaxDomains; i++) { + if (!this->domain_allocated[i]) { + this->domain_allocated[i] = true; + return GetPointer(this->domain_storages[i]); + } + } + return nullptr; + } + + virtual void FreeDomain(void *domain) override final { + std::scoped_lock lk(this->resource_mutex); + DomainStorage *ptr = static_cast(domain); + const size_t index = ptr - this->domain_storages; + STS_ASSERT(index < ManagerOptions::MaxDomains); + STS_ASSERT(this->domain_allocated[index]); + this->domain_allocated[index] = false; + } + virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const override final { if constexpr (ManagerOptions::PointerBufferSize > 0) { return this->GetObjectBySessionIndex(session, this->pointer_buffers_start, ManagerOptions::PointerBufferSize); @@ -300,7 +339,7 @@ namespace sts::sf::hipc { return this->GetObjectBySessionIndex(session, this->saved_messages_start, hipc::TlsMessageBufferSize); } public: - ServerManager() : ServerManagerBase() { + ServerManager() : ServerManagerBase(this->domain_entry_storages, ManagerOptions::MaxDomainObjects) { /* Clear storages. */ std::memset(this->server_storages, 0, sizeof(this->server_storages)); std::memset(this->server_allocated, 0, sizeof(this->server_allocated)); @@ -308,6 +347,13 @@ namespace sts::sf::hipc { std::memset(this->session_allocated, 0, sizeof(this->session_allocated)); std::memset(this->pointer_buffer_storage, 0, sizeof(this->pointer_buffer_storage)); std::memset(this->saved_message_storage, 0, sizeof(this->saved_message_storage)); + if constexpr (ManagerOptions::MaxDomains > 0) { + std::memset(this->domain_storages, 0, sizeof(this->domain_storages)); + std::memset(this->domain_allocated, 0, sizeof(this->domain_allocated)); + } + if constexpr (ManagerOptions::MaxDomainObjects > 0) { + std::memset(this->domain_entry_storages, 0, sizeof(this->domain_entry_storages)); + } /* Set resource starts. */ this->pointer_buffers_start = util::AlignUp(reinterpret_cast(this->pointer_buffer_storage), 0x10); diff --git a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp index 37e82c592..1be5e91a2 100644 --- a/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp @@ -26,9 +26,16 @@ namespace sts::sf::hipc { class ServerSessionManager; class ServerManagerBase; + namespace impl { + + class HipcManager; + + } + class ServerSession : public os::WaitableHolder { friend class ServerSessionManager; friend class ServerManagerBase; + friend class impl::HipcManager; NON_COPYABLE(ServerSession); NON_MOVEABLE(ServerSession); private: @@ -83,9 +90,10 @@ namespace sts::sf::hipc { void DestroySession(ServerSession *session); Result ProcessRequestImpl(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); + virtual void RegisterSessionToWaitList(ServerSession *session) = 0; + protected: Result DispatchRequest(cmif::ServiceObjectHolder &&obj, ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); - virtual void RegisterSessionToWaitList(ServerSession *session) = 0; protected: virtual ServerSession *AllocateSession() = 0; virtual void FreeSession(ServerSession *session) = 0; @@ -130,11 +138,6 @@ namespace sts::sf::hipc { }; return this->CreateSessionImpl(out, ctor); } - - virtual ServerSessionManager *GetSessionManagerByTag(u32 tag) { - /* This is unused. */ - return this; - } public: Result RegisterSession(Handle session_handle, cmif::ServiceObjectHolder &&obj); Result AcceptSession(Handle port_handle, cmif::ServiceObjectHolder &&obj); @@ -152,6 +155,11 @@ namespace sts::sf::hipc { } Result ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message); + + virtual ServerSessionManager *GetSessionManagerByTag(u32 tag) { + /* This is unused. */ + return this; + } }; } diff --git a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp new file mode 100644 index 000000000..f59d00424 --- /dev/null +++ b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace sts::sf::cmif { + + ServerDomainManager::Domain::~Domain() { + while (!this->entries.empty()) { + Entry *entry = &this->entries.front(); + { + std::scoped_lock lk(this->manager->entry_owner_lock); + STS_ASSERT(entry->owner == this); + entry->owner = nullptr; + } + entry->object.Reset(); + this->entries.pop_front(); + this->manager->entry_manager.FreeEntry(entry); + } + } + + Result ServerDomainManager::Domain::ReserveIds(DomainObjectId *out_ids, size_t count) { + for (size_t i = 0; i < count; i++) { + Entry *entry = this->manager->entry_manager.AllocateEntry(); + R_UNLESS(entry != nullptr, ResultServiceFrameworkOutOfDomainEntries); + STS_ASSERT(entry->owner == nullptr); + out_ids[i] = this->manager->entry_manager.GetId(entry); + } + return ResultSuccess; + } + + Result ServerDomainManager::Domain::AlterReservedIds(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) { + this->manager->entry_manager.ReallocateEntries(old_reserved_ids, new_reserved_ids, count); + return ResultSuccess; + } + + void ServerDomainManager::Domain::UnreserveIds(const DomainObjectId *ids, size_t count) { + for (size_t i = 0; i < count; i++) { + Entry *entry = this->manager->entry_manager.GetEntry(ids[i]); + STS_ASSERT(entry != nullptr); + STS_ASSERT(entry->owner == nullptr); + this->manager->entry_manager.FreeEntry(entry); + } + } + + void ServerDomainManager::Domain::RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) { + Entry *entry = this->manager->entry_manager.GetEntry(id); + STS_ASSERT(entry != nullptr); + { + std::scoped_lock lk(this->manager->entry_owner_lock); + STS_ASSERT(entry->owner == nullptr); + entry->owner = this; + this->entries.push_back(*entry); + } + entry->object = std::move(obj); + } + + ServiceObjectHolder ServerDomainManager::Domain::UnregisterObject(DomainObjectId id) { + ServiceObjectHolder obj; + Entry *entry = this->manager->entry_manager.GetEntry(id); + if (entry == nullptr) { + return ServiceObjectHolder(); + } + { + std::scoped_lock lk(this->manager->entry_owner_lock); + if (entry->owner != this) { + return ServiceObjectHolder(); + } + entry->owner = nullptr; + obj = std::move(entry->object); + this->entries.erase(this->entries.iterator_to(*entry)); + } + this->manager->entry_manager.FreeEntry(entry); + return obj; + } + + ServiceObjectHolder ServerDomainManager::Domain::GetObject(DomainObjectId id) { + Entry *entry = this->manager->entry_manager.GetEntry(id); + if (entry == nullptr) { + return ServiceObjectHolder(); + } + { + std::scoped_lock lk(this->manager->entry_owner_lock); + if (entry->owner != this) { + return ServiceObjectHolder(); + } + } + return entry->object.Clone(); + } + + ServerDomainManager::EntryManager::EntryManager(DomainEntryStorage *entry_storage, size_t entry_count) { + this->entries = reinterpret_cast(entry_storage); + this->num_entries = entry_count; + for (size_t i = 0; i < this->num_entries; i++) { + Entry *entry = new (this->entries + i) Entry(); + this->free_list.push_back(*entry); + } + } + + ServerDomainManager::EntryManager::~EntryManager() { + for (size_t i = 0; i < this->num_entries; i++) { + this->entries[i].~Entry(); + } + } + + ServerDomainManager::Entry *ServerDomainManager::EntryManager::AllocateEntry() { + std::scoped_lock lk(this->lock); + if (this->free_list.empty()) { + return nullptr; + } + Entry *e = &this->free_list.front(); + this->free_list.pop_front(); + return e; + } + + void ServerDomainManager::EntryManager::FreeEntry(Entry *entry) { + std::scoped_lock lk(this->lock); + STS_ASSERT(entry->owner == nullptr); + STS_ASSERT(!entry->object); + this->free_list.push_front(*entry); + } + + void ServerDomainManager::EntryManager::ReallocateEntries(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_ids, size_t count) { + std::scoped_lock lk(this->lock); + + /* Free old ids. */ + for (size_t i = 0; i < count; i++) { + const auto id = old_reserved_ids[i]; + Entry *entry = this->GetEntry(id); + if (id != InvalidDomainObjectId) { + STS_ASSERT(entry != nullptr); + STS_ASSERT(entry->owner == nullptr); + STS_ASSERT(!entry->object); + this->free_list.push_front(*entry); + } + } + + /* Allocate new IDs. */ + for (size_t i = 0; i < count; i++) { + const auto id = old_reserved_ids[i]; + Entry *entry = this->GetEntry(id); + if (id != InvalidDomainObjectId) { + STS_ASSERT(entry != nullptr); + this->free_list.erase(this->free_list.iterator_to(*entry)); + } + } + } + +} diff --git a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp index 6ddfdc1e8..62b6c09f2 100644 --- a/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp +++ b/stratosphere/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp @@ -40,7 +40,7 @@ namespace sts::sf::cmif { /* Invoke handler. */ CmifOutHeader *out_header = nullptr; - Result command_result = cmd_handler(&out_header, ctx, cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*out_header), in_raw_data.GetSize() - sizeof(*out_header))); + Result command_result = cmd_handler(&out_header, ctx, cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header))); /* Forward forwardable results, otherwise ensure we can send result to user. */ R_TRY_CATCH(command_result) { @@ -84,7 +84,7 @@ namespace sts::sf::cmif { /* Invoke handler. */ CmifOutHeader *out_header = nullptr; - Result command_result = cmd_handler(&out_header, ctx, cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*out_header), in_raw_data.GetSize() - sizeof(*out_header))); + Result command_result = cmd_handler(&out_header, ctx, cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header))); /* Forward forwardable results, otherwise ensure we can send result to user. */ R_TRY_CATCH(command_result) { diff --git a/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp b/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp new file mode 100644 index 000000000..fd2d8a6a0 --- /dev/null +++ b/stratosphere/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace sts::sf::hipc { + + namespace impl { + + class HipcManager : public IServiceObject { + private: + enum class CommandId { + ConvertCurrentObjectToDomain = 0, + CopyFromCurrentDomain = 1, + CloneCurrentObject = 2, + QueryPointerBufferSize = 3, + CloneCurrentObjectEx = 4, + }; + private: + ServerDomainSessionManager *manager; + ServerSession *session; + bool is_mitm_session; + private: + Result CloneCurrentObjectImpl(Handle *out_client_handle, ServerSessionManager *tagged_manager) { + /* Clone the object. */ + cmif::ServiceObjectHolder &&clone = this->session->srv_obj_holder.Clone(); + R_UNLESS(clone, ResultHipcDomainObjectNotFound); + + /* Create new session handles. */ + Handle server_handle; + R_ASSERT(hipc::CreateSession(&server_handle, out_client_handle)); + + /* Register with manager. */ + if (!is_mitm_session) { + R_ASSERT(tagged_manager->RegisterSession(server_handle, std::move(clone))); + } else { + std::shared_ptr<::Service> forward_service = this->session->forward_service; + R_ASSERT(tagged_manager->RegisterMitmSession(server_handle, std::move(clone), std::move(forward_service))); + } + + return ResultSuccess; + } + public: + explicit HipcManager(ServerDomainSessionManager *m, ServerSession *s) : manager(m), session(s), is_mitm_session(s->forward_service != nullptr) { + /* ... */ + } + + /* TODO: ConvertCurrentObjectToDomain */ + /* TODO: CopyFromCurrentDomain */ + + Result CloneCurrentObject(sf::OutMoveHandle out) { + return this->CloneCurrentObjectImpl(out.GetHandlePointer(), this->manager); + } + + void QueryPointerBufferSize(sf::Out out) { + out.SetValue(this->session->pointer_buffer.GetSize()); + } + + Result CloneCurrentObjectEx(sf::OutMoveHandle out, u32 tag) { + return this->CloneCurrentObjectImpl(out.GetHandlePointer(), this->manager->GetSessionManagerByTag(tag)); + } + + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* TODO: MAKE_SERVICE_COMMAND_META(ConvertCurrentObjectToDomain), */ + /* TODO: MAKE_SERVICE_COMMAND_META(CopyFromCurrentDomain), */ + MAKE_SERVICE_COMMAND_META(CloneCurrentObject), + MAKE_SERVICE_COMMAND_META(QueryPointerBufferSize), + MAKE_SERVICE_COMMAND_META(CloneCurrentObjectEx), + }; + }; + + } + + Result ServerDomainSessionManager::DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) { + /* Make a stack object, and pass a shared pointer to it to DispatchRequest. */ + /* Note: This is safe, as no additional references to the hipc manager can ever be stored. */ + /* The shared pointer to stack object is definitely gross, though. */ + impl::HipcManager hipc_manager(this, session); + return this->DispatchRequest(cmif::ServiceObjectHolder(std::shared_ptr(&hipc_manager, [](impl::HipcManager *) { /* Empty deleter. */ })), session, in_message, out_message); + } + +} diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index 57365ad31..cbcb080e3 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -318,7 +318,8 @@ namespace sts::ro::impl { bool ShouldEaseNroRestriction() { /* Retrieve whether we should ease restrictions from set:sys. */ bool should_ease = false; - if (R_FAILED(setsysGetSettingsItemValue("ro", "ease_nro_restriction", &should_ease, sizeof(should_ease)))) { + u64 size_out; + if (R_FAILED(setsysGetSettingsItemValue("ro", "ease_nro_restriction", &should_ease, sizeof(should_ease), &size_out))) { return false; }