loader: refactor to remove fake namespaces

This commit is contained in:
Michael Scire 2021-10-10 21:37:29 -07:00
parent d9dc04318d
commit 06f68a8159
16 changed files with 407 additions and 370 deletions

View file

@ -20,8 +20,8 @@
#include <stratosphere/sf.hpp> #include <stratosphere/sf.hpp>
#define AMS_LDR_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \ #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, 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, 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, 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, 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, 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)) AMS_SF_METHOD_INFO(C, H, 65000, void, AtmosphereHasLaunchedBootProgram, (sf::Out<bool> out, ncm::ProgramId program_id), (out, program_id))

View file

@ -20,8 +20,8 @@
#include <stratosphere/sf.hpp> #include <stratosphere/sf.hpp>
#define AMS_LDR_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ #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, 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, 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, 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, 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, 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)) AMS_SF_METHOD_INFO(C, H, 65001, void, AtmosphereUnregisterExternalCode, (ncm::ProgramId program_id), (program_id))

View file

@ -55,4 +55,4 @@
/* Declare singleton instance variables. */ \ /* Declare singleton instance variables. */ \
static constinit _CLASSNAME_ s_singleton_instance; \ static constinit _CLASSNAME_ s_singleton_instance; \
return s_singleton_instance; \ return s_singleton_instance; \
} }

View 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();
}
}

View 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);
};
}

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -16,7 +16,7 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ldr_capabilities.hpp" #include "ldr_capabilities.hpp"
namespace ams::ldr::caps { namespace ams::ldr {
namespace { namespace {
@ -319,19 +319,14 @@ namespace ams::ldr::caps {
} }
/* Capabilities API. */ /* Capabilities API. */
Result ValidateCapabilities(const void *acid_kac, size_t acid_kac_size, const void *aci_kac, size_t aci_kac_size) { Result TestCapability(const util::BitPack32 *kacd, size_t kacd_count, const util::BitPack32 *kac, size_t kac_count) {
const util::BitPack32 *acid_caps = reinterpret_cast<const util::BitPack32 *>(acid_kac); for (size_t i = 0; i < kac_count; i++) {
const util::BitPack32 *aci_caps = reinterpret_cast<const util::BitPack32 *>(aci_kac); const auto cap = kac[i];
const size_t num_acid_caps = acid_kac_size / sizeof(*acid_caps); const auto id = GetCapabilityId(cap);
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);
#define VALIDATE_CASE(id) \ #define VALIDATE_CASE(id) \
case CapabilityId::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 break
switch (id) { switch (id) {
VALIDATE_CASE(KernelFlags); VALIDATE_CASE(KernelFlags);
@ -347,8 +342,8 @@ namespace ams::ldr::caps {
{ {
/* Map Range needs extra logic because there it involves two sequential caps. */ /* Map Range needs extra logic because there it involves two sequential caps. */
i++; i++;
R_UNLESS(i < num_aci_caps, ldr::ResultInvalidCapabilityMapRange()); R_UNLESS(i < kac_count, ldr::ResultInvalidCapabilityMapRange());
R_UNLESS(CapabilityMapRange::Decode(cur_cap).IsValid(aci_caps[i], acid_caps, num_acid_caps), ldr::ResultInvalidCapabilityMapRange()); R_UNLESS(CapabilityMapRange::Decode(cap).IsValid(kac[i], kacd, kacd_count), ldr::ResultInvalidCapabilityMapRange());
} }
break; break;
default: default:
@ -361,25 +356,23 @@ namespace ams::ldr::caps {
return ResultSuccess(); return ResultSuccess();
} }
u16 GetProgramInfoFlags(const void *kac, size_t kac_size) { u16 MakeProgramInfoFlag(const util::BitPack32 *kac, size_t count) {
const util::BitPack32 *caps = reinterpret_cast<const util::BitPack32 *>(kac);
const size_t num_caps = kac_size / sizeof(*caps);
u16 flags = 0; u16 flags = 0;
for (size_t i = 0; i < num_caps; i++) { for (size_t i = 0; i < count; ++i) {
const auto cur_cap = caps[i]; const auto cap = kac[i];
switch (GetCapabilityId(cur_cap)) { switch (GetCapabilityId(cap)) {
case CapabilityId::ApplicationType: 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) { if (app_type != ProgramInfoFlag_InvalidType) {
flags |= app_type; flags |= app_type;
} }
} }
break; break;
case CapabilityId::DebugFlags: case CapabilityId::DebugFlags:
if (CapabilityDebugFlags::Decode(cur_cap).GetAllowDebug()) { if (CapabilityDebugFlags::Decode(cap).GetAllowDebug()) {
flags |= ProgramInfoFlag_AllowDebug; flags |= ProgramInfoFlag_AllowDebug;
} }
break; break;
@ -391,18 +384,15 @@ namespace ams::ldr::caps {
return flags; return flags;
} }
void SetProgramInfoFlags(u16 flags, void *kac, size_t kac_size) { void UpdateProgramInfoFlag(u16 flags, util::BitPack32 *kac, size_t count) {
util::BitPack32 *caps = reinterpret_cast<util::BitPack32 *>(kac); for (size_t i = 0; i < count; ++i) {
const size_t num_caps = kac_size / sizeof(*caps); const auto cap = kac[i];
switch (GetCapabilityId(cap)) {
for (size_t i = 0; i < num_caps; i++) {
const auto cur_cap = caps[i];
switch (GetCapabilityId(cur_cap)) {
case CapabilityId::ApplicationType: case CapabilityId::ApplicationType:
caps[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask); kac[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask);
break; break;
case CapabilityId::DebugFlags: 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; break;
default: default:
break; break;
@ -410,19 +400,16 @@ namespace ams::ldr::caps {
} }
} }
void ProcessCapabilities(void *kac, size_t kac_size) { void PreProcessCapability(util::BitPack32 *kac, size_t count) {
util::BitPack32 *caps = reinterpret_cast<util::BitPack32 *>(kac); for (size_t i = 0; i < count; ++i) {
const size_t num_caps = kac_size / sizeof(*caps); const auto cap = kac[i];
switch (GetCapabilityId(cap)) {
for (size_t i = 0; i < num_caps; i++) {
const auto cur_cap = caps[i];
switch (GetCapabilityId(cur_cap)) {
case CapabilityId::MapRegion: case CapabilityId::MapRegion:
{ {
/* MapRegion was added in 8.0.0+, and is only allowed under kernels which have the relevant mappings. */ /* 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. */ /* However, we allow it under all firmwares on mesosphere, to facilitate KTrace usage by hbl. */
if (!svc::IsKTraceEnabled()) { if (!svc::IsKTraceEnabled()) {
caps[i] = EmptyCapability; kac[i] = EmptyCapability;
} }
} }
break; break;

View file

@ -16,13 +16,13 @@
#pragma once #pragma once
#include <stratosphere.hpp> #include <stratosphere.hpp>
namespace ams::ldr::caps { namespace ams::ldr {
/* Capabilities API. */ Result TestCapability(const util::BitPack32 *kacd, size_t kacd_count, const util::BitPack32 *kac, size_t kac_count);
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);
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);
} }

View file

@ -52,10 +52,8 @@ namespace ams::ldr {
AMS_ABORT_UNLESS(m_has_status); AMS_ABORT_UNLESS(m_has_status);
/* Get the content path. */ /* Get the content path. */
char content_path[fs::EntryNameLengthMax + 1] = "/"; char content_path[fs::EntryNameLengthMax + 1];
if (static_cast<ncm::StorageId>(loc.storage_id) != ncm::StorageId::None) { R_TRY(GetProgramPath(content_path, sizeof(content_path), loc));
R_TRY(ResolveContentPath(content_path, loc));
}
/* Mount the atmosphere code file system. */ /* 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())); 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. */ /* 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; lr::Path path;
/* Check that path registration is allowable. */ /* Check that path registration is allowable. */
@ -103,23 +108,35 @@ namespace ams::ldr {
} }
} R_END_TRY_CATCH; } R_END_TRY_CATCH;
std::strncpy(out_path, path.str, fs::EntryNameLengthMax); /* Fix directory separators in path. */
out_path[fs::EntryNameLengthMax - 1] = '\0'; 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(); return ResultSuccess();
} }
Result RedirectContentPath(const char *path, const ncm::ProgramLocation &loc) { Result RedirectProgramPath(const char *path, size_t size, const ncm::ProgramLocation &loc) {
/* Copy in path. */ /* Check for storage id none. */
lr::Path lr_path; if (static_cast<ncm::StorageId>(loc.storage_id) == ncm::StorageId::None) {
std::strncpy(lr_path.str, path, sizeof(lr_path.str)); return ResultSuccess();
lr_path.str[sizeof(lr_path.str) - 1] = '\0'; }
/* Redirect the path. */ /* Open location resolver. */
lr::LocationResolver lr; lr::LocationResolver lr;
R_TRY(lr::OpenLocationResolver(std::addressof(lr), static_cast<ncm::StorageId>(loc.storage_id))); 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); lr.RedirectProgramPath(lr_path, loc.program_id);
return ResultSuccess(); return ResultSuccess();

View file

@ -72,8 +72,8 @@ namespace ams::ldr {
#define ENCODE_CODE_PATH(relative) "code:" relative #define ENCODE_CODE_PATH(relative) "code:" relative
/* Redirection API. */ /* Redirection API. */
Result ResolveContentPath(char *out_path, const ncm::ProgramLocation &loc); Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc);
Result RedirectContentPath(const char *path, const ncm::ProgramLocation &loc); Result RedirectProgramPath(const char *path, size_t size, const ncm::ProgramLocation &loc);
Result RedirectHtmlDocumentPathForHbl(const ncm::ProgramLocation &loc); Result RedirectHtmlDocumentPathForHbl(const ncm::ProgramLocation &loc);
} }

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ldr_arguments.hpp" #include "ldr_argument_store.hpp"
#include "ldr_content_management.hpp" #include "ldr_content_management.hpp"
#include "ldr_development_manager.hpp" #include "ldr_development_manager.hpp"
#include "ldr_process_creation.hpp" #include "ldr_process_creation.hpp"
@ -25,90 +25,93 @@ namespace ams::ldr {
namespace { namespace {
Result GetProgramInfoImpl(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) { constinit ArgumentStore g_argument_store;
/* 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();
}
} }
/* 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; ncm::ProgramLocation loc;
cfg::OverrideStatus override_status; 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]; char path[fs::EntryNameLengthMax];
R_TRY(GetProgramPath(path, sizeof(path), loc));
/* Get location and override status. */ path[sizeof(path) - 1] = '\x00';
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';
}
/* Create the process. */ /* Create the process. */
os::NativeHandle process_handle; return ldr::CreateProcess(out, pin_id, loc, override_status, path, g_argument_store.Get(loc.program_id), flags, resource_limit);
R_TRY(ldr::CreateProcess(std::addressof(process_handle), id, loc, override_status, path, flags, reslimit_h.GetOsHandle())); }
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(); return ResultSuccess();
} }
Result LoaderService::GetProgramInfo(sf::Out<ProgramInfo> out, const ncm::ProgramLocation &loc) { Result LoaderService::PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
return GetProgramInfoImpl(out.GetPointer(), nullptr, loc); *out = {};
} return ldr::PinProgram(out, loc, status);
Result LoaderService::PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc) {
return ldr::PinProgram(out_id.GetPointer(), loc, cfg::OverrideStatus{});
} }
Result LoaderService::UnpinProgram(PinId id) { Result LoaderService::UnpinProgram(PinId id) {
return ldr::UnpinProgram(id); return ldr::UnpinProgram(id);
} }
Result LoaderService::SetProgramArgumentsDeprecated(ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size) { Result LoaderService::SetProgramArgument(ncm::ProgramId program_id, const void *argument, size_t size) {
return args::Set(program_id, args.GetPointer(), std::min(args.GetSize(), size_t(args_size))); return g_argument_store.Set(program_id, argument, size);
}
Result LoaderService::SetProgramArguments(ncm::ProgramId program_id, const sf::InPointerBuffer &args) {
return args::Set(program_id, args.GetPointer(), args.GetSize());
} }
Result LoaderService::FlushArguments() { 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) { Result LoaderService::GetProcessModuleInfo(u32 *out_count, ModuleInfo *out, size_t max_out_count, os::ProcessId process_id) {
*count = 0; *out_count = 0;
std::memset(out.GetPointer(), 0, out.GetSize() * sizeof(ldr::ModuleInfo)); std::memset(out, 0, max_out_count * sizeof(*out));
return ldr::GetProcessModuleInfo(count.GetPointer(), out.GetPointer(), out.GetSize(), process_id); 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) { Result LoaderService::SetEnabledProgramVerification(bool enabled) {
@ -116,29 +119,4 @@ namespace ams::ldr {
return ResultSuccess(); 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);
}
} }

View file

@ -21,22 +21,74 @@ namespace ams::ldr {
class LoaderService { class LoaderService {
public: public:
/* Official commands. */ /* Official commands. */
Result CreateProcess(sf::OutMoveHandle proc_h, PinId id, u32 flags, sf::CopyHandle &&reslimit_h); 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); os::NativeHandle handle = os::InvalidNativeHandle;
Result PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc); 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 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 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); Result SetEnabledProgramVerification(bool enabled);
/* Atmosphere commands. */ /* Atmosphere commands. */
Result AtmosphereRegisterExternalCode(sf::OutMoveHandle out, ncm::ProgramId program_id); Result AtmosphereRegisterExternalCode(sf::OutMoveHandle out, ncm::ProgramId program_id) {
void AtmosphereUnregisterExternalCode(ncm::ProgramId program_id); os::NativeHandle handle = os::InvalidNativeHandle;
void AtmosphereHasLaunchedBootProgram(sf::Out<bool> out, ncm::ProgramId program_id); const auto result = this->RegisterExternalCode(std::addressof(handle), program_id);
Result AtmosphereGetProgramInfo(sf::Out<ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status, const ncm::ProgramLocation &loc); out.SetValue(handle, true);
Result AtmospherePinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status); 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::IsIProcessManagerInterface<LoaderService>);
static_assert(ams::ldr::impl::IsIDebugMonitorInterface<LoaderService>); static_assert(ams::ldr::impl::IsIDebugMonitorInterface<LoaderService>);

View file

@ -218,9 +218,9 @@ namespace ams::ldr {
} }
/* Fix flags. */ /* Fix flags. */
const u16 program_info_flags = caps::GetProgramInfoFlags(o_meta->aci_kac, o_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));
caps::SetProgramInfoFlags(program_info_flags, meta->acid_kac, meta->acid->kac_size); UpdateProgramInfoFlag(program_info_flags, static_cast<util::BitPack32 *>(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32));
caps::SetProgramInfoFlags(program_info_flags, meta->aci_kac, meta->aci->kac_size); 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. */ /* 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 HblMainThreadPriorityApplication = 44;
constexpr auto HblMainThreadPriorityApplet = 40; constexpr auto HblMainThreadPriorityApplet = 40;
if (meta->npdm->main_thread_priority == HblMainThreadPriorityApplication) { if (meta->npdm->main_thread_priority == HblMainThreadPriorityApplication) {
@ -262,8 +262,8 @@ namespace ams::ldr {
/* Pre-process the capabilities. */ /* Pre-process the capabilities. */
/* This is used to e.g. avoid passing memory region descriptor to older kernels. */ /* This is used to e.g. avoid passing memory region descriptor to older kernels. */
caps::ProcessCapabilities(meta->acid_kac, meta->acid->kac_size); PreProcessCapability(static_cast<util::BitPack32 *>(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32));
caps::ProcessCapabilities(meta->aci_kac, meta->aci->kac_size); PreProcessCapability(static_cast<util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32));
/* Set output. */ /* Set output. */
g_cached_program_id = loc.program_id; g_cached_program_id = loc.program_id;

View file

@ -132,10 +132,10 @@ namespace ams::ldr {
/* Helpers. */ /* Helpers. */
Result GetProgramInfoFromMeta(ProgramInfo *out, const Meta *meta) { Result GetProgramInfoFromMeta(ProgramInfo *out, const Meta *meta) {
/* Copy basic info. */ /* Copy basic info. */
out->main_thread_priority = meta->npdm->main_thread_priority; out->main_thread_priority = meta->npdm->main_thread_priority;
out->default_cpu_id = meta->npdm->default_cpu_id; out->default_cpu_id = meta->npdm->default_cpu_id;
out->main_thread_stack_size = meta->npdm->main_thread_stack_size; 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. */ /* Copy access controls. */
size_t offset = 0; size_t offset = 0;
@ -156,16 +156,16 @@ namespace ams::ldr {
#undef COPY_ACCESS_CONTROL #undef COPY_ACCESS_CONTROL
/* Copy flags. */ /* 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(); return ResultSuccess();
} }
bool IsApplet(const Meta *meta) { 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) { 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) { 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()); R_UNLESS(meta->aci->program_id <= meta->acid->program_id_max, ldr::ResultInvalidProgramId());
/* Validate the kernel capabilities. */ /* 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 we have data to validate, validate it. */
if (code_verification_data.has_data && meta->check_verification_data) { if (code_verification_data.has_data && meta->check_verification_data) {
@ -335,15 +335,15 @@ namespace ams::ldr {
return ResultSuccess(); 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. */ /* Clear output. */
std::memset(out, 0, sizeof(*out)); std::memset(out, 0, sizeof(*out));
/* Set name, version, program id, resource limit handle. */ /* Set name, version, program id, resource limit handle. */
std::memcpy(out->name, meta->npdm->program_name, sizeof(out->name) - 1); std::memcpy(out->name, meta->npdm->program_name, sizeof(out->name) - 1);
out->version = meta->npdm->version; out->version = meta->npdm->version;
out->program_id = static_cast<u64>(meta->aci->program_id); out->program_id = meta->aci->program_id.value;
out->reslimit = reslimit_h; out->reslimit = resource_limit;
/* Set flags. */ /* Set flags. */
R_TRY(GetCreateProcessFlags(std::addressof(out->flags), meta, 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. */ /* Clear output. */
out->args_address = 0; out->args_address = 0;
out->args_size = 0; out->args_size = 0;
@ -435,6 +435,7 @@ namespace ams::ldr {
std::memset(out->nso_size, 0, sizeof(out->nso_size)); std::memset(out->nso_size, 0, sizeof(out->nso_size));
size_t total_size = 0; size_t total_size = 0;
bool argument_allocated = false;
/* Calculate base offsets. */ /* Calculate base offsets. */
for (size_t i = 0; i < Nso_Count; i++) { 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] = text_end;
out->nso_size[i] = std::max(out->nso_size[i], ro_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] = 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]; 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_address = total_size;
out->args_size = 2 * arg_info->args_size + args::ArgumentSizeMax + 2 * sizeof(u32); out->args_size = util::AlignUp(2 * sizeof(u32) + argument->argument_size * 2 + ArgumentStore::ArgumentBufferSize, os::MemoryPageSize);
out->args_size = (out->args_size + size_t(0xFFFul)) & ~size_t(0xFFFul);
total_size += out->args_size; total_size += out->args_size;
argument_allocated = true;
} }
} }
} }
@ -516,13 +517,13 @@ namespace ams::ldr {
return ResultSuccess(); 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. */ /* Get CreateProcessParameter. */
svc::CreateProcessParameter param; 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. */ /* 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. */ /* Actually create process. */
svc::Handle process_handle; svc::Handle process_handle;
@ -567,7 +568,7 @@ namespace ams::ldr {
return ResultSuccess(); 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. */ /* Map and read data from file. */
{ {
AutoCloseMap map(map_address, process_handle, nso_address, nso_size); 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), 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 + 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 + 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. */ /* Apply embedded patches. */
ApplyEmbeddedPatchesToModule(nso_header->module_id, map_address, nso_size); ApplyEmbeddedPatchesToModule(nso_header->module_id, map_address, nso_size);
@ -598,9 +599,9 @@ namespace ams::ldr {
} }
/* Set permissions. */ /* Set permissions. */
const size_t text_size = (static_cast<size_t>(nso_header->text_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 = (static_cast<size_t>(nso_header->ro_size) + size_t(0xFFFul)) & ~size_t(0xFFFul); const size_t ro_size = util::AlignUp(nso_header->ro_size, os::MemoryPageSize);
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 rw_size = util::AlignUp(nso_header->rw_size + nso_header->bss_size, os::MemoryPageSize);
if (text_size) { if (text_size) {
R_TRY(svc::SetProcessMemoryPermission(process_handle, nso_address + nso_header->text_dst_offset, text_size, svc::MemoryPermission_ReadExecute)); 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(); 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. */ /* Load each NSO. */
for (size_t i = 0; i < Nso_Count; i++) { for (size_t i = 0; i < Nso_Count; i++) {
if (has_nso[i]) { if (has_nso[i]) {
@ -625,12 +626,12 @@ namespace ams::ldr {
uintptr_t map_address; uintptr_t map_address;
R_TRY(SearchFreeRegion(std::addressof(map_address), process_info->nso_size[i])); 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. */ /* Load arguments, if present. */
if (arg_info != nullptr) { if (argument != nullptr) {
/* Write argument data into memory. */ /* Write argument data into memory. */
{ {
uintptr_t map_address; uintptr_t map_address;
@ -642,8 +643,8 @@ namespace ams::ldr {
ProgramArguments *args = reinterpret_cast<ProgramArguments *>(map_address); ProgramArguments *args = reinterpret_cast<ProgramArguments *>(map_address);
std::memset(args, 0, sizeof(*args)); std::memset(args, 0, sizeof(*args));
args->allocated_size = process_info->args_size; args->allocated_size = process_info->args_size;
args->arguments_size = arg_info->args_size; args->arguments_size = argument->argument_size;
std::memcpy(args->arguments, arg_info->args, arg_info->args_size); std::memcpy(args->arguments, argument->argument, argument->argument_size);
} }
/* Set argument region permissions. */ /* Set argument region permissions. */
@ -656,87 +657,81 @@ namespace ams::ldr {
} }
/* Process Creation API. */ /* 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 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) {
/* Use global storage for NSOs. */ /* Mount code. */
NsoHeader *nso_headers = g_nso_headers; AMS_UNUSED(path);
bool *has_nso = g_has_nso; ScopedCodeMount mount(loc, override_status);
const auto arg_info = args::Get(loc.program_id); 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. */ /* Ensure we close the process handle, if we fail. */
AMS_UNUSED(path); auto process_guard = SCOPE_GUARD { os::CloseNativeHandle(info.process_handle); };
ScopedCodeMount mount(loc, override_status);
R_TRY(mount.GetResult());
/* Load meta, possibly from cache. */ /* Load all NSOs. */
Meta meta; R_TRY(LoadAutoLoadModules(std::addressof(info), g_nso_headers, g_has_nso, argument));
R_TRY(LoadMetaFromCache(std::addressof(meta), loc, override_status));
/* Validate meta. */ /* We don't need to close the process handle, since we succeeded. */
R_TRY(ValidateMeta(std::addressof(meta), loc, mount.GetCodeVerificationData())); process_guard.Cancel();
}
/* Load, validate NSOs. */ /* Register NSOs with the RoManager. */
R_TRY(LoadNsoHeaders(nso_headers, has_nso)); {
R_TRY(ValidateNsoHeaders(nso_headers, has_nso)); /* Nintendo doesn't validate this get, but we do. */
os::ProcessId process_id = os::GetProcessId(info.process_handle);
/* Actually create process. */ /* Register new process. */
ProcessInfo info; const auto as_type = GetAddressSpaceType(std::addressof(meta));
R_TRY(CreateProcessImpl(std::addressof(info), std::addressof(meta), nso_headers, has_nso, arg_info, flags, reslimit_h)); 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. */ /* Register all NSOs. */
{ for (size_t i = 0; i < Nso_Count; i++) {
/* Ensure we close the process handle, if we fail. */ if (g_has_nso[i]) {
auto process_guard = SCOPE_GUARD { os::CloseNativeHandle(info.process_handle); }; RoManager::GetInstance().AddNso(pin_id, g_nso_headers[i].module_id, info.nso_address[i], info.nso_size[i]);
/* 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]);
}
} }
} }
/* 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(); 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; Meta meta;
/* Load Meta. */ /* Load Meta. */
{ {
AMS_UNUSED(path);
ScopedCodeMount mount(loc); ScopedCodeMount mount(loc);
R_TRY(mount.GetResult()); R_TRY(mount.GetResult());
R_TRY(LoadMeta(std::addressof(meta), loc, mount.GetOverrideStatus())); R_TRY(LoadMeta(std::addressof(meta), loc, mount.GetOverrideStatus()));

View file

@ -14,13 +14,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "ldr_arguments.hpp" #include "ldr_argument_store.hpp"
namespace ams::ldr { namespace ams::ldr {
/* Process Creation API. */ /* 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 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); 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 PinProgram(PinId *out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status);
Result UnpinProgram(PinId id); Result UnpinProgram(PinId id);