From 3a9689b46ee753b8c787efcd865e5fdff83f78eb Mon Sep 17 00:00:00 2001 From: CTCaer Date: Fri, 8 Aug 2025 15:49:47 +0300 Subject: [PATCH] hos: add NX BIT/BC structures and utilize them These are used to communicate between bootloader stages and pass config. The NX Boot Config is now passed as is from PKG2 partition. --- bootloader/hos/hos.c | 103 ++++++++++++++---------------------------- bootloader/hos/pkg1.h | 50 ++++++++++++++++++++ bootloader/hos/pkg2.h | 45 ++++++++++++++++++ 3 files changed, 128 insertions(+), 70 deletions(-) diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index 88745b1f..a89f8641 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -36,34 +36,6 @@ ({ gfx_con.mute = false; \ gfx_printf("%k"text"%k\n", TXT_CLR_ERROR, args, TXT_CLR_DEFAULT); }) -#define SECMON_BCT_CFG_ADDR 0x4003D000 -#define SECMON6_BCT_CFG_ADDR 0x4003F800 - - // Secmon mailbox. -#define SECMON_MAILBOX_ADDR 0x40002E00 -#define SECMON7_MAILBOX_ADDR 0x40000000 -#define SECMON_STATE_OFFSET 0xF8 - -typedef enum -{ - SECMON_STATE_NOT_READY = 0, - - PKG1_STATE_NOT_READY = 0, - PKG1_STATE_BCT_COPIED = 1, - PKG1_STATE_DRAM_READY = 2, - PKG1_STATE_PKG2_READY_OLD = 3, - PKG1_STATE_PKG2_READY = 4 -} pkg1_states_t; - -typedef struct _secmon_mailbox_t -{ - // < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot. - // >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot. - u32 in; - // Non-zero: Secmon ready. - u32 out; -} secmon_mailbox_t; - static const u8 eks_keyseeds[HOS_MKEY_VER_600 - HOS_MKEY_VER_100 + 1][SE_KEY_128_SIZE] = { { 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, // 1.0.0. { 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, // 3.0.0. @@ -630,7 +602,7 @@ try_load: static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt) { - u8 *bctBuf = NULL; + u8 *nx_bc = NULL; emummc_storage_set_mmc_partition(EMMC_GPP); @@ -644,27 +616,30 @@ DPRINTF("Parsed GPT\n"); goto out; // Read in package2 header and get package2 real size. - static const u32 BCT_SIZE = SZ_16K; - bctBuf = (u8 *)malloc(BCT_SIZE); - emmc_part_read(pkg2_part, BCT_SIZE / EMMC_BLOCKSIZE, 1, bctBuf); - u32 *hdr = (u32 *)(bctBuf + 0x100); + static const u32 PKG2_OFFSET = SZ_16K; + nx_bc = (u8 *)malloc(sizeof(nx_bc_t)); + emmc_part_read(pkg2_part, PKG2_OFFSET / EMMC_BLOCKSIZE, 1, nx_bc); + u32 *hdr = (u32 *)(nx_bc + 0x100); u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3]; DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size); - // Read in Boot Config. - emmc_part_read(pkg2_part, 0, BCT_SIZE / EMMC_BLOCKSIZE, bctBuf); + // Check that size is valid. + if (!pkg2_size || pkg2_size > SZ_8M) + goto out; + + // Read in NX Boot Config. + emmc_part_read(pkg2_part, 0, sizeof(nx_bc_t) / EMMC_BLOCKSIZE, nx_bc); // Read in package2. u32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE); DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned); ctxt->pkg2 = malloc(pkg2_size_aligned); ctxt->pkg2_size = pkg2_size; - emmc_part_read(pkg2_part, BCT_SIZE / EMMC_BLOCKSIZE, - pkg2_size_aligned / EMMC_BLOCKSIZE, ctxt->pkg2); + emmc_part_read(pkg2_part, PKG2_OFFSET / EMMC_BLOCKSIZE, pkg2_size_aligned / EMMC_BLOCKSIZE, ctxt->pkg2); out: emmc_gpt_free(&gpt); - return bctBuf; + return nx_bc; } static void _free_launch_components(launch_ctxt_t *ctxt) @@ -932,8 +907,8 @@ void hos_launch(ini_sec_t *cfg) gfx_puts("Loaded warmboot and secmon\n"); // Read package2. - u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt); - if (!bootConfigBuf) + u8 *pkg2_nx_bc = _read_emmc_pkg2(&ctxt); + if (!pkg2_nx_bc) { _hos_crit_error("Pkg2 read failed!"); goto error; @@ -1088,20 +1063,6 @@ void hos_launch(ini_sec_t *cfg) break; } - // Clear BCT area for retail units and copy it over if dev unit. - if (mkey <= HOS_MKEY_VER_500 && !is_exo) - { - memset((void *)SECMON_BCT_CFG_ADDR, 0, SZ_4K + SZ_8K); - if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) - memcpy((void *)SECMON_BCT_CFG_ADDR, bootConfigBuf, SZ_4K); - } - else - { - memset((void *)SECMON6_BCT_CFG_ADDR, 0, SZ_2K); - if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) - memcpy((void *)SECMON6_BCT_CFG_ADDR, bootConfigBuf, SZ_2K); - } - // Finalize MC carveout. if (mkey <= HOS_MKEY_VER_301 && !is_exo) mc_config_carveout(); @@ -1116,23 +1077,25 @@ void hos_launch(ini_sec_t *cfg) // NX Bootloader locks LP0 Carveout secure scratch registers. //pmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS); - // Set secmon mailbox address and clear it. - volatile secmon_mailbox_t *secmon_mailbox; - if (mkey >= HOS_MKEY_VER_700 || is_exo) - { - memset((void *)SECMON7_MAILBOX_ADDR, 0, 0x200); - secmon_mailbox = (secmon_mailbox_t *)(SECMON7_MAILBOX_ADDR + SECMON_STATE_OFFSET); - } - else - { - if (mkey <= HOS_MKEY_VER_301) - memset((void *)SECMON_MAILBOX_ADDR, 0, 0x200); - secmon_mailbox = (secmon_mailbox_t *)(SECMON_MAILBOX_ADDR + SECMON_STATE_OFFSET); - } + // Copy the read NX BC to the correct address. + nx_bc_t *nxbc = (mkey >= HOS_MKEY_VER_600 || is_exo) ? + (nx_bc_t *)NX_BC6_ADDR : + (nx_bc_t *)NX_BC1_ADDR; + memcpy(nxbc, pkg2_nx_bc, sizeof(nx_bc_t)); // NX bootloader copies 4KB. - // Start directly from PKG2 ready signal and reset outgoing value. - secmon_mailbox->in = pkg1_state_pkg2_ready; - secmon_mailbox->out = SECMON_STATE_NOT_READY; + // Set NX BIT mailbox address and clear it. + nx_bit_t *nxbit = (mkey >= HOS_MKEY_VER_700 || is_exo) ? + (nx_bit_t *)NX_BIT7_MAILBOX_ADDR : + (nx_bit_t *)NX_BIT1_MAILBOX_ADDR; + memset(nxbit, 0, sizeof(nx_bit_t)); + + // Set used NX BIT parameters. + nxbit->bl_attribute = 0; + nxbit->boot_type = BIT_BOOT_TYPE_COLD; + + // Start directly from PKG2 ready signal and reset secmon state. + nxbit->secldr_state = pkg1_state_pkg2_ready; + nxbit->secmon_state = SECMON_STATE_NOT_READY; // Disable display. display_end(); diff --git a/bootloader/hos/pkg1.h b/bootloader/hos/pkg1.h index dc4b590d..e810d6f4 100644 --- a/bootloader/hos/pkg1.h +++ b/bootloader/hos/pkg1.h @@ -110,6 +110,56 @@ typedef struct _pk11_hdr_t /* 0x1C */ u32 sm_off; } pk11_hdr_t; +/* + * NX BIT - Secure monitor mailbox + * + * On older versions the Tegra BIT was remaining intact. + * The bootloader info from BCT was copied in the mailbox at 0x40002E10. + * On >= 4.0.0 the boot reason was replaced by BCT boot type. + * On newer versions (>= 7.0.0) the Tegra BIT is replaced with NX BIT. + * That also includes secmon state mailbox and pkg1 and pkg11 headers. + */ +#define NX_BIT1_MAILBOX_ADDR 0x40002E00 +#define NX_BIT7_MAILBOX_ADDR 0x40000000 + +enum +{ + SECMON_STATE_NOT_READY = 0, + + PKG1_STATE_NOT_READY = 0, + PKG1_STATE_NXBC_COPIED = 1, + PKG1_STATE_DRAM_READY = 2, + PKG1_STATE_PKG2_READY_OLD = 3, + PKG1_STATE_PKG2_READY = 4 +}; + +#define NX_BIT_BL_ATTR_SAFE_MODE BIT(0) +#define NX_BIT_BL_ATTR_SMC_BLACKLIST_STANDARD BIT(1) // Accounted only on >= 8.0.0. +#define NX_BIT_BL_ATTR_SMC_BLACKLIST_DEVICEUD BIT(2) // Accounted only on >= 8.0.0. +#define NX_BIT_BL_ATTR_SMC_BLACKLIST_SAFEMODE BIT(3) // Accounted only on >= 8.0.0. + +typedef struct _nx_bit_t +{ +/* 0x00 */ u32 secldr_tmr_start; +/* 0x04 */ u32 secldr_tmr_end; +/* 0x08 */ u32 secmon_tmr_start; +/* 0x0C */ u32 secmon_tmr_end; +/* 0x10 */ u32 bl_version; +/* 0x14 */ u32 bl_start_block; +/* 0x18 */ u32 bl_start_page; +/* 0x1C */ u32 bl_attribute; // bit0: Safe, bit1-4: SMC blacklist mask. +/* 0x20 */ u32 boot_type; // 0: None, 1: Coldboot, 2: RMC, 3: UART, 4: Exit RCM. +/* 0x24 */ u8 padding_nxbit[12]; + +/* 0x30 */ pk1_hdr_t pk1_hdr; // (>= 7.0.0). +/* 0x50 */ pk11_hdr_t pk11_hdr; // (>= 7.0.0). +/* 0x70 */ u8 padding_pkg1[0x88]; + +/* 0xF8 */ vu32 secldr_state; +/* 0xFC */ vu32 secmon_state; + u8 padding_mail[0x100]; +} nx_bit_t; + const pkg1_id_t *pkg1_get_latest(); const pkg1_id_t *pkg1_identify(u8 *pkg1); int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); diff --git a/bootloader/hos/pkg2.h b/bootloader/hos/pkg2.h index 6e86cd8d..e0bc1b59 100644 --- a/bootloader/hos/pkg2.h +++ b/bootloader/hos/pkg2.h @@ -163,6 +163,51 @@ typedef struct _kip1_id_t const kip1_patchset_t *patchset; } kip1_id_t; +/* + * NX NC - Package2 BOOT Configuration + * + * This is taken from the first 1KB of a Package2 partition. + * On retail, it's not zeroes, but on devkits it has actual data. + * The signed part is reserved for special in-house devkits. + */ +#define NX_BC1_ADDR 0x4003D000 +#define NX_BC6_ADDR 0x4003F800 + +#define NX_BC_DBG_FLAG00_DEV_MODE BIT(1) +#define NX_BC_DBG_FLAG00_SERROR BIT(2) +#define NX_BC_DBG_FLAG00_ALL_FLAGS 0xFF + +#define NX_BC_HW_FLAG01_ALL_FLAGS 0xFF +#define NX_BC_HW_FLAG03_MEM_MODE 0xFF +#define NX_BC_HW_FLAG04_CNTCV_SET BIT(0) + +#define NX_BC_PKG2_FLAG_DECRYPTED BIT(0) +#define NX_BC_PKG2_FLAG_UNSIGNED BIT(1) + +#define NX_BC_NCA_FLAG_UNSIGNED BIT(0) + +typedef struct _nx_bc_t { + /* Unsigned section */ + u32 version; + u32 rsvd0[3]; + u8 dbg_flags[0x10]; // Normally all are set to 0xFF if devkit. + u8 hw_flags[0x10]; + u64 cntcv_value; + u8 padding0[0x1C8]; + + u8 rsa_pss_signature[0x100]; + + /* Signed section */ + u32 version_signed; + u32 rsvd1; + u8 pkg2_flags; + u8 padding1[7]; + u32 ecid[4]; + u8 nca_flags[0x10]; + u8 unk_flags[0x10]; + u8 padding2[0xC0]; +} nx_bc_t; + bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); int pkg2_has_kip(link_t *info, u64 tid); void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);