Second Loader: Difference between revisions
CelesteBlue (talk | contribs) |
(Add short description) |
||
Line 1: | Line 1: | ||
Also called <code>SecureLoader</code> and <code>SBL</code> ('''S'''ecure '''B'''oot '''L'''oader?), Second Loader is an [[SLSK]] loaded by [[First Loader]] and executed on [[CMeP]]. | |||
== Notes == | == Notes == | ||
Revision as of 21:01, 21 August 2024
Also called SecureLoader
and SBL
(Secure Boot Loader?), Second Loader is an SLSK loaded by First Loader and executed on CMeP.
Notes
If Ernie version is less than 0x80300, second_loader refuses to boot.
Misc function
sceKernelCheckDipsw
Version | Offset |
---|---|
3.60 | 0x802088 |
sceSysconReadScratchPad
Version | Offset |
---|---|
3.60 | 0x804530 |
sceSysconCtrlSdPower
Version | Offset |
---|---|
3.60 | 0x8048a6 |
SceSysconForDriver_7F198FA2
Version | Offset |
---|---|
3.60 | 0x8048b0 |
check_sbl2_on_emmc
Version | Offset |
---|---|
3.36 | 0x805ac2 |
Boot type indicator 1 for SLSK
This flag is set to cmep keyring 0x50C. It is defined at same time as KBL Param#Boot type indicator 1 and embeds some common information but with different flags.
cmep keyring 0x50C | KBL Param Boot type indicator 1 |
---|---|
0x4 | 0x1 |
0x20 | 0x10000 |
0x100 | 0x20000 |
0x8 | no equivalent |
Boot process (3.60)
TODO
int __usercall boot_800432@<W4>() { v51 = v0; setup_gpio_0_1_leds_809422(); gpio_something_809582(0LL, 7LL, 0LL); gpio_something2_80950A(0LL, 7LL); memset_FF_16_bytes_802302(); sub_80193E(); clear_line_0x516_80255C();
EMMC and syscon init
set_emmc_hook_80712A(0x80374ELL); // syscon_setup_80374E ret = try_init_emmc_801070(); v50 = ret; if ( ret ) goto LABEL_97; get_syscon_setup_cached_retval_807132((__int64)&v50); ret = v50; if ( v50 ) goto LABEL_97;
emmc device (sdif0) is initialized. It sets keys for emmc crypto to be 0x20E/0x20F pair and protects them (dword_E0030024 = 0x1FEF020F; dword_E0030024 = 0x1FEF020E; unk_E0070008 = 0x20E020F; unk_E0070000 = 0; unk_E0070000 = 1;
)
The command sequence sent to emmc is GO_IDLE_STATE, SEND_OP_COND, SEND_CID, SET_RELATIVE_ADDR, SEND_CSD, SELECT_CARD, SEND_EXT_CSD, SET_BLOCKLEN, SWITCH, SWITCH.
During SEND_OP_COND the function pointer from set_emmc_hook
is called, it performs syscon init. It enables syscon device using gpio and sends syscon commands 1 (get syscon ver), 5 (get vita model info), 2 (get syscon date string), optionally 0x80.
Model/devkit checks
model_info = get_cached_model_info_8038F2(); model_info_1 = model_info; set_global_model_info_808C24(model_info); model_upper = model_info_1 & 0xFF0000; if ( model_upper == 0x600000 ) goto its_devkit; if ( model_upper > 0x600000 ) goto LABEL_8; if ( model_upper == 0x310000 ) goto its_devkit; v5 = 0x100000; if ( model_upper > 0x310000 ) { if ( model_upper == 0x410000 ) goto its_devkit; LABEL_8: if ( model_upper == 0x800000 || model_upper <= 0x800000 && model_upper == 0x700000 || model_upper == 0x820000 ) goto its_devkit; v5 = 0x900000; goto LABEL_13; } do { LABEL_13: if ( model_upper == v5 ) { its_devkit: sub_802044(); enable_leds_808B7A(); } set_status(65LL); v6 = get_syscon_ver_8038EC(); v5 = 0x802FF; syscon_ver = v6; } while ( v6 <= 0x802FF ); keyring_writeX_80250C(0x508LL, (__int64)&syscon_ver, 4LL); model_info_2 = get_cached_model_info_8038F2(); keyring_writeX_80250C(0x51BLL, (__int64)&model_info_2, 4LL); if ( (model_info_2 & 0xFF0000u) > 0x7FFFFF ) v7 = 0x1030; else v7 = 0x10; dword_E3100180 = v7; set_status(67LL);
Model info is retrieved from a global set by syscon command 5. Some checks are performed to determine if the vita is a devkit, if it is then a flag to enable debug LEDs is set. Syscon hw version from command 1 is written to keyslot 0x508 and vita model info is written to keyslot 0x51B.
Retrieve boot type from syscon
boot_type = 0; v8 = syscon_cmd_0x10_get_boot_type_80452A((__int64)&boot_type); v50 = v8; if ( (_DWORD)v8 ) { v9 = 67LL; LABEL_21: v10 = 0LL; LABEL_22: report_error_808CAA(2LL, v9, v8, v10); LABEL_23: ret = v50; goto LABEL_97; } set_status(68LL);
Boot type is retrieved from syscon cmd 0x10, 0xFF14 on cold boot or 0xFF80 on resume boot.
TODO
ret_from_E002_1 = dword_E0020004; ret_from_E002 = ret_from_E002_1; ret_from_brom_1 = dword_E0010004; ret_from_brom = ret_from_brom_1; v15 = dword_E0062020; v8 = check_0x501_protection_and_compare_800DBC(ret_from_E002, ret_from_brom); v50 = v8; if ( (_DWORD)v8 ) { v9 = 68LL; goto LABEL_21; } set_status(69LL);
Resume checks
is_resume = (boot_type >> 7) & 1; v17 = something_with_dram_808662(1LL, is_resume); v50 = v17; if ( (_DWORD)v17 ) { v18 = (unsigned __int8)sub_80877E(); v19 = sub_808784(); v9 = 69LL; v8 = v17; v10 = (v18 << 8) | (unsigned int)v19; goto LABEL_22; } if ( !(_DWORD)is_resume ) goto LABEL_32; if ( !check_tz_magic_800A82() ) { is_resume = 0LL; LABEL_32: v20 = 0; clear_kbl_param_801C0C(); goto LBL_123; } if ( copy_kbl_param_to_0x4001FD00_801C1E() ) { is_resume = 1LL; goto LABEL_32; } is_resume = 1LL; v20 = 1; LBL_123: emmc_key_reg = dword_E0070004; if ( emmc_key_reg & 1 ) { set_status(82LL); report_error_808CAA(2LL, 82LL, 0x800F0029LL, 0LL); ret = 0x800F0029; goto LABEL_97; } sub_806B58(0x40000500LL, 0x1000LL); set_status(84LL);
Coldboot/resume is determined from bit 7 of boot_type returned by syscon. Then, something with dram??? If boot type is resume but TZ magic word (0x9E3199B7) isn't present, it changes boot type to coldboot.
If coldboot, KBL Param at 0x1F000100 is cleared, otherwise it's restored from 0x4001FD00. Then, some check on emmc crypto reg??? sub_806B58(0x40000500LL, 0x1000LL);
???
Factory firmware check
a3 = 0; v8 = get_factory_fw_801BAC((__int64)&a3); v50 = v8; if ( (_DWORD)v8 ) { v9 = 84LL; goto LABEL_21; } v10 = a3; if ( a3 >= 0x3600001 ) { v8 = 0x800F0030LL; v50 = 0x800F0030; v9 = 84LL; goto LABEL_22; } keyring_writeX_80250C(0x50FLL, (__int64)&a3, 4LL); set_status(85LL);
Factory firmware version is retrieved from idstorage and written to keyring slot 0x50F. The factory firmware must be not higher than this second_loader version, otherwise the boot is aborted to prevent downgrading below factory firmware version.
IDPS and OpenPSID
ret = idps_and_openpsid_800B06(); v50 = ret; if ( !ret ) { set_status(95LL);
IDPS and OpenPSID are retrieved from idstorage and written to keyslots 0x509 and 0x50D.
TODO
v22 = calls_syscon_0x88E_8089F0(6LL); v50 = v22; if ( (_DWORD)v22 ) report_error_808CAA(1LL, 95LL, v22, 0LL); some_set_clock_808960(6LL); some_set_clock2_808982(); v23 = 0x800F0026; if ( !(_DWORD)is_resume ) { dmac_init_804BEC(&ctx); v23 = dmac_memset_int_804F04(0x40000000LL, 0x200000LL, 0LL, &ctx); } set_status(86LL); v24 = syscon_read_cmd_0x1082_ptr_0x480_into_gbuf_80232A(); v50 = v24; if ( (_DWORD)v24 ) report_error_808CAA(1LL, 86LL, v24, 0LL); if ( !v20 ) syscon_read_cmd_0x1082_ptr_0x4a0_into_kbl_param_802346(); if ( !(_DWORD)is_resume && !v23 ) dmac_wait_804C16(&ctx); set_status(77LL); if ( (_DWORD)is_resume ) v25 = syscon_ver > 0x1000101; else v25 = 0LL; v50 = derive_slots_and_set_0x50B_8023A2(v25); if ( v50 ) { syscon_unk_808C2A(); v9 = 77LL; LABEL_77: v8 = (unsigned int)v50; goto LABEL_21; } set_status(81LL); v50 = pervasive_and_syscon_cmd_0x888_optional_801038(v26); if ( v50 ) { syscon_unk_808C2A(); v9 = 81LL; goto LABEL_77; } memset((__int64)line_0x510, 0LL, 0x20LL); if ( sub_802050() ) { set_status(87LL); v27 = read_syscon_cmd_0x90_off_0xE0_802056((__int64)line_0x510); v50 = v27; if ( (_DWORD)v27 ) report_error_808CAA(1LL, 87LL, v27, 0LL); if ( !is_bit_set_802088((__int64)line_0x510, 0x9FLL) && !is_bit_set_802088((__int64)line_0x510, 0x81LL) ) sub_808B66(1LL); } write_kbl_param_fields_from_syscon_801FC0(); keyring_writeX_80250C(0x510LL, (__int64)line_0x510, 0x20LL); memset((__int64)line_0x50A, 0LL, 0x10LL); set_keys_0x506_0x507_8020EA(); if ( !is_bit_set_802088((__int64)line_0x510, 0xF0LL) ) { set_status(88LL); v28 = some_syscon_derivation_802112((__int64)line_0x50A); v50 = v28; if ( (_DWORD)v28 != 0x800F0002 && (_DWORD)v28 != 0x800F0025 ) { if ( (_DWORD)v28 ) { report_error_808CAA(1LL, 88LL, v28, 0LL); } else if ( is_bit_set_802088((__int64)line_0x510, 241LL) ) { unset_bit_8022F4((__int64)line_0x50A, 13LL, 1LL); unset_bit_8022F4((__int64)line_0x50A, 14LL, 1LL); } } } keyring_writeX_80250C(0x50ALL, (__int64)line_0x50A, 0x10LL); set_status(70LL);
No-op
ret = zero_801B0E(); v50 = ret; if ( !ret ) { set_status(71LL);
No-op
v50 = zero_801B24(); if ( v50 ) { syscon_unk_808C2A(); report_error_808CAA(2LL, 71LL, (unsigned int)v50, 0LL); set_status(79LL); goto LABEL_23; } set_status(73LL);
kbl decryption
kbl_fw_version = 0; if ( (_DWORD)is_resume && (boot_type & 0x7F) != 0x17 ) { copy_arm_tz_reset_vectors_800A9A(); } else { v50 = decrypt_kernel_boot_loader_self_801162((__int64)&kbl_fw_version); if ( v50 ) { syscon_unk_808C2A(); v9 = 73LL; goto LABEL_77; } } set_status(89LL);
If resume, ARM exception vectors are copied from TZ memory at 0x40000000 to 0x1F000000 (0x0 alias on ARM). If coldboot, kernel_boot_loader.self is loaded from emmc and decrypted.
TODO
syscon_unk_808C2A(); print_info_log_800A5E(); seven = ret_7_801B2C(); six = ret_6_801B30(); *(_DWORD *)(unsigned int)&dword_80C698 = zero_801B34(); sub_804764((unsigned int)&unk_801888); set_status(78LL);
Check kbl version integrity
v8 = set_and_check_current_fw_version_800E74(kbl_fw_version, is_resume); v50 = v8; if ( (_DWORD)v8 ) { v9 = 78LL; goto LABEL_21; } sub_804786((__int64)&v50); v8 = (unsigned int)v50; if ( v50 ) { v9 = 74LL; goto LABEL_21; } set_status(94LL);
??? If coldboot, makes sure that kbl version from SELF matches this second_loader version. Also writes current version to keyslots 0x50E and 0x518. ???
Check kbl fw version vs factory version
if ( (_DWORD)is_resume || kbl_fw_version >= a3 ) { set_status(90LL);
If coldboot, make sure that kbl version is not lower than factory firmware version.
Write KBL Param fields
write_kbl_param_801C36((__int64)line_0x510, (__int64)line_0x50A, boot_type, is_resume, a3); set_status(96LL);
Writes most of KBL Param fields ???
TODO
v29 = reads_pervasivevid_calls_syscon_0x88E_80899C(seven); v50 = v29; if ( (_DWORD)v29 ) report_error_808CAA(1LL, 76LL, v29, 0LL); set_status(76LL);
Prepares to start ARM
v8 = prepare_to_start_arm_80878A(seven, *(unsigned int *)(unsigned int)&dword_80C698, 0LL); v50 = v8; if ( (_DWORD)v8 ) { v9 = 76LL; goto LABEL_21; } v30 = some_line; set_status(80LL);
Some dance with ARM clock/pervasive stuff ???
TODO
read_line32_8003E8(0x602LL, (__int64)some_line); v31 = 0xE0020100LL; v32 = some_line; v33 = 8; do { v34 = *(_DWORD *)v32; v32 = (char *)(unsigned int)((_DWORD)v32 + 4); *(_DWORD *)v31 = v34; v31 = (unsigned int)(v31 + 4); --v33; } while ( v33 ); read_line32_8003E8(0x601LL, (__int64)some_line); v35 = 8; do { v36 = *(_DWORD *)v30; v30 = (char *)(unsigned int)((_DWORD)v30 + 4); *(_DWORD *)v31 = v36; v31 = (unsigned int)(v31 + 4); --v35; } while ( v35 ); nullsub_2(); if ( six < 7 ) { if ( six != 6 ) { some_set_clock_808960(six); calls_syscon_0x88E_8089F0(six); } } else { calls_syscon_0x88E_8089F0(six); some_set_clock_808960(six); } } else { report_error_808CAA(2LL, 94LL, a3, kbl_fw_version); ret = 0x800F0030; } } } LABEL_97: protect_lines_and_set_E002_8010CE(); if ( ret ) { send_status_to_arm_8010E2(0LL); print_info_log_800A5E(); set_number_base_808D40((unsigned int)&g_unused, 0x10LL); printnum_808D46(2LL); printf((unsigned int)aB1B004fa16); // boot failed randnum = dword_E005003C; sleep_8051D0((unsigned __int16)randnum); if ( !sub_808B82() && sub_803744() ) syscon_cmd_0xC0_804606(0LL, 0LL); } else { send_status_to_arm_8010E2(1LL); syncm_8003E0(); set_status(64LL); } return ret; }
Keyrings protection
On FWs 0.995-3.60 the following keyrings are protected with flag 0x1C1F (so cmep read disabled) after starting ARM: 0x0-0x7F, 0x140-0x17F, 0x200-0x203, 0x206-0x20D, 0x344-0x353, 0x400-0x47F, 0x502-0x57F, 0x700-0x77F.
Bypassing version checks
Cmep keyring 0x50B (mgmt data) offset 0x4 bit 1 set = ignore version mismatch errors. This keyring itself is set from reading SNVS block 0 using Syscon command 0xD2. Alternatively set version to 0xDEADBEEF to skip version checks.
Session key/coredump encryption
0x20 random bytes are generated and written to keyslot 0x51A. Then, the buffer is encrypted with aes128-cbc using coredump_key and coredump_iv. The result is copied to KBL Param +0x100 (0x1F000200)
Changelog
FW version | What changed compared to previous FW version |
---|---|
3.36 | unknown |
3.50 | Model identification code (hw_info) checking algorithm changes,
Fluctuation of some addresses due to increase/decrease in the amount of code. Some in_gp register layout is changed. Some struct size is 0x260-bytes to 0x268-bytes. (See func, 3.36:0x803738/3.50:0x80374e) Changed sector read function offset. (See func, 3.36:0x805ac2) Changed hardware mask. (See func, 3.36:0x80842a/3.50:0x808440) FW strings/inst binary, build date, bootloader revision. |
3.51-3.52 | FW strings/inst binary, build date, bootloader revision. |