diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 8db9d241f1..8a62144097 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 7ac5c3b016..fcb107c06f 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; };