aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/service/am/process_creation.cpp
blob: 237151d06103255bd62622f6bd20303a82d9ca00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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));
    }

    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