diff options
| author | 2021-05-15 22:30:21 -0700 | |
|---|---|---|
| committer | 2021-05-15 22:30:21 -0700 | |
| commit | 5a2b15bf75318987d773a2bc69bd6224a28b7939 (patch) | |
| tree | f213f5b011410022e8e98f7c3905d16d575ed413 | |
| parent | Merge pull request #6289 from ameerj/oob-blit (diff) | |
| parent | common: tree: Avoid a nullptr dereference. (diff) | |
| download | yuzu-5a2b15bf75318987d773a2bc69bd6224a28b7939.tar.gz yuzu-5a2b15bf75318987d773a2bc69bd6224a28b7939.tar.xz yuzu-5a2b15bf75318987d773a2bc69bd6224a28b7939.zip | |
Merge pull request #6299 from bunnei/ipc-improvements
Various improvements to IPC and session management
| -rw-r--r-- | src/common/tree.h | 2 | ||||
| -rw-r--r-- | src/core/hle/ipc.h | 17 | ||||
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 56 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 145 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 26 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_session.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/slab_helpers.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/service/audio/audren_u.cpp | 39 | ||||
| -rw-r--r-- | src/core/hle/service/audio/audren_u.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 55 | ||||
| -rw-r--r-- | src/core/hle/service/service.h | 35 | ||||
| -rw-r--r-- | src/core/hle/service/sm/controller.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 107 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.h | 10 |
19 files changed, 354 insertions, 220 deletions
diff --git a/src/common/tree.h b/src/common/tree.h index 3da49e422..9d2d0df4e 100644 --- a/src/common/tree.h +++ b/src/common/tree.h | |||
| @@ -322,7 +322,7 @@ void RB_INSERT_COLOR(RBHead<Node>* head, Node* elm) { | |||
| 322 | template <typename Node> | 322 | template <typename Node> |
| 323 | void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { | 323 | void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { |
| 324 | Node* tmp; | 324 | Node* tmp; |
| 325 | while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root()) { | 325 | while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root() && parent != nullptr) { |
| 326 | if (RB_LEFT(parent) == elm) { | 326 | if (RB_LEFT(parent) == elm) { |
| 327 | tmp = RB_RIGHT(parent); | 327 | tmp = RB_RIGHT(parent); |
| 328 | if (RB_IS_RED(tmp)) { | 328 | if (RB_IS_RED(tmp)) { |
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 55b1716e4..602e12606 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -32,7 +32,8 @@ enum class CommandType : u32 { | |||
| 32 | Control = 5, | 32 | Control = 5, |
| 33 | RequestWithContext = 6, | 33 | RequestWithContext = 6, |
| 34 | ControlWithContext = 7, | 34 | ControlWithContext = 7, |
| 35 | Unspecified, | 35 | TIPC_Close = 15, |
| 36 | TIPC_CommandRegion = 16, // Start of TIPC commands, this is an offset. | ||
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 38 | struct CommandHeader { | 39 | struct CommandHeader { |
| @@ -57,6 +58,20 @@ struct CommandHeader { | |||
| 57 | BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; | 58 | BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; |
| 58 | BitField<31, 1, u32> enable_handle_descriptor; | 59 | BitField<31, 1, u32> enable_handle_descriptor; |
| 59 | }; | 60 | }; |
| 61 | |||
| 62 | bool IsTipc() const { | ||
| 63 | return type.Value() >= CommandType::TIPC_CommandRegion; | ||
| 64 | } | ||
| 65 | |||
| 66 | bool IsCloseCommand() const { | ||
| 67 | switch (type.Value()) { | ||
| 68 | case CommandType::Close: | ||
| 69 | case CommandType::TIPC_Close: | ||
| 70 | return true; | ||
| 71 | default: | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | } | ||
| 60 | }; | 75 | }; |
| 61 | static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); | 76 | static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); |
| 62 | 77 | ||
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index d136be452..5fed3dbf5 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | #include "core/hle/ipc.h" | 15 | #include "core/hle/ipc.h" |
| 16 | #include "core/hle/kernel/hle_ipc.h" | 16 | #include "core/hle/kernel/hle_ipc.h" |
| 17 | #include "core/hle/kernel/k_client_port.h" | 17 | #include "core/hle/kernel/k_client_port.h" |
| 18 | #include "core/hle/kernel/k_process.h" | ||
| 19 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 18 | #include "core/hle/kernel/k_session.h" | 20 | #include "core/hle/kernel/k_session.h" |
| 19 | #include "core/hle/result.h" | 21 | #include "core/hle/result.h" |
| 20 | 22 | ||
| @@ -26,7 +28,7 @@ class RequestHelperBase { | |||
| 26 | protected: | 28 | protected: |
| 27 | Kernel::HLERequestContext* context = nullptr; | 29 | Kernel::HLERequestContext* context = nullptr; |
| 28 | u32* cmdbuf; | 30 | u32* cmdbuf; |
| 29 | ptrdiff_t index = 0; | 31 | u32 index = 0; |
| 30 | 32 | ||
| 31 | public: | 33 | public: |
| 32 | explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {} | 34 | explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {} |
| @@ -38,7 +40,7 @@ public: | |||
| 38 | if (set_to_null) { | 40 | if (set_to_null) { |
| 39 | memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); | 41 | memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); |
| 40 | } | 42 | } |
| 41 | index += static_cast<ptrdiff_t>(size_in_words); | 43 | index += size_in_words; |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | /** | 46 | /** |
| @@ -51,11 +53,11 @@ public: | |||
| 51 | } | 53 | } |
| 52 | 54 | ||
| 53 | u32 GetCurrentOffset() const { | 55 | u32 GetCurrentOffset() const { |
| 54 | return static_cast<u32>(index); | 56 | return index; |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 57 | void SetCurrentOffset(u32 offset) { | 59 | void SetCurrentOffset(u32 offset) { |
| 58 | index = static_cast<ptrdiff_t>(offset); | 60 | index = offset; |
| 59 | } | 61 | } |
| 60 | }; | 62 | }; |
| 61 | 63 | ||
| @@ -84,7 +86,9 @@ public: | |||
| 84 | 86 | ||
| 85 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory | 87 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory |
| 86 | // padding. | 88 | // padding. |
| 87 | u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; | 89 | u32 raw_data_size = ctx.IsTipc() |
| 90 | ? normal_params_size - 1 | ||
| 91 | : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; | ||
| 88 | 92 | ||
| 89 | u32 num_handles_to_move{}; | 93 | u32 num_handles_to_move{}; |
| 90 | u32 num_domain_objects{}; | 94 | u32 num_domain_objects{}; |
| @@ -97,9 +101,14 @@ public: | |||
| 97 | } | 101 | } |
| 98 | 102 | ||
| 99 | if (ctx.Session()->IsDomain()) { | 103 | if (ctx.Session()->IsDomain()) { |
| 100 | raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; | 104 | raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects); |
| 101 | } | 105 | } |
| 102 | 106 | ||
| 107 | if (ctx.IsTipc()) { | ||
| 108 | header.type.Assign(ctx.GetCommandType()); | ||
| 109 | } | ||
| 110 | |||
| 111 | ctx.data_size = static_cast<u32>(raw_data_size); | ||
| 103 | header.data_size.Assign(static_cast<u32>(raw_data_size)); | 112 | header.data_size.Assign(static_cast<u32>(raw_data_size)); |
| 104 | if (num_handles_to_copy || num_handles_to_move) { | 113 | if (num_handles_to_copy || num_handles_to_move) { |
| 105 | header.enable_handle_descriptor.Assign(1); | 114 | header.enable_handle_descriptor.Assign(1); |
| @@ -111,22 +120,30 @@ public: | |||
| 111 | handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy); | 120 | handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy); |
| 112 | handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move); | 121 | handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move); |
| 113 | PushRaw(handle_descriptor_header); | 122 | PushRaw(handle_descriptor_header); |
| 123 | |||
| 124 | ctx.handles_offset = index; | ||
| 125 | |||
| 114 | Skip(num_handles_to_copy + num_handles_to_move, true); | 126 | Skip(num_handles_to_copy + num_handles_to_move, true); |
| 115 | } | 127 | } |
| 116 | 128 | ||
| 117 | AlignWithPadding(); | 129 | if (!ctx.IsTipc()) { |
| 130 | AlignWithPadding(); | ||
| 118 | 131 | ||
| 119 | if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) { | 132 | if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) { |
| 120 | IPC::DomainMessageHeader domain_header{}; | 133 | IPC::DomainMessageHeader domain_header{}; |
| 121 | domain_header.num_objects = num_domain_objects; | 134 | domain_header.num_objects = num_domain_objects; |
| 122 | PushRaw(domain_header); | 135 | PushRaw(domain_header); |
| 136 | } | ||
| 137 | |||
| 138 | IPC::DataPayloadHeader data_payload_header{}; | ||
| 139 | data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O'); | ||
| 140 | PushRaw(data_payload_header); | ||
| 123 | } | 141 | } |
| 124 | 142 | ||
| 125 | IPC::DataPayloadHeader data_payload_header{}; | 143 | data_payload_index = index; |
| 126 | data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O'); | ||
| 127 | PushRaw(data_payload_header); | ||
| 128 | 144 | ||
| 129 | datapayload_index = index; | 145 | ctx.data_payload_offset = index; |
| 146 | ctx.domain_offset = index + raw_data_size / 4; | ||
| 130 | } | 147 | } |
| 131 | 148 | ||
| 132 | template <class T> | 149 | template <class T> |
| @@ -134,6 +151,9 @@ public: | |||
| 134 | if (context->Session()->IsDomain()) { | 151 | if (context->Session()->IsDomain()) { |
| 135 | context->AddDomainObject(std::move(iface)); | 152 | context->AddDomainObject(std::move(iface)); |
| 136 | } else { | 153 | } else { |
| 154 | // kernel.CurrentProcess()->GetResourceLimit()->Reserve( | ||
| 155 | // Kernel::LimitableResource::Sessions, 1); | ||
| 156 | |||
| 137 | auto* session = Kernel::KSession::Create(kernel); | 157 | auto* session = Kernel::KSession::Create(kernel); |
| 138 | session->Initialize(nullptr, iface->GetServiceName()); | 158 | session->Initialize(nullptr, iface->GetServiceName()); |
| 139 | 159 | ||
| @@ -152,7 +172,7 @@ public: | |||
| 152 | const std::size_t num_move_objects = context->NumMoveObjects(); | 172 | const std::size_t num_move_objects = context->NumMoveObjects(); |
| 153 | ASSERT_MSG(!num_domain_objects || !num_move_objects, | 173 | ASSERT_MSG(!num_domain_objects || !num_move_objects, |
| 154 | "cannot move normal handles and domain objects"); | 174 | "cannot move normal handles and domain objects"); |
| 155 | ASSERT_MSG((index - datapayload_index) == normal_params_size, | 175 | ASSERT_MSG((index - data_payload_index) == normal_params_size, |
| 156 | "normal_params_size value is incorrect"); | 176 | "normal_params_size value is incorrect"); |
| 157 | ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, | 177 | ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, |
| 158 | "num_objects_to_move value is incorrect"); | 178 | "num_objects_to_move value is incorrect"); |
| @@ -229,14 +249,14 @@ private: | |||
| 229 | u32 normal_params_size{}; | 249 | u32 normal_params_size{}; |
| 230 | u32 num_handles_to_copy{}; | 250 | u32 num_handles_to_copy{}; |
| 231 | u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent | 251 | u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent |
| 232 | std::ptrdiff_t datapayload_index{}; | 252 | u32 data_payload_index{}; |
| 233 | Kernel::KernelCore& kernel; | 253 | Kernel::KernelCore& kernel; |
| 234 | }; | 254 | }; |
| 235 | 255 | ||
| 236 | /// Push /// | 256 | /// Push /// |
| 237 | 257 | ||
| 238 | inline void ResponseBuilder::PushImpl(s32 value) { | 258 | inline void ResponseBuilder::PushImpl(s32 value) { |
| 239 | cmdbuf[index++] = static_cast<u32>(value); | 259 | cmdbuf[index++] = value; |
| 240 | } | 260 | } |
| 241 | 261 | ||
| 242 | inline void ResponseBuilder::PushImpl(u32 value) { | 262 | inline void ResponseBuilder::PushImpl(u32 value) { |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 93907f75e..ce3466df8 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -55,7 +55,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 55 | IPC::RequestParser rp(src_cmdbuf); | 55 | IPC::RequestParser rp(src_cmdbuf); |
| 56 | command_header = rp.PopRaw<IPC::CommandHeader>(); | 56 | command_header = rp.PopRaw<IPC::CommandHeader>(); |
| 57 | 57 | ||
| 58 | if (command_header->type == IPC::CommandType::Close) { | 58 | if (command_header->IsCloseCommand()) { |
| 59 | // Close does not populate the rest of the IPC header | 59 | // Close does not populate the rest of the IPC header |
| 60 | return; | 60 | return; |
| 61 | } | 61 | } |
| @@ -99,39 +99,43 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 99 | buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | 99 | buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; | 102 | const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; |
| 103 | 103 | ||
| 104 | // Padding to align to 16 bytes | 104 | if (!command_header->IsTipc()) { |
| 105 | rp.AlignWithPadding(); | 105 | // Padding to align to 16 bytes |
| 106 | 106 | rp.AlignWithPadding(); | |
| 107 | if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request || | 107 | |
| 108 | command_header->type == IPC::CommandType::RequestWithContext) || | 108 | if (Session()->IsDomain() && |
| 109 | !incoming)) { | 109 | ((command_header->type == IPC::CommandType::Request || |
| 110 | // If this is an incoming message, only CommandType "Request" has a domain header | 110 | command_header->type == IPC::CommandType::RequestWithContext) || |
| 111 | // All outgoing domain messages have the domain header, if only incoming has it | 111 | !incoming)) { |
| 112 | if (incoming || domain_message_header) { | 112 | // If this is an incoming message, only CommandType "Request" has a domain header |
| 113 | domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); | 113 | // All outgoing domain messages have the domain header, if only incoming has it |
| 114 | } else { | 114 | if (incoming || domain_message_header) { |
| 115 | if (Session()->IsDomain()) { | 115 | domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); |
| 116 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); | 116 | } else { |
| 117 | if (Session()->IsDomain()) { | ||
| 118 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); | ||
| 119 | } | ||
| 117 | } | 120 | } |
| 118 | } | 121 | } |
| 119 | } | ||
| 120 | 122 | ||
| 121 | data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); | 123 | data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); |
| 122 | 124 | ||
| 123 | data_payload_offset = rp.GetCurrentOffset(); | 125 | data_payload_offset = rp.GetCurrentOffset(); |
| 124 | 126 | ||
| 125 | if (domain_message_header && domain_message_header->command == | 127 | if (domain_message_header && |
| 126 | IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { | 128 | domain_message_header->command == |
| 127 | // CloseVirtualHandle command does not have SFC* or any data | 129 | IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { |
| 128 | return; | 130 | // CloseVirtualHandle command does not have SFC* or any data |
| 129 | } | 131 | return; |
| 132 | } | ||
| 130 | 133 | ||
| 131 | if (incoming) { | 134 | if (incoming) { |
| 132 | ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); | 135 | ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); |
| 133 | } else { | 136 | } else { |
| 134 | ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); | 137 | ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); |
| 138 | } | ||
| 135 | } | 139 | } |
| 136 | 140 | ||
| 137 | rp.SetCurrentOffset(buffer_c_offset); | 141 | rp.SetCurrentOffset(buffer_c_offset); |
| @@ -166,84 +170,67 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 166 | ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, | 170 | ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, |
| 167 | u32_le* src_cmdbuf) { | 171 | u32_le* src_cmdbuf) { |
| 168 | ParseCommandBuffer(handle_table, src_cmdbuf, true); | 172 | ParseCommandBuffer(handle_table, src_cmdbuf, true); |
| 169 | if (command_header->type == IPC::CommandType::Close) { | 173 | |
| 174 | if (command_header->IsCloseCommand()) { | ||
| 170 | // Close does not populate the rest of the IPC header | 175 | // Close does not populate the rest of the IPC header |
| 171 | return RESULT_SUCCESS; | 176 | return RESULT_SUCCESS; |
| 172 | } | 177 | } |
| 173 | 178 | ||
| 174 | // The data_size already includes the payload header, the padding and the domain header. | 179 | std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin()); |
| 175 | std::size_t size = data_payload_offset + command_header->data_size - | 180 | |
| 176 | sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; | ||
| 177 | if (domain_message_header) | ||
| 178 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); | ||
| 179 | std::copy_n(src_cmdbuf, size, cmd_buf.begin()); | ||
| 180 | return RESULT_SUCCESS; | 181 | return RESULT_SUCCESS; |
| 181 | } | 182 | } |
| 182 | 183 | ||
| 183 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { | 184 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { |
| 185 | auto current_offset = handles_offset; | ||
| 184 | auto& owner_process = *requesting_thread.GetOwnerProcess(); | 186 | auto& owner_process = *requesting_thread.GetOwnerProcess(); |
| 185 | auto& handle_table = owner_process.GetHandleTable(); | 187 | auto& handle_table = owner_process.GetHandleTable(); |
| 186 | 188 | ||
| 187 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; | ||
| 188 | memory.ReadBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), | ||
| 189 | dst_cmdbuf.size() * sizeof(u32)); | ||
| 190 | |||
| 191 | // The header was already built in the internal command buffer. Attempt to parse it to verify | ||
| 192 | // the integrity and then copy it over to the target command buffer. | ||
| 193 | ParseCommandBuffer(handle_table, cmd_buf.data(), false); | ||
| 194 | |||
| 195 | // The data_size already includes the payload header, the padding and the domain header. | 189 | // The data_size already includes the payload header, the padding and the domain header. |
| 196 | std::size_t size = data_payload_offset + command_header->data_size - | 190 | std::size_t size{}; |
| 197 | sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; | ||
| 198 | if (domain_message_header) | ||
| 199 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); | ||
| 200 | |||
| 201 | std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data()); | ||
| 202 | 191 | ||
| 203 | if (command_header->enable_handle_descriptor) { | 192 | if (IsTipc()) { |
| 204 | ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), | 193 | size = cmd_buf.size(); |
| 205 | "Handle descriptor bit set but no handles to translate"); | 194 | } else { |
| 206 | // We write the translated handles at a specific offset in the command buffer, this space | 195 | size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; |
| 207 | // was already reserved when writing the header. | 196 | if (Session()->IsDomain()) { |
| 208 | std::size_t current_offset = | 197 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); |
| 209 | (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32); | ||
| 210 | ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented"); | ||
| 211 | |||
| 212 | ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy); | ||
| 213 | ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move); | ||
| 214 | |||
| 215 | // We don't make a distinction between copy and move handles when translating since HLE | ||
| 216 | // services don't deal with handles directly. However, the guest applications might check | ||
| 217 | // for specific values in each of these descriptors. | ||
| 218 | for (auto& object : copy_objects) { | ||
| 219 | ASSERT(object != nullptr); | ||
| 220 | R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); | ||
| 221 | } | 198 | } |
| 199 | } | ||
| 222 | 200 | ||
| 223 | for (auto& object : move_objects) { | 201 | for (auto& object : copy_objects) { |
| 224 | ASSERT(object != nullptr); | 202 | Handle handle{}; |
| 225 | R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); | 203 | if (object) { |
| 204 | R_TRY(handle_table.Add(&handle, object)); | ||
| 226 | } | 205 | } |
| 206 | cmd_buf[current_offset++] = handle; | ||
| 227 | } | 207 | } |
| 208 | for (auto& object : move_objects) { | ||
| 209 | Handle handle{}; | ||
| 210 | if (object) { | ||
| 211 | R_TRY(handle_table.Add(&handle, object)); | ||
| 228 | 212 | ||
| 229 | // TODO(Subv): Translate the X/A/B/W buffers. | 213 | // Close our reference to the object, as it is being moved to the caller. |
| 214 | object->Close(); | ||
| 215 | } | ||
| 216 | cmd_buf[current_offset++] = handle; | ||
| 217 | } | ||
| 230 | 218 | ||
| 231 | if (Session()->IsDomain() && domain_message_header) { | 219 | // Write the domain objects to the command buffer, these go after the raw untranslated data. |
| 232 | ASSERT(domain_message_header->num_objects == domain_objects.size()); | 220 | // TODO(Subv): This completely ignores C buffers. |
| 233 | // Write the domain objects to the command buffer, these go after the raw untranslated data. | ||
| 234 | // TODO(Subv): This completely ignores C buffers. | ||
| 235 | std::size_t domain_offset = size - domain_message_header->num_objects; | ||
| 236 | 221 | ||
| 222 | if (Session()->IsDomain()) { | ||
| 223 | current_offset = domain_offset - static_cast<u32>(domain_objects.size()); | ||
| 237 | for (const auto& object : domain_objects) { | 224 | for (const auto& object : domain_objects) { |
| 238 | server_session->AppendDomainRequestHandler(object); | 225 | server_session->AppendDomainRequestHandler(object); |
| 239 | dst_cmdbuf[domain_offset++] = | 226 | cmd_buf[current_offset++] = |
| 240 | static_cast<u32_le>(server_session->NumDomainRequestHandlers()); | 227 | static_cast<u32_le>(server_session->NumDomainRequestHandlers()); |
| 241 | } | 228 | } |
| 242 | } | 229 | } |
| 243 | 230 | ||
| 244 | // Copy the translated command buffer back into the thread's command buffer area. | 231 | // Copy the translated command buffer back into the thread's command buffer area. |
| 245 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), | 232 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), |
| 246 | dst_cmdbuf.size() * sizeof(u32)); | 233 | size * sizeof(u32)); |
| 247 | 234 | ||
| 248 | return RESULT_SUCCESS; | 235 | return RESULT_SUCCESS; |
| 249 | } | 236 | } |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 21e384706..4fba300dc 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -66,7 +66,8 @@ public: | |||
| 66 | * this request (ServerSession, Originator thread, Translated command buffer, etc). | 66 | * this request (ServerSession, Originator thread, Translated command buffer, etc). |
| 67 | * @returns ResultCode the result code of the translate operation. | 67 | * @returns ResultCode the result code of the translate operation. |
| 68 | */ | 68 | */ |
| 69 | virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0; | 69 | virtual ResultCode HandleSyncRequest(Kernel::KServerSession& session, |
| 70 | Kernel::HLERequestContext& context) = 0; | ||
| 70 | 71 | ||
| 71 | /** | 72 | /** |
| 72 | * Signals that a client has just connected to this HLE handler and keeps the | 73 | * Signals that a client has just connected to this HLE handler and keeps the |
| @@ -128,15 +129,28 @@ public: | |||
| 128 | /// Writes data from this context back to the requesting process/thread. | 129 | /// Writes data from this context back to the requesting process/thread. |
| 129 | ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread); | 130 | ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread); |
| 130 | 131 | ||
| 131 | u32_le GetCommand() const { | 132 | u32_le GetHipcCommand() const { |
| 132 | return command; | 133 | return command; |
| 133 | } | 134 | } |
| 134 | 135 | ||
| 136 | u32_le GetTipcCommand() const { | ||
| 137 | return static_cast<u32_le>(command_header->type.Value()) - | ||
| 138 | static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion); | ||
| 139 | } | ||
| 140 | |||
| 141 | u32_le GetCommand() const { | ||
| 142 | return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand(); | ||
| 143 | } | ||
| 144 | |||
| 145 | bool IsTipc() const { | ||
| 146 | return command_header->IsTipc(); | ||
| 147 | } | ||
| 148 | |||
| 135 | IPC::CommandType GetCommandType() const { | 149 | IPC::CommandType GetCommandType() const { |
| 136 | return command_header->type; | 150 | return command_header->type; |
| 137 | } | 151 | } |
| 138 | 152 | ||
| 139 | unsigned GetDataPayloadOffset() const { | 153 | u32 GetDataPayloadOffset() const { |
| 140 | return data_payload_offset; | 154 | return data_payload_offset; |
| 141 | } | 155 | } |
| 142 | 156 | ||
| @@ -291,8 +305,10 @@ private: | |||
| 291 | std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; | 305 | std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; |
| 292 | std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; | 306 | std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; |
| 293 | 307 | ||
| 294 | unsigned data_payload_offset{}; | 308 | u32 data_payload_offset{}; |
| 295 | unsigned buffer_c_offset{}; | 309 | u32 handles_offset{}; |
| 310 | u32 domain_offset{}; | ||
| 311 | u32 data_size{}; | ||
| 296 | u32_le command{}; | 312 | u32_le command{}; |
| 297 | 313 | ||
| 298 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | 314 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; |
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index e14b915b9..ad01cf67e 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp | |||
| @@ -58,9 +58,9 @@ bool KClientPort::IsSignaled() const { | |||
| 58 | 58 | ||
| 59 | ResultCode KClientPort::CreateSession(KClientSession** out) { | 59 | ResultCode KClientPort::CreateSession(KClientSession** out) { |
| 60 | // Reserve a new session from the resource limit. | 60 | // Reserve a new session from the resource limit. |
| 61 | KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), | 61 | // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), |
| 62 | LimitableResource::Sessions); | 62 | // LimitableResource::Sessions); |
| 63 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); | 63 | // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); |
| 64 | 64 | ||
| 65 | // Update the session counts. | 65 | // Update the session counts. |
| 66 | { | 66 | { |
| @@ -91,7 +91,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { | |||
| 91 | // Create a new session. | 91 | // Create a new session. |
| 92 | KSession* session = KSession::Create(kernel); | 92 | KSession* session = KSession::Create(kernel); |
| 93 | if (session == nullptr) { | 93 | if (session == nullptr) { |
| 94 | /* Decrement the session count. */ | 94 | // Decrement the session count. |
| 95 | const auto prev = num_sessions--; | 95 | const auto prev = num_sessions--; |
| 96 | if (prev == max_sessions) { | 96 | if (prev == max_sessions) { |
| 97 | this->NotifyAvailable(); | 97 | this->NotifyAvailable(); |
| @@ -104,7 +104,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { | |||
| 104 | session->Initialize(this, parent->GetName()); | 104 | session->Initialize(this, parent->GetName()); |
| 105 | 105 | ||
| 106 | // Commit the session reservation. | 106 | // Commit the session reservation. |
| 107 | session_reservation.Commit(); | 107 | // session_reservation.Commit(); |
| 108 | 108 | ||
| 109 | // Register the session. | 109 | // Register the session. |
| 110 | KSession::Register(kernel, session); | 110 | KSession::Register(kernel, session); |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index b28cc2499..8850d9af5 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -95,7 +95,7 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co | |||
| 95 | UNREACHABLE(); | 95 | UNREACHABLE(); |
| 96 | return RESULT_SUCCESS; // Ignore error if asserts are off | 96 | return RESULT_SUCCESS; // Ignore error if asserts are off |
| 97 | } | 97 | } |
| 98 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); | 98 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context); |
| 99 | 99 | ||
| 100 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | 100 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { |
| 101 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); | 101 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); |
| @@ -135,7 +135,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 135 | // If there is no domain header, the regular session handler is used | 135 | // If there is no domain header, the regular session handler is used |
| 136 | } else if (hle_handler != nullptr) { | 136 | } else if (hle_handler != nullptr) { |
| 137 | // If this ServerSession has an associated HLE handler, forward the request to it. | 137 | // If this ServerSession has an associated HLE handler, forward the request to it. |
| 138 | result = hle_handler->HandleSyncRequest(context); | 138 | result = hle_handler->HandleSyncRequest(*this, context); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | if (convert_to_domain) { | 141 | if (convert_to_domain) { |
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index 025b8b555..b7ce27a0b 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp | |||
| @@ -78,7 +78,7 @@ void KSession::OnClientClosed() { | |||
| 78 | void KSession::PostDestroy(uintptr_t arg) { | 78 | void KSession::PostDestroy(uintptr_t arg) { |
| 79 | // Release the session count resource the owner process holds. | 79 | // Release the session count resource the owner process holds. |
| 80 | KProcess* owner = reinterpret_cast<KProcess*>(arg); | 80 | KProcess* owner = reinterpret_cast<KProcess*>(arg); |
| 81 | owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); | 81 | // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); |
| 82 | owner->Close(); | 82 | owner->Close(); |
| 83 | } | 83 | } |
| 84 | 84 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index bd4e4d350..8b55df82e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | #include "core/hle/kernel/time_manager.h" | 44 | #include "core/hle/kernel/time_manager.h" |
| 45 | #include "core/hle/lock.h" | 45 | #include "core/hle/lock.h" |
| 46 | #include "core/hle/result.h" | 46 | #include "core/hle/result.h" |
| 47 | #include "core/hle/service/sm/sm.h" | ||
| 47 | #include "core/memory.h" | 48 | #include "core/memory.h" |
| 48 | 49 | ||
| 49 | MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); | 50 | MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); |
| @@ -656,6 +657,7 @@ struct KernelCore::Impl { | |||
| 656 | 657 | ||
| 657 | /// Map of named ports managed by the kernel, which can be retrieved using | 658 | /// Map of named ports managed by the kernel, which can be retrieved using |
| 658 | /// the ConnectToPort SVC. | 659 | /// the ConnectToPort SVC. |
| 660 | std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; | ||
| 659 | NamedPortTable named_ports; | 661 | NamedPortTable named_ports; |
| 660 | 662 | ||
| 661 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | 663 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; |
| @@ -844,18 +846,17 @@ void KernelCore::PrepareReschedule(std::size_t id) { | |||
| 844 | // TODO: Reimplement, this | 846 | // TODO: Reimplement, this |
| 845 | } | 847 | } |
| 846 | 848 | ||
| 847 | void KernelCore::AddNamedPort(std::string name, KClientPort* port) { | 849 | void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) { |
| 848 | port->Open(); | 850 | impl->service_interface_factory.emplace(std::move(name), factory); |
| 849 | impl->named_ports.emplace(std::move(name), port); | ||
| 850 | } | 851 | } |
| 851 | 852 | ||
| 852 | KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { | 853 | KClientPort* KernelCore::CreateNamedServicePort(std::string name) { |
| 853 | return impl->named_ports.find(name); | 854 | auto search = impl->service_interface_factory.find(name); |
| 854 | } | 855 | if (search == impl->service_interface_factory.end()) { |
| 855 | 856 | UNIMPLEMENTED(); | |
| 856 | KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort( | 857 | return {}; |
| 857 | const std::string& name) const { | 858 | } |
| 858 | return impl->named_ports.find(name); | 859 | return &search->second(impl->system.ServiceManager(), impl->system); |
| 859 | } | 860 | } |
| 860 | 861 | ||
| 861 | bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { | 862 | bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 51aaccbc7..2d01e1ae0 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -27,6 +27,10 @@ class CoreTiming; | |||
| 27 | struct EventType; | 27 | struct EventType; |
| 28 | } // namespace Core::Timing | 28 | } // namespace Core::Timing |
| 29 | 29 | ||
| 30 | namespace Service::SM { | ||
| 31 | class ServiceManager; | ||
| 32 | } | ||
| 33 | |||
| 30 | namespace Kernel { | 34 | namespace Kernel { |
| 31 | 35 | ||
| 32 | class KClientPort; | 36 | class KClientPort; |
| @@ -51,6 +55,9 @@ class ServiceThread; | |||
| 51 | class Synchronization; | 55 | class Synchronization; |
| 52 | class TimeManager; | 56 | class TimeManager; |
| 53 | 57 | ||
| 58 | using ServiceInterfaceFactory = | ||
| 59 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; | ||
| 60 | |||
| 54 | namespace Init { | 61 | namespace Init { |
| 55 | struct KSlabResourceCounts; | 62 | struct KSlabResourceCounts; |
| 56 | } | 63 | } |
| @@ -172,14 +179,11 @@ public: | |||
| 172 | 179 | ||
| 173 | void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); | 180 | void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); |
| 174 | 181 | ||
| 175 | /// Adds a port to the named port table | 182 | /// Registers a named HLE service, passing a factory used to open a port to that service. |
| 176 | void AddNamedPort(std::string name, KClientPort* port); | 183 | void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory); |
| 177 | |||
| 178 | /// Finds a port within the named port table with the given name. | ||
| 179 | NamedPortTable::iterator FindNamedPort(const std::string& name); | ||
| 180 | 184 | ||
| 181 | /// Finds a port within the named port table with the given name. | 185 | /// Opens a port to a service previously registered with RegisterNamedService. |
| 182 | NamedPortTable::const_iterator FindNamedPort(const std::string& name) const; | 186 | KClientPort* CreateNamedServicePort(std::string name); |
| 183 | 187 | ||
| 184 | /// Determines whether or not the given port is a valid named port. | 188 | /// Determines whether or not the given port is a valid named port. |
| 185 | bool IsValidNamedPort(NamedPortTable::const_iterator port) const; | 189 | bool IsValidNamedPort(NamedPortTable::const_iterator port) const; |
diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index 0c5995db0..d0f7f084b 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h | |||
| @@ -67,11 +67,11 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { | |||
| 67 | 67 | ||
| 68 | private: | 68 | private: |
| 69 | static Derived* Allocate(KernelCore& kernel) { | 69 | static Derived* Allocate(KernelCore& kernel) { |
| 70 | return kernel.SlabHeap<Derived>().AllocateWithKernel(kernel); | 70 | return new Derived(kernel); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static void Free(KernelCore& kernel, Derived* obj) { | 73 | static void Free(KernelCore& kernel, Derived* obj) { |
| 74 | kernel.SlabHeap<Derived>().Free(obj); | 74 | delete obj; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | public: | 77 | public: |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 52011be9c..6b445677e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -284,12 +284,11 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po | |||
| 284 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 284 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 285 | 285 | ||
| 286 | // Find the client port. | 286 | // Find the client port. |
| 287 | const auto it = kernel.FindNamedPort(port_name); | 287 | auto port = kernel.CreateNamedServicePort(port_name); |
| 288 | if (!kernel.IsValidNamedPort(it)) { | 288 | if (!port) { |
| 289 | LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); | 289 | LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name); |
| 290 | return ResultNotFound; | 290 | return ResultNotFound; |
| 291 | } | 291 | } |
| 292 | auto port = it->second; | ||
| 293 | 292 | ||
| 294 | // Reserve a handle for the port. | 293 | // Reserve a handle for the port. |
| 295 | // NOTE: Nintendo really does write directly to the output handle here. | 294 | // NOTE: Nintendo really does write directly to the output handle here. |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 513bd3730..65887011f 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -169,10 +169,9 @@ private: | |||
| 169 | 169 | ||
| 170 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { | 170 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
| 171 | public: | 171 | public: |
| 172 | explicit IAudioDevice(Core::System& system_, u32_le revision_num) | 172 | explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_) |
| 173 | : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num}, | 173 | : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{ |
| 174 | buffer_event{system.Kernel()}, audio_input_device_switch_event{system.Kernel()}, | 174 | revision_} { |
| 175 | audio_output_device_switch_event{system.Kernel()} { | ||
| 176 | static const FunctionInfo functions[] = { | 175 | static const FunctionInfo functions[] = { |
| 177 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, | 176 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, |
| 178 | {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, | 177 | {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, |
| @@ -189,18 +188,6 @@ public: | |||
| 189 | {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, | 188 | {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, |
| 190 | }; | 189 | }; |
| 191 | RegisterHandlers(functions); | 190 | RegisterHandlers(functions); |
| 192 | |||
| 193 | Kernel::KAutoObject::Create(std::addressof(buffer_event)); | ||
| 194 | buffer_event.Initialize("IAudioOutBufferReleasedEvent"); | ||
| 195 | |||
| 196 | // Should be similar to audio_output_device_switch_event | ||
| 197 | Kernel::KAutoObject::Create(std::addressof(audio_input_device_switch_event)); | ||
| 198 | audio_input_device_switch_event.Initialize("IAudioDevice:AudioInputDeviceSwitchedEvent"); | ||
| 199 | |||
| 200 | // Should only be signalled when an audio output device has been changed, example: speaker | ||
| 201 | // to headset | ||
| 202 | Kernel::KAutoObject::Create(std::addressof(audio_output_device_switch_event)); | ||
| 203 | audio_output_device_switch_event.Initialize("IAudioDevice:AudioOutputDeviceSwitchedEvent"); | ||
| 204 | } | 191 | } |
| 205 | 192 | ||
| 206 | private: | 193 | private: |
| @@ -310,7 +297,7 @@ private: | |||
| 310 | 297 | ||
| 311 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 298 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 312 | rb.Push(RESULT_SUCCESS); | 299 | rb.Push(RESULT_SUCCESS); |
| 313 | rb.PushCopyObjects(audio_input_device_switch_event.GetReadableEvent()); | 300 | rb.PushCopyObjects(buffer_event.GetReadableEvent()); |
| 314 | } | 301 | } |
| 315 | 302 | ||
| 316 | void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { | 303 | void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { |
| @@ -318,17 +305,16 @@ private: | |||
| 318 | 305 | ||
| 319 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 306 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 320 | rb.Push(RESULT_SUCCESS); | 307 | rb.Push(RESULT_SUCCESS); |
| 321 | rb.PushCopyObjects(audio_output_device_switch_event.GetReadableEvent()); | 308 | rb.PushCopyObjects(buffer_event.GetReadableEvent()); |
| 322 | } | 309 | } |
| 323 | 310 | ||
| 311 | Kernel::KEvent& buffer_event; | ||
| 324 | u32_le revision = 0; | 312 | u32_le revision = 0; |
| 325 | Kernel::KEvent buffer_event; | 313 | }; |
| 326 | Kernel::KEvent audio_input_device_switch_event; | ||
| 327 | Kernel::KEvent audio_output_device_switch_event; | ||
| 328 | 314 | ||
| 329 | }; // namespace Audio | 315 | AudRenU::AudRenU(Core::System& system_) |
| 316 | : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} { | ||
| 330 | 317 | ||
| 331 | AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} { | ||
| 332 | // clang-format off | 318 | // clang-format off |
| 333 | static const FunctionInfo functions[] = { | 319 | static const FunctionInfo functions[] = { |
| 334 | {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, | 320 | {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, |
| @@ -340,6 +326,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} | |||
| 340 | // clang-format on | 326 | // clang-format on |
| 341 | 327 | ||
| 342 | RegisterHandlers(functions); | 328 | RegisterHandlers(functions); |
| 329 | |||
| 330 | Kernel::KAutoObject::Create(std::addressof(buffer_event)); | ||
| 331 | buffer_event.Initialize("IAudioOutBufferReleasedEvent"); | ||
| 343 | } | 332 | } |
| 344 | 333 | ||
| 345 | AudRenU::~AudRenU() = default; | 334 | AudRenU::~AudRenU() = default; |
| @@ -662,7 +651,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { | |||
| 662 | // always assumes the initial release revision (REV1). | 651 | // always assumes the initial release revision (REV1). |
| 663 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 652 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 664 | rb.Push(RESULT_SUCCESS); | 653 | rb.Push(RESULT_SUCCESS); |
| 665 | rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); | 654 | rb.PushIpcInterface<IAudioDevice>(system, buffer_event, Common::MakeMagic('R', 'E', 'V', '1')); |
| 666 | } | 655 | } |
| 667 | 656 | ||
| 668 | void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) { | 657 | void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) { |
| @@ -684,7 +673,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c | |||
| 684 | 673 | ||
| 685 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 674 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 686 | rb.Push(RESULT_SUCCESS); | 675 | rb.Push(RESULT_SUCCESS); |
| 687 | rb.PushIpcInterface<IAudioDevice>(system, revision); | 676 | rb.PushIpcInterface<IAudioDevice>(system, buffer_event, revision); |
| 688 | } | 677 | } |
| 689 | 678 | ||
| 690 | void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { | 679 | void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 37e8b4716..0ee6f9542 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | 9 | ||
| 9 | namespace Core { | 10 | namespace Core { |
| @@ -31,6 +32,7 @@ private: | |||
| 31 | void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); | 32 | void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); |
| 32 | 33 | ||
| 33 | std::size_t audren_instance_count = 0; | 34 | std::size_t audren_instance_count = 0; |
| 35 | Kernel::KEvent buffer_event; | ||
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 36 | // Describes a particular audio feature that may be supported in a particular revision. | 38 | // Describes a particular audio feature that may be supported in a particular revision. |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 00e683c2f..2c9b2ce6d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -111,7 +111,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | |||
| 111 | port_installed = true; | 111 | port_installed = true; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { | 114 | Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) { |
| 115 | const auto guard = LockService(); | 115 | const auto guard = LockService(); |
| 116 | 116 | ||
| 117 | ASSERT(!port_installed); | 117 | ASSERT(!port_installed); |
| @@ -119,9 +119,10 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { | |||
| 119 | auto* port = Kernel::KPort::Create(kernel); | 119 | auto* port = Kernel::KPort::Create(kernel); |
| 120 | port->Initialize(max_sessions, false, service_name); | 120 | port->Initialize(max_sessions, false, service_name); |
| 121 | port->GetServerPort().SetHleHandler(shared_from_this()); | 121 | port->GetServerPort().SetHleHandler(shared_from_this()); |
| 122 | kernel.AddNamedPort(service_name, &port->GetClientPort()); | ||
| 123 | 122 | ||
| 124 | port_installed = true; | 123 | port_installed = true; |
| 124 | |||
| 125 | return port->GetClientPort(); | ||
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { | 128 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { |
| @@ -132,6 +133,16 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function | |||
| 132 | } | 133 | } |
| 133 | } | 134 | } |
| 134 | 135 | ||
| 136 | void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions, | ||
| 137 | std::size_t n) { | ||
| 138 | handlers_tipc.reserve(handlers_tipc.size() + n); | ||
| 139 | for (std::size_t i = 0; i < n; ++i) { | ||
| 140 | // Usually this array is sorted by id already, so hint to insert at the end | ||
| 141 | handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header, | ||
| 142 | functions[i]); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 135 | void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, | 146 | void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, |
| 136 | const FunctionInfoBase* info) { | 147 | const FunctionInfoBase* info) { |
| 137 | auto cmd_buf = ctx.CommandBuffer(); | 148 | auto cmd_buf = ctx.CommandBuffer(); |
| @@ -166,33 +177,55 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { | |||
| 166 | handler_invoker(this, info->handler_callback, ctx); | 177 | handler_invoker(this, info->handler_callback, ctx); |
| 167 | } | 178 | } |
| 168 | 179 | ||
| 169 | ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { | 180 | void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) { |
| 181 | boost::container::flat_map<u32, FunctionInfoBase>::iterator itr; | ||
| 182 | |||
| 183 | itr = handlers_tipc.find(ctx.GetCommand()); | ||
| 184 | |||
| 185 | const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second; | ||
| 186 | if (info == nullptr || info->handler_callback == nullptr) { | ||
| 187 | return ReportUnimplementedFunction(ctx, info); | ||
| 188 | } | ||
| 189 | |||
| 190 | LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); | ||
| 191 | handler_invoker(this, info->handler_callback, ctx); | ||
| 192 | } | ||
| 193 | |||
| 194 | ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, | ||
| 195 | Kernel::HLERequestContext& ctx) { | ||
| 170 | const auto guard = LockService(); | 196 | const auto guard = LockService(); |
| 171 | 197 | ||
| 172 | switch (context.GetCommandType()) { | 198 | switch (ctx.GetCommandType()) { |
| 173 | case IPC::CommandType::Close: { | 199 | case IPC::CommandType::Close: |
| 174 | IPC::ResponseBuilder rb{context, 2}; | 200 | case IPC::CommandType::TIPC_Close: { |
| 201 | session.Close(); | ||
| 202 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 175 | rb.Push(RESULT_SUCCESS); | 203 | rb.Push(RESULT_SUCCESS); |
| 176 | return IPC::ERR_REMOTE_PROCESS_DEAD; | 204 | return IPC::ERR_REMOTE_PROCESS_DEAD; |
| 177 | } | 205 | } |
| 178 | case IPC::CommandType::ControlWithContext: | 206 | case IPC::CommandType::ControlWithContext: |
| 179 | case IPC::CommandType::Control: { | 207 | case IPC::CommandType::Control: { |
| 180 | system.ServiceManager().InvokeControlRequest(context); | 208 | system.ServiceManager().InvokeControlRequest(ctx); |
| 181 | break; | 209 | break; |
| 182 | } | 210 | } |
| 183 | case IPC::CommandType::RequestWithContext: | 211 | case IPC::CommandType::RequestWithContext: |
| 184 | case IPC::CommandType::Request: { | 212 | case IPC::CommandType::Request: { |
| 185 | InvokeRequest(context); | 213 | InvokeRequest(ctx); |
| 186 | break; | 214 | break; |
| 187 | } | 215 | } |
| 188 | default: | 216 | default: |
| 189 | UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType()); | 217 | if (ctx.IsTipc()) { |
| 218 | InvokeRequestTipc(ctx); | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | |||
| 222 | UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); | ||
| 190 | } | 223 | } |
| 191 | 224 | ||
| 192 | // If emulation was shutdown, we are closing service threads, do not write the response back to | 225 | // If emulation was shutdown, we are closing service threads, do not write the response back to |
| 193 | // memory that may be shutting down as well. | 226 | // memory that may be shutting down as well. |
| 194 | if (system.IsPoweredOn()) { | 227 | if (system.IsPoweredOn()) { |
| 195 | context.WriteToOutgoingCommandBuffer(context.GetThread()); | 228 | ctx.WriteToOutgoingCommandBuffer(ctx.GetThread()); |
| 196 | } | 229 | } |
| 197 | 230 | ||
| 198 | return RESULT_SUCCESS; | 231 | return RESULT_SUCCESS; |
| @@ -207,7 +240,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system | |||
| 207 | 240 | ||
| 208 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | 241 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); |
| 209 | 242 | ||
| 210 | SM::ServiceManager::InstallInterfaces(sm, system); | 243 | system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory); |
| 211 | 244 | ||
| 212 | Account::InstallInterfaces(system); | 245 | Account::InstallInterfaces(system); |
| 213 | AM::InstallInterfaces(*sm, *nv_flinger, system); | 246 | AM::InstallInterfaces(*sm, *nv_flinger, system); |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 884951428..3dfb0740a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -21,7 +21,9 @@ class System; | |||
| 21 | 21 | ||
| 22 | namespace Kernel { | 22 | namespace Kernel { |
| 23 | class HLERequestContext; | 23 | class HLERequestContext; |
| 24 | } | 24 | class KClientPort; |
| 25 | class KServerSession; | ||
| 26 | } // namespace Kernel | ||
| 25 | 27 | ||
| 26 | namespace Service { | 28 | namespace Service { |
| 27 | 29 | ||
| @@ -64,12 +66,19 @@ public: | |||
| 64 | 66 | ||
| 65 | /// Creates a port pair and registers this service with the given ServiceManager. | 67 | /// Creates a port pair and registers this service with the given ServiceManager. |
| 66 | void InstallAsService(SM::ServiceManager& service_manager); | 68 | void InstallAsService(SM::ServiceManager& service_manager); |
| 67 | /// Creates a port pair and registers it on the kernel's global port registry. | 69 | |
| 68 | void InstallAsNamedPort(Kernel::KernelCore& kernel); | 70 | /// Invokes a service request routine using the HIPC protocol. |
| 69 | /// Invokes a service request routine. | ||
| 70 | void InvokeRequest(Kernel::HLERequestContext& ctx); | 71 | void InvokeRequest(Kernel::HLERequestContext& ctx); |
| 72 | |||
| 73 | /// Invokes a service request routine using the HIPC protocol. | ||
| 74 | void InvokeRequestTipc(Kernel::HLERequestContext& ctx); | ||
| 75 | |||
| 76 | /// Creates a port pair and registers it on the kernel's global port registry. | ||
| 77 | Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel); | ||
| 78 | |||
| 71 | /// Handles a synchronization request for the service. | 79 | /// Handles a synchronization request for the service. |
| 72 | ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; | 80 | ResultCode HandleSyncRequest(Kernel::KServerSession& session, |
| 81 | Kernel::HLERequestContext& context) override; | ||
| 73 | 82 | ||
| 74 | protected: | 83 | protected: |
| 75 | /// Member-function pointer type of SyncRequest handlers. | 84 | /// Member-function pointer type of SyncRequest handlers. |
| @@ -102,6 +111,7 @@ private: | |||
| 102 | ~ServiceFrameworkBase() override; | 111 | ~ServiceFrameworkBase() override; |
| 103 | 112 | ||
| 104 | void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); | 113 | void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); |
| 114 | void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n); | ||
| 105 | void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); | 115 | void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); |
| 106 | 116 | ||
| 107 | /// Identifier string used to connect to the service. | 117 | /// Identifier string used to connect to the service. |
| @@ -116,6 +126,7 @@ private: | |||
| 116 | /// Function used to safely up-cast pointers to the derived class before invoking a handler. | 126 | /// Function used to safely up-cast pointers to the derived class before invoking a handler. |
| 117 | InvokerFn* handler_invoker; | 127 | InvokerFn* handler_invoker; |
| 118 | boost::container::flat_map<u32, FunctionInfoBase> handlers; | 128 | boost::container::flat_map<u32, FunctionInfoBase> handlers; |
| 129 | boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc; | ||
| 119 | 130 | ||
| 120 | /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. | 131 | /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. |
| 121 | Common::SpinLock lock_service; | 132 | Common::SpinLock lock_service; |
| @@ -183,6 +194,20 @@ protected: | |||
| 183 | RegisterHandlersBase(functions, n); | 194 | RegisterHandlersBase(functions, n); |
| 184 | } | 195 | } |
| 185 | 196 | ||
| 197 | /// Registers handlers in the service. | ||
| 198 | template <std::size_t N> | ||
| 199 | void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) { | ||
| 200 | RegisterHandlersTipc(functions, N); | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Registers handlers in the service. Usually prefer using the other RegisterHandlers | ||
| 205 | * overload in order to avoid needing to specify the array size. | ||
| 206 | */ | ||
| 207 | void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) { | ||
| 208 | RegisterHandlersBaseTipc(functions, n); | ||
| 209 | } | ||
| 210 | |||
| 186 | private: | 211 | private: |
| 187 | /** | 212 | /** |
| 188 | * This function is used to allow invocation of pointers to handlers stored in the base class | 213 | * This function is used to allow invocation of pointers to handlers stored in the base class |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index ee026e22f..de530cbfb 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -26,15 +26,23 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { | |||
| 26 | // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong | 26 | // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong |
| 27 | // and that we probably want to actually make an entirely new Session, but we still need to | 27 | // and that we probably want to actually make an entirely new Session, but we still need to |
| 28 | // verify this on hardware. | 28 | // verify this on hardware. |
| 29 | |||
| 29 | LOG_DEBUG(Service, "called"); | 30 | LOG_DEBUG(Service, "called"); |
| 30 | 31 | ||
| 32 | auto session = ctx.Session()->GetParent(); | ||
| 33 | |||
| 34 | // Open a reference to the session to simulate a new one being created. | ||
| 35 | session->Open(); | ||
| 36 | session->GetClientSession().Open(); | ||
| 37 | session->GetServerSession().Open(); | ||
| 38 | |||
| 31 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 39 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 32 | rb.Push(RESULT_SUCCESS); | 40 | rb.Push(RESULT_SUCCESS); |
| 33 | rb.PushMoveObjects(ctx.Session()->GetParent()->GetClientSession()); | 41 | rb.PushMoveObjects(session->GetClientSession()); |
| 34 | } | 42 | } |
| 35 | 43 | ||
| 36 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { | 44 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { |
| 37 | LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); | 45 | LOG_DEBUG(Service, "called"); |
| 38 | 46 | ||
| 39 | CloneCurrentObject(ctx); | 47 | CloneCurrentObject(ctx); |
| 40 | } | 48 | } |
| @@ -44,7 +52,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 44 | 52 | ||
| 45 | IPC::ResponseBuilder rb{ctx, 3}; | 53 | IPC::ResponseBuilder rb{ctx, 3}; |
| 46 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.Push<u16>(0x1000); | 55 | rb.Push<u16>(0x8000); |
| 48 | } | 56 | } |
| 49 | 57 | ||
| 50 | // https://switchbrew.org/wiki/IPC_Marshalling | 58 | // https://switchbrew.org/wiki/IPC_Marshalling |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 568effbc9..8cc9aee8a 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/hle/kernel/k_client_port.h" | 9 | #include "core/hle/kernel/k_client_port.h" |
| 10 | #include "core/hle/kernel/k_client_session.h" | 10 | #include "core/hle/kernel/k_client_session.h" |
| 11 | #include "core/hle/kernel/k_port.h" | 11 | #include "core/hle/kernel/k_port.h" |
| 12 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 12 | #include "core/hle/kernel/k_server_port.h" | 13 | #include "core/hle/kernel/k_server_port.h" |
| 13 | #include "core/hle/kernel/k_server_session.h" | 14 | #include "core/hle/kernel/k_server_session.h" |
| 14 | #include "core/hle/kernel/k_session.h" | 15 | #include "core/hle/kernel/k_session.h" |
| @@ -18,6 +19,7 @@ | |||
| 18 | 19 | ||
| 19 | namespace Service::SM { | 20 | namespace Service::SM { |
| 20 | 21 | ||
| 22 | constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2); | ||
| 21 | constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); | 23 | constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); |
| 22 | constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); | 24 | constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); |
| 23 | constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); | 25 | constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); |
| @@ -34,20 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) { | |||
| 34 | LOG_ERROR(Service_SM, "Invalid service name! service={}", name); | 36 | LOG_ERROR(Service_SM, "Invalid service name! service={}", name); |
| 35 | return ERR_INVALID_NAME; | 37 | return ERR_INVALID_NAME; |
| 36 | } | 38 | } |
| 37 | if (name.rfind('\0') != std::string::npos) { | ||
| 38 | LOG_ERROR(Service_SM, "A non null terminated service was passed"); | ||
| 39 | return ERR_INVALID_NAME; | ||
| 40 | } | ||
| 41 | return RESULT_SUCCESS; | 39 | return RESULT_SUCCESS; |
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { | 42 | Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { |
| 45 | ASSERT(self->sm_interface.expired()); | 43 | ASSERT(self.sm_interface.expired()); |
| 46 | 44 | ||
| 47 | auto sm = std::make_shared<SM>(self, system); | 45 | auto sm = std::make_shared<SM>(self, system); |
| 48 | sm->InstallAsNamedPort(system.Kernel()); | 46 | self.sm_interface = sm; |
| 49 | self->sm_interface = sm; | 47 | self.controller_interface = std::make_unique<Controller>(system); |
| 50 | self->controller_interface = std::make_unique<Controller>(system); | 48 | |
| 49 | return sm->CreatePort(system.Kernel()); | ||
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, | 52 | ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, |
| @@ -107,33 +106,68 @@ SM::~SM() = default; | |||
| 107 | void SM::Initialize(Kernel::HLERequestContext& ctx) { | 106 | void SM::Initialize(Kernel::HLERequestContext& ctx) { |
| 108 | LOG_DEBUG(Service_SM, "called"); | 107 | LOG_DEBUG(Service_SM, "called"); |
| 109 | 108 | ||
| 109 | is_initialized = true; | ||
| 110 | |||
| 110 | IPC::ResponseBuilder rb{ctx, 2}; | 111 | IPC::ResponseBuilder rb{ctx, 2}; |
| 111 | rb.Push(RESULT_SUCCESS); | 112 | rb.Push(RESULT_SUCCESS); |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | void SM::GetService(Kernel::HLERequestContext& ctx) { | 115 | void SM::GetService(Kernel::HLERequestContext& ctx) { |
| 115 | IPC::RequestParser rp{ctx}; | 116 | auto result = GetServiceImpl(ctx); |
| 117 | if (result.Succeeded()) { | ||
| 118 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | ||
| 119 | rb.Push(result.Code()); | ||
| 120 | rb.PushMoveObjects(result.Unwrap()); | ||
| 121 | } else { | ||
| 122 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 123 | rb.Push(result.Code()); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) { | ||
| 128 | auto result = GetServiceImpl(ctx); | ||
| 129 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | ||
| 130 | rb.Push(result.Code()); | ||
| 131 | rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr); | ||
| 132 | } | ||
| 133 | |||
| 134 | static std::string PopServiceName(IPC::RequestParser& rp) { | ||
| 116 | auto name_buf = rp.PopRaw<std::array<char, 8>>(); | 135 | auto name_buf = rp.PopRaw<std::array<char, 8>>(); |
| 117 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 136 | std::string result; |
| 137 | for (const auto& c : name_buf) { | ||
| 138 | if (c >= ' ' && c <= '~') { | ||
| 139 | result.push_back(c); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | return result; | ||
| 143 | } | ||
| 118 | 144 | ||
| 119 | std::string name(name_buf.begin(), end); | 145 | ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) { |
| 146 | if (!is_initialized) { | ||
| 147 | return ERR_NOT_INITIALIZED; | ||
| 148 | } | ||
| 149 | |||
| 150 | IPC::RequestParser rp{ctx}; | ||
| 151 | std::string name(PopServiceName(rp)); | ||
| 120 | 152 | ||
| 121 | auto result = service_manager->GetServicePort(name); | 153 | auto result = service_manager.GetServicePort(name); |
| 122 | if (result.Failed()) { | 154 | if (result.Failed()) { |
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 124 | rb.Push(result.Code()); | ||
| 125 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); | 155 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); |
| 126 | if (name.length() == 0) | 156 | return result.Code(); |
| 127 | return; // LibNX Fix | ||
| 128 | UNIMPLEMENTED(); | ||
| 129 | return; | ||
| 130 | } | 157 | } |
| 131 | 158 | ||
| 132 | auto* port = result.Unwrap(); | 159 | auto* port = result.Unwrap(); |
| 133 | 160 | ||
| 161 | // Kernel::KScopedResourceReservation session_reservation( | ||
| 162 | // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); | ||
| 163 | // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); | ||
| 164 | |||
| 134 | auto* session = Kernel::KSession::Create(kernel); | 165 | auto* session = Kernel::KSession::Create(kernel); |
| 135 | session->Initialize(&port->GetClientPort(), std::move(name)); | 166 | session->Initialize(&port->GetClientPort(), std::move(name)); |
| 136 | 167 | ||
| 168 | // Commit the session reservation. | ||
| 169 | // session_reservation.Commit(); | ||
| 170 | |||
| 137 | if (port->GetServerPort().GetHLEHandler()) { | 171 | if (port->GetServerPort().GetHLEHandler()) { |
| 138 | port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); | 172 | port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); |
| 139 | } else { | 173 | } else { |
| @@ -141,18 +175,12 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { | |||
| 141 | } | 175 | } |
| 142 | 176 | ||
| 143 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); | 177 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); |
| 144 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 178 | return MakeResult(&session->GetClientSession()); |
| 145 | rb.Push(RESULT_SUCCESS); | ||
| 146 | rb.PushMoveObjects(session->GetClientSession()); | ||
| 147 | } | 179 | } |
| 148 | 180 | ||
| 149 | void SM::RegisterService(Kernel::HLERequestContext& ctx) { | 181 | void SM::RegisterService(Kernel::HLERequestContext& ctx) { |
| 150 | IPC::RequestParser rp{ctx}; | 182 | IPC::RequestParser rp{ctx}; |
| 151 | 183 | std::string name(PopServiceName(rp)); | |
| 152 | const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | ||
| 153 | const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 154 | |||
| 155 | const std::string name(name_buf.begin(), end); | ||
| 156 | 184 | ||
| 157 | const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); | 185 | const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); |
| 158 | const auto max_session_count = rp.PopRaw<u32>(); | 186 | const auto max_session_count = rp.PopRaw<u32>(); |
| @@ -160,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { | |||
| 160 | LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, | 188 | LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, |
| 161 | max_session_count, is_light); | 189 | max_session_count, is_light); |
| 162 | 190 | ||
| 163 | auto handle = service_manager->RegisterService(name, max_session_count); | 191 | auto handle = service_manager.RegisterService(name, max_session_count); |
| 164 | if (handle.Failed()) { | 192 | if (handle.Failed()) { |
| 165 | LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", | 193 | LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", |
| 166 | handle.Code().raw); | 194 | handle.Code().raw); |
| @@ -178,28 +206,31 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { | |||
| 178 | 206 | ||
| 179 | void SM::UnregisterService(Kernel::HLERequestContext& ctx) { | 207 | void SM::UnregisterService(Kernel::HLERequestContext& ctx) { |
| 180 | IPC::RequestParser rp{ctx}; | 208 | IPC::RequestParser rp{ctx}; |
| 209 | std::string name(PopServiceName(rp)); | ||
| 181 | 210 | ||
| 182 | const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | ||
| 183 | const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 184 | |||
| 185 | const std::string name(name_buf.begin(), end); | ||
| 186 | LOG_DEBUG(Service_SM, "called with name={}", name); | 211 | LOG_DEBUG(Service_SM, "called with name={}", name); |
| 187 | 212 | ||
| 188 | IPC::ResponseBuilder rb{ctx, 2}; | 213 | IPC::ResponseBuilder rb{ctx, 2}; |
| 189 | rb.Push(service_manager->UnregisterService(name)); | 214 | rb.Push(service_manager.UnregisterService(name)); |
| 190 | } | 215 | } |
| 191 | 216 | ||
| 192 | SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) | 217 | SM::SM(ServiceManager& service_manager_, Core::System& system_) |
| 193 | : ServiceFramework{system_, "sm:", 4}, | 218 | : ServiceFramework{system_, "sm:", 4}, |
| 194 | service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { | 219 | service_manager{service_manager_}, kernel{system_.Kernel()} { |
| 195 | static const FunctionInfo functions[] = { | 220 | RegisterHandlers({ |
| 196 | {0, &SM::Initialize, "Initialize"}, | 221 | {0, &SM::Initialize, "Initialize"}, |
| 197 | {1, &SM::GetService, "GetService"}, | 222 | {1, &SM::GetService, "GetService"}, |
| 198 | {2, &SM::RegisterService, "RegisterService"}, | 223 | {2, &SM::RegisterService, "RegisterService"}, |
| 199 | {3, &SM::UnregisterService, "UnregisterService"}, | 224 | {3, &SM::UnregisterService, "UnregisterService"}, |
| 200 | {4, nullptr, "DetachClient"}, | 225 | {4, nullptr, "DetachClient"}, |
| 201 | }; | 226 | }); |
| 202 | RegisterHandlers(functions); | 227 | RegisterHandlersTipc({ |
| 228 | {0, &SM::Initialize, "Initialize"}, | ||
| 229 | {1, &SM::GetServiceTipc, "GetService"}, | ||
| 230 | {2, &SM::RegisterService, "RegisterService"}, | ||
| 231 | {3, &SM::UnregisterService, "UnregisterService"}, | ||
| 232 | {4, nullptr, "DetachClient"}, | ||
| 233 | }); | ||
| 203 | } | 234 | } |
| 204 | 235 | ||
| 205 | } // namespace Service::SM | 236 | } // namespace Service::SM |
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index af5010c3b..60f0b3f8a 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -34,22 +34,26 @@ class Controller; | |||
| 34 | /// Interface to "sm:" service | 34 | /// Interface to "sm:" service |
| 35 | class SM final : public ServiceFramework<SM> { | 35 | class SM final : public ServiceFramework<SM> { |
| 36 | public: | 36 | public: |
| 37 | explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); | 37 | explicit SM(ServiceManager& service_manager_, Core::System& system_); |
| 38 | ~SM() override; | 38 | ~SM() override; |
| 39 | 39 | ||
| 40 | private: | 40 | private: |
| 41 | void Initialize(Kernel::HLERequestContext& ctx); | 41 | void Initialize(Kernel::HLERequestContext& ctx); |
| 42 | void GetService(Kernel::HLERequestContext& ctx); | 42 | void GetService(Kernel::HLERequestContext& ctx); |
| 43 | void GetServiceTipc(Kernel::HLERequestContext& ctx); | ||
| 43 | void RegisterService(Kernel::HLERequestContext& ctx); | 44 | void RegisterService(Kernel::HLERequestContext& ctx); |
| 44 | void UnregisterService(Kernel::HLERequestContext& ctx); | 45 | void UnregisterService(Kernel::HLERequestContext& ctx); |
| 45 | 46 | ||
| 46 | std::shared_ptr<ServiceManager> service_manager; | 47 | ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx); |
| 48 | |||
| 49 | ServiceManager& service_manager; | ||
| 50 | bool is_initialized{}; | ||
| 47 | Kernel::KernelCore& kernel; | 51 | Kernel::KernelCore& kernel; |
| 48 | }; | 52 | }; |
| 49 | 53 | ||
| 50 | class ServiceManager { | 54 | class ServiceManager { |
| 51 | public: | 55 | public: |
| 52 | static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); | 56 | static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); |
| 53 | 57 | ||
| 54 | explicit ServiceManager(Kernel::KernelCore& kernel_); | 58 | explicit ServiceManager(Kernel::KernelCore& kernel_); |
| 55 | ~ServiceManager(); | 59 | ~ServiceManager(); |