Merge upstream Atmosphere-NX/Atmosphere master

This commit is contained in:
2026-07-17 12:07:12 +02:00
36 changed files with 554 additions and 255 deletions

View File

@@ -13,6 +13,10 @@ $(strip $1):
@echo "Building $(strip $1)"
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
dist-no-debug-$(strip $1):
@echo "Building $(strip $1)"
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk dist-no-debug ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
clean-$(strip $1):
@echo "Cleaning $(strip $1)"
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)

View File

@@ -54,7 +54,7 @@ dist: dist-no-debug
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
cd $(DIST_DIR); zip -1 -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
rm -rf $(DIST_DIR)
dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)

View File

@@ -1,4 +1,8 @@
# Changelog
## 1.11.2
+ Basic support was added for 22.5.0.
+ Atmosphère was updated to use GCC 16/newlib (latest devkitA64/devkitARM releases).
+ General system stability improvements to enhance the user's experience.
## 1.11.1
+ Basic support was added for 22.1.0.
+ General system stability improvements to enhance the user's experience.

4
emummc/.gitrepo vendored
View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emummc
branch = develop
commit = 3726bfd659600cdafd138277054568a3edba60a6
parent = 80bd459516e813fc6f10268ca31dd72a053a4ef3
commit = f6b3a28ecea9834f96151a526de66abd11033b70
parent = 1478f3443e8f04534edac8c15bf2d504663d0384
method = merge
cmdver = 0.4.9

2
emummc/README.md vendored
View File

@@ -2,7 +2,7 @@
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
### Supported Horizon Versions
**1.0.0 - 21.2.0**
**1.0.0 - 22.5.0**
## Features
* Arbitrary SDMMC backend selection

View File

@@ -85,6 +85,8 @@
#include "offsets/2120_exfat.h"
#include "offsets/2200.h"
#include "offsets/2200_exfat.h"
#include "offsets/2250.h"
#include "offsets/2250_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -181,6 +183,8 @@ DEFINE_OFFSET_STRUCT(_2120);
DEFINE_OFFSET_STRUCT(_2120_EXFAT);
DEFINE_OFFSET_STRUCT(_2200);
DEFINE_OFFSET_STRUCT(_2200_EXFAT);
DEFINE_OFFSET_STRUCT(_2250);
DEFINE_OFFSET_STRUCT(_2250_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -322,6 +326,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_2200));
case FS_VER_22_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2200_EXFAT));
case FS_VER_22_5_0:
return &(GET_OFFSET_STRUCT_NAME(_2250));
case FS_VER_22_5_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_2250_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View File

@@ -124,6 +124,9 @@ enum FS_VER
FS_VER_22_0_0,
FS_VER_22_0_0_EXFAT,
FS_VER_22_5_0,
FS_VER_22_5_0_EXFAT,
FS_VER_MAX,
};

59
emummc/source/FS/offsets/2250.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-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/>.
*/
#ifndef __FS_2250_H__
#define __FS_2250_H__
// Accessor vtable getters
#define FS_OFFSET_2250_SDMMC_ACCESSOR_GC 0x1B01C0
#define FS_OFFSET_2250_SDMMC_ACCESSOR_SD 0x1B21C0
#define FS_OFFSET_2250_SDMMC_ACCESSOR_NAND 0x1B07F0
// Hooks
#define FS_OFFSET_2250_SDMMC_WRAPPER_READ 0x1AC0F0
#define FS_OFFSET_2250_SDMMC_WRAPPER_WRITE 0x1AC150
#define FS_OFFSET_2250_RTLD 0x2DED0
#define FS_OFFSET_2250_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2250_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
// Misc funcs
#define FS_OFFSET_2250_LOCK_MUTEX 0x1A4EF0
#define FS_OFFSET_2250_UNLOCK_MUTEX 0x1A4F40
#define FS_OFFSET_2250_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0
#define FS_OFFSET_2250_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AC0D0
// Misc Data
#define FS_OFFSET_2250_SD_MUTEX 0xFF1408
#define FS_OFFSET_2250_NAND_MUTEX 0xFECD00
#define FS_OFFSET_2250_ACTIVE_PARTITION 0xFECD40
#define FS_OFFSET_2250_SDMMC_DAS_HANDLE 0xFCEB98
// NOPs
#define FS_OFFSET_2250_SD_DAS_INIT 0x2B438
// Nintendo Paths
#define FS_OFFSET_2250_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000715EC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00082E64, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008B888, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A1B1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2250_H__

59
emummc/source/FS/offsets/2250_exfat.h vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-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/>.
*/
#ifndef __FS_2250_EXFAT_H__
#define __FS_2250_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_GC 0x1BB3B0
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_SD 0x1BD3B0
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_NAND 0x1BB9E0
// Hooks
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_READ 0x1B72E0
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_WRITE 0x1B7340
#define FS_OFFSET_2250_EXFAT_RTLD 0x2DED0
#define FS_OFFSET_2250_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
#define FS_OFFSET_2250_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
// Misc funcs
#define FS_OFFSET_2250_EXFAT_LOCK_MUTEX 0x1B00E0
#define FS_OFFSET_2250_EXFAT_UNLOCK_MUTEX 0x1B0130
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B72A0
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B72C0
// Misc Data
#define FS_OFFSET_2250_EXFAT_SD_MUTEX 0x1002408
#define FS_OFFSET_2250_EXFAT_NAND_MUTEX 0xFFDD00
#define FS_OFFSET_2250_EXFAT_ACTIVE_PARTITION 0xFFDD40
#define FS_OFFSET_2250_EXFAT_SDMMC_DAS_HANDLE 0xFDBB98
// NOPs
#define FS_OFFSET_2250_EXFAT_SD_DAS_INIT 0x2B438
// Nintendo Paths
#define FS_OFFSET_2250_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x000715EC, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00082E64, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0008B888, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x000A1B1C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_2250_EXFAT_H__

View File

@@ -194,6 +194,9 @@ namespace ams::nxboot {
FsVersion_22_0_0,
FsVersion_22_0_0_Exfat,
FsVersion_22_5_0,
FsVersion_22_5_0_Exfat,
FsVersion_Count,
};
@@ -302,6 +305,9 @@ namespace ams::nxboot {
{ 0xB7, 0xA2, 0x97, 0x39, 0xB7, 0xED, 0xDE, 0xFC }, /* FsVersion_22_0_0 */
{ 0xFB, 0x0B, 0x68, 0xDB, 0x24, 0x03, 0xD1, 0x19 }, /* FsVersion_22_0_0_Exfat */
{ 0x53, 0x6D, 0x93, 0x84, 0x69, 0xFE, 0x73, 0xBE }, /* FsVersion_22_5_0 */
{ 0xD4, 0x45, 0x28, 0x29, 0x5B, 0x41, 0x92, 0xBA }, /* FsVersion_22_5_0_Exfat */
};
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
@@ -716,11 +722,13 @@ namespace ams::nxboot {
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_22_0_0:
case FsVersion_22_5_0:
AddPatch(fs_meta, 0x1B023D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1B0255, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x183060, NogcPatch1, sizeof(NogcPatch1));
break;
case FsVersion_22_0_0_Exfat:
case FsVersion_22_5_0_Exfat:
AddPatch(fs_meta, 0x1BB42D, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x1BB445, NogcPatch0, sizeof(NogcPatch0));
AddPatch(fs_meta, 0x18E250, NogcPatch1, sizeof(NogcPatch1));

View File

@@ -1355,6 +1355,9 @@ namespace ams::nxboot {
uint32_t emc_zcal_wait_cnt_new = dst_timing->burst_regs.emc_zcal_wait_cnt;
emc_zcal_wait_cnt_old &= ~0x7ff;
emc_zcal_wait_cnt_new &= ~0x7ff;
/* TODO: Unused variable. */
AMS_UNUSED(emc_zcal_wait_cnt_old);
if (dram_type == DRAM_TYPE_LPDDR4) {
zq_wait_long = std::max<u32>(1, util::DivideUp(1000000, destination_clock_period));

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 82f1553c4c7e68364f7e630b1c68f2aee8681dee
parent = 252f8685b493d0dfd428e9439b0296109776b935
commit = d3083af1827cd6ca2a96feb9316eb85cd01bae1f
parent = 974a1025b834136134e8133d8db23f69cb5ae0be
method = merge
cmdver = 0.4.9

View File

@@ -104,7 +104,10 @@ namespace ams::se {
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0;
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0;
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0;
/* TODO: Unused variable. */
AMS_UNUSED(value);
reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE),
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE),
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE));

View File

@@ -729,6 +729,9 @@ namespace ams::kern::arch::arm64 {
}
}
MESOSPHERE_ASSERT(mapped_pages == num_pages);
/* TODO: Unused variable. */
AMS_UNUSED(mapped_pages);
/* Perform what coalescing we can. */
this->MergePages(orig_virt_addr, num_pages, page_list);

View File

@@ -682,7 +682,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm:
mov x30, x10
/* Write the word to io. */
sttr w9, [x5]
sttr w9, [x4]
dsb sy
2: /* Continue. */
@@ -727,7 +727,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm:
mov x30, x10
/* Write the word to io. */
sttrh w9, [x5]
sttrh w9, [x4]
dsb sy
2: /* Continue. */
@@ -772,7 +772,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm:
mov x30, x10
/* Write the word to io. */
sttrb w9, [x5]
sttrb w9, [x4]
dsb sy
2: /* Continue. */

View File

@@ -756,11 +756,13 @@ namespace ams::kern {
case ams::svc::DebugException_UndefinedSystemCall:
{
MESOSPHERE_ASSERT(num_params >= 3);
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 1;
info->info.exception.exception_data[0] = params[2];
/* Keep the compiler happy, even though the assert has us covered. */
if (num_params >= 3) {
info->info.exception.exception_address = params[1];
info->info.exception.exception_data_count = 1;
info->info.exception.exception_data[0] = params[2];
}
}
break;
case ams::svc::DebugException_DebuggerAttached:
@@ -773,9 +775,12 @@ namespace ams::kern {
case ams::svc::DebugException_UserBreak:
{
MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_address = params[1];
/* Keep the compiler happy, even though the assert has us covered. */
if (num_params >= 2) {
info->info.exception.exception_address = params[1];
}
info->info.exception.exception_data_count = 0;
for (size_t i = 2; i < num_params; ++i) {
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
@@ -805,8 +810,11 @@ namespace ams::kern {
default:
{
MESOSPHERE_ASSERT(num_params >= 2);
info->info.exception.exception_address = params[1];
/* Keep the compiler happy, even though the assert has us covered. */
if (num_params >= 2) {
info->info.exception.exception_address = params[1];
}
}
break;
}

View File

@@ -979,6 +979,7 @@
HANDLER(FsSaveDataFileSystemPeakMountCount, 777, FsProxyErrorInfo3, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(TestBool, 778, Test, FieldType_Bool, FieldFlag_None ) \
HANDLER(TestI8Array, 779, Test, FieldType_I8Array, FieldFlag_None ) \
HANDLER(SslProcessHeapAllocatable, 781, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \
HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \

View File

@@ -102,6 +102,7 @@ namespace ams::hos {
Version_21_2_0 = ::ams::TargetFirmware_21_2_0,
Version_22_0_0 = ::ams::TargetFirmware_22_0_0,
Version_22_1_0 = ::ams::TargetFirmware_22_1_0,
Version_22_5_0 = ::ams::TargetFirmware_22_5_0,
Version_Current = ::ams::TargetFirmware_Current,

View File

@@ -41,7 +41,8 @@ namespace ams::pgl {
u32 version;
ncm::ContentType content_type;
u8 id_offset;
u8 reserved_0E[2];
ncm::ContentMetaType content_meta_type;
u8 reserved_0F;
static constexpr ContentMetaInfo Make(u64 id, u32 version, ncm::ContentType content_type, u8 id_offset) {
return {

View File

@@ -18,14 +18,18 @@
#include <vapours.hpp>
namespace ams::util {
constexpr size_t DecompressZstdWithBicWorkBufferSizeDefault = 0x176E8;
/* Compression utilities. */
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
size_t CompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size);
/* Decompression utilities. */
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
bool DecompressZstdForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size);
size_t DecompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size);
bool DecompressZstdWithBic(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size);
}

View File

@@ -47,7 +47,7 @@ namespace ams::hos {
#endif
exosphere::ApiInfo GetExosphereApiInfo(bool allow_approximate) {
exosphere::ApiInfo info;
exosphere::ApiInfo info = exosphere::ApiInfo{ util::BitPack64{0} };
#if defined(ATMOSPHERE_OS_HORIZON)
while (true) {
if (R_SUCCEEDED(GetExosphereApiInfo(std::addressof(info)))) {

View File

@@ -220,6 +220,9 @@ namespace ams::ncm {
/* Assert that we copied the right number of infos. */
AMS_ASSERT(count == fragment_count);
/* TODO: Unused variable. */
AMS_UNUSED(count);
R_SUCCEED();
}
@@ -432,6 +435,9 @@ namespace ams::ncm {
/* Assert that we copied the right number of infos. */
AMS_ASSERT(count == fragment_count);
/* TODO: Unused variable. */
AMS_UNUSED(count);
R_SUCCEED();
}

View File

@@ -345,10 +345,11 @@ namespace ams::pgl::srv {
/* Get the content meta info. */
*out = {
.id = reader.GetProgramId().value,
.version = reader.GetProgramVersion(),
.content_type = ncm::ContentType::Program,
.id_offset = reader.GetProgramIndex(),
.id = reader.GetProgramId().value,
.version = reader.GetProgramVersion(),
.content_type = ncm::ContentType::Program,
.id_offset = reader.GetProgramIndex(),
.content_meta_type = reader.GetContentMetaType(),
};
R_SUCCEED();

View File

@@ -104,25 +104,25 @@ namespace ams::pinmux::driver::board::nintendo::nx {
#if defined(AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART)
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart2Tx,
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
});
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart2Cts,
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
});
#endif
#if defined(AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART)
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart3Tx,
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
});
UpdateSinglePinmuxPad({
.index = PinmuxPadIndex_Uart3Cts,
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
});
#endif
}

View File

@@ -24,170 +24,6 @@ namespace ams::pinmux::driver::board::nintendo::nx {
uintptr_t g_apb_misc_virtual_address = dd::QueryIoMapping(0x70000000, 0x4000);
enum PinmuxPadMask : u32 {
PinmuxPadMask_Pm = 0x3,
PinmuxPadMask_Pupd = 0xC,
PinmuxPadMask_Tristate = 0x10,
PinmuxPadMask_Park = 0x20,
PinmuxPadMask_EInput = 0x40,
PinmuxPadMask_Lock = 0x80,
PinmuxPadMask_ELpdr = 0x100,
PinmuxPadMask_EHsm = 0x200,
PinmuxPadMask_EIoHv = 0x400,
PinmuxPadMask_EOd = 0x800,
PinmuxPadMask_ESchmt = 0x1000,
PinmuxPadMask_DrvType = 0x6000,
PinmuxPadMask_Preemp = 0x8000,
PinmuxPadMask_IoReset = 0x10000,
};
enum PinmuxPadBitOffset : u32 {
PinmuxPadBitOffset_Pm = 0x0,
PinmuxPadBitOffset_Pupd = 0x2,
PinmuxPadBitOffset_Tristate = 0x4,
PinmuxPadBitOffset_Park = 0x5,
PinmuxPadBitOffset_EInput = 0x6,
PinmuxPadBitOffset_Lock = 0x7,
PinmuxPadBitOffset_ELpdr = 0x8,
PinmuxPadBitOffset_EHsm = 0x9,
PinmuxPadBitOffset_EIoHv = 0xA,
PinmuxPadBitOffset_EOd = 0xB,
PinmuxPadBitOffset_ESchmt = 0xC,
PinmuxPadBitOffset_DrvType = 0xD,
PinmuxPadBitOffset_Preemp = 0xF,
PinmuxPadBitOffset_IoReset = 0x10,
};
enum PinmuxOptBitMask : u32 {
PinmuxOptBitMask_Pm = 0x7,
PinmuxOptBitMask_Pupd = 0x18,
PinmuxOptBitMask_Dir = 0x60,
PinmuxOptBitMask_Lock = 0x80,
PinmuxOptBitMask_IoReset = 0x100,
PinmuxOptBitMask_IoHv = 0x200,
PinmuxOptBitMask_Park = 0x400,
PinmuxOptBitMask_Lpdr = 0x800,
PinmuxOptBitMask_Hsm = 0x1000,
PinmuxOptBitMask_Schmt = 0x2000,
PinmuxOptBitMask_DrvType = 0xC000,
PinmuxOptBitMask_Preemp = 0x10000,
};
enum PinmuxOptBitOffset {
PinmuxOptBitOffset_Pm = 0x0,
PinmuxOptBitOffset_Pupd = 0x3,
PinmuxOptBitOffset_Dir = 0x5,
PinmuxOptBitOffset_Lock = 0x7,
PinmuxOptBitOffset_IoReset = 0x8,
PinmuxOptBitOffset_IoHv = 0x9,
PinmuxOptBitOffset_Park = 0xA,
PinmuxOptBitOffset_Lpdr = 0xB,
PinmuxOptBitOffset_Hsm = 0xC,
PinmuxOptBitOffset_Schmt = 0xD,
PinmuxOptBitOffset_DrvType = 0xE,
PinmuxOptBitOffset_Preemp = 0x10,
};
enum PinmuxDrivePadMask : u32{
PinmuxDrivePadMask_DrvDn = 0x0001F000,
PinmuxDrivePadMask_DrvUp = 0x01F00000,
PinmuxDrivePadMask_CzDrvDn = 0x0007F000,
PinmuxDrivePadMask_CzDrvUp = 0x07F00000,
PinmuxDrivePadMask_SlwR = 0x30000000,
PinmuxDrivePadMask_SlwF = 0xC0000000,
};
enum PinmuxDrivePadBitOffset : u32 {
PinmuxDrivePadBitOffset_DrvDn = 12,
PinmuxDrivePadBitOffset_DrvUp = 20,
PinmuxDrivePadBitOffset_CzDrvDn = 12,
PinmuxDrivePadBitOffset_CzDrvUp = 20,
PinmuxDrivePadBitOffset_SlwR = 28,
PinmuxDrivePadBitOffset_SlwF = 30,
};
enum PinmuxDriveOptBitMask : u32 {
PinmuxDriveOptBitMask_DrvDn = 0x0001F000,
PinmuxDriveOptBitMask_DrvUp = 0x01F00000,
PinmuxDriveOptBitMask_CzDrvDn = 0x0007F000,
PinmuxDriveOptBitMask_CzDrvUp = 0x07F00000,
PinmuxDriveOptBitMask_SlwR = 0x30000000,
PinmuxDriveOptBitMask_SlwF = 0xC0000000,
};
enum PinmuxDriveOptBitOffset : u32 {
PinmuxDriveOptBitOffset_DrvDn = 12,
PinmuxDriveOptBitOffset_DrvUp = 20,
PinmuxDriveOptBitOffset_CzDrvDn = 12,
PinmuxDriveOptBitOffset_CzDrvUp = 20,
PinmuxDriveOptBitOffset_SlwR = 28,
PinmuxDriveOptBitOffset_SlwF = 30,
};
enum PinmuxOpt : u32 {
/* Pm */
PinmuxOpt_Gpio = 0x4,
PinmuxOpt_Unused = 0x5,
/* Pupd */
PinmuxOpt_NoPupd = 0x0,
PinmuxOpt_PullDown = 0x8,
PinmuxOpt_PullUp = 0x10,
/* Dir */
PinmuxOpt_Output = 0x0,
PinmuxOpt_Input = 0x20,
PinmuxOpt_Bidirection = 0x40,
PinmuxOpt_OpenDrain = 0x60,
/* Lock */
PinmuxOpt_Unlock = 0x0,
PinmuxOpt_Lock = 0x80,
/* IoReset */
PinmuxOpt_DisableIoReset = 0x0,
PinmuxOpt_EnableIoReset = 0x100,
/* IoHv */
PinmuxOpt_NormalVoltage = 0x0,
PinmuxOpt_HighVoltage = 0x200,
/* Park */
PinmuxOpt_ResetOnLowPower = 0x0,
PinmuxOpt_ParkOnLowPower = 0x400,
/* Lpdr */
PinmuxOpt_DisableBaseDriver = 0x0,
PinmuxOpt_EnableBaseDriver = 0x800,
/* Hsm */
PinmuxOpt_DisableHighSpeedMode = 0x0,
PinmuxOpt_EnableHighSpeedMode = 0x1000,
/* Schmt */
PinmuxOpt_CmosMode = 0x0,
PinmuxOpt_SchmittTrigger = 0x2000,
/* DrvType */
PinmuxOpt_DrvType1X = 0x0,
PinmuxOpt_DrvType2X = 0x4000,
PinmuxOpt_DrvType3X = 0x8000,
PinmuxOpt_DrvType4X = 0xC000,
/* Preemp */
PinmuxOpt_DisablePreemp = 0x0,
PinmuxOpt_EnablePreemp = 0x10000,
};
enum PinmuxPadPm : u32 {
PinmuxPadPm_Default = 0xFFFFFFFF,
PinmuxPadPm_Pm0 = 0x0,
PinmuxPadPm_Pm1 = 0x1,
PinmuxPadPm_Pm2 = 0x2,
PinmuxPadPm_Pm3 = 0x3,
PinmuxPadPm_Safe = 0x4,
};
struct PinmuxPadCharacter {
u32 reg_offset;
u32 reg_mask;

View File

@@ -30,6 +30,170 @@ namespace ams::pinmux::driver::board::nintendo::nx {
u32 option_mask;
};
enum PinmuxPadMask : u32 {
PinmuxPadMask_Pm = 0x3,
PinmuxPadMask_Pupd = 0xC,
PinmuxPadMask_Tristate = 0x10,
PinmuxPadMask_Park = 0x20,
PinmuxPadMask_EInput = 0x40,
PinmuxPadMask_Lock = 0x80,
PinmuxPadMask_ELpdr = 0x100,
PinmuxPadMask_EHsm = 0x200,
PinmuxPadMask_EIoHv = 0x400,
PinmuxPadMask_EOd = 0x800,
PinmuxPadMask_ESchmt = 0x1000,
PinmuxPadMask_DrvType = 0x6000,
PinmuxPadMask_Preemp = 0x8000,
PinmuxPadMask_IoReset = 0x10000,
};
enum PinmuxPadBitOffset : u32 {
PinmuxPadBitOffset_Pm = 0x0,
PinmuxPadBitOffset_Pupd = 0x2,
PinmuxPadBitOffset_Tristate = 0x4,
PinmuxPadBitOffset_Park = 0x5,
PinmuxPadBitOffset_EInput = 0x6,
PinmuxPadBitOffset_Lock = 0x7,
PinmuxPadBitOffset_ELpdr = 0x8,
PinmuxPadBitOffset_EHsm = 0x9,
PinmuxPadBitOffset_EIoHv = 0xA,
PinmuxPadBitOffset_EOd = 0xB,
PinmuxPadBitOffset_ESchmt = 0xC,
PinmuxPadBitOffset_DrvType = 0xD,
PinmuxPadBitOffset_Preemp = 0xF,
PinmuxPadBitOffset_IoReset = 0x10,
};
enum PinmuxOptBitMask : u32 {
PinmuxOptBitMask_Pm = 0x7,
PinmuxOptBitMask_Pupd = 0x18,
PinmuxOptBitMask_Dir = 0x60,
PinmuxOptBitMask_Lock = 0x80,
PinmuxOptBitMask_IoReset = 0x100,
PinmuxOptBitMask_IoHv = 0x200,
PinmuxOptBitMask_Park = 0x400,
PinmuxOptBitMask_Lpdr = 0x800,
PinmuxOptBitMask_Hsm = 0x1000,
PinmuxOptBitMask_Schmt = 0x2000,
PinmuxOptBitMask_DrvType = 0xC000,
PinmuxOptBitMask_Preemp = 0x10000,
};
enum PinmuxOptBitOffset {
PinmuxOptBitOffset_Pm = 0x0,
PinmuxOptBitOffset_Pupd = 0x3,
PinmuxOptBitOffset_Dir = 0x5,
PinmuxOptBitOffset_Lock = 0x7,
PinmuxOptBitOffset_IoReset = 0x8,
PinmuxOptBitOffset_IoHv = 0x9,
PinmuxOptBitOffset_Park = 0xA,
PinmuxOptBitOffset_Lpdr = 0xB,
PinmuxOptBitOffset_Hsm = 0xC,
PinmuxOptBitOffset_Schmt = 0xD,
PinmuxOptBitOffset_DrvType = 0xE,
PinmuxOptBitOffset_Preemp = 0x10,
};
enum PinmuxDrivePadMask : u32 {
PinmuxDrivePadMask_DrvDn = 0x0001F000,
PinmuxDrivePadMask_DrvUp = 0x01F00000,
PinmuxDrivePadMask_CzDrvDn = 0x0007F000,
PinmuxDrivePadMask_CzDrvUp = 0x07F00000,
PinmuxDrivePadMask_SlwR = 0x30000000,
PinmuxDrivePadMask_SlwF = 0xC0000000,
};
enum PinmuxDrivePadBitOffset : u32 {
PinmuxDrivePadBitOffset_DrvDn = 12,
PinmuxDrivePadBitOffset_DrvUp = 20,
PinmuxDrivePadBitOffset_CzDrvDn = 12,
PinmuxDrivePadBitOffset_CzDrvUp = 20,
PinmuxDrivePadBitOffset_SlwR = 28,
PinmuxDrivePadBitOffset_SlwF = 30,
};
enum PinmuxDriveOptBitMask : u32 {
PinmuxDriveOptBitMask_DrvDn = 0x0001F000,
PinmuxDriveOptBitMask_DrvUp = 0x01F00000,
PinmuxDriveOptBitMask_CzDrvDn = 0x0007F000,
PinmuxDriveOptBitMask_CzDrvUp = 0x07F00000,
PinmuxDriveOptBitMask_SlwR = 0x30000000,
PinmuxDriveOptBitMask_SlwF = 0xC0000000,
};
enum PinmuxDriveOptBitOffset : u32 {
PinmuxDriveOptBitOffset_DrvDn = 12,
PinmuxDriveOptBitOffset_DrvUp = 20,
PinmuxDriveOptBitOffset_CzDrvDn = 12,
PinmuxDriveOptBitOffset_CzDrvUp = 20,
PinmuxDriveOptBitOffset_SlwR = 28,
PinmuxDriveOptBitOffset_SlwF = 30,
};
enum PinmuxOpt : u32 {
/* Pm */
PinmuxOpt_Gpio = 0x4,
PinmuxOpt_Unused = 0x5,
/* Pupd */
PinmuxOpt_NoPupd = 0x0,
PinmuxOpt_PullDown = 0x8,
PinmuxOpt_PullUp = 0x10,
/* Dir */
PinmuxOpt_Output = 0x0,
PinmuxOpt_Input = 0x20,
PinmuxOpt_Bidirection = 0x40,
PinmuxOpt_OpenDrain = 0x60,
/* Lock */
PinmuxOpt_Unlock = 0x0,
PinmuxOpt_Lock = 0x80,
/* IoReset */
PinmuxOpt_DisableIoReset = 0x0,
PinmuxOpt_EnableIoReset = 0x100,
/* IoHv */
PinmuxOpt_NormalVoltage = 0x0,
PinmuxOpt_HighVoltage = 0x200,
/* Park */
PinmuxOpt_ResetOnLowPower = 0x0,
PinmuxOpt_ParkOnLowPower = 0x400,
/* Lpdr */
PinmuxOpt_DisableBaseDriver = 0x0,
PinmuxOpt_EnableBaseDriver = 0x800,
/* Hsm */
PinmuxOpt_DisableHighSpeedMode = 0x0,
PinmuxOpt_EnableHighSpeedMode = 0x1000,
/* Schmt */
PinmuxOpt_CmosMode = 0x0,
PinmuxOpt_SchmittTrigger = 0x2000,
/* DrvType */
PinmuxOpt_DrvType1X = 0x0,
PinmuxOpt_DrvType2X = 0x4000,
PinmuxOpt_DrvType3X = 0x8000,
PinmuxOpt_DrvType4X = 0xC000,
/* Preemp */
PinmuxOpt_DisablePreemp = 0x0,
PinmuxOpt_EnablePreemp = 0x10000,
};
enum PinmuxPadPm : u32 {
PinmuxPadPm_Default = 0xFFFFFFFF,
PinmuxPadPm_Pm0 = 0x0,
PinmuxPadPm_Pm1 = 0x1,
PinmuxPadPm_Pm2 = 0x2,
PinmuxPadPm_Pm3 = 0x3,
PinmuxPadPm_Safe = 0x4,
};
void InitializePlatformPads();
void UpdateSinglePinmuxPad(const PinmuxPadConfig &config);

View File

@@ -0,0 +1,39 @@
/*
* 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 "lz4.h"
namespace ams::util {
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* This is just a thin wrapper around LZ4. */
return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
}
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* This is just a thin wrapper around LZ4. */
return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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>
#define ZSTD_STATIC_LINKING_ONLY
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#include "zstd.h"
#include "zstd.inc"
#pragma GCC diagnostic pop
namespace ams::util {
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* Additionally, we must check the compression boundary. */
auto bound = ZSTD_compressBound(src_size);
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
AMS_ABORT_UNLESS(dst_size >= bound);
/* Use Zstd default level. */
int compressionLevel = 3;
/* This is just a wrapper around Zstd. */
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
}
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* Additionally, we must check the decompression boundary. */
auto bound = ZSTD_decompressBound(src, src_size);
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
AMS_ABORT_UNLESS(dst_size >= bound);
/* This is just a wrapper around Zstd. */
return ZSTD_decompress(dst, dst_size, src, src_size);
}
}

View File

@@ -14,24 +14,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "lz4.h"
#define ZSTD_STATIC_LINKING_ONLY
#define ZSTD_ZBIC_SUPPORT 1
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#include "zstd.h"
#include "zstd.inc"
#pragma GCC diagnostic pop
namespace ams::util {
static_assert(sizeof(ZSTD_DCtx) <= DecompressZstdWithBicWorkBufferSizeDefault);
/* Compression utilities. */
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* This is just a thin wrapper around LZ4. */
return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
}
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
size_t CompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
@@ -44,21 +41,11 @@ namespace ams::util {
/* Use Zstd default level. */
int compressionLevel = 3;
/* This is just a wrapper around Zstd. */
/* This is just a wrapper around Zstd with BIC support enabled. */
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
}
/* Decompression utilities. */
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
/* This is just a thin wrapper around LZ4. */
return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
}
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
size_t DecompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
@@ -68,14 +55,22 @@ namespace ams::util {
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
AMS_ABORT_UNLESS(dst_size >= bound);
/* This is just a wrapper around Zstd. */
/* This is just a wrapper around Zstd with BIC support enabled. */
return ZSTD_decompress(dst, dst_size, src, src_size);
}
bool DecompressZstdForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size) {
bool DecompressZstdWithBic(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size) {
/* Check decompression margin. */
auto margin = ZSTD_decompressionMargin(src, src_size);
if (ZSTD_isError(margin)) {
auto error_code = ZSTD_getErrorCode(margin);
auto error_string = ZSTD_getErrorString(error_code);
AMS_LOG("[util] Can't determine decompression margin: %u (%s)\n", error_code, error_string);
/* TODO: Unused variables in non-debug build. */
AMS_UNUSED(error_code, error_string);
return false;
}
@@ -86,20 +81,30 @@ namespace ams::util {
/* Make sure we fit in the destination buffer. */
if (margin + expected_dec_size > dst_size) {
AMS_LOG("[util] Not enough space for decompression %lu + %lu > %lu\n", margin, expected_dec_size, dst_size);
return false;
}
/* This is a runtime assert in Loader code. We replicate it here. */
AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() == workspace_size);
/* This is a runtime assert in Loader code. Note that Nintendo does == comparison here. */
AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() <= workspace_size);
/* Decompress using a static decompression context. */
auto dctx = ZSTD_initStaticDCtx(workspace, workspace_size);
size_t dec_size = ZSTD_decompressDCtx(dctx, dst, dst_size, src, src_size);
if (ZSTD_isError(dec_size)) {
auto error_code = ZSTD_getErrorCode(margin);
auto error_string = ZSTD_getErrorString(error_code);
AMS_LOG("[util] Decompression failed: %u (%s)\n", error_code, error_string);
/* TODO: Unused variables in non-debug build. */
AMS_UNUSED(error_code, error_string);
return false;
}
/* Make sure we match the expected size. */
if (dec_size != expected_dec_size) {
return false;
}

View File

@@ -17,10 +17,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 22
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 5
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0

View File

@@ -100,8 +100,9 @@
#define ATMOSPHERE_TARGET_FIRMWARE_21_2_0 ATMOSPHERE_TARGET_FIRMWARE(21, 2, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_22_0_0 ATMOSPHERE_TARGET_FIRMWARE(22, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_22_1_0 ATMOSPHERE_TARGET_FIRMWARE(22, 1, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_22_5_0 ATMOSPHERE_TARGET_FIRMWARE(22, 5, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_1_0
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_5_0
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
@@ -194,6 +195,7 @@ namespace ams {
TargetFirmware_21_2_0 = ATMOSPHERE_TARGET_FIRMWARE_21_2_0,
TargetFirmware_22_0_0 = ATMOSPHERE_TARGET_FIRMWARE_22_0_0,
TargetFirmware_22_1_0 = ATMOSPHERE_TARGET_FIRMWARE_22_1_0,
TargetFirmware_22_5_0 = ATMOSPHERE_TARGET_FIRMWARE_22_5_0,
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,

View File

@@ -494,6 +494,14 @@ namespace ams::result::impl {
} \
}
#define R_UNLESS_LOG(expr, res, ...) \
{ \
if (!(expr)) { \
AMS_LOG(__VA_ARGS__); \
R_THROW(res); \
} \
}
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess())

View File

@@ -185,7 +185,10 @@ namespace ams::svc::codegen::impl {
/* Process all arguments, in order. */
size_t i = 0;
(layout.ProcessArgument<AbiType, ArgumentTypes>(i++, NGRN, NSAA), ...);
/* TODO: Unused variable. */
AMS_UNUSED(i);
return layout;
}

View File

@@ -100,5 +100,6 @@ constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = {
{ ParseModuleId("40E80E7442C0DFC985315E6F9E8C77229818AC0F"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.0.0 */
{ ParseModuleId("A5EF8D22EDF8A384E4135270ED596C1D2D524159"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.1.0 - 20.5.0 */
{ ParseModuleId("766D0C2277207B40AD9B8DE309396D50CCE94885"), util::size(Usb30ForceEnablePatches_21_0_0), Usb30ForceEnablePatches_21_0_0 }, /* 21.0.0 */
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 */
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 - 22.1.0 */
{ ParseModuleId("AD8D36F2029822A4C498F055ADBDAA789EB913C6"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.5.0 */
};

View File

@@ -121,8 +121,7 @@ namespace ams::ldr {
NsoHeader g_nso_headers[Nso_Count];
/* Global Zstd decompression context. */
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8;
alignas(8) u8 g_zstd_dctx_workspace[ZstdDctxWorkspaceSize];
alignas(8) u8 g_zstd_dctx_workspace[util::DecompressZstdWithBicWorkBufferSizeDefault];
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
/* No version verification is done before 8.1.0. */
@@ -220,7 +219,7 @@ namespace ams::ldr {
/* Read NSO header. */
size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader)));
R_UNLESS(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso());
R_UNLESS_LOG(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso(), "[ldr] NSO header truncated!\n");
/* Note nso is present. */
switch (i) {
@@ -259,7 +258,7 @@ namespace ams::ldr {
Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
/* We must always have a main. */
R_UNLESS(ctx.ali.has_main, ldr::ResultInvalidNso());
R_UNLESS_LOG(ctx.ali.has_main, ldr::ResultInvalidNso(), "[ldr] Missing main!\n");
/* Validate flags and extents for all present NSOs. */
for (int i = 0; i < ctx.nso_count; ++i) {
@@ -267,11 +266,11 @@ namespace ams::ldr {
/* All NSOs must not be --X. */
/* This is "probably" not checked on Ounce? */
R_UNLESS((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso());
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] --x not allowed!\n", i);
/* Zstd compression only allowed on main, and only when both rtld+sdk are present. */
if (i != ctx.main_nso_idx || ctx.rtld_idx < 0 || ctx.sdk_nso_idx < 0) {
R_UNLESS((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso());
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] zbic not allowed!\n", i);
}
/* NSOs must have page-aligned segments. */
@@ -294,13 +293,13 @@ namespace ams::ldr {
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0;
if (ctx.ali.has_rtld || ctx.ali.has_sdk) {
/* If we have sdk we must have rtld. */
R_UNLESS(ctx.ali.has_rtld, ldr::ResultInvalidNso());
R_UNLESS_LOG(ctx.ali.has_rtld, ldr::ResultInvalidNso(), "[ldr] Missing rtld!\n");
/* If we have rtld, we must not have browser core dll. */
R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso());
R_UNLESS_LOG(!has_browser_dll, ldr::ResultInvalidNso(), "[ldr] BrowserCoreDll must not be present!\n");
} else {
/* We must not have both subsdk and browser dll. */
R_UNLESS(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso());
R_UNLESS_LOG(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso(), "[ldr] Can't have both subsdk and BrowserCoreDll!\n");
}
R_SUCCEED();
@@ -385,6 +384,8 @@ namespace ams::ldr {
/* If the signature check fails, we need to check if this is allowable. */
if (!is_signature_valid) {
AMS_LOG("[ldr] invalid signature!\n");
/* We have to enforce signature checks on prod and when we have a signature to check on dev. */
R_UNLESS(IsDevelopmentForAcidProductionCheck(), ldr::ResultInvalidNcaSignature());
R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature());
@@ -635,10 +636,13 @@ namespace ams::ldr {
R_SUCCEED();
}
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zstd, uintptr_t map_base, uintptr_t map_end) {
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zbic, uintptr_t map_base, uintptr_t map_end) {
/* Select read size based on compression. */
size_t file_size = is_compressed ? compressed_size : segment_size;
AMS_LOG("[ldr] Loading segment @ 0x%016lx: compressed=%d, file_size=0x%08lx, compressed_size=0x%08lx, segment_size=0x%08lx\n",
map_base, is_compressed, file_size, compressed_size, segment_size);
/* Validate size. */
R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
R_UNLESS(file_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
@@ -648,19 +652,19 @@ namespace ams::ldr {
uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, file_offset, reinterpret_cast<void *>(load_address), file_size));
R_UNLESS(read_size == file_size, ldr::ResultInvalidNso());
R_UNLESS_LOG(read_size == file_size, ldr::ResultInvalidNso(), "[ldr] Couldn't read segment from file!\n");
/* Uncompress if necessary. */
R_SUCCEED_IF(!is_compressed);
auto compressed_data_buf = reinterpret_cast<const void *>(load_address);
if (is_zstd) {
bool decompressed = util::DecompressZstdForLoader(reinterpret_cast<void *>(g_zstd_dctx_workspace), ZstdDctxWorkspaceSize, reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
R_UNLESS(decompressed, ldr::ResultInvalidNso());
if (is_zbic) {
bool decompressed = util::DecompressZstdWithBic(reinterpret_cast<void *>(g_zstd_dctx_workspace), sizeof(g_zstd_dctx_workspace), reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with zbic!\n");
} else {
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment_size, compressed_data_buf, file_size) == static_cast<int>(segment_size));
R_UNLESS(decompressed, ldr::ResultInvalidNso());
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with lz4!\n");
}
R_SUCCEED();
@@ -675,12 +679,12 @@ namespace ams::ldr {
crypto::GenerateSha256(hash, sizeof(hash),
reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset),
nso_header->segments[segment].size);
R_UNLESS(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso());
R_UNLESS_LOG(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso(), "[ldr] Invalid segment hash!\n");
R_SUCCEED();
}
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size, size_t map_size) {
const bool is_zstd = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
const bool is_zbic = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
/* Map and read data from file. */
{
@@ -694,11 +698,11 @@ namespace ams::ldr {
/* Load NSO segments. */
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Text].file_offset, nso_header->text_compressed_size, nso_header->text_size,
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zstd, map_address + nso_header->text_dst_offset, map_end));
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zbic, map_address + nso_header->text_dst_offset, map_end));
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Ro].file_offset, nso_header->ro_compressed_size, nso_header->ro_size,
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zstd, map_address + nso_header->ro_dst_offset, map_end));
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zbic, map_address + nso_header->ro_dst_offset, map_end));
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Rw].file_offset, nso_header->rw_compressed_size, nso_header->rw_size,
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zstd, map_address + nso_header->rw_dst_offset, map_end));
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zbic, map_address + nso_header->rw_dst_offset, map_end));
/* Clear unused space to zero. */
const size_t text_end = static_cast<size_t>(nso_header->text_dst_offset) + static_cast<size_t>(nso_header->text_size);
@@ -744,14 +748,15 @@ namespace ams::ldr {
for (int i = 0; i < ctx.nso_count; i++) {
const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[i]);
const bool is_zbic = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
const size_t map_size = is_zbic ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
AMS_LOG("[ldr] module[%d]: idx=%d, path='%s', zbic=%d\n", i, (int)nso_idx, GetNsoPath(nso_idx), is_zbic);
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
const bool is_zstd = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
const size_t map_size = is_zstd ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, ctx.headers + i,
process_info->nso_address[i], process_info->nso_size[i], map_size));
}