diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 779979fc7..d62889e5b 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/alignment.h" #include "core/hle/ipc.h" #include "core/hle/kernel/handle_table.h" @@ -14,70 +15,10 @@ namespace Kernel { -void ScanForAndUnmapBuffer(std::array& dst_cmd_buf, - const std::size_t dst_command_size, std::size_t& target_index, - SharedPtr src_process, SharedPtr dst_process, - const VAddr source_address, const VAddr page_start, const u32 num_pages, - const u32 size, const IPC::MappedBufferPermissions permissions) { - while (target_index < dst_command_size) { - u32 desc = dst_cmd_buf[target_index++]; - - if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::CopyHandle || - IPC::GetDescriptorType(desc) == IPC::DescriptorType::MoveHandle) { - u32 num_handles = IPC::HandleNumberFromDesc(desc); - for (u32 j = 0; j < num_handles; ++j) { - target_index += 1; - } - continue; - } - - if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::CallingPid || - IPC::GetDescriptorType(desc) == IPC::DescriptorType::StaticBuffer) { - target_index += 1; - continue; - } - - if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::MappedBuffer) { - VAddr dest_address = dst_cmd_buf[target_index]; - IPC::MappedBufferDescInfo dest_descInfo{desc}; - u32 dest_size = static_cast(dest_descInfo.size); - IPC::MappedBufferPermissions dest_permissions = dest_descInfo.perms; - - if (dest_size == 0) { - target_index += 1; - continue; - } - - ASSERT(permissions == dest_permissions && size == dest_size); - // Readonly buffers do not need to be copied over to the target - // process again because they were (presumably) not modified. This - // behavior is consistent with the real kernel. - if (permissions != IPC::MappedBufferPermissions::R) { - // Copy the modified buffer back into the target process - Memory::CopyBlock(*src_process, *dst_process, source_address, dest_address, size); - } - - VAddr prev_reserve = page_start - Memory::PAGE_SIZE; - VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; - - auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; - auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; - ASSERT(prev_vma.meminfo_state == MemoryState::Reserved && - next_vma.meminfo_state == MemoryState::Reserved); - - // Unmap the buffer and guard pages from the source process - ResultCode result = src_process->vm_manager.UnmapRange( - page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); - - target_index += 1; - break; - } - } -} - ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr dst_thread, - VAddr src_address, VAddr dst_address, bool reply) { + VAddr src_address, VAddr dst_address, + std::vector& mapped_buffer_context, + bool reply) { auto& src_process = src_thread->owner_process; auto& dst_process = dst_thread->owner_process; @@ -95,18 +36,6 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr cmd_buf; Memory::ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32)); - // Create a copy of the target's command buffer - IPC::Header dst_header; - Memory::ReadBlock(*dst_process, dst_address, &dst_header.raw, sizeof(dst_header.raw)); - - std::size_t dst_untranslated_size = 1u + dst_header.normal_params_size; - std::size_t dst_command_size = dst_untranslated_size + dst_header.translate_params_size; - std::size_t target_index = dst_untranslated_size; - - std::array dst_cmd_buf; - Memory::ReadBlock(*dst_process, dst_address, dst_cmd_buf.data(), - dst_command_size * sizeof(u32)); - std::size_t i = untranslated_size; while (i < command_size) { u32 descriptor = cmd_buf[i]; @@ -212,9 +141,36 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrtarget_address, + found->source_address, size); + } + + VAddr prev_reserve = page_start - Memory::PAGE_SIZE; + VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; + + auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; + auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; + ASSERT(prev_vma.meminfo_state == MemoryState::Reserved && + next_vma.meminfo_state == MemoryState::Reserved); + + // Unmap the buffer and guard pages from the source process + ResultCode result = src_process->vm_manager.UnmapRange( + page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + + mapped_buffer_context.erase(found); i += 1; break; @@ -246,6 +202,9 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrvm_manager.MapMemoryBlockToBase( Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, 0, static_cast(reserve_buffer->size()), Kernel::MemoryState::Reserved); + + mapped_buffer_context.push_back({permissions, size, source_address, target_address}); + break; } default: diff --git a/src/core/hle/kernel/ipc.h b/src/core/hle/kernel/ipc.h index d77fd1d1f..6ca4dbb6e 100644 --- a/src/core/hle/kernel/ipc.h +++ b/src/core/hle/kernel/ipc.h @@ -4,11 +4,23 @@ #pragma once +#include #include "common/common_types.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/thread.h" namespace Kernel { + +struct MappedBufferContext { + IPC::MappedBufferPermissions permissions; + u32 size; + VAddr source_address; + VAddr target_address; +}; + /// Performs IPC command buffer translation from one process to another. ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr dst_thread, - VAddr src_address, VAddr dst_address, bool reply); + VAddr src_address, VAddr dst_address, + std::vector& mapped_buffer_context, + bool reply); } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 18411e417..956deba3f 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -8,6 +8,7 @@ #include #include "common/assert.h" #include "common/common_types.h" +#include "core/hle/kernel/ipc.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" @@ -83,6 +84,9 @@ public: /// TODO(Subv): Find a better name for this. SharedPtr currently_handling; + /// A temporary list holding mapped buffer info from IPC request, used for during IPC reply + std::vector mapped_buffer_context; + private: explicit ServerSession(KernelSystem& kernel); ~ServerSession() override; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 53728a66d..59771e14f 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -600,8 +600,9 @@ static ResultCode ReceiveIPCRequest(SharedPtr server_session, VAddr target_address = thread->GetCommandBufferAddress(); VAddr source_address = server_session->currently_handling->GetCommandBufferAddress(); - ResultCode translation_result = TranslateCommandBuffer( - server_session->currently_handling, thread, source_address, target_address, false); + ResultCode translation_result = + TranslateCommandBuffer(server_session->currently_handling, thread, source_address, + target_address, server_session->mapped_buffer_context, false); // If a translation error occurred, immediately resume the client thread. if (translation_result.IsError()) { @@ -667,7 +668,8 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co VAddr target_address = request_thread->GetCommandBufferAddress(); ResultCode translation_result = - TranslateCommandBuffer(thread, request_thread, source_address, target_address, true); + TranslateCommandBuffer(thread, request_thread, source_address, target_address, + session->mapped_buffer_context, true); // Note: The real kernel seems to always panic if the Server->Client buffer translation // fails for whatever reason.