Changes

Jump to navigation Jump to search
3,704 bytes added ,  15:26, 21 November 2018
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
| Unknown (version?)
+
| Version
|-
   
|}
 
|}
   Line 58: Line 56:     
=== 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.
+
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
  enable_hw_devices();
+
  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();
  −
u32 FLOW_CTLR_HALT_COP_EVENTS = 0x60007004;
  −
u32 FLOW_MODE_STOP = 0x40000000;
  −
u32 HALT_COP_EVENT_JTAG = 0x10000000;
   
   
 
   
 
  // 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">  
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 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 =====

Navigation menu