From 556e6284780bac5f7152d10e58f53915cbf5f626 Mon Sep 17 00:00:00 2001 From: Alula Date: Tue, 23 Jun 2026 16:10:39 +0200 Subject: [PATCH 1/6] ams: add dist-no-debug targets to main makefile --- Makefile | 4 ++++ atmosphere.mk | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d85056f77..f9bf4a0c5 100644 --- a/Makefile +++ b/Makefile @@ -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 "Cleaning $(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) diff --git a/atmosphere.mk b/atmosphere.mk index 7d80c94be..691597a3e 100644 --- a/atmosphere.mk +++ b/atmosphere.mk @@ -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) From 7b6ee4916ea9bad88529818cfab54a48e766ca96 Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 24 Jun 2026 20:46:23 +0200 Subject: [PATCH 2/6] pinmux: use the actual option definitions instead of magic numbers --- .../nintendo/nx/pinmux_board_driver_api.cpp | 16 +- .../nintendo/nx/pinmux_platform_pads.cpp | 164 ------------------ .../nintendo/nx/pinmux_platform_pads.hpp | 164 ++++++++++++++++++ 3 files changed, 172 insertions(+), 172 deletions(-) diff --git a/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_board_driver_api.cpp b/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_board_driver_api.cpp index 827a02c1c..e687f9bbc 100644 --- a/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_board_driver_api.cpp +++ b/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_board_driver_api.cpp @@ -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 } diff --git a/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.cpp b/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.cpp index c7c9de2c2..081b7aba7 100644 --- a/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.cpp +++ b/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.cpp @@ -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; diff --git a/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.hpp b/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.hpp index 6ec386b70..5e1087d13 100644 --- a/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.hpp +++ b/libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.hpp @@ -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); From 38251801df5ce09759f455c617d9787209680b08 Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 24 Jun 2026 20:50:41 +0200 Subject: [PATCH 3/6] loader/strat: fix/refactor zstd-zbic integration --- .../stratosphere/util/util_compression.hpp | 8 ++-- .../source/util/util_compression_lz4.cpp | 41 ++++++++++++++++++ ...pression.cpp => util_compression_zbic.cpp} | 43 ++++++++----------- .../source/util/{zstd.c => zstd.inc} | 0 .../loader/source/ldr_process_creation.cpp | 5 +-- 5 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 libraries/libstratosphere/source/util/util_compression_lz4.cpp rename libraries/libstratosphere/source/util/{util_compression.cpp => util_compression_zbic.cpp} (68%) rename libraries/libstratosphere/source/util/{zstd.c => zstd.inc} (100%) diff --git a/libraries/libstratosphere/include/stratosphere/util/util_compression.hpp b/libraries/libstratosphere/include/stratosphere/util/util_compression.hpp index a9f03641b..b22f3441e 100644 --- a/libraries/libstratosphere/include/stratosphere/util/util_compression.hpp +++ b/libraries/libstratosphere/include/stratosphere/util/util_compression.hpp @@ -21,11 +21,13 @@ namespace ams::util { /* 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 CompressZbic(void *dst, size_t dst_size, const void *src, size_t src_size); + + constexpr size_t ZstdDctxWorkspaceSize = 0x176E8; /* 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 DecompressZbic(void *dst, size_t dst_size, const void *src, size_t src_size); + bool DecompressZbicForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size); } \ No newline at end of file diff --git a/libraries/libstratosphere/source/util/util_compression_lz4.cpp b/libraries/libstratosphere/source/util/util_compression_lz4.cpp new file mode 100644 index 000000000..2f5704f47 --- /dev/null +++ b/libraries/libstratosphere/source/util/util_compression_lz4.cpp @@ -0,0 +1,41 @@ +/* + * 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 . + */ +#include +#include "lz4.h" + +namespace ams::util { + + /* 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::max()); + AMS_ABORT_UNLESS(src_size <= std::numeric_limits::max()); + + /* This is just a thin wrapper around LZ4. */ + return LZ4_compress_default(reinterpret_cast(src), reinterpret_cast(dst), static_cast(src_size), static_cast(dst_size)); + } + + /* 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::max()); + AMS_ABORT_UNLESS(src_size <= std::numeric_limits::max()); + + /* This is just a thin wrapper around LZ4. */ + return LZ4_decompress_safe(reinterpret_cast(src), reinterpret_cast(dst), static_cast(src_size), static_cast(dst_size)); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/util/util_compression.cpp b/libraries/libstratosphere/source/util/util_compression_zbic.cpp similarity index 68% rename from libraries/libstratosphere/source/util/util_compression.cpp rename to libraries/libstratosphere/source/util/util_compression_zbic.cpp index f17021024..69743bf2d 100644 --- a/libraries/libstratosphere/source/util/util_compression.cpp +++ b/libraries/libstratosphere/source/util/util_compression_zbic.cpp @@ -17,21 +17,19 @@ #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) <= ZstdDctxWorkspaceSize); - /* 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::max()); - AMS_ABORT_UNLESS(src_size <= std::numeric_limits::max()); - - /* This is just a thin wrapper around LZ4. */ - return LZ4_compress_default(reinterpret_cast(src), reinterpret_cast(dst), static_cast(src_size), static_cast(dst_size)); - } - - size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) { + size_t CompressZbic(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Basic size checks. */ AMS_ABORT_UNLESS(dst_size <= std::numeric_limits::max()); AMS_ABORT_UNLESS(src_size <= std::numeric_limits::max()); @@ -47,18 +45,8 @@ namespace ams::util { /* This is just a wrapper around Zstd. */ 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::max()); - AMS_ABORT_UNLESS(src_size <= std::numeric_limits::max()); - - /* This is just a thin wrapper around LZ4. */ - return LZ4_decompress_safe(reinterpret_cast(src), reinterpret_cast(dst), static_cast(src_size), static_cast(dst_size)); - } - size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) { + size_t DecompressZbic(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Basic size checks. */ AMS_ABORT_UNLESS(dst_size <= std::numeric_limits::max()); AMS_ABORT_UNLESS(src_size <= std::numeric_limits::max()); @@ -72,10 +60,12 @@ namespace ams::util { 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 DecompressZbicForLoader(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 ec = ZSTD_getErrorCode(margin); + AMS_LOG("[ldr] can't determine decompression margin: %u (%s)\n", ec, ZSTD_getErrorString(ec)); return false; } @@ -86,17 +76,20 @@ namespace ams::util { /* Make sure we fit in the destination buffer. */ if (margin + expected_dec_size > dst_size) { + AMS_LOG("[ldr] 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 ec = ZSTD_getErrorCode(dec_size); + AMS_LOG("[ldr] decompression failed: %u (%s)\n", ec, ZSTD_getErrorString(ec)); return false; } diff --git a/libraries/libstratosphere/source/util/zstd.c b/libraries/libstratosphere/source/util/zstd.inc similarity index 100% rename from libraries/libstratosphere/source/util/zstd.c rename to libraries/libstratosphere/source/util/zstd.inc diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 276484824..51e69ebdd 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -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::ZstdDctxWorkspaceSize]; Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) { /* No version verification is done before 8.1.0. */ @@ -656,7 +655,7 @@ namespace ams::ldr { auto compressed_data_buf = reinterpret_cast(load_address); if (is_zstd) { - bool decompressed = util::DecompressZstdForLoader(reinterpret_cast(g_zstd_dctx_workspace), ZstdDctxWorkspaceSize, reinterpret_cast(map_base), static_cast(map_end - map_base), segment_size, compressed_data_buf, file_size); + bool decompressed = util::DecompressZbicForLoader(reinterpret_cast(g_zstd_dctx_workspace), sizeof(g_zstd_dctx_workspace), reinterpret_cast(map_base), static_cast(map_end - map_base), segment_size, compressed_data_buf, file_size); R_UNLESS(decompressed, ldr::ResultInvalidNso()); } else { bool decompressed = (util::DecompressLZ4(reinterpret_cast(map_base), segment_size, compressed_data_buf, file_size) == static_cast(segment_size)); From fbeea2691997d1769603438f4dc1781dfa6365ca Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 24 Jun 2026 20:51:39 +0200 Subject: [PATCH 4/6] ams: add R_UNLESS_LOG() --- .../libvapours/include/vapours/results/results_common.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/libvapours/include/vapours/results/results_common.hpp b/libraries/libvapours/include/vapours/results/results_common.hpp index a9a72505b..a013d7c9d 100644 --- a/libraries/libvapours/include/vapours/results/results_common.hpp +++ b/libraries/libvapours/include/vapours/results/results_common.hpp @@ -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()) From 94e62a7b1b253f0cfc07ca53c6d0ec3f9599359c Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 24 Jun 2026 20:54:42 +0200 Subject: [PATCH 5/6] loader: add non-release build debug logging --- .../loader/source/ldr_process_creation.cpp | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 51e69ebdd..f4dc57862 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -219,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) { @@ -258,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) { @@ -266,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. */ @@ -293,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(); @@ -384,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()); @@ -634,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::max(), ldr::ResultInvalidNso()); @@ -647,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(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(load_address); - if (is_zstd) { + if (is_zbic) { bool decompressed = util::DecompressZbicForLoader(reinterpret_cast(g_zstd_dctx_workspace), sizeof(g_zstd_dctx_workspace), reinterpret_cast(map_base), static_cast(map_end - map_base), segment_size, compressed_data_buf, file_size); - R_UNLESS(decompressed, ldr::ResultInvalidNso()); + R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with zbic!\n"); } else { bool decompressed = (util::DecompressLZ4(reinterpret_cast(map_base), segment_size, compressed_data_buf, file_size) == static_cast(segment_size)); - R_UNLESS(decompressed, ldr::ResultInvalidNso()); + R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with lz4!\n"); } R_SUCCEED(); @@ -674,12 +679,12 @@ namespace ams::ldr { crypto::GenerateSha256(hash, sizeof(hash), reinterpret_cast(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. */ { @@ -693,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(nso_header->text_dst_offset) + static_cast(nso_header->text_size); @@ -743,14 +748,15 @@ namespace ams::ldr { for (int i = 0; i < ctx.nso_count; i++) { const NsoIndex nso_idx = static_cast(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)); } From 59846adcb77b47815e2fc847fec8406401ca118a Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 24 Jun 2026 21:01:43 +0200 Subject: [PATCH 6/6] ams: fix a copy paste mistake in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f9bf4a0c5..26bc306a7 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ $(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 "Cleaning $(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):