shared_memory.cpp 5.8 KB

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