shared_memory.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <utility>
  5. #include "common/assert.h"
  6. #include "common/logging/log.h"
  7. #include "core/hle/kernel/errors.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/shared_memory.h"
  10. namespace Kernel {
  11. SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {}
  12. SharedMemory::~SharedMemory() = default;
  13. SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, u64 size,
  14. MemoryPermission permissions,
  15. MemoryPermission other_permissions, VAddr address,
  16. MemoryRegion region, std::string name) {
  17. SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
  18. shared_memory->owner_process = owner_process;
  19. shared_memory->name = std::move(name);
  20. shared_memory->size = size;
  21. shared_memory->permissions = permissions;
  22. shared_memory->other_permissions = other_permissions;
  23. if (address == 0) {
  24. shared_memory->backing_block = std::make_shared<std::vector<u8>>(size);
  25. shared_memory->backing_block_offset = 0;
  26. // Refresh the address mappings for the current process.
  27. if (kernel.CurrentProcess() != nullptr) {
  28. kernel.CurrentProcess()->VMManager().RefreshMemoryBlockMappings(
  29. shared_memory->backing_block.get());
  30. }
  31. } else {
  32. const auto& vm_manager = shared_memory->owner_process->VMManager();
  33. // The memory is already available and mapped in the owner process.
  34. const auto vma = vm_manager.FindVMA(address);
  35. ASSERT_MSG(vm_manager.IsValidHandle(vma), "Invalid memory address");
  36. ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
  37. // The returned VMA might be a bigger one encompassing the desired address.
  38. const auto vma_offset = address - vma->first;
  39. ASSERT_MSG(vma_offset + size <= vma->second.size,
  40. "Shared memory exceeds bounds of mapped block");
  41. shared_memory->backing_block = vma->second.backing_block;
  42. shared_memory->backing_block_offset = vma->second.offset + vma_offset;
  43. }
  44. shared_memory->base_address = address;
  45. return shared_memory;
  46. }
  47. SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
  48. KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, std::size_t offset, u64 size,
  49. MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
  50. SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
  51. shared_memory->owner_process = nullptr;
  52. shared_memory->name = std::move(name);
  53. shared_memory->size = size;
  54. shared_memory->permissions = permissions;
  55. shared_memory->other_permissions = other_permissions;
  56. shared_memory->backing_block = std::move(heap_block);
  57. shared_memory->backing_block_offset = offset;
  58. shared_memory->base_address =
  59. kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset;
  60. return shared_memory;
  61. }
  62. ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermission permissions,
  63. MemoryPermission other_permissions) {
  64. const MemoryPermission own_other_permissions =
  65. &target_process == owner_process ? this->permissions : this->other_permissions;
  66. // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
  67. if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
  68. return ERR_INVALID_MEMORY_PERMISSIONS;
  69. }
  70. // Error out if the requested permissions don't match what the creator process allows.
  71. if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
  72. LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
  73. GetObjectId(), address, name);
  74. return ERR_INVALID_MEMORY_PERMISSIONS;
  75. }
  76. // Error out if the provided permissions are not compatible with what the creator process needs.
  77. if (other_permissions != MemoryPermission::DontCare &&
  78. static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
  79. LOG_ERROR(Kernel, "cannot map id={}, address=0x{:X} name={}, permissions don't match",
  80. GetObjectId(), address, name);
  81. return ERR_INVALID_MEMORY_PERMISSIONS;
  82. }
  83. VAddr target_address = address;
  84. // Map the memory block into the target process
  85. auto result = target_process.VMManager().MapMemoryBlock(
  86. target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
  87. if (result.Failed()) {
  88. LOG_ERROR(
  89. Kernel,
  90. "cannot map id={}, target_address=0x{:X} name={}, error mapping to virtual memory",
  91. GetObjectId(), target_address, name);
  92. return result.Code();
  93. }
  94. return target_process.VMManager().ReprotectRange(target_address, size,
  95. ConvertPermissions(permissions));
  96. }
  97. ResultCode SharedMemory::Unmap(Process& target_process, VAddr address, u64 unmap_size) {
  98. if (unmap_size != size) {
  99. LOG_ERROR(Kernel,
  100. "Invalid size passed to Unmap. Size must be equal to the size of the "
  101. "memory managed. Shared memory size=0x{:016X}, Unmap size=0x{:016X}",
  102. size, unmap_size);
  103. return ERR_INVALID_SIZE;
  104. }
  105. // TODO(Subv): Verify what happens if the application tries to unmap an address that is not
  106. // mapped to a SharedMemory.
  107. return target_process.VMManager().UnmapRange(address, size);
  108. }
  109. VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
  110. u32 masked_permissions =
  111. static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
  112. return static_cast<VMAPermission>(masked_permissions);
  113. }
  114. u8* SharedMemory::GetPointer(std::size_t offset) {
  115. return backing_block->data() + backing_block_offset + offset;
  116. }
  117. const u8* SharedMemory::GetPointer(std::size_t offset) const {
  118. return backing_block->data() + backing_block_offset + offset;
  119. }
  120. } // namespace Kernel