sf: implement service framework enough for ro to work.

This completely re-does the whole interface for ipc servers.
This commit is contained in:
Michael Scire
2019-10-10 23:49:28 -07:00
committed by SciresM
parent bd341d5c00
commit f4dcd1db9b
47 changed files with 3545 additions and 166 deletions

View File

@@ -37,4 +37,5 @@
#include "stratosphere/ncm.hpp"
#include "stratosphere/pm.hpp"
#include "stratosphere/rnd.hpp"
#include "stratosphere/sm.hpp"
#include "stratosphere/sm.hpp"
#include "stratosphere/sf.hpp"

View File

@@ -17,4 +17,4 @@
#pragma once
#include "ams/ams_types.hpp"
#include "ams/ams_firmware_version_api.hpp"
#include "ams/ams_hos_version_api.hpp"

View File

@@ -17,9 +17,9 @@
#pragma once
#include "ams_types.hpp"
namespace sts::ams {
namespace sts::hos {
FirmwareVersion GetRuntimeFirmwareVersion();
void SetFirmwareVersionForLibnx();
sts::hos::Version GetVersion();
void SetVersionForLibnx();
}

View File

@@ -21,21 +21,25 @@
/* Define firmware version in global namespace, for convenience. */
namespace sts {
enum FirmwareVersion : u32 {
FirmwareVersion_Min = 0,
FirmwareVersion_100 = FirmwareVersion_Min,
FirmwareVersion_200 = 1,
FirmwareVersion_300 = 2,
FirmwareVersion_400 = 3,
FirmwareVersion_500 = 4,
FirmwareVersion_600 = 5,
FirmwareVersion_700 = 6,
FirmwareVersion_800 = 7,
FirmwareVersion_810 = 8,
FirmwareVersion_900 = 9,
FirmwareVersion_Current = FirmwareVersion_900,
FirmwareVersion_Max = 32,
};
namespace hos {
enum Version : u16 {
Version_Min = 0,
Version_100 = Version_Min,
Version_200 = 1,
Version_300 = 2,
Version_400 = 3,
Version_500 = 4,
Version_600 = 5,
Version_700 = 6,
Version_800 = 7,
Version_810 = 8,
Version_900 = 9,
Version_Current = Version_900,
Version_Max = 32,
};
}
}

View File

@@ -22,7 +22,7 @@ namespace sts::cfg {
/* Privileged Process configuration. */
bool IsInitialProcess();
void GetInitialProcessRange(u64 *out_min, u64 *out_max);
void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max);
/* SD card configuration. */
bool IsSdCardInitialized();

View File

@@ -29,4 +29,49 @@ namespace sts::os {
ForNotFull,
};
struct ProcessId {
u64 value;
inline constexpr explicit operator u64() const {
return this->value;
}
/* Invalid Process ID. */
static const ProcessId Invalid;
};
inline constexpr const ProcessId ProcessId::Invalid = {static_cast<u64>(-1ull)};
inline constexpr const ProcessId InvalidProcessId = ProcessId::Invalid;
NX_INLINE ProcessId GetCurrentProcessId() {
u64 current_process_id = 0;
R_ASSERT(svcGetProcessId(&current_process_id, CUR_PROCESS_HANDLE));
return os::ProcessId{current_process_id};
}
inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value != rhs.value;
}
inline constexpr bool operator<(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value < rhs.value;
}
inline constexpr bool operator<=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value <= rhs.value;
}
inline constexpr bool operator>(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value > rhs.value;
}
inline constexpr bool operator>=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value >= rhs.value;
}
}

View File

@@ -19,9 +19,19 @@
static constexpr u32 Module_Hipc = 11;
static constexpr Result ResultHipcOutOfDomains = MAKERESULT(Module_Hipc, 200);
static constexpr Result ResultHipcSessionAllocationFailure = MAKERESULT(Module_Hipc, 102);
static constexpr Result ResultHipcSessionClosed = MAKERESULT(Module_Hipc, 301);
static constexpr Result ResultHipcOutOfSessions = MAKERESULT(Module_Hipc, 131);
static constexpr Result ResultHipcPointerBufferTooSmall = MAKERESULT(Module_Hipc, 141);
static constexpr Result ResultHipcOutOfDomains = MAKERESULT(Module_Hipc, 200);
static constexpr Result ResultHipcSessionClosed = MAKERESULT(Module_Hipc, 301);
static constexpr Result ResultHipcInvalidRequestSize = MAKERESULT(Module_Hipc, 402);
static constexpr Result ResultHipcUnknownCommandType = MAKERESULT(Module_Hipc, 403);
static constexpr Result ResultHipcInvalidRequest = MAKERESULT(Module_Hipc, 420);
static constexpr Result ResultHipcTargetNotDomain = MAKERESULT(Module_Hipc, 491);
static constexpr Result ResultHipcDomainObjectNotFound = MAKERESULT(Module_Hipc, 492);

View File

@@ -57,6 +57,7 @@ static constexpr Result ResultKernelOwnedByAnotherProcess = MAKERESULT(Mo
static constexpr Result ResultKernelConnectionRefused = MAKERESULT(Module_Kernel, KernelError_ConnectionRefused);
static constexpr Result ResultKernelLimitReached = MAKERESULT(Module_Kernel, 132 /* KernelError_OutOfResource */);
static constexpr Result ResultKernelReceiveListBroken = MAKERESULT(Module_Kernel, 258);
static constexpr Result ResultKernelIpcMapFailed = MAKERESULT(Module_Kernel, KernelError_IpcMapFailed);
static constexpr Result ResultKernelIpcCmdBufTooSmall = MAKERESULT(Module_Kernel, KernelError_IpcCmdbufTooSmall);

View File

@@ -19,9 +19,17 @@
static constexpr u32 Module_ServiceFramework = 10;
static constexpr Result ResultServiceFrameworkTargetNotFound = MAKERESULT(Module_ServiceFramework, 261);
static constexpr Result ResultServiceFrameworkNotSupported = MAKERESULT(Module_ServiceFramework, 1);
static constexpr Result ResultServiceFrameworkPreconditionViolation = MAKERESULT(Module_ServiceFramework, 3);
static constexpr Result ResultServiceFrameworkOutOfDomainEntries = MAKERESULT(Module_ServiceFramework, 301);
static constexpr Result ResultServiceFrameworkInvalidCmifHeaderSize = MAKERESULT(Module_ServiceFramework, 202);
static constexpr Result ResultServiceFrameworkInvalidCmifInHeader = MAKERESULT(Module_ServiceFramework, 211);
static constexpr Result ResultServiceFrameworkUnknownCmifCommandId = MAKERESULT(Module_ServiceFramework, 221);
static constexpr Result ResultServiceFrameworkInvalidCmifOutRawSize = MAKERESULT(Module_ServiceFramework, 232);
static constexpr Result ResultServiceFrameworkTargetNotFound = MAKERESULT(Module_ServiceFramework, 261);
static constexpr Result ResultServiceFrameworkOutOfDomainEntries = MAKERESULT(Module_ServiceFramework, 301);
static constexpr Result ResultServiceFrameworkRequestDeferred = MAKERESULT(Module_ServiceFramework, 811);

View File

@@ -18,6 +18,7 @@
#include <switch.h>
#include <cstdlib>
#include "../defines.hpp"
#include "../ncm.hpp"
namespace sts::ro {
@@ -44,7 +45,7 @@ namespace sts::ro {
u8 modulus[0x100];
u8 fixed_key_signature[0x100];
u8 nrr_signature[0x100];
u64 title_id;
ncm::TitleId title_id;
u32 size;
u8 type; /* 7.0.0+ */
u8 reserved_33D[3];
@@ -57,7 +58,7 @@ namespace sts::ro {
}
bool IsTitleIdValid() const {
return (this->title_id & this->title_id_mask) == this->title_id_pattern;
return (static_cast<u64>(this->title_id) & this->title_id_mask) == this->title_id_pattern;
}
ModuleType GetType() const {
@@ -66,7 +67,7 @@ namespace sts::ro {
return type;
}
u64 GetTitleId() const {
ncm::TitleId GetTitleId() const {
return this->title_id;
}

View File

@@ -0,0 +1,28 @@
/*
* 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>
#include "sf/sf_common.hpp"
#include "sf/sf_service_object.hpp"
#include "sf/hipc/sf_hipc_server_session_manager.hpp"
#include "sf/sf_out.hpp"
#include "sf/sf_buffers.hpp"
#include "sf/impl/sf_impl_command_serialization.hpp"
#include "sf/hipc/sf_hipc_server_manager.hpp"

View File

@@ -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 sts::sf::cmif {
struct DomainObjectId {
u32 value;
constexpr void SetValue(u32 new_value) { this->value = new_value; }
};
static_assert(std::is_trivial<DomainObjectId>::value, "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 Result AlterReservedIds(const DomainObjectId *old_reserved_ids, const DomainObjectId *new_reserved_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;
};
}

View File

@@ -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 sts::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;
}
};
}

View File

@@ -0,0 +1,39 @@
/*
* 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 sts::sf::cmif {
/* Forward declare ServiceDispatchContext, ServiceObjectHolder. */
struct ServiceDispatchContext;
class ServiceObjectHolder;
struct DomainObjectId;
class ServerMessageProcessor {
public:
/* Used to enabled templated message processors. */
virtual void SetImplementationProcessor(ServerMessageProcessor *impl) { /* ... */ }
virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const size_t headers_size) const = 0;
virtual Result GetInObjects(ServiceObjectHolder *in_objects) const = 0;
virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size, size_t &num_out_object_handles) = 0;
virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const size_t headers_size) = 0;
virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) = 0;
};
}

View File

@@ -0,0 +1,148 @@
/*
* 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 sts::sf::hipc {
class ServerSessionManager;
}
namespace sts::sf::cmif {
class ServerMessageProcessor;
struct HandlesToClose {
Handle handles[8];
size_t num_handles;
};
struct ServiceDispatchContext {
sf::IServiceObject *srv_obj;
hipc::ServerSessionManager *manager;
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 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;
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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 sts::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) { /* ... */ }
/* 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)) { /* ... */ }
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>
ServiceImpl *GetServiceObject() const {
if (this->GetServiceId() == GetServiceDispatchMeta<ServiceImpl>()->GetServiceId()) {
return static_cast<ServiceImpl *>(this->srv.get());
}
return nullptr;
}
sf::IServiceObject *GetServiceObjectUnsafe() const {
return this->srv.get();
}
/* Processing. */
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const;
};
}

View File

@@ -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 sts::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);
}

View File

@@ -0,0 +1,328 @@
/*
* 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"
namespace sts::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 ServerSessionManager {
NON_COPYABLE(ServerManagerBase);
NON_MOVEABLE(ServerManagerBase);
private:
enum class UserDataTag : uintptr_t {
Server = 1,
Session = 2,
MitmServer = 3,
};
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(new ::Service(), [](::Service *srv) {
serviceClose(srv);
delete srv;
});
/* Get mitm forward session. */
os::ProcessId client_pid;
ncm::TitleId client_tid;
R_ASSERT(sm::mitm::AcknowledgeSession(forward_service.get(), &client_pid, &client_tid, this->service_name));
*out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared(forward_service))));
*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;
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);
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();
STS_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);
}
protected:
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(&notify_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;
}
/* 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:
/* 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;
/* TODO: Domain resources. */
private:
constexpr inline size_t GetServerIndex(const ServerBase *server) const {
const size_t i = server - GetPointer(this->server_storages[0]);
STS_ASSERT(i < MaxServers);
return i;
}
constexpr inline size_t GetSessionIndex(const ServerSession *session) const {
const size_t i = session - GetPointer(this->session_storages[0]);
STS_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);
STS_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);
STS_ASSERT(this->server_allocated[index]);
server->~ServerBase();
this->server_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() {
/* Clear storages. */
std::memset(this->server_storages, 0, sizeof(this->server_storages));
std::memset(this->server_allocated, 0, sizeof(this->server_allocated));
std::memset(this->session_storages, 0, sizeof(this->session_storages));
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));
/* 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]));
}
}
}
};
}

View File

@@ -0,0 +1,156 @@
/*
* 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 sts::sf::hipc {
class ServerSessionManager;
class ServerManagerBase;
class ServerSession : public os::WaitableHolder {
friend class ServerSessionManager;
friend class ServerManagerBase;
NON_COPYABLE(ServerSession);
NON_MOVEABLE(ServerSession);
private:
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;
STS_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);
STS_ASSERT(this->IsMitmSession());
}
bool IsMitmSession() const {
return this->forward_service != nullptr;
}
};
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, ResultHipcSessionAllocationFailure);
/* 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);
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;
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);
}
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);
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);
};
}

View File

@@ -0,0 +1,308 @@
/*
* 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 sts::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");
}
}();
}
/* Helper structs for serialization of buffers. */
struct LargeData{};
struct PrefersMapAliasTransferMode{};
struct PrefersPointerTransferMode{};
struct PrefersAutoSelectTransferMode{};
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();
}
constexpr size_t GetSizeImpl() const {
return this->pas.GetSize();
}
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();
}
};
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();
}
};
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();
}
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();
}
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>");
}
}();
}

View File

@@ -0,0 +1,25 @@
/*
* 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 <type_traits>
#include <memory>
#include "../defines.hpp"
#include "../results.hpp"
#include "../util.hpp"
#include "../svc.hpp"
#include "../ams.hpp"
#include "../os.hpp"

View 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 sts::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>;
}

View File

@@ -0,0 +1,73 @@
/*
* 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 sts::sf {
namespace impl {
struct OutBaseTag{};
}
template<typename>
struct IsOutForceEnabled : public std::false_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 STS_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)");
};
}

View File

@@ -0,0 +1,43 @@
/*
* 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 sts::sf {
class IServiceObject{};
class IMitmServiceObject : public IServiceObject {
protected:
std::shared_ptr<::Service> forward_service;
os::ProcessId process_id;
ncm::TitleId title_id;
public:
IMitmServiceObject(std::shared_ptr<::Service> &&s, os::ProcessId p, ncm::TitleId t) : forward_service(std::move(s)), process_id(p), title_id(t) { /* ... */ }
static bool ShouldMitm(os::ProcessId process_id, ncm::TitleId title_id);
};
template<typename T>
struct ServiceObjectTraits {
static_assert(std::is_base_of<sts::sf::IServiceObject, T>::value, "ServiceObjectTraits requires ServiceObject");
static constexpr bool IsMitmServiceObject = std::is_base_of<IMitmServiceObject, T>::value;
};
}

View File

@@ -25,7 +25,7 @@ namespace sts::sm::mitm {
Result InstallMitm(Handle *out_port, Handle *out_query, ServiceName name);
Result UninstallMitm(ServiceName name);
Result DeclareFutureMitm(ServiceName name);
Result AcknowledgeSession(Service *out_service, u64 *out_pid, ncm::TitleId *out_tid, ServiceName name);
Result AcknowledgeSession(Service *out_service, os::ProcessId *out_pid, ncm::TitleId *out_tid, ServiceName name);
Result HasMitm(bool *out, ServiceName name);
Result WaitMitm(ServiceName name);

View File

@@ -20,6 +20,7 @@
#include <switch.h>
#include "../defines.hpp"
#include "../results.hpp"
#include "../os.hpp"
namespace sts::sm {
@@ -60,18 +61,15 @@ namespace sts::sm {
/* For Debug Monitor extensions. */
struct ServiceRecord {
ServiceName service;
u64 owner_pid;
os::ProcessId owner_pid;
u64 max_sessions;
u64 mitm_pid;
u64 mitm_waiting_ack_pid;
os::ProcessId mitm_pid;
os::ProcessId mitm_waiting_ack_pid;
bool is_light;
bool mitm_waiting_ack;
};
static_assert(sizeof(ServiceRecord) == 0x30, "ServiceRecord definition!");
/* For process validation. */
static constexpr u64 InvalidProcessId = static_cast<u64>(-1ull);
/* Utility, for scoped access to libnx services. */
template<Result Initializer(), void Finalizer()>
class ScopedServiceHolder {

View File

@@ -303,7 +303,7 @@ namespace sts::util {
iterator first(_first.GetNonConstIterator());
iterator last(_last.GetNonConstIterator());
first->Unlink(&*last);
pos->SplicePrev(&*first, &*last);
pos->SplicePrev(&*first, &*first);
}
};