diff --git a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp index 5cc2fbb8b..475c87b57 100644 --- a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp @@ -94,12 +94,13 @@ namespace ams::ldr { }; enum Flag : u32 { - Flag_CompressedText = (1 << 0), - Flag_CompressedRo = (1 << 1), - Flag_CompressedRw = (1 << 2), - Flag_CheckHashText = (1 << 3), - Flag_CheckHashRo = (1 << 4), - Flag_CheckHashRw = (1 << 5), + Flag_CompressedText = (1 << 0), + Flag_CompressedRo = (1 << 1), + Flag_CompressedRw = (1 << 2), + Flag_CheckHashText = (1 << 3), + Flag_CheckHashRo = (1 << 4), + Flag_CheckHashRw = (1 << 5), + Flag_PreventCodeReads = (1 << 6), }; struct SegmentInfo { @@ -180,6 +181,8 @@ namespace ams::ldr { AcidFlag_PoolPartitionShift = 2, AcidFlag_PoolPartitionMask = (0xF << AcidFlag_PoolPartitionShift), + + AcidFlag_LoadBrowserCoreDll = (1 << 7), }; enum PoolPartition { diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp index b8e7bcd41..f6cfc77a0 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp @@ -102,6 +102,8 @@ namespace ams::ncm { static const SystemProgramId End; + static const SystemProgramId BrowserCoreDll; + static const SystemProgramId Manu; static const SystemProgramId Htc; static const SystemProgramId DmntGen2; @@ -212,10 +214,12 @@ namespace ams::ncm { inline constexpr const SystemProgramId SystemProgramId::End = { 0x01000000000007FFul }; - inline constexpr const SystemProgramId SystemProgramId::Manu = { 0x010000000000B14Aul }; - inline constexpr const SystemProgramId SystemProgramId::Htc = { 0x010000000000B240ul }; - inline constexpr const SystemProgramId SystemProgramId::DmntGen2 = { 0x010000000000D609ul }; - inline constexpr const SystemProgramId SystemProgramId::DevServer = { 0x010000000000D623ul }; + inline constexpr const SystemProgramId SystemProgramId::BrowserCoreDll = { 0x010000000000085Dul }; + + inline constexpr const SystemProgramId SystemProgramId::Manu = { 0x010000000000B14Aul }; + inline constexpr const SystemProgramId SystemProgramId::Htc = { 0x010000000000B240ul }; + inline constexpr const SystemProgramId SystemProgramId::DmntGen2 = { 0x010000000000D609ul }; + inline constexpr const SystemProgramId SystemProgramId::DevServer = { 0x010000000000D623ul }; inline constexpr bool IsSystemProgramId(const ProgramId &program_id) { return (SystemProgramId::Start <= program_id && program_id <= SystemProgramId::End) || IsAtmosphereProgramId(program_id); diff --git a/stratosphere/loader/source/ldr_content_management.cpp b/stratosphere/loader/source/ldr_content_management.cpp index f1d0dfa14..ce295471c 100644 --- a/stratosphere/loader/source/ldr_content_management.cpp +++ b/stratosphere/loader/source/ldr_content_management.cpp @@ -18,31 +18,25 @@ namespace ams::ldr { - namespace { - - constinit os::SdkMutex g_scoped_code_mount_lock; - - } - /* ScopedCodeMount functionality. */ - ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs) : m_lk(g_scoped_code_mount_lock), m_has_status(false), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) { + ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs, os::SdkMutex &mutex, const char *ams, const char *sd_b, const char *b) : m_lk(mutex), m_ams_path(ams), m_sd_or_base_path(sd_b), m_base_path(b), m_has_status(false), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) { m_result = this->Initialize(loc, attrs); } - ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o, const ldr::ProgramAttributes &attrs) : m_lk(g_scoped_code_mount_lock), m_override_status(o), m_has_status(true), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) { + ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o, const ldr::ProgramAttributes &attrs, os::SdkMutex &mutex, const char *ams, const char *sd_b, const char *b) : m_lk(mutex), m_ams_path(ams), m_sd_or_base_path(sd_b), m_base_path(b), m_override_status(o), m_has_status(true), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) { m_result = this->Initialize(loc, attrs); } ScopedCodeMount::~ScopedCodeMount() { /* Unmount filesystems. */ if (m_mounted_ams) { - fs::Unmount(AtmosphereCodeMountName); + fs::Unmount(m_ams_path); } if (m_mounted_sd_or_code) { - fs::Unmount(SdOrCodeMountName); + fs::Unmount(m_sd_or_base_path); } if (m_mounted_code) { - fs::Unmount(CodeMountName); + fs::Unmount(m_base_path); } } @@ -59,15 +53,15 @@ namespace ams::ldr { const auto content_attributes = attrs.content_attributes; /* Mount the atmosphere code file system. */ - R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(m_ams_code_verification_data), AtmosphereCodeMountName, content_path, content_attributes, loc.program_id, static_cast(loc.storage_id), m_override_status.IsHbl(), m_override_status.IsProgramSpecific())); + R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(m_ams_code_verification_data), m_ams_path, content_path, content_attributes, loc.program_id, static_cast(loc.storage_id), m_override_status.IsHbl(), m_override_status.IsProgramSpecific())); m_mounted_ams = true; /* Mount the sd or base code file system. */ - R_TRY(fs::MountCodeForAtmosphere(std::addressof(m_sd_or_base_code_verification_data), SdOrCodeMountName, content_path, content_attributes, loc.program_id, static_cast(loc.storage_id))); + R_TRY(fs::MountCodeForAtmosphere(std::addressof(m_sd_or_base_code_verification_data), m_sd_or_base_path, content_path, content_attributes, loc.program_id, static_cast(loc.storage_id))); m_mounted_sd_or_code = true; /* Mount the base code file system. */ - if (R_SUCCEEDED(fs::MountCode(std::addressof(m_base_code_verification_data), CodeMountName, content_path, content_attributes, loc.program_id, static_cast(loc.storage_id)))) { + if (R_SUCCEEDED(fs::MountCode(std::addressof(m_base_code_verification_data), m_base_path, content_path, content_attributes, loc.program_id, static_cast(loc.storage_id)))) { m_mounted_code = true; } diff --git a/stratosphere/loader/source/ldr_content_management.hpp b/stratosphere/loader/source/ldr_content_management.hpp index d20c80709..2db0f8204 100644 --- a/stratosphere/loader/source/ldr_content_management.hpp +++ b/stratosphere/loader/source/ldr_content_management.hpp @@ -24,6 +24,9 @@ namespace ams::ldr { NON_MOVEABLE(ScopedCodeMount); private: std::scoped_lock m_lk; + const char *m_ams_path; + const char *m_sd_or_base_path; + const char *m_base_path; cfg::OverrideStatus m_override_status; fs::CodeVerificationData m_ams_code_verification_data; fs::CodeVerificationData m_sd_or_base_code_verification_data; @@ -34,8 +37,8 @@ namespace ams::ldr { bool m_mounted_sd_or_code; bool m_mounted_code; public: - ScopedCodeMount(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs); - ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const ldr::ProgramAttributes &attrs); + ScopedCodeMount(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs, os::SdkMutex &mutex, const char *ams, const char *sd_b, const char *b); + ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const ldr::ProgramAttributes &attrs, os::SdkMutex &mutex, const char *ams, const char *sd_b, const char *b); ~ScopedCodeMount(); Result GetResult() const { @@ -63,17 +66,64 @@ namespace ams::ldr { void EnsureOverrideStatus(const ncm::ProgramLocation &loc); }; - constexpr inline const char * const AtmosphereCodeMountName = "ams-code"; - constexpr inline const char * const AtmosphereCompatMountName = "ams-cmpt"; - constexpr inline const char * const SdOrCodeMountName = "sd-code"; - constexpr inline const char * const CodeMountName = "code"; - constexpr inline const char * const CompatMountName = "cmpt"; + constexpr inline const char * const AtmosphereCodeMountName = "ams-code"; + constexpr inline const char * const AtmosphereCompatMountName = "ams-cmpt"; + constexpr inline const char * const AtmosphereBrowserCoreDllMountName = "ams-bdll"; + constexpr inline const char * const SdOrCodeMountName = "sd-code"; + constexpr inline const char * const SdOrCompatMountName = "sd-code"; + constexpr inline const char * const SdOrBrowserCoreDllMountName = "sd-bdll"; + constexpr inline const char * const CodeMountName = "code"; + constexpr inline const char * const CompatMountName = "cmpt"; + constexpr inline const char * const BrowserCoreDllMountName = "bdll"; #define ENCODE_ATMOSPHERE_CODE_PATH(relative) "ams-code:" relative #define ENCODE_ATMOSPHERE_CMPT_PATH(relative) "ams-cmpt:" relative + #define ENCODE_ATMOSPHERE_BDLL_PATH(relative) "ams-bdll:" relative #define ENCODE_SD_OR_CODE_PATH(relative) "sd-code:" relative + #define ENCODE_SD_OR_CMPT_PATH(relative) "sd-cmpt:" relative + #define ENCODE_SD_OR_BDLL_PATH(relative) "sd-bdll:" relative #define ENCODE_CODE_PATH(relative) "code:" relative #define ENCODE_CMPT_PATH(relative) "cmpt:" relative + #define ENCODE_BDLL_PATH(relative) "bdll:" relative + + class ScopedCodeMountForCode : public ScopedCodeMount { + private: + static constinit inline os::SdkMutex s_mutex; + public: + ScopedCodeMountForCode(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs) : ScopedCodeMount(loc, attrs, s_mutex, AtmosphereCodeMountName, SdOrCodeMountName, CodeMountName) { + /* ... */ + } + + ScopedCodeMountForCode(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const ldr::ProgramAttributes &attrs) : ScopedCodeMount(loc, override_status, attrs, s_mutex, AtmosphereCodeMountName, SdOrCodeMountName, CodeMountName) { + /* ... */ + } + }; + + class ScopedCodeMountForCompat : public ScopedCodeMount { + private: + static constinit inline os::SdkMutex s_mutex; + public: + ScopedCodeMountForCompat(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs) : ScopedCodeMount(loc, attrs, s_mutex, AtmosphereCompatMountName, SdOrCompatMountName, CompatMountName) { + /* ... */ + } + + ScopedCodeMountForCompat(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const ldr::ProgramAttributes &attrs) : ScopedCodeMount(loc, override_status, attrs, s_mutex, AtmosphereCompatMountName, SdOrCompatMountName, CompatMountName) { + /* ... */ + } + }; + + class ScopedCodeMountForBrowserCoreDll : public ScopedCodeMount { + private: + static constinit inline os::SdkMutex s_mutex; + public: + ScopedCodeMountForBrowserCoreDll(const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs) : ScopedCodeMount(loc, attrs, s_mutex, AtmosphereBrowserCoreDllMountName, SdOrBrowserCoreDllMountName, BrowserCoreDllMountName) { + /* ... */ + } + + ScopedCodeMountForBrowserCoreDll(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const ldr::ProgramAttributes &attrs) : ScopedCodeMount(loc, override_status, attrs, s_mutex, AtmosphereBrowserCoreDllMountName, SdOrBrowserCoreDllMountName, BrowserCoreDllMountName) { + /* ... */ + } + }; /* Redirection API. */ Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs); diff --git a/stratosphere/loader/source/ldr_meta.cpp b/stratosphere/loader/source/ldr_meta.cpp index 04e71d38b..d6b6d7852 100644 --- a/stratosphere/loader/source/ldr_meta.cpp +++ b/stratosphere/loader/source/ldr_meta.cpp @@ -25,9 +25,13 @@ namespace ams::ldr { /* Convenience definitions. */ constexpr size_t MetaCacheBufferSize = 0x8000; - constexpr inline const char AtmosphereMetaPath[] = ENCODE_ATMOSPHERE_CODE_PATH("/main.npdm"); - constexpr inline const char SdOrBaseMetaPath[] = ENCODE_SD_OR_CODE_PATH("/main.npdm"); - constexpr inline const char BaseMetaPath[] = ENCODE_CODE_PATH("/main.npdm"); + constexpr inline const char AtmosphereCodeMetaPath[] = ENCODE_ATMOSPHERE_CODE_PATH("/main.npdm"); + constexpr inline const char SdOrBaseCodeMetaPath[] = ENCODE_SD_OR_CODE_PATH("/main.npdm"); + constexpr inline const char BaseCodeMetaPath[] = ENCODE_CODE_PATH("/main.npdm"); + + constexpr inline const char AtmosphereBrowserCoreDllMetaPath[] = ENCODE_ATMOSPHERE_BDLL_PATH("/main.npdm"); + constexpr inline const char SdOrBaseBrowserCoreDllMetaPath[] = ENCODE_SD_OR_BDLL_PATH("/main.npdm"); + constexpr inline const char BaseBrowserCoreDllMetaPath[] = ENCODE_BDLL_PATH("/main.npdm"); /* Types. */ struct MetaCache { @@ -35,11 +39,40 @@ namespace ams::ldr { u8 buffer[MetaCacheBufferSize]; }; + struct MetaLoader { + ncm::ProgramId m_cached_program_id; + cfg::OverrideStatus m_cached_override_status; + MetaCache m_meta_cache; + MetaCache m_original_meta_cache; + + Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused, const char *ams_path, const char *sd_or_base_path, const char *base_path); + Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, const char *ams_path, const char *sd_or_base_path, const char *base_path); + void InvalidateMetaCache(); + }; + + struct MetaLoaderForCode : public MetaLoader { + Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused) { + R_RETURN(MetaLoader::LoadMeta(out_meta, loc, status, platform, unk_unused, AtmosphereCodeMetaPath, SdOrBaseCodeMetaPath, BaseCodeMetaPath)); + } + + Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform) { + R_RETURN(MetaLoader::LoadMetaFromCache(out_meta, loc, status, platform, AtmosphereCodeMetaPath, SdOrBaseCodeMetaPath, BaseCodeMetaPath)); + } + }; + + struct MetaLoaderForBdll : public MetaLoader { + Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused) { + R_RETURN(MetaLoader::LoadMeta(out_meta, loc, status, platform, unk_unused, AtmosphereBrowserCoreDllMetaPath, SdOrBaseBrowserCoreDllMetaPath, BaseBrowserCoreDllMetaPath)); + } + + Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform) { + R_RETURN(MetaLoader::LoadMetaFromCache(out_meta, loc, status, platform, AtmosphereBrowserCoreDllMetaPath, SdOrBaseBrowserCoreDllMetaPath, BaseBrowserCoreDllMetaPath)); + } + }; + /* Global storage. */ - ncm::ProgramId g_cached_program_id; - cfg::OverrideStatus g_cached_override_status; - MetaCache g_meta_cache; - MetaCache g_original_meta_cache; + MetaLoaderForCode g_meta_loader_for_code; + MetaLoaderForBdll g_meta_loader_for_bdll; /* Helpers. */ Result ValidateSubregion(size_t allowed_start, size_t allowed_end, size_t start, size_t size, size_t min_size = 0) { @@ -187,112 +220,136 @@ namespace ams::ldr { R_SUCCEED(); } + Result MetaLoader::LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused, const char *ams_path, const char *sd_or_base_path, const char *base_path) { + /* Set the cached program id back to zero. */ + m_cached_program_id = {}; + + /* Try to load meta from file. */ + fs::FileHandle file; + R_TRY(fs::OpenFile(std::addressof(file), ams_path, fs::OpenMode_Read)); + { + ON_SCOPE_EXIT { fs::CloseFile(file); }; + R_TRY(LoadMetaFromFile(file, std::addressof(m_meta_cache))); + } + + /* Patch meta. Start by setting all program ids to the current program id. */ + Meta *meta = std::addressof(m_meta_cache.meta); + meta->acid->program_id_min = loc.program_id; + meta->acid->program_id_max = loc.program_id; + meta->aci->program_id = loc.program_id; + + /* For HBL, we need to copy some information from the base meta. */ + if (status.IsHbl()) { + if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), sd_or_base_path, fs::OpenMode_Read))) { + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + + if (R_SUCCEEDED(LoadMetaFromFile(file, std::addressof(m_original_meta_cache)))) { + Meta *o_meta = std::addressof(m_original_meta_cache.meta); + + /* Fix pool partition. */ + if (hos::GetVersion() >= hos::Version_5_0_0) { + meta->acid->flags = (meta->acid->flags & 0xFFFFFFC3) | (o_meta->acid->flags & 0x0000003C); + } + + /* Fix flags. */ + const u16 program_info_flags = MakeProgramInfoFlag(static_cast(o_meta->aci_kac), o_meta->aci->kac_size / sizeof(util::BitPack32)); + UpdateProgramInfoFlag(program_info_flags, static_cast(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32)); + UpdateProgramInfoFlag(program_info_flags, static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)); + } + } + + /* Perform address space override. */ + if (status.HasOverrideAddressSpace()) { + /* Clear the existing address space. */ + meta->npdm->flags &= ~Npdm::MetaFlag_AddressSpaceTypeMask; + + /* Set the new address space flag. */ + switch (status.GetOverrideAddressSpaceFlags()) { + case cfg::impl::OverrideStatusFlag_AddressSpace32Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_32Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break; + case cfg::impl::OverrideStatusFlag_AddressSpace64BitDeprecated: meta->npdm->flags |= (Npdm::AddressSpaceType_64BitDeprecated) << Npdm::MetaFlag_AddressSpaceTypeShift; break; + case cfg::impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias: meta->npdm->flags |= (Npdm::AddressSpaceType_32BitWithoutAlias) << Npdm::MetaFlag_AddressSpaceTypeShift; break; + case cfg::impl::OverrideStatusFlag_AddressSpace64Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + /* When hbl is applet, adjust main thread priority. */ + if ((MakeProgramInfoFlag(static_cast(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) { + meta->npdm->main_thread_priority = HblMainThreadPriorityApplet; + } + } + + /* Fix the debug capabilities, to prevent needing a hbl recompilation. */ + FixDebugCapabilityForHbl(static_cast(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32)); + FixDebugCapabilityForHbl(static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)); + } else if (hos::GetVersion() >= hos::Version_10_0_0) { + /* If storage id is none, there is no base code filesystem, and thus it is impossible for us to validate. */ + /* However, if we're an application, we are guaranteed a base code filesystem. */ + if (static_cast(loc.storage_id) != ncm::StorageId::None || ncm::IsApplicationId(loc.program_id)) { + R_TRY(fs::OpenFile(std::addressof(file), base_path, fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + R_TRY(LoadMetaFromFile(file, std::addressof(m_original_meta_cache))); + R_TRY(ValidateAcidSignature(std::addressof(m_original_meta_cache.meta), platform, unk_unused)); + meta->modulus = m_original_meta_cache.meta.modulus; + meta->check_verification_data = m_original_meta_cache.meta.check_verification_data; + } + } + + /* Pre-process the capabilities. */ + /* This is used to e.g. avoid passing memory region descriptor to older kernels. */ + PreProcessCapability(static_cast(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32)); + PreProcessCapability(static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)); + + /* Set output. */ + m_cached_program_id = loc.program_id; + m_cached_override_status = status; + *out_meta = *meta; + + R_SUCCEED(); + } + + Result MetaLoader::LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, const char *ams_path, const char *sd_or_base_path, const char *base_path) { + if (m_cached_program_id != loc.program_id || m_cached_override_status != status) { + R_RETURN(this->LoadMeta(out_meta, loc, status, platform, false, ams_path, sd_or_base_path, base_path)); + } + *out_meta = m_meta_cache.meta; + R_SUCCEED(); + } + + void MetaLoader::InvalidateMetaCache() { + /* Set the cached program id back to zero. */ + m_cached_program_id = {}; + } + } /* API. */ Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused) { - /* Set the cached program id back to zero. */ - g_cached_program_id = {}; - - /* Try to load meta from file. */ - fs::FileHandle file; - R_TRY(fs::OpenFile(std::addressof(file), AtmosphereMetaPath, fs::OpenMode_Read)); - { - ON_SCOPE_EXIT { fs::CloseFile(file); }; - R_TRY(LoadMetaFromFile(file, std::addressof(g_meta_cache))); - } - - /* Patch meta. Start by setting all program ids to the current program id. */ - Meta *meta = std::addressof(g_meta_cache.meta); - meta->acid->program_id_min = loc.program_id; - meta->acid->program_id_max = loc.program_id; - meta->aci->program_id = loc.program_id; - - /* For HBL, we need to copy some information from the base meta. */ - if (status.IsHbl()) { - if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), SdOrBaseMetaPath, fs::OpenMode_Read))) { - ON_SCOPE_EXIT { fs::CloseFile(file); }; - - - if (R_SUCCEEDED(LoadMetaFromFile(file, std::addressof(g_original_meta_cache)))) { - Meta *o_meta = std::addressof(g_original_meta_cache.meta); - - /* Fix pool partition. */ - if (hos::GetVersion() >= hos::Version_5_0_0) { - meta->acid->flags = (meta->acid->flags & 0xFFFFFFC3) | (o_meta->acid->flags & 0x0000003C); - } - - /* Fix flags. */ - const u16 program_info_flags = MakeProgramInfoFlag(static_cast(o_meta->aci_kac), o_meta->aci->kac_size / sizeof(util::BitPack32)); - UpdateProgramInfoFlag(program_info_flags, static_cast(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32)); - UpdateProgramInfoFlag(program_info_flags, static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)); - } - } - - /* Perform address space override. */ - if (status.HasOverrideAddressSpace()) { - /* Clear the existing address space. */ - meta->npdm->flags &= ~Npdm::MetaFlag_AddressSpaceTypeMask; - - /* Set the new address space flag. */ - switch (status.GetOverrideAddressSpaceFlags()) { - case cfg::impl::OverrideStatusFlag_AddressSpace32Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_32Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break; - case cfg::impl::OverrideStatusFlag_AddressSpace64BitDeprecated: meta->npdm->flags |= (Npdm::AddressSpaceType_64BitDeprecated) << Npdm::MetaFlag_AddressSpaceTypeShift; break; - case cfg::impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias: meta->npdm->flags |= (Npdm::AddressSpaceType_32BitWithoutAlias) << Npdm::MetaFlag_AddressSpaceTypeShift; break; - case cfg::impl::OverrideStatusFlag_AddressSpace64Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break; - AMS_UNREACHABLE_DEFAULT_CASE(); - } - } - - /* When hbl is applet, adjust main thread priority. */ - if ((MakeProgramInfoFlag(static_cast(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) { - meta->npdm->main_thread_priority = HblMainThreadPriorityApplet; - } - } - - /* Fix the debug capabilities, to prevent needing a hbl recompilation. */ - FixDebugCapabilityForHbl(static_cast(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32)); - FixDebugCapabilityForHbl(static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)); - } else if (hos::GetVersion() >= hos::Version_10_0_0) { - /* If storage id is none, there is no base code filesystem, and thus it is impossible for us to validate. */ - /* However, if we're an application, we are guaranteed a base code filesystem. */ - if (static_cast(loc.storage_id) != ncm::StorageId::None || ncm::IsApplicationId(loc.program_id)) { - R_TRY(fs::OpenFile(std::addressof(file), BaseMetaPath, fs::OpenMode_Read)); - ON_SCOPE_EXIT { fs::CloseFile(file); }; - R_TRY(LoadMetaFromFile(file, std::addressof(g_original_meta_cache))); - R_TRY(ValidateAcidSignature(std::addressof(g_original_meta_cache.meta), platform, unk_unused)); - meta->modulus = g_original_meta_cache.meta.modulus; - meta->check_verification_data = g_original_meta_cache.meta.check_verification_data; - } - } - - /* Pre-process the capabilities. */ - /* This is used to e.g. avoid passing memory region descriptor to older kernels. */ - PreProcessCapability(static_cast(meta->acid_kac), meta->acid->kac_size / sizeof(util::BitPack32)); - PreProcessCapability(static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)); - - /* Set output. */ - g_cached_program_id = loc.program_id; - g_cached_override_status = status; - *out_meta = *meta; - - R_SUCCEED(); + R_RETURN(g_meta_loader_for_code.LoadMeta(out_meta, loc, status, platform, unk_unused)); } Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform) { - if (g_cached_program_id != loc.program_id || g_cached_override_status != status) { - R_RETURN(LoadMeta(out_meta, loc, status, platform, false)); - } - *out_meta = g_meta_cache.meta; - R_SUCCEED(); + R_RETURN(g_meta_loader_for_code.LoadMetaFromCache(out_meta, loc, status, platform)); } void InvalidateMetaCache() { - /* Set the cached program id back to zero. */ - g_cached_program_id = {}; + g_meta_loader_for_code.InvalidateMetaCache(); + } + + Result LoadMetaForBrowserCoreDll(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused) { + R_RETURN(g_meta_loader_for_bdll.LoadMeta(out_meta, loc, status, platform, unk_unused)); + } + + Result LoadMetaFromCacheForBrowserCoreDll(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform) { + R_RETURN(g_meta_loader_for_bdll.LoadMetaFromCache(out_meta, loc, status, platform)); + } + + void InvalidateMetaCacheForBrowserCoreDll() { + g_meta_loader_for_bdll.InvalidateMetaCache(); } } diff --git a/stratosphere/loader/source/ldr_meta.hpp b/stratosphere/loader/source/ldr_meta.hpp index 4d3ce3fb8..cf5864d4c 100644 --- a/stratosphere/loader/source/ldr_meta.hpp +++ b/stratosphere/loader/source/ldr_meta.hpp @@ -40,4 +40,8 @@ namespace ams::ldr { Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform); void InvalidateMetaCache(); + Result LoadMetaForBrowserCoreDll(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused); + Result LoadMetaFromCacheForBrowserCoreDll(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform); + void InvalidateMetaCacheForBrowserCoreDll(); + } diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 5f6f2226b..a67e535db 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -29,21 +29,22 @@ namespace ams::ldr { /* Convenience defines. */ constexpr size_t SystemResourceSizeMax = 0x1FE00000; + constexpr size_t AutoLoadModuleSizeMax = 0x800000000; /* Types. */ enum NsoIndex { Nso_Rtld = 0, Nso_Main = 1, - Nso_Compat0 = 2, - Nso_Compat1 = 3, - Nso_Compat2 = 4, - Nso_Compat3 = 5, - Nso_Compat4 = 6, - Nso_Compat5 = 7, - Nso_Compat6 = 8, - Nso_Compat7 = 9, - Nso_Compat8 = 10, - Nso_Compat9 = 11, + Nso_Wkc0 = 2, + Nso_Wkc1 = 3, + Nso_Wkc2 = 4, + Nso_Wkc3 = 5, + Nso_Wkc4 = 6, + Nso_Wkc5 = 7, + Nso_Wkc6 = 8, + Nso_Wkc7 = 9, + Nso_Wkc8 = 10, + Nso_Wkc9 = 11, Nso_SubSdk0 = 12, Nso_SubSdk1 = 13, Nso_SubSdk2 = 14, @@ -61,16 +62,16 @@ namespace ams::ldr { constexpr inline const char *NsoPaths[Nso_Count] = { ENCODE_ATMOSPHERE_CODE_PATH("/rtld"), ENCODE_ATMOSPHERE_CODE_PATH("/main"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat0"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat1"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat2"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat3"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat4"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat5"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat6"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat7"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat8"), - ENCODE_ATMOSPHERE_CMPT_PATH("/compat9"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc0"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc1"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc2"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc3"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc4"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc5"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc6"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc7"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc8"), + ENCODE_ATMOSPHERE_BDLL_PATH("/wkc9"), ENCODE_ATMOSPHERE_CODE_PATH("/subsdk0"), ENCODE_ATMOSPHERE_CODE_PATH("/subsdk1"), ENCODE_ATMOSPHERE_CODE_PATH("/subsdk2"), @@ -97,8 +98,15 @@ namespace ams::ldr { size_t nso_size[Nso_Count]; }; + struct AutoLoadModuleInfo { + bool has_rtld; + bool has_main; + bool has_sdk; + bool has_subsdk; + bool has_nso[Nso_Count]; + }; + /* Global NSO header cache. */ - bool g_has_nso[Nso_Count]; NsoHeader g_nso_headers[Nso_Count]; Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) { @@ -161,12 +169,30 @@ namespace ams::ldr { return static_cast((meta->acid->flags & Acid::AcidFlag_PoolPartitionMask) >> Acid::AcidFlag_PoolPartitionShift); } - Result LoadAutoLoadHeaders(NsoHeader *nso_headers, bool *has_nso) { + Result LoadAutoLoadHeaders(NsoHeader *nso_headers, AutoLoadModuleInfo *ali, u32 acid_flags) { /* Clear NSOs. */ std::memset(nso_headers, 0, sizeof(*nso_headers) * Nso_Count); - std::memset(has_nso, 0, sizeof(*has_nso) * Nso_Count); + *ali = {}; for (size_t i = 0; i < Nso_Count; i++) { + /* Only load browser DLLs if acid flags say to do so. */ + switch (i) { + case Nso_Wkc0: + case Nso_Wkc1: + case Nso_Wkc2: + case Nso_Wkc3: + case Nso_Wkc4: + case Nso_Wkc5: + case Nso_Wkc6: + case Nso_Wkc7: + case Nso_Wkc8: + case Nso_Wkc9: + if ((acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) == 0) { + continue; + } + break; + } + fs::FileHandle file; if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), GetNsoPath(i), fs::OpenMode_Read))) { ON_SCOPE_EXIT { fs::CloseFile(file); }; @@ -176,27 +202,82 @@ namespace ams::ldr { R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, nso_headers + i, sizeof(*nso_headers))); R_UNLESS(read_size == sizeof(*nso_headers), ldr::ResultInvalidNso()); - has_nso[i] = true; + /* Note nso is present. */ + switch (i) { + case Nso_Rtld: + ali->has_rtld = true; + break; + case Nso_Main: + ali->has_main = true; + break; + case Nso_SubSdk0: + case Nso_SubSdk1: + case Nso_SubSdk2: + case Nso_SubSdk3: + case Nso_SubSdk4: + case Nso_SubSdk5: + case Nso_SubSdk6: + case Nso_SubSdk7: + case Nso_SubSdk8: + case Nso_SubSdk9: + ali->has_subsdk = true; + break; + case Nso_Sdk: + ali->has_sdk = true; + break; + } + ali->has_nso[i] = true; } } R_SUCCEED(); } - Result CheckAutoLoad(const NsoHeader *nso_headers, const bool *has_nso) { + Result CheckAutoLoad(const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, u32 acid_flags) { /* We must always have a main. */ - R_UNLESS(has_nso[Nso_Main], ldr::ResultInvalidNso()); + R_UNLESS(ali->has_main, ldr::ResultInvalidNso()); - /* If we don't have an RTLD, we must only have a main. */ - if (!has_nso[Nso_Rtld]) { - for (size_t i = Nso_Main + 1; i < Nso_Count; i++) { - R_UNLESS(!has_nso[i], ldr::ResultInvalidNso()); - } + /* All NSOs must not be --X. */ + /* This is "probably" not checked on Ounce? */ + for (size_t i = 0; i < Nso_Count; ++i) { + R_UNLESS((nso_headers[i].flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso()); } - /* All NSOs must have zero text offset. */ + /* If we don't have an RTLD, we must only have a main. */ + const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0; + if (ali->has_rtld) { + /* If we have rtld, we must also have sdk. */ + R_UNLESS(ali->has_sdk, ldr::ResultInvalidNso()); + + /* We must also only have one of [subsdk, browser dll]. */ + R_UNLESS(!(ali->has_subsdk && has_browser_dll), ldr::ResultInvalidNso()); + } else { + /* If we don't have rtld, we are not browser, and must not have browser core dll. */ + R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso()); + } + + /* Check NSO extents. */ for (size_t i = 0; i < Nso_Count; i++) { + /* Only validate the nsos we have. */ + if (!ali->has_nso[i]) { + continue; + } + + /* NSOs must have page-aligned segments. */ + R_UNLESS(util::IsAligned(nso_headers[i].text_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso()); + R_UNLESS(util::IsAligned(nso_headers[i].ro_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso()); + R_UNLESS(util::IsAligned(nso_headers[i].rw_dst_offset, os::MemoryPageSize), ldr::ResultInvalidNso()); + + /* NSOs must have zero text offset. */ R_UNLESS(nso_headers[i].text_dst_offset == 0, ldr::ResultInvalidNso()); + + /* NSO .text must precede .rodata. */ + const size_t text_end = static_cast(nso_headers[i].text_dst_offset) + static_cast(nso_headers[i].text_size); + R_UNLESS(text_end <= static_cast(nso_headers[i].ro_dst_offset), ldr::ResultInvalidNso()); + + /* NSO .rodata must precede .rwdata. */ + const size_t ro_end = static_cast(nso_headers[i].ro_dst_offset) + static_cast(nso_headers[i].ro_size); + R_UNLESS(ro_end <= static_cast(nso_headers[i].rw_dst_offset), ldr::ResultInvalidNso()); } R_SUCCEED(); @@ -433,7 +514,7 @@ namespace ams::ldr { return rand % (max + 1); } - Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument) { + Result DecideAddressSpaceLayout(ProcessInfo *out, svc::CreateProcessParameter *out_param, const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, const ArgumentStore::Entry *argument) { /* Clear output. */ out->args_address = 0; out->args_size = 0; @@ -445,22 +526,32 @@ namespace ams::ldr { /* Calculate base offsets. */ for (size_t i = 0; i < Nso_Count; i++) { - if (has_nso[i]) { + if (ali->has_nso[i]) { out->nso_address[i] = total_size; - const size_t text_end = nso_headers[i].text_dst_offset + nso_headers[i].text_size; - const size_t ro_end = nso_headers[i].ro_dst_offset + nso_headers[i].ro_size; - const size_t rw_end = nso_headers[i].rw_dst_offset + nso_headers[i].rw_size + nso_headers[i].bss_size; + const size_t text_end = static_cast(nso_headers[i].text_dst_offset) + static_cast(nso_headers[i].text_size); + const size_t ro_end = static_cast(nso_headers[i].ro_dst_offset) + static_cast(nso_headers[i].ro_size); + const size_t rw_end = static_cast(nso_headers[i].rw_dst_offset) + static_cast(nso_headers[i].rw_size); 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] = util::AlignUp(out->nso_size[i], os::MemoryPageSize); + out->nso_size[i] += static_cast(nso_headers[i].bss_size); + const size_t aligned_up_size = util::AlignUp(out->nso_size[i], os::MemoryPageSize) & (AutoLoadModuleSizeMax - 1); + R_UNLESS(out->nso_size[i] <= aligned_up_size, ldr::ResultInvalidNso()); + R_UNLESS(aligned_up_size > 0, ldr::ResultInvalidNso()); + + out->nso_size[i] = aligned_up_size; + + R_UNLESS(util::CanAddWithoutOverflow(total_size, out->nso_size[i]), ldr::ResultInvalidNso()); total_size += out->nso_size[i]; if (!argument_allocated && argument != nullptr) { out->args_address = total_size; out->args_size = util::AlignUp(2 * sizeof(u32) + argument->argument_size * 2 + ArgumentStore::ArgumentBufferSize, os::MemoryPageSize); + + R_UNLESS(util::CanAddWithoutOverflow(total_size, out->args_size), ldr::ResultInvalidNso()); total_size += out->args_size; + argument_allocated = true; } } @@ -508,11 +599,13 @@ namespace ams::ldr { /* Set out. */ aslr_start += aslr_slide; for (size_t i = 0; i < Nso_Count; i++) { - if (has_nso[i]) { + if (ali->has_nso[i]) { + R_UNLESS(util::CanAddWithoutOverflow(out->nso_address[i], aslr_start), ldr::ResultInvalidNso()); out->nso_address[i] += aslr_start; } } if (out->args_address) { + R_UNLESS(util::CanAddWithoutOverflow(out->args_address, aslr_start), ldr::ResultInvalidNso()); out->args_address += aslr_start; } @@ -555,7 +648,7 @@ namespace ams::ldr { R_SUCCEED(); } - Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size, bool prevent_code_reads) { + Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size) { /* Map and read data from file. */ { /* Map the process memory. */ @@ -574,9 +667,9 @@ namespace ams::ldr { (nso_header->flags & NsoHeader::Flag_CheckHashRw) != 0, map_address + nso_header->rw_dst_offset, map_address + nso_size)); /* Clear unused space to zero. */ - const size_t text_end = nso_header->text_dst_offset + nso_header->text_size; - const size_t ro_end = nso_header->ro_dst_offset + nso_header->ro_size; - const size_t rw_end = nso_header->rw_dst_offset + nso_header->rw_size; + const size_t text_end = static_cast(nso_header->text_dst_offset) + static_cast(nso_header->text_size); + const size_t ro_end = static_cast(nso_header->ro_dst_offset) + static_cast(nso_header->ro_size); + const size_t rw_end = static_cast(nso_header->rw_dst_offset) + static_cast(nso_header->rw_size); std::memset(reinterpret_cast(map_address + 0), 0, nso_header->text_dst_offset); std::memset(reinterpret_cast(map_address + text_end), 0, nso_header->ro_dst_offset - text_end); std::memset(reinterpret_cast(map_address + ro_end), 0, nso_header->rw_dst_offset - ro_end); @@ -594,6 +687,7 @@ namespace ams::ldr { 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) { + const bool prevent_code_reads = (nso_header->flags & NsoHeader::Flag_PreventCodeReads); R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->text_dst_offset, text_size, prevent_code_reads ? os::MemoryPermission_ExecuteOnly : os::MemoryPermission_ReadExecute)); } if (ro_size) { @@ -606,15 +700,15 @@ namespace ams::ldr { R_SUCCEED(); } - Result LoadAutoLoadModules(const ProcessInfo *process_info, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument, bool prevent_code_reads) { + Result LoadAutoLoadModules(const ProcessInfo *process_info, const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, const ArgumentStore::Entry *argument) { /* Load each NSO. */ for (size_t i = 0; i < Nso_Count; i++) { - if (has_nso[i]) { + if (ali->has_nso[i]) { fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(i), fs::OpenMode_Read)); ON_SCOPE_EXIT { fs::CloseFile(file); }; - R_TRY(LoadAutoLoadModule(process_info->process_handle, file, nso_headers + i, process_info->nso_address[i], process_info->nso_size[i], prevent_code_reads)); + R_TRY(LoadAutoLoadModule(process_info->process_handle, file, nso_headers + i, process_info->nso_address[i], process_info->nso_size[i])); } } @@ -641,13 +735,13 @@ namespace ams::ldr { R_SUCCEED(); } - Result CreateProcessAndLoadAutoLoadModules(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const bool *has_nso, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) { + Result CreateProcessAndLoadAutoLoadModules(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const AutoLoadModuleInfo *ali, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) { /* Get CreateProcessParameter. */ svc::CreateProcessParameter param; 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, argument)); + R_TRY(DecideAddressSpaceLayout(out, std::addressof(param), nso_headers, ali, argument)); /* Actually create process. */ svc::Handle process_handle; @@ -658,7 +752,7 @@ namespace ams::ldr { ON_RESULT_FAILURE { svc::CloseHandle(process_handle); }; /* Load all auto load modules. */ - R_RETURN(LoadAutoLoadModules(out, nso_headers, has_nso, argument, (meta->npdm->flags & ldr::Npdm::MetaFlag_PreventCodeReads) != 0)); + R_RETURN(LoadAutoLoadModules(out, nso_headers, ali, argument)); } } @@ -667,7 +761,7 @@ namespace ams::ldr { 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, const ldr::ProgramAttributes &attrs) { /* Mount code. */ AMS_UNUSED(path); - ScopedCodeMount mount(loc, override_status, attrs); + ScopedCodeMountForCode mount(loc, override_status, attrs); R_TRY(mount.GetResult()); /* Load meta, possibly from cache. */ @@ -677,13 +771,35 @@ namespace ams::ldr { /* Validate meta. */ R_TRY(ValidateMeta(std::addressof(meta), loc, mount.GetCodeVerificationData())); + /* If we should, load/validate the browser core dll. */ + util::optional bdll_mount; + if ((meta.acid->flags & Acid::AcidFlag_LoadBrowserCoreDll)) { + /* NOTE: I'm unsure whether we should be getting a fresh override status (allowing for different override between main and bdll?) */ + /* or whether we should be using the main override status. Going to go with main, for sanity's sake. */ + /* Also noting that Nintendo always passes ProgramAttributes=0 here, but this "should" be different on Ounce? */ + /* Kind of unclear how to handle this without knowing what exactly is being ifdef'd. */ + const ncm::ProgramLocation bdll_loc = ncm::ProgramLocation::Make(ncm::SystemProgramId::BrowserCoreDll, ncm::StorageId::BuiltInSystem); + const cfg::OverrideStatus bdll_override_status = override_status; + const ldr::ProgramAttributes bdll_attrs = attrs; + bdll_mount.emplace(bdll_loc, bdll_override_status, bdll_attrs); + R_TRY(bdll_mount->GetResult()); + + /* Load browser dll meta, possibly from cache. */ + Meta bdll_meta; + R_TRY(LoadMetaFromCacheForBrowserCoreDll(std::addressof(bdll_meta), bdll_loc, bdll_override_status, bdll_attrs.platform)); + + /* Validate browser dll meta. */ + R_TRY(ValidateMeta(std::addressof(bdll_meta), loc, mount.GetCodeVerificationData())); + } + /* Load, validate NSO headers. */ - R_TRY(LoadAutoLoadHeaders(g_nso_headers, g_has_nso)); - R_TRY(CheckAutoLoad(g_nso_headers, g_has_nso)); + AutoLoadModuleInfo auto_load_info = {}; + R_TRY(LoadAutoLoadHeaders(g_nso_headers, std::addressof(auto_load_info), meta.acid->flags)); + R_TRY(CheckAutoLoad(g_nso_headers, std::addressof(auto_load_info), meta.acid->flags)); /* Actually create the process and load NSOs into process memory. */ ProcessInfo info; - R_TRY(CreateProcessAndLoadAutoLoadModules(std::addressof(info), std::addressof(meta), g_nso_headers, g_has_nso, argument, flags, resource_limit)); + R_TRY(CreateProcessAndLoadAutoLoadModules(std::addressof(info), std::addressof(meta), g_nso_headers, std::addressof(auto_load_info), argument, flags, resource_limit)); /* Register NSOs with the RoManager. */ { @@ -696,7 +812,7 @@ namespace ams::ldr { /* Register all NSOs. */ for (size_t i = 0; i < Nso_Count; i++) { - if (g_has_nso[i]) { + if (auto_load_info.has_nso[i]) { RoManager::GetInstance().AddNso(pin_id, g_nso_headers[i].module_id, info.nso_address[i], info.nso_size[i]); } } @@ -727,7 +843,7 @@ namespace ams::ldr { { AMS_UNUSED(path); - ScopedCodeMount mount(loc, attrs); + ScopedCodeMountForCode mount(loc, attrs); R_TRY(mount.GetResult()); R_TRY(LoadMeta(std::addressof(meta), loc, mount.GetOverrideStatus(), attrs.platform, false)); if (out_status != nullptr) {