summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/am/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/am/process.cpp')
-rw-r--r--src/core/hle/service/am/process.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp
new file mode 100644
index 000000000..16b685f86
--- /dev/null
+++ b/src/core/hle/service/am/process.cpp
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/service/am/process.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/loader/loader.h"
+
+namespace Service::AM {
+
+Process::Process(Core::System& system)
+ : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
+ m_program_id(), m_process_started() {}
+
+Process::~Process() {
+ this->Finalize();
+}
+
+bool Process::Initialize(u64 program_id) {
+ // First, ensure we are not holding another process.
+ this->Finalize();
+
+ // Get the filesystem controller.
+ auto& fsc = m_system.GetFileSystemController();
+
+ // Attempt to load program NCA.
+ const FileSys::RegisteredCache* bis_system{};
+ FileSys::VirtualFile nca{};
+
+ // Get the program NCA from built-in storage.
+ bis_system = fsc.GetSystemNANDContents();
+ if (bis_system) {
+ nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
+ }
+
+ // Ensure we retrieved a program NCA.
+ if (!nca) {
+ return false;
+ }
+
+ // Get the appropriate loader to parse this NCA.
+ auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
+
+ // Ensure we have a loader which can parse the NCA.
+ if (!app_loader) {
+ return false;
+ }
+
+ // Create the process.
+ auto* const process = Kernel::KProcess::Create(m_system.Kernel());
+ Kernel::KProcess::Register(m_system.Kernel(), process);
+
+ // On exit, ensure we free the additional reference to the process.
+ SCOPE_EXIT({ process->Close(); });
+
+ // Insert process modules into memory.
+ const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
+
+ // Ensure loading was successful.
+ if (load_result != Loader::ResultStatus::Success) {
+ return false;
+ }
+
+ // TODO: remove this, kernel already tracks this
+ m_system.Kernel().AppendNewProcess(process);
+
+ // Note the load parameters from NPDM.
+ m_main_thread_priority = load_parameters->main_thread_priority;
+ m_main_thread_stack_size = load_parameters->main_thread_stack_size;
+
+ // This process has not started yet.
+ m_process_started = false;
+
+ // Take ownership of the process object.
+ m_process = process;
+ m_process->Open();
+
+ // We succeeded.
+ return true;
+}
+
+void Process::Finalize() {
+ // Terminate, if we are currently holding a process.
+ this->Terminate();
+
+ // Close the process.
+ if (m_process) {
+ m_process->Close();
+
+ // TODO: remove this, kernel already tracks this
+ m_system.Kernel().RemoveProcess(m_process);
+ }
+
+ // Clean up.
+ m_process = nullptr;
+ m_main_thread_priority = 0;
+ m_main_thread_stack_size = 0;
+ m_program_id = 0;
+ m_process_started = false;
+}
+
+bool Process::Run() {
+ // If we already started the process, don't start again.
+ if (m_process_started) {
+ return false;
+ }
+
+ // Start.
+ if (m_process) {
+ m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
+ }
+
+ // Mark as started.
+ m_process_started = true;
+
+ // We succeeded.
+ return true;
+}
+
+void Process::Terminate() {
+ if (m_process) {
+ m_process->Terminate();
+ }
+}
+
+u64 Process::GetProcessId() const {
+ if (m_process) {
+ return m_process->GetProcessId();
+ }
+
+ return 0;
+}
+
+} // namespace Service::AM