@ -7,6 +7,7 @@
# include "common/logging/log.h"
# include "core/memory.h"
# include "core/hle/kernel/memory.h"
# include "core/hle/kernel/shared_memory.h"
namespace Kernel {
@ -14,93 +15,94 @@ namespace Kernel {
SharedMemory : : SharedMemory ( ) { }
SharedMemory : : ~ SharedMemory ( ) { }
SharedPtr < SharedMemory > SharedMemory : : Create ( u32 size , MemoryPermission permissions ,
MemoryPermission other_permissions , std: : string name ) {
SharedPtr < SharedMemory > SharedMemory : : Create ( SharedPtr< Process > owner_process , u32 size , MemoryPermission permissions ,
MemoryPermission other_permissions , VAddr address , MemoryRegion region , std: : string name ) {
SharedPtr < SharedMemory > shared_memory ( new SharedMemory ) ;
shared_memory - > owner_process = owner_process ;
shared_memory - > name = std : : move ( name ) ;
shared_memory - > base_address = 0x0 ;
shared_memory - > fixed_address = 0x0 ;
shared_memory - > size = size ;
shared_memory - > permissions = permissions ;
shared_memory - > other_permissions = other_permissions ;
if ( address = = 0 ) {
// We need to allocate a block from the Linear Heap ourselves.
// We'll manually allocate some memory from the linear heap in the specified region.
MemoryRegionInfo * memory_region = GetMemoryRegion ( region ) ;
auto & linheap_memory = memory_region - > linear_heap_memory ;
ASSERT_MSG ( linheap_memory - > size ( ) + size < = memory_region - > size , " Not enough space in region to allocate shared memory! " ) ;
shared_memory - > backing_block = linheap_memory ;
shared_memory - > backing_block_offset = linheap_memory - > size ( ) ;
// Allocate some memory from the end of the linear heap for this region.
linheap_memory - > insert ( linheap_memory - > end ( ) , size , 0 ) ;
memory_region - > used + = size ;
shared_memory - > linear_heap_phys_address = Memory : : FCRAM_PADDR + memory_region - > base + shared_memory - > backing_block_offset ;
// Refresh the address mappings for the current process.
if ( Kernel : : g_current_process ! = nullptr ) {
Kernel : : g_current_process - > vm_manager . RefreshMemoryBlockMappings ( linheap_memory . get ( ) ) ;
}
} else {
auto & vm_manager = shared_memory - > owner_process - > vm_manager ;
// The memory is already available and mapped in the owner process.
auto vma = vm_manager . FindVMA ( address ) - > second ;
// Copy it over to our own storage
shared_memory - > backing_block = std : : make_shared < std : : vector < u8 > > ( vma . backing_block - > data ( ) + vma . offset ,
vma . backing_block - > data ( ) + vma . offset + size ) ;
// Unmap the existing pages
vm_manager . UnmapRange ( address , size ) ;
// Map our own block into the address space
vm_manager . MapMemoryBlock ( address , shared_memory - > backing_block , 0 , size , MemoryState : : Shared ) ;
}
shared_memory - > base_address = address ;
return shared_memory ;
}
ResultCode SharedMemory : : Map ( VAddr address , MemoryPermission permissions ,
ResultCode SharedMemory : : Map ( Process* target_process , VAddr address , MemoryPermission permissions ,
MemoryPermission other_permissions ) {
if ( base_address ! = 0 ) {
LOG_ERROR ( Kernel , " cannot map id=%u, address=0x%08X name=%s: already mapped at 0x%08X! " ,
GetObjectId ( ) , address , name . c_str ( ) , base_address ) ;
// TODO: Verify error code with hardware
return ResultCode ( ErrorDescription : : InvalidAddress , ErrorModule : : Kernel ,
ErrorSummary : : InvalidArgument , ErrorLevel : : Permanent ) ;
}
// TODO(Subv): Return E0E01BEE when permissions and other_permissions don't
// match what was specified when the memory block was created.
// TODO(Subv): Return E0E01BEE when address should be 0.
// Note: Find out when that's the case.
// TODO(Subv): Check for the Shared Device Mem flag in the creator process.
/*if (was_created_with_shared_device_mem && address != 0) {
return ResultCode ( ErrorDescription : : InvalidCombination , ErrorModule : : OS , ErrorSummary : : InvalidArgument , ErrorLevel : : Usage ) ;
} */
if ( fixed_address ! = 0 ) {
if ( address ! = 0 & & address ! = fixed_address ) {
LOG_ERROR ( Kernel , " cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X! " ,
GetObjectId ( ) , address , name . c_str ( ) , fixed_address ) ;
// TODO: Verify error code with hardware
return ResultCode ( ErrorDescription : : InvalidAddress , ErrorModule : : Kernel ,
ErrorSummary : : InvalidArgument , ErrorLevel : : Permanent ) ;
}
// TODO(Subv): The same process that created a SharedMemory object
// can not map it in its own address space unless it was created with addr=0, result 0xD900182C.
// HACK(yuriks): This is only here to support the APT shared font mapping right now.
// Later, this should actually map the memory block onto the address space.
return RESULT_SUCCESS ;
}
if ( address < Memory : : SHARED_MEMORY_VADDR | | address + size > = Memory : : SHARED_MEMORY_VADDR_END ) {
LOG_ERROR ( Kernel , " cannot map id=%u, address=0x%08X name=%s outside of shared mem bounds! " ,
if ( address < Memory : : HEAP_VADDR | | address + size > = Memory : : SHARED_MEMORY_VADDR_END ) {
LOG_ERROR ( Kernel , " cannot map id=%u, address=0x%08X name=%s, invalid address " ,
GetObjectId ( ) , address , name . c_str ( ) ) ;
// TODO: Verify error code with hardware
return ResultCode ( ErrorDescription : : InvalidAddress , ErrorModule : : Kernel ,
ErrorSummary : : InvalidArgument , ErrorLevel : : Permanent ) ;
return ResultCode ( ErrorDescription : : InvalidAddress , ErrorModule : : OS ,
ErrorSummary : : InvalidArgument , ErrorLevel : : Usage ) ;
}
// TODO: Test permissions
VAddr target_address = address ;
// HACK: Since there's no way to write to the memory block without mapping it onto the game
// process yet, at least initialize memory the first time it's mapped.
if ( address ! = this - > base_address ) {
std : : memset ( Memory : : GetPointer ( address ) , 0 , size ) ;
if ( base_address = = 0 & & target_address = = 0 ) {
// Calculate the address at which to map the memory block.
target_address = Memory : : PhysicalToVirtualAddress ( linear_heap_phys_address ) ;
}
this - > base_address = address ;
// Map the memory block into the target process
target_process - > vm_manager . MapMemoryBlock ( target_address , backing_block , backing_block_offset , size , MemoryState : : Shared ) ;
return RESULT_SUCCESS ;
}
ResultCode SharedMemory : : Unmap ( VAddr address ) {
if ( base_address = = 0 ) {
// TODO(Subv): Verify what actually happens when you want to unmap a memory block that
// was originally mapped with address = 0
return ResultCode ( ErrorDescription : : InvalidAddress , ErrorModule : : OS , ErrorSummary : : InvalidArgument , ErrorLevel : : Usage ) ;
}
if ( base_address ! = address )
return ResultCode ( ErrorDescription : : WrongAddress , ErrorModule : : OS , ErrorSummary : : InvalidState , ErrorLevel : : Usage ) ;
base_address = 0 ;
return RESULT_SUCCESS ;
ResultCode SharedMemory : : Unmap ( Process * target_process , VAddr address ) {
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
return target_process - > vm_manager . UnmapRange ( address , size ) ;
}
u8 * SharedMemory : : GetPointer ( u32 offset ) {
if ( base_address ! = 0 )
return Memory : : GetPointer ( base_address + offset ) ;
LOG_ERROR ( Kernel_SVC , " memory block id=%u not mapped! " , GetObjectId ( ) ) ;
return nullptr ;
return backing_block - > data ( ) + backing_block_offset + offset ;
}
} // namespace