Merge pull request #2817 from alula/fix-zbic-games

Fix zbic games + misc changes
This commit is contained in:
hexkyz 2026-06-24 20:32:18 +01:00 committed by GitHub
commit 10722de8b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 277 additions and 224 deletions

View File

@ -13,6 +13,10 @@ $(strip $1):
@echo "Building $(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) @$$(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): clean-$(strip $1):
@echo "Cleaning $(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) @$$(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/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.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 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) rm -rf $(DIST_DIR)
dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)

View File

@ -21,11 +21,13 @@ namespace ams::util {
/* Compression utilities. */ /* Compression utilities. */
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size); 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. */ /* Decompression utilities. */
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size); 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); size_t DecompressZbic(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); 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);
} }

View File

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

View File

@ -30,6 +30,170 @@ namespace ams::pinmux::driver::board::nintendo::nx {
u32 option_mask; 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 InitializePlatformPads();
void UpdateSinglePinmuxPad(const PinmuxPadConfig &config); void UpdateSinglePinmuxPad(const PinmuxPadConfig &config);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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<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));
}
/* 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));
}
}

View File

@ -17,21 +17,19 @@
#include "lz4.h" #include "lz4.h"
#define ZSTD_STATIC_LINKING_ONLY #define ZSTD_STATIC_LINKING_ONLY
#define ZSTD_ZBIC_SUPPORT 1 #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.h"
#include "zstd.inc"
#pragma GCC diagnostic pop
namespace ams::util { namespace ams::util {
static_assert(sizeof(ZSTD_DCtx) <= ZstdDctxWorkspaceSize);
/* Compression utilities. */ size_t CompressZbic(void *dst, size_t dst_size, const void *src, size_t src_size) {
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) {
/* Basic size checks. */ /* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max()); AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max()); AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
@ -48,17 +46,7 @@ namespace ams::util {
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel); return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
} }
/* Decompression utilities. */ size_t DecompressZbic(void *dst, size_t dst_size, const void *src, size_t src_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));
}
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Basic size checks. */ /* Basic size checks. */
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max()); AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max()); AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
@ -72,10 +60,12 @@ namespace ams::util {
return ZSTD_decompress(dst, dst_size, src, src_size); 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. */ /* Check decompression margin. */
auto margin = ZSTD_decompressionMargin(src, src_size); auto margin = ZSTD_decompressionMargin(src, src_size);
if (ZSTD_isError(margin)) { 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; return false;
} }
@ -86,17 +76,20 @@ namespace ams::util {
/* Make sure we fit in the destination buffer. */ /* Make sure we fit in the destination buffer. */
if (margin + expected_dec_size > dst_size) { 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; return false;
} }
/* This is a runtime assert in Loader code. We replicate it here. */ /* This is a runtime assert in Loader code. Note that Nintendo does == comparison here. */
AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() == workspace_size); AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() <= workspace_size);
/* Decompress using a static decompression context. */ /* Decompress using a static decompression context. */
auto dctx = ZSTD_initStaticDCtx(workspace, workspace_size); auto dctx = ZSTD_initStaticDCtx(workspace, workspace_size);
size_t dec_size = ZSTD_decompressDCtx(dctx, dst, dst_size, src, src_size); size_t dec_size = ZSTD_decompressDCtx(dctx, dst, dst_size, src, src_size);
if (ZSTD_isError(dec_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; return false;
} }

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. /// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess()) #define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess())

View File

@ -121,8 +121,7 @@ namespace ams::ldr {
NsoHeader g_nso_headers[Nso_Count]; NsoHeader g_nso_headers[Nso_Count];
/* Global Zstd decompression context. */ /* Global Zstd decompression context. */
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8; alignas(8) u8 g_zstd_dctx_workspace[util::ZstdDctxWorkspaceSize];
alignas(8) u8 g_zstd_dctx_workspace[ZstdDctxWorkspaceSize];
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) { Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
/* No version verification is done before 8.1.0. */ /* No version verification is done before 8.1.0. */
@ -220,7 +219,7 @@ namespace ams::ldr {
/* Read NSO header. */ /* Read NSO header. */
size_t read_size; size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader))); 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. */ /* Note nso is present. */
switch (i) { switch (i) {
@ -259,7 +258,7 @@ namespace ams::ldr {
Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) { Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
/* We must always have a main. */ /* 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. */ /* Validate flags and extents for all present NSOs. */
for (int i = 0; i < ctx.nso_count; ++i) { for (int i = 0; i < ctx.nso_count; ++i) {
@ -267,11 +266,11 @@ namespace ams::ldr {
/* All NSOs must not be --X. */ /* All NSOs must not be --X. */
/* This is "probably" not checked on Ounce? */ /* 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. */ /* 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) { 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. */ /* NSOs must have page-aligned segments. */
@ -294,13 +293,13 @@ namespace ams::ldr {
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0; const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0;
if (ctx.ali.has_rtld || ctx.ali.has_sdk) { if (ctx.ali.has_rtld || ctx.ali.has_sdk) {
/* If we have sdk we must have rtld. */ /* 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. */ /* 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 { } else {
/* We must not have both subsdk and browser dll. */ /* 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(); R_SUCCEED();
@ -385,6 +384,8 @@ namespace ams::ldr {
/* If the signature check fails, we need to check if this is allowable. */ /* If the signature check fails, we need to check if this is allowable. */
if (!is_signature_valid) { 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. */ /* 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(IsDevelopmentForAcidProductionCheck(), ldr::ResultInvalidNcaSignature());
R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature()); R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature());
@ -635,10 +636,13 @@ namespace ams::ldr {
R_SUCCEED(); 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. */ /* Select read size based on compression. */
size_t file_size = is_compressed ? compressed_size : segment_size; 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. */ /* Validate size. */
R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso()); R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
R_UNLESS(file_size <= std::numeric_limits<s32>::max(), 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; uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
size_t read_size; size_t read_size;
R_TRY(fs::ReadFile(std::addressof(read_size), file, file_offset, reinterpret_cast<void *>(load_address), file_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. */ /* Uncompress if necessary. */
R_SUCCEED_IF(!is_compressed); R_SUCCEED_IF(!is_compressed);
auto compressed_data_buf = reinterpret_cast<const void *>(load_address); auto compressed_data_buf = reinterpret_cast<const void *>(load_address);
if (is_zstd) { if (is_zbic) {
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); bool decompressed = util::DecompressZbicForLoader(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(decompressed, ldr::ResultInvalidNso()); R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with zbic!\n");
} else { } else {
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment_size, compressed_data_buf, file_size) == static_cast<int>(segment_size)); 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(); R_SUCCEED();
@ -675,12 +679,12 @@ namespace ams::ldr {
crypto::GenerateSha256(hash, sizeof(hash), crypto::GenerateSha256(hash, sizeof(hash),
reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset), reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset),
nso_header->segments[segment].size); 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(); 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) { 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. */ /* Map and read data from file. */
{ {
@ -694,11 +698,11 @@ namespace ams::ldr {
/* Load NSO segments. */ /* Load NSO segments. */
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Text].file_offset, nso_header->text_compressed_size, nso_header->text_size, 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, 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, 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. */ /* 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); 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++) { for (int i = 0; i < ctx.nso_count; i++) {
const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[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; fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read)); R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); }; 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, R_TRY(LoadAutoLoadModule(process_info->process_handle, file, ctx.headers + i,
process_info->nso_address[i], process_info->nso_size[i], map_size)); process_info->nso_address[i], process_info->nso_size[i], map_size));
} }