mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-20 07:20:08 +00:00
LLE Mapped Buffer: Add unmapping, zero-size, and multiple page handling
This commit is contained in:
parent
9f972b9f5c
commit
19291ba465
@ -128,7 +128,11 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
|||||||
u32 num_pages =
|
u32 num_pages =
|
||||||
Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS;
|
Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS;
|
||||||
|
|
||||||
ASSERT(num_pages >= 1);
|
// Skip when the size is zero
|
||||||
|
if (size == 0) {
|
||||||
|
i += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
// TODO(Subv): Scan the target's command buffer to make sure that there was a
|
// TODO(Subv): Scan the target's command buffer to make sure that there was a
|
||||||
@ -139,13 +143,23 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
|||||||
// process again because they were (presumably) not modified. This behavior is
|
// process again because they were (presumably) not modified. This behavior is
|
||||||
// consistent with the real kernel.
|
// consistent with the real kernel.
|
||||||
if (permissions == IPC::MappedBufferPermissions::R) {
|
if (permissions == IPC::MappedBufferPermissions::R) {
|
||||||
|
ResultCode result = src_process->vm_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<std::vector<u8>>(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(
|
ResultCode result = src_process->vm_manager.UnmapRange(
|
||||||
page_start, num_pages * Memory::PAGE_SIZE);
|
page_start, num_pages * Memory::PAGE_SIZE);
|
||||||
ASSERT(result == RESULT_SUCCESS);
|
ASSERT(result == RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_MSG(permissions == IPC::MappedBufferPermissions::R,
|
|
||||||
"Unmapping Write MappedBuffers is unimplemented");
|
|
||||||
i += 1;
|
i += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -156,19 +170,13 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
|||||||
return (address & Memory::PAGE_MASK) == 0;
|
return (address & Memory::PAGE_MASK) == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(Subv): Support more than 1 page and aligned page mappings
|
|
||||||
ASSERT_MSG(
|
|
||||||
num_pages == 1 &&
|
|
||||||
(!IsPageAligned(source_address) || !IsPageAligned(source_address + size)),
|
|
||||||
"MappedBuffers of more than one page or aligned transfers are not implemented");
|
|
||||||
|
|
||||||
// TODO(Subv): Perform permission checks.
|
// TODO(Subv): Perform permission checks.
|
||||||
|
|
||||||
// TODO(Subv): Leave a page of Reserved memory before the first page and after the last
|
// TODO(Subv): Leave a page of unmapped memory before the first page and after the last
|
||||||
// page.
|
// page.
|
||||||
|
|
||||||
if (!IsPageAligned(source_address) ||
|
if (num_pages == 1 && !IsPageAligned(source_address) &&
|
||||||
(num_pages == 1 && !IsPageAligned(source_address + size))) {
|
!IsPageAligned(source_address + size)) {
|
||||||
// If the address of the source buffer is not page-aligned or if the buffer doesn't
|
// If the address of the source buffer is not page-aligned or if the buffer doesn't
|
||||||
// fill an entire page, then we have to allocate a page of memory in the target
|
// fill an entire page, then we have to allocate a page of memory in the target
|
||||||
// process and copy over the data from the input buffer. This allocated buffer will
|
// process and copy over the data from the input buffer. This allocated buffer will
|
||||||
@ -195,7 +203,24 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
|||||||
buffer, 0, static_cast<u32>(buffer->size()),
|
buffer, 0, static_cast<u32>(buffer->size()),
|
||||||
Kernel::MemoryState::Shared)
|
Kernel::MemoryState::Shared)
|
||||||
.Unwrap();
|
.Unwrap();
|
||||||
|
} else {
|
||||||
|
auto buffer = std::make_shared<std::vector<u8>>(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<u32>(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;
|
cmd_buf[i++] = target_address + page_offset;
|
||||||
break;
|
break;
|
||||||
|
@ -86,6 +86,9 @@ struct VirtualMemoryArea {
|
|||||||
PAddr paddr = 0;
|
PAddr paddr = 0;
|
||||||
Memory::MMIORegionPointer mmio_handler = nullptr;
|
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`.
|
/// Tests if this area can be merged to the right with `next`.
|
||||||
bool CanBeMergedWith(const VirtualMemoryArea& next) const;
|
bool CanBeMergedWith(const VirtualMemoryArea& next) const;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user