Line 88: |
Line 88: |
| ==== FUSE_WRITE_ACCESS ==== | | ==== FUSE_WRITE_ACCESS ==== |
| If set to 0x01, this register disables software writes to the fuse driver registers. | | If set to 0x01, this register disables software writes to the fuse driver registers. |
− |
| |
| | | |
| === Cache registers === | | === Cache registers === |
Line 575: |
Line 574: |
| | | |
| === bootrom_ipatch === | | === bootrom_ipatch === |
− | Tegra210 based hardware such as the Switch provides support for bootrom patches. The patch data is burned to the hardware fuse array using a specific format (see [https://gist.github.com/shuffle2/f8728159da100e9df2606d43925de0af shuffle2's ipatch decoder]). The bootrom reads these fuses in order to initialize the IPATCH hardware, which allows overriding data returned for code and data fetches done by BPMP. | + | Tegra210 based hardware such as the Switch provides support for bootrom patches. The patch data is burned to the hardware fuse array using a specific format (see [https://gist.github.com/shuffle2/f8728159da100e9df2606d43925de0af shuffle2's ipatch decoder]). The bootrom reads these fuses in order to initialize the IPATCH hardware, which allows overriding data returned for code and data fetches done by BPMP. The revision stored in FUSE_CP_REV indicates the unique set of values stored in ipatch fuses. |
− | | |
− | The revision stored in FUSE_CP_REV indicates the unique set of values stored in ipatch fuses. | |
| | | |
| The following represents the patch data dumped from a Switch console: | | The following represents the patch data dumped from a Switch console: |
Line 815: |
Line 812: |
| | | |
| The last 4 patches are exclusive to the Switch, while the remaining ones are often included in most Tegra210 based devices. | | The last 4 patches are exclusive to the Switch, while the remaining ones are often included in most Tegra210 based devices. |
| + | |
| + | ==== ipatch 0 ==== |
| + | This patch configures clock enables and clock gate overrides for new hardware. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 CLK_ENB_H_SET = 0x60006328; |
| + | u32 CLK_ENB_L_SET = 0x60006320; |
| + | u32 CLK_ENB_U_SET = 0x60006330; |
| + | u32 CLK_ENB_V_SET = 0x60006440; |
| + | u32 CLK_ENB_W_SET = 0x60006448; |
| + | u32 CLK_ENB_X_SET = 0x60006284; |
| + | u32 CLK_ENB_Y_SET = 0x6000629C; |
| + | u32 LVL2_CLK_GATE_OVRA = 0x600060F8; |
| + | u32 LVL2_CLK_GATE_OVRB = 0x600060FC; |
| + | u32 LVL2_CLK_GATE_OVRC = 0x600063A0; |
| + | u32 LVL2_CLK_GATE_OVRD = 0x600063A4; |
| + | u32 LVL2_CLK_GATE_OVRE = 0x60006554; |
| + | u32 CLK_SOURCE_VI = 0x60006148; |
| + | u32 CLK_SOURCE_HOST1X = 0x60006180; |
| + | u32 CLK_SOURCE_NVENC = 0x600066A0; |
| + | |
| + | // Set all clock enables and overrides |
| + | *(u32 *)CLK_ENB_V_SET = 0xFFFFFFFF; |
| + | *(u32 *)CLK_ENB_W_SET = 0xFFFFFFFF; |
| + | *(u32 *)LVL2_CLK_GATE_OVRA = 0xFFFFFFFF; |
| + | *(u32 *)LVL2_CLK_GATE_OVRB = 0xFFFFFFFF; |
| + | *(u32 *)CLK_ENB_X_SET = 0xFFFFFFFF; |
| + | *(u32 *)CLK_ENB_Y_SET = 0xFFFFFFFF; |
| + | *(u32 *)CLK_ENB_L_SET = 0xFFFFFFFF; |
| + | *(u32 *)CLK_ENB_H_SET = 0xFFFFFFFF; |
| + | *(u32 *)CLK_ENB_U_SET = 0xFFFFFFFF; |
| + | *(u32 *)LVL2_CLK_GATE_OVRC = 0xFFFFFFFF; |
| + | *(u32 *)LVL2_CLK_GATE_OVRD = 0xFFFFFFFF; |
| + | *(u32 *)LVL2_CLK_GATE_OVRE = 0xFFFFFFFF; |
| + | |
| + | // Set VI, HOST1X and NVENC clock sources to CLK_M |
| + | *(u32 *)CLK_SOURCE_VI = 0xA0000000; |
| + | *(u32 *)CLK_SOURCE_HOST1X = 0xA0000000; |
| + | *(u32 *)CLK_SOURCE_NVENC = 0xE0000000; |
| + | |
| + | /* |
| + | Untranslated instructions: |
| + | |
| + | MOVS R1, #0 |
| + | MOVS R0, #0xE |
| + | */ |
| + | |
| + | return; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 1 ==== |
| + | This patch is a bugfix. |
| + | |
| + | LP0 resume code expects APBDEV_PMC_SCRATCH190_0 to be set to 0x01, but the bootrom didn't set it. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 APBDEV_PMC_SCRATCH190_0 = 0x7000EC18; |
| + | u32 pmc_scratch190_val = *(u32 *)APBDEV_PMC_SCRATCH190_0; |
| + | |
| + | return (pmc_scratch190_val | 0x01); |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 2 ==== |
| + | This patch adjusts USB configurations. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 USB1_UTMIP_SPARE_CFG0_0 = 0x7D000834; |
| + | u32 USB1_UTMIP_BIAS_CFG2_0 = 0x7D000850; |
| + | |
| + | // Increase UTMIP_HSSQUELCH_LEVEL_NEW by 0x02 |
| + | *(u32 *)USB1_UTMIP_BIAS_CFG2_0 += 0x02; |
| + | |
| + | // Clear FUSE_HS_IREF_CAP_CFG |
| + | *(u32 *)USB1_UTMIP_SPARE_CFG0_0 = ((*(u32 *)USB1_UTMIP_SPARE_CFG0_0 & ~(0x118)) - 0x80); |
| + | |
| + | return; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 3 ==== |
| + | This patch pertains to XHCI IRQ clearing checks and forces a result code to be 0. |
| + | |
| + | ==== ipatch 4 ==== |
| + | This patch allows backing up and restoring strapping options for warmboot. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 APBDEV_PMC_SCRATCH0_0 = 0x7000E450; |
| + | u32 APBDEV_PMC_RST_STATUS_0 = 0x7000E5B4; |
| + | u32 APBDEV_PMC_SEC_DISABLE8_0 = 0x7000E9C0; |
| + | u32 APBDEV_PMC_SECURE_SCRATCH111_0 = 0x7000EF14; |
| + | u32 APB_MISC_PP_STRAPPING_OPT_A_0 = 0x70000008; |
| + | |
| + | u32 reset_status = *(u32 *)APBDEV_PMC_RST_STATUS_0; |
| + | |
| + | // Check for regular power on |
| + | if (reset_status == 0) |
| + | { |
| + | // Set all buttons in RCM_STRAPS and backup to PMC scratch |
| + | *(u32 *)APBDEV_PMC_SECURE_SCRATCH111_0 = (*(u32 *)APB_MISC_PP_STRAPPING_OPT_A_0 | 0x1C00); |
| + | } |
| + | else |
| + | { |
| + | // Restore strapping options from PMC scratch |
| + | *(u32 *)APB_MISC_PP_STRAPPING_OPT_A_0 = *(u32 *)APBDEV_PMC_SECURE_SCRATCH111_0; |
| + | } |
| + | |
| + | // Disable write access to APBDEV_PMC_SECURE_SCRATCH111_0 |
| + | *(u32 *)APBDEV_PMC_SEC_DISABLE8_0 |= 0x4000; |
| + | |
| + | return *(u32 *)APBDEV_PMC_SCRATCH0_0; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 5 ==== |
| + | This patch adjusts USB configurations. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 USB1_UTMIP_HSRX_CFG0_0 = 0x7D000810; |
| + | u32 USB1_UTMIP_BIAS_CFG2_0 = 0x7D000850; |
| + | |
| + | // Clear UTMIP_IDLE_WAIT, UTMIP_ELASTIC_LIMIT and UTMIP_PCOUNT_UPDN_DIV, |
| + | // and set UTMIP_IDLE_WAIT to 0x11 and UTMIP_ELASTIC_LIMIT to 0x10 |
| + | *(u32 *)USB1_UTMIP_HSRX_CFG0_0 = ((*(u32 *)USB1_UTMIP_HSRX_CFG0_0 & ~(0xF8000) + 0x88000 & ~(0x7C00) + 0x4000) & ~(0xF000000)); |
| + | |
| + | // Clear UTMIP_HSSQUELCH_LEVEL_NEW |
| + | *(u32 *)USB1_UTMIP_BIAS_CFG2_0 &= ~(0x07); |
| + | |
| + | return; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 6 ==== |
| + | This patch is a factory backdoor. |
| + | |
| + | It allows controlling the debug authentication configuration using a fuse. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 FUSE_DEBUG_AUTH_OVERRIDE = 0x7000FA9C; |
| + | |
| + | u32 debug_auth_override_val = *(u32 *)FUSE_DEBUG_AUTH_OVERRIDE; |
| + | debug_auth_override_val = ((debug_auth_override_val >> 0x08) << 0x01); |
| + | |
| + | // Override debug authentication value stored in IRAM |
| + | *(u32 *)0x400028E4 &= ~(debug_auth_override_val); |
| + | |
| + | /* |
| + | Untranslated instructions: |
| + | |
| + | CMP R0, #0 |
| + | */ |
| + | |
| + | return; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 7 ==== |
| + | This patch is a bugfix. |
| + | |
| + | It prevents overflowing IRAM (0x40010000) when copying the warmboot binary from DRAM. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 APBDEV_PMC_CNTRL_0 = 0x7000E400; |
| + | |
| + | u32 warmboot_header_addr = 0x400049F0; |
| + | u32 warmboot_bin_size = *(u32 *)warmboot_bin_header_addr; |
| + | |
| + | // Invalid warmboot binary size |
| + | if (warmboot_size >> 0x11) |
| + | { |
| + | // Assert MAIN_RST |
| + | // 0x40004BF0 comes from R4 and the bootrom doesn't bother to change it |
| + | *(u32 *)APBDEV_PMC_CNTRL_0 = 0x40004BF0; |
| + | |
| + | // Deadlock |
| + | while(1); |
| + | } |
| + | |
| + | /* |
| + | Untranslated instructions: |
| + | |
| + | LDR R0, =0x40010000 |
| + | LDR R2, [warmboot_bin_header_addr] |
| + | */ |
| + | |
| + | return; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatch 8 ==== |
| + | This patch is a bugfix. |
| + | |
| + | It sets the correct warmboot binary entrypoint address for RSA signature verification, which would be done in DRAM instead of IRAM without this patch. |
| + | |
| + | <syntaxhighlight lang="c"> |
| + | u32 warmboot_addr_ptr = 0x40010238; |
| + | u32 warmboot_entry_addr_ptr = 0x40004C28; |
| + | |
| + | *(u32 *)warmboot_entry_addr_ptr = *(u32 *)warmboot_addr_ptr; |
| + | |
| + | /* |
| + | Untranslated instructions: |
| + | |
| + | LDR R2, [warmboot_addr_ptr] |
| + | */ |
| + | |
| + | return; |
| + | </syntaxhighlight> |
| + | |
| + | ==== ipatches 9 and 10 ==== |
| + | These patches modify the 256-bit Secure Provisioning AES key with index 0x3A. |
| + | |
| + | ==== ipatch 11 ==== |
| + | This patch pertains to the [[Security_Engine|Security Engine]] context restore process and forces SE_OPERATION_UNK1 to be 0x01. |
| | | |
| == Anti-downgrade == | | == Anti-downgrade == |