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 = |
− | Package1 is distributed as a plaintext initial bootloader and a secondary encrypted blob. Execution starts at the plaintext bootloader which will set up hardware, generate keys and decrypt the next stage.
| + | == 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. |
| | | |
− | == Bootloader == | + | === Header === |
− | 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.
| + | {| 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 |
| + | | 0x2 |
| + | | 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 56: |
| </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 96: |
| | | |
| // Setup I2S1, I2S2, I2S3, I2S4, DISPLAY and VIC | | // Setup I2S1, I2S2, I2S3, I2S4, DISPLAY and VIC |
− | enable_hw_devices(); | + | mbist_workaround(); |
| | | |
| // Program the SE clock and resets | | // Program the SE clock and resets |
Line 117: |
Line 150: |
| </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 323: |
| // Clear the PK11 blob from memory | | // Clear the PK11 blob from memory |
| clear_pk11_blob(); | | clear_pk11_blob(); |
− |
| |
− | u32 FLOW_CTLR_HALT_COP_EVENTS = 0x60007004;
| |
− | u32 FLOW_MODE_WAITEVENT = 0x40000000;
| |
− | u32 HALT_COP_EVENT_JTAG = 0x10000000;
| |
| | | |
| // Halt the boot processor | | // Halt the boot processor |
| while (true) | | while (true) |
− | *(u32 *)FLOW_CTLR_HALT_COP_EVENTS = (FLOW_MODE_WAITEVENT | HALT_COP_EVENT_JTAG); | + | *(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"> |
− | u32 PERIPH_CLK_SOURCE_EMC = 0x6000619C;
| |
− | u32 CLK_OUT_ENB_SET_H = 0x60006328;
| |
− | u32 CLK_OUT_ENB_SET_X = 0x60006284;
| |
− | u32 RST_DEVICES_SET_H = 0x60006308;
| |
− | u32 RST_DEVICES_CLR_Y = 0x600062AC;
| |
− | u32 MC_IRAM_REG_CTRL = 0x70019964;
| |
− | u32 MC_IRAM_BOM = 0x7001965C;
| |
− | u32 MC_IRAM_TOM = 0x70019660;
| |
− |
| |
| // 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 386: |
| </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 485: |
| </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#Device_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. | + | 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 548: |
| aes_cmac(out_addr, out_size, keyslot, in_addr, in_size); | | aes_cmac(out_addr, out_size, keyslot, in_addr, in_size); |
| | | |
− | // Comapre the generated hash with the first | + | // 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 603: |
| </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 671: |
| </syntaxhighlight> | | </syntaxhighlight> |
| | | |
− | == PK11 Blob == | + | === Package1 (PK11) === |
− | This blob is stored encrypted inside the package and is decrypted by the initial bootloader. | + | 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 722: |
| </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 764: |
| |} | | |} |
| | | |
− | === 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. |
| | | |
− | = Changelog = | + | == Mariko == |
− | == 2.0.0 ==
| + | This package is now distributed in a custom, signed and encrypted format. |
− | * The encrypted binaries' order and calculation for next stage's entrypoint was changed.
| |
| | | |
− | Old layout (before 2.0.0):
| + | {| class="wikitable" border="1" |
− | 1.- PK11 header
| + | |- |
− | 2.- Secure Monitor blob
| + | ! Offset |
− | 3.- NX bootloader blob
| + | ! Size |
− | 4.- Warmboot blob
| + | ! Description |
− | | + | |- |
− | NX bootloader entrypoint is calculated as: | + | | 0x0 |
− | 0x40013FE0 + 0x20 + 0x20 + NX bootloader blob's offset + Secure Monitor blob's size
| + | | 0x110 |
− | | + | | Cryptographic signature |
− | New layout (2.0.0+):
| + | 0x0000: CryptoHash (empty) |
− | 1.- PK11 header
| + | 0x0010: RsaPssSig |
− | 2.- Warmboot blob
| + | |- |
− | 3.- NX bootloader blob
| + | | 0x110 |
− | 4.- Secure Monitor blob
| + | | 0x20 |
− |
| + | | Random block |
− | NX bootloader entrypoint is calculated as:
| + | |- |
− | 0x40013FE0 + 0x20 + 0x20 + NX bootloader blob's offset + Warmboot blob's size
| + | | 0x130 |
− | | + | | 0x20 |
− | * Some AES-ECB decryption related code was refactored.
| + | | SHA256 hash over package1 data |
− | | + | |- |
− | == 3.0.0 ==
| + | | 0x150 |
− | * The functions set_se_addr() and check_se_status() are now called right after enabling the security engine clocks and resets.
| + | | 0x4 |
− | See [[Switch_System_Flaws#Stage_1_Bootloader]].
| + | | Version |
− | | + | |- |
− | * Keyslot 0x0A is now used instead of keyslot 0x0D for generating the master_device_key.
| + | | 0x154 |
| + | | 0x4 |
| + | | Length |
| + | |- |
| + | | 0x158 |
| + | | 0x4 |
| + | | LoadAddress |
| + | |- |
| + | | 0x15C |
| + | | 0x4 |
| + | | EntryPoint |
| + | |- |
| + | | 0x160 |
| + | | 0x10 |
| + | | Reserved |
| + | |- |
| + | | 0x170 |
| + | | Variable |
| + | | Package1 data |
| + | 0x0170: [[Package1#Header|Header]] |
| + | 0x0190: Body (encrypted) |
| + | |} |