diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 8138002fc..dade1f520 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -195,18 +195,13 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy // TODO(Subv): Perform permission checks. - // Reserve a page of memory before the mapped buffer - std::shared_ptr reserve_buffer = - std::make_shared(Memory::CITRA_PAGE_SIZE); - dst_process->vm_manager.MapBackingMemoryToBase( - Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, - Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Reserved); - + // Create a buffer which contains the mapped buffer and two additional guard pages. std::shared_ptr buffer = - std::make_shared(num_pages * Memory::CITRA_PAGE_SIZE); - memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size); + std::make_shared((num_pages + 2) * Memory::CITRA_PAGE_SIZE); + memory.ReadBlock(*src_process, source_address, + buffer->GetPtr() + Memory::CITRA_PAGE_SIZE + page_offset, size); - // Map the page(s) into the target process' address space. + // Map the guard pages and mapped pages at once. target_address = dst_process->vm_manager .MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, @@ -214,16 +209,25 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy Kernel::MemoryState::Shared) .Unwrap(); + // Change the permissions and state of the guard pages. + const VAddr low_guard_address = target_address; + const VAddr high_guard_address = + low_guard_address + static_cast(buffer->GetSize()) - Memory::CITRA_PAGE_SIZE; + ASSERT(dst_process->vm_manager.ChangeMemoryState( + low_guard_address, Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Shared, + Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Reserved, + Kernel::VMAPermission::None) == RESULT_SUCCESS); + ASSERT(dst_process->vm_manager.ChangeMemoryState( + high_guard_address, Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Shared, + Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Reserved, + Kernel::VMAPermission::None) == RESULT_SUCCESS); + + // Get proper mapped buffer address and store it in the cmd buffer. + target_address += Memory::CITRA_PAGE_SIZE; cmd_buf[i++] = target_address + page_offset; - // Reserve a page of memory after the mapped buffer - dst_process->vm_manager.MapBackingMemoryToBase( - Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, - static_cast(reserve_buffer->GetSize()), Kernel::MemoryState::Reserved); - mapped_buffer_context.push_back({permissions, size, source_address, - target_address + page_offset, std::move(buffer), - std::move(reserve_buffer)}); + target_address + page_offset, std::move(buffer)}); break; } diff --git a/src/core/hle/kernel/ipc.h b/src/core/hle/kernel/ipc.h index 2a5fcb4b2..c1fd5b6fb 100644 --- a/src/core/hle/kernel/ipc.h +++ b/src/core/hle/kernel/ipc.h @@ -26,7 +26,6 @@ struct MappedBufferContext { VAddr target_address; std::shared_ptr buffer; - std::shared_ptr reserve_buffer; private: template @@ -36,7 +35,6 @@ private: ar& source_address; ar& target_address; ar& buffer; - ar& reserve_buffer; } friend class boost::serialization::access; };