Package1: Difference between revisions
m FLOW_MODE_STOP -> FLOW_MODE_WAITEVENT (0x40000000 isn't FLOW_MODE_STOP) |
This one is really "Version" (see t186 cboot source) |
||
(14 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
Present in the firmware package titles (0100000000000819, 010000000000081A, 010000000000081B and 010000000000081C) and installed into eMMC storage's [[Flash_Filesystem#Boot_Partitions|boot partitions 0 and 1]], "package1" contains the first Switch bootloader to run under the NVIDIA boot processor (an ARM7TDMI called "BPMP", "BPMP-Lite", "AVP" or "COP"). | Present in the firmware package titles (0100000000000819, 010000000000081A, 010000000000081B and 010000000000081C) and installed into eMMC storage's [[Flash_Filesystem#Boot_Partitions|boot partitions 0 and 1]], "package1" contains the first Switch bootloader ("Package1ldr") to run under the NVIDIA boot processor (an ARM7TDMI called "BPMP", "BPMP-Lite", "AVP" or "COP"), as well as the actual encrypted package1 ("PK11") blob containing the second Switch Bootloader and TrustZone code. | ||
The boot ROM validates, copies to IRAM and executes this package by parsing it's information block from the [[BCT|BCT]]. | The boot ROM validates, copies to IRAM and executes this package by parsing it's information block from the [[BCT|BCT]]. | ||
= Format = | = Format = | ||
== Erista == | |||
This package is distributed as a plaintext initial bootloader (package1ldr) and a secondary encrypted blob ("PK11"). Execution starts at plaintext package1ldr which will set up hardware, generate keys and decrypt the next stage. | |||
== | === Header === | ||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 | |||
| 0x4 | |||
| Package1ldr hash (first four bytes of SHA256(package1ldr)) | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Secure Monitor hash (first four bytes of SHA256(secure_monitor)) | |||
|- | |||
| 0x8 | |||
| 0x4 | |||
| NX Bootloader hash (first four bytes of SHA256(nx_bootloader)) | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| Build ID | |||
|- | |||
| 0x10 | |||
| 0xE | |||
| Build Timestamp (yyyyMMddHHmmss) | |||
|- | |||
| 0x1E | |||
| 0x1 | |||
| [7.0.0+] Key Generation | |||
|- | |||
| 0x1F | |||
| 0x1 | |||
| Version | |||
|} | |||
=== Initialization === | === Package1ldr === | ||
The code for this stage is stored in plaintext inside the package. By looking into the BCT's bootloader0_info (normal) or bootloader1_info (safe mode), the boot ROM starts executing this stage at address 0x40010020 in IRAM (0x40010040 for 4.0.0+). | |||
==== Initialization ==== | |||
The stack pointer is set. | The stack pointer is set. | ||
Line 23: | Line 60: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Main === | ==== Main ==== | ||
The bootloader poisons the exception vectors, cleans up memory (.bss and init_array), sets up hardware devices (including the security engine and fuses), does all the necessary checks, generates keys and finally decrypts and executes the next stage. | The bootloader poisons the exception vectors, cleans up memory (.bss and init_array), sets up hardware devices (including the security engine and fuses), does all the necessary checks, generates keys and finally decrypts and executes the next stage. | ||
Line 63: | Line 100: | ||
// Setup I2S1, I2S2, I2S3, I2S4, DISPLAY and VIC | // Setup I2S1, I2S2, I2S3, I2S4, DISPLAY and VIC | ||
mbist_workaround(); | |||
// Program the SE clock and resets | // Program the SE clock and resets | ||
Line 117: | Line 154: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Panic ==== | [6.2.0+] The bootloader maintains most of its design, but passes execution to a [[TSEC]] payload and is left in an infinite loop. | ||
<syntaxhighlight lang="c"> | |||
// Poison all exception vectors | |||
*(u32 *)0x6000F200 = panic(); | |||
*(u32 *)0x6000F204 = panic(); | |||
*(u32 *)0x6000F208 = panic(); | |||
*(u32 *)0x6000F20C = panic(); | |||
*(u32 *)0x6000F210 = panic(); | |||
*(u32 *)0x6000F214 = panic(); | |||
*(u32 *)0x6000F218 = panic(); | |||
*(u32 *)0x6000F21C = panic(); | |||
u32 bss_addr_end = bss_addr_start; | |||
u32 bss_offset = 0; | |||
u32 bss_size = bss_addr_end - bss_addr_start; | |||
// Clear .bss region | |||
// Never happens due to bss_size being set to 0 | |||
while (bss_offset < bss_size) | |||
{ | |||
*(u32 *)bss_addr_start + bss_offset = 0; | |||
bss_offset += 0x04; | |||
} | |||
u32 init_array_addr_end = init_array_addr_start; | |||
u32 init_array_offset = init_array_addr_start; | |||
// Call init methods | |||
// Never happens due to init_array_addr_end being set to init_array_addr_start | |||
while (init_array_offset < init_array_addr_end) | |||
{ | |||
u32 init_method_offset = *(u32 *)init_array_offset; | |||
call_init_method(init_method_offset + init_array_offset); | |||
init_array_offset += 0x04; | |||
} | |||
// Setup I2S1, I2S2, I2S3, I2S4, DISPLAY and VIC | |||
mbist_workaround(); | |||
// Program the SE clock and resets | |||
// Uses RST_DEVICES_V, CLK_OUT_ENB_V, CLK_SOURCE_SE and CLK_V_SE | |||
enable_se_clkrst(); | |||
// Set MISC_CLK_ENB | |||
// This makes fuse registers visible | |||
enable_misc_clk(0x01); | |||
// Setup the security engine's address | |||
set_se_addr(0x70012000); | |||
// Check SE global config | |||
check_se_status(); | |||
// Read FUSE_SKU_INFO and compare with 0x83 | |||
check_sku(); | |||
// Check configuration fuses | |||
check_config_fuses(); | |||
u32 bct_iram_addr = 0x40000000; | |||
// Check bootloader version from BCT | |||
check_bootloader_ver(bct_iram_addr); | |||
// Check anti-downgrade fuses | |||
check_downgrade(); | |||
// Setup memory controllers | |||
enable_mem_ctl(); | |||
// Clear SYS_CLK_DIVISOR | |||
*(u32 *)CLK_SOURCE_SYS = 0; | |||
// Place I2C5 in reset | |||
u32 rst_dev_h_val = *(u32 *)RST_DEVICES_H; | |||
rst_dev_h_val &= ~(0x8000); | |||
rst_dev_h_val |= 0x8000; | |||
*(u32 *)RST_DEVICES_H = rst_dev_h_val; | |||
// Program the HOST1X clock and resets | |||
// Uses RST_DEVICES_L, CLK_OUT_ENB_L, CLK_SOURCE_HOST1X and CLK_L_HOST1X | |||
enable_host1x_clkrst(); | |||
// Program the TSEC clock and resets | |||
// Uses RST_DEVICES_U, CLK_OUT_ENB_U, CLK_SOURCE_TSEC and CLK_U_TSEC | |||
enable_tsec_clkrst(); | |||
// Program the SOR_SAFE clock and resets | |||
// Uses RST_DEVICES_Y, CLK_OUT_ENB_Y and CLK_Y_SOR_SAFE | |||
enable_sor_safe_clkrst(); | |||
// Program the SOR0 clock and resets | |||
// Uses RST_DEVICES_X, CLK_OUT_ENB_X and CLK_X_SOR0 | |||
enable_sor0_clkrst(); | |||
// Program the SOR1 clock and resets | |||
// Uses RST_DEVICES_X, CLK_OUT_ENB_X, CLK_SOURCE_SOR1 and CLK_X_SOR1 | |||
enable_sor1_clkrst(); | |||
// Program the KFUSE clock resets | |||
// Uses RST_DEVICES_H, CLK_OUT_ENB_H and CLK_H_KFUSE | |||
enable_kfuse_clkrst(); | |||
// Clear the Falcon DMA control register | |||
*(u32 *)FALCON_DMACTL = 0; | |||
// Enable Falcon IRQs | |||
*(u32 *)FALCON_IRQMSET = 0xFFF2; | |||
// Enable Falcon IRQs | |||
*(u32 *)FALCON_IRQDEST = 0xFFF0; | |||
// Enable Falcon interfaces | |||
*(u32 *)FALCON_ITFEN = 0x03; | |||
// Wait for Falcon's DMA engine to be idle | |||
wait_flcn_dma_idle(); | |||
// Set DMA transfer base address to 0x40010E00>> 0x08 | |||
*(u32 *)FALCON_DMATRFBASE = 0x40010E; | |||
u32 trf_mode = 0; // A value of 0 sets FALCON_DMATRFCMD_IMEM | |||
u32 dst_offset = 0; | |||
u32 src_offset = 0; | |||
// Load code into Falcon (0x100 bytes at a time) | |||
while (src_offset < 0x2900) | |||
{ | |||
flcn_load_firm(trf_mode, src_offset, dst_offset); | |||
src_offset += 0x100; | |||
dst_offset += 0x100; | |||
} | |||
// Set magic value in host1x scratch space | |||
*(u32 *)0x50003300 = 0x34C2E1DA; | |||
// Clear Falcon scratch1 MMIO | |||
*(u32 *)FALCON_SCRATCH1 = 0; | |||
// Set Falcon boot key version in scratch0 MMIO | |||
*(u32 *)FALCON_SCRATCH0 = 0x01; | |||
// Set Falcon's boot vector address | |||
*(u32 *)FALCON_BOOTVEC = 0; | |||
// Signal Falcon's CPU | |||
*(u32 *)FALCON_CPUCTL = 0x02; | |||
// Infinite loop | |||
deadlock(); | |||
</syntaxhighlight> | |||
===== Panic ===== | |||
If a panic occurs, all sensitive memory contents are cleared, the security engine and fuse programming are disabled and the boot processor is left in a halted state. | If a panic occurs, all sensitive memory contents are cleared, the security engine and fuse programming are disabled and the boot processor is left in a halted state. | ||
Line 136: | Line 327: | ||
// Clear the PK11 blob from memory | // Clear the PK11 blob from memory | ||
clear_pk11_blob(); | clear_pk11_blob(); | ||
// Halt the boot processor | // Halt the boot processor | ||
while (true) | while (true) | ||
*(u32 *)FLOW_CTLR_HALT_COP_EVENTS = ( | *(u32 *)FLOW_CTLR_HALT_COP_EVENTS = (FLOW_MODE_STOP | HALT_COP_EVENT_JTAG); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Anti-downgrade ==== | ===== Anti-downgrade ===== | ||
See [[Fuses#Anti-downgrade|Anti-downgrade]]. | See [[Fuses#Anti-downgrade|Anti-downgrade]]. | ||
==== Memory controllers ==== | ===== Memory controllers ===== | ||
After disabling fuse programming, the bootloader configures the EMC and MEM/MC. It additionally disables QSPI resets and programs a special aperture designed for AHB redirected access to IRAM. | After disabling fuse programming, the bootloader configures the EMC and MEM/MC. It additionally disables QSPI resets and programs a special aperture designed for AHB redirected access to IRAM. | ||
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
// Initialize EMC's clock source | // Initialize EMC's clock source | ||
u32 emc_clk_src_val = *(u32 *)PERIPH_CLK_SOURCE_EMC; | u32 emc_clk_src_val = *(u32 *)PERIPH_CLK_SOURCE_EMC; | ||
Line 212: | Line 390: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Key generation ==== | [6.2.0+] MC_IRAM_TOM is now set to 0x80000000 to allow TSEC to access IRAM and all MMIO. | ||
===== Key generation ===== | |||
After the security engine is ready and before decrypting the next stage, the bootloader initializes and generates several keys into hardware keyslots. | After the security engine is ready and before decrypting the next stage, the bootloader initializes and generates several keys into hardware keyslots. | ||
For more details on the Switch's cryptosystem, please see [[Cryptosystem|this page]]. | For more details on the Switch's cryptosystem, please see [[Cryptosystem|this page]]. | ||
===== Selection ===== | [6.2.0+] The key generation process was moved into an encrypted [[TSEC]] payload. | ||
====== Selection ====== | |||
Depending on [[Fuses#FUSE_RESERVED_ODM4|FUSE_RESERVED_ODM4]] and [[Fuses#FUSE_SPARE_BIT_5|FUSE_SPARE_BIT_5]] different static seeds are selected for key generation. | Depending on [[Fuses#FUSE_RESERVED_ODM4|FUSE_RESERVED_ODM4]] and [[Fuses#FUSE_SPARE_BIT_5|FUSE_SPARE_BIT_5]] different static seeds are selected for key generation. | ||
Line 307: | Line 489: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===== generate_retail_keys ===== | ====== generate_retail_keys ====== | ||
In order to generate retail keys, the bootloader starts by initializing TSEC and grabbing it's [[TSEC# | In order to generate retail keys, the bootloader starts by initializing TSEC and grabbing it's [[TSEC#TSEC_key_generation|device key]]. Using static seeds and the SBK, the keyblob injected into the BCT's [[BCT#customer_data|customer_data]] is validated and decrypted. The resulting keys will then be used to generate the master static key and the master device key. | ||
See the pseudocode bellow for the detailed process. | See the pseudocode bellow for the detailed process. | ||
Line 370: | Line 552: | ||
aes_cmac(out_addr, out_size, keyslot, in_addr, in_size); | aes_cmac(out_addr, out_size, keyslot, in_addr, in_size); | ||
// | // Compare the generated hash with the first | ||
// 0x10 bytes of bct_customer_data | // 0x10 bytes of bct_customer_data | ||
bool match = safe_memcmp(mac_addr, bct_customer_data_addr, 0x10); | bool match = safe_memcmp(mac_addr, bct_customer_data_addr, 0x10); | ||
Line 425: | Line 607: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===== generate_debug_keys ===== | ====== generate_debug_keys ====== | ||
In order to generate debug keys, the bootloader only uses static seeds, the SBK and the SSK. | In order to generate debug keys, the bootloader only uses static seeds, the SBK and the SSK. | ||
Line 493: | Line 675: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== PK11 | === Package1 (PK11) === | ||
This blob is stored encrypted inside the package and is decrypted by | This blob is stored encrypted inside the package and is decrypted by package1ldr. | ||
=== Encryption === | ==== Encryption ==== | ||
The encrypted blob is prepended with it's CTR and total image size. After checking the image's size against an hardcoded value (can change on firmware updates), the image is AES-CTR decrypted and the keyslot used for decryption is immediately cleared. | The encrypted blob is prepended with it's CTR and total image size. After checking the image's size against an hardcoded value (can change on firmware updates), the image is AES-CTR decrypted and the keyslot used for decryption is immediately cleared. | ||
Line 544: | Line 726: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== Header === | ==== Header ==== | ||
When decrypted, the blob is encapsulated in the following header. | When decrypted, the blob is encapsulated in the following header. | ||
Line 586: | Line 768: | ||
|} | |} | ||
=== Section 0 === | What each section is used for may vary per system-version. | ||
==== Section 0 ==== | |||
This section contains the warmboot binary. | This section contains the warmboot binary. | ||
=== Section 1 === | ==== Section 1 ==== | ||
This section contains the NX bootloader, which is run after the initial bootloader in package1. | This section contains the NX bootloader, which is run after the initial bootloader in package1. | ||
=== Section 2 === | ==== Section 2 ==== | ||
This section contains the Secure Monitor binary. | This section contains the Secure Monitor binary. | ||
= | == Mariko == | ||
This package is now distributed in a custom, signed and encrypted format. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 | |||
| 0x110 | |||
| Cryptographic signature | |||
0x0000: CryptoHash (empty) | |||
0x0010: RsaPssSig | |||
|- | |||
| 0x110 | |||
| 0x20 | |||
| Random block | |||
|- | |||
| 0x130 | |||
| 0x20 | |||
| SHA256 hash over package1 data | |||
|- | |||
| 0x150 | |||
| 0x4 | |||
| Version | |||
|- | |||
| 0x154 | |||
| 0x4 | |||
| Length | |||
|- | |||
| 0x158 | |||
| 0x4 | |||
| LoadAddress | |||
|- | |||
| 0x15C | |||
| 0x4 | |||
| EntryPoint | |||
|- | |||
| 0x160 | |||
| 0x10 | |||
| Reserved | |||
|- | |||
| 0x170 | |||
| Variable | |||
| Package1 data | |||
0x0170: [[Package1#Header|Header]] | |||
0x0190: Body (encrypted) | |||
|} |