diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index 2f8a520ba9..16f51a6356 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -144,6 +144,16 @@ struct DataPayloadHeader {
 };
 static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadRequest size is incorrect");
 
+struct DomainMessageHeader {
+    union {
+        BitField<0, 8, u32_le> command;
+        BitField<16, 16, u32_le> size;
+    };
+    u32_le object_id;
+    INSERT_PADDING_WORDS(2);
+};
+static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect");
+
 enum DescriptorType : u32 {
     // Buffer related desciptors types (mask : 0x0F)
     StaticBuffer = 0x02,
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 083d3a0d05..41899c519b 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -80,7 +80,7 @@ public:
         AlignWithPadding();
 
         IPC::DataPayloadHeader data_payload_header{};
-        data_payload_header.magic = 0x4f434653;
+        data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
         PushRaw(data_payload_header);
     }
 
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index b7070af03c..35cac68f1a 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -4,6 +4,7 @@
 
 #include <boost/range/algorithm_ext/erase.hpp>
 #include "common/assert.h"
+#include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/kernel/handle_table.h"
@@ -45,10 +46,15 @@ void HLERequestContext::ClearIncomingObjects() {
     request_handles.clear();
 }
 
-void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf) {
+void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
     IPC::RequestParser rp(src_cmdbuf);
     command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>());
 
+    if (command_header->type == IPC::CommandType::Close) {
+        // Close does not populate the rest of the IPC header
+        return;
+    }
+
     // If handle descriptor is present, add size of it
     if (command_header->enable_handle_descriptor) {
         handle_descriptor_header =
@@ -80,9 +86,18 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf) {
         UNIMPLEMENTED();
     }
 
+    if (incoming && Session()->IsDomain()) {
+        domain_message_header = std::make_unique<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>());
+    }
+
     data_payload_header =
         std::make_unique<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>());
-    ASSERT(data_payload_header->magic == 0x49434653 || data_payload_header->magic == 0x4F434653);
+
+    if (incoming) {
+        ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
+    } else {
+        ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
+    }
 
     data_payload_offset = rp.GetCurrentOffset();
     command = rp.Pop<u32_le>();
@@ -91,7 +106,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf) {
 ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf,
                                                                 Process& src_process,
                                                                 HandleTable& src_table) {
-    ParseCommandBuffer(src_cmdbuf);
+    ParseCommandBuffer(src_cmdbuf, true);
     size_t untranslated_size = data_payload_offset + command_header->data_size;
     std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin());
 
@@ -106,7 +121,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
 
 ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
                                                            HandleTable& dst_table) {
-    ParseCommandBuffer(&cmd_buf[0]);
+    ParseCommandBuffer(&cmd_buf[0], false);
     size_t untranslated_size = data_payload_offset + command_header->data_size;
     std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf);
 
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 32a528968a..17baffc06e 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -119,7 +119,7 @@ public:
      */
     void ClearIncomingObjects();
 
-    void ParseCommandBuffer(u32_le* src_cmdbuf);
+    void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
 
     /// Populates this context with data from the requesting process/thread.
     ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process,
@@ -149,6 +149,7 @@ private:
     std::unique_ptr<IPC::CommandHeader> command_header;
     std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header;
     std::unique_ptr<IPC::DataPayloadHeader> data_payload_header;
+    std::unique_ptr<IPC::DomainMessageHeader> domain_message_header;
 
     unsigned data_payload_offset{};
     u32_le command{};
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index f4360ddf32..78db5510d4 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -91,6 +91,14 @@ public:
     /// TODO(Subv): Find a better name for this.
     SharedPtr<Thread> currently_handling;
 
+    void ConvertToDomain() {
+        is_domain = true;
+    }
+
+    bool IsDomain() const {
+        return is_domain;
+    }
+
 private:
     ServerSession();
     ~ServerSession() override;
@@ -102,6 +110,8 @@ private:
      * @return The created server session
      */
     static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
+
+    bool is_domain{};
 };
 
 /**
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 3c5fa7de30..d66ac55cac 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -18,7 +18,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
  *  Inputs:
  *      0: 0x00000000
  *  Outputs:
- *      1: ResultCode
+ *      0: ResultCode
  */
 void LM::Initialize(Kernel::HLERequestContext& ctx) {
     IPC::RequestBuilder rb{ctx, 1};
@@ -29,10 +29,6 @@ void LM::Initialize(Kernel::HLERequestContext& ctx) {
 LM::LM() : ServiceFramework("lm") {
     static const FunctionInfo functions[] = {
         {0x00000000, &LM::Initialize, "Initialize"},
-        {0x00000001, nullptr, "Unknown2"},
-        {0x00000002, nullptr, "Unknown3"},
-        {0x00000003, nullptr, "Unknown4"},
-        {0x00000004, nullptr, "Unknown5"},
     };
     RegisterHandlers(functions);
 }
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 1532776814..240d797153 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -10,11 +10,11 @@
 #include "core/hle/ipc.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/thread.h"
-#include "core/hle/kernel/handle_table.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/apm/apm.h"
 #include "core/hle/service/dsp_dsp.h"
@@ -82,7 +82,8 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function
     }
 }
 
-void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info) {
+void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx,
+                                                       const FunctionInfoBase* info) {
     auto cmd_buf = ctx.CommandBuffer();
     std::string function_name = info == nullptr ? fmt::format("{:#08x}", cmd_buf[0]) : info->name;
 
@@ -96,7 +97,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
 
     LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str());
     // TODO(bunnei): Hack - ignore error
-    IPC::RequestBuilder rb{ ctx, 1 };
+    IPC::RequestBuilder rb{ctx, 1};
     rb.Push(RESULT_SUCCESS);
 }
 
@@ -107,13 +108,14 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
         return ReportUnimplementedFunction(ctx, info);
     }
 
-    LOG_TRACE(Service, "%s",
+    LOG_TRACE(
+        Service, "%s",
         MakeFunctionString(info->name, GetServiceName().c_str(), ctx.CommandBuffer()).c_str());
     handler_invoker(this, info->handler_callback, ctx);
 }
 
 void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_session) {
-    u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());;
+    u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
 
     // TODO(yuriks): The kernel should be the one handling this as part of translation after
     // everything else is migrated
@@ -122,19 +124,16 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses
                                               Kernel::g_handle_table);
 
     switch (context.GetCommandType()) {
-    case IPC::CommandType::Close:
-    {
+    case IPC::CommandType::Close: {
         IPC::RequestBuilder rb{context, 1};
         rb.Push(RESULT_SUCCESS);
         break;
     }
-    case IPC::CommandType::Control:
-    {
+    case IPC::CommandType::Control: {
         SM::g_service_manager->InvokeControlRequest(context);
         break;
     }
-    case IPC::CommandType::Request:
-    {
+    case IPC::CommandType::Request: {
         InvokeRequest(context);
         break;
     }
@@ -176,4 +175,4 @@ void Shutdown() {
     g_kernel_named_ports.clear();
     LOG_DEBUG(Service, "shutdown OK");
 }
-}
+} // namespace Service
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 4b250d6ba6..174ee81610 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -9,25 +9,43 @@
 namespace Service {
 namespace SM {
 
+/**
+ * Controller::ConvertSessionToDomain service function
+ *  Inputs:
+ *      0: 0x00000000
+ *  Outputs:
+ *      0: ResultCode
+ *      2: Handle of domain
+ */
+void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
+    ctx.Session()->ConvertToDomain();
+    IPC::RequestBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Skip(1, true);
+    Kernel::Handle handle = Kernel::g_handle_table.Create(ctx.Session()).Unwrap();
+    rb.Push(handle);
+    LOG_DEBUG(Service, "called, handle=0x%08x", handle);
+}
+
 /**
  * Controller::QueryPointerBufferSize service function
  *  Inputs:
  *      0: 0x00000003
  *  Outputs:
- *      1: ResultCode
- *      3: Size of memory
+ *      0: ResultCode
+ *      2: Size of memory
  */
 void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
-    IPC::RequestBuilder rb{ctx, 2};
+    IPC::RequestBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
-    rb.Push(0x0U);
-    rb.Push(0x500U);
+    rb.Skip(1, true);
+    rb.Push<u32>(0x500);
     LOG_WARNING(Service, "(STUBBED) called");
 }
 
 Controller::Controller() : ServiceFramework("IpcController") {
     static const FunctionInfo functions[] = {
-        {0x00000000, nullptr, "ConvertSessionToDomain"},
+        {0x00000000, &Controller::ConvertSessionToDomain, "ConvertSessionToDomain"},
         {0x00000001, nullptr, "ConvertDomainToSession"},
         {0x00000002, nullptr, "DuplicateSession"},
         {0x00000003, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"},
diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h
index c6aa6f5022..bb5a815f8f 100644
--- a/src/core/hle/service/sm/controller.h
+++ b/src/core/hle/service/sm/controller.h
@@ -15,6 +15,7 @@ public:
     ~Controller();
 
 private:
+    void ConvertSessionToDomain(Kernel::HLERequestContext& ctx);
     void QueryPointerBufferSize(Kernel::HLERequestContext& ctx);
 };
 
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index b027651d00..e77ec8df96 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -80,7 +80,7 @@ std::shared_ptr<ServiceManager> g_service_manager;
  *  Inputs:
  *      0: 0x00000000
  *  Outputs:
- *      1: ResultCode
+ *      0: ResultCode
  */
 void SM::Initialize(Kernel::HLERequestContext& ctx) {
     IPC::RequestBuilder rb{ctx, 1};
@@ -89,15 +89,14 @@ void SM::Initialize(Kernel::HLERequestContext& ctx) {
 }
 
 /**
- * SM::GetServiceHandle service function
+ * SM::GetService service function
  *  Inputs:
  *      0: 0x00000001
  *      1: Unknown
  *      2: Unknown
  *      3-4: 8-byte UTF-8 service name
  *  Outputs:
- *      1: ResultCode
- *      3: Service handle
+ *      0: ResultCode
  */
 void SM::GetService(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};