diff --git a/stratosphere/libstratosphere/Makefile b/stratosphere/libstratosphere/Makefile
index 5a8943a..677d955 100644
--- a/stratosphere/libstratosphere/Makefile
+++ b/stratosphere/libstratosphere/Makefile
@@ -16,7 +16,7 @@
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
-SOURCES := source source/os source/os/impl source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb
+SOURCES := source source/ams source/os source/os/impl source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb
DATA := data
INCLUDES := include
diff --git a/stratosphere/libstratosphere/include/stratosphere.hpp b/stratosphere/libstratosphere/include/stratosphere.hpp
index 5c3d899..a5b239d 100644
--- a/stratosphere/libstratosphere/include/stratosphere.hpp
+++ b/stratosphere/libstratosphere/include/stratosphere.hpp
@@ -23,18 +23,13 @@
#include "stratosphere/version_check.hpp"
-#include "stratosphere/iwaitable.hpp"
-
-#include "stratosphere/waitable_manager.hpp"
-
-#include "stratosphere/ipc.hpp"
-#include "stratosphere/mitm.hpp"
-
#include "stratosphere/results.hpp"
#include "stratosphere/on_crash.hpp"
+#include "stratosphere/util.hpp"
#include "stratosphere/svc.hpp"
+#include "stratosphere/ams.hpp"
#include "stratosphere/os.hpp"
#include "stratosphere/cfg.hpp"
#include "stratosphere/fatal.hpp"
@@ -42,5 +37,4 @@
#include "stratosphere/ncm.hpp"
#include "stratosphere/pm.hpp"
#include "stratosphere/rnd.hpp"
-#include "stratosphere/sm.hpp"
-#include "stratosphere/util.hpp"
\ No newline at end of file
+#include "stratosphere/sm.hpp"
\ No newline at end of file
diff --git a/stratosphere/libstratosphere/include/stratosphere/ams.hpp b/stratosphere/libstratosphere/include/stratosphere/ams.hpp
new file mode 100644
index 0000000..4a679b3
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/ams.hpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "ams/ams_types.hpp"
+#include "ams/ams_firmware_version_api.hpp"
\ No newline at end of file
diff --git a/stratosphere/libstratosphere/include/stratosphere/ams/ams_firmware_version_api.hpp b/stratosphere/libstratosphere/include/stratosphere/ams/ams_firmware_version_api.hpp
new file mode 100644
index 0000000..d509d77
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/ams/ams_firmware_version_api.hpp
@@ -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 .
+ */
+
+#pragma once
+#include "ams_types.hpp"
+
+namespace sts::ams {
+
+ FirmwareVersion GetRuntimeFirmwareVersion();
+ void SetFirmwareVersionForLibnx();
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/ams/ams_types.hpp b/stratosphere/libstratosphere/include/stratosphere/ams/ams_types.hpp
new file mode 100644
index 0000000..9989e62
--- /dev/null
+++ b/stratosphere/libstratosphere/include/stratosphere/ams/ams_types.hpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include "../defines.hpp"
+
+/* 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 sts::ams {
+
+ enum TargetFirmware : u32 {
+ TargetFirmware_100 = 1,
+ TargetFirmware_200 = 2,
+ TargetFirmware_300 = 3,
+ TargetFirmware_400 = 4,
+ TargetFirmware_500 = 5,
+ TargetFirmware_600 = 6,
+ TargetFirmware_620 = 7,
+ TargetFirmware_700 = 8,
+ TargetFirmware_800 = 9,
+ TargetFirmware_810 = 10,
+ TargetFirmware_900 = 11,
+ };
+
+}
diff --git a/stratosphere/libstratosphere/include/stratosphere/firmware_version.hpp b/stratosphere/libstratosphere/include/stratosphere/firmware_version.hpp
deleted file mode 100644
index 3fc5507..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/firmware_version.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-
-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,
-};
-
-enum AtmosphereTargetFirmware : u32 {
- AtmosphereTargetFirmware_100 = 1,
- AtmosphereTargetFirmware_200 = 2,
- AtmosphereTargetFirmware_300 = 3,
- AtmosphereTargetFirmware_400 = 4,
- AtmosphereTargetFirmware_500 = 5,
- AtmosphereTargetFirmware_600 = 6,
- AtmosphereTargetFirmware_620 = 7,
- AtmosphereTargetFirmware_700 = 8,
- AtmosphereTargetFirmware_800 = 9,
- AtmosphereTargetFirmware_810 = 10,
- AtmosphereTargetFirmware_900 = 11,
-};
-
-FirmwareVersion GetRuntimeFirmwareVersion();
-
-void SetFirmwareVersionForLibnx();
\ No newline at end of file
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_buffers.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_buffers.hpp
deleted file mode 100644
index 903ee43..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_buffers.hpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-#include
-
-enum class IpcBufferType {
- InBuffer,
- OutBuffer,
- InPointer,
- OutPointer,
-};
-
-/* Base for In/Out Buffers. */
-struct IpcBufferBase {};
-
-struct InOutBufferBase : public IpcBufferBase {};
-
-/* Represents an A descriptor. */
-struct InBufferBase : public InOutBufferBase {};
-
-template
-struct InBuffer : public InBufferBase {
- T *buffer;
- size_t num_elements;
- BufferType type;
- static const BufferType expected_type = e_t;
-
- /* Convenience. */
- T& operator[](size_t i) const {
- return buffer[i];
- }
-
- InBuffer(void *b, size_t n, BufferType t) : buffer((T *)b), num_elements(n/sizeof(T)), type(t) { }
-};
-
-/* Represents a B descriptor. */
-struct OutBufferBase : public InOutBufferBase {};
-
-template
-struct OutBuffer : OutBufferBase {
- T *buffer;
- size_t num_elements;
- BufferType type;
- static const BufferType expected_type = e_t;
-
- /* Convenience. */
- T& operator[](size_t i) const {
- return buffer[i];
- }
-
- OutBuffer(void *b, size_t n, BufferType t) : buffer((T *)b), num_elements(n/sizeof(T)), type(t) { }
-};
-
-/* Represents an X descriptor. */
-struct InPointerBase : public IpcBufferBase {};
-
-template
-struct InPointer : public InPointerBase {
- T *pointer;
- size_t num_elements;
-
- /* Convenience. */
- T& operator[](size_t i) const {
- return pointer[i];
- }
-
- InPointer(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { }
-};
-
-/* Represents a C descriptor. */
-struct OutPointerWithServerSizeBase : public IpcBufferBase {};
-
-template
-struct OutPointerWithServerSize : public OutPointerWithServerSizeBase {
- T *pointer;
- static const size_t num_elements = N;
- static const size_t element_size = sizeof(T);
-
- /* Convenience. */
- T& operator[](size_t i) const {
- return pointer[i];
- }
-
- OutPointerWithServerSize(void *p) : pointer((T *)p) { }
- OutPointerWithServerSize(void *p, size_t n) : pointer((T *)p) { }
-};
-
-struct OutPointerWithClientSizeBase : public IpcBufferBase {};
-
-/* Represents a C descriptor with size in raw data. */
-template
-struct OutPointerWithClientSize : public OutPointerWithClientSizeBase {
- T *pointer;
- size_t num_elements;
-
- /* Convenience. */
- T& operator[](size_t i) const {
- return pointer[i];
- }
-
- OutPointerWithClientSize(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { }
-};
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_domain_object.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_domain_object.hpp
deleted file mode 100644
index 3cc9cbc..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_domain_object.hpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-#include
-#include
-#include
-
-#include "ipc_service_object.hpp"
-
-class IDomainObject;
-
-class DomainManager {
- public:
- static constexpr u32 MinimumDomainId = 1;
- public:
- virtual std::shared_ptr AllocateDomain() = 0;
- virtual void FreeDomain(IDomainObject *domain) = 0;
- virtual Result ReserveObject(IDomainObject *domain, u32 *out_object_id) = 0;
- virtual Result ReserveSpecificObject(IDomainObject *domain, u32 object_id) = 0;
- virtual void SetObject(IDomainObject *domain, u32 object_id, ServiceObjectHolder&& holder) = 0;
- virtual ServiceObjectHolder *GetObject(IDomainObject *domain, u32 object_id) = 0;
- virtual Result FreeObject(IDomainObject *domain, u32 object_id) = 0;
- virtual Result ForceFreeObject(u32 object_id) = 0;
-};
-
-class IDomainObject : public IServiceObject {
- private:
- DomainManager *manager;
- public:
- IDomainObject(DomainManager *m) : manager(m) {}
-
- virtual ~IDomainObject() override {
- this->manager->FreeDomain(this);
- }
-
- DomainManager *GetManager() {
- return this->manager;
- }
-
- ServiceObjectHolder *GetObject(u32 object_id) {
- return this->manager->GetObject(this, object_id);
- }
-
- Result ReserveObject(u32 *out_object_id) {
- return this->manager->ReserveObject(this, out_object_id);
- }
-
- Result ReserveSpecificObject(u32 object_id) {
- return this->manager->ReserveSpecificObject(this, object_id);
- }
-
- void SetObject(u32 object_id, ServiceObjectHolder&& holder) {
- this->manager->SetObject(this, object_id, std::move(holder));
- }
-
- Result FreeObject(u32 object_id) {
- return this->manager->FreeObject(this, object_id);
- }
-
- Result ForceFreeObject(u32 object_id) {
- return this->manager->ForceFreeObject(object_id);
- }
-
- public:
- DEFINE_SERVICE_DISPATCH_TABLE {
- /* IDomainObject has no callable functions. */
- };
-};
-
-static constexpr bool IsDomainObject(ServiceObjectHolder &holder) {
- return holder.GetServiceId() == ServiceObjectId();
-}
-
-static constexpr bool IsDomainObject(ServiceObjectHolder *holder) {
- return holder->GetServiceId() == ServiceObjectId();
-}
-
-/* Out for service impl. */
-template
-class Out> : public OutSessionTag {
- static_assert(std::is_base_of_v, "OutSessions must be shared_ptr!");
-
- template
- friend class Out;
-
- private:
- std::shared_ptr *srv;
- IDomainObject *domain = nullptr;
- u32 *object_id = nullptr;
- public:
- Out>(std::shared_ptr *s, IDomainObject *dm, u32 *o) : srv(reinterpret_cast *>(s)), domain(dm), object_id(o) { }
-
- ServiceObjectHolder GetHolder() {
- std::shared_ptr clone = *srv;
- return ServiceObjectHolder(std::move(clone));
- }
-
- bool IsDomain() {
- return domain != nullptr;
- }
-
- u32 GetObjectId() {
- return *object_id;
- }
-
- void ChangeObjectId(u32 o) {
- domain->ForceFreeObject(*object_id);
- domain->ReserveSpecificObject(o);
- *object_id = o;
- }
-
- void SetValue(std::shared_ptr &&s) {
- *this->srv = std::move(s);
- }
-};
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_out.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_out.hpp
deleted file mode 100644
index aba2254..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_out.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-#include
-
-/* Declare false allowed struct. */
-template
-struct AllowedOut : std::false_type {};
-
-struct OutDataTag{};
-struct OutHandleTag{};
-struct OutSessionTag{};
-
-/* Define out struct, so that we can get errors on enable_if */
-template
-class Out {
- static_assert(std::is_pod::value && !std::is_pod::value, "Invalid IPC Out Type!");
-};
-
-template
-class Out::value || AllowedOut::value>::type> : public OutDataTag {
-private:
- T *obj;
-public:
- Out(T *o) : obj(o) { }
-
- void SetValue(const T& t) {
- *obj = t;
- }
-
- const T& GetValue() {
- return *obj;
- }
-
- T *GetPointer() {
- return obj;
- }
-
- /* Convenience operators. */
- T& operator*() {
- return *obj;
- }
-
- T* operator->() {
- return obj;
- }
-};
-
-template
-class Out {
- static_assert(std::is_pod::value && !std::is_pod::value, "Invalid IPC Out Type (Raw Pointer)!");
-};
-
-template
-struct OutHelper;
-
-template
-struct OutHelper> {
- using type = T;
-};
\ No newline at end of file
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_response_context.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_response_context.hpp
deleted file mode 100644
index f1f8748..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_response_context.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-
-#include "ipc_service_object.hpp"
-#include "ipc_domain_object.hpp"
-
-#include "ipc_special.hpp"
-
-#include "ipc_session_manager_base.hpp"
-
-struct IpcResponseContext {
- /* Request/Reply data. */
- IpcParsedCommand request;
- IpcCommand reply;
- u8 out_data[0x100];
- std::shared_ptr *out_objs[8];
- Handle out_object_server_handles[8];
- IpcHandle out_handles[8];
- u32 out_object_ids[8];
- IpcCommandType cmd_type;
- u64 cmd_id;
- Result rc;
- /* Context. */
- SessionManagerBase *manager;
- ServiceObjectHolder *obj_holder;
- unsigned char *pb;
- size_t pb_size;
-};
\ No newline at end of file
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_serialization.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_serialization.hpp
deleted file mode 100644
index 278626c..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_serialization.hpp
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "../results.hpp"
-
-#include "ipc_out.hpp"
-#include "ipc_buffers.hpp"
-#include "ipc_special.hpp"
-
-#include "ipc_domain_object.hpp"
-
-#include "ipc_response_context.hpp"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-
-template
-struct TypeList{};
-
-template
-constexpr auto Concatenate(TypeList, TypeList) {
- return TypeList{};
-}
-
-template typename Condition, typename R>
-constexpr auto FilterTypes(R result, TypeList<>) {
- return result;
-}
-
-template typename Condition, typename R, typename T, typename... Ts>
-constexpr auto FilterTypes(R result, TypeList) {
- if constexpr (Condition{})
- return FilterTypes(Concatenate(result, TypeList{}), TypeList{});
- else
- return FilterTypes(result, TypeList{});
-}
-
-template struct TypeListToTuple;
-
-template
-struct TypeListToTuple> {
- using type = std::tuple;
-};
-
-template typename Condition, typename... Types>
-using FilteredTypes = typename TypeListToTuple(TypeList<>{}, TypeList{}))>>::type;
-
-enum class ArgType {
- InData,
- OutData,
- InHandle,
- OutHandle,
- InSession,
- OutSession,
- PidDesc,
- InBuffer,
- OutBuffer,
- InPointer,
- OutPointerClientSize,
- OutPointerServerSize,
-};
-
-template
-constexpr ArgType GetArgType() {
- if constexpr (std::is_base_of_v) {
- return ArgType::OutData;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::OutSession;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::OutHandle;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::InBuffer;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::OutBuffer;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::InPointer;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::OutPointerClientSize;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::OutPointerServerSize;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::PidDesc;
- } else if constexpr (std::is_base_of_v) {
- return ArgType::InHandle;
- } else if constexpr (std::is_trivial_v && !std::is_pointer_v) {
- return ArgType::InData;
- } else {
- static_assert(std::is_pod_v && !std::is_pod_v, "Unhandled InSession!");
- return ArgType::InSession;
- }
-}
-
-template
-struct ArgTypeFilter {
- template
- using type = std::conditional_t() == ArgT, std::true_type, std::false_type>;
-};
-
-template
-struct IsArgTypeBuffer {
- static constexpr bool value = ArgT == ArgType::InBuffer || ArgT == ArgType::OutBuffer || ArgT == ArgType::InPointer || ArgT == ArgType::OutPointerClientSize || ArgT == ArgType::OutPointerServerSize;
-};
-
-struct ArgTypeBufferFilter {
- template
- using type = std::conditional_t()>::value, std::true_type, std::false_type>;
-};
-
-template
-struct IsArgTypeInData {
- static constexpr bool value = ArgT == ArgType::InData || ArgT == ArgType::PidDesc;
-};
-
-struct ArgTypeInDataFilter {
- template
- using type = std::conditional_t()>::value, std::true_type, std::false_type>;
-};
-
-template
-struct RawDataHelper {
- static_assert(GetArgType() == ArgType::InData || GetArgType() == ArgType::PidDesc);
- static constexpr size_t align = (GetArgType() == ArgType::InData) ? __alignof__(T) : __alignof__(u64);
- static constexpr size_t size = (GetArgType() == ArgType::InData) ? sizeof(T) : sizeof(u64);
-};
-
-template
-struct RawDataHelper> {
- static_assert(GetArgType() == ArgType::InData);
- static constexpr size_t align = __alignof(T);
- static constexpr size_t size = sizeof(T);
-};
-
-template
-struct RawDataComputer;
-
-template
-struct RawDataComputer> {
- /* https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,2604 */
- static constexpr void QuickSort(std::array &map, std::array &values, int left, int right) {
- do {
- int i = left;
- int j = right;
- int x = map[i + ((j - i) >> 1)];
- do {
- while (i < static_cast(sizeof...(Ts)) && values[x] > values[map[i]]) i++;
- while (j >= 0 && values[x] < values[map[j]]) j--;
- if (i > j) break;
- if (i < j) {
- const size_t temp = map[i];
- map[i] = map[j];
- map[j] = temp;
- }
- i++;
- j--;
- } while (i <= j);
- if (j - left <= right - i) {
- if (left < j) QuickSort(map, values, left, j);
- left = i;
- } else {
- if (i < right) QuickSort(map, values, i, right);
- right = j;
- }
- } while (left < right);
- }
-
- static constexpr void StableSort(std::array &map, std::array &values) {
- /* First, quicksort a copy of the map. */
- std::array map_unstable(map);
- QuickSort(map_unstable, values, 0, sizeof...(Ts)-1);
-
- /* Now, create stable sorted map from unstably quicksorted indices (via repeated insertion sort on element runs). */
- for (size_t i = 0; i < sizeof...(Ts); i++) {
- map[i] = map_unstable[i];
- for (ssize_t j = i-1; j >= 0 && values[map[j]] == values[map[j+1]] && map[j] > map[j+1]; j--) {
- const size_t temp = map[j];
- map[j] = map[j+1];
- map[j+1] = temp;
- }
- }
- }
-
- static constexpr std::array GetOffsets() {
- std::array offsets = {};
- offsets[0] = 0;
- if constexpr (sizeof...(Ts) > 0) {
- /* Get size, alignment for each type. */
- std::array sizes = { RawDataHelper::size... };
- std::array aligns = { RawDataHelper::align... };
-
- /* We want to sort...by alignment. */
- std::array map = {};
- for (size_t i = 0; i < sizeof...(Ts); i++) { map[i] = i; }
- StableSort(map, aligns);
-
- /* Iterate over sorted types. */
- size_t cur_offset = 0;
- for (size_t i = 0; i < sizeof...(Ts); i++) {
- const size_t align = aligns[map[i]];
- if (cur_offset % align != 0) {
- cur_offset += align - (cur_offset % align);
- }
- offsets[map[i]] = cur_offset;
- cur_offset += sizes[map[i]];
- }
- offsets[sizeof...(Ts)] = cur_offset;
- }
- return offsets;
- }
-
- static constexpr std::array offsets = GetOffsets();
-};
-
-template
-struct CommandMetaInfo;
-
-template
-struct CommandMetaInfo, _ReturnType> {
- using Args = std::tuple<_Args...>;
- using ReturnType = _ReturnType;
-
- static constexpr bool ReturnsResult = std::is_same_v;
- static constexpr bool ReturnsVoid = std::is_same_v;
-
- using InDatas = FilteredTypes;
- using OutDatas = FilteredTypes::type, _Args...>;
- using InHandles = FilteredTypes::type, _Args...>;
- using OutHandles = FilteredTypes::type, _Args...>;
- using InSessions = FilteredTypes::type, _Args...>;
- using OutSessions = FilteredTypes::type, _Args...>;
- using PidDescs = FilteredTypes::type, _Args...>;
-
- using InBuffers = FilteredTypes::type, _Args...>;
- using OutBuffers = FilteredTypes::type, _Args...>;
- using InPointers = FilteredTypes::type, _Args...>;
- using ClientSizeOutPointers = FilteredTypes::type, _Args...>;
- using ServerSizeOutPointers = FilteredTypes::type, _Args...>;
- using Buffers = FilteredTypes;
-
- static constexpr size_t NumInDatas = std::tuple_size_v;
- static constexpr size_t NumOutDatas = std::tuple_size_v;
- static constexpr size_t NumInHandles = std::tuple_size_v;
- static constexpr size_t NumOutHandles = std::tuple_size_v;
- static constexpr size_t NumInSessions = std::tuple_size_v;
- static constexpr size_t NumOutSessions = std::tuple_size_v;
- static constexpr size_t NumPidDescs = std::tuple_size_v;
-
- static constexpr size_t NumInBuffers = std::tuple_size_v;
- static constexpr size_t NumOutBuffers = std::tuple_size_v;
- static constexpr size_t NumInPointers = std::tuple_size_v;
- static constexpr size_t NumClientSizeOutPointers = std::tuple_size_v;
- static constexpr size_t NumServerSizeOutPointers = std::tuple_size_v;
- static constexpr size_t NumBuffers = std::tuple_size_v;
-
- static_assert(NumInSessions == 0, "InSessions not yet supported!");
- static_assert(NumPidDescs == 0 || NumPidDescs == 1, "Methods can only take in 0 or 1 PIDs!");
- static_assert(NumBuffers <= 8, "Methods can only take in <= 8 Buffers!");
- static_assert(NumInHandles <= 8, "Methods can take in <= 8 Handles!");
- static_assert(NumOutHandles + NumOutSessions <= 8, "Methods can only return <= 8 Handles+Sessions!");
-
- static constexpr std::array InDataOffsets = RawDataComputer::offsets;
- static constexpr size_t InRawArgSize = InDataOffsets[NumInDatas];
- static constexpr size_t InRawArgSizeWithOutPointers = ((InRawArgSize + NumClientSizeOutPointers * sizeof(u16)) + 3) & ~3;
-
- static constexpr std::array OutDataOffsets = RawDataComputer::offsets;
- static constexpr size_t OutRawArgSize = OutDataOffsets[NumOutDatas];
-};
-
-
-/* ================================================================================= */
-/* Actual wrapping implementation goes here. */
-
-/* Validator. */
-struct Validator {
-
- template
- static constexpr bool ValidateCommandArgument(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& h_index, size_t& cur_c_size_offset, size_t& total_c_size) {
- constexpr ArgType argT = GetArgType();
- if constexpr (argT == ArgType::InBuffer) {
- return (ctx->request.Buffers[a_index] != nullptr || ctx->request.BufferSizes[a_index] == 0) && ctx->request.BufferDirections[a_index] == BufferDirection_Send && ctx->request.BufferTypes[a_index++] == T::expected_type;
- } else if constexpr (argT == ArgType::OutBuffer) {
- return (ctx->request.Buffers[b_index] != nullptr || ctx->request.BufferSizes[b_index] == 0) && ctx->request.BufferDirections[b_index] == BufferDirection_Recv && ctx->request.BufferTypes[b_index++] == T::expected_type;
- } else if constexpr (argT == ArgType::InPointer) {
- return ctx->request.Statics[x_index++] != nullptr;
- } else if constexpr (argT == ArgType::InHandle) {
- if constexpr (std::is_same_v) {
- return !ctx->request.WasHandleCopied[h_index++];
- } else if constexpr (std::is_same_v) {
- return ctx->request.WasHandleCopied[h_index++];
- }
- } else {
- if constexpr (argT == ArgType::OutPointerServerSize) {
- total_c_size += T::num_elements * sizeof(T);
- } else if constexpr (argT == ArgType::OutPointerClientSize) {
- total_c_size += *((u16 *)((uintptr_t)(ctx->request.Raw) + 0x10 + cur_c_size_offset));
- cur_c_size_offset += sizeof(u16);
- }
- return true;
- }
- }
-
- template
- struct ValidateCommandTuple;
-
- template
- struct ValidateCommandTuple> {
- static constexpr bool IsValid(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& h_index, size_t& cur_c_size_offset, size_t& total_c_size) {
- return (ValidateCommandArgument(ctx, a_index, b_index, x_index, h_index, cur_c_size_offset, total_c_size) && ...);
- }
- };
-
- template
- static constexpr Result Validate(IpcResponseContext *ctx) {
- if (ctx->request.RawSize < MetaInfo::InRawArgSizeWithOutPointers) {
- return ResultKernelConnectionClosed;
- }
-
- if (ctx->request.NumBuffers != MetaInfo::NumInBuffers + MetaInfo::NumOutBuffers) {
- return ResultKernelConnectionClosed;
- }
-
- if (ctx->request.NumStatics != MetaInfo::NumInPointers) {
- return ResultKernelConnectionClosed;
- }
-
- if (ctx->request.NumStaticsOut != MetaInfo::NumClientSizeOutPointers + MetaInfo::NumServerSizeOutPointers) {
- return ResultKernelConnectionClosed;
- }
-
- if (ctx->request.NumHandles != MetaInfo::NumInHandles) {
- return ResultKernelConnectionClosed;
- }
-
-
- if ((ctx->request.HasPid && MetaInfo::NumPidDescs == 0) || (!ctx->request.HasPid && MetaInfo::NumPidDescs != 0)) {
- return ResultKernelConnectionClosed;
- }
-
- if (((u32 *)ctx->request.Raw)[0] != SFCI_MAGIC) {
- return ResultKernelConnectionClosed;
- }
-
- size_t a_index = 0, b_index = MetaInfo::NumInBuffers, x_index = 0, h_index = 0;
- size_t cur_c_size_offset = MetaInfo::InRawArgSize + (0x10 - ((uintptr_t)ctx->request.Raw - (ctx->request.IsDomainRequest ? sizeof(DomainMessageHeader) : 0) - (uintptr_t)ctx->request.RawWithoutPadding));
- size_t total_c_size = 0;
-
- if (!ValidateCommandTuple::IsValid(ctx, a_index, b_index, x_index, h_index, cur_c_size_offset, total_c_size)) {
- return ResultKernelConnectionClosed;
- }
-
- if (total_c_size > ctx->pb_size) {
- return ResultKernelConnectionClosed;
- }
-
- return ResultSuccess;
- }
-};
-
-/* ================================================================================= */
-
-/* Decoder. */
-template
-struct Decoder {
-
- template
- static constexpr T DecodeCommandArgument(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& in_h_index, size_t& out_h_index, size_t& out_obj_index, size_t& in_data_index, size_t& out_data_index, size_t& pb_offset, size_t& c_sz_offset) {
- constexpr ArgType argT = GetArgType();
- if constexpr (argT == ArgType::InBuffer) {
- const T& value = T(ctx->request.Buffers[a_index], ctx->request.BufferSizes[a_index], ctx->request.BufferTypes[a_index]);
- ++a_index;
- return value;
- } else if constexpr (argT == ArgType::OutBuffer) {
- const T& value = T(ctx->request.Buffers[b_index], ctx->request.BufferSizes[b_index], ctx->request.BufferTypes[b_index]);
- ++b_index;
- return value;
- } else if constexpr (argT == ArgType::InPointer) {
- const T& value = T(ctx->request.Statics[x_index], ctx->request.StaticSizes[x_index]);
- ++x_index;
- return value;
- } else if constexpr (argT == ArgType::InHandle) {
- return T(ctx->request.Handles[in_h_index++]);
- } else if constexpr (argT == ArgType::OutHandle) {
- return T(&ctx->out_handles[out_h_index++]);
- } else if constexpr (argT == ArgType::PidDesc) {
- uintptr_t ptr = ((uintptr_t)ctx->request.Raw + 0x10 + MetaInfo::InDataOffsets[in_data_index++]);
- *(u64 *)ptr = ctx->request.Pid;
- return T(ctx->request.Pid);
- } else if constexpr (argT == ArgType::InData) {
- uintptr_t ptr = ((uintptr_t)ctx->request.Raw + 0x10 + MetaInfo::InDataOffsets[in_data_index++]);
- if constexpr (std::is_same_v) {
- return *((u8 *)ptr) & 1;
- } else {
- return *((T *)ptr);
- }
- } else if constexpr (argT == ArgType::OutData) {
- uintptr_t ptr = ((uintptr_t)ctx->out_data + MetaInfo::OutDataOffsets[out_data_index++]);
- return T(reinterpret_cast::type *>(ptr));
- } else if constexpr (argT == ArgType::OutPointerClientSize || argT == ArgType::OutPointerServerSize) {
- u16 sz;
- if constexpr(argT == ArgType::OutPointerServerSize) {
- sz = T::element_size;
- } else {
- sz = *(const u16 *)((uintptr_t)ctx->request.Raw + 0x10 + c_sz_offset);
- }
- u8* buf = ctx->pb + pb_offset;
- c_sz_offset += sizeof(u16);
- pb_offset += sz;
- ipcAddSendStatic(&ctx->reply, buf, sz, c_index++);
- return T(buf, sz);
- } else if constexpr (argT == ArgType::OutSession) {
- if (IsDomainObject(ctx->obj_holder)) {
- const T& value = T(ctx->out_objs[out_obj_index], ctx->obj_holder->GetServiceObject(), &ctx->out_object_ids[out_obj_index]);
- out_obj_index++;
- return value;
- } else {
- const T& value = T(ctx->out_objs[out_obj_index], nullptr, 0);
- out_obj_index++;
- return value;
- }
- }
- }
-
- template
- struct DecodeTuple;
-
- template
- struct DecodeTuple> {
- static constexpr std::tuple GetArgs(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& in_h_index, size_t& out_h_index, size_t& out_obj_index, size_t& in_data_index, size_t& out_data_index, size_t& pb_offset, size_t& c_sz_offset) {
- return std::tuple {
- DecodeCommandArgument(ctx, a_index, b_index, x_index, c_index, in_h_index, out_h_index, out_obj_index, in_data_index, out_data_index, pb_offset, c_sz_offset)
- ...
- };
- }
- };
-
-
- static constexpr typename MetaInfo::Args Decode(IpcResponseContext *ctx) {
- size_t a_index = 0, b_index = MetaInfo::NumInBuffers, x_index = 0, c_index = 0, in_h_index = 0, out_h_index = 0, out_obj_index = 0;
- size_t in_data_index = 0x0, out_data_index = 0, pb_offset = 0;
- size_t c_sz_offset = MetaInfo::InRawArgSize + (0x10 - ((uintptr_t)ctx->request.Raw - (ctx->request.IsDomainRequest ? sizeof(DomainMessageHeader) : 0) - (uintptr_t)ctx->request.RawWithoutPadding));
- return DecodeTuple::GetArgs(ctx, a_index, b_index, x_index, c_index, in_h_index, out_h_index, out_obj_index, in_data_index, out_data_index, pb_offset, c_sz_offset);
- }
-};
-
-/* ================================================================================= */
-
-template
-static constexpr void EncodeArgument(IpcResponseContext *ctx, size_t&out_obj_index, T& arg) {
- constexpr ArgType argT = GetArgType();
- if constexpr (argT == ArgType::OutHandle) {
- if constexpr (std::is_same_v::type>) {
- ipcSendHandleMove(&ctx->reply, arg.GetValue().handle);
- } else {
- ipcSendHandleCopy(&ctx->reply, arg.GetValue().handle);
- }
- } else if constexpr (argT == ArgType::OutSession) {
- if (IsDomainObject(ctx->obj_holder)) {
- auto domain = ctx->obj_holder->GetServiceObject();
- domain->SetObject(arg.GetObjectId(), std::move(arg.GetHolder()));
- } else {
- ctx->manager->AddSession(ctx->out_object_server_handles[out_obj_index++], std::move(arg.GetHolder()));
- }
- }
-}
-
-template
-struct Encoder;
-
-template
-struct Encoder> {
-
- static constexpr void EncodeFailure(IpcResponseContext *ctx, Result rc) {
- memset(armGetTls(), 0, 0x100);
- ipcInitialize(&ctx->reply);
- struct {
- u64 magic;
- u64 result;
- } *raw;
-
- if (IsDomainObject(ctx->obj_holder)) {
- raw = (decltype(raw))ipcPrepareHeaderForDomain(&ctx->reply, sizeof(*raw), 0);
- auto resp_header = (DomainResponseHeader *)((uintptr_t)raw - sizeof(DomainResponseHeader));
- *resp_header = {};
- } else {
- raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
- }
- raw->magic = SFCO_MAGIC;
- raw->result = rc;
- }
-
-
-
- static constexpr void EncodeSuccess(IpcResponseContext *ctx, Args... args) {
- size_t out_obj_index = 0;
-
- ((EncodeArgument(ctx, out_obj_index, args)), ...);
-
- const bool is_domain = IsDomainObject(ctx->obj_holder);
-
- if (!is_domain) {
- for (unsigned int i = 0; i < MetaInfo::NumOutSessions; i++) {
- ipcSendHandleMove(&ctx->reply, ctx->out_handles[MetaInfo::NumOutHandles + i].handle);
- }
- }
-
- struct {
- u64 magic;
- u64 result;
- } *raw;
- if (is_domain) {
- raw = (decltype(raw))ipcPrepareHeaderForDomain(&ctx->reply, sizeof(*raw) + MetaInfo::OutRawArgSize + sizeof(*ctx->out_object_ids) * MetaInfo::NumOutSessions, 0);
- auto resp_header = (DomainResponseHeader *)((uintptr_t)raw - sizeof(DomainResponseHeader));
- *resp_header = {};
- resp_header->NumObjectIds = MetaInfo::NumOutSessions;
- } else {
- raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw)+ MetaInfo::OutRawArgSize);
- }
-
- raw->magic = SFCO_MAGIC;
- raw->result = 0;
-
- memcpy((void *)((uintptr_t)raw + sizeof(*raw)), ctx->out_data, MetaInfo::OutRawArgSize);
- if (is_domain) {
- memcpy((void *)((uintptr_t)raw + sizeof(*raw) + MetaInfo::OutRawArgSize), ctx->out_object_ids, sizeof(*ctx->out_object_ids) * MetaInfo::NumOutSessions);
- }
- }
-
-};
-
-/* ================================================================================= */
-
-template
-struct MemberFunctionTraits {
- private:
- template
- static R GetReturnTypeImpl(R(C::*)(A...));
-
- template
- static C GetClassTypeImpl(R(C::*)(A...));
-
- template
- static std::tuple GetArgsImpl(R(C::*)(A...));
- public:
- using ReturnType = decltype(GetReturnTypeImpl(MemberFunction));
- using ClassType = decltype(GetClassTypeImpl(MemberFunction));
- using ArgsType = decltype(GetArgsImpl(MemberFunction));
-};
-
-template::ClassType>
-constexpr Result WrapIpcCommandImpl(IpcResponseContext *ctx) {
- using Traits = MemberFunctionTraits;
- using ArgsType = typename Traits::ArgsType;
- using ReturnType = typename Traits::ReturnType;
- using BaseClassType = typename Traits::ClassType;
- static_assert(std::is_base_of_v, "Override class type incorrect");
- using CommandMetaData = CommandMetaInfo;
-
- static_assert(CommandMetaData::ReturnsResult || CommandMetaData::ReturnsVoid, "IpcCommandImpls must return Result or void");
-
- ipcInitialize(&ctx->reply);
- memset(ctx->out_data, 0, CommandMetaData::OutRawArgSize);
-
- R_TRY(Validator::Validate(ctx));
-
- ClassType *this_ptr = nullptr;
- if (IsDomainObject(ctx->obj_holder)) {
- this_ptr = ctx->obj_holder->GetServiceObject()->GetObject(ctx->request.InThisObjectId)->GetServiceObject();
- } else {
- this_ptr = ctx->obj_holder->GetServiceObject();
- }
- if (this_ptr == nullptr) {
- return ResultServiceFrameworkTargetNotFound;
- }
-
- size_t num_out_objects;
- std::shared_ptr out_objects[CommandMetaData::NumOutSessions];
-
- auto cleanup_guard = SCOPE_GUARD {
- /* Clean up objects as necessary. */
- if (IsDomainObject(ctx->obj_holder)) {
- for (unsigned int i = 0; i < num_out_objects; i++) {
- ctx->obj_holder->GetServiceObject()->FreeObject(ctx->out_object_ids[i]);
- }
- } else {
- for (unsigned int i = 0; i < num_out_objects; i++) {
- svcCloseHandle(ctx->out_object_server_handles[i]);
- svcCloseHandle(ctx->out_handles[CommandMetaData::NumOutHandles + i].handle);
- }
- }
-
- for (unsigned int i = 0; i < num_out_objects; i++) {
- ctx->out_objs[i] = nullptr;
- }
- };
-
- /* Allocate out object IDs. */
- if (IsDomainObject(ctx->obj_holder)) {
- for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) {
- R_TRY_CLEANUP(ctx->obj_holder->GetServiceObject()->ReserveObject(&ctx->out_object_ids[num_out_objects]), {
- std::apply(Encoder::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(R_CLEANUP_RESULT)));
- });
- ctx->out_objs[num_out_objects] = &out_objects[num_out_objects];
- }
- } else {
- for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) {
- Handle server_h, client_h;
- R_TRY_CLEANUP(SessionManagerBase::CreateSessionHandles(&server_h, &client_h), {
- std::apply(Encoder::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(R_CLEANUP_RESULT)));
- });
- ctx->out_object_server_handles[num_out_objects] = server_h;
- ctx->out_handles[CommandMetaData::NumOutHandles + num_out_objects].handle = client_h;
- ctx->out_objs[num_out_objects] = &out_objects[num_out_objects];
- }
- }
-
- /* Decode, apply, encode. */
- {
- auto args = Decoder::Decode(ctx);
-
- if constexpr (CommandMetaData::ReturnsResult) {
- R_TRY_CLEANUP(std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args), {
- std::apply(Encoder::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(R_CLEANUP_RESULT)));
- });
- } else {
- std::apply( [=](auto&&... args) { (this_ptr->*IpcCommandImpl)(args...); }, args);
- }
-
- std::apply(Encoder::EncodeSuccess, std::tuple_cat(std::make_tuple(ctx), args));
- }
-
- /* Cancel object guard, clear remaining object references. */
- cleanup_guard.Cancel();
- for (unsigned int i = 0; i < num_out_objects; i++) {
- ctx->out_objs[i] = nullptr;
- }
-
- return ResultSuccess;
-}
-
-template
-inline static constexpr ServiceCommandMeta MakeServiceCommandMeta() {
- return {
- .fw_low = Low,
- .fw_high = High,
- .cmd_id = static_cast(CommandId),
- .handler = WrapIpcCommandImpl,
- };
-};
-
-#define MAKE_SERVICE_COMMAND_META(class, name, ...) MakeServiceCommandMeta()
-
-#pragma GCC diagnostic pop
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_object.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_object.hpp
deleted file mode 100644
index 0341c92..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_object.hpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-#include
-#include
-
-#include "ipc_out.hpp"
-
-#include "../firmware_version.hpp"
-
-class IpcResponseContext;
-
-struct ServiceCommandMeta {
- FirmwareVersion fw_low = FirmwareVersion_Max;
- FirmwareVersion fw_high = FirmwareVersion_Max;
- u32 cmd_id = 0;
- Result (*handler)(IpcResponseContext *) = nullptr;
-};
-
-class IServiceObject {
- public:
- virtual ~IServiceObject() { }
- virtual bool IsMitmObject() const { return false; }
-};
-
-#define SERVICE_DISPATCH_TABLE_NAME s_DispatchTable
-#define DEFINE_SERVICE_DISPATCH_TABLE static constexpr ServiceCommandMeta SERVICE_DISPATCH_TABLE_NAME[]
-
-template
-static constexpr size_t DispatchTableEntryCount() {
- static_assert(std::is_base_of::value, "DispatchTable owners must derive from IServiceObject");
- return sizeof(T::SERVICE_DISPATCH_TABLE_NAME)/sizeof(ServiceCommandMeta);
-}
-template
-static constexpr const ServiceCommandMeta* DispatchTable() {
- static_assert(std::is_base_of::value, "DispatchTable owners must derive from IServiceObject");
- return reinterpret_cast(&T::SERVICE_DISPATCH_TABLE_NAME);
-}
-
-template
-static constexpr uintptr_t ServiceObjectId() {
- static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject");
- return reinterpret_cast(&T::SERVICE_DISPATCH_TABLE_NAME);
-}
-
-class ServiceObjectHolder {
- private:
- std::shared_ptr srv;
- const ServiceCommandMeta *dispatch_table;
- size_t entry_count;
-
- /* Private copy constructor. */
- ServiceObjectHolder(const ServiceObjectHolder& other) : srv(other.srv), dispatch_table(other.dispatch_table), entry_count(other.entry_count) { }
- ServiceObjectHolder& operator=(const ServiceObjectHolder& other);
- public:
- /* Templated constructor ensures correct type id at runtime. */
- template
- explicit ServiceObjectHolder(std::shared_ptr&& s) : srv(std::move(s)), dispatch_table(DispatchTable()), entry_count(DispatchTableEntryCount()) { }
-
- template
- ServiceImpl *GetServiceObject() const {
- if (GetServiceId() == ServiceObjectId()) {
- return static_cast(this->srv.get());
- }
- return nullptr;
- }
-
- template
- ServiceImpl *GetServiceObjectUnsafe() const {
- return static_cast(this->srv.get());
- }
-
- const ServiceCommandMeta *GetDispatchTable() const {
- return this->dispatch_table;
- }
-
- size_t GetDispatchTableEntryCount() const {
- return this->entry_count;
- }
-
- constexpr uintptr_t GetServiceId() const {
- return reinterpret_cast(this->dispatch_table);
- }
-
- bool IsMitmObject() const {
- return this->srv->IsMitmObject();
- }
-
- /* Default constructor, move constructor, move assignment operator. */
- ServiceObjectHolder() : srv(nullptr), dispatch_table(nullptr) { }
-
- ServiceObjectHolder(ServiceObjectHolder&& other) : srv(std::move(other.srv)), dispatch_table(std::move(other.dispatch_table)), entry_count(std::move(other.entry_count)) { }
-
- ServiceObjectHolder& operator=(ServiceObjectHolder&& other) {
- this->srv = other.srv;
- this->dispatch_table = other.dispatch_table;
- this->entry_count = other.entry_count;
- other.Reset();
- return *this;
- }
-
- explicit operator bool() const {
- return this->srv != nullptr;
- }
-
- bool operator!() const {
- return this->srv == nullptr;
- }
-
- void Reset() {
- this->srv.reset();
- this->dispatch_table = nullptr;
- this->entry_count = 0;
- }
-
- ServiceObjectHolder Clone() const {
- ServiceObjectHolder clone(*this);
- return clone;
- }
-};
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_session.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_session.hpp
deleted file mode 100644
index e6efc3a..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_session.hpp
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-
-#include "../results.hpp"
-#include "../iwaitable.hpp"
-#include "ipc_service_object.hpp"
-#include "ipc_serialization.hpp"
-
-class ServiceSession : public IWaitable
-{
- protected:
- Handle session_handle;
- std::vector pointer_buffer;
- ServiceObjectHolder obj_holder;
- ServiceObjectHolder control_holder = ServiceObjectHolder(std::make_shared(this));
- u8 backup_tls[0x100];
-
- ServiceSession(Handle s_h) : session_handle(s_h) { }
- public:
- template
- ServiceSession(Handle s_h, size_t pbs) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::make_shared()) { }
-
- ServiceSession(Handle s_h, size_t pbs, ServiceObjectHolder &&h) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::move(h)) { }
-
- virtual ~ServiceSession() override {
- svcCloseHandle(this->session_handle);
- }
-
- SessionManagerBase *GetSessionManager() {
- return static_cast(this->GetManager());
- }
-
- DomainManager *GetDomainManager() {
- return static_cast(this->GetSessionManager());
- }
-
- Result Receive() {
- int handle_index;
- /* Prepare pointer buffer... */
- IpcCommand c;
- ipcInitialize(&c);
- if (this->pointer_buffer.size() > 0) {
- ipcAddRecvStatic(&c, this->pointer_buffer.data(), this->pointer_buffer.size(), 0);
- ipcPrepareHeader(&c, 0);
-
- /* Fix libnx bug in serverside C descriptor handling. */
- ((u32 *)armGetTls())[1] &= 0xFFFFC3FF;
- ((u32 *)armGetTls())[1] |= (2) << 10;
- } else {
- ipcPrepareHeader(&c, 0);
- }
-
- /* Receive. */
- R_TRY(svcReplyAndReceive(&handle_index, &this->session_handle, 1, 0, U64_MAX));
-
- std::memcpy(this->backup_tls, armGetTls(), sizeof(this->backup_tls));
- return ResultSuccess;
- }
-
- Result Reply() {
- int handle_index;
- return svcReplyAndReceive(&handle_index, &this->session_handle, 0, this->session_handle, 0);
- }
-
- /* For preparing basic replies. */
- Result PrepareBasicResponse(IpcResponseContext *ctx, Result rc) {
- ipcInitialize(&ctx->reply);
- struct {
- u64 magic;
- u64 result;
- } *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
-
- raw->magic = SFCO_MAGIC;
- raw->result = rc;
- return raw->result;
- }
-
- Result PrepareBasicDomainResponse(IpcResponseContext *ctx, Result rc) {
- ipcInitialize(&ctx->reply);
- struct {
- DomainResponseHeader hdr;
- u64 magic;
- u64 result;
- } *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw));
-
- raw->hdr = {};
- raw->magic = SFCO_MAGIC;
- raw->result = rc;
- return raw->result;
- }
-
- /* For making a new response context. */
- void InitializeResponseContext(IpcResponseContext *ctx) {
- std::memset(ctx, 0, sizeof(*ctx));
- ctx->manager = this->GetSessionManager();
- ctx->obj_holder = &this->obj_holder;
- ctx->pb = this->pointer_buffer.data();
- ctx->pb_size = this->pointer_buffer.size();
- }
-
- /* IWaitable */
- virtual Handle GetHandle() {
- return this->session_handle;
- }
-
- virtual Result GetResponse(IpcResponseContext *ctx) {
- FirmwareVersion fw = GetRuntimeFirmwareVersion();
-
- const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable();
- size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount();
-
- if (IsDomainObject(ctx->obj_holder)) {
- switch (ctx->request.InMessageType) {
- case DomainMessageType_Invalid:
- return ResultKernelConnectionClosed;
- case DomainMessageType_Close:
- return PrepareBasicDomainResponse(ctx, ctx->obj_holder->GetServiceObject()->FreeObject(ctx->request.InThisObjectId));
- case DomainMessageType_SendMessage:
- {
- auto sub_obj = ctx->obj_holder->GetServiceObject()->GetObject(ctx->request.InThisObjectId);
- if (sub_obj == nullptr) {
- return PrepareBasicDomainResponse(ctx, ResultHipcDomainObjectNotFound);
- }
- dispatch_table = sub_obj->GetDispatchTable();
- entry_count = sub_obj->GetDispatchTableEntryCount();
- }
- }
- }
-
- for (size_t i = 0; i < entry_count; i++) {
- if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) {
- R_TRY(dispatch_table[i].handler(ctx));
- break;
- }
- }
-
- return ResultSuccess;
- }
-
- virtual Result HandleReceived() {
- IpcResponseContext ctx;
- this->InitializeResponseContext(&ctx);
-
- ctx.cmd_type = (IpcCommandType)(*(u16 *)(armGetTls()));
-
- ctx.rc = ResultSuccess;
-
- /* Parse based on command type. */
- switch (ctx.cmd_type) {
- case IpcCommandType_Invalid:
- case IpcCommandType_LegacyRequest:
- case IpcCommandType_LegacyControl:
- return ResultKernelConnectionClosed;
- case IpcCommandType_Close:
- {
- /* Clean up gracefully. */
- PrepareBasicResponse(&ctx, 0);
- this->Reply();
- }
- return ResultKernelConnectionClosed;
- case IpcCommandType_Control:
- case IpcCommandType_ControlWithContext:
- ctx.rc = ipcParse(&ctx.request);
- ctx.obj_holder = &this->control_holder;
- break;
- case IpcCommandType_Request:
- case IpcCommandType_RequestWithContext:
- if (IsDomainObject(&this->obj_holder)) {
- ctx.rc = ipcParseDomainRequest(&ctx.request);
- } else {
- ctx.rc = ipcParse(&ctx.request);
- }
- break;
- default:
- return ResultKernelConnectionClosed;
- }
-
-
- if (R_SUCCEEDED(ctx.rc)) {
- ctx.cmd_id = ((u32 *)ctx.request.Raw)[2];
- this->PreProcessRequest(&ctx);
- ctx.rc = this->GetResponse(&ctx);
- }
-
- if (ctx.rc == ResultServiceFrameworkRequestDeferredByUser) {
- /* Session defer. */
- this->SetDeferred(true);
- } else if (ctx.rc == ResultKernelConnectionClosed) {
- /* Session close, nothing to do. */
- } else {
- if (R_SUCCEEDED(ctx.rc)) {
- this->PostProcessResponse(&ctx);
- }
-
- ctx.rc = this->Reply();
-
- if (ctx.rc == ResultKernelTimedOut) {
- ctx.rc = ResultSuccess;
- }
-
- this->CleanupResponse(&ctx);
- }
-
- return ctx.rc;
- }
-
- virtual Result HandleDeferred() override {
- memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls));
-
- auto defer_guard = SCOPE_GUARD {
- this->SetDeferred(false);
- };
-
- R_TRY_CATCH(this->HandleReceived()) {
- R_CATCH(ResultServiceFrameworkRequestDeferredByUser) {
- defer_guard.Cancel();
- return ResultServiceFrameworkRequestDeferredByUser;
- }
- } R_END_TRY_CATCH;
-
- return ResultSuccess;
- }
-
- virtual Result HandleSignaled(u64 timeout) {
- R_TRY(this->Receive());
- R_TRY(this->HandleReceived());
- return ResultSuccess;
- }
-
- virtual void PreProcessRequest(IpcResponseContext *ctx) {
- /* ... */
- (void)(ctx);
- }
-
- virtual void PostProcessResponse(IpcResponseContext *ctx) {
- /* ... */
- (void)(ctx);
- }
-
- virtual void CleanupResponse(IpcResponseContext *ctx) {
- std::memset(this->backup_tls, 0, sizeof(this->backup_tls));
- }
-
-
- public:
- class IHipcControlService : public IServiceObject {
- private:
- enum class CommandId {
- ConvertCurrentObjectToDomain = 0,
- CopyFromCurrentDomain = 1,
- CloneCurrentObject = 2,
- QueryPointerBufferSize = 3,
- CloneCurrentObjectEx = 4,
- };
- private:
- ServiceSession *session;
- public:
- explicit IHipcControlService(ServiceSession *s) : session(s) {
-
- }
-
- virtual ~IHipcControlService() override { }
-
- Result ConvertCurrentObjectToDomain(Out object_id) {
- /* Allocate new domain. */
- auto new_domain = this->session->GetDomainManager()->AllocateDomain();
- if (new_domain == nullptr) {
- return ResultHipcOutOfDomains;
- }
-
- /* Reserve an object in the domain for our session. */
- u32 reserved_id;
- R_TRY(new_domain->ReserveObject(&reserved_id));
- new_domain->SetObject(reserved_id, std::move(this->session->obj_holder));
- this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain)));
-
- /* Return the object id. */
- object_id.SetValue(reserved_id);
- return ResultSuccess;
- }
-
- Result CopyFromCurrentDomain(Out out_h, u32 id) {
- auto domain = this->session->obj_holder.GetServiceObject();
- if (domain == nullptr) {
- return ResultHipcTargetNotDomain;
- }
-
-
- auto object = domain->GetObject(id);
- if (object == nullptr) {
- return ResultHipcDomainObjectNotFound;
- }
-
- Handle server_h, client_h;
- R_ASSERT(SessionManagerBase::CreateSessionHandles(&server_h, &client_h));
-
- this->session->GetSessionManager()->AddSession(server_h, std::move(object->Clone()));
- out_h.SetValue(client_h);
- return ResultSuccess;
- }
-
- void CloneCurrentObject(Out out_h) {
- Handle server_h, client_h;
- R_ASSERT(SessionManagerBase::CreateSessionHandles(&server_h, &client_h));
-
- this->session->GetSessionManager()->AddSession(server_h, std::move(this->session->obj_holder.Clone()));
- out_h.SetValue(client_h);
- }
-
- void QueryPointerBufferSize(Out size) {
- size.SetValue(this->session->pointer_buffer.size());
- }
-
- void CloneCurrentObjectEx(Out out_h, u32 which) {
- /* TODO: Figure out what this u32 controls. */
- return CloneCurrentObject(out_h);
- }
-
- public:
- DEFINE_SERVICE_DISPATCH_TABLE {
- MAKE_SERVICE_COMMAND_META(ServiceSession::IHipcControlService, ConvertCurrentObjectToDomain),
- MAKE_SERVICE_COMMAND_META(ServiceSession::IHipcControlService, CopyFromCurrentDomain),
- MAKE_SERVICE_COMMAND_META(ServiceSession::IHipcControlService, CloneCurrentObject),
- MAKE_SERVICE_COMMAND_META(ServiceSession::IHipcControlService, QueryPointerBufferSize),
- MAKE_SERVICE_COMMAND_META(ServiceSession::IHipcControlService, CloneCurrentObjectEx),
- };
- };
-};
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_session_manager_base.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_session_manager_base.hpp
deleted file mode 100644
index ed98011..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_session_manager_base.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-
-#include "../waitable_manager_base.hpp"
-#include "ipc_service_object.hpp"
-
-class SessionManagerBase : public WaitableManagerBase, public DomainManager {
- public:
- SessionManagerBase() = default;
- virtual ~SessionManagerBase() = default;
-
- virtual void AddSession(Handle server_h, ServiceObjectHolder &&service) = 0;
-
- static Result CreateSessionHandles(Handle *server_h, Handle *client_h) {
- return svcCreateSession(server_h, client_h, 0, 0);
- }
-};
-
diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_special.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_special.hpp
deleted file mode 100644
index 044a7f4..0000000
--- a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_special.hpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-#include
-#include
-
-#include "ipc_out.hpp"
-
-/* Represents an input PID. */
-struct PidDescriptorTag{};
-
-struct PidDescriptor : public PidDescriptorTag {
- u64 pid;
-
- void operator=(u64 &p) {
- pid = p;
- }
-
- PidDescriptor(u64 p) : pid(p) { }
-};
-
-struct IpcHandleTag{};
-
-struct IpcHandle : public IpcHandleTag {
- Handle handle;
-};
-
-/* Represents a moved handle. */
-struct MovedHandle : public IpcHandle {
- void operator=(const Handle &h) {
- this->handle = h;
- }
-
- void operator=(const IpcHandle &o) {
- this->handle = o.handle;
- }
-
- MovedHandle(Handle h) {
- this->handle = h;
- }
-
- Handle GetValue() const {
- return this->handle;
- }
-};
-
-/* Represents a copied handle. */
-struct CopiedHandle : public IpcHandle {
- void operator=(const Handle &h) {
- handle = h;
- }
-
- void operator=(const IpcHandle &o) {
- this->handle = o.handle;
- }
-
- CopiedHandle(Handle h) {
- this->handle = h;
- }
-
- Handle GetValue() const {
- return this->handle;
- }
-};
-
-template <>
-class Out : public OutHandleTag {
-private:
- MovedHandle *obj;
-public:
- Out(IpcHandle *o) : obj(static_cast(o)) { }
-
- void SetValue(const Handle& h) {
- *obj = h;
- }
-
- void SetValue(const MovedHandle& o) {
- *obj = o;
- }
-
- const MovedHandle& GetValue() {
- return *obj;
- }
-
- MovedHandle* GetPointer() {
- return obj;
- }
-
- Handle* GetHandlePointer() {
- return &obj->handle;
- }
-
- /* Convenience operators. */
- MovedHandle& operator*() {
- return *obj;
- }
-
- MovedHandle* operator->() {
- return obj;
- }
-};
-
-template <>
-class Out : public OutHandleTag {
-private:
- CopiedHandle *obj;
-public:
- Out(IpcHandle *o) : obj(static_cast