diff options
| author | 2016-04-17 21:58:51 -0500 | |
|---|---|---|
| committer | 2016-05-12 20:01:26 -0500 | |
| commit | 0fb6d2a24729401e17cd69264cdb630516d9c151 (patch) | |
| tree | d51689fbf847d396496d9e8ff372bc7dfcc65c0e | |
| parent | APT: Implement relocating the shared font to its true address. (diff) | |
| download | yuzu-0fb6d2a24729401e17cd69264cdb630516d9c151.tar.gz yuzu-0fb6d2a24729401e17cd69264cdb630516d9c151.tar.xz yuzu-0fb6d2a24729401e17cd69264cdb630516d9c151.zip | |
Kernel: Implemented shared memory permissions.
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 50 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.h | 6 | ||||
| -rw-r--r-- | src/core/hle/result.h | 1 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 2 |
4 files changed, 50 insertions, 9 deletions
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 6f731f317..c1e0e556b 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -46,6 +46,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 46 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); | 46 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); |
| 47 | } | 47 | } |
| 48 | } else { | 48 | } else { |
| 49 | // TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address? | ||
| 49 | auto& vm_manager = shared_memory->owner_process->vm_manager; | 50 | auto& vm_manager = shared_memory->owner_process->vm_manager; |
| 50 | // The memory is already available and mapped in the owner process. | 51 | // The memory is already available and mapped in the owner process. |
| 51 | auto vma = vm_manager.FindVMA(address)->second; | 52 | auto vma = vm_manager.FindVMA(address)->second; |
| @@ -56,6 +57,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 56 | vm_manager.UnmapRange(address, size); | 57 | vm_manager.UnmapRange(address, size); |
| 57 | // Map our own block into the address space | 58 | // Map our own block into the address space |
| 58 | vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared); | 59 | vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared); |
| 60 | // Reprotect the block with the new permissions | ||
| 61 | vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions)); | ||
| 59 | } | 62 | } |
| 60 | 63 | ||
| 61 | shared_memory->base_address = address; | 64 | shared_memory->base_address = address; |
| @@ -65,8 +68,28 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 65 | ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, | 68 | ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, |
| 66 | MemoryPermission other_permissions) { | 69 | MemoryPermission other_permissions) { |
| 67 | 70 | ||
| 68 | // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't | 71 | MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions; |
| 69 | // match what was specified when the memory block was created. | 72 | |
| 73 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare | ||
| 74 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { | ||
| 75 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 76 | } | ||
| 77 | |||
| 78 | // Error out if the requested permissions don't match what the creator process allows. | ||
| 79 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { | ||
| 80 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 81 | } | ||
| 82 | |||
| 83 | // Heap-backed memory blocks can not be mapped with other_permissions = DontCare | ||
| 84 | if (base_address != 0 && other_permissions == MemoryPermission::DontCare) { | ||
| 85 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 86 | } | ||
| 87 | |||
| 88 | // Error out if the provided permissions are not compatible with what the creator process needs. | ||
| 89 | if (other_permissions != MemoryPermission::DontCare && | ||
| 90 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { | ||
| 91 | return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 92 | } | ||
| 70 | 93 | ||
| 71 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. | 94 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. |
| 72 | /*if (was_created_with_shared_device_mem && address != 0) { | 95 | /*if (was_created_with_shared_device_mem && address != 0) { |
| @@ -76,11 +99,13 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 76 | // TODO(Subv): The same process that created a SharedMemory object | 99 | // TODO(Subv): The same process that created a SharedMemory object |
| 77 | // can not map it in its own address space unless it was created with addr=0, result 0xD900182C. | 100 | // can not map it in its own address space unless it was created with addr=0, result 0xD900182C. |
| 78 | 101 | ||
| 79 | if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { | 102 | if (address != 0) { |
| 80 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address", | 103 | if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { |
| 81 | GetObjectId(), address, name.c_str()); | 104 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address", |
| 82 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, | 105 | GetObjectId(), address, name.c_str()); |
| 83 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 106 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, |
| 107 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 108 | } | ||
| 84 | } | 109 | } |
| 85 | 110 | ||
| 86 | VAddr target_address = address; | 111 | VAddr target_address = address; |
| @@ -91,9 +116,11 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 91 | } | 116 | } |
| 92 | 117 | ||
| 93 | // Map the memory block into the target process | 118 | // Map the memory block into the target process |
| 94 | target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | 119 | auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared); |
| 120 | if (result.Failed()) | ||
| 121 | return result.Code(); | ||
| 95 | 122 | ||
| 96 | return RESULT_SUCCESS; | 123 | return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions)); |
| 97 | } | 124 | } |
| 98 | 125 | ||
| 99 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { | 126 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { |
| @@ -101,6 +128,11 @@ ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { | |||
| 101 | return target_process->vm_manager.UnmapRange(address, size); | 128 | return target_process->vm_manager.UnmapRange(address, size); |
| 102 | } | 129 | } |
| 103 | 130 | ||
| 131 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | ||
| 132 | u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute); | ||
| 133 | return static_cast<VMAPermission>(masked_permissions); | ||
| 134 | }; | ||
| 135 | |||
| 104 | u8* SharedMemory::GetPointer(u32 offset) { | 136 | u8* SharedMemory::GetPointer(u32 offset) { |
| 105 | return backing_block->data() + backing_block_offset + offset; | 137 | return backing_block->data() + backing_block_offset + offset; |
| 106 | } | 138 | } |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index b442cb764..af145bef5 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -49,6 +49,12 @@ public: | |||
| 49 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 49 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| 52 | * Converts the specified MemoryPermission into the equivalent VMAPermission. | ||
| 53 | * @param permission The MemoryPermission to convert. | ||
| 54 | */ | ||
| 55 | static VMAPermission ConvertPermissions(MemoryPermission permission); | ||
| 56 | |||
| 57 | /** | ||
| 52 | * Maps a shared memory block to an address in the target process' address space | 58 | * Maps a shared memory block to an address in the target process' address space |
| 53 | * @param target_process Process on which to map the memory block. | 59 | * @param target_process Process on which to map the memory block. |
| 54 | * @param address Address in system memory to map shared memory block to | 60 | * @param address Address in system memory to map shared memory block to |
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 3fc1ab4ee..bfb3327ce 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | /// Detailed description of the error. This listing is likely incomplete. | 17 | /// Detailed description of the error. This listing is likely incomplete. |
| 18 | enum class ErrorDescription : u32 { | 18 | enum class ErrorDescription : u32 { |
| 19 | Success = 0, | 19 | Success = 0, |
| 20 | WrongPermission = 46, | ||
| 20 | OS_InvalidBufferDescriptor = 48, | 21 | OS_InvalidBufferDescriptor = 48, |
| 21 | WrongAddress = 53, | 22 | WrongAddress = 53, |
| 22 | FS_NotFound = 120, | 23 | FS_NotFound = 120, |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 701dffef3..3a53126c1 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -99,6 +99,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add | |||
| 99 | switch (operation & MEMOP_OPERATION_MASK) { | 99 | switch (operation & MEMOP_OPERATION_MASK) { |
| 100 | case MEMOP_FREE: | 100 | case MEMOP_FREE: |
| 101 | { | 101 | { |
| 102 | // TODO(Subv): What happens if an application tries to FREE a block of memory that has a SharedMemory pointing to it? | ||
| 102 | if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { | 103 | if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { |
| 103 | ResultCode result = process.HeapFree(addr0, size); | 104 | ResultCode result = process.HeapFree(addr0, size); |
| 104 | if (result.IsError()) return result; | 105 | if (result.IsError()) return result; |
| @@ -798,6 +799,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | |||
| 798 | case MemoryPermission::Read: | 799 | case MemoryPermission::Read: |
| 799 | case MemoryPermission::Write: | 800 | case MemoryPermission::Write: |
| 800 | case MemoryPermission::ReadWrite: | 801 | case MemoryPermission::ReadWrite: |
| 802 | case MemoryPermission::DontCare: | ||
| 801 | return true; | 803 | return true; |
| 802 | default: | 804 | default: |
| 803 | return false; | 805 | return false; |