git subrepo clone https://github.com/Atmosphere-NX/Atmosphere-libs libraries
subrepo: subdir: "libraries" merged: "07af583b" upstream: origin: "https://github.com/Atmosphere-NX/Atmosphere-libs" branch: "master" commit: "07af583b" git-subrepo: version: "0.4.0" origin: "https://github.com/ingydotnet/git-subrepo" commit: "5d6aba9"
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_common.hpp"
|
||||
#include "sf_cmif_service_object_holder.hpp"
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
struct DomainObjectId {
|
||||
u32 value;
|
||||
|
||||
constexpr void SetValue(u32 new_value) { this->value = new_value; }
|
||||
};
|
||||
|
||||
static_assert(std::is_trivial<DomainObjectId>::value && sizeof(DomainObjectId) == sizeof(u32), "DomainObjectId");
|
||||
|
||||
inline constexpr bool operator==(const DomainObjectId &lhs, const DomainObjectId &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator!=(const DomainObjectId &lhs, const DomainObjectId &rhs) {
|
||||
return lhs.value != rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator<(const DomainObjectId &lhs, const DomainObjectId &rhs) {
|
||||
return lhs.value < rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator<=(const DomainObjectId &lhs, const DomainObjectId &rhs) {
|
||||
return lhs.value <= rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator>(const DomainObjectId &lhs, const DomainObjectId &rhs) {
|
||||
return lhs.value > rhs.value;
|
||||
}
|
||||
|
||||
inline constexpr bool operator>=(const DomainObjectId &lhs, const DomainObjectId &rhs) {
|
||||
return lhs.value >= rhs.value;
|
||||
}
|
||||
|
||||
constexpr inline const DomainObjectId InvalidDomainObjectId = { .value = 0 };
|
||||
|
||||
class ServerDomainBase {
|
||||
public:
|
||||
virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) = 0;
|
||||
virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) = 0;
|
||||
virtual void UnreserveIds(const DomainObjectId *ids, size_t count) = 0;
|
||||
virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) = 0;
|
||||
|
||||
virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) = 0;
|
||||
virtual ServiceObjectHolder GetObject(DomainObjectId id) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_common.hpp"
|
||||
#include "sf_cmif_domain_api.hpp"
|
||||
#include "sf_cmif_domain_service_object.hpp"
|
||||
|
||||
namespace ams::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();
|
||||
|
||||
void DestroySelf();
|
||||
|
||||
virtual ServerDomainBase *GetServerDomain() override final {
|
||||
return static_cast<ServerDomainBase *>(this);
|
||||
}
|
||||
|
||||
virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) override final;
|
||||
virtual void ReserveSpecificIds(const DomainObjectId *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 AllocateSpecificEntries(const DomainObjectId *ids, size_t count);
|
||||
|
||||
inline DomainObjectId GetId(Entry *e) {
|
||||
const size_t index = e - this->entries;
|
||||
AMS_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);
|
||||
}
|
||||
public:
|
||||
static void DestroyDomainServiceObject(DomainServiceObject *obj) {
|
||||
static_cast<Domain *>(obj)->DestroySelf();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_cmif_service_dispatch.hpp"
|
||||
#include "sf_cmif_domain_api.hpp"
|
||||
#include "sf_cmif_server_message_processor.hpp"
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
class DomainServiceObjectDispatchTable : public impl::ServiceDispatchTableBase {
|
||||
private:
|
||||
Result ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const;
|
||||
Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const;
|
||||
public:
|
||||
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const;
|
||||
Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const;
|
||||
};
|
||||
|
||||
|
||||
class DomainServiceObjectProcessor : public ServerMessageProcessor {
|
||||
private:
|
||||
ServerMessageProcessor *impl_processor;
|
||||
ServerDomainBase *domain;
|
||||
DomainObjectId *in_object_ids;
|
||||
DomainObjectId *out_object_ids;
|
||||
size_t num_in_objects;
|
||||
ServerMessageRuntimeMetadata impl_metadata;
|
||||
public:
|
||||
DomainServiceObjectProcessor(ServerDomainBase *d, DomainObjectId *in_obj_ids, size_t num_in_objs) : domain(d), in_object_ids(in_obj_ids), num_in_objects(num_in_objs) {
|
||||
AMS_ASSERT(this->domain != nullptr);
|
||||
AMS_ASSERT(this->in_object_ids != nullptr);
|
||||
this->impl_processor = nullptr;
|
||||
this->out_object_ids = nullptr;
|
||||
this->impl_metadata = {};
|
||||
}
|
||||
|
||||
constexpr size_t GetInObjectCount() const {
|
||||
return this->num_in_objects;
|
||||
}
|
||||
|
||||
constexpr size_t GetOutObjectCount() const {
|
||||
return this->impl_metadata.GetOutObjectCount();
|
||||
}
|
||||
|
||||
constexpr size_t GetImplOutHeadersSize() const {
|
||||
return this->impl_metadata.GetOutHeadersSize();
|
||||
}
|
||||
|
||||
constexpr size_t GetImplOutDataTotalSize() const {
|
||||
return this->impl_metadata.GetOutDataSize() + this->impl_metadata.GetOutHeadersSize();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
this->impl_metadata = this->impl_processor->GetRuntimeMetadata();
|
||||
}
|
||||
|
||||
virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const override final {
|
||||
const auto runtime_metadata = this->impl_processor->GetRuntimeMetadata();
|
||||
|
||||
return ServerMessageRuntimeMetadata {
|
||||
.in_data_size = static_cast<u16>(runtime_metadata.GetInDataSize() + runtime_metadata.GetInObjectCount() * sizeof(DomainObjectId)),
|
||||
.out_data_size = static_cast<u16>(runtime_metadata.GetOutDataSize() + runtime_metadata.GetOutObjectCount() * sizeof(DomainObjectId)),
|
||||
.in_headers_size = static_cast<u8>(runtime_metadata.GetInHeadersSize() + sizeof(CmifDomainInHeader)),
|
||||
.out_headers_size = static_cast<u8>(runtime_metadata.GetOutHeadersSize() + sizeof(CmifDomainOutHeader)),
|
||||
.in_object_count = 0,
|
||||
.out_object_count = 0,
|
||||
};
|
||||
}
|
||||
|
||||
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const override final;
|
||||
virtual Result GetInObjects(ServiceObjectHolder *in_objects) const override final;
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final;
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) 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 {
|
||||
friend class DomainServiceObjectDispatchTable;
|
||||
public:
|
||||
static constexpr inline DomainServiceObjectDispatchTable s_CmifServiceDispatchTable{};
|
||||
private:
|
||||
virtual ServerDomainBase *GetServerDomain() = 0;
|
||||
public:
|
||||
/* TODO: Implement to use domain object processor. */
|
||||
};
|
||||
|
||||
class MitmDomainServiceObject : public DomainServiceObject{};
|
||||
|
||||
static_assert(sizeof(DomainServiceObject) == sizeof(MitmDomainServiceObject));
|
||||
|
||||
template<>
|
||||
struct ServiceDispatchTraits<DomainServiceObject> {
|
||||
static_assert(std::is_base_of<sf::IServiceObject, DomainServiceObject>::value, "DomainServiceObject must derive from sf::IServiceObject");
|
||||
static_assert(!std::is_base_of<sf::IMitmServiceObject, DomainServiceObject>::value, "DomainServiceObject must not derive from sf::IMitmServiceObject");
|
||||
using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler);
|
||||
|
||||
using DispatchTableType = DomainServiceObjectDispatchTable;
|
||||
static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessage<DispatchTableType>;
|
||||
|
||||
static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ServiceDispatchTraits<MitmDomainServiceObject> {
|
||||
static_assert(std::is_base_of<DomainServiceObject, MitmDomainServiceObject>::value, "MitmDomainServiceObject must derive from DomainServiceObject");
|
||||
using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler);
|
||||
|
||||
using DispatchTableType = DomainServiceObjectDispatchTable;
|
||||
static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessageForMitm<DispatchTableType>;
|
||||
|
||||
static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_common.hpp"
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
class PointerAndSize {
|
||||
private:
|
||||
uintptr_t pointer;
|
||||
size_t size;
|
||||
public:
|
||||
constexpr PointerAndSize() : pointer(0), size(0) { /* ... */ }
|
||||
constexpr PointerAndSize(uintptr_t ptr, size_t sz) : pointer(ptr), size(sz) { /* ... */ }
|
||||
constexpr PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
|
||||
constexpr void *GetPointer() const {
|
||||
return reinterpret_cast<void *>(this->pointer);
|
||||
}
|
||||
|
||||
constexpr uintptr_t GetAddress() const {
|
||||
return this->pointer;
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return this->size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_service_object.hpp"
|
||||
#include "sf_cmif_pointer_and_size.hpp"
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
/* Forward declare ServiceDispatchContext, ServiceObjectHolder. */
|
||||
struct ServiceDispatchContext;
|
||||
class ServiceObjectHolder;
|
||||
struct DomainObjectId;
|
||||
|
||||
/* This is needed for non-templated domain message processing. */
|
||||
struct ServerMessageRuntimeMetadata {
|
||||
u16 in_data_size;
|
||||
u16 out_data_size;
|
||||
u8 in_headers_size;
|
||||
u8 out_headers_size;
|
||||
u8 in_object_count;
|
||||
u8 out_object_count;
|
||||
|
||||
constexpr size_t GetInDataSize() const {
|
||||
return size_t(this->in_data_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetOutDataSize() const {
|
||||
return size_t(this->out_data_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetInHeadersSize() const {
|
||||
return size_t(this->in_headers_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetOutHeadersSize() const {
|
||||
return size_t(this->out_headers_size);
|
||||
}
|
||||
|
||||
constexpr size_t GetInObjectCount() const {
|
||||
return size_t(this->in_object_count);
|
||||
}
|
||||
|
||||
constexpr size_t GetOutObjectCount() const {
|
||||
return size_t(this->out_object_count);
|
||||
}
|
||||
|
||||
constexpr size_t GetUnfixedOutPointerSizeOffset() const {
|
||||
return this->GetInDataSize() + this->GetInHeadersSize() + 0x10 /* padding. */;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_pod<ServerMessageRuntimeMetadata>::value, "std::is_pod<ServerMessageRuntimeMetadata>::value");
|
||||
static_assert(sizeof(ServerMessageRuntimeMetadata) == sizeof(u64), "sizeof(ServerMessageRuntimeMetadata)");
|
||||
|
||||
class ServerMessageProcessor {
|
||||
public:
|
||||
/* Used to enabled templated message processors. */
|
||||
virtual void SetImplementationProcessor(ServerMessageProcessor *impl) = 0;
|
||||
virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const = 0;
|
||||
|
||||
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const = 0;
|
||||
virtual Result GetInObjects(ServiceObjectHolder *in_objects) const = 0;
|
||||
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0;
|
||||
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0;
|
||||
virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_service_object.hpp"
|
||||
#include "sf_cmif_pointer_and_size.hpp"
|
||||
#include "sf_cmif_server_message_processor.hpp"
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
class ServerSessionManager;
|
||||
class ServerSession;
|
||||
|
||||
}
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
class ServerMessageProcessor;
|
||||
|
||||
struct HandlesToClose {
|
||||
Handle handles[8];
|
||||
size_t num_handles;
|
||||
};
|
||||
|
||||
struct ServiceDispatchContext {
|
||||
sf::IServiceObject *srv_obj;
|
||||
hipc::ServerSessionManager *manager;
|
||||
hipc::ServerSession *session;
|
||||
ServerMessageProcessor *processor;
|
||||
HandlesToClose *handles_to_close;
|
||||
const PointerAndSize pointer_buffer;
|
||||
const PointerAndSize in_message_buffer;
|
||||
const PointerAndSize out_message_buffer;
|
||||
const HipcParsedRequest request;
|
||||
};
|
||||
|
||||
struct ServiceCommandMeta {
|
||||
hos::Version hosver_low;
|
||||
hos::Version hosver_high;
|
||||
u32 cmd_id;
|
||||
Result (*handler)(CmifOutHeader **out_header_ptr, ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data);
|
||||
|
||||
constexpr inline bool Matches(u32 cmd_id, hos::Version hosver) const {
|
||||
return this->cmd_id == cmd_id && this->hosver_low <= hosver && hosver <= this->hosver_high;
|
||||
}
|
||||
|
||||
constexpr inline decltype(handler) GetHandler() const {
|
||||
return this->handler;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<ServiceCommandMeta>::value && sizeof(ServiceCommandMeta) == 0x10, "sizeof(ServiceCommandMeta)");
|
||||
|
||||
namespace impl {
|
||||
|
||||
class ServiceDispatchTableBase {
|
||||
protected:
|
||||
Result ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const;
|
||||
Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const;
|
||||
public:
|
||||
/* CRTP. */
|
||||
template<typename T>
|
||||
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
static_assert(std::is_base_of<ServiceDispatchTableBase, T>::value, "ServiceDispatchTableBase::Process<T>");
|
||||
return static_cast<const T *>(this)->ProcessMessage(ctx, in_raw_data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
static_assert(std::is_base_of<ServiceDispatchTableBase, T>::value, "ServiceDispatchTableBase::ProcessForMitm<T>");
|
||||
return static_cast<const T *>(this)->ProcessMessageForMitm(ctx, in_raw_data);
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t N, class = std::make_index_sequence<N>>
|
||||
class ServiceDispatchTableImpl;
|
||||
|
||||
template<size_t N, size_t... Is>
|
||||
class ServiceDispatchTableImpl<N, std::index_sequence<Is...>> : public ServiceDispatchTableBase {
|
||||
private:
|
||||
template<size_t>
|
||||
using EntryType = ServiceCommandMeta;
|
||||
private:
|
||||
const std::array<ServiceCommandMeta, N> entries;
|
||||
public:
|
||||
explicit constexpr ServiceDispatchTableImpl(EntryType<Is>... args) : entries { args... } { /* ... */ }
|
||||
|
||||
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
return this->ProcessMessageImpl(ctx, in_raw_data, this->entries.data(), this->entries.size());
|
||||
}
|
||||
|
||||
Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
|
||||
return this->ProcessMessageForMitmImpl(ctx, in_raw_data, this->entries.data(), this->entries.size());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename ...Entries>
|
||||
class ServiceDispatchTable : public impl::ServiceDispatchTableImpl<sizeof...(Entries)> {
|
||||
public:
|
||||
explicit constexpr ServiceDispatchTable(Entries... entries) : impl::ServiceDispatchTableImpl<sizeof...(Entries)>(entries...) { /* ... */ }
|
||||
};
|
||||
|
||||
#define DEFINE_SERVICE_DISPATCH_TABLE \
|
||||
template<typename ServiceImpl> \
|
||||
static constexpr inline ::ams::sf::cmif::ServiceDispatchTable s_CmifServiceDispatchTable
|
||||
|
||||
struct ServiceDispatchMeta {
|
||||
const impl::ServiceDispatchTableBase *DispatchTable;
|
||||
Result (impl::ServiceDispatchTableBase::*ProcessHandler)(ServiceDispatchContext &, const cmif::PointerAndSize &) const;
|
||||
|
||||
constexpr uintptr_t GetServiceId() const {
|
||||
return reinterpret_cast<uintptr_t>(this->DispatchTable);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ServiceDispatchTraits {
|
||||
static_assert(std::is_base_of<sf::IServiceObject, T>::value, "ServiceObjects must derive from sf::IServiceObject");
|
||||
|
||||
using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler);
|
||||
|
||||
static constexpr inline auto DispatchTable = T::template s_CmifServiceDispatchTable<T>;
|
||||
using DispatchTableType = decltype(DispatchTable);
|
||||
|
||||
static constexpr ProcessHandlerType ProcessHandlerImpl = ServiceObjectTraits<T>::IsMitmServiceObject ? (&impl::ServiceDispatchTableBase::ProcessMessageForMitm<DispatchTableType>)
|
||||
: (&impl::ServiceDispatchTableBase::ProcessMessage<DispatchTableType>);
|
||||
|
||||
static constexpr inline ServiceDispatchMeta Meta{&DispatchTable, ProcessHandlerImpl};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
NX_CONSTEXPR const ServiceDispatchMeta *GetServiceDispatchMeta() {
|
||||
return &ServiceDispatchTraits<T>::Meta;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_service_object.hpp"
|
||||
#include "sf_cmif_service_dispatch.hpp"
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
class ServiceObjectHolder {
|
||||
private:
|
||||
std::shared_ptr<sf::IServiceObject> srv;
|
||||
const ServiceDispatchMeta *dispatch_meta;
|
||||
private:
|
||||
/* Copy constructor. */
|
||||
ServiceObjectHolder(const ServiceObjectHolder &o) : srv(o.srv), dispatch_meta(o.dispatch_meta) { /* ... */ }
|
||||
ServiceObjectHolder &operator=(const ServiceObjectHolder &o) = delete;
|
||||
public:
|
||||
/* Default constructor, null all members. */
|
||||
ServiceObjectHolder() : srv(nullptr), dispatch_meta(nullptr) { /* ... */ }
|
||||
|
||||
~ServiceObjectHolder() {
|
||||
this->dispatch_meta = nullptr;
|
||||
}
|
||||
|
||||
/* Ensure correct type id at runtime through template constructor. */
|
||||
template<typename ServiceImpl>
|
||||
constexpr explicit ServiceObjectHolder(std::shared_ptr<ServiceImpl> &&s) {
|
||||
this->srv = std::move(s);
|
||||
this->dispatch_meta = GetServiceDispatchMeta<ServiceImpl>();
|
||||
}
|
||||
|
||||
/* Move constructor, assignment operator. */
|
||||
ServiceObjectHolder(ServiceObjectHolder &&o) : srv(std::move(o.srv)), dispatch_meta(std::move(o.dispatch_meta)) {
|
||||
o.dispatch_meta = nullptr;
|
||||
}
|
||||
|
||||
ServiceObjectHolder &operator=(ServiceObjectHolder &&o) {
|
||||
ServiceObjectHolder tmp(std::move(o));
|
||||
tmp.Swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* State management. */
|
||||
void Swap(ServiceObjectHolder &o) {
|
||||
std::swap(this->srv, o.srv);
|
||||
std::swap(this->dispatch_meta, o.dispatch_meta);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
this->srv = nullptr;
|
||||
this->dispatch_meta = nullptr;
|
||||
}
|
||||
|
||||
ServiceObjectHolder Clone() const {
|
||||
return ServiceObjectHolder(*this);
|
||||
}
|
||||
|
||||
/* Boolean operators. */
|
||||
explicit constexpr operator bool() const {
|
||||
return this->dispatch_meta != nullptr;
|
||||
}
|
||||
|
||||
constexpr bool operator!() const {
|
||||
return this->dispatch_meta == nullptr;
|
||||
}
|
||||
|
||||
/* Getters. */
|
||||
constexpr uintptr_t GetServiceId() const {
|
||||
if (this->dispatch_meta) {
|
||||
return this->dispatch_meta->GetServiceId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename ServiceImpl>
|
||||
constexpr inline bool IsServiceObjectValid() const {
|
||||
return this->GetServiceId() == GetServiceDispatchMeta<ServiceImpl>()->GetServiceId();
|
||||
}
|
||||
|
||||
template<typename ServiceImpl>
|
||||
inline std::shared_ptr<ServiceImpl> GetServiceObject() const {
|
||||
if (this->GetServiceId() == GetServiceDispatchMeta<ServiceImpl>()->GetServiceId()) {
|
||||
return std::static_pointer_cast<ServiceImpl>(this->srv);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline sf::IServiceObject *GetServiceObjectUnsafe() const {
|
||||
return this->srv.get();
|
||||
}
|
||||
|
||||
/* Processing. */
|
||||
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_common.hpp"
|
||||
#include "../cmif/sf_cmif_pointer_and_size.hpp"
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
constexpr size_t TlsMessageBufferSize = 0x100;
|
||||
|
||||
enum class ReceiveResult {
|
||||
Success,
|
||||
Closed,
|
||||
NeedsRetry,
|
||||
};
|
||||
|
||||
Result Receive(ReceiveResult *out_recv_result, Handle session_handle, const cmif::PointerAndSize &message_buffer);
|
||||
Result Receive(bool *out_closed, Handle session_handle, const cmif::PointerAndSize &message_buffer);
|
||||
Result Reply(Handle session_handle, const cmif::PointerAndSize &message_buffer);
|
||||
|
||||
Result CreateSession(Handle *out_server_handle, Handle *out_client_handle);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_hipc_server_session_manager.hpp"
|
||||
#include "../cmif/sf_cmif_domain_manager.hpp"
|
||||
|
||||
namespace ams::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) { /* ... */ }
|
||||
|
||||
inline cmif::DomainServiceObject *AllocateDomainServiceObject() {
|
||||
return cmif::ServerDomainManager::AllocateDomainServiceObject();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_hipc_server_domain_session_manager.hpp"
|
||||
#include "../../sm.hpp"
|
||||
|
||||
namespace ams::sf::hipc {
|
||||
|
||||
struct DefaultServerManagerOptions {
|
||||
static constexpr size_t PointerBufferSize = 0;
|
||||
static constexpr size_t MaxDomains = 0;
|
||||
static constexpr size_t MaxDomainObjects = 0;
|
||||
};
|
||||
|
||||
static constexpr size_t ServerSessionCountMax = 0x40;
|
||||
static_assert(ServerSessionCountMax == 0x40, "ServerSessionCountMax isn't 0x40 somehow, this assert is a reminder that this will break lots of things");
|
||||
|
||||
template<size_t, typename, size_t>
|
||||
class ServerManager;
|
||||
|
||||
class ServerManagerBase : public ServerDomainSessionManager {
|
||||
NON_COPYABLE(ServerManagerBase);
|
||||
NON_MOVEABLE(ServerManagerBase);
|
||||
public:
|
||||
using MitmQueryFunction = bool (*)(const sm::MitmProcessInfo &);
|
||||
private:
|
||||
enum class UserDataTag : uintptr_t {
|
||||
Server = 1,
|
||||
Session = 2,
|
||||
MitmServer = 3,
|
||||
};
|
||||
protected:
|
||||
using ServerDomainSessionManager::DomainEntryStorage;
|
||||
using ServerDomainSessionManager::DomainStorage;
|
||||
private:
|
||||
class ServerBase : public os::WaitableHolder {
|
||||
friend class ServerManagerBase;
|
||||
template<size_t, typename, size_t>
|
||||
friend class ServerManager;
|
||||
NON_COPYABLE(ServerBase);
|
||||
NON_MOVEABLE(ServerBase);
|
||||
protected:
|
||||
cmif::ServiceObjectHolder static_object;
|
||||
::Handle port_handle;
|
||||
sm::ServiceName service_name;
|
||||
bool service_managed;
|
||||
public:
|
||||
ServerBase(Handle ph, sm::ServiceName sn, bool m, cmif::ServiceObjectHolder &&sh) :
|
||||
os::WaitableHolder(ph), static_object(std::move(sh)), port_handle(ph), service_name(sn), service_managed(m)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~ServerBase() = 0;
|
||||
virtual void CreateSessionObjectHolder(cmif::ServiceObjectHolder *out_obj, std::shared_ptr<::Service> *out_fsrv) const = 0;
|
||||
};
|
||||
|
||||
template<typename ServiceImpl, auto MakeShared = std::make_shared<ServiceImpl>>
|
||||
class Server : public ServerBase {
|
||||
NON_COPYABLE(Server);
|
||||
NON_MOVEABLE(Server);
|
||||
private:
|
||||
static constexpr bool IsMitmServer = ServiceObjectTraits<ServiceImpl>::IsMitmServiceObject;
|
||||
public:
|
||||
Server(Handle ph, sm::ServiceName sn, bool m, cmif::ServiceObjectHolder &&sh) : ServerBase(ph, sn, m, std::forward<cmif::ServiceObjectHolder>(sh)) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~Server() override {
|
||||
if (this->service_managed) {
|
||||
if constexpr (IsMitmServer) {
|
||||
R_ASSERT(sm::mitm::UninstallMitm(this->service_name));
|
||||
} else {
|
||||
R_ASSERT(sm::UnregisterService(this->service_name));
|
||||
}
|
||||
R_ASSERT(svcCloseHandle(this->port_handle));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void CreateSessionObjectHolder(cmif::ServiceObjectHolder *out_obj, std::shared_ptr<::Service> *out_fsrv) const override final {
|
||||
/* If we're serving a static object, use it. */
|
||||
if (this->static_object) {
|
||||
*out_obj = std::move(this->static_object.Clone());
|
||||
*out_fsrv = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, we're either a mitm session or a non-mitm session. */
|
||||
if constexpr (IsMitmServer) {
|
||||
/* Custom deleter ensures that nothing goes awry. */
|
||||
/* TODO: Should this just be a custom wrapper object? */
|
||||
std::shared_ptr<::Service> forward_service = std::move(ServerSession::CreateForwardService());
|
||||
|
||||
/* Get mitm forward session. */
|
||||
sm::MitmProcessInfo client_info;
|
||||
R_ASSERT(sm::mitm::AcknowledgeSession(forward_service.get(), &client_info, this->service_name));
|
||||
|
||||
*out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared(std::shared_ptr<::Service>(forward_service), client_info))));
|
||||
*out_fsrv = std::move(forward_service);
|
||||
} else {
|
||||
*out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared())));
|
||||
*out_fsrv = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
private:
|
||||
/* Management of waitables. */
|
||||
os::WaitableManager waitable_manager;
|
||||
os::Event request_stop_event;
|
||||
os::WaitableHolder request_stop_event_holder;
|
||||
os::Event notify_event;
|
||||
os::WaitableHolder notify_event_holder;
|
||||
|
||||
os::Mutex waitable_selection_mutex;
|
||||
|
||||
os::Mutex waitlist_mutex;
|
||||
os::WaitableManager waitlist;
|
||||
|
||||
os::Mutex deferred_session_mutex;
|
||||
using DeferredSessionList = typename util::IntrusiveListMemberTraits<&ServerSession::deferred_list_node>::ListType;
|
||||
DeferredSessionList deferred_session_list;
|
||||
private:
|
||||
virtual void RegisterSessionToWaitList(ServerSession *session) override final;
|
||||
void RegisterToWaitList(os::WaitableHolder *holder);
|
||||
void ProcessWaitList();
|
||||
|
||||
bool WaitAndProcessImpl();
|
||||
|
||||
Result ProcessForServer(os::WaitableHolder *holder);
|
||||
Result ProcessForMitmServer(os::WaitableHolder *holder);
|
||||
Result ProcessForSession(os::WaitableHolder *holder);
|
||||
|
||||
void ProcessDeferredSessions();
|
||||
|
||||
template<typename ServiceImpl, auto MakeShared = std::make_shared<ServiceImpl>>
|
||||
void RegisterServerImpl(Handle port_handle, sm::ServiceName service_name, bool managed, cmif::ServiceObjectHolder &&static_holder) {
|
||||
/* Allocate server memory. */
|
||||
auto *server = this->AllocateServer();
|
||||
AMS_ASSERT(server != nullptr);
|
||||
new (server) Server<ServiceImpl, MakeShared>(port_handle, service_name, managed, std::forward<cmif::ServiceObjectHolder>(static_holder));
|
||||
|
||||
if constexpr (!ServiceObjectTraits<ServiceImpl>::IsMitmServiceObject) {
|
||||
/* Non-mitm server. */
|
||||
server->SetUserData(static_cast<uintptr_t>(UserDataTag::Server));
|
||||
} else {
|
||||
/* Mitm server. */
|
||||
server->SetUserData(static_cast<uintptr_t>(UserDataTag::MitmServer));
|
||||
}
|
||||
|
||||
this->waitable_manager.LinkWaitableHolder(server);
|
||||
}
|
||||
|
||||
template<typename ServiceImpl>
|
||||
static constexpr inline std::shared_ptr<ServiceImpl> MakeSharedMitm(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &client_info) {
|
||||
return std::make_shared<ServiceImpl>(std::forward<std::shared_ptr<::Service>>(s), client_info);
|
||||
}
|
||||
|
||||
Result InstallMitmServerImpl(Handle *out_port_handle, sm::ServiceName service_name, MitmQueryFunction query_func);
|
||||
protected:
|
||||
virtual ServerBase *AllocateServer() = 0;
|
||||
virtual void DestroyServer(ServerBase *server) = 0;
|
||||
public:
|
||||
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);
|
||||
this->waitable_manager.LinkWaitableHolder(&this->notify_event_holder);
|
||||
}
|
||||
|
||||
template<typename ServiceImpl, auto MakeShared = std::make_shared<ServiceImpl>>
|
||||
void RegisterServer(Handle port_handle, std::shared_ptr<ServiceImpl> static_object = nullptr) {
|
||||
static_assert(!ServiceObjectTraits<ServiceImpl>::IsMitmServiceObject, "RegisterServer requires non-mitm object. Use RegisterMitmServer instead.");
|
||||
/* Register server. */
|
||||
cmif::ServiceObjectHolder static_holder;
|
||||
if (static_object != nullptr) {
|
||||
static_holder = cmif::ServiceObjectHolder(std::move(static_object));
|
||||
}
|
||||
this->RegisterServerImpl<ServiceImpl, MakeShared>(port_handle, sm::InvalidServiceName, false, std::move(static_holder));
|
||||
}
|
||||
|
||||
template<typename ServiceImpl, auto MakeShared = std::make_shared<ServiceImpl>>
|
||||
Result RegisterServer(sm::ServiceName service_name, size_t max_sessions, std::shared_ptr<ServiceImpl> static_object = nullptr) {
|
||||
static_assert(!ServiceObjectTraits<ServiceImpl>::IsMitmServiceObject, "RegisterServer requires non-mitm object. Use RegisterMitmServer instead.");
|
||||
|
||||
/* Register service. */
|
||||
Handle port_handle;
|
||||
R_TRY(sm::RegisterService(&port_handle, service_name, max_sessions, false));
|
||||
|
||||
/* Register server. */
|
||||
cmif::ServiceObjectHolder static_holder;
|
||||
if (static_object != nullptr) {
|
||||
static_holder = cmif::ServiceObjectHolder(std::move(static_object));
|
||||
}
|
||||
this->RegisterServerImpl<ServiceImpl, MakeShared>(port_handle, service_name, true, std::move(static_holder));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
template<typename ServiceImpl, auto MakeShared = MakeSharedMitm<ServiceImpl>>
|
||||
Result RegisterMitmServer(sm::ServiceName service_name) {
|
||||
static_assert(ServiceObjectTraits<ServiceImpl>::IsMitmServiceObject, "RegisterMitmServer requires mitm object. Use RegisterServer instead.");
|
||||
|
||||
/* Install mitm service. */
|
||||
Handle port_handle;
|
||||
R_TRY(this->InstallMitmServerImpl(&port_handle, service_name, &ServiceImpl::ShouldMitm));
|
||||
|
||||
this->RegisterServerImpl<ServiceImpl, MakeShared>(port_handle, service_name, true, cmif::ServiceObjectHolder());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Processing. */
|
||||
os::WaitableHolder *WaitSignaled();
|
||||
|
||||
void ResumeProcessing();
|
||||
void RequestStopProcessing();
|
||||
void AddUserWaitableHolder(os::WaitableHolder *waitable);
|
||||
|
||||
Result Process(os::WaitableHolder *waitable);
|
||||
void WaitAndProcess();
|
||||
void LoopProcess();
|
||||
};
|
||||
|
||||
template<size_t MaxServers, typename ManagerOptions = DefaultServerManagerOptions, size_t MaxSessions = ServerSessionCountMax - MaxServers>
|
||||
class ServerManager : public ServerManagerBase {
|
||||
NON_COPYABLE(ServerManager);
|
||||
NON_MOVEABLE(ServerManager);
|
||||
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;
|
||||
TYPED_STORAGE(ServerBase) server_storages[MaxServers];
|
||||
bool server_allocated[MaxServers];
|
||||
TYPED_STORAGE(ServerSession) session_storages[MaxSessions];
|
||||
bool session_allocated[MaxSessions];
|
||||
u8 pointer_buffer_storage[0x10 + (MaxSessions * ManagerOptions::PointerBufferSize)];
|
||||
u8 saved_message_storage[0x10 + (MaxSessions * hipc::TlsMessageBufferSize)];
|
||||
uintptr_t pointer_buffers_start;
|
||||
uintptr_t saved_messages_start;
|
||||
|
||||
/* 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]);
|
||||
AMS_ASSERT(i < MaxServers);
|
||||
return i;
|
||||
}
|
||||
|
||||
constexpr inline size_t GetSessionIndex(const ServerSession *session) const {
|
||||
const size_t i = session - GetPointer(this->session_storages[0]);
|
||||
AMS_ASSERT(i < MaxSessions);
|
||||
return i;
|
||||
}
|
||||
|
||||
constexpr inline cmif::PointerAndSize GetObjectBySessionIndex(const ServerSession *session, uintptr_t start, size_t size) const {
|
||||
return cmif::PointerAndSize(start + this->GetSessionIndex(session) * size, size);
|
||||
}
|
||||
protected:
|
||||
virtual ServerSession *AllocateSession() override final {
|
||||
std::scoped_lock lk(this->resource_mutex);
|
||||
for (size_t i = 0; i < MaxSessions; i++) {
|
||||
if (!this->session_allocated[i]) {
|
||||
this->session_allocated[i] = true;
|
||||
return GetPointer(this->session_storages[i]);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void FreeSession(ServerSession *session) override final {
|
||||
std::scoped_lock lk(this->resource_mutex);
|
||||
const size_t index = this->GetSessionIndex(session);
|
||||
AMS_ASSERT(this->session_allocated[index]);
|
||||
this->session_allocated[index] = false;
|
||||
}
|
||||
|
||||
virtual ServerBase *AllocateServer() override final {
|
||||
std::scoped_lock lk(this->resource_mutex);
|
||||
for (size_t i = 0; i < MaxServers; i++) {
|
||||
if (!this->server_allocated[i]) {
|
||||
this->server_allocated[i] = true;
|
||||
return GetPointer(this->server_storages[i]);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void DestroyServer(ServerBase *server) override final {
|
||||
std::scoped_lock lk(this->resource_mutex);
|
||||
const size_t index = this->GetServerIndex(server);
|
||||
AMS_ASSERT(this->server_allocated[index]);
|
||||
server->~ServerBase();
|
||||
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<DomainStorage *>(domain);
|
||||
const size_t index = ptr - this->domain_storages;
|
||||
AMS_ASSERT(index < ManagerOptions::MaxDomains);
|
||||
AMS_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);
|
||||
} else {
|
||||
return cmif::PointerAndSize();
|
||||
}
|
||||
}
|
||||
|
||||
virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const override final {
|
||||
return this->GetObjectBySessionIndex(session, this->saved_messages_start, hipc::TlsMessageBufferSize);
|
||||
}
|
||||
public:
|
||||
ServerManager() : ServerManagerBase(this->domain_entry_storages, ManagerOptions::MaxDomainObjects) {
|
||||
/* Clear storages. */
|
||||
#define SF_SM_MEMCLEAR(obj) if constexpr (sizeof(obj) > 0) { std::memset(obj, 0, sizeof(obj)); }
|
||||
SF_SM_MEMCLEAR(this->server_storages);
|
||||
SF_SM_MEMCLEAR(this->server_allocated);
|
||||
SF_SM_MEMCLEAR(this->session_storages);
|
||||
SF_SM_MEMCLEAR(this->session_allocated);
|
||||
SF_SM_MEMCLEAR(this->pointer_buffer_storage);
|
||||
SF_SM_MEMCLEAR(this->saved_message_storage);
|
||||
SF_SM_MEMCLEAR(this->domain_allocated);
|
||||
#undef SF_SM_MEMCLEAR
|
||||
|
||||
/* Set resource starts. */
|
||||
this->pointer_buffers_start = util::AlignUp(reinterpret_cast<uintptr_t>(this->pointer_buffer_storage), 0x10);
|
||||
this->saved_messages_start = util::AlignUp(reinterpret_cast<uintptr_t>(this->saved_message_storage), 0x10);
|
||||
}
|
||||
|
||||
~ServerManager() {
|
||||
/* Close all sessions. */
|
||||
for (size_t i = 0; i < MaxSessions; i++) {
|
||||
if (this->session_allocated[i]) {
|
||||
this->CloseSessionImpl(GetPointer(this->session_storages[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Close all servers. */
|
||||
for (size_t i = 0; i < MaxServers; i++) {
|
||||
if (this->server_allocated[i]) {
|
||||
this->DestroyServer(GetPointer(this->server_storages[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../sf_common.hpp"
|
||||
#include "../sf_service_object.hpp"
|
||||
#include "../cmif/sf_cmif_pointer_and_size.hpp"
|
||||
#include "../cmif/sf_cmif_service_object_holder.hpp"
|
||||
#include "sf_hipc_api.hpp"
|
||||
|
||||
namespace ams::sf::cmif {
|
||||
|
||||
struct ServiceDispatchContext;
|
||||
|
||||
}
|
||||
|
||||
namespace ams::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:
|
||||
util::IntrusiveListNode deferred_list_node;
|
||||
cmif::ServiceObjectHolder srv_obj_holder;
|
||||
cmif::PointerAndSize pointer_buffer;
|
||||
cmif::PointerAndSize saved_message;
|
||||
std::shared_ptr<::Service> forward_service;
|
||||
Handle session_handle;
|
||||
bool is_closed;
|
||||
bool has_received;
|
||||
public:
|
||||
ServerSession(Handle h, cmif::ServiceObjectHolder &&obj) : WaitableHolder(h), srv_obj_holder(std::move(obj)), session_handle(h) {
|
||||
this->is_closed = false;
|
||||
this->has_received = false;
|
||||
this->forward_service = nullptr;
|
||||
AMS_ASSERT(!this->IsMitmSession());
|
||||
}
|
||||
|
||||
ServerSession(Handle h, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) : WaitableHolder(h), srv_obj_holder(std::move(obj)), session_handle(h) {
|
||||
this->is_closed = false;
|
||||
this->has_received = false;
|
||||
this->forward_service = std::move(fsrv);
|
||||
AMS_ASSERT(this->IsMitmSession());
|
||||
}
|
||||
|
||||
bool IsMitmSession() const {
|
||||
return this->forward_service != nullptr;
|
||||
}
|
||||
|
||||
Result ForwardRequest(const cmif::ServiceDispatchContext &ctx) const;
|
||||
|
||||
static inline void ForwardServiceDeleter(Service *srv) {
|
||||
serviceClose(srv);
|
||||
delete srv;
|
||||
}
|
||||
|
||||
static inline std::shared_ptr<::Service> CreateForwardService() {
|
||||
return std::shared_ptr<::Service>(new ::Service(), ForwardServiceDeleter);
|
||||
}
|
||||
};
|
||||
|
||||
class ServerSessionManager {
|
||||
private:
|
||||
template<typename Constructor>
|
||||
Result CreateSessionImpl(ServerSession **out, const Constructor &ctor) {
|
||||
/* Allocate session. */
|
||||
ServerSession *session_memory = this->AllocateSession();
|
||||
R_UNLESS(session_memory != nullptr, sf::hipc::ResultOutOfSessionMemory());
|
||||
/* Register session. */
|
||||
bool succeeded = false;
|
||||
ON_SCOPE_EXIT {
|
||||
if (!succeeded) {
|
||||
this->DestroySession(session_memory);
|
||||
}
|
||||
};
|
||||
R_TRY(ctor(session_memory));
|
||||
/* Save new session to output. */
|
||||
succeeded = true;
|
||||
*out = session_memory;
|
||||
return ResultSuccess();
|
||||
}
|
||||
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);
|
||||
protected:
|
||||
virtual ServerSession *AllocateSession() = 0;
|
||||
virtual void FreeSession(ServerSession *session) = 0;
|
||||
virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const = 0;
|
||||
virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const = 0;
|
||||
|
||||
Result ReceiveRequestImpl(ServerSession *session, const cmif::PointerAndSize &message);
|
||||
void CloseSessionImpl(ServerSession *session);
|
||||
Result RegisterSessionImpl(ServerSession *session_memory, Handle session_handle, cmif::ServiceObjectHolder &&obj);
|
||||
Result AcceptSessionImpl(ServerSession *session_memory, Handle port_handle, cmif::ServiceObjectHolder &&obj);
|
||||
Result RegisterMitmSessionImpl(ServerSession *session_memory, Handle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
|
||||
Result AcceptMitmSessionImpl(ServerSession *session_memory, Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
|
||||
|
||||
Result ReceiveRequest(ServerSession *session, const cmif::PointerAndSize &message) {
|
||||
return this->ReceiveRequestImpl(session, message);
|
||||
}
|
||||
|
||||
Result RegisterSession(ServerSession **out, Handle session_handle, cmif::ServiceObjectHolder &&obj) {
|
||||
auto ctor = [&](ServerSession *session_memory) -> Result {
|
||||
return this->RegisterSessionImpl(session_memory, session_handle, std::forward<cmif::ServiceObjectHolder>(obj));
|
||||
};
|
||||
return this->CreateSessionImpl(out, ctor);
|
||||
}
|
||||
|
||||
Result AcceptSession(ServerSession **out, Handle port_handle, cmif::ServiceObjectHolder &&obj) {
|
||||
auto ctor = [&](ServerSession *session_memory) -> Result {
|
||||
return this->AcceptSessionImpl(session_memory, port_handle, std::forward<cmif::ServiceObjectHolder>(obj));
|
||||
};
|
||||
return this->CreateSessionImpl(out, ctor);
|
||||
}
|
||||
|
||||
Result RegisterMitmSession(ServerSession **out, Handle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
auto ctor = [&](ServerSession *session_memory) -> Result {
|
||||
return this->RegisterMitmSessionImpl(session_memory, mitm_session_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv));
|
||||
};
|
||||
return this->CreateSessionImpl(out, ctor);
|
||||
}
|
||||
|
||||
Result AcceptMitmSession(ServerSession **out, Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
auto ctor = [&](ServerSession *session_memory) -> Result {
|
||||
return this->AcceptMitmSessionImpl(session_memory, mitm_port_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv));
|
||||
};
|
||||
return this->CreateSessionImpl(out, ctor);
|
||||
}
|
||||
public:
|
||||
Result RegisterSession(Handle session_handle, cmif::ServiceObjectHolder &&obj);
|
||||
Result AcceptSession(Handle port_handle, cmif::ServiceObjectHolder &&obj);
|
||||
Result RegisterMitmSession(Handle session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
|
||||
Result AcceptMitmSession(Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
|
||||
|
||||
template<typename ServiceImpl>
|
||||
Result AcceptSession(Handle port_handle, std::shared_ptr<ServiceImpl> obj) {
|
||||
return this->AcceptSession(port_handle, cmif::ServiceObjectHolder(std::move(obj)));
|
||||
}
|
||||
|
||||
template<typename ServiceImpl>
|
||||
Result AcceptMitmSession(Handle mitm_port_handle, std::shared_ptr<ServiceImpl> obj, std::shared_ptr<::Service> &&fsrv) {
|
||||
return this->AcceptMitmSession(mitm_port_handle, cmif::ServiceObjectHolder(std::move(obj)), std::forward<std::shared_ptr<::Service>>(fsrv));
|
||||
}
|
||||
|
||||
Result ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message);
|
||||
|
||||
virtual ServerSessionManager *GetSessionManagerByTag(u32 tag) {
|
||||
/* This is unused. */
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
/* Helper structs for serialization of buffers. */
|
||||
struct LargeData{};
|
||||
|
||||
struct PrefersMapAliasTransferMode{};
|
||||
|
||||
struct PrefersPointerTransferMode{};
|
||||
|
||||
struct PrefersAutoSelectTransferMode{};
|
||||
|
||||
}
|
||||
301
libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp
Normal file
301
libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_common.hpp"
|
||||
#include "sf_out.hpp"
|
||||
#include "cmif/sf_cmif_pointer_and_size.hpp"
|
||||
#include "sf_buffer_tags.hpp"
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
enum class BufferTransferMode {
|
||||
MapAlias,
|
||||
Pointer,
|
||||
AutoSelect,
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
/* Buffer utilities. */
|
||||
struct BufferBaseTag{};
|
||||
|
||||
template<BufferTransferMode TransferMode>
|
||||
constexpr inline u32 BufferTransferModeAttributes = [] {
|
||||
if constexpr (TransferMode == BufferTransferMode::MapAlias) {
|
||||
return SfBufferAttr_HipcMapAlias;
|
||||
} else if constexpr (TransferMode == BufferTransferMode::Pointer) {
|
||||
return SfBufferAttr_HipcPointer;
|
||||
} else if constexpr(TransferMode == BufferTransferMode::AutoSelect) {
|
||||
return SfBufferAttr_HipcAutoSelect;
|
||||
} else {
|
||||
static_assert(TransferMode != TransferMode, "Invalid BufferTransferMode");
|
||||
}
|
||||
}();
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline bool IsLargeData = std::is_base_of<sf::LargeData, T>::value;
|
||||
|
||||
template<typename T>
|
||||
constexpr inline bool IsLargeData<Out<T>> = IsLargeData<T>;
|
||||
|
||||
template<typename T>
|
||||
constexpr inline size_t LargeDataSize = sizeof(T);
|
||||
|
||||
template<typename T>
|
||||
constexpr inline size_t LargeDataSize<Out<T>> = sizeof(T);
|
||||
|
||||
template<typename T>
|
||||
constexpr inline BufferTransferMode PreferredTransferMode = [] {
|
||||
constexpr bool prefers_map_alias = std::is_base_of<PrefersMapAliasTransferMode, T>::value;
|
||||
constexpr bool prefers_pointer = std::is_base_of<PrefersPointerTransferMode, T>::value;
|
||||
constexpr bool prefers_auto_select = std::is_base_of<PrefersAutoSelectTransferMode, T>::value;
|
||||
if constexpr (prefers_map_alias) {
|
||||
static_assert(!prefers_pointer && !prefers_auto_select, "Type T must only prefer one transfer mode.");
|
||||
return BufferTransferMode::MapAlias;
|
||||
} else if constexpr (prefers_pointer) {
|
||||
static_assert(!prefers_map_alias && !prefers_auto_select, "Type T must only prefer one transfer mode.");
|
||||
return BufferTransferMode::Pointer;
|
||||
} else if constexpr (prefers_auto_select) {
|
||||
static_assert(!prefers_map_alias && !prefers_pointer, "Type T must only prefer one transfer mode.");
|
||||
return BufferTransferMode::AutoSelect;
|
||||
} else if constexpr (IsLargeData<T>) {
|
||||
return BufferTransferMode::Pointer;
|
||||
} else {
|
||||
return BufferTransferMode::MapAlias;
|
||||
}
|
||||
}();
|
||||
|
||||
template<typename T>
|
||||
constexpr inline BufferTransferMode PreferredTransferMode<Out<T>> = PreferredTransferMode<T>;
|
||||
|
||||
namespace impl {
|
||||
|
||||
class BufferBase : public BufferBaseTag {
|
||||
public:
|
||||
static constexpr u32 AdditionalAttributes = 0;
|
||||
private:
|
||||
const cmif::PointerAndSize pas;
|
||||
protected:
|
||||
constexpr uintptr_t GetAddressImpl() const {
|
||||
return this->pas.GetAddress();
|
||||
}
|
||||
|
||||
template<typename Entry>
|
||||
constexpr inline size_t GetSizeImpl() const {
|
||||
return this->pas.GetSize() / sizeof(Entry);
|
||||
}
|
||||
public:
|
||||
constexpr BufferBase() : pas() { /* ... */ }
|
||||
constexpr BufferBase(const cmif::PointerAndSize &_pas) : pas(_pas) { /* ... */ }
|
||||
constexpr BufferBase(uintptr_t ptr, size_t sz) : pas(ptr, sz) { /* ... */ }
|
||||
};
|
||||
|
||||
class InBufferBase : public BufferBase {
|
||||
public:
|
||||
using BaseType = BufferBase;
|
||||
static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes |
|
||||
SfBufferAttr_In;
|
||||
public:
|
||||
constexpr InBufferBase() : BaseType() { /* ... */ }
|
||||
constexpr InBufferBase(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ }
|
||||
constexpr InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ }
|
||||
|
||||
constexpr InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
constexpr InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
};
|
||||
|
||||
class OutBufferBase : public BufferBase {
|
||||
public:
|
||||
using BaseType = BufferBase;
|
||||
static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes |
|
||||
SfBufferAttr_Out;
|
||||
public:
|
||||
constexpr OutBufferBase() : BaseType() { /* ... */ }
|
||||
constexpr OutBufferBase(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ }
|
||||
constexpr OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ }
|
||||
|
||||
constexpr OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
constexpr OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
};
|
||||
|
||||
template<BufferTransferMode TMode, u32 ExtraAttributes = 0>
|
||||
class InBufferImpl : public InBufferBase {
|
||||
public:
|
||||
using BaseType = InBufferBase;
|
||||
static constexpr BufferTransferMode TransferMode = TMode;
|
||||
static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes |
|
||||
ExtraAttributes;
|
||||
public:
|
||||
constexpr InBufferImpl() : BaseType() { /* ... */ }
|
||||
constexpr InBufferImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ }
|
||||
constexpr InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ }
|
||||
|
||||
constexpr InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
constexpr InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
|
||||
constexpr const u8 *GetPointer() const {
|
||||
return reinterpret_cast<const u8 *>(this->GetAddressImpl());
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return this->GetSizeImpl<u8>();
|
||||
}
|
||||
};
|
||||
|
||||
template<BufferTransferMode TMode, u32 ExtraAttributes = 0>
|
||||
class OutBufferImpl : public OutBufferBase {
|
||||
public:
|
||||
using BaseType = OutBufferBase;
|
||||
static constexpr BufferTransferMode TransferMode = TMode;
|
||||
static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes |
|
||||
ExtraAttributes;
|
||||
public:
|
||||
constexpr OutBufferImpl() : BaseType() { /* ... */ }
|
||||
constexpr OutBufferImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ }
|
||||
constexpr OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ }
|
||||
|
||||
constexpr OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
constexpr OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
|
||||
constexpr u8 *GetPointer() const {
|
||||
return reinterpret_cast<u8 *>(this->GetAddressImpl());
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return this->GetSizeImpl<u8>();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, BufferTransferMode TMode = PreferredTransferMode<T>>
|
||||
struct InArrayImpl : public InBufferBase {
|
||||
public:
|
||||
using BaseType = InBufferBase;
|
||||
static constexpr BufferTransferMode TransferMode = TMode;
|
||||
static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes;
|
||||
public:
|
||||
constexpr InArrayImpl() : BaseType() { /* ... */ }
|
||||
constexpr InArrayImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ }
|
||||
constexpr InArrayImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ }
|
||||
|
||||
constexpr InArrayImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
constexpr InArrayImpl(const T *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
|
||||
constexpr const T *GetPointer() const {
|
||||
return reinterpret_cast<const T *>(this->GetAddressImpl());
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return this->GetSizeImpl<T>();
|
||||
}
|
||||
|
||||
constexpr const T &operator[](size_t i) const {
|
||||
return this->GetPointer()[i];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, BufferTransferMode TMode = PreferredTransferMode<T>>
|
||||
struct OutArrayImpl : public OutBufferBase {
|
||||
public:
|
||||
using BaseType = OutBufferBase;
|
||||
static constexpr BufferTransferMode TransferMode = TMode;
|
||||
static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes;
|
||||
public:
|
||||
constexpr OutArrayImpl() : BaseType() { /* ... */ }
|
||||
constexpr OutArrayImpl(const cmif::PointerAndSize &_pas) : BaseType(_pas) { /* ... */ }
|
||||
constexpr OutArrayImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ }
|
||||
|
||||
constexpr OutArrayImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
constexpr OutArrayImpl(T *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ }
|
||||
|
||||
constexpr T *GetPointer() const {
|
||||
return reinterpret_cast<T *>(this->GetAddressImpl());
|
||||
}
|
||||
|
||||
constexpr size_t GetSize() const {
|
||||
return this->GetSizeImpl<T>();
|
||||
}
|
||||
|
||||
constexpr T &operator[](size_t i) const {
|
||||
return this->GetPointer()[i];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/* Buffer Types. */
|
||||
using InBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias>;
|
||||
using InMapAliasBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias>;
|
||||
using InPointerBuffer = typename impl::InBufferImpl<BufferTransferMode::Pointer>;
|
||||
using InAutoSelectBuffer = typename impl::InBufferImpl<BufferTransferMode::AutoSelect>;
|
||||
using InNonSecureBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonSecure>;
|
||||
using InNonDeviceBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonDevice>;
|
||||
|
||||
using OutBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias>;
|
||||
using OutMapAliasBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias>;
|
||||
using OutPointerBuffer = typename impl::OutBufferImpl<BufferTransferMode::Pointer>;
|
||||
using OutAutoSelectBuffer = typename impl::OutBufferImpl<BufferTransferMode::AutoSelect>;
|
||||
using OutNonSecureBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonSecure>;
|
||||
using OutNonDeviceBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonDevice>;
|
||||
|
||||
template<typename T>
|
||||
using InArray = typename impl::InArrayImpl<T>;
|
||||
template<typename T>
|
||||
using InMapAliasArray = typename impl::InArrayImpl<T, BufferTransferMode::MapAlias>;
|
||||
template<typename T>
|
||||
using InPointerArray = typename impl::InArrayImpl<T, BufferTransferMode::Pointer>;
|
||||
template<typename T>
|
||||
using InAutoSelectArray = typename impl::InArrayImpl<T, BufferTransferMode::AutoSelect>;
|
||||
|
||||
template<typename T>
|
||||
using OutArray = typename impl::OutArrayImpl<T>;
|
||||
template<typename T>
|
||||
using OutMapAliasArray = typename impl::OutArrayImpl<T, BufferTransferMode::MapAlias>;
|
||||
template<typename T>
|
||||
using OutPointerArray = typename impl::OutArrayImpl<T, BufferTransferMode::Pointer>;
|
||||
template<typename T>
|
||||
using OutAutoSelectArray = typename impl::OutArrayImpl<T, BufferTransferMode::AutoSelect>;
|
||||
|
||||
/* Attribute serialization structs. */
|
||||
template<typename T>
|
||||
constexpr inline bool IsBuffer = [] {
|
||||
const bool is_buffer = std::is_base_of<impl::BufferBaseTag, T>::value;
|
||||
const bool is_large_data = IsLargeData<T>;
|
||||
static_assert(!(is_buffer && is_large_data), "Invalid sf::IsBuffer state");
|
||||
return is_buffer || is_large_data;
|
||||
}();
|
||||
|
||||
template<typename T>
|
||||
constexpr inline u32 BufferAttributes = [] {
|
||||
static_assert(IsBuffer<T>, "BufferAttributes requires IsBuffer");
|
||||
if constexpr (std::is_base_of<impl::BufferBaseTag, T>::value) {
|
||||
return impl::BufferTransferModeAttributes<T::TransferMode> | T::AdditionalAttributes;
|
||||
} else if constexpr (IsLargeData<T>) {
|
||||
u32 attr = SfBufferAttr_FixedSize | impl::BufferTransferModeAttributes<PreferredTransferMode<T>>;
|
||||
if constexpr (std::is_base_of<impl::OutBaseTag, T>::value) {
|
||||
attr |= SfBufferAttr_Out;
|
||||
} else {
|
||||
attr |= SfBufferAttr_In;
|
||||
}
|
||||
return attr;
|
||||
} else {
|
||||
static_assert(!std::is_same<T, T>::value, "Invalid BufferAttributes<T>");
|
||||
}
|
||||
}();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include "../ams.hpp"
|
||||
#include "../os.hpp"
|
||||
#include "../sm/sm_types.hpp"
|
||||
171
libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp
Normal file
171
libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_common.hpp"
|
||||
#include "sf_out.hpp"
|
||||
#include "cmif/sf_cmif_pointer_and_size.hpp"
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct InHandleTag{};
|
||||
struct OutHandleTag{};
|
||||
|
||||
template<u32 Attribute>
|
||||
struct InHandle : public InHandleTag {
|
||||
::Handle handle;
|
||||
|
||||
constexpr InHandle() : handle(INVALID_HANDLE) { /* ... */ }
|
||||
constexpr InHandle(::Handle h) : handle(h) { /* ... */ }
|
||||
constexpr InHandle(const InHandle &o) : handle(o.handle) { /* ... */ }
|
||||
|
||||
constexpr void operator=(const ::Handle &h) { this->handle = h; }
|
||||
constexpr void operator=(const InHandle &o) { this->handle = o.handle; }
|
||||
|
||||
constexpr /* TODO: explicit? */ operator ::Handle() const { return this->handle; }
|
||||
constexpr ::Handle GetValue() const { return this->handle; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OutHandleImpl : public OutHandleTag {
|
||||
static_assert(std::is_base_of<InHandleTag, T>::value, "OutHandleImpl requires InHandle base");
|
||||
private:
|
||||
T *ptr;
|
||||
public:
|
||||
constexpr OutHandleImpl(T *p) : ptr(p) { /* ... */ }
|
||||
|
||||
constexpr void SetValue(const Handle &value) {
|
||||
*this->ptr = value;
|
||||
}
|
||||
|
||||
constexpr void SetValue(const T &value) {
|
||||
*this->ptr = value;
|
||||
}
|
||||
|
||||
constexpr const T &GetValue() const {
|
||||
return *this->ptr;
|
||||
}
|
||||
|
||||
constexpr T *GetPointer() const {
|
||||
return this->ptr;
|
||||
}
|
||||
|
||||
constexpr Handle *GetHandlePointer() const {
|
||||
return &this->ptr->handle;
|
||||
}
|
||||
|
||||
constexpr T &operator *() const {
|
||||
return *this->ptr;
|
||||
}
|
||||
|
||||
constexpr T *operator ->() const {
|
||||
return this->ptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using MoveHandle = typename impl::InHandle<SfOutHandleAttr_HipcMove>;
|
||||
using CopyHandle = typename impl::InHandle<SfOutHandleAttr_HipcCopy>;
|
||||
|
||||
static_assert(sizeof(MoveHandle) == sizeof(::Handle), "sizeof(MoveHandle)");
|
||||
static_assert(sizeof(CopyHandle) == sizeof(::Handle), "sizeof(CopyHandle)");
|
||||
|
||||
template<>
|
||||
class IsOutForceEnabled<MoveHandle> : public std::true_type{};
|
||||
template<>
|
||||
class IsOutForceEnabled<CopyHandle> : public std::true_type{};
|
||||
|
||||
template<>
|
||||
class Out<MoveHandle> : public impl::OutHandleImpl<MoveHandle> {
|
||||
private:
|
||||
using T = MoveHandle;
|
||||
using Base = impl::OutHandleImpl<T>;
|
||||
public:
|
||||
constexpr Out<T>(T *p) : Base(p) { /* ... */ }
|
||||
|
||||
constexpr void SetValue(const Handle &value) {
|
||||
Base::SetValue(value);
|
||||
}
|
||||
|
||||
constexpr void SetValue(const T &value) {
|
||||
Base::SetValue(value);
|
||||
}
|
||||
|
||||
constexpr const T &GetValue() const {
|
||||
return Base::GetValue();
|
||||
}
|
||||
|
||||
constexpr T *GetPointer() const {
|
||||
return Base::GetPointer();
|
||||
}
|
||||
|
||||
constexpr Handle *GetHandlePointer() const {
|
||||
return Base::GetHandlePointer();
|
||||
}
|
||||
|
||||
constexpr T &operator *() const {
|
||||
return Base::operator*();
|
||||
}
|
||||
|
||||
constexpr T *operator ->() const {
|
||||
return Base::operator->();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class Out<CopyHandle> : public impl::OutHandleImpl<CopyHandle> {
|
||||
private:
|
||||
using T = CopyHandle;
|
||||
using Base = impl::OutHandleImpl<T>;
|
||||
public:
|
||||
constexpr Out<T>(T *p) : Base(p) { /* ... */ }
|
||||
|
||||
constexpr void SetValue(const Handle &value) {
|
||||
Base::SetValue(value);
|
||||
}
|
||||
|
||||
constexpr void SetValue(const T &value) {
|
||||
Base::SetValue(value);
|
||||
}
|
||||
|
||||
constexpr const T &GetValue() const {
|
||||
return Base::GetValue();
|
||||
}
|
||||
|
||||
constexpr T *GetPointer() const {
|
||||
return Base::GetPointer();
|
||||
}
|
||||
|
||||
constexpr Handle *GetHandlePointer() const {
|
||||
return Base::GetHandlePointer();
|
||||
}
|
||||
|
||||
constexpr T &operator *() const {
|
||||
return Base::operator*();
|
||||
}
|
||||
|
||||
constexpr T *operator ->() const {
|
||||
return Base::operator->();
|
||||
}
|
||||
};
|
||||
|
||||
using OutMoveHandle = sf::Out<sf::MoveHandle>;
|
||||
using OutCopyHandle = sf::Out<sf::CopyHandle>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
Handle target_session;
|
||||
u32 context;
|
||||
|
||||
SfBufferAttrs buffer_attrs;
|
||||
SfBuffer buffers[8];
|
||||
|
||||
bool in_send_pid;
|
||||
|
||||
u32 in_num_objects;
|
||||
const Service* in_objects[8];
|
||||
|
||||
u32 in_num_handles;
|
||||
Handle in_handles[8];
|
||||
|
||||
u32 out_num_objects;
|
||||
Service* out_objects;
|
||||
|
||||
SfOutHandleAttrs out_handle_attrs;
|
||||
Handle* out_handles;
|
||||
|
||||
u64 override_pid;
|
||||
} SfMitmDispatchParams;
|
||||
|
||||
NX_INLINE Result serviceMitmDispatchImpl(
|
||||
Service* s, u32 request_id,
|
||||
const void* in_data, u32 in_data_size,
|
||||
void* out_data, u32 out_data_size,
|
||||
SfMitmDispatchParams disp
|
||||
)
|
||||
{
|
||||
// Make a copy of the service struct, so that the compiler can assume that it won't be modified by function calls.
|
||||
Service srv = *s;
|
||||
|
||||
void* in = serviceMakeRequest(&srv, request_id, disp.context,
|
||||
in_data_size, disp.in_send_pid,
|
||||
disp.buffer_attrs, disp.buffers,
|
||||
disp.in_num_objects, disp.in_objects,
|
||||
disp.in_num_handles, disp.in_handles);
|
||||
|
||||
if (in_data_size)
|
||||
__builtin_memcpy(in, in_data, in_data_size);
|
||||
|
||||
if (disp.in_send_pid && disp.override_pid) {
|
||||
const u64 pid = (disp.override_pid & 0x0000FFFFFFFFFFFFul) | 0xFFFE000000000000ul;
|
||||
__builtin_memcpy((u8 *)armGetTls() + 0xC, &pid, sizeof(pid));
|
||||
}
|
||||
|
||||
Result rc = svcSendSyncRequest(disp.target_session == INVALID_HANDLE ? s->session : disp.target_session);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
void* out = NULL;
|
||||
rc = serviceParseResponse(&srv,
|
||||
out_data_size, &out,
|
||||
disp.out_num_objects, disp.out_objects,
|
||||
disp.out_handle_attrs, disp.out_handles);
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_data && out_data_size)
|
||||
__builtin_memcpy(out_data, out, out_data_size);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define serviceMitmDispatch(_s,_rid,...) \
|
||||
serviceMitmDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfMitmDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#define serviceMitmDispatchIn(_s,_rid,_in,...) \
|
||||
serviceMitmDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfMitmDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#define serviceMitmDispatchOut(_s,_rid,_out,...) \
|
||||
serviceMitmDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfMitmDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#define serviceMitmDispatchInOut(_s,_rid,_in,_out,...) \
|
||||
serviceMitmDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfMitmDispatchParams){ __VA_ARGS__ })
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
76
libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp
Normal file
76
libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_common.hpp"
|
||||
#include "cmif/sf_cmif_pointer_and_size.hpp"
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct OutBaseTag{};
|
||||
|
||||
}
|
||||
|
||||
template<typename>
|
||||
struct IsOutForceEnabled : public std::false_type{};
|
||||
|
||||
template<>
|
||||
struct IsOutForceEnabled<::ams::Result> : public std::true_type{};
|
||||
|
||||
template<typename T>
|
||||
using IsOutEnabled = typename std::enable_if<std::is_trivial<T>::value || IsOutForceEnabled<T>::value>::type;
|
||||
|
||||
template<typename T, typename = IsOutEnabled<T>>
|
||||
class Out : public impl::OutBaseTag {
|
||||
public:
|
||||
static constexpr size_t TypeSize = sizeof(T);
|
||||
private:
|
||||
T *ptr;
|
||||
public:
|
||||
constexpr Out(uintptr_t p) : ptr(reinterpret_cast<T *>(p)) { /* ... */ }
|
||||
constexpr Out(T *p) : ptr(p) { /* ... */ }
|
||||
constexpr Out(const cmif::PointerAndSize &pas) : ptr(reinterpret_cast<T *>(pas.GetAddress())) { /* TODO: Is AMS_ASSERT(pas.GetSize() >= sizeof(T)); necessary? */ }
|
||||
|
||||
void SetValue(const T& value) const {
|
||||
*this->ptr = value;
|
||||
}
|
||||
|
||||
const T &GetValue() const {
|
||||
return *this->ptr;
|
||||
}
|
||||
|
||||
T *GetPointer() const {
|
||||
return this->ptr;
|
||||
}
|
||||
|
||||
/* Convenience operators. */
|
||||
T &operator*() const {
|
||||
return *this->ptr;
|
||||
}
|
||||
|
||||
T *operator->() const {
|
||||
return this->ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Out<T *> {
|
||||
static_assert(!std::is_same<T, T>::value, "Invalid sf::Out<T> (Raw Pointer)");
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "sf_common.hpp"
|
||||
#include "sf_out.hpp"
|
||||
|
||||
namespace ams::sf {
|
||||
|
||||
class IServiceObject {
|
||||
public:
|
||||
virtual ~IServiceObject() { /* ... */ }
|
||||
};
|
||||
|
||||
class IMitmServiceObject : public IServiceObject {
|
||||
protected:
|
||||
std::shared_ptr<::Service> forward_service;
|
||||
sm::MitmProcessInfo client_info;
|
||||
public:
|
||||
IMitmServiceObject(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : forward_service(std::move(s)), client_info(c) { /* ... */ }
|
||||
|
||||
virtual ~IMitmServiceObject() { /* ... */ }
|
||||
|
||||
static bool ShouldMitm(os::ProcessId process_id, ncm::ProgramId program_id);
|
||||
};
|
||||
|
||||
/* Utility. */
|
||||
#define SF_MITM_SERVICE_OBJECT_CTOR(cls) cls(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : ::ams::sf::IMitmServiceObject(std::forward<std::shared_ptr<::Service>>(s), c)
|
||||
|
||||
template<typename T>
|
||||
struct ServiceObjectTraits {
|
||||
static_assert(std::is_base_of<ams::sf::IServiceObject, T>::value, "ServiceObjectTraits requires ServiceObject");
|
||||
|
||||
static constexpr bool IsMitmServiceObject = std::is_base_of<IMitmServiceObject, T>::value;
|
||||
|
||||
struct SharedPointerHelper {
|
||||
|
||||
static constexpr void EmptyDelete(T *) { /* Empty deleter, for fake shared pointer. */ }
|
||||
|
||||
static constexpr std::shared_ptr<T> GetEmptyDeleteSharedPointer(T *srv_obj) {
|
||||
return std::shared_ptr<T>(srv_obj, EmptyDelete);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user