k_process.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  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 <bitset>
  6. #include <ctime>
  7. #include <memory>
  8. #include <random>
  9. #include "common/alignment.h"
  10. #include "common/assert.h"
  11. #include "common/logging/log.h"
  12. #include "common/scope_exit.h"
  13. #include "common/settings.h"
  14. #include "core/core.h"
  15. #include "core/file_sys/program_metadata.h"
  16. #include "core/hle/kernel/code_set.h"
  17. #include "core/hle/kernel/k_memory_block_manager.h"
  18. #include "core/hle/kernel/k_page_table.h"
  19. #include "core/hle/kernel/k_process.h"
  20. #include "core/hle/kernel/k_resource_limit.h"
  21. #include "core/hle/kernel/k_scheduler.h"
  22. #include "core/hle/kernel/k_scoped_resource_reservation.h"
  23. #include "core/hle/kernel/k_shared_memory.h"
  24. #include "core/hle/kernel/k_shared_memory_info.h"
  25. #include "core/hle/kernel/k_thread.h"
  26. #include "core/hle/kernel/kernel.h"
  27. #include "core/hle/kernel/svc_results.h"
  28. #include "core/memory.h"
  29. namespace Kernel {
  30. namespace {
  31. /**
  32. * Sets up the primary application thread
  33. *
  34. * @param system The system instance to create the main thread under.
  35. * @param owner_process The parent process for the main thread
  36. * @param priority The priority to give the main thread
  37. */
  38. void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) {
  39. const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
  40. ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
  41. KThread* thread = KThread::Create(system.Kernel());
  42. SCOPE_EXIT({ thread->Close(); });
  43. ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
  44. owner_process.GetIdealCoreId(), &owner_process)
  45. .IsSuccess());
  46. // Register 1 must be a handle to the main thread
  47. Handle thread_handle{};
  48. owner_process.GetHandleTable().Add(&thread_handle, thread);
  49. thread->SetName("main");
  50. thread->GetContext32().cpu_registers[0] = 0;
  51. thread->GetContext64().cpu_registers[0] = 0;
  52. thread->GetContext32().cpu_registers[1] = thread_handle;
  53. thread->GetContext64().cpu_registers[1] = thread_handle;
  54. if (system.DebuggerEnabled()) {
  55. thread->RequestSuspend(SuspendType::Debug);
  56. }
  57. // Run our thread.
  58. void(thread->Run());
  59. }
  60. } // Anonymous namespace
  61. Result KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name,
  62. ProcessType type, KResourceLimit* res_limit) {
  63. auto& kernel = system.Kernel();
  64. process->name = std::move(process_name);
  65. process->resource_limit = res_limit;
  66. process->status = ProcessStatus::Created;
  67. process->program_id = 0;
  68. process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
  69. : kernel.CreateNewUserProcessID();
  70. process->capabilities.InitializeForMetadatalessProcess();
  71. process->is_initialized = true;
  72. std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
  73. std::uniform_int_distribution<u64> distribution;
  74. std::generate(process->random_entropy.begin(), process->random_entropy.end(),
  75. [&] { return distribution(rng); });
  76. kernel.AppendNewProcess(process);
  77. // Clear remaining fields.
  78. process->num_running_threads = 0;
  79. process->is_signaled = false;
  80. process->exception_thread = nullptr;
  81. process->is_suspended = false;
  82. process->schedule_count = 0;
  83. // Open a reference to the resource limit.
  84. process->resource_limit->Open();
  85. return ResultSuccess;
  86. }
  87. void KProcess::DoWorkerTaskImpl() {
  88. UNIMPLEMENTED();
  89. }
  90. KResourceLimit* KProcess::GetResourceLimit() const {
  91. return resource_limit;
  92. }
  93. void KProcess::IncrementRunningThreadCount() {
  94. ASSERT(num_running_threads.load() >= 0);
  95. ++num_running_threads;
  96. }
  97. void KProcess::DecrementRunningThreadCount() {
  98. ASSERT(num_running_threads.load() > 0);
  99. if (const auto prev = num_running_threads--; prev == 1) {
  100. // TODO(bunnei): Process termination to be implemented when multiprocess is supported.
  101. UNIMPLEMENTED_MSG("KProcess termination is not implemennted!");
  102. }
  103. }
  104. u64 KProcess::GetTotalPhysicalMemoryAvailable() const {
  105. const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
  106. page_table->GetNormalMemorySize() + GetSystemResourceSize() + image_size +
  107. main_thread_stack_size};
  108. if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
  109. capacity != pool_size) {
  110. LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size);
  111. }
  112. if (capacity < memory_usage_capacity) {
  113. return capacity;
  114. }
  115. return memory_usage_capacity;
  116. }
  117. u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
  118. return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize();
  119. }
  120. u64 KProcess::GetTotalPhysicalMemoryUsed() const {
  121. return image_size + main_thread_stack_size + page_table->GetNormalMemorySize() +
  122. GetSystemResourceSize();
  123. }
  124. u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
  125. return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
  126. }
  127. bool KProcess::ReleaseUserException(KThread* thread) {
  128. KScopedSchedulerLock sl{kernel};
  129. if (exception_thread == thread) {
  130. exception_thread = nullptr;
  131. // Remove waiter thread.
  132. s32 num_waiters{};
  133. if (KThread* next = thread->RemoveWaiterByKey(
  134. std::addressof(num_waiters),
  135. reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
  136. next != nullptr) {
  137. next->EndWait(ResultSuccess);
  138. }
  139. KScheduler::SetSchedulerUpdateNeeded(kernel);
  140. return true;
  141. } else {
  142. return false;
  143. }
  144. }
  145. void KProcess::PinCurrentThread(s32 core_id) {
  146. ASSERT(kernel.GlobalSchedulerContext().IsLocked());
  147. // Get the current thread.
  148. KThread* cur_thread =
  149. kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
  150. // If the thread isn't terminated, pin it.
  151. if (!cur_thread->IsTerminationRequested()) {
  152. // Pin it.
  153. PinThread(core_id, cur_thread);
  154. cur_thread->Pin(core_id);
  155. // An update is needed.
  156. KScheduler::SetSchedulerUpdateNeeded(kernel);
  157. }
  158. }
  159. void KProcess::UnpinCurrentThread(s32 core_id) {
  160. ASSERT(kernel.GlobalSchedulerContext().IsLocked());
  161. // Get the current thread.
  162. KThread* cur_thread =
  163. kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
  164. // Unpin it.
  165. cur_thread->Unpin();
  166. UnpinThread(core_id, cur_thread);
  167. // An update is needed.
  168. KScheduler::SetSchedulerUpdateNeeded(kernel);
  169. }
  170. void KProcess::UnpinThread(KThread* thread) {
  171. ASSERT(kernel.GlobalSchedulerContext().IsLocked());
  172. // Get the thread's core id.
  173. const auto core_id = thread->GetActiveCore();
  174. // Unpin it.
  175. UnpinThread(core_id, thread);
  176. thread->Unpin();
  177. // An update is needed.
  178. KScheduler::SetSchedulerUpdateNeeded(kernel);
  179. }
  180. Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
  181. [[maybe_unused]] size_t size) {
  182. // Lock ourselves, to prevent concurrent access.
  183. KScopedLightLock lk(state_lock);
  184. // Try to find an existing info for the memory.
  185. KSharedMemoryInfo* shemen_info = nullptr;
  186. const auto iter = std::find_if(
  187. shared_memory_list.begin(), shared_memory_list.end(),
  188. [shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
  189. if (iter != shared_memory_list.end()) {
  190. shemen_info = *iter;
  191. }
  192. if (shemen_info == nullptr) {
  193. shemen_info = KSharedMemoryInfo::Allocate(kernel);
  194. R_UNLESS(shemen_info != nullptr, ResultOutOfMemory);
  195. shemen_info->Initialize(shmem);
  196. shared_memory_list.push_back(shemen_info);
  197. }
  198. // Open a reference to the shared memory and its info.
  199. shmem->Open();
  200. shemen_info->Open();
  201. return ResultSuccess;
  202. }
  203. void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
  204. [[maybe_unused]] size_t size) {
  205. // Lock ourselves, to prevent concurrent access.
  206. KScopedLightLock lk(state_lock);
  207. KSharedMemoryInfo* shemen_info = nullptr;
  208. const auto iter = std::find_if(
  209. shared_memory_list.begin(), shared_memory_list.end(),
  210. [shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
  211. if (iter != shared_memory_list.end()) {
  212. shemen_info = *iter;
  213. }
  214. ASSERT(shemen_info != nullptr);
  215. if (shemen_info->Close()) {
  216. shared_memory_list.erase(iter);
  217. KSharedMemoryInfo::Free(kernel, shemen_info);
  218. }
  219. // Close a reference to the shared memory.
  220. shmem->Close();
  221. }
  222. void KProcess::RegisterThread(KThread* thread) {
  223. KScopedLightLock lk{list_lock};
  224. thread_list.push_back(thread);
  225. }
  226. void KProcess::UnregisterThread(KThread* thread) {
  227. KScopedLightLock lk{list_lock};
  228. thread_list.remove(thread);
  229. }
  230. Result KProcess::Reset() {
  231. // Lock the process and the scheduler.
  232. KScopedLightLock lk(state_lock);
  233. KScopedSchedulerLock sl{kernel};
  234. // Validate that we're in a state that we can reset.
  235. R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
  236. R_UNLESS(is_signaled, ResultInvalidState);
  237. // Clear signaled.
  238. is_signaled = false;
  239. return ResultSuccess;
  240. }
  241. Result KProcess::SetActivity(ProcessActivity activity) {
  242. // Lock ourselves and the scheduler.
  243. KScopedLightLock lk{state_lock};
  244. KScopedLightLock list_lk{list_lock};
  245. KScopedSchedulerLock sl{kernel};
  246. // Validate our state.
  247. R_UNLESS(status != ProcessStatus::Exiting, ResultInvalidState);
  248. R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
  249. // Either pause or resume.
  250. if (activity == ProcessActivity::Paused) {
  251. // Verify that we're not suspended.
  252. if (is_suspended) {
  253. return ResultInvalidState;
  254. }
  255. // Suspend all threads.
  256. for (auto* thread : GetThreadList()) {
  257. thread->RequestSuspend(SuspendType::Process);
  258. }
  259. // Set ourselves as suspended.
  260. SetSuspended(true);
  261. } else {
  262. ASSERT(activity == ProcessActivity::Runnable);
  263. // Verify that we're suspended.
  264. if (!is_suspended) {
  265. return ResultInvalidState;
  266. }
  267. // Resume all threads.
  268. for (auto* thread : GetThreadList()) {
  269. thread->Resume(SuspendType::Process);
  270. }
  271. // Set ourselves as resumed.
  272. SetSuspended(false);
  273. }
  274. return ResultSuccess;
  275. }
  276. Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size) {
  277. program_id = metadata.GetTitleID();
  278. ideal_core = metadata.GetMainThreadCore();
  279. is_64bit_process = metadata.Is64BitProgram();
  280. system_resource_size = metadata.GetSystemResourceSize();
  281. image_size = code_size;
  282. KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
  283. code_size + system_resource_size);
  284. if (!memory_reservation.Succeeded()) {
  285. LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
  286. code_size + system_resource_size);
  287. return ResultLimitReached;
  288. }
  289. // Initialize proces address space
  290. if (const Result result{page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false,
  291. 0x8000000, code_size,
  292. KMemoryManager::Pool::Application)};
  293. result.IsError()) {
  294. return result;
  295. }
  296. // Map process code region
  297. if (const Result result{page_table->MapProcessCode(page_table->GetCodeRegionStart(),
  298. code_size / PageSize, KMemoryState::Code,
  299. KMemoryPermission::None)};
  300. result.IsError()) {
  301. return result;
  302. }
  303. // Initialize process capabilities
  304. const auto& caps{metadata.GetKernelCapabilities()};
  305. if (const Result result{
  306. capabilities.InitializeForUserProcess(caps.data(), caps.size(), *page_table)};
  307. result.IsError()) {
  308. return result;
  309. }
  310. // Set memory usage capacity
  311. switch (metadata.GetAddressSpaceType()) {
  312. case FileSys::ProgramAddressSpaceType::Is32Bit:
  313. case FileSys::ProgramAddressSpaceType::Is36Bit:
  314. case FileSys::ProgramAddressSpaceType::Is39Bit:
  315. memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart();
  316. break;
  317. case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
  318. memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart() +
  319. page_table->GetAliasRegionEnd() - page_table->GetAliasRegionStart();
  320. break;
  321. default:
  322. ASSERT(false);
  323. }
  324. // Create TLS region
  325. R_TRY(this->CreateThreadLocalRegion(std::addressof(tls_region_address)));
  326. memory_reservation.Commit();
  327. return handle_table.Initialize(capabilities.GetHandleTableSize());
  328. }
  329. void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
  330. AllocateMainThreadStack(stack_size);
  331. resource_limit->Reserve(LimitableResource::Threads, 1);
  332. resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
  333. const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
  334. ASSERT(!page_table->SetMaxHeapSize(heap_capacity).IsError());
  335. ChangeStatus(ProcessStatus::Running);
  336. SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top);
  337. }
  338. void KProcess::PrepareForTermination() {
  339. ChangeStatus(ProcessStatus::Exiting);
  340. const auto stop_threads = [this](const std::vector<KThread*>& in_thread_list) {
  341. for (auto* thread : in_thread_list) {
  342. if (thread->GetOwnerProcess() != this)
  343. continue;
  344. if (thread == GetCurrentThreadPointer(kernel))
  345. continue;
  346. // TODO(Subv): When are the other running/ready threads terminated?
  347. ASSERT_MSG(thread->GetState() == ThreadState::Waiting,
  348. "Exiting processes with non-waiting threads is currently unimplemented");
  349. thread->Exit();
  350. }
  351. };
  352. stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList());
  353. this->DeleteThreadLocalRegion(tls_region_address);
  354. tls_region_address = 0;
  355. if (resource_limit) {
  356. resource_limit->Release(LimitableResource::PhysicalMemory,
  357. main_thread_stack_size + image_size);
  358. }
  359. ChangeStatus(ProcessStatus::Exited);
  360. }
  361. void KProcess::Finalize() {
  362. // Free all shared memory infos.
  363. {
  364. auto it = shared_memory_list.begin();
  365. while (it != shared_memory_list.end()) {
  366. KSharedMemoryInfo* info = *it;
  367. KSharedMemory* shmem = info->GetSharedMemory();
  368. while (!info->Close()) {
  369. shmem->Close();
  370. }
  371. shmem->Close();
  372. it = shared_memory_list.erase(it);
  373. KSharedMemoryInfo::Free(kernel, info);
  374. }
  375. }
  376. // Release memory to the resource limit.
  377. if (resource_limit != nullptr) {
  378. resource_limit->Close();
  379. resource_limit = nullptr;
  380. }
  381. // Finalize the page table.
  382. page_table.reset();
  383. // Perform inherited finalization.
  384. KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
  385. }
  386. Result KProcess::CreateThreadLocalRegion(VAddr* out) {
  387. KThreadLocalPage* tlp = nullptr;
  388. VAddr tlr = 0;
  389. // See if we can get a region from a partially used TLP.
  390. {
  391. KScopedSchedulerLock sl{kernel};
  392. if (auto it = partially_used_tlp_tree.begin(); it != partially_used_tlp_tree.end()) {
  393. tlr = it->Reserve();
  394. ASSERT(tlr != 0);
  395. if (it->IsAllUsed()) {
  396. tlp = std::addressof(*it);
  397. partially_used_tlp_tree.erase(it);
  398. fully_used_tlp_tree.insert(*tlp);
  399. }
  400. *out = tlr;
  401. return ResultSuccess;
  402. }
  403. }
  404. // Allocate a new page.
  405. tlp = KThreadLocalPage::Allocate(kernel);
  406. R_UNLESS(tlp != nullptr, ResultOutOfMemory);
  407. auto tlp_guard = SCOPE_GUARD({ KThreadLocalPage::Free(kernel, tlp); });
  408. // Initialize the new page.
  409. R_TRY(tlp->Initialize(kernel, this));
  410. // Reserve a TLR.
  411. tlr = tlp->Reserve();
  412. ASSERT(tlr != 0);
  413. // Insert into our tree.
  414. {
  415. KScopedSchedulerLock sl{kernel};
  416. if (tlp->IsAllUsed()) {
  417. fully_used_tlp_tree.insert(*tlp);
  418. } else {
  419. partially_used_tlp_tree.insert(*tlp);
  420. }
  421. }
  422. // We succeeded!
  423. tlp_guard.Cancel();
  424. *out = tlr;
  425. return ResultSuccess;
  426. }
  427. Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
  428. KThreadLocalPage* page_to_free = nullptr;
  429. // Release the region.
  430. {
  431. KScopedSchedulerLock sl{kernel};
  432. // Try to find the page in the partially used list.
  433. auto it = partially_used_tlp_tree.find_key(Common::AlignDown(addr, PageSize));
  434. if (it == partially_used_tlp_tree.end()) {
  435. // If we don't find it, it has to be in the fully used list.
  436. it = fully_used_tlp_tree.find_key(Common::AlignDown(addr, PageSize));
  437. R_UNLESS(it != fully_used_tlp_tree.end(), ResultInvalidAddress);
  438. // Release the region.
  439. it->Release(addr);
  440. // Move the page out of the fully used list.
  441. KThreadLocalPage* tlp = std::addressof(*it);
  442. fully_used_tlp_tree.erase(it);
  443. if (tlp->IsAllFree()) {
  444. page_to_free = tlp;
  445. } else {
  446. partially_used_tlp_tree.insert(*tlp);
  447. }
  448. } else {
  449. // Release the region.
  450. it->Release(addr);
  451. // Handle the all-free case.
  452. KThreadLocalPage* tlp = std::addressof(*it);
  453. if (tlp->IsAllFree()) {
  454. partially_used_tlp_tree.erase(it);
  455. page_to_free = tlp;
  456. }
  457. }
  458. }
  459. // If we should free the page it was in, do so.
  460. if (page_to_free != nullptr) {
  461. page_to_free->Finalize();
  462. KThreadLocalPage::Free(kernel, page_to_free);
  463. }
  464. return ResultSuccess;
  465. }
  466. bool KProcess::InsertWatchpoint(Core::System& system, VAddr addr, u64 size,
  467. DebugWatchpointType type) {
  468. const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) {
  469. return wp.type == DebugWatchpointType::None;
  470. })};
  471. if (watch == watchpoints.end()) {
  472. return false;
  473. }
  474. watch->start_address = addr;
  475. watch->end_address = addr + size;
  476. watch->type = type;
  477. for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) {
  478. debug_page_refcounts[page]++;
  479. system.Memory().MarkRegionDebug(page, PageSize, true);
  480. }
  481. return true;
  482. }
  483. bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size,
  484. DebugWatchpointType type) {
  485. const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) {
  486. return wp.start_address == addr && wp.end_address == addr + size && wp.type == type;
  487. })};
  488. if (watch == watchpoints.end()) {
  489. return false;
  490. }
  491. watch->start_address = 0;
  492. watch->end_address = 0;
  493. watch->type = DebugWatchpointType::None;
  494. for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) {
  495. debug_page_refcounts[page]--;
  496. if (!debug_page_refcounts[page]) {
  497. system.Memory().MarkRegionDebug(page, PageSize, false);
  498. }
  499. }
  500. return true;
  501. }
  502. void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
  503. const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
  504. Svc::MemoryPermission permission) {
  505. page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
  506. };
  507. kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
  508. code_set.memory.size());
  509. ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute);
  510. ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read);
  511. ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
  512. }
  513. bool KProcess::IsSignaled() const {
  514. ASSERT(kernel.GlobalSchedulerContext().IsLocked());
  515. return is_signaled;
  516. }
  517. KProcess::KProcess(KernelCore& kernel_)
  518. : KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{std::make_unique<KPageTable>(
  519. kernel_.System())},
  520. handle_table{kernel_}, address_arbiter{kernel_.System()}, condition_var{kernel_.System()},
  521. state_lock{kernel_}, list_lock{kernel_} {}
  522. KProcess::~KProcess() = default;
  523. void KProcess::ChangeStatus(ProcessStatus new_status) {
  524. if (status == new_status) {
  525. return;
  526. }
  527. status = new_status;
  528. is_signaled = true;
  529. NotifyAvailable();
  530. }
  531. Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
  532. ASSERT(stack_size);
  533. // The kernel always ensures that the given stack size is page aligned.
  534. main_thread_stack_size = Common::AlignUp(stack_size, PageSize);
  535. const VAddr start{page_table->GetStackRegionStart()};
  536. const std::size_t size{page_table->GetStackRegionEnd() - start};
  537. CASCADE_RESULT(main_thread_stack_top,
  538. page_table->AllocateAndMapMemory(
  539. main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize,
  540. KMemoryState::Stack, KMemoryPermission::UserReadWrite));
  541. main_thread_stack_top += main_thread_stack_size;
  542. return ResultSuccess;
  543. }
  544. } // namespace Kernel