process.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <memory>
  6. #include "common/assert.h"
  7. #include "common/common_funcs.h"
  8. #include "common/logging/log.h"
  9. #include "core/hle/kernel/errors.h"
  10. #include "core/hle/kernel/process.h"
  11. #include "core/hle/kernel/resource_limit.h"
  12. #include "core/hle/kernel/thread.h"
  13. #include "core/hle/kernel/vm_manager.h"
  14. #include "core/memory.h"
  15. namespace Kernel {
  16. // Lists all processes that exist in the current session.
  17. static std::vector<SharedPtr<Process>> process_list;
  18. SharedPtr<CodeSet> CodeSet::Create(std::string name) {
  19. SharedPtr<CodeSet> codeset(new CodeSet);
  20. codeset->name = std::move(name);
  21. return codeset;
  22. }
  23. CodeSet::CodeSet() {}
  24. CodeSet::~CodeSet() {}
  25. u32 Process::next_process_id;
  26. SharedPtr<Process> Process::Create(std::string&& name) {
  27. SharedPtr<Process> process(new Process);
  28. process->name = std::move(name);
  29. process->flags.raw = 0;
  30. process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
  31. process->status = ProcessStatus::Created;
  32. process->program_id = 0;
  33. process_list.push_back(process);
  34. return process;
  35. }
  36. void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
  37. for (size_t i = 0; i < len; ++i) {
  38. u32 descriptor = kernel_caps[i];
  39. u32 type = descriptor >> 20;
  40. if (descriptor == 0xFFFFFFFF) {
  41. // Unused descriptor entry
  42. continue;
  43. } else if ((type & 0xF00) == 0xE00) { // 0x0FFF
  44. // Allowed interrupts list
  45. LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
  46. } else if ((type & 0xF80) == 0xF00) { // 0x07FF
  47. // Allowed syscalls mask
  48. unsigned int index = ((descriptor >> 24) & 7) * 24;
  49. u32 bits = descriptor & 0xFFFFFF;
  50. while (bits && index < svc_access_mask.size()) {
  51. svc_access_mask.set(index, bits & 1);
  52. ++index;
  53. bits >>= 1;
  54. }
  55. } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
  56. // Handle table size
  57. handle_table_size = descriptor & 0x3FF;
  58. } else if ((type & 0xFF8) == 0xFF0) { // 0x007F
  59. // Misc. flags
  60. flags.raw = descriptor & 0xFFFF;
  61. } else if ((type & 0xFFE) == 0xFF8) { // 0x001F
  62. // Mapped memory range
  63. if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
  64. LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
  65. continue;
  66. }
  67. u32 end_desc = kernel_caps[i + 1];
  68. ++i; // Skip over the second descriptor on the next iteration
  69. AddressMapping mapping;
  70. mapping.address = descriptor << 12;
  71. VAddr end_address = end_desc << 12;
  72. if (mapping.address < end_address) {
  73. mapping.size = end_address - mapping.address;
  74. } else {
  75. mapping.size = 0;
  76. }
  77. mapping.read_only = (descriptor & (1 << 20)) != 0;
  78. mapping.unk_flag = (end_desc & (1 << 20)) != 0;
  79. address_mappings.push_back(mapping);
  80. } else if ((type & 0xFFF) == 0xFFE) { // 0x000F
  81. // Mapped memory page
  82. AddressMapping mapping;
  83. mapping.address = descriptor << 12;
  84. mapping.size = Memory::PAGE_SIZE;
  85. mapping.read_only = false;
  86. mapping.unk_flag = false;
  87. address_mappings.push_back(mapping);
  88. } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
  89. // Kernel version
  90. kernel_version = descriptor & 0xFFFF;
  91. int minor = kernel_version & 0xFF;
  92. int major = (kernel_version >> 8) & 0xFF;
  93. LOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
  94. } else {
  95. LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x{:08X}", descriptor);
  96. }
  97. }
  98. }
  99. void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
  100. // Allocate and map the main thread stack
  101. // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
  102. // of the user address space.
  103. vm_manager
  104. .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size,
  105. std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
  106. MemoryState::Mapped)
  107. .Unwrap();
  108. vm_manager.LogLayout();
  109. status = ProcessStatus::Running;
  110. Kernel::SetupMainThread(entry_point, main_thread_priority, this);
  111. }
  112. void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
  113. const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
  114. MemoryState memory_state) {
  115. auto vma = vm_manager
  116. .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset,
  117. segment.size, memory_state)
  118. .Unwrap();
  119. vm_manager.Reprotect(vma, permissions);
  120. };
  121. // Map CodeSet segments
  122. MapSegment(module_->CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic);
  123. MapSegment(module_->RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable);
  124. MapSegment(module_->DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable);
  125. }
  126. ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
  127. if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
  128. target + size < target) {
  129. return ERR_INVALID_ADDRESS;
  130. }
  131. if (heap_memory == nullptr) {
  132. // Initialize heap
  133. heap_memory = std::make_shared<std::vector<u8>>();
  134. heap_start = heap_end = target;
  135. } else {
  136. vm_manager.UnmapRange(heap_start, heap_end - heap_start);
  137. }
  138. // If necessary, expand backing vector to cover new heap extents.
  139. if (target < heap_start) {
  140. heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
  141. heap_start = target;
  142. vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
  143. }
  144. if (target + size > heap_end) {
  145. heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
  146. heap_end = target + size;
  147. vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
  148. }
  149. ASSERT(heap_end - heap_start == heap_memory->size());
  150. CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
  151. size, MemoryState::Heap));
  152. vm_manager.Reprotect(vma, perms);
  153. heap_used = size;
  154. return MakeResult<VAddr>(heap_end - size);
  155. }
  156. ResultCode Process::HeapFree(VAddr target, u32 size) {
  157. if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
  158. target + size < target) {
  159. return ERR_INVALID_ADDRESS;
  160. }
  161. if (size == 0) {
  162. return RESULT_SUCCESS;
  163. }
  164. ResultCode result = vm_manager.UnmapRange(target, size);
  165. if (result.IsError())
  166. return result;
  167. heap_used -= size;
  168. return RESULT_SUCCESS;
  169. }
  170. ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
  171. auto vma = vm_manager.FindVMA(src_addr);
  172. ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
  173. ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
  174. // The returned VMA might be a bigger one encompassing the desired address.
  175. auto vma_offset = src_addr - vma->first;
  176. ASSERT_MSG(vma_offset + size <= vma->second.size,
  177. "Shared memory exceeds bounds of mapped block");
  178. const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
  179. size_t backing_block_offset = vma->second.offset + vma_offset;
  180. CASCADE_RESULT(auto new_vma,
  181. vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
  182. MemoryState::Mapped));
  183. // Protect mirror with permissions from old region
  184. vm_manager.Reprotect(new_vma, vma->second.permissions);
  185. // Remove permissions from old region
  186. vm_manager.Reprotect(vma, VMAPermission::None);
  187. return RESULT_SUCCESS;
  188. }
  189. ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
  190. return vm_manager.UnmapRange(dst_addr, size);
  191. }
  192. Kernel::Process::Process() {}
  193. Kernel::Process::~Process() {}
  194. void ClearProcessList() {
  195. process_list.clear();
  196. }
  197. SharedPtr<Process> GetProcessById(u32 process_id) {
  198. auto itr = std::find_if(
  199. process_list.begin(), process_list.end(),
  200. [&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
  201. if (itr == process_list.end())
  202. return nullptr;
  203. return *itr;
  204. }
  205. } // namespace Kernel