mirror of
https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
synced 2025-03-21 01:53:15 +00:00
139 lines
3.5 KiB
C++
139 lines
3.5 KiB
C++
// 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
|