Package1: Difference between revisions
m →generate_retail_keys:  typo  | 
				 6.2.0 changes  | 
				||
| Line 10: | Line 10: | ||
=== Header ===  | === Header ===  | ||
{| class="wikitable" border="1"  | {| class="wikitable" border="1"  | ||
|-  | |-  | ||
| Line 39: | Line 38: | ||
| 0x1E  | | 0x1E  | ||
| 0x2  | | 0x2  | ||
|   | | Version  | ||
|}  | |}  | ||
| Line 58: | Line 56: | ||
=== Main ===  | === Main ===  | ||
From firmware versions 1.0.0 to 6.1.0, 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.  | |||
<syntaxhighlight lang="c">  | <syntaxhighlight lang="c">  | ||
| Line 97: | Line 95: | ||
  // 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 149: | Line 147: | ||
  return;  |   return;  | ||
</syntaxhighlight>  | |||
Starting with firmware version 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>  | </syntaxhighlight>  | ||
| Line 170: | Line 322: | ||
  // 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  | ||
| Line 186: | Line 334: | ||
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 249: | Line 388: | ||
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]].  | ||
[6.2.0+] The key generation process was moved into an encrypted [[TSEC]] payload.  | |||
===== Selection =====  | ===== Selection =====  | ||