diff options
Diffstat (limited to 'src/core/hle/kernel')
| -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 |
9 files changed, 122 insertions, 115 deletions
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. |