From 0b8d2ecabefe556be1cc0c78d4ee170f00bbced2 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 8 Nov 2018 13:53:20 -0500 Subject: [PATCH] IPC: store mapped buffer info in session context So that it doesn't have to scan over the request buffer again on reply. This also allow us to store additional info like memory mapping --- src/core/hle/kernel/ipc.cpp | 115 +++++++++------------------ src/core/hle/kernel/ipc.h | 14 +++- src/core/hle/kernel/server_session.h | 4 + src/core/hle/kernel/svc.cpp | 8 +- 4 files changed, 59 insertions(+), 82 deletions(-) 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.