@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Refer to the license.txt file included.
# include "common/alignment.h"
# include "core/hle/ipc.h"
# include "core/hle/ipc.h"
# include "core/hle/kernel/handle_table.h"
# include "core/hle/kernel/handle_table.h"
# include "core/hle/kernel/ipc.h"
# include "core/hle/kernel/ipc.h"
@ -14,7 +15,7 @@
namespace Kernel {
namespace Kernel {
ResultCode TranslateCommandBuffer ( SharedPtr < Thread > src_thread , SharedPtr < Thread > dst_thread ,
ResultCode TranslateCommandBuffer ( SharedPtr < Thread > src_thread , SharedPtr < Thread > dst_thread ,
VAddr src_address , VAddr dst_address ) {
VAddr src_address , VAddr dst_address , bool reply ) {
auto & src_process = src_thread - > owner_process ;
auto & src_process = src_thread - > owner_process ;
auto & dst_process = dst_thread - > owner_process ;
auto & dst_process = dst_thread - > owner_process ;
@ -115,6 +116,88 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
cmd_buf [ i + + ] = target_buffer . address ;
cmd_buf [ i + + ] = target_buffer . address ;
break ;
break ;
}
}
case IPC : : DescriptorType : : MappedBuffer : {
IPC : : MappedBufferDescInfo descInfo { descriptor } ;
VAddr source_address = cmd_buf [ i ] ;
size_t size = descInfo . size ;
IPC : : MappedBufferPermissions permissions = descInfo . perms ;
VAddr page_start = Common : : AlignDown ( source_address , Memory : : PAGE_SIZE ) ;
u32 page_offset = source_address - page_start ;
u32 num_pages =
Common : : AlignUp ( page_offset + size , Memory : : PAGE_SIZE ) > > Memory : : PAGE_BITS ;
ASSERT ( num_pages > = 1 ) ;
if ( reply ) {
// TODO(Subv): Scan the target's command buffer to make sure that there was a
// MappedBuffer descriptor in the original request. The real kernel panics if you
// try to reply with an unsolicited MappedBuffer.
// Unmap the buffers. 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 ) {
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 ;
}
VAddr target_address = 0 ;
auto IsPageAligned = [ ] ( VAddr address ) - > bool {
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): Leave a page of Reserved memory before the first page and after the last
// page.
if ( ! IsPageAligned ( source_address ) | |
( num_pages = = 1 & & ! IsPageAligned ( source_address + size ) ) ) {
// 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
// process and copy over the data from the input buffer. This allocated buffer will
// be copied back to the source process and deallocated when the server replies to
// the request via ReplyAndReceive.
auto buffer = std : : make_shared < std : : vector < u8 > > ( Memory : : PAGE_SIZE ) ;
// Number of bytes until the next page.
size_t difference_to_page =
Common : : AlignUp ( source_address , Memory : : PAGE_SIZE ) - source_address ;
// If the data fits in one page we can just copy the required size instead of the
// entire page.
size_t read_size = num_pages = = 1 ? size : difference_to_page ;
Memory : : ReadBlock ( * src_process , source_address , buffer - > data ( ) + page_offset ,
read_size ) ;
// Map the page into the target process' address space.
target_address = dst_process - > vm_manager
. MapMemoryBlockToBase (
Memory : : IPC_MAPPING_VADDR , Memory : : IPC_MAPPING_SIZE ,
buffer , 0 , buffer - > size ( ) , Kernel : : MemoryState : : Shared )
. Unwrap ( ) ;
}
cmd_buf [ i + + ] = target_address + page_offset ;
break ;
}
default :
default :
UNIMPLEMENTED_MSG ( " Unsupported handle translation: 0x%08X " , descriptor ) ;
UNIMPLEMENTED_MSG ( " Unsupported handle translation: 0x%08X " , descriptor ) ;
}
}