Compare commits

...

6 commits

Author SHA1 Message Date
Deleted user
4c648acb62
Merge cd6d129540 into 548b48b2a6 2024-05-27 19:10:40 -07:00
Michael Scire
548b48b2a6 loader: update to reflect latest 18.0.0 changes
well, this sure is late, whoops
2024-05-27 15:43:58 -07:00
Ammako
cd6d129540
Delete feature_request.md 2021-08-09 20:10:42 +00:00
Ammako
700d811cb7
Create feature_request.yaml 2021-08-09 20:10:35 +00:00
Ammako
37a910802f
Delete bug_report.md 2021-08-09 20:10:19 +00:00
Ammako
0d4377b43b
Create bug_report.yaml 2021-08-09 20:10:13 +00:00
16 changed files with 351 additions and 223 deletions

View file

@ -1,58 +0,0 @@
---
name: Bug Report
about: Something doesn't work correctly in Atmosphère.
#assignees:
---
## Bug Report
[ If any section does not apply, replace its contents with "N/A". ]</br>
[ Lines between [ ] (square brackets) should be removed before posting. ]</br>
[ * ]</br>
[ Note: If the bug or crash you encountered is related to; ]</br>
[ - software used to make "backups", ]</br>
[ - software explicitly distributed for piracy, etc ]</br>
[ then contributors will not provide support for your issue and your issue will be closed. ]</br>
### What's the issue you encountered?
[ Describe the issue in detail and what you were doing beforehand. ]</br>
[ Did you make any changes related to Atmosphère itself? ]</br>
[ If so, make sure to include details relating to what exactly you changed. ]</br>
### How can the issue be reproduced?
[ * ]</br>
[ Include a detailed step by step process for recreating your issue. ]</br>
### Crash Report
[ Crash reports can be found under ``/atmosphere/crash_reports``. ]</br>
[ If your issue caused Atmosphère to crash, include the crash report(s) by creating a [gist](https://gist.github.com/) and pasting the link here. ]</br>
[ If you don't include a crash report in instances of crash related issues, we will ask you one to provide one. ]</br>
### System Firmware Version
X.X.X</br>
[ Replace X's with system firmware version at time of crash. ]</br>
[ You can find your firmware version in the Settings -> System, under "System Update". ]</br>
[ If it says "Update Pending", you can clear the pending update by rebooting to Maintenance Mode. ]</br>
### Environment?
- What bootloader (fusèe, hekate, etc) was Atmosphère launched by:
- Official release or unofficial build:
- [ Official release version x.x.x (or) unofficial build ]
- [ If using an unofficial build, include details on where/how you acquired the build. ]
- [ Ex: Self-compilation ]
- [ Ex: Kosmos' distribution of Atmosphère ]
- Do you have additional kips or sysmodules you're loading:
- Homebrew software installed: [ * ]
- EmuMMC or SysNAND:
- [ If using an EmuMMC, include whether it's partition-based or file-based. ]
### Additional context?
- Additional info about your environment:
- [ Any other information relevant to your issue. ]

67
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View file

@ -0,0 +1,67 @@
name: Bug Report
description: Something doesn't work correctly in Atmosphère.
title: "[BUG] "
body:
- type: markdown
attributes:
value: |
Note: If the bug or crash you encountered is related to
- software used to make "backups"
- software explicitly distributed for piracy, etc.
then contributors will not provide support for your issue and your issue will be closed.
- type: textarea
attributes:
label: What's the issue you encountered?
description: |
Describe the issue in detail and what you were doing beforehand.
Did you make any changes related to Atmosphère itself?
If so, make sure to include details relating to what exactly you changed.
validations:
required: true
- type: textarea
attributes:
label: How can the issue be reproduced?
description: Include a detailed step by step process for recreating your issue.
validations:
required: true
- type: textarea
attributes:
label: Crash Report
description: |
Crash reports can be found under ``/atmosphere/crash_reports``.
- If your issue caused Atmosphère to crash, include the crash report(s) by creating a [gist](https://gist.github.com/) and pasting the link here.
- If you don't include a crash report in instances of crash related issues, we will ask you one to provide one.
validations:
required: false
- type: textarea
attributes:
label: System Firmware Version
description: |
Replace X's with system firmware version at time of crash.
You can find your firmware version in the Settings -> System, under "System Update".
If it says "Update Pending", you can clear the pending update by rebooting to Maintenance Mode.
placeholder: X.X.X
validations:
required: true
- type: textarea
attributes:
label: Environment?
value: |
- What bootloader (fusée, hekate, etc) was Atmosphère launched by:
- Official release or unofficial build:
- If using an unofficial build, include details on where/how you acquired the build:
- Do you have additional kips or sysmodules you're loading:
- Homebrew software installed:
- EmuMMC or SysMMC:
- If using an EmuMMC, include whether it's partition-based or file-based:
validations:
required: true
- type: textarea
attributes:
label: Additional context?
value: |
- Additional info about your environment:
- Any other information relevant to your issue:
validations:
required: false

View file

@ -1,48 +0,0 @@
---
name: Feature Request
about: Suggest a new feature for Atmosphère.
#assignees:
---
## Feature Request
[ If any section does not apply, replace its contents with "N/A". ]</br>
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
[ Lines between [ ] (square brackets) are to be removed before posting. ]
[ Please search for existing [feature requests](https://github.com/Atmosphere-NX/Atmosphere/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22features%2Ffeature-request%22) before you make your own request. ]</br>
[ Duplicate requests will be marked as such and you will be referred to the original request. ]
### What feature are you suggesting?
#### Overview:
- [ Include the basic, high-level concepts for this feature here. ]</br>
#### Smaller Details:
- [ These may include specific methods of implementation etc. ]</br>
#### Nature of Request:
[ Remove all that do not apply to your request. ]
- Addition
- [ Ex: Addition of certain original features or features from other community projects. ]
- [ If you are suggesting porting features or including features from other projects, include what license they are distributed under and what, if any libraries those project use. ]
- Change
- Removal
- [Ex: Removal of certain features or implementation due to a specific issue/bug or because of low quality code, etc.]
### What component do you feel this would best fit within?
- [Fusée](https://github.com/Atmosphere-NX/Atmosphere#components)</br>
- Atmosphère's custom bootloader.</br>
- [Exosphère](https://github.com/Atmosphere-NX/Atmosphere#components)</br>
- Fully-featured custom secure monitor.</br>
- [Stratosphère](https://github.com/Atmosphere-NX/Atmosphere#components)</br>
- Custom system modules.</br>
- [**Thermosphère**](https://github.com/Atmosphere-NX/Atmosphere#components)</br>
- Atmosphère's emuNAND implementation.</br>
- [**Troposphère**](https://github.com/Atmosphere-NX/Atmosphere#components)</br>
- Application-level patches to the Horizon OS.</br>
[ Note: **Bolded components are not implemented** or are still at the prototyping phase. ]
### Why would this feature be useful?
[ If this is a feature for an end-user, how does it benefit the end-user? ]</br>
[ If this feature is for developers, what does it add to Atmosphère that did not already exist? ]</br>

View file

@ -0,0 +1,44 @@
name: Feature Request
description: Suggest a new feature for Atmosphère.
title: "[FEATURE REQUEST] "
body:
- type: markdown
attributes:
value: |
Please search for [existing feature requests](https://github.com/Atmosphere-NX/Atmosphere/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22features%2Ffeature-request%22) before you make your own request.
Duplicate requests will be marked as such, and you will be referred to the original request.
- type: textarea
attributes:
label: What feature are you suggesting?
description: Include the basic concepts for this feature here.
validations:
required: true
- type: textarea
attributes:
label: Smaller details
description: These may include specific methods of implementation, etc.
validations:
required: false
- type: textarea
attributes:
label: Nature of the request
description: |
Is this request an addition, a change, or a removal?
If you are suggesting porting features or including features from other projects, include what license they are distributed under, and what (if any) libraries those projects use.
validations:
required: true
- type: textarea
attributes:
label: What component do you feel this would best fit within?
description: See [here](https://github.com/Atmosphere-NX/Atmosphere#components) for more information.
validations:
required: true
- type: textarea
attributes:
label: Why would this feature be useful?
description: |
- If this is a feature for an end-user, how does it benefit the end-user?
- If this feature is for developers, what does it add to Atmosphère that did not already exist?
validations:
required: true

View file

@ -16,6 +16,7 @@
#pragma once #pragma once
#include <vapours.hpp> #include <vapours.hpp>
#include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp>
#include <stratosphere/ldr/ldr_platform_id.hpp>
namespace ams::fssystem { namespace ams::fssystem {
@ -25,10 +26,13 @@ namespace ams::fssystem {
void InvalidateHardwareAesKey(); void InvalidateHardwareAesKey();
const u8 *GetAcidSignatureKeyModulus(bool prod, size_t key_generation); bool IsValidSignatureKeyGeneration(ldr::PlatformId platform, size_t key_generation);
const u8 *GetAcidSignatureKeyModulus(ldr::PlatformId platform, bool prod, size_t key_generation, bool unk_unused);
size_t GetAcidSignatureKeyModulusSize(ldr::PlatformId platform, bool unk_unused);
const u8 *GetAcidSignatureKeyPublicExponent(); const u8 *GetAcidSignatureKeyPublicExponent();
constexpr inline size_t AcidSignatureKeyModulusSize = NcaCryptoConfiguration::Rsa2048KeyModulusSize;
constexpr inline size_t AcidSignatureKeyPublicExponentSize = NcaCryptoConfiguration::Rsa2048KeyPublicExponentSize; constexpr inline size_t AcidSignatureKeyPublicExponentSize = NcaCryptoConfiguration::Rsa2048KeyPublicExponentSize;
} }

View file

@ -0,0 +1,27 @@
/*
* 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 <vapours.hpp>
namespace ams::ldr {
/* TODO: Is this really a FS type? What namespace does this actually live inside? */
enum PlatformId {
PlatformId_Nx = 0,
};
}

View file

@ -19,6 +19,7 @@
#include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/ncm/ncm_ids.hpp>
#include <stratosphere/ncm/ncm_program_location.hpp> #include <stratosphere/ncm/ncm_program_location.hpp>
#include <stratosphere/sf/sf_buffer_tags.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp>
#include <stratosphere/ldr/ldr_platform_id.hpp>
namespace ams::ldr { namespace ams::ldr {
@ -224,6 +225,7 @@ namespace ams::ldr {
MetaFlag_OptimizeMemoryAllocation = (1 << 4), MetaFlag_OptimizeMemoryAllocation = (1 << 4),
MetaFlag_DisableDeviceAddressSpaceMerge = (1 << 5), MetaFlag_DisableDeviceAddressSpaceMerge = (1 << 5),
MetaFlag_EnableAliasRegionExtraSize = (1 << 6),
}; };
enum AddressSpaceType { enum AddressSpaceType {

View file

@ -22,9 +22,11 @@ namespace ams::fssystem {
constexpr inline const size_t KeySize = crypto::AesDecryptor128::KeySize; constexpr inline const size_t KeySize = crypto::AesDecryptor128::KeySize;
constexpr inline const size_t AcidSignatureKeyGenerationMax = 1; constexpr inline const size_t NxAcidSignatureKeyGenerationMax = 1;
constexpr inline const u8 AcidSignatureKeyModulusDev[AcidSignatureKeyGenerationMax + 1][AcidSignatureKeyModulusSize] = { constexpr inline const size_t NxAcidSignatureKeyModulusSize = NcaCryptoConfiguration::Rsa2048KeyModulusSize;
constexpr inline const u8 NxAcidSignatureKeyModulusDev[NxAcidSignatureKeyGenerationMax + 1][NxAcidSignatureKeyModulusSize] = {
{ {
0xD6, 0x34, 0xA5, 0x78, 0x6C, 0x68, 0xCE, 0x5A, 0xC2, 0x37, 0x17, 0xF3, 0x82, 0x45, 0xC6, 0x89, 0xD6, 0x34, 0xA5, 0x78, 0x6C, 0x68, 0xCE, 0x5A, 0xC2, 0x37, 0x17, 0xF3, 0x82, 0x45, 0xC6, 0x89,
0xE1, 0x2D, 0x06, 0x67, 0xBF, 0xB4, 0x06, 0x19, 0x55, 0x6B, 0x27, 0x66, 0x0C, 0xA4, 0xB5, 0x87, 0xE1, 0x2D, 0x06, 0x67, 0xBF, 0xB4, 0x06, 0x19, 0x55, 0x6B, 0x27, 0x66, 0x0C, 0xA4, 0xB5, 0x87,
@ -63,7 +65,7 @@ namespace ams::fssystem {
} }
}; };
constexpr inline const u8 AcidSignatureKeyModulusProd[AcidSignatureKeyGenerationMax + 1][AcidSignatureKeyModulusSize] = { constexpr inline const u8 NxAcidSignatureKeyModulusProd[NxAcidSignatureKeyGenerationMax + 1][NxAcidSignatureKeyModulusSize] = {
{ {
0xDD, 0xC8, 0xDD, 0xF2, 0x4E, 0x6D, 0xF0, 0xCA, 0x9E, 0xC7, 0x5D, 0xC7, 0x7B, 0xAD, 0xFE, 0x7D, 0xDD, 0xC8, 0xDD, 0xF2, 0x4E, 0x6D, 0xF0, 0xCA, 0x9E, 0xC7, 0x5D, 0xC7, 0x7B, 0xAD, 0xFE, 0x7D,
0x23, 0x89, 0x69, 0xB6, 0xF2, 0x06, 0xA2, 0x02, 0x88, 0xE1, 0x55, 0x91, 0xAB, 0xCB, 0x4D, 0x50, 0x23, 0x89, 0x69, 0xB6, 0xF2, 0x06, 0xA2, 0x02, 0x88, 0xE1, 0x55, 0x91, 0xAB, 0xCB, 0x4D, 0x50,
@ -102,7 +104,7 @@ namespace ams::fssystem {
} }
}; };
static_assert(sizeof(AcidSignatureKeyModulusProd) == sizeof(AcidSignatureKeyModulusDev)); static_assert(sizeof(NxAcidSignatureKeyModulusProd) == sizeof(NxAcidSignatureKeyModulusDev));
constexpr inline const u8 AcidSignatureKeyPublicExponent[] = { constexpr inline const u8 AcidSignatureKeyPublicExponent[] = {
0x01, 0x00, 0x01 0x01, 0x00, 0x01
@ -295,10 +297,36 @@ namespace ams::fssystem {
} }
} }
const u8 *GetAcidSignatureKeyModulus(bool prod, size_t key_generation) { bool IsValidSignatureKeyGeneration(ldr::PlatformId platform, size_t key_generation) {
AMS_ASSERT(key_generation <= AcidSignatureKeyGenerationMax); switch (platform) {
const size_t used_keygen = (key_generation % (AcidSignatureKeyGenerationMax + 1)); case ldr::PlatformId_Nx:
return prod ? AcidSignatureKeyModulusProd[used_keygen] : AcidSignatureKeyModulusDev[used_keygen]; return key_generation <= NxAcidSignatureKeyGenerationMax;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
const u8 *GetAcidSignatureKeyModulus(ldr::PlatformId platform, bool prod, size_t key_generation, bool unk_unused) {
AMS_ASSERT(IsValidSignatureKeyGeneration(platform, key_generation));
AMS_UNUSED(unk_unused);
switch (platform) {
case ldr::PlatformId_Nx:
{
const size_t used_keygen = (key_generation % (NxAcidSignatureKeyGenerationMax + 1));
return prod ? NxAcidSignatureKeyModulusProd[used_keygen] : NxAcidSignatureKeyModulusDev[used_keygen];
}
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
size_t GetAcidSignatureKeyModulusSize(ldr::PlatformId platform, bool unk_unused) {
AMS_UNUSED(unk_unused);
switch (platform) {
case ldr::PlatformId_Nx:
return NxAcidSignatureKeyModulusSize;
AMS_UNREACHABLE_DEFAULT_CASE();
}
} }
const u8 *GetAcidSignatureKeyPublicExponent() { const u8 *GetAcidSignatureKeyPublicExponent() {

View file

@ -34,6 +34,8 @@ namespace ams::ldr {
R_DEFINE_ERROR_RESULT(InvalidAcidSignature, 11); R_DEFINE_ERROR_RESULT(InvalidAcidSignature, 11);
R_DEFINE_ERROR_RESULT(InvalidNcaSignature, 12); R_DEFINE_ERROR_RESULT(InvalidNcaSignature, 12);
R_DEFINE_ERROR_RESULT(InvalidPlatformId, 14);
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 51); R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 51);
R_DEFINE_ERROR_RESULT(InvalidNroImage, 52); R_DEFINE_ERROR_RESULT(InvalidNroImage, 52);
R_DEFINE_ERROR_RESULT(InvalidNrrImage, 53); R_DEFINE_ERROR_RESULT(InvalidNrrImage, 53);

View file

@ -25,12 +25,12 @@ namespace ams::ldr {
} }
/* ScopedCodeMount functionality. */ /* ScopedCodeMount functionality. */
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc) : 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, PlatformId platform) : 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) {
m_result = this->Initialize(loc); m_result = this->Initialize(loc, platform);
} }
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o) : 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, PlatformId platform) : 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) {
m_result = this->Initialize(loc); m_result = this->Initialize(loc, platform);
} }
ScopedCodeMount::~ScopedCodeMount() { ScopedCodeMount::~ScopedCodeMount() {
@ -46,25 +46,28 @@ namespace ams::ldr {
} }
} }
Result ScopedCodeMount::Initialize(const ncm::ProgramLocation &loc) { Result ScopedCodeMount::Initialize(const ncm::ProgramLocation &loc, PlatformId platform) {
/* Capture override status, if necessary. */ /* Capture override status, if necessary. */
this->EnsureOverrideStatus(loc); this->EnsureOverrideStatus(loc);
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];
R_TRY(GetProgramPath(content_path, sizeof(content_path), loc)); R_TRY(GetProgramPath(content_path, sizeof(content_path), loc, platform));
/* Get the content attributes. */
const auto content_attributes = GetPlatformContentAttributes(platform);
/* 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, fs::ContentAttributes_None, 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, content_attributes, loc.program_id, m_override_status.IsHbl(), m_override_status.IsProgramSpecific()));
m_mounted_ams = true; m_mounted_ams = true;
/* Mount the sd or base code file system. */ /* Mount the sd or base code file system. */
R_TRY(fs::MountCodeForAtmosphere(std::addressof(m_sd_or_base_code_verification_data), SdOrCodeMountName, content_path, fs::ContentAttributes_None, loc.program_id)); R_TRY(fs::MountCodeForAtmosphere(std::addressof(m_sd_or_base_code_verification_data), SdOrCodeMountName, content_path, content_attributes, loc.program_id));
m_mounted_sd_or_code = true; m_mounted_sd_or_code = true;
/* Mount the base code file system. */ /* Mount the base code file system. */
if (R_SUCCEEDED(fs::MountCode(std::addressof(m_base_code_verification_data), CodeMountName, content_path, fs::ContentAttributes_None, loc.program_id))) { if (R_SUCCEEDED(fs::MountCode(std::addressof(m_base_code_verification_data), CodeMountName, content_path, content_attributes, loc.program_id))) {
m_mounted_code = true; m_mounted_code = true;
} }
@ -80,7 +83,7 @@ namespace ams::ldr {
} }
/* Redirection API. */ /* Redirection API. */
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc) { Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, PlatformId platform) {
/* Check for storage id none. */ /* Check for storage id none. */
if (static_cast<ncm::StorageId>(loc.storage_id) == ncm::StorageId::None) { if (static_cast<ncm::StorageId>(loc.storage_id) == ncm::StorageId::None) {
std::memset(out_path, 0, out_size); std::memset(out_path, 0, out_size);
@ -88,6 +91,10 @@ namespace ams::ldr {
R_SUCCEED(); R_SUCCEED();
} }
/* Get the content attributes. */
const auto content_attributes = GetPlatformContentAttributes(platform);
AMS_UNUSED(content_attributes);
lr::Path path; lr::Path path;
/* Check that path registration is allowable. */ /* Check that path registration is allowable. */
@ -159,4 +166,12 @@ namespace ams::ldr {
R_SUCCEED(); R_SUCCEED();
} }
fs::ContentAttributes GetPlatformContentAttributes(PlatformId platform) {
switch (platform) {
case PlatformId_Nx:
return fs::ContentAttributes_None;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
} }

View file

@ -34,8 +34,8 @@ namespace ams::ldr {
bool m_mounted_sd_or_code; bool m_mounted_sd_or_code;
bool m_mounted_code; bool m_mounted_code;
public: public:
ScopedCodeMount(const ncm::ProgramLocation &loc); ScopedCodeMount(const ncm::ProgramLocation &loc, PlatformId platform);
ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status); ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, PlatformId platform);
~ScopedCodeMount(); ~ScopedCodeMount();
Result GetResult() const { Result GetResult() const {
@ -59,21 +59,27 @@ namespace ams::ldr {
return m_base_code_verification_data; return m_base_code_verification_data;
} }
private: private:
Result Initialize(const ncm::ProgramLocation &loc); Result Initialize(const ncm::ProgramLocation &loc, PlatformId platform);
void EnsureOverrideStatus(const ncm::ProgramLocation &loc); void EnsureOverrideStatus(const ncm::ProgramLocation &loc);
}; };
constexpr inline const char * const AtmosphereCodeMountName = "ams-code"; constexpr inline const char * const AtmosphereCodeMountName = "ams-code";
constexpr inline const char * const SdOrCodeMountName = "sd-code"; constexpr inline const char * const AtmosphereCompatMountName = "ams-cmpt";
constexpr inline const char * const CodeMountName = "code"; constexpr inline const char * const SdOrCodeMountName = "sd-code";
constexpr inline const char * const CodeMountName = "code";
constexpr inline const char * const CompatMountName = "cmpt";
#define ENCODE_ATMOSPHERE_CODE_PATH(relative) "ams-code:" relative #define ENCODE_ATMOSPHERE_CODE_PATH(relative) "ams-code:" relative
#define ENCODE_ATMOSPHERE_CMPT_PATH(relative) "ams-cmpt:" relative
#define ENCODE_SD_OR_CODE_PATH(relative) "sd-code:" relative #define ENCODE_SD_OR_CODE_PATH(relative) "sd-code:" relative
#define ENCODE_CODE_PATH(relative) "code:" relative #define ENCODE_CODE_PATH(relative) "code:" relative
#define ENCODE_CMPT_PATH(relative) "cmpt:" relative
/* Redirection API. */ /* Redirection API. */
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc); Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, PlatformId platform);
Result RedirectProgramPath(const char *path, size_t size, 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);
fs::ContentAttributes GetPlatformContentAttributes(PlatformId platform);
} }

View file

@ -27,56 +27,72 @@ namespace ams::ldr {
constinit ArgumentStore g_argument_store; constinit ArgumentStore g_argument_store;
bool IsValidPlatform(PlatformId platform) {
return platform == PlatformId_Nx;
}
Result CreateProcessByPlatform(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit, PlatformId platform) {
/* Check that the platform is valid. */
R_UNLESS(IsValidPlatform(platform), ldr::ResultInvalidPlatformId());
/* Get the location and override status. */
ncm::ProgramLocation loc;
cfg::OverrideStatus override_status;
R_TRY(ldr::GetProgramLocationAndOverrideStatusFromPinId(std::addressof(loc), std::addressof(override_status), pin_id));
/* Get the program path. */
char path[fs::EntryNameLengthMax];
R_TRY(GetProgramPath(path, sizeof(path), loc, platform));
path[sizeof(path) - 1] = '\x00';
/* Create the process. */
R_RETURN(ldr::CreateProcess(out, pin_id, loc, override_status, path, g_argument_store.Get(loc.program_id), flags, resource_limit, platform));
}
Result GetProgramInfoByPlatform(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, PlatformId platform) {
/* Check that the platform is valid. */
R_UNLESS(IsValidPlatform(platform), ldr::ResultInvalidPlatformId());
/* Zero output. */
std::memset(out, 0, sizeof(*out));
/* Get the program path. */
char path[fs::EntryNameLengthMax];
R_TRY(GetProgramPath(path, sizeof(path), loc, platform));
path[sizeof(path) - 1] = '\x00';
/* Get the program info. */
cfg::OverrideStatus status;
R_TRY(ldr::GetProgramInfo(out, std::addressof(status), loc, path, platform));
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(g_argument_store.Set(new_loc.program_id, entry->argument, entry->argument_size));
}
}
/* If we should, set the output status. */
if (out_status != nullptr) {
*out_status = status;
}
R_SUCCEED();
}
} }
Result LoaderService::CreateProcess(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit) { Result LoaderService::CreateProcess(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit) {
/* Declare program path, which we'll need later. */ R_RETURN(CreateProcessByPlatform(out, pin_id, flags, resource_limit, PlatformId_Nx));
/* Get the location and override status. */
ncm::ProgramLocation loc;
cfg::OverrideStatus override_status;
R_TRY(ldr::GetProgramLocationAndOverrideStatusFromPinId(std::addressof(loc), std::addressof(override_status), pin_id));
/* Get the program path. */
char path[fs::EntryNameLengthMax];
R_TRY(GetProgramPath(path, sizeof(path), loc));
path[sizeof(path) - 1] = '\x00';
/* Create the process. */
R_RETURN(ldr::CreateProcess(out, pin_id, loc, override_status, path, g_argument_store.Get(loc.program_id), flags, resource_limit));
} }
Result LoaderService::GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) { Result LoaderService::GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) {
/* Zero output. */ R_RETURN(GetProgramInfoByPlatform(out, out_status, loc, PlatformId_Nx));
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;
}
R_SUCCEED();
} }
Result LoaderService::PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) { Result LoaderService::PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {

View file

@ -55,21 +55,8 @@ namespace ams::ldr {
R_UNLESS(npdm->magic == Npdm::Magic, ldr::ResultInvalidMeta()); R_UNLESS(npdm->magic == Npdm::Magic, ldr::ResultInvalidMeta());
/* Validate flags. */ /* Validate flags. */
u32 mask; constexpr u32 InvalidMetaFlagMask = 0x80000000;
if (hos::GetVersion() >= hos::Version_11_0_0) { R_UNLESS(!(npdm->flags & InvalidMetaFlagMask), ldr::ResultInvalidMeta());
/* 11.0.0 added bit 5 = "DisableDeviceAddressSpaceMerge". */
mask = ~0x3F;
} else if (hos::GetVersion() >= hos::Version_7_0_0) {
/* 7.0.0 added bit 4 = "UseOptimizedMemory" */
mask = ~0x1F;
} else {
mask = ~0xF;
}
/* We set the "DisableDeviceAddressSpaceMerge" bit on all versions, so be permissive with it. */
mask &= ~0x20;
R_UNLESS(!(npdm->flags & mask), ldr::ResultInvalidMeta());
/* Validate Acid extents. */ /* Validate Acid extents. */
R_TRY(ValidateSubregion(sizeof(Npdm), size, npdm->acid_offset, npdm->acid_size, sizeof(Acid))); R_TRY(ValidateSubregion(sizeof(Npdm), size, npdm->acid_offset, npdm->acid_size, sizeof(Acid)));
@ -90,8 +77,8 @@ namespace ams::ldr {
} }
/* Validate that the acid version is correct. */ /* Validate that the acid version is correct. */
constexpr u8 MinimumValueForAcid209 = 14; /* TODO: What is the actual meaning of this value? */ constexpr u8 SupportedSdkMajorVersion = ams::svc::ConvertToSdkMajorVersion(ams::svc::SupportedKernelMajorVersion);
if (acid->unknown_209 < MinimumValueForAcid209) { if (acid->unknown_209 < SupportedSdkMajorVersion) {
R_UNLESS(acid->version == 0, ldr::ResultInvalidMeta()); R_UNLESS(acid->version == 0, ldr::ResultInvalidMeta());
R_UNLESS(acid->unknown_209 == 0, ldr::ResultInvalidMeta()); R_UNLESS(acid->unknown_209 == 0, ldr::ResultInvalidMeta());
} }
@ -116,22 +103,30 @@ namespace ams::ldr {
R_SUCCEED(); R_SUCCEED();
} }
const u8 *GetAcidSignatureModulus(u32 key_generation) { const u8 *GetAcidSignatureModulus(PlatformId platform, u8 key_generation, bool unk_unused) {
return fssystem::GetAcidSignatureKeyModulus(!IsDevelopmentForAcidSignatureCheck(), key_generation); return fssystem::GetAcidSignatureKeyModulus(platform, !IsDevelopmentForAcidSignatureCheck(), key_generation, unk_unused);
} }
Result ValidateAcidSignature(Meta *meta) { size_t GetAcidSignatureModulusSize(PlatformId platform, bool unk_unused) {
return fssystem::GetAcidSignatureKeyModulusSize(platform, unk_unused);
}
Result ValidateAcidSignature(Meta *meta, PlatformId platform, bool unk_unused) {
/* Loader did not check signatures prior to 10.0.0. */ /* Loader did not check signatures prior to 10.0.0. */
if (hos::GetVersion() < hos::Version_10_0_0) { if (hos::GetVersion() < hos::Version_10_0_0) {
meta->check_verification_data = false; meta->check_verification_data = false;
R_SUCCEED(); R_SUCCEED();
} }
/* Get the signature key generation. */
const auto signature_key_generation = meta->npdm->signature_key_generation;
R_UNLESS(fssystem::IsValidSignatureKeyGeneration(platform, signature_key_generation), ldr::ResultInvalidMeta());
/* Verify the signature. */ /* Verify the signature. */
const u8 *sig = meta->acid->signature; const u8 *sig = meta->acid->signature;
const size_t sig_size = sizeof(meta->acid->signature); const size_t sig_size = sizeof(meta->acid->signature);
const u8 *mod = GetAcidSignatureModulus(meta->npdm->signature_key_generation); const u8 *mod = GetAcidSignatureModulus(platform, signature_key_generation, unk_unused);
const size_t mod_size = fssystem::AcidSignatureKeyModulusSize; const size_t mod_size = GetAcidSignatureModulusSize(platform, unk_unused);
const u8 *exp = fssystem::GetAcidSignatureKeyPublicExponent(); const u8 *exp = fssystem::GetAcidSignatureKeyPublicExponent();
const size_t exp_size = fssystem::AcidSignatureKeyPublicExponentSize; const size_t exp_size = fssystem::AcidSignatureKeyPublicExponentSize;
const u8 *msg = meta->acid->modulus; const u8 *msg = meta->acid->modulus;
@ -195,7 +190,10 @@ namespace ams::ldr {
} }
/* API. */ /* API. */
Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) { Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform, bool unk_unused) {
/* Set the cached program id back to zero. */
g_cached_program_id = {};
/* Try to load meta from file. */ /* Try to load meta from file. */
fs::FileHandle file; fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), AtmosphereMetaPath, fs::OpenMode_Read)); R_TRY(fs::OpenFile(std::addressof(file), AtmosphereMetaPath, fs::OpenMode_Read));
@ -261,7 +259,7 @@ namespace ams::ldr {
R_TRY(fs::OpenFile(std::addressof(file), BaseMetaPath, fs::OpenMode_Read)); R_TRY(fs::OpenFile(std::addressof(file), BaseMetaPath, fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); }; ON_SCOPE_EXIT { fs::CloseFile(file); };
R_TRY(LoadMetaFromFile(file, std::addressof(g_original_meta_cache))); R_TRY(LoadMetaFromFile(file, std::addressof(g_original_meta_cache)));
R_TRY(ValidateAcidSignature(std::addressof(g_original_meta_cache.meta))); R_TRY(ValidateAcidSignature(std::addressof(g_original_meta_cache.meta), platform, unk_unused));
meta->modulus = g_original_meta_cache.meta.modulus; meta->modulus = g_original_meta_cache.meta.modulus;
meta->check_verification_data = g_original_meta_cache.meta.check_verification_data; meta->check_verification_data = g_original_meta_cache.meta.check_verification_data;
} }
@ -280,9 +278,9 @@ namespace ams::ldr {
R_SUCCEED(); R_SUCCEED();
} }
Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) { Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform) {
if (g_cached_program_id != loc.program_id || g_cached_override_status != status) { if (g_cached_program_id != loc.program_id || g_cached_override_status != status) {
R_RETURN(LoadMeta(out_meta, loc, status)); R_RETURN(LoadMeta(out_meta, loc, status, platform, false));
} }
*out_meta = g_meta_cache.meta; *out_meta = g_meta_cache.meta;
R_SUCCEED(); R_SUCCEED();

View file

@ -36,8 +36,8 @@ namespace ams::ldr {
}; };
/* Meta API. */ /* Meta API. */
Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status); Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform, bool unk_unused);
Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status); Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform);
void InvalidateMetaCache(); void InvalidateMetaCache();
} }

View file

@ -34,23 +34,43 @@ namespace ams::ldr {
enum NsoIndex { enum NsoIndex {
Nso_Rtld = 0, Nso_Rtld = 0,
Nso_Main = 1, Nso_Main = 1,
Nso_SubSdk0 = 2, Nso_Compat0 = 2,
Nso_SubSdk1 = 3, Nso_Compat1 = 3,
Nso_SubSdk2 = 4, Nso_Compat2 = 4,
Nso_SubSdk3 = 5, Nso_Compat3 = 5,
Nso_SubSdk4 = 6, Nso_Compat4 = 6,
Nso_SubSdk5 = 7, Nso_Compat5 = 7,
Nso_SubSdk6 = 8, Nso_Compat6 = 8,
Nso_SubSdk7 = 9, Nso_Compat7 = 9,
Nso_SubSdk8 = 10, Nso_Compat8 = 10,
Nso_SubSdk9 = 11, Nso_Compat9 = 11,
Nso_Sdk = 12, Nso_SubSdk0 = 12,
Nso_SubSdk1 = 13,
Nso_SubSdk2 = 14,
Nso_SubSdk3 = 15,
Nso_SubSdk4 = 16,
Nso_SubSdk5 = 17,
Nso_SubSdk6 = 18,
Nso_SubSdk7 = 19,
Nso_SubSdk8 = 20,
Nso_SubSdk9 = 21,
Nso_Sdk = 22,
Nso_Count, Nso_Count,
}; };
constexpr inline const char *NsoPaths[Nso_Count] = { constexpr inline const char *NsoPaths[Nso_Count] = {
ENCODE_ATMOSPHERE_CODE_PATH("/rtld"), ENCODE_ATMOSPHERE_CODE_PATH("/rtld"),
ENCODE_ATMOSPHERE_CODE_PATH("/main"), 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_CODE_PATH("/subsdk0"), ENCODE_ATMOSPHERE_CODE_PATH("/subsdk0"),
ENCODE_ATMOSPHERE_CODE_PATH("/subsdk1"), ENCODE_ATMOSPHERE_CODE_PATH("/subsdk1"),
ENCODE_ATMOSPHERE_CODE_PATH("/subsdk2"), ENCODE_ATMOSPHERE_CODE_PATH("/subsdk2"),
@ -360,6 +380,11 @@ namespace ams::ldr {
flags |= svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge; flags |= svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge;
} }
/* 18.0.0+/meso Set Alias region extra size. */
if (meta_flags & Npdm::MetaFlag_EnableAliasRegionExtraSize) {
flags |= svc::CreateProcessFlag_EnableAliasRegionExtraSize;
}
*out = flags; *out = flags;
R_SUCCEED(); R_SUCCEED();
} }
@ -639,15 +664,15 @@ 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, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) { 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, PlatformId platform) {
/* Mount code. */ /* Mount code. */
AMS_UNUSED(path); AMS_UNUSED(path);
ScopedCodeMount mount(loc, override_status); ScopedCodeMount mount(loc, override_status, platform);
R_TRY(mount.GetResult()); R_TRY(mount.GetResult());
/* Load meta, possibly from cache. */ /* Load meta, possibly from cache. */
Meta meta; Meta meta;
R_TRY(LoadMetaFromCache(std::addressof(meta), loc, override_status)); R_TRY(LoadMetaFromCache(std::addressof(meta), loc, override_status, platform));
/* Validate meta. */ /* Validate meta. */
R_TRY(ValidateMeta(std::addressof(meta), loc, mount.GetCodeVerificationData())); R_TRY(ValidateMeta(std::addressof(meta), loc, mount.GetCodeVerificationData()));
@ -695,16 +720,16 @@ namespace ams::ldr {
R_SUCCEED(); R_SUCCEED();
} }
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path) { Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path, PlatformId platform) {
Meta meta; Meta meta;
/* Load Meta. */ /* Load Meta. */
{ {
AMS_UNUSED(path); AMS_UNUSED(path);
ScopedCodeMount mount(loc); ScopedCodeMount mount(loc, platform);
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(), platform, false));
if (out_status != nullptr) { if (out_status != nullptr) {
*out_status = mount.GetOverrideStatus(); *out_status = mount.GetOverrideStatus();
} }

View file

@ -19,8 +19,8 @@
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, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit); 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, PlatformId platform);
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path); Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path, PlatformId platform);
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);