shared_memory.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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/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, SharedPtr<Process> owner_process,
  15. u64 size, 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 = std::move(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 (Core::CurrentProcess() != nullptr) {
  29. Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(
  30. shared_memory->backing_block.get());
  31. }
  32. } else {
  33. auto& vm_manager = shared_memory->owner_process->vm_manager;
  34. // The memory is already available and mapped in the owner process.
  35. auto vma = vm_manager.FindVMA(address);
  36. ASSERT_MSG(vma != vm_manager.vma_map.end(), "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. 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, u32 offset, u32 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 = Memory::HEAP_VADDR + offset;
  60. return shared_memory;
  61. }
  62. ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
  63. MemoryPermission other_permissions) {
  64. 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_COMBINATION;
  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_COMBINATION;
  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->vm_manager.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->vm_manager.ReprotectRange(target_address, size,
  95. ConvertPermissions(permissions));
  96. }
  97. ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
  98. // TODO(Subv): Verify what happens if the application tries to unmap an address that is not
  99. // mapped to a SharedMemory.
  100. return target_process->vm_manager.UnmapRange(address, size);
  101. }
  102. VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
  103. u32 masked_permissions =
  104. static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
  105. return static_cast<VMAPermission>(masked_permissions);
  106. }
  107. u8* SharedMemory::GetPointer(u32 offset) {
  108. return backing_block->data() + backing_block_offset + offset;
  109. }
  110. } // namespace Kernel