mirror of
https://github.com/starr-dusT/yuzu-mainline
synced 2024-03-05 21:12:25 -08:00

Allows the use of the macro in constexpr-contexts. Also avoids some potential problems when nesting braces inside it.
154 lines
4.1 KiB
C++
154 lines
4.1 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/content_archive.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, u8 minimum_key_generation, u8 maximum_key_generation) {
|
|
// 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_raw{};
|
|
|
|
// Get the program NCA from built-in storage.
|
|
bis_system = fsc.GetSystemNANDContents();
|
|
if (bis_system) {
|
|
nca_raw = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
|
|
}
|
|
|
|
// Ensure we retrieved a program NCA.
|
|
if (!nca_raw) {
|
|
return false;
|
|
}
|
|
|
|
// Ensure we have a suitable version.
|
|
if (minimum_key_generation > 0) {
|
|
FileSys::NCA nca(nca_raw);
|
|
if (nca.GetStatus() == Loader::ResultStatus::Success &&
|
|
(nca.GetKeyGeneration() < minimum_key_generation ||
|
|
nca.GetKeyGeneration() > maximum_key_generation)) {
|
|
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
|
|
nca.GetKeyGeneration());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Get the appropriate loader to parse this NCA.
|
|
auto app_loader = Loader::GetLoader(m_system, nca_raw, 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
|