mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
loader: refactor to remove fake namespaces
This commit is contained in:
parent
d9dc04318d
commit
06f68a8159
16 changed files with 407 additions and 370 deletions
|
@ -20,8 +20,8 @@
|
|||
#include <stratosphere/sf.hpp>
|
||||
|
||||
#define AMS_LDR_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgumentsDeprecated, (ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size), (program_id, args, args_size), hos::Version_Min, hos::Version_10_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArguments, (ncm::ProgramId program_id, const sf::InPointerBuffer &args), (program_id, args), hos::Version_11_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgumentDeprecated, (ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size), (program_id, args, args_size), hos::Version_Min, hos::Version_10_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgument, (ncm::ProgramId program_id, const sf::InPointerBuffer &args), (program_id, args), hos::Version_11_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, FlushArguments, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, GetProcessModuleInfo, (sf::Out<u32> count, const sf::OutPointerArray<ldr::ModuleInfo> &out, os::ProcessId process_id), (count, out, process_id)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 65000, void, AtmosphereHasLaunchedBootProgram, (sf::Out<bool> out, ncm::ProgramId program_id), (out, program_id))
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <stratosphere/sf.hpp>
|
||||
|
||||
#define AMS_LDR_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgumentsDeprecated, (ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size), (program_id, args, args_size), hos::Version_Min, hos::Version_10_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArguments, (ncm::ProgramId program_id, const sf::InPointerBuffer &args), (program_id, args), hos::Version_11_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgumentDeprecated, (ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size), (program_id, args, args_size), hos::Version_Min, hos::Version_10_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgument, (ncm::ProgramId program_id, const sf::InPointerBuffer &args), (program_id, args), hos::Version_11_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, FlushArguments, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereRegisterExternalCode, (sf::OutMoveHandle out, ncm::ProgramId program_id), (out, program_id)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 65001, void, AtmosphereUnregisterExternalCode, (ncm::ProgramId program_id), (program_id))
|
||||
|
|
62
stratosphere/loader/source/ldr_argument_store.cpp
Normal file
62
stratosphere/loader/source/ldr_argument_store.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "ldr_argument_store.hpp"
|
||||
|
||||
namespace ams::ldr {
|
||||
|
||||
int ArgumentStore::FindIndex(Entry *map, ncm::ProgramId program_id) {
|
||||
for (auto i = 0; i < ArgumentMapCount; ++i) {
|
||||
if (map[i].program_id == program_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const ArgumentStore::Entry *ArgumentStore::Get(ncm::ProgramId program_id) {
|
||||
/* Find the matching arguments entry. */
|
||||
Entry *argument = nullptr;
|
||||
if (auto idx = FindIndex(m_argument_map, program_id); idx >= 0) {
|
||||
argument = m_argument_map + idx;
|
||||
}
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
Result ArgumentStore::Set(ncm::ProgramId program_id, const void *argument, size_t size) {
|
||||
/* Check that the argument size is within bounds. */
|
||||
R_UNLESS(size < ArgumentBufferSize, ldr::ResultArgumentOverflow());
|
||||
|
||||
/* Find either a matching arguments entry, or an empty entry. */
|
||||
auto idx = FindIndex(m_argument_map, program_id);
|
||||
if (idx < 0) {
|
||||
idx = FindIndex(m_argument_map, ncm::InvalidProgramId);
|
||||
}
|
||||
R_UNLESS(idx >= 0, ldr::ResultArgumentCountOverflow());
|
||||
|
||||
/* Set the arguments in the entry. */
|
||||
auto &entry = m_argument_map[idx];
|
||||
|
||||
entry.program_id = program_id;
|
||||
entry.argument_size = size;
|
||||
std::memcpy(entry.argument, argument, entry.argument_size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
52
stratosphere/loader/source/ldr_argument_store.hpp
Normal file
52
stratosphere/loader/source/ldr_argument_store.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::ldr {
|
||||
|
||||
class ArgumentStore {
|
||||
public:
|
||||
static constexpr size_t ArgumentBufferSize = 32_KB;
|
||||
|
||||
struct Entry {
|
||||
ncm::ProgramId program_id;
|
||||
size_t argument_size;
|
||||
u8 argument[ArgumentBufferSize];
|
||||
};
|
||||
private:
|
||||
static constexpr int ArgumentMapCount = 10;
|
||||
private:
|
||||
Entry m_argument_map[ArgumentMapCount];
|
||||
public:
|
||||
constexpr ArgumentStore() : m_argument_map{} {
|
||||
this->Flush();
|
||||
}
|
||||
public:
|
||||
const Entry *Get(ncm::ProgramId program_id);
|
||||
Result Set(ncm::ProgramId program_id, const void *argument, size_t size);
|
||||
|
||||
constexpr Result Flush() {
|
||||
for (auto &entry : m_argument_map) {
|
||||
entry.program_id = ncm::InvalidProgramId;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
private:
|
||||
static int FindIndex(Entry *map, ncm::ProgramId program_id);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "ldr_arguments.hpp"
|
||||
|
||||
namespace ams::ldr::args {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr size_t MaxArgumentInfos = 10;
|
||||
|
||||
/* Global storage. */
|
||||
ArgumentInfo g_argument_infos[MaxArgumentInfos];
|
||||
|
||||
/* Helpers. */
|
||||
ArgumentInfo *FindArgumentInfo(ncm::ProgramId program_id) {
|
||||
for (size_t i = 0; i < MaxArgumentInfos; i++) {
|
||||
if (g_argument_infos[i].program_id == program_id) {
|
||||
return g_argument_infos + i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ArgumentInfo *FindFreeArgumentInfo() {
|
||||
return FindArgumentInfo(ncm::InvalidProgramId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* API. */
|
||||
const ArgumentInfo *Get(ncm::ProgramId program_id) {
|
||||
return FindArgumentInfo(program_id);
|
||||
}
|
||||
|
||||
Result Set(ncm::ProgramId program_id, const void *args, size_t args_size) {
|
||||
R_UNLESS(args_size < ArgumentSizeMax, ldr::ResultArgumentOverflow());
|
||||
|
||||
ArgumentInfo *arg_info = FindArgumentInfo(program_id);
|
||||
if (arg_info == nullptr) {
|
||||
arg_info = FindFreeArgumentInfo();
|
||||
}
|
||||
R_UNLESS(arg_info != nullptr, ldr::ResultArgumentCountOverflow());
|
||||
|
||||
arg_info->program_id = program_id;
|
||||
arg_info->args_size = args_size;
|
||||
std::memcpy(arg_info->args, args, args_size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result Flush() {
|
||||
for (size_t i = 0; i < MaxArgumentInfos; i++) {
|
||||
g_argument_infos[i].program_id = ncm::InvalidProgramId;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::ldr::args {
|
||||
|
||||
constexpr size_t ArgumentSizeMax = 0x8000;
|
||||
|
||||
struct ArgumentInfo {
|
||||
ncm::ProgramId program_id;
|
||||
size_t args_size;
|
||||
u8 args[ArgumentSizeMax];
|
||||
};
|
||||
|
||||
/* API. */
|
||||
const ArgumentInfo *Get(ncm::ProgramId program_id);
|
||||
Result Set(ncm::ProgramId program_id, const void *args, size_t args_size);
|
||||
Result Flush();
|
||||
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
#include <stratosphere.hpp>
|
||||
#include "ldr_capabilities.hpp"
|
||||
|
||||
namespace ams::ldr::caps {
|
||||
namespace ams::ldr {
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -319,19 +319,14 @@ namespace ams::ldr::caps {
|
|||
}
|
||||
|
||||
/* Capabilities API. */
|
||||
Result ValidateCapabilities(const void *acid_kac, size_t acid_kac_size, const void *aci_kac, size_t aci_kac_size) {
|
||||
const util::BitPack32 *acid_caps = reinterpret_cast<const util::BitPack32 *>(acid_kac);
|
||||
const util::BitPack32 *aci_caps = reinterpret_cast<const util::BitPack32 *>(aci_kac);
|
||||
const size_t num_acid_caps = acid_kac_size / sizeof(*acid_caps);
|
||||
const size_t num_aci_caps = aci_kac_size / sizeof(*aci_caps);
|
||||
|
||||
for (size_t i = 0; i < num_aci_caps; i++) {
|
||||
const auto cur_cap = aci_caps[i];
|
||||
const auto id = GetCapabilityId(cur_cap);
|
||||
Result TestCapability(const util::BitPack32 *kacd, size_t kacd_count, const util::BitPack32 *kac, size_t kac_count) {
|
||||
for (size_t i = 0; i < kac_count; i++) {
|
||||
const auto cap = kac[i];
|
||||
const auto id = GetCapabilityId(cap);
|
||||
|
||||
#define VALIDATE_CASE(id) \
|
||||
case CapabilityId::id: \
|
||||
R_UNLESS(Capability##id::Decode(cur_cap).IsValid(acid_caps, num_acid_caps), ldr::ResultInvalidCapability##id()); \
|
||||
R_UNLESS(Capability##id::Decode(cap).IsValid(kacd, kacd_count), ldr::ResultInvalidCapability##id()); \
|
||||
break
|
||||
switch (id) {
|
||||
VALIDATE_CASE(KernelFlags);
|
||||
|
@ -347,8 +342,8 @@ namespace ams::ldr::caps {
|
|||
{
|
||||
/* Map Range needs extra logic because there it involves two sequential caps. */
|
||||
i++;
|
||||
R_UNLESS(i < num_aci_caps, ldr::ResultInvalidCapabilityMapRange());
|
||||
R_UNLESS(CapabilityMapRange::Decode(cur_cap).IsValid(aci_caps[i], acid_caps, num_acid_caps), ldr::ResultInvalidCapabilityMapRange());
|
||||
R_UNLESS(i < kac_count, ldr::ResultInvalidCapabilityMapRange());
|
||||
R_UNLESS(CapabilityMapRange::Decode(cap).IsValid(kac[i], kacd, kacd_count), ldr::ResultInvalidCapabilityMapRange());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -361,25 +356,23 @@ namespace ams::ldr::caps {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
u16 GetProgramInfoFlags(const void *kac, size_t kac_size) {
|
||||
const util::BitPack32 *caps = reinterpret_cast<const util::BitPack32 *>(kac);
|
||||
const size_t num_caps = kac_size / sizeof(*caps);
|
||||
u16 MakeProgramInfoFlag(const util::BitPack32 *kac, size_t count) {
|
||||
u16 flags = 0;
|
||||
|
||||
for (size_t i = 0; i < num_caps; i++) {
|
||||
const auto cur_cap = caps[i];
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const auto cap = kac[i];
|
||||
|
||||
switch (GetCapabilityId(cur_cap)) {
|
||||
switch (GetCapabilityId(cap)) {
|
||||
case CapabilityId::ApplicationType:
|
||||
{
|
||||
const auto app_type = CapabilityApplicationType::Decode(cur_cap).GetApplicationType() & ProgramInfoFlag_ApplicationTypeMask;
|
||||
const auto app_type = CapabilityApplicationType::Decode(cap).GetApplicationType() & ProgramInfoFlag_ApplicationTypeMask;
|
||||
if (app_type != ProgramInfoFlag_InvalidType) {
|
||||
flags |= app_type;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CapabilityId::DebugFlags:
|
||||
if (CapabilityDebugFlags::Decode(cur_cap).GetAllowDebug()) {
|
||||
if (CapabilityDebugFlags::Decode(cap).GetAllowDebug()) {
|
||||
flags |= ProgramInfoFlag_AllowDebug;
|
||||
}
|
||||
break;
|
||||
|
@ -391,18 +384,15 @@ namespace ams::ldr::caps {
|
|||
return flags;
|
||||
}
|
||||
|
||||
void SetProgramInfoFlags(u16 flags, void *kac, size_t kac_size) {
|
||||
util::BitPack32 *caps = reinterpret_cast<util::BitPack32 *>(kac);
|
||||
const size_t num_caps = kac_size / sizeof(*caps);
|
||||
|
||||
for (size_t i = 0; i < num_caps; i++) {
|
||||
const auto cur_cap = caps[i];
|
||||
switch (GetCapabilityId(cur_cap)) {
|
||||
void UpdateProgramInfoFlag(u16 flags, util::BitPack32 *kac, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const auto cap = kac[i];
|
||||
switch (GetCapabilityId(cap)) {
|
||||
case CapabilityId::ApplicationType:
|
||||
caps[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask);
|
||||
kac[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask);
|
||||
break;
|
||||
case CapabilityId::DebugFlags:
|
||||
caps[i] = CapabilityDebugFlags::Encode((flags & ProgramInfoFlag_AllowDebug) != 0, CapabilityDebugFlags::Decode(cur_cap).GetForceDebug());
|
||||
kac[i] = CapabilityDebugFlags::Encode((flags & ProgramInfoFlag_AllowDebug) != 0, CapabilityDebugFlags::Decode(cap).GetForceDebug());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -410,19 +400,16 @@ namespace ams::ldr::caps {
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessCapabilities(void *kac, size_t kac_size) {
|
||||
util::BitPack32 *caps = reinterpret_cast<util::BitPack32 *>(kac);
|
||||
const size_t num_caps = kac_size / sizeof(*caps);
|
||||
|
||||
for (size_t i = 0; i < num_caps; i++) {
|
||||
const auto cur_cap = caps[i];
|
||||
switch (GetCapabilityId(cur_cap)) {
|
||||
void PreProcessCapability(util::BitPack32 *kac, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const auto cap = kac[i];
|
||||
switch (GetCapabilityId(cap)) {
|
||||
case CapabilityId::MapRegion:
|
||||
{
|
||||
/* MapRegion was added in 8.0.0+, and is only allowed under kernels which have the relevant mappings. */
|
||||
/* However, we allow it under all firmwares on mesosphere, to facilitate KTrace usage by hbl. */
|
||||
if (!svc::IsKTraceEnabled()) {
|
||||
caps[i] = EmptyCapability;
|
||||
kac[i] = EmptyCapability;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::ldr::caps {
|
||||
namespace ams::ldr {
|
||||
|
||||
/* Capabilities API. */
|
||||
Result ValidateCapabilities(const void *acid_kac, size_t acid_kac_size, const void *aci_kac, size_t aci_kac_size);
|
||||
u16 GetProgramInfoFlags(const void *kac, size_t kac_size);
|
||||
void SetProgramInfoFlags(u16 flags, void *kac, size_t kac_size);
|
||||
Result TestCapability(const util::BitPack32 *kacd, size_t kacd_count, const util::BitPack32 *kac, size_t kac_count);
|
||||
|
||||
void ProcessCapabilities(void *kac, size_t kac_size);
|
||||
u16 MakeProgramInfoFlag(const util::BitPack32 *kac, size_t count);
|
||||
void UpdateProgramInfoFlag(u16 flags, util::BitPack32 *kac, size_t count);
|
||||
|
||||
void PreProcessCapability(util::BitPack32 *kac, size_t count);
|
||||
|
||||
}
|
||||
|
|
|
@ -52,10 +52,8 @@ namespace ams::ldr {
|
|||
AMS_ABORT_UNLESS(m_has_status);
|
||||
|
||||
/* Get the content path. */
|
||||
char content_path[fs::EntryNameLengthMax + 1] = "/";
|
||||
if (static_cast<ncm::StorageId>(loc.storage_id) != ncm::StorageId::None) {
|
||||
R_TRY(ResolveContentPath(content_path, loc));
|
||||
}
|
||||
char content_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(GetProgramPath(content_path, sizeof(content_path), loc));
|
||||
|
||||
/* Mount the atmosphere code file system. */
|
||||
R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(m_ams_code_verification_data), AtmosphereCodeMountName, content_path, loc.program_id, m_override_status.IsHbl(), m_override_status.IsProgramSpecific()));
|
||||
|
@ -82,7 +80,14 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* Redirection API. */
|
||||
Result ResolveContentPath(char *out_path, const ncm::ProgramLocation &loc) {
|
||||
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc) {
|
||||
/* Check for storage id none. */
|
||||
if (static_cast<ncm::StorageId>(loc.storage_id) == ncm::StorageId::None) {
|
||||
std::memset(out_path, 0, out_size);
|
||||
std::memcpy(out_path, "/", std::min<size_t>(out_size, 2));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
lr::Path path;
|
||||
|
||||
/* Check that path registration is allowable. */
|
||||
|
@ -103,23 +108,35 @@ namespace ams::ldr {
|
|||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
std::strncpy(out_path, path.str, fs::EntryNameLengthMax);
|
||||
out_path[fs::EntryNameLengthMax - 1] = '\0';
|
||||
/* Fix directory separators in path. */
|
||||
fs::Replace(path.str, sizeof(path.str), fs::StringTraits::AlternateDirectorySeparator, fs::StringTraits::DirectorySeparator);
|
||||
|
||||
fs::Replace(out_path, fs::EntryNameLengthMax + 1, fs::StringTraits::AlternateDirectorySeparator, fs::StringTraits::DirectorySeparator);
|
||||
/* Check that the path is valid. */
|
||||
AMS_ABORT_UNLESS(path.IsValid());
|
||||
|
||||
/* Copy the output path. */
|
||||
std::memset(out_path, 0, out_size);
|
||||
std::memcpy(out_path, path.str, std::min(out_size, sizeof(path)));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RedirectContentPath(const char *path, const ncm::ProgramLocation &loc) {
|
||||
/* Copy in path. */
|
||||
lr::Path lr_path;
|
||||
std::strncpy(lr_path.str, path, sizeof(lr_path.str));
|
||||
lr_path.str[sizeof(lr_path.str) - 1] = '\0';
|
||||
Result RedirectProgramPath(const char *path, size_t size, const ncm::ProgramLocation &loc) {
|
||||
/* Check for storage id none. */
|
||||
if (static_cast<ncm::StorageId>(loc.storage_id) == ncm::StorageId::None) {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Redirect the path. */
|
||||
/* Open location resolver. */
|
||||
lr::LocationResolver lr;
|
||||
R_TRY(lr::OpenLocationResolver(std::addressof(lr), static_cast<ncm::StorageId>(loc.storage_id)));
|
||||
|
||||
/* Copy in path. */
|
||||
lr::Path lr_path;
|
||||
std::memcpy(lr_path.str, path, std::min(size, sizeof(lr_path.str)));
|
||||
lr_path.str[sizeof(lr_path.str) - 1] = '\x00';
|
||||
|
||||
/* Redirect the path. */
|
||||
lr.RedirectProgramPath(lr_path, loc.program_id);
|
||||
|
||||
return ResultSuccess();
|
||||
|
|
|
@ -72,8 +72,8 @@ namespace ams::ldr {
|
|||
#define ENCODE_CODE_PATH(relative) "code:" relative
|
||||
|
||||
/* Redirection API. */
|
||||
Result ResolveContentPath(char *out_path, const ncm::ProgramLocation &loc);
|
||||
Result RedirectContentPath(const char *path, const ncm::ProgramLocation &loc);
|
||||
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc);
|
||||
Result RedirectProgramPath(const char *path, size_t size, const ncm::ProgramLocation &loc);
|
||||
Result RedirectHtmlDocumentPathForHbl(const ncm::ProgramLocation &loc);
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "ldr_arguments.hpp"
|
||||
#include "ldr_argument_store.hpp"
|
||||
#include "ldr_content_management.hpp"
|
||||
#include "ldr_development_manager.hpp"
|
||||
#include "ldr_process_creation.hpp"
|
||||
|
@ -25,90 +25,93 @@ namespace ams::ldr {
|
|||
|
||||
namespace {
|
||||
|
||||
Result GetProgramInfoImpl(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) {
|
||||
/* Zero output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
cfg::OverrideStatus status = {};
|
||||
|
||||
R_TRY(ldr::GetProgramInfo(out, std::addressof(status), loc));
|
||||
|
||||
if (loc.storage_id != static_cast<u8>(ncm::StorageId::None) && loc.program_id != out->program_id) {
|
||||
char path[fs::EntryNameLengthMax];
|
||||
const ncm::ProgramLocation new_loc = ncm::ProgramLocation::Make(out->program_id, static_cast<ncm::StorageId>(loc.storage_id));
|
||||
|
||||
R_TRY(ResolveContentPath(path, loc));
|
||||
path[sizeof(path) - 1] = '\x00';
|
||||
|
||||
R_TRY(RedirectContentPath(path, new_loc));
|
||||
|
||||
const auto arg_info = args::Get(loc.program_id);
|
||||
if (arg_info != nullptr) {
|
||||
R_TRY(args::Set(new_loc.program_id, arg_info->args, arg_info->args_size));
|
||||
}
|
||||
}
|
||||
|
||||
if (out_status != nullptr) {
|
||||
*out_status = status;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
constinit ArgumentStore g_argument_store;
|
||||
|
||||
}
|
||||
|
||||
/* Official commands. */
|
||||
Result LoaderService::CreateProcess(sf::OutMoveHandle out, PinId id, u32 flags, sf::CopyHandle &&reslimit_h) {
|
||||
|
||||
Result LoaderService::CreateProcess(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit) {
|
||||
/* Declare program path, which we'll need later. */
|
||||
|
||||
/* Get the location and override status. */
|
||||
ncm::ProgramLocation loc;
|
||||
cfg::OverrideStatus override_status;
|
||||
R_TRY(ldr::GetProgramLocationAndOverrideStatusFromPinId(std::addressof(loc), std::addressof(override_status), pin_id));
|
||||
|
||||
/* Get the program path. */
|
||||
char path[fs::EntryNameLengthMax];
|
||||
|
||||
/* Get location and override status. */
|
||||
R_TRY(ldr::GetProgramLocationAndOverrideStatusFromPinId(std::addressof(loc), std::addressof(override_status), id));
|
||||
|
||||
if (loc.storage_id != static_cast<u8>(ncm::StorageId::None)) {
|
||||
R_TRY(ResolveContentPath(path, loc));
|
||||
path[sizeof(path) - 1] = '\x00';
|
||||
} else {
|
||||
path[0] = '\x00';
|
||||
}
|
||||
R_TRY(GetProgramPath(path, sizeof(path), loc));
|
||||
path[sizeof(path) - 1] = '\x00';
|
||||
|
||||
/* Create the process. */
|
||||
os::NativeHandle process_handle;
|
||||
R_TRY(ldr::CreateProcess(std::addressof(process_handle), id, loc, override_status, path, flags, reslimit_h.GetOsHandle()));
|
||||
return ldr::CreateProcess(out, pin_id, loc, override_status, path, g_argument_store.Get(loc.program_id), flags, resource_limit);
|
||||
}
|
||||
|
||||
Result LoaderService::GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) {
|
||||
/* Zero output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
|
||||
/* Get the program path. */
|
||||
char path[fs::EntryNameLengthMax];
|
||||
R_TRY(GetProgramPath(path, sizeof(path), loc));
|
||||
path[sizeof(path) - 1] = '\x00';
|
||||
|
||||
/* Get the program info. */
|
||||
cfg::OverrideStatus status;
|
||||
R_TRY(ldr::GetProgramInfo(out, std::addressof(status), loc, path));
|
||||
|
||||
if (loc.program_id != out->program_id) {
|
||||
/* Redirect the program path. */
|
||||
const ncm::ProgramLocation new_loc = ncm::ProgramLocation::Make(out->program_id, static_cast<ncm::StorageId>(loc.storage_id));
|
||||
R_TRY(RedirectProgramPath(path, sizeof(path), new_loc));
|
||||
|
||||
/* Update the arguments, as needed. */
|
||||
if (const auto *entry = g_argument_store.Get(loc.program_id); entry != nullptr) {
|
||||
R_TRY(this->SetProgramArgument(new_loc.program_id, entry->argument, entry->argument_size));
|
||||
}
|
||||
}
|
||||
|
||||
/* If we should, set the output status. */
|
||||
if (out_status != nullptr) {
|
||||
*out_status = status;
|
||||
}
|
||||
|
||||
/* Set output process handle. */
|
||||
out.SetValue(process_handle, true);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoaderService::GetProgramInfo(sf::Out<ProgramInfo> out, const ncm::ProgramLocation &loc) {
|
||||
return GetProgramInfoImpl(out.GetPointer(), nullptr, loc);
|
||||
}
|
||||
|
||||
Result LoaderService::PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc) {
|
||||
return ldr::PinProgram(out_id.GetPointer(), loc, cfg::OverrideStatus{});
|
||||
Result LoaderService::PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
|
||||
*out = {};
|
||||
return ldr::PinProgram(out, loc, status);
|
||||
}
|
||||
|
||||
Result LoaderService::UnpinProgram(PinId id) {
|
||||
return ldr::UnpinProgram(id);
|
||||
}
|
||||
|
||||
Result LoaderService::SetProgramArgumentsDeprecated(ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size) {
|
||||
return args::Set(program_id, args.GetPointer(), std::min(args.GetSize(), size_t(args_size)));
|
||||
}
|
||||
|
||||
Result LoaderService::SetProgramArguments(ncm::ProgramId program_id, const sf::InPointerBuffer &args) {
|
||||
return args::Set(program_id, args.GetPointer(), args.GetSize());
|
||||
Result LoaderService::SetProgramArgument(ncm::ProgramId program_id, const void *argument, size_t size) {
|
||||
return g_argument_store.Set(program_id, argument, size);
|
||||
}
|
||||
|
||||
Result LoaderService::FlushArguments() {
|
||||
return args::Flush();
|
||||
return g_argument_store.Flush();
|
||||
}
|
||||
|
||||
Result LoaderService::GetProcessModuleInfo(sf::Out<u32> count, const sf::OutPointerArray<ModuleInfo> &out, os::ProcessId process_id) {
|
||||
*count = 0;
|
||||
std::memset(out.GetPointer(), 0, out.GetSize() * sizeof(ldr::ModuleInfo));
|
||||
return ldr::GetProcessModuleInfo(count.GetPointer(), out.GetPointer(), out.GetSize(), process_id);
|
||||
Result LoaderService::GetProcessModuleInfo(u32 *out_count, ModuleInfo *out, size_t max_out_count, os::ProcessId process_id) {
|
||||
*out_count = 0;
|
||||
std::memset(out, 0, max_out_count * sizeof(*out));
|
||||
return ldr::GetProcessModuleInfo(out_count, out, max_out_count, process_id);
|
||||
}
|
||||
|
||||
Result LoaderService::RegisterExternalCode(os::NativeHandle *out, ncm::ProgramId program_id) {
|
||||
return fssystem::CreateExternalCode(out, program_id);
|
||||
}
|
||||
|
||||
void LoaderService::UnregisterExternalCode(ncm::ProgramId program_id) {
|
||||
fssystem::DestroyExternalCode(program_id);
|
||||
}
|
||||
|
||||
void LoaderService::HasLaunchedBootProgram(bool *out, ncm::ProgramId program_id) {
|
||||
*out = ldr::HasLaunchedBootProgram(program_id);
|
||||
}
|
||||
|
||||
Result LoaderService::SetEnabledProgramVerification(bool enabled) {
|
||||
|
@ -116,29 +119,4 @@ namespace ams::ldr {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Atmosphere commands. */
|
||||
Result LoaderService::AtmosphereRegisterExternalCode(sf::OutMoveHandle out, ncm::ProgramId program_id) {
|
||||
os::NativeHandle handle;
|
||||
R_TRY(fssystem::CreateExternalCode(std::addressof(handle), program_id));
|
||||
|
||||
out.SetValue(handle, true);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void LoaderService::AtmosphereUnregisterExternalCode(ncm::ProgramId program_id) {
|
||||
fssystem::DestroyExternalCode(program_id);
|
||||
}
|
||||
|
||||
void LoaderService::AtmosphereHasLaunchedBootProgram(sf::Out<bool> out, ncm::ProgramId program_id) {
|
||||
out.SetValue(ldr::HasLaunchedBootProgram(program_id));
|
||||
}
|
||||
|
||||
Result LoaderService::AtmosphereGetProgramInfo(sf::Out<ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status, const ncm::ProgramLocation &loc) {
|
||||
return GetProgramInfoImpl(out_program_info.GetPointer(), out_status.GetPointer(), loc);
|
||||
}
|
||||
|
||||
Result LoaderService::AtmospherePinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status) {
|
||||
return ldr::PinProgram(out_id.GetPointer(), loc, override_status);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,22 +21,74 @@ namespace ams::ldr {
|
|||
class LoaderService {
|
||||
public:
|
||||
/* Official commands. */
|
||||
Result CreateProcess(sf::OutMoveHandle proc_h, PinId id, u32 flags, sf::CopyHandle &&reslimit_h);
|
||||
Result GetProgramInfo(sf::Out<ProgramInfo> out_program_info, const ncm::ProgramLocation &loc);
|
||||
Result PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc);
|
||||
Result CreateProcess(sf::OutMoveHandle proc_h, PinId id, u32 flags, sf::CopyHandle &&reslimit_h) {
|
||||
os::NativeHandle handle = os::InvalidNativeHandle;
|
||||
const auto result = this->CreateProcess(std::addressof(handle), id, flags, reslimit_h.GetOsHandle());
|
||||
proc_h.SetValue(handle, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result GetProgramInfo(sf::Out<ProgramInfo> out_program_info, const ncm::ProgramLocation &loc) {
|
||||
return this->GetProgramInfo(out_program_info.GetPointer(), nullptr, loc);
|
||||
}
|
||||
|
||||
Result PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc) {
|
||||
return this->PinProgram(out_id.GetPointer(), loc, cfg::OverrideStatus{});
|
||||
}
|
||||
|
||||
Result UnpinProgram(PinId id);
|
||||
Result SetProgramArgumentsDeprecated(ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size);
|
||||
Result SetProgramArguments(ncm::ProgramId program_id, const sf::InPointerBuffer &args);
|
||||
|
||||
Result SetProgramArgumentDeprecated(ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size) {
|
||||
AMS_UNUSED(args_size);
|
||||
return this->SetProgramArgument(program_id, args.GetPointer(), std::min<size_t>(args_size, args.GetSize()));
|
||||
}
|
||||
|
||||
Result SetProgramArgument(ncm::ProgramId program_id, const sf::InPointerBuffer &args) {
|
||||
return this->SetProgramArgument(program_id, args.GetPointer(), args.GetSize());
|
||||
}
|
||||
|
||||
Result FlushArguments();
|
||||
Result GetProcessModuleInfo(sf::Out<u32> count, const sf::OutPointerArray<ModuleInfo> &out, os::ProcessId process_id);
|
||||
|
||||
Result GetProcessModuleInfo(sf::Out<u32> count, const sf::OutPointerArray<ModuleInfo> &out, os::ProcessId process_id) {
|
||||
R_UNLESS(out.GetSize() <= std::numeric_limits<s32>::max(), ldr::ResultInvalidSize());
|
||||
|
||||
return this->GetProcessModuleInfo(count.GetPointer(), out.GetPointer(), out.GetSize(), process_id);
|
||||
}
|
||||
|
||||
Result SetEnabledProgramVerification(bool enabled);
|
||||
|
||||
/* Atmosphere commands. */
|
||||
Result AtmosphereRegisterExternalCode(sf::OutMoveHandle out, ncm::ProgramId program_id);
|
||||
void AtmosphereUnregisterExternalCode(ncm::ProgramId program_id);
|
||||
void AtmosphereHasLaunchedBootProgram(sf::Out<bool> out, ncm::ProgramId program_id);
|
||||
Result AtmosphereGetProgramInfo(sf::Out<ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status, const ncm::ProgramLocation &loc);
|
||||
Result AtmospherePinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status);
|
||||
Result AtmosphereRegisterExternalCode(sf::OutMoveHandle out, ncm::ProgramId program_id) {
|
||||
os::NativeHandle handle = os::InvalidNativeHandle;
|
||||
const auto result = this->RegisterExternalCode(std::addressof(handle), program_id);
|
||||
out.SetValue(handle, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
void AtmosphereUnregisterExternalCode(ncm::ProgramId program_id) {
|
||||
return this->UnregisterExternalCode(program_id);
|
||||
}
|
||||
|
||||
void AtmosphereHasLaunchedBootProgram(sf::Out<bool> out, ncm::ProgramId program_id) {
|
||||
return this->HasLaunchedBootProgram(out.GetPointer(), program_id);
|
||||
}
|
||||
|
||||
Result AtmosphereGetProgramInfo(sf::Out<ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status, const ncm::ProgramLocation &loc) {
|
||||
return this->GetProgramInfo(out_program_info.GetPointer(), out_status.GetPointer(), loc);
|
||||
}
|
||||
|
||||
Result AtmospherePinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status) {
|
||||
return this->PinProgram(out_id.GetPointer(), loc, override_status);
|
||||
}
|
||||
private:
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit);
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc);
|
||||
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status);
|
||||
Result SetProgramArgument(ncm::ProgramId program_id, const void *argument, size_t size);
|
||||
Result GetProcessModuleInfo(u32 *out_count, ModuleInfo *out, size_t max_out_count, os::ProcessId process_id);
|
||||
Result RegisterExternalCode(os::NativeHandle *out, ncm::ProgramId program_id);
|
||||
void UnregisterExternalCode(ncm::ProgramId program_id);
|
||||
void HasLaunchedBootProgram(bool *out, ncm::ProgramId program_id);
|
||||
};
|
||||
static_assert(ams::ldr::impl::IsIProcessManagerInterface<LoaderService>);
|
||||
static_assert(ams::ldr::impl::IsIDebugMonitorInterface<LoaderService>);
|
||||
|
|
|
@ -218,9 +218,9 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* Fix flags. */
|
||||
const u16 program_info_flags = caps::GetProgramInfoFlags(o_meta->aci_kac, o_meta->aci->kac_size);
|
||||
caps::SetProgramInfoFlags(program_info_flags, meta->acid_kac, meta->acid->kac_size);
|
||||
caps::SetProgramInfoFlags(program_info_flags, meta->aci_kac, meta->aci->kac_size);
|
||||
const u16 program_info_flags = MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(o_meta->aci_kac), o_meta->aci->kac_size / sizeof(util::BitPack32));
|
||||
UpdateProgramInfoFlag(program_info_flags, static_cast<util::BitPack32 *>(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32));
|
||||
UpdateProgramInfoFlag(program_info_flags, static_cast<util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* When hbl is applet, adjust main thread priority. */
|
||||
if ((caps::GetProgramInfoFlags(meta->aci_kac, meta->aci->kac_size) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Applet) {
|
||||
if ((MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Applet) {
|
||||
constexpr auto HblMainThreadPriorityApplication = 44;
|
||||
constexpr auto HblMainThreadPriorityApplet = 40;
|
||||
if (meta->npdm->main_thread_priority == HblMainThreadPriorityApplication) {
|
||||
|
@ -262,8 +262,8 @@ namespace ams::ldr {
|
|||
|
||||
/* Pre-process the capabilities. */
|
||||
/* This is used to e.g. avoid passing memory region descriptor to older kernels. */
|
||||
caps::ProcessCapabilities(meta->acid_kac, meta->acid->kac_size);
|
||||
caps::ProcessCapabilities(meta->aci_kac, meta->aci->kac_size);
|
||||
PreProcessCapability(static_cast<util::BitPack32 *>(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32));
|
||||
PreProcessCapability(static_cast<util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32));
|
||||
|
||||
/* Set output. */
|
||||
g_cached_program_id = loc.program_id;
|
||||
|
|
|
@ -132,10 +132,10 @@ namespace ams::ldr {
|
|||
/* Helpers. */
|
||||
Result GetProgramInfoFromMeta(ProgramInfo *out, const Meta *meta) {
|
||||
/* Copy basic info. */
|
||||
out->main_thread_priority = meta->npdm->main_thread_priority;
|
||||
out->default_cpu_id = meta->npdm->default_cpu_id;
|
||||
out->main_thread_priority = meta->npdm->main_thread_priority;
|
||||
out->default_cpu_id = meta->npdm->default_cpu_id;
|
||||
out->main_thread_stack_size = meta->npdm->main_thread_stack_size;
|
||||
out->program_id = meta->aci->program_id;
|
||||
out->program_id = meta->aci->program_id;
|
||||
|
||||
/* Copy access controls. */
|
||||
size_t offset = 0;
|
||||
|
@ -156,16 +156,16 @@ namespace ams::ldr {
|
|||
#undef COPY_ACCESS_CONTROL
|
||||
|
||||
/* Copy flags. */
|
||||
out->flags = caps::GetProgramInfoFlags(meta->acid_kac, meta->acid->kac_size);
|
||||
out->flags = MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
bool IsApplet(const Meta *meta) {
|
||||
return (caps::GetProgramInfoFlags(meta->aci_kac, meta->aci->kac_size) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Applet;
|
||||
return (MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Applet;
|
||||
}
|
||||
|
||||
bool IsApplication(const Meta *meta) {
|
||||
return (caps::GetProgramInfoFlags(meta->aci_kac, meta->aci->kac_size) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Application;
|
||||
return (MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Application;
|
||||
}
|
||||
|
||||
Npdm::AddressSpaceType GetAddressSpaceType(const Meta *meta) {
|
||||
|
@ -226,7 +226,7 @@ namespace ams::ldr {
|
|||
R_UNLESS(meta->aci->program_id <= meta->acid->program_id_max, ldr::ResultInvalidProgramId());
|
||||
|
||||
/* Validate the kernel capabilities. */
|
||||
R_TRY(caps::ValidateCapabilities(meta->acid_kac, meta->acid->kac_size, meta->aci_kac, meta->aci->kac_size));
|
||||
R_TRY(TestCapability(static_cast<const util::BitPack32 *>(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32), static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)));
|
||||
|
||||
/* If we have data to validate, validate it. */
|
||||
if (code_verification_data.has_data && meta->check_verification_data) {
|
||||
|
@ -335,15 +335,15 @@ namespace ams::ldr {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetCreateProcessParameter(svc::CreateProcessParameter *out, const Meta *meta, u32 flags, os::NativeHandle reslimit_h) {
|
||||
Result GetCreateProcessParameter(svc::CreateProcessParameter *out, const Meta *meta, u32 flags, os::NativeHandle resource_limit) {
|
||||
/* Clear output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
|
||||
/* Set name, version, program id, resource limit handle. */
|
||||
std::memcpy(out->name, meta->npdm->program_name, sizeof(out->name) - 1);
|
||||
out->version = meta->npdm->version;
|
||||
out->program_id = static_cast<u64>(meta->aci->program_id);
|
||||
out->reslimit = reslimit_h;
|
||||
out->version = meta->npdm->version;
|
||||
out->program_id = meta->aci->program_id.value;
|
||||
out->reslimit = resource_limit;
|
||||
|
||||
/* Set flags. */
|
||||
R_TRY(GetCreateProcessFlags(std::addressof(out->flags), meta, flags));
|
||||
|
@ -427,7 +427,7 @@ namespace ams::ldr {
|
|||
}
|
||||
}
|
||||
|
||||
Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info) {
|
||||
Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument) {
|
||||
/* Clear output. */
|
||||
out->args_address = 0;
|
||||
out->args_size = 0;
|
||||
|
@ -435,6 +435,7 @@ namespace ams::ldr {
|
|||
std::memset(out->nso_size, 0, sizeof(out->nso_size));
|
||||
|
||||
size_t total_size = 0;
|
||||
bool argument_allocated = false;
|
||||
|
||||
/* Calculate base offsets. */
|
||||
for (size_t i = 0; i < Nso_Count; i++) {
|
||||
|
@ -446,15 +447,15 @@ namespace ams::ldr {
|
|||
out->nso_size[i] = text_end;
|
||||
out->nso_size[i] = std::max(out->nso_size[i], ro_end);
|
||||
out->nso_size[i] = std::max(out->nso_size[i], rw_end);
|
||||
out->nso_size[i] = (out->nso_size[i] + size_t(0xFFFul)) & ~size_t(0xFFFul);
|
||||
out->nso_size[i] = util::AlignUp(out->nso_size[i], os::MemoryPageSize);
|
||||
|
||||
total_size += out->nso_size[i];
|
||||
|
||||
if (arg_info != nullptr && arg_info->args_size && !out->args_size) {
|
||||
if (!argument_allocated && argument != nullptr) {
|
||||
out->args_address = total_size;
|
||||
out->args_size = 2 * arg_info->args_size + args::ArgumentSizeMax + 2 * sizeof(u32);
|
||||
out->args_size = (out->args_size + size_t(0xFFFul)) & ~size_t(0xFFFul);
|
||||
out->args_size = util::AlignUp(2 * sizeof(u32) + argument->argument_size * 2 + ArgumentStore::ArgumentBufferSize, os::MemoryPageSize);
|
||||
total_size += out->args_size;
|
||||
argument_allocated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -516,13 +517,13 @@ namespace ams::ldr {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CreateProcessImpl(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info, u32 flags, os::NativeHandle reslimit_h) {
|
||||
Result CreateProcessImpl(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) {
|
||||
/* Get CreateProcessParameter. */
|
||||
svc::CreateProcessParameter param;
|
||||
R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, reslimit_h));
|
||||
R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, resource_limit));
|
||||
|
||||
/* Decide on an NSO layout. */
|
||||
R_TRY(DecideAddressSpaceLayout(out, std::addressof(param), nso_headers, has_nso, arg_info));
|
||||
R_TRY(DecideAddressSpaceLayout(out, std::addressof(param), nso_headers, has_nso, argument));
|
||||
|
||||
/* Actually create process. */
|
||||
svc::Handle process_handle;
|
||||
|
@ -567,7 +568,7 @@ namespace ams::ldr {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadNsoIntoProcessMemory(os::NativeHandle process_handle, fs::FileHandle file, uintptr_t map_address, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size) {
|
||||
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, uintptr_t map_address, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size) {
|
||||
/* Map and read data from file. */
|
||||
{
|
||||
AutoCloseMap map(map_address, process_handle, nso_address, nso_size);
|
||||
|
@ -588,7 +589,7 @@ namespace ams::ldr {
|
|||
std::memset(reinterpret_cast<void *>(map_address), 0, nso_header->text_dst_offset);
|
||||
std::memset(reinterpret_cast<void *>(map_address + text_end), 0, nso_header->ro_dst_offset - text_end);
|
||||
std::memset(reinterpret_cast<void *>(map_address + ro_end), 0, nso_header->rw_dst_offset - ro_end);
|
||||
std::memset(reinterpret_cast<void *>(map_address + rw_end), 0, nso_header->bss_size);
|
||||
std::memset(reinterpret_cast<void *>(map_address + rw_end), 0, nso_header->bss_size);
|
||||
|
||||
/* Apply embedded patches. */
|
||||
ApplyEmbeddedPatchesToModule(nso_header->module_id, map_address, nso_size);
|
||||
|
@ -598,9 +599,9 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* Set permissions. */
|
||||
const size_t text_size = (static_cast<size_t>(nso_header->text_size) + size_t(0xFFFul)) & ~size_t(0xFFFul);
|
||||
const size_t ro_size = (static_cast<size_t>(nso_header->ro_size) + size_t(0xFFFul)) & ~size_t(0xFFFul);
|
||||
const size_t rw_size = (static_cast<size_t>(nso_header->rw_size + nso_header->bss_size) + size_t(0xFFFul)) & ~size_t(0xFFFul);
|
||||
const size_t text_size = util::AlignUp(nso_header->text_size, os::MemoryPageSize);
|
||||
const size_t ro_size = util::AlignUp(nso_header->ro_size, os::MemoryPageSize);
|
||||
const size_t rw_size = util::AlignUp(nso_header->rw_size + nso_header->bss_size, os::MemoryPageSize);
|
||||
if (text_size) {
|
||||
R_TRY(svc::SetProcessMemoryPermission(process_handle, nso_address + nso_header->text_dst_offset, text_size, svc::MemoryPermission_ReadExecute));
|
||||
}
|
||||
|
@ -614,7 +615,7 @@ namespace ams::ldr {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadNsosIntoProcessMemory(const ProcessInfo *process_info, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info) {
|
||||
Result LoadAutoLoadModules(const ProcessInfo *process_info, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument) {
|
||||
/* Load each NSO. */
|
||||
for (size_t i = 0; i < Nso_Count; i++) {
|
||||
if (has_nso[i]) {
|
||||
|
@ -625,12 +626,12 @@ namespace ams::ldr {
|
|||
uintptr_t map_address;
|
||||
R_TRY(SearchFreeRegion(std::addressof(map_address), process_info->nso_size[i]));
|
||||
|
||||
R_TRY(LoadNsoIntoProcessMemory(process_info->process_handle, file, map_address, nso_headers + i, process_info->nso_address[i], process_info->nso_size[i]));
|
||||
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, map_address, nso_headers + i, process_info->nso_address[i], process_info->nso_size[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Load arguments, if present. */
|
||||
if (arg_info != nullptr) {
|
||||
if (argument != nullptr) {
|
||||
/* Write argument data into memory. */
|
||||
{
|
||||
uintptr_t map_address;
|
||||
|
@ -642,8 +643,8 @@ namespace ams::ldr {
|
|||
ProgramArguments *args = reinterpret_cast<ProgramArguments *>(map_address);
|
||||
std::memset(args, 0, sizeof(*args));
|
||||
args->allocated_size = process_info->args_size;
|
||||
args->arguments_size = arg_info->args_size;
|
||||
std::memcpy(args->arguments, arg_info->args, arg_info->args_size);
|
||||
args->arguments_size = argument->argument_size;
|
||||
std::memcpy(args->arguments, argument->argument, argument->argument_size);
|
||||
}
|
||||
|
||||
/* Set argument region permissions. */
|
||||
|
@ -656,87 +657,81 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* Process Creation API. */
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, u32 flags, os::NativeHandle reslimit_h) {
|
||||
/* Use global storage for NSOs. */
|
||||
NsoHeader *nso_headers = g_nso_headers;
|
||||
bool *has_nso = g_has_nso;
|
||||
const auto arg_info = args::Get(loc.program_id);
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) {
|
||||
/* Mount code. */
|
||||
AMS_UNUSED(path);
|
||||
ScopedCodeMount mount(loc, override_status);
|
||||
R_TRY(mount.GetResult());
|
||||
|
||||
/* Load meta, possibly from cache. */
|
||||
Meta meta;
|
||||
R_TRY(LoadMetaFromCache(std::addressof(meta), loc, override_status));
|
||||
|
||||
/* Validate meta. */
|
||||
R_TRY(ValidateMeta(std::addressof(meta), loc, mount.GetCodeVerificationData()));
|
||||
|
||||
/* Load, validate NSOs. */
|
||||
R_TRY(LoadNsoHeaders(g_nso_headers, g_has_nso));
|
||||
R_TRY(ValidateNsoHeaders(g_nso_headers, g_has_nso));
|
||||
|
||||
/* Actually create process. */
|
||||
ProcessInfo info;
|
||||
R_TRY(CreateProcessImpl(std::addressof(info), std::addressof(meta), g_nso_headers, g_has_nso, argument, flags, resource_limit));
|
||||
|
||||
/* Load NSOs into process memory. */
|
||||
{
|
||||
/* Mount code. */
|
||||
AMS_UNUSED(path);
|
||||
ScopedCodeMount mount(loc, override_status);
|
||||
R_TRY(mount.GetResult());
|
||||
/* Ensure we close the process handle, if we fail. */
|
||||
auto process_guard = SCOPE_GUARD { os::CloseNativeHandle(info.process_handle); };
|
||||
|
||||
/* Load meta, possibly from cache. */
|
||||
Meta meta;
|
||||
R_TRY(LoadMetaFromCache(std::addressof(meta), loc, override_status));
|
||||
/* Load all NSOs. */
|
||||
R_TRY(LoadAutoLoadModules(std::addressof(info), g_nso_headers, g_has_nso, argument));
|
||||
|
||||
/* Validate meta. */
|
||||
R_TRY(ValidateMeta(std::addressof(meta), loc, mount.GetCodeVerificationData()));
|
||||
/* We don't need to close the process handle, since we succeeded. */
|
||||
process_guard.Cancel();
|
||||
}
|
||||
|
||||
/* Load, validate NSOs. */
|
||||
R_TRY(LoadNsoHeaders(nso_headers, has_nso));
|
||||
R_TRY(ValidateNsoHeaders(nso_headers, has_nso));
|
||||
/* Register NSOs with the RoManager. */
|
||||
{
|
||||
/* Nintendo doesn't validate this get, but we do. */
|
||||
os::ProcessId process_id = os::GetProcessId(info.process_handle);
|
||||
|
||||
/* Actually create process. */
|
||||
ProcessInfo info;
|
||||
R_TRY(CreateProcessImpl(std::addressof(info), std::addressof(meta), nso_headers, has_nso, arg_info, flags, reslimit_h));
|
||||
/* Register new process. */
|
||||
const auto as_type = GetAddressSpaceType(std::addressof(meta));
|
||||
RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated);
|
||||
|
||||
/* Load NSOs into process memory. */
|
||||
{
|
||||
/* Ensure we close the process handle, if we fail. */
|
||||
auto process_guard = SCOPE_GUARD { os::CloseNativeHandle(info.process_handle); };
|
||||
|
||||
/* Load all NSOs. */
|
||||
R_TRY(LoadNsosIntoProcessMemory(std::addressof(info), nso_headers, has_nso, arg_info));
|
||||
|
||||
/* We don't need to close the process handle, since we succeeded. */
|
||||
process_guard.Cancel();
|
||||
}
|
||||
|
||||
/* Register NSOs with the RoManager. */
|
||||
{
|
||||
/* Nintendo doesn't validate this get, but we do. */
|
||||
os::ProcessId process_id = os::GetProcessId(info.process_handle);
|
||||
|
||||
/* Register new process. */
|
||||
/* NOTE: Nintendo uses meta->aci->program_id, not loc.program_id. Should we? */
|
||||
const auto as_type = GetAddressSpaceType(std::addressof(meta));
|
||||
RoManager::GetInstance().RegisterProcess(pin_id, process_id, loc.program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated);
|
||||
|
||||
/* Register all NSOs. */
|
||||
for (size_t i = 0; i < Nso_Count; i++) {
|
||||
if (has_nso[i]) {
|
||||
RoManager::GetInstance().AddNso(pin_id, nso_headers[i].module_id, info.nso_address[i], info.nso_size[i]);
|
||||
}
|
||||
/* Register all NSOs. */
|
||||
for (size_t i = 0; i < Nso_Count; i++) {
|
||||
if (g_has_nso[i]) {
|
||||
RoManager::GetInstance().AddNso(pin_id, g_nso_headers[i].module_id, info.nso_address[i], info.nso_size[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're overriding for HBL, perform HTML document redirection. */
|
||||
if (override_status.IsHbl()) {
|
||||
/* Don't validate result, failure is okay. */
|
||||
RedirectHtmlDocumentPathForHbl(loc);
|
||||
}
|
||||
|
||||
/* Clear the external code for the program. */
|
||||
fssystem::DestroyExternalCode(loc.program_id);
|
||||
|
||||
/* Note that we've created the program. */
|
||||
SetLaunchedBootProgram(loc.program_id);
|
||||
|
||||
/* Move the process handle to output. */
|
||||
*out = info.process_handle;
|
||||
}
|
||||
|
||||
/* If we're overriding for HBL, perform HTML document redirection. */
|
||||
if (override_status.IsHbl()) {
|
||||
/* Don't validate result, failure is okay. */
|
||||
RedirectHtmlDocumentPathForHbl(loc);
|
||||
}
|
||||
|
||||
/* Clear the external code for the program. */
|
||||
fssystem::DestroyExternalCode(loc.program_id);
|
||||
|
||||
/* Note that we've created the program. */
|
||||
SetLaunchedBootProgram(loc.program_id);
|
||||
|
||||
/* Move the process handle to output. */
|
||||
*out = info.process_handle;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) {
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path) {
|
||||
Meta meta;
|
||||
|
||||
/* Load Meta. */
|
||||
{
|
||||
AMS_UNUSED(path);
|
||||
|
||||
ScopedCodeMount mount(loc);
|
||||
R_TRY(mount.GetResult());
|
||||
R_TRY(LoadMeta(std::addressof(meta), loc, mount.GetOverrideStatus()));
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "ldr_arguments.hpp"
|
||||
#include "ldr_argument_store.hpp"
|
||||
|
||||
namespace ams::ldr {
|
||||
|
||||
/* Process Creation API. */
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, u32 flags, os::NativeHandle reslimit_h);
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc);
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit);
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path);
|
||||
|
||||
Result PinProgram(PinId *out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status);
|
||||
Result UnpinProgram(PinId id);
|
||||
|
|
Loading…
Reference in a new issue