am: separate logical concerns for process creation

This commit is contained in:
Liam 2024-02-12 00:09:04 -05:00
parent 1bec420695
commit d08422cc78
11 changed files with 265 additions and 64 deletions

View File

@ -434,8 +434,10 @@ add_library(core STATIC
hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h
hle/service/am/process.cpp
hle/service/am/process.h
hle/service/am/process_creation.cpp
hle/service/am/process_creation.h
hle/service/am/process_holder.cpp
hle/service/am/process_holder.h
hle/service/am/service/all_system_applet_proxies_service.cpp
hle/service/am/service/all_system_applet_proxies_service.h
hle/service/am/service/applet_common_functions.cpp
@ -914,6 +916,8 @@ add_library(core STATIC
hle/service/os/multi_wait_utils.h
hle/service/os/mutex.cpp
hle/service/os/mutex.h
hle/service/os/process.cpp
hle/service/os/process.h
hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h
hle/service/pctl/parental_control_service_factory.cpp

View File

@ -10,13 +10,14 @@
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/os/process.h"
#include "core/hle/service/service.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/am/display_layer_manager.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/am/process_holder.h"
namespace Service::AM {
@ -35,6 +36,7 @@ struct Applet {
// Process
std::unique_ptr<Process> process;
std::optional<ProcessHolder> process_holder;
// Creation state
AppletId applet_id{};

View File

@ -3,8 +3,8 @@
#include "core/core.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/os/process.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/resource_manager.h"

View File

@ -13,9 +13,11 @@ namespace Service::HID {
class IHidServer;
}
namespace Service::AM {
namespace Service {
class Process;
}
namespace Service::AM {
class HidRegistration {
public:

View File

@ -0,0 +1,127 @@
// 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,
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;
}
}
// Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, nca_raw, program_id, 0);
// 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)) {
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) {
std::unique_ptr<Loader::AppLoader> loader;
return CreateProcessImpl(loader, system, program_id, minimum_key_generation,
maximum_key_generation);
}
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
Core::System& system, u64 application_id,
u64 program_id) {
std::unique_ptr<Loader::AppLoader> loader;
auto process = CreateProcessImpl(loader, system, program_id, 0, 0);
if (!process) {
return nullptr;
}
FileSys::NACP nacp;
if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = program_id;
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

View File

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <vector>
#include "common/common_types.h"
namespace Core {
class System;
}
namespace Service {
class Process;
}
namespace Service::AM {
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation);
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
Core::System& system, u64 application_id,
u64 program_id);
} // namespace Service::AM

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/process_holder.h"
#include "core/hle/service/os/process.h"
namespace Service::AM {
ProcessHolder::ProcessHolder(Applet& applet, Process& process)
: MultiWaitHolder(process.GetHandle()), m_applet(applet), m_process(process) {}
ProcessHolder::~ProcessHolder() = default;
} // namespace Service::AM

View File

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/os/multi_wait_holder.h"
namespace Service {
class Process;
}
namespace Service::AM {
struct Applet;
class ProcessHolder : public MultiWaitHolder {
public:
explicit ProcessHolder(Applet& applet, Process& process);
~ProcessHolder();
Applet& GetApplet() const {
return m_applet;
}
Process& GetProcess() const {
return m_process;
}
private:
Applet& m_applet;
Process& m_process;
};
} // namespace Service::AM

View File

@ -7,6 +7,7 @@
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/library_applet_creator.h"
#include "core/hle/service/am/service/storage.h"
@ -110,8 +111,8 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
Firmware1700 = 17,
};
auto process = std::make_unique<Process>(system);
if (!process->Initialize(program_id, Firmware1400, Firmware1700)) {
auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700);
if (!process) {
// Couldn't initialize the guest process
return {};
}

View File

@ -3,15 +3,12 @@
#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/hle/kernel/svc_types.h"
#include "core/hle/service/os/process.h"
#include "core/loader/loader.h"
namespace Service::AM {
namespace Service {
Process::Process(Core::System& system)
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
@ -21,48 +18,10 @@ Process::~Process() {
this->Finalize();
}
bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
bool Process::Initialize(Loader::AppLoader& loader) {
// 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);
@ -73,7 +32,7 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
};
// Insert process modules into memory.
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
const auto [load_result, load_parameters] = loader.Load(*process, m_system);
// Ensure loading was successful.
if (load_result != Loader::ResultStatus::Success) {
@ -142,6 +101,20 @@ void Process::Terminate() {
}
}
void Process::ResetSignal() {
if (m_process) {
m_process->Reset();
}
}
bool Process::IsTerminated() const {
if (m_process) {
return m_process->IsTerminated();
}
return false;
}
u64 Process::GetProcessId() const {
if (m_process) {
return m_process->GetProcessId();
@ -150,4 +123,11 @@ u64 Process::GetProcessId() const {
return 0;
}
} // namespace Service::AM
void Process::Suspend(bool suspended) {
if (m_process) {
m_process->SetActivity(suspended ? Kernel::Svc::ProcessActivity::Paused
: Kernel::Svc::ProcessActivity::Runnable);
}
}
} // namespace Service

View File

@ -3,38 +3,47 @@
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Kernel {
class KProcess;
}
namespace Core {
class System;
}
namespace Service::AM {
namespace Loader {
class AppLoader;
}
namespace Kernel {
class KProcess;
}
namespace Service {
class Process {
public:
explicit Process(Core::System& system);
~Process();
bool Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
bool Initialize(Loader::AppLoader& loader);
void Finalize();
bool Run();
void Terminate();
void Suspend(bool suspended);
void ResetSignal();
bool IsInitialized() const {
return m_process != nullptr;
}
bool IsTerminated() const;
u64 GetProcessId() const;
u64 GetProgramId() const {
return m_program_id;
}
Kernel::KProcess* GetProcess() const {
Kernel::KProcess* GetHandle() const {
return m_process;
}
@ -47,4 +56,4 @@ private:
bool m_process_started{};
};
} // namespace Service::AM
} // namespace Service