diff options
| author | 2020-04-08 18:53:52 -0400 | |
|---|---|---|
| committer | 2020-04-17 00:59:32 -0400 | |
| commit | d0162fc3d7841190bf163afc754b0ec0cdbd7462 (patch) | |
| tree | 28617dc6c379ed3814d08e771dfbc0b172f35b8c /src/core | |
| parent | core: device_memory: Update to use VirtualBuffer class. (diff) | |
| download | yuzu-d0162fc3d7841190bf163afc754b0ec0cdbd7462.tar.gz yuzu-d0162fc3d7841190bf163afc754b0ec0cdbd7462.tar.xz yuzu-d0162fc3d7841190bf163afc754b0ec0cdbd7462.zip | |
kernel: shared_memory: Refactor for new VMM.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 151 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.h | 127 |
2 files changed, 58 insertions, 220 deletions
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index afb2e3fc2..e28da6869 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -2,149 +2,56 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <utility> | ||
| 6 | |||
| 7 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 6 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/errors.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/memory/page_table.h" | ||
| 11 | #include "core/hle/kernel/shared_memory.h" | 9 | #include "core/hle/kernel/shared_memory.h" |
| 12 | 10 | ||
| 13 | namespace Kernel { | 11 | namespace Kernel { |
| 14 | 12 | ||
| 15 | SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {} | 13 | SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) |
| 16 | SharedMemory::~SharedMemory() = default; | 14 | : Object{kernel}, device_memory{device_memory} {} |
| 17 | |||
| 18 | std::shared_ptr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, | ||
| 19 | u64 size, MemoryPermission permissions, | ||
| 20 | MemoryPermission other_permissions, | ||
| 21 | VAddr address, MemoryRegion region, | ||
| 22 | std::string name) { | ||
| 23 | std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel); | ||
| 24 | |||
| 25 | shared_memory->owner_process = owner_process; | ||
| 26 | shared_memory->name = std::move(name); | ||
| 27 | shared_memory->size = size; | ||
| 28 | shared_memory->permissions = permissions; | ||
| 29 | shared_memory->other_permissions = other_permissions; | ||
| 30 | |||
| 31 | if (address == 0) { | ||
| 32 | shared_memory->backing_block = std::make_shared<Kernel::PhysicalMemory>(size); | ||
| 33 | shared_memory->backing_block_offset = 0; | ||
| 34 | |||
| 35 | // Refresh the address mappings for the current process. | ||
| 36 | if (kernel.CurrentProcess() != nullptr) { | ||
| 37 | kernel.CurrentProcess()->VMManager().RefreshMemoryBlockMappings( | ||
| 38 | shared_memory->backing_block.get()); | ||
| 39 | } | ||
| 40 | } else { | ||
| 41 | const auto& vm_manager = shared_memory->owner_process->VMManager(); | ||
| 42 | 15 | ||
| 43 | // The memory is already available and mapped in the owner process. | 16 | SharedMemory::~SharedMemory() = default; |
| 44 | const auto vma = vm_manager.FindVMA(address); | ||
| 45 | ASSERT_MSG(vm_manager.IsValidHandle(vma), "Invalid memory address"); | ||
| 46 | ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); | ||
| 47 | |||
| 48 | // The returned VMA might be a bigger one encompassing the desired address. | ||
| 49 | const auto vma_offset = address - vma->first; | ||
| 50 | ASSERT_MSG(vma_offset + size <= vma->second.size, | ||
| 51 | "Shared memory exceeds bounds of mapped block"); | ||
| 52 | |||
| 53 | shared_memory->backing_block = vma->second.backing_block; | ||
| 54 | shared_memory->backing_block_offset = vma->second.offset + vma_offset; | ||
| 55 | } | ||
| 56 | |||
| 57 | shared_memory->base_address = address; | ||
| 58 | 17 | ||
| 59 | return shared_memory; | 18 | std::shared_ptr<SharedMemory> SharedMemory::Create( |
| 60 | } | 19 | KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, |
| 20 | Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, | ||
| 21 | Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, | ||
| 22 | std::string name) { | ||
| 61 | 23 | ||
| 62 | std::shared_ptr<SharedMemory> SharedMemory::CreateForApplet( | 24 | std::shared_ptr<SharedMemory> shared_memory{ |
| 63 | KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, | 25 | std::make_shared<SharedMemory>(kernel, device_memory)}; |
| 64 | u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { | ||
| 65 | std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel); | ||
| 66 | 26 | ||
| 67 | shared_memory->owner_process = nullptr; | 27 | shared_memory->owner_process = owner_process; |
| 68 | shared_memory->name = std::move(name); | 28 | shared_memory->page_list = std::move(page_list); |
| 29 | shared_memory->owner_permission = owner_permission; | ||
| 30 | shared_memory->user_permission = user_permission; | ||
| 31 | shared_memory->physical_address = physical_address; | ||
| 69 | shared_memory->size = size; | 32 | shared_memory->size = size; |
| 70 | shared_memory->permissions = permissions; | 33 | shared_memory->name = name; |
| 71 | shared_memory->other_permissions = other_permissions; | ||
| 72 | shared_memory->backing_block = std::move(heap_block); | ||
| 73 | shared_memory->backing_block_offset = offset; | ||
| 74 | shared_memory->base_address = | ||
| 75 | kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset; | ||
| 76 | 34 | ||
| 77 | return shared_memory; | 35 | return shared_memory; |
| 78 | } | 36 | } |
| 79 | 37 | ||
| 80 | ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermission permissions, | 38 | ResultCode SharedMemory::Map(Process& target_process, VAddr address, std::size_t size, |
| 81 | MemoryPermission other_permissions) { | 39 | Memory::MemoryPermission permission) { |
| 82 | const MemoryPermission own_other_permissions = | 40 | const u64 page_count{(size + Memory::PageSize - 1) / Memory::PageSize}; |
| 83 | &target_process == owner_process ? this->permissions : this->other_permissions; | ||
| 84 | |||
| 85 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare | ||
| 86 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { | ||
| 87 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 88 | } | ||
| 89 | |||
| 90 | // Error out if the requested permissions don't match what the creator process allows. | ||
| 91 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { | ||
| 92 | LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", | ||
| 93 | GetObjectId(), address, name); | ||
| 94 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 95 | } | ||
| 96 | 41 | ||
| 97 | // Error out if the provided permissions are not compatible with what the creator process needs. | 42 | if (page_list.GetNumPages() != page_count) { |
| 98 | if (other_permissions != MemoryPermission::DontCare && | 43 | UNIMPLEMENTED(); |
| 99 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { | ||
| 100 | LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match", | ||
| 101 | GetObjectId(), address, name); | ||
| 102 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 103 | } | 44 | } |
| 104 | 45 | ||
| 105 | VAddr target_address = address; | 46 | Memory::MemoryPermission expected = |
| 47 | &target_process == owner_process ? owner_permission : user_permission; | ||
| 106 | 48 | ||
| 107 | // Map the memory block into the target process | 49 | if (permission != expected) { |
| 108 | auto result = target_process.VMManager().MapMemoryBlock( | 50 | UNIMPLEMENTED(); |
| 109 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | ||
| 110 | if (result.Failed()) { | ||
| 111 | LOG_ERROR( | ||
| 112 | Kernel, | ||
| 113 | "cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory", | ||
| 114 | GetObjectId(), target_address, name); | ||
| 115 | return result.Code(); | ||
| 116 | } | 51 | } |
| 117 | 52 | ||
| 118 | return target_process.VMManager().ReprotectRange(target_address, size, | 53 | return target_process.PageTable().MapPages(address, page_list, Memory::MemoryState::Shared, |
| 119 | ConvertPermissions(permissions)); | 54 | permission); |
| 120 | } | ||
| 121 | |||
| 122 | ResultCode SharedMemory::Unmap(Process& target_process, VAddr address, u64 unmap_size) { | ||
| 123 | if (unmap_size != size) { | ||
| 124 | LOG_ERROR(Kernel, | ||
| 125 | "Invalid size passed to Unmap. Size must be equal to the size of the " | ||
| 126 | "memory managed. Shared memory size=0x{:016X}, Unmap size=0x{:016X}", | ||
| 127 | size, unmap_size); | ||
| 128 | return ERR_INVALID_SIZE; | ||
| 129 | } | ||
| 130 | |||
| 131 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not | ||
| 132 | // mapped to a SharedMemory. | ||
| 133 | return target_process.VMManager().UnmapRange(address, size); | ||
| 134 | } | ||
| 135 | |||
| 136 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | ||
| 137 | u32 masked_permissions = | ||
| 138 | static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute); | ||
| 139 | return static_cast<VMAPermission>(masked_permissions); | ||
| 140 | } | ||
| 141 | |||
| 142 | u8* SharedMemory::GetPointer(std::size_t offset) { | ||
| 143 | return backing_block->data() + backing_block_offset + offset; | ||
| 144 | } | ||
| 145 | |||
| 146 | const u8* SharedMemory::GetPointer(std::size_t offset) const { | ||
| 147 | return backing_block->data() + backing_block_offset + offset; | ||
| 148 | } | 55 | } |
| 149 | 56 | ||
| 150 | } // namespace Kernel | 57 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 014951d82..06fe693de 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -8,8 +8,10 @@ | |||
| 8 | #include <string> | 8 | #include <string> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/device_memory.h" | ||
| 12 | #include "core/hle/kernel/memory/memory_block.h" | ||
| 13 | #include "core/hle/kernel/memory/page_linked_list.h" | ||
| 11 | #include "core/hle/kernel/object.h" | 14 | #include "core/hle/kernel/object.h" |
| 12 | #include "core/hle/kernel/physical_memory.h" | ||
| 13 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 15 | 17 | ||
| @@ -17,63 +19,21 @@ namespace Kernel { | |||
| 17 | 19 | ||
| 18 | class KernelCore; | 20 | class KernelCore; |
| 19 | 21 | ||
| 20 | /// Permissions for mapped shared memory blocks | ||
| 21 | enum class MemoryPermission : u32 { | ||
| 22 | None = 0, | ||
| 23 | Read = (1u << 0), | ||
| 24 | Write = (1u << 1), | ||
| 25 | ReadWrite = (Read | Write), | ||
| 26 | Execute = (1u << 2), | ||
| 27 | ReadExecute = (Read | Execute), | ||
| 28 | WriteExecute = (Write | Execute), | ||
| 29 | ReadWriteExecute = (Read | Write | Execute), | ||
| 30 | DontCare = (1u << 28) | ||
| 31 | }; | ||
| 32 | |||
| 33 | class SharedMemory final : public Object { | 22 | class SharedMemory final : public Object { |
| 34 | public: | 23 | public: |
| 35 | explicit SharedMemory(KernelCore& kernel); | 24 | explicit SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory); |
| 36 | ~SharedMemory() override; | 25 | ~SharedMemory() override; |
| 37 | 26 | ||
| 38 | /** | 27 | static std::shared_ptr<SharedMemory> Create( |
| 39 | * Creates a shared memory object. | 28 | KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, |
| 40 | * @param kernel The kernel instance to create a shared memory instance under. | 29 | Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, |
| 41 | * @param owner_process Process that created this shared memory object. | 30 | Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, |
| 42 | * @param size Size of the memory block. Must be page-aligned. | 31 | std::string name = "Unknown"); |
| 43 | * @param permissions Permission restrictions applied to the process which created the block. | ||
| 44 | * @param other_permissions Permission restrictions applied to other processes mapping the | ||
| 45 | * block. | ||
| 46 | * @param address The address from which to map the Shared Memory. | ||
| 47 | * @param region If the address is 0, the shared memory will be allocated in this region of the | ||
| 48 | * linear heap. | ||
| 49 | * @param name Optional object name, used for debugging purposes. | ||
| 50 | */ | ||
| 51 | static std::shared_ptr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, | ||
| 52 | u64 size, MemoryPermission permissions, | ||
| 53 | MemoryPermission other_permissions, | ||
| 54 | VAddr address = 0, | ||
| 55 | MemoryRegion region = MemoryRegion::BASE, | ||
| 56 | std::string name = "Unknown"); | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Creates a shared memory object from a block of memory managed by an HLE applet. | ||
| 60 | * @param kernel The kernel instance to create a shared memory instance under. | ||
| 61 | * @param heap_block Heap block of the HLE applet. | ||
| 62 | * @param offset The offset into the heap block that the SharedMemory will map. | ||
| 63 | * @param size Size of the memory block. Must be page-aligned. | ||
| 64 | * @param permissions Permission restrictions applied to the process which created the block. | ||
| 65 | * @param other_permissions Permission restrictions applied to other processes mapping the | ||
| 66 | * block. | ||
| 67 | * @param name Optional object name, used for debugging purposes. | ||
| 68 | */ | ||
| 69 | static std::shared_ptr<SharedMemory> CreateForApplet( | ||
| 70 | KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, | ||
| 71 | u64 size, MemoryPermission permissions, MemoryPermission other_permissions, | ||
| 72 | std::string name = "Unknown Applet"); | ||
| 73 | 32 | ||
| 74 | std::string GetTypeName() const override { | 33 | std::string GetTypeName() const override { |
| 75 | return "SharedMemory"; | 34 | return "SharedMemory"; |
| 76 | } | 35 | } |
| 36 | |||
| 77 | std::string GetName() const override { | 37 | std::string GetName() const override { |
| 78 | return name; | 38 | return name; |
| 79 | } | 39 | } |
| @@ -83,71 +43,42 @@ public: | |||
| 83 | return HANDLE_TYPE; | 43 | return HANDLE_TYPE; |
| 84 | } | 44 | } |
| 85 | 45 | ||
| 86 | /// Gets the size of the underlying memory block in bytes. | ||
| 87 | u64 GetSize() const { | ||
| 88 | return size; | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Converts the specified MemoryPermission into the equivalent VMAPermission. | ||
| 93 | * @param permission The MemoryPermission to convert. | ||
| 94 | */ | ||
| 95 | static VMAPermission ConvertPermissions(MemoryPermission permission); | ||
| 96 | |||
| 97 | /** | 46 | /** |
| 98 | * Maps a shared memory block to an address in the target process' address space | 47 | * Maps a shared memory block to an address in the target process' address space |
| 99 | * @param target_process Process on which to map the memory block. | 48 | * @param target_process Process on which to map the memory block |
| 100 | * @param address Address in system memory to map shared memory block to | 49 | * @param address Address in system memory to map shared memory block to |
| 50 | * @param size Size of the shared memory block to map | ||
| 101 | * @param permissions Memory block map permissions (specified by SVC field) | 51 | * @param permissions Memory block map permissions (specified by SVC field) |
| 102 | * @param other_permissions Memory block map other permissions (specified by SVC field) | ||
| 103 | */ | ||
| 104 | ResultCode Map(Process& target_process, VAddr address, MemoryPermission permissions, | ||
| 105 | MemoryPermission other_permissions); | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Unmaps a shared memory block from the specified address in system memory | ||
| 109 | * | ||
| 110 | * @param target_process Process from which to unmap the memory block. | ||
| 111 | * @param address Address in system memory where the shared memory block is mapped. | ||
| 112 | * @param unmap_size The amount of bytes to unmap from this shared memory instance. | ||
| 113 | * | ||
| 114 | * @return Result code of the unmap operation | ||
| 115 | * | ||
| 116 | * @pre The given size to unmap must be the same size as the amount of memory managed by | ||
| 117 | * the SharedMemory instance itself, otherwise ERR_INVALID_SIZE will be returned. | ||
| 118 | */ | 52 | */ |
| 119 | ResultCode Unmap(Process& target_process, VAddr address, u64 unmap_size); | 53 | ResultCode Map(Process& target_process, VAddr address, std::size_t size, |
| 54 | Memory::MemoryPermission permission); | ||
| 120 | 55 | ||
| 121 | /** | 56 | /** |
| 122 | * Gets a pointer to the shared memory block | 57 | * Gets a pointer to the shared memory block |
| 123 | * @param offset Offset from the start of the shared memory block to get pointer | 58 | * @param offset Offset from the start of the shared memory block to get pointer |
| 124 | * @return A pointer to the shared memory block from the specified offset | 59 | * @return A pointer to the shared memory block from the specified offset |
| 125 | */ | 60 | */ |
| 126 | u8* GetPointer(std::size_t offset = 0); | 61 | u8* GetPointer(std::size_t offset = 0) { |
| 62 | return device_memory.GetPointer(physical_address + offset); | ||
| 63 | } | ||
| 127 | 64 | ||
| 128 | /** | 65 | /** |
| 129 | * Gets a constant pointer to the shared memory block | 66 | * Gets a pointer to the shared memory block |
| 130 | * @param offset Offset from the start of the shared memory block to get pointer | 67 | * @param offset Offset from the start of the shared memory block to get pointer |
| 131 | * @return A constant pointer to the shared memory block from the specified offset | 68 | * @return A pointer to the shared memory block from the specified offset |
| 132 | */ | 69 | */ |
| 133 | const u8* GetPointer(std::size_t offset = 0) const; | 70 | const u8* GetPointer(std::size_t offset = 0) const { |
| 71 | return device_memory.GetPointer(physical_address + offset); | ||
| 72 | } | ||
| 134 | 73 | ||
| 135 | private: | 74 | private: |
| 136 | /// Backing memory for this shared memory block. | 75 | Core::DeviceMemory& device_memory; |
| 137 | std::shared_ptr<PhysicalMemory> backing_block; | 76 | Process* owner_process{}; |
| 138 | /// Offset into the backing block for this shared memory. | 77 | Memory::PageLinkedList page_list; |
| 139 | std::size_t backing_block_offset = 0; | 78 | Memory::MemoryPermission owner_permission{}; |
| 140 | /// Size of the memory block. Page-aligned. | 79 | Memory::MemoryPermission user_permission{}; |
| 141 | u64 size = 0; | 80 | PAddr physical_address{}; |
| 142 | /// Permission restrictions applied to the process which created the block. | 81 | std::size_t size{}; |
| 143 | MemoryPermission permissions{}; | ||
| 144 | /// Permission restrictions applied to other processes mapping the block. | ||
| 145 | MemoryPermission other_permissions{}; | ||
| 146 | /// Process that created this shared memory block. | ||
| 147 | Process* owner_process; | ||
| 148 | /// Address of shared memory block in the owner process if specified. | ||
| 149 | VAddr base_address = 0; | ||
| 150 | /// Name of shared memory object. | ||
| 151 | std::string name; | 82 | std::string name; |
| 152 | }; | 83 | }; |
| 153 | 84 | ||