1
1
Fork 0
forked from suyu/suyu
suyu/src/core/hle/service/am/process_creation.cpp

132 lines
4.9 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/os/process.h"
#include "core/loader/loader.h"
namespace Service::AM {
namespace {
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
}
switch (*slot) {
case FileSys::ContentProviderUnionSlot::UserNAND:
return FileSys::StorageId::NandUser;
case FileSys::ContentProviderUnionSlot::SysNAND:
return FileSys::StorageId::NandSystem;
case FileSys::ContentProviderUnionSlot::SDMC:
return FileSys::StorageId::SdCard;
case FileSys::ContentProviderUnionSlot::FrontendManual:
return FileSys::StorageId::Host;
default:
return FileSys::StorageId::None;
}
}
std::unique_ptr<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
// Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, file, program_id, program_index);
// Ensure we have a loader which can parse the NCA.
if (!out_loader) {
return nullptr;
}
// Try to load the process.
auto process = std::make_unique<Process>(system);
if (process->Initialize(*out_loader, out_load_result)) {
return process;
}
return nullptr;
}
} // Anonymous namespace
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation) {
// Attempt to load program NCA.
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
auto& storage = system.GetContentProviderUnion();
nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
// Ensure we retrieved a program NCA.
if (!nca_raw) {
return nullptr;
}
// 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 nullptr;
}
}
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus status;
return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
}
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
auto process =
CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
if (!process) {
return nullptr;
}
FileSys::NACP nacp;
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
memset(out_control.data(), 0, sizeof(u8) * out_control.size());
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(
storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
}
} // namespace Service::AM