shared_memory.cpp 5.9 KB

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