From d08bd3e062e629e34afa4e4947cfb6c28377e12f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 8 May 2021 02:21:50 -0700 Subject: hle: ipc_helpers: Update IPC response generation for TIPC. --- src/core/hle/kernel/hle_ipc.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 21e384706..7cdde2294 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -132,6 +132,10 @@ public: return command; } + bool IsTipc() const { + return command_header->IsTipc(); + } + IPC::CommandType GetCommandType() const { return command_header->type; } @@ -291,8 +295,10 @@ private: std::vector buffer_w_desciptors; std::vector buffer_c_desciptors; - unsigned data_payload_offset{}; - unsigned buffer_c_offset{}; + u32 data_payload_offset{}; + u32 buffer_c_offset{}; + u32 handles_offset{}; + u32 domain_offset{}; u32_le command{}; std::vector> domain_request_handlers; -- cgit v1.2.3 From ed25191ee634c3cd0df11b25407809c2ba4fe422 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 8 May 2021 02:50:47 -0700 Subject: hle: kernel: Further cleanup and add TIPC helpers. --- src/core/hle/kernel/hle_ipc.cpp | 2 +- src/core/hle/kernel/hle_ipc.h | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 93907f75e..d6929d2c0 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -99,7 +99,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 buffer_w_desciptors.push_back(rp.PopRaw()); } - buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; + const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; // Padding to align to 16 bytes rp.AlignWithPadding(); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 7cdde2294..07360629e 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -128,10 +128,19 @@ public: /// Writes data from this context back to the requesting process/thread. ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread); - u32_le GetCommand() const { + u32_le GetHipcCommand() const { return command; } + u32_le GetTipcCommand() const { + return static_cast(command_header->type.Value()) - + static_cast(IPC::CommandType::TIPC_CommandRegion); + } + + u32_le GetCommand() const { + return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand(); + } + bool IsTipc() const { return command_header->IsTipc(); } @@ -140,7 +149,7 @@ public: return command_header->type; } - unsigned GetDataPayloadOffset() const { + u32 GetDataPayloadOffset() const { return data_payload_offset; } @@ -296,7 +305,6 @@ private: std::vector buffer_c_desciptors; u32 data_payload_offset{}; - u32 buffer_c_offset{}; u32 handles_offset{}; u32 domain_offset{}; u32_le command{}; -- cgit v1.2.3 From 75f23ad494cc1576f12b27b626e3c0de6817a7de Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 10 May 2021 15:41:46 -0700 Subject: hle: kernel: KClientPort: Cleanup comment format. --- src/core/hle/kernel/k_client_port.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index e14b915b9..4a12dee10 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -91,7 +91,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { // Create a new session. KSession* session = KSession::Create(kernel); if (session == nullptr) { - /* Decrement the session count. */ + // Decrement the session count. const auto prev = num_sessions--; if (prev == max_sessions) { this->NotifyAvailable(); -- cgit v1.2.3 From c6de9657be71a9c659f9c991ec8d024ebf44d56e Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 10 May 2021 15:57:59 -0700 Subject: hle: kernel: Implement named service ports using service interface factory. - This allows us to create a new interface each time ConnectToNamedPort is called, removing the assumption that these are static. --- src/core/hle/kernel/kernel.cpp | 21 +++++++++++---------- src/core/hle/kernel/kernel.h | 18 +++++++++++------- 2 files changed, 22 insertions(+), 17 deletions(-) (limited to 'src/core/hle/kernel') 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 @@ #include "core/hle/kernel/time_manager.h" #include "core/hle/lock.h" #include "core/hle/result.h" +#include "core/hle/service/sm/sm.h" #include "core/memory.h" MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); @@ -656,6 +657,7 @@ struct KernelCore::Impl { /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. + std::unordered_map service_interface_factory; NamedPortTable named_ports; std::unique_ptr exclusive_monitor; @@ -844,18 +846,17 @@ void KernelCore::PrepareReschedule(std::size_t id) { // TODO: Reimplement, this } -void KernelCore::AddNamedPort(std::string name, KClientPort* port) { - port->Open(); - impl->named_ports.emplace(std::move(name), port); +void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) { + impl->service_interface_factory.emplace(std::move(name), factory); } -KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { - return impl->named_ports.find(name); -} - -KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort( - const std::string& name) const { - return impl->named_ports.find(name); +KClientPort* KernelCore::CreateNamedServicePort(std::string name) { + auto search = impl->service_interface_factory.find(name); + if (search == impl->service_interface_factory.end()) { + UNIMPLEMENTED(); + return {}; + } + return &search->second(impl->system.ServiceManager(), impl->system); } 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; struct EventType; } // namespace Core::Timing +namespace Service::SM { +class ServiceManager; +} + namespace Kernel { class KClientPort; @@ -51,6 +55,9 @@ class ServiceThread; class Synchronization; class TimeManager; +using ServiceInterfaceFactory = + std::function; + namespace Init { struct KSlabResourceCounts; } @@ -172,14 +179,11 @@ public: void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); - /// Adds a port to the named port table - void AddNamedPort(std::string name, KClientPort* port); - - /// Finds a port within the named port table with the given name. - NamedPortTable::iterator FindNamedPort(const std::string& name); + /// Registers a named HLE service, passing a factory used to open a port to that service. + void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory); - /// Finds a port within the named port table with the given name. - NamedPortTable::const_iterator FindNamedPort(const std::string& name) const; + /// Opens a port to a service previously registered with RegisterNamedService. + KClientPort* CreateNamedServicePort(std::string name); /// Determines whether or not the given port is a valid named port. bool IsValidNamedPort(NamedPortTable::const_iterator port) const; -- cgit v1.2.3 From f54ea749a4a593f63f75f6d21550534eac5eec8c Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 10 May 2021 15:58:33 -0700 Subject: hle: kernel: svc: Update ConnectToNamedPort to use new CreateNamedServicePort interface. --- src/core/hle/kernel/svc.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') 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 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); // Find the client port. - const auto it = kernel.FindNamedPort(port_name); - if (!kernel.IsValidNamedPort(it)) { - LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); + auto port = kernel.CreateNamedServicePort(port_name); + if (!port) { + LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ResultNotFound; } - auto port = it->second; // Reserve a handle for the port. // NOTE: Nintendo really does write directly to the output handle here. -- cgit v1.2.3 From da25a5986666c55de1421aed978f7e92e5a87c8f Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 10 May 2021 16:05:37 -0700 Subject: hle: service: Implement IPC::CommandType::Close. - This was not actually closing sessions before. --- src/core/hle/kernel/k_server_session.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') 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 UNREACHABLE(); return RESULT_SUCCESS; // Ignore error if asserts are off } - return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); + return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context); case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); @@ -135,7 +135,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { // If there is no domain header, the regular session handler is used } else if (hle_handler != nullptr) { // If this ServerSession has an associated HLE handler, forward the request to it. - result = hle_handler->HandleSyncRequest(context); + result = hle_handler->HandleSyncRequest(*this, context); } if (convert_to_domain) { -- cgit v1.2.3 From 913971417e0732ef813c57c532f9e221641cee9d Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 10 May 2021 16:16:36 -0700 Subject: hle: kernel: hle_ipc: Improve IPC code and add initial support for TIPC. - Fixes our move handles implementation to actually move objects. - Simplifies the traditional IPC path. --- src/core/hle/kernel/hle_ipc.cpp | 135 ++++++++++++++++------------------------ src/core/hle/kernel/hle_ipc.h | 3 +- 2 files changed, 57 insertions(+), 81 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index d6929d2c0..edb3f8d98 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 IPC::RequestParser rp(src_cmdbuf); command_header = rp.PopRaw(); - if (command_header->type == IPC::CommandType::Close) { + if (command_header->IsCloseCommand()) { // Close does not populate the rest of the IPC header return; } @@ -101,37 +101,41 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; - // Padding to align to 16 bytes - rp.AlignWithPadding(); - - if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request || - command_header->type == IPC::CommandType::RequestWithContext) || - !incoming)) { - // If this is an incoming message, only CommandType "Request" has a domain header - // All outgoing domain messages have the domain header, if only incoming has it - if (incoming || domain_message_header) { - domain_message_header = rp.PopRaw(); - } else { - if (Session()->IsDomain()) { - LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); + if (!command_header->IsTipc()) { + // Padding to align to 16 bytes + rp.AlignWithPadding(); + + if (Session()->IsDomain() && + ((command_header->type == IPC::CommandType::Request || + command_header->type == IPC::CommandType::RequestWithContext) || + !incoming)) { + // If this is an incoming message, only CommandType "Request" has a domain header + // All outgoing domain messages have the domain header, if only incoming has it + if (incoming || domain_message_header) { + domain_message_header = rp.PopRaw(); + } else { + if (Session()->IsDomain()) { + LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); + } } } - } - data_payload_header = rp.PopRaw(); + data_payload_header = rp.PopRaw(); - data_payload_offset = rp.GetCurrentOffset(); + data_payload_offset = rp.GetCurrentOffset(); - if (domain_message_header && domain_message_header->command == - IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { - // CloseVirtualHandle command does not have SFC* or any data - return; - } + if (domain_message_header && + domain_message_header->command == + IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { + // CloseVirtualHandle command does not have SFC* or any data + return; + } - if (incoming) { - ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); - } else { - ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); + if (incoming) { + ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); + } else { + ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); + } } rp.SetCurrentOffset(buffer_c_offset); @@ -166,84 +170,55 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf) { ParseCommandBuffer(handle_table, src_cmdbuf, true); - if (command_header->type == IPC::CommandType::Close) { + + if (command_header->IsCloseCommand()) { // Close does not populate the rest of the IPC header return RESULT_SUCCESS; } - // The data_size already includes the payload header, the padding and the domain header. - std::size_t size = data_payload_offset + command_header->data_size - - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; - if (domain_message_header) - size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); - std::copy_n(src_cmdbuf, size, cmd_buf.begin()); + std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin()); + return RESULT_SUCCESS; } ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { + auto current_offset = handles_offset; auto& owner_process = *requesting_thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); - std::array dst_cmdbuf; - memory.ReadBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); - - // The header was already built in the internal command buffer. Attempt to parse it to verify - // the integrity and then copy it over to the target command buffer. - ParseCommandBuffer(handle_table, cmd_buf.data(), false); - - // The data_size already includes the payload header, the padding and the domain header. - std::size_t size = data_payload_offset + command_header->data_size - - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; - if (domain_message_header) - size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); - - std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data()); - - if (command_header->enable_handle_descriptor) { - ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), - "Handle descriptor bit set but no handles to translate"); - // We write the translated handles at a specific offset in the command buffer, this space - // was already reserved when writing the header. - std::size_t current_offset = - (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32); - ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented"); - - ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy); - ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move); - - // We don't make a distinction between copy and move handles when translating since HLE - // services don't deal with handles directly. However, the guest applications might check - // for specific values in each of these descriptors. - for (auto& object : copy_objects) { - ASSERT(object != nullptr); - R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); + for (auto& object : copy_objects) { + Handle handle{}; + if (object) { + R_TRY(handle_table.Add(&handle, object)); } + cmd_buf[current_offset++] = handle; + } + for (auto& object : move_objects) { + Handle handle{}; + if (object) { + R_TRY(handle_table.Add(&handle, object)); - for (auto& object : move_objects) { - ASSERT(object != nullptr); - R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); + // Close our reference to the object, as it is being moved to the caller. + object->Close(); } + cmd_buf[current_offset++] = handle; } - // TODO(Subv): Translate the X/A/B/W buffers. - - if (Session()->IsDomain() && domain_message_header) { - ASSERT(domain_message_header->num_objects == domain_objects.size()); - // Write the domain objects to the command buffer, these go after the raw untranslated data. - // TODO(Subv): This completely ignores C buffers. - std::size_t domain_offset = size - domain_message_header->num_objects; + // Write the domain objects to the command buffer, these go after the raw untranslated data. + // TODO(Subv): This completely ignores C buffers. + if (Session()->IsDomain()) { + current_offset = domain_offset - static_cast(domain_objects.size()); for (const auto& object : domain_objects) { server_session->AppendDomainRequestHandler(object); - dst_cmdbuf[domain_offset++] = + cmd_buf[current_offset++] = static_cast(server_session->NumDomainRequestHandlers()); } } // Copy the translated command buffer back into the thread's command buffer area. - memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), + cmd_buf.size() * sizeof(u32)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 07360629e..3e66e5542 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -66,7 +66,8 @@ public: * this request (ServerSession, Originator thread, Translated command buffer, etc). * @returns ResultCode the result code of the translate operation. */ - virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0; + virtual ResultCode HandleSyncRequest(Kernel::KServerSession& session, + Kernel::HLERequestContext& context) = 0; /** * Signals that a client has just connected to this HLE handler and keeps the -- cgit v1.2.3 From f2c26443f85a3c3fd43137509368ba5c7ab80ee7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 11 May 2021 10:27:18 -0700 Subject: WORKAROUND: Do not use slab heap while we track down issues with resource management. --- src/core/hle/kernel/slab_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') 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 { private: static Derived* Allocate(KernelCore& kernel) { - return kernel.SlabHeap().AllocateWithKernel(kernel); + return new Derived(kernel); } static void Free(KernelCore& kernel, Derived* obj) { - kernel.SlabHeap().Free(obj); + delete obj; } public: -- cgit v1.2.3 From fc086f93b2165b5c210cb7dcd6c18ebe17f1fd7b Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 11 May 2021 10:51:39 -0700 Subject: WORKAROUND: temp. disable session resource limits while we work out issues --- src/core/hle/kernel/k_client_port.cpp | 8 ++++---- src/core/hle/kernel/k_session.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 4a12dee10..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 { ResultCode KClientPort::CreateSession(KClientSession** out) { // Reserve a new session from the resource limit. - KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), - LimitableResource::Sessions); - R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); + // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), + // LimitableResource::Sessions); + // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); // Update the session counts. { @@ -104,7 +104,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { session->Initialize(this, parent->GetName()); // Commit the session reservation. - session_reservation.Commit(); + // session_reservation.Commit(); // Register the session. KSession::Register(kernel, session); 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() { void KSession::PostDestroy(uintptr_t arg) { // Release the session count resource the owner process holds. KProcess* owner = reinterpret_cast(arg); - owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); + // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); owner->Close(); } -- cgit v1.2.3 From 12d569e483834c74613a744abee7f277cc3d4e16 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 11 May 2021 12:27:43 -0700 Subject: hle: kernel: hle_ipc: Fix outgoing IPC response size calculation. --- src/core/hle/kernel/hle_ipc.cpp | 14 +++++++++++++- src/core/hle/kernel/hle_ipc.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index edb3f8d98..ce3466df8 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -186,6 +186,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t auto& owner_process = *requesting_thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); + // The data_size already includes the payload header, the padding and the domain header. + std::size_t size{}; + + if (IsTipc()) { + size = cmd_buf.size(); + } else { + size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; + if (Session()->IsDomain()) { + size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); + } + } + for (auto& object : copy_objects) { Handle handle{}; if (object) { @@ -218,7 +230,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t // Copy the translated command buffer back into the thread's command buffer area. memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), - cmd_buf.size() * sizeof(u32)); + size * sizeof(u32)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 3e66e5542..4fba300dc 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -308,6 +308,7 @@ private: u32 data_payload_offset{}; u32 handles_offset{}; u32 domain_offset{}; + u32 data_size{}; u32_le command{}; std::vector> domain_request_handlers; -- cgit v1.2.3