process.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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/memory.h"
  11. #include "core/hle/kernel/process.h"
  12. #include "core/hle/kernel/resource_limit.h"
  13. #include "core/hle/kernel/thread.h"
  14. #include "core/hle/kernel/vm_manager.h"
  15. #include "core/memory.h"
  16. namespace Kernel {
  17. // Lists all processes that exist in the current session.
  18. static std::vector<SharedPtr<Process>> process_list;
  19. SharedPtr<CodeSet> CodeSet::Create(std::string name) {
  20. SharedPtr<CodeSet> codeset(new CodeSet);
  21. codeset->name = std::move(name);
  22. return codeset;
  23. }
  24. CodeSet::CodeSet() {}
  25. CodeSet::~CodeSet() {}
  26. u32 Process::next_process_id;
  27. SharedPtr<Process> Process::Create(std::string&& name) {
  28. SharedPtr<Process> process(new Process);
  29. process->name = std::move(name);
  30. process->flags.raw = 0;
  31. process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
  32. process->status = ProcessStatus::Created;
  33. process->program_id = 0;
  34. process_list.push_back(process);
  35. return process;
  36. }
  37. void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
  38. for (size_t i = 0; i < len; ++i) {
  39. u32 descriptor = kernel_caps[i];
  40. u32 type = descriptor >> 20;
  41. if (descriptor == 0xFFFFFFFF) {
  42. // Unused descriptor entry
  43. continue;
  44. } else if ((type & 0xF00) == 0xE00) { // 0x0FFF
  45. // Allowed interrupts list
  46. NGLOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
  47. } else if ((type & 0xF80) == 0xF00) { // 0x07FF
  48. // Allowed syscalls mask
  49. unsigned int index = ((descriptor >> 24) & 7) * 24;
  50. u32 bits = descriptor & 0xFFFFFF;
  51. while (bits && index < svc_access_mask.size()) {
  52. svc_access_mask.set(index, bits & 1);
  53. ++index;
  54. bits >>= 1;
  55. }
  56. } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
  57. // Handle table size
  58. handle_table_size = descriptor & 0x3FF;
  59. } else if ((type & 0xFF8) == 0xFF0) { // 0x007F
  60. // Misc. flags
  61. flags.raw = descriptor & 0xFFFF;
  62. } else if ((type & 0xFFE) == 0xFF8) { // 0x001F
  63. // Mapped memory range
  64. if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
  65. NGLOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
  66. continue;
  67. }
  68. u32 end_desc = kernel_caps[i + 1];
  69. ++i; // Skip over the second descriptor on the next iteration
  70. AddressMapping mapping;
  71. mapping.address = descriptor << 12;
  72. VAddr end_address = end_desc << 12;
  73. if (mapping.address < end_address) {
  74. mapping.size = end_address - mapping.address;
  75. } else {
  76. mapping.size = 0;
  77. }
  78. mapping.read_only = (descriptor & (1 << 20)) != 0;
  79. mapping.unk_flag = (end_desc & (1 << 20)) != 0;
  80. address_mappings.push_back(mapping);
  81. } else if ((type & 0xFFF) == 0xFFE) { // 0x000F
  82. // Mapped memory page
  83. AddressMapping mapping;
  84. mapping.address = descriptor << 12;
  85. mapping.size = Memory::PAGE_SIZE;
  86. mapping.read_only = false;
  87. mapping.unk_flag = false;
  88. address_mappings.push_back(mapping);
  89. } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
  90. // Kernel version
  91. kernel_version = descriptor & 0xFFFF;
  92. int minor = kernel_version & 0xFF;
  93. int major = (kernel_version >> 8) & 0xFF;
  94. NGLOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
  95. } else {
  96. NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: {:#010X}", descriptor);
  97. }
  98. }
  99. }
  100. void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
  101. // Allocate and map the main thread stack
  102. // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
  103. // of the user address space.
  104. vm_manager
  105. .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size,
  106. std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
  107. MemoryState::Mapped)
  108. .Unwrap();
  109. misc_memory_used += stack_size;
  110. memory_region->used += stack_size;
  111. // Map special address mappings
  112. MapSharedPages(vm_manager);
  113. for (const auto& mapping : address_mappings) {
  114. HandleSpecialMapping(vm_manager, mapping);
  115. }
  116. vm_manager.LogLayout(Log::Level::Debug);
  117. status = ProcessStatus::Running;
  118. Kernel::SetupMainThread(entry_point, main_thread_priority, this);
  119. }
  120. void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
  121. memory_region = GetMemoryRegion(flags.memory_region);
  122. auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
  123. MemoryState memory_state) {
  124. auto vma = vm_manager
  125. .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset,
  126. segment.size, memory_state)
  127. .Unwrap();
  128. vm_manager.Reprotect(vma, permissions);
  129. misc_memory_used += segment.size;
  130. memory_region->used += segment.size;
  131. };
  132. // Map CodeSet segments
  133. MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic);
  134. MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable);
  135. MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable);
  136. }
  137. VAddr Process::GetLinearHeapAreaAddress() const {
  138. // Starting from system version 8.0.0 a new linear heap layout is supported to allow usage of
  139. // the extra RAM in the n3DS.
  140. return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR;
  141. }
  142. VAddr Process::GetLinearHeapBase() const {
  143. return GetLinearHeapAreaAddress() + memory_region->base;
  144. }
  145. VAddr Process::GetLinearHeapLimit() const {
  146. return GetLinearHeapBase() + memory_region->size;
  147. }
  148. ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
  149. if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
  150. target + size < target) {
  151. return ERR_INVALID_ADDRESS;
  152. }
  153. if (heap_memory == nullptr) {
  154. // Initialize heap
  155. heap_memory = std::make_shared<std::vector<u8>>();
  156. heap_start = heap_end = target;
  157. } else {
  158. vm_manager.UnmapRange(heap_start, heap_end - heap_start);
  159. }
  160. // If necessary, expand backing vector to cover new heap extents.
  161. if (target < heap_start) {
  162. heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
  163. heap_start = target;
  164. vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
  165. }
  166. if (target + size > heap_end) {
  167. heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
  168. heap_end = target + size;
  169. vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
  170. }
  171. ASSERT(heap_end - heap_start == heap_memory->size());
  172. CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
  173. size, MemoryState::Heap));
  174. vm_manager.Reprotect(vma, perms);
  175. heap_used = size;
  176. memory_region->used += size;
  177. return MakeResult<VAddr>(heap_end - size);
  178. }
  179. ResultCode Process::HeapFree(VAddr target, u32 size) {
  180. if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
  181. target + size < target) {
  182. return ERR_INVALID_ADDRESS;
  183. }
  184. if (size == 0) {
  185. return RESULT_SUCCESS;
  186. }
  187. ResultCode result = vm_manager.UnmapRange(target, size);
  188. if (result.IsError())
  189. return result;
  190. heap_used -= size;
  191. memory_region->used -= size;
  192. return RESULT_SUCCESS;
  193. }
  194. ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) {
  195. UNIMPLEMENTED();
  196. return {};
  197. }
  198. ResultCode Process::LinearFree(VAddr target, u32 size) {
  199. auto& linheap_memory = memory_region->linear_heap_memory;
  200. if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
  201. target + size < target) {
  202. return ERR_INVALID_ADDRESS;
  203. }
  204. if (size == 0) {
  205. return RESULT_SUCCESS;
  206. }
  207. VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
  208. if (target + size > heap_end) {
  209. return ERR_INVALID_ADDRESS_STATE;
  210. }
  211. ResultCode result = vm_manager.UnmapRange(target, size);
  212. if (result.IsError())
  213. return result;
  214. linear_heap_used -= size;
  215. memory_region->used -= size;
  216. if (target + size == heap_end) {
  217. // End of linear heap has been freed, so check what's the last allocated block in it and
  218. // reduce the size.
  219. auto vma = vm_manager.FindVMA(target);
  220. ASSERT(vma != vm_manager.vma_map.end());
  221. ASSERT(vma->second.type == VMAType::Free);
  222. VAddr new_end = vma->second.base;
  223. if (new_end >= GetLinearHeapBase()) {
  224. linheap_memory->resize(new_end - GetLinearHeapBase());
  225. }
  226. }
  227. return RESULT_SUCCESS;
  228. }
  229. ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
  230. auto vma = vm_manager.FindVMA(src_addr);
  231. ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
  232. ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
  233. // The returned VMA might be a bigger one encompassing the desired address.
  234. auto vma_offset = src_addr - vma->first;
  235. ASSERT_MSG(vma_offset + size <= vma->second.size,
  236. "Shared memory exceeds bounds of mapped block");
  237. const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
  238. size_t backing_block_offset = vma->second.offset + vma_offset;
  239. CASCADE_RESULT(auto new_vma,
  240. vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
  241. MemoryState::Mapped));
  242. // Protect mirror with permissions from old region
  243. vm_manager.Reprotect(new_vma, vma->second.permissions);
  244. // Remove permissions from old region
  245. vm_manager.Reprotect(vma, VMAPermission::None);
  246. return RESULT_SUCCESS;
  247. }
  248. ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
  249. return vm_manager.UnmapRange(dst_addr, size);
  250. }
  251. Kernel::Process::Process() {}
  252. Kernel::Process::~Process() {}
  253. void ClearProcessList() {
  254. process_list.clear();
  255. }
  256. SharedPtr<Process> GetProcessById(u32 process_id) {
  257. auto itr = std::find_if(
  258. process_list.begin(), process_list.end(),
  259. [&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
  260. if (itr == process_list.end())
  261. return nullptr;
  262. return *itr;
  263. }
  264. } // namespace Kernel