From 19291ba4655a9dac59a0222efe0e019b7e56fe3b Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Tue, 11 Sep 2018 14:34:18 -0400 Subject: [PATCH] LLE Mapped Buffer: Add unmapping, zero-size, and multiple page handling --- src/core/hle/kernel/ipc.cpp | 49 ++++++++++++++++++++++++-------- src/core/hle/kernel/vm_manager.h | 3 ++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 8db9d241f..8a6214409 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -128,7 +128,11 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr> Memory::PAGE_BITS; - ASSERT(num_pages >= 1); + // Skip when the size is zero + if (size == 0) { + i += 1; + break; + } if (reply) { // TODO(Subv): Scan the target's command buffer to make sure that there was a @@ -139,13 +143,23 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrvm_manager.UnmapRange( + page_start, num_pages * Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + } else { + const auto vma_iter = src_process->vm_manager.vma_map.find(source_address); + const auto& vma = vma_iter->second; + const VAddr dest_address = vma.originating_buffer_address; + + auto buffer = std::make_shared>(size); + Memory::ReadBlock(*src_process, source_address, buffer->data(), size); + Memory::WriteBlock(*dst_process, dest_address, buffer->data(), size); + ResultCode result = src_process->vm_manager.UnmapRange( page_start, num_pages * Memory::PAGE_SIZE); ASSERT(result == RESULT_SUCCESS); } - ASSERT_MSG(permissions == IPC::MappedBufferPermissions::R, - "Unmapping Write MappedBuffers is unimplemented"); i += 1; break; } @@ -156,19 +170,13 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr src_thread, SharedPtr(buffer->size()), Kernel::MemoryState::Shared) .Unwrap(); + } else { + auto buffer = std::make_shared>(num_pages * Memory::PAGE_SIZE); + Memory::ReadBlock(*src_process, source_address, buffer->data() + page_offset, size); + + // Map the pages into the target process' address space. + target_address = + dst_process->vm_manager + .MapMemoryBlockToBase(Memory::IPC_MAPPING_VADDR + Memory::PAGE_SIZE, + Memory::IPC_MAPPING_SIZE - Memory::PAGE_SIZE, buffer, + 0, static_cast(buffer->size()), + Kernel::MemoryState::Shared) + .Unwrap(); } + // Save the original address we copied the buffer from so that we can copy the modified + // buffer back, if needed + auto vma_iter = dst_process->vm_manager.vma_map.find(target_address + page_offset); + auto& vma = vma_iter->second; + vma.originating_buffer_address = source_address; cmd_buf[i++] = target_address + page_offset; break; diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 7ac5c3b01..fcb107c06 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -86,6 +86,9 @@ struct VirtualMemoryArea { PAddr paddr = 0; Memory::MMIORegionPointer mmio_handler = nullptr; + /// Originating address of the IPC mapped buffer + VAddr originating_buffer_address = 0; + /// Tests if this area can be merged to the right with `next`. bool CanBeMergedWith(const VirtualMemoryArea& next) const; };