Changes

Jump to navigation Jump to search
13,568 bytes added ,  21:38, 2 September 2021
Line 1: Line 1: −
== eeprom protection ==
+
== Notes ==
   −
On 0.995 and 3.60 the following lines are protected after starting arm: 0x0-0x7F, 0x140-0x17F, 0x200-0x203, 0x206-0x20D, 0x344-0x353, 0x400-0x47F, 0x502-0x57F, 0x700-0x77F
+
If the Ernie version is less than 0x80300, second_loader refuses to boot.
   −
The protection it sets is 0x1C1F (so f00d read disabled).
+
== 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.
 +
 
 +
{| class="wikitable"
 +
|-
 +
! cmep keyring 0x50C !! [[KBL Param#Boot type indicator 1|KBL Param Boot type indicator 1]]
 +
|-
 +
| 0x4 || 0x1
 +
|-
 +
| 0x20 || 0x10000
 +
|-
 +
| 0x100 || 0x20000
 +
|-
 +
| 0x8 || no equivalent
 +
|}
 +
 
 +
== Boot process (3.60) ==
 +
 
 +
=== TODO ===
 +
 
 +
<pre>
 +
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();
 +
</pre>
 +
 
 +
=== EMMC and syscon init ===
 +
 
 +
<pre>
 +
  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;
 +
</pre>
 +
 
 +
emmc device (sdif0) is initialized. It sets keys for emmc crypto to be 0x20E/0x20F pair and protects them (<code>dword_E0030024 = 0x1FEF020F; dword_E0030024 = 0x1FEF020E; unk_E0070008 = 0x20E020F; unk_E0070000 = 0; unk_E0070000 = 1;</code>)
 +
 
 +
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 <code>set_emmc_hook</code> 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 ===
 +
 
 +
<pre>
 +
  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);
 +
</pre>
 +
 
 +
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 ===
 +
 
 +
<pre>
 +
  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);
 +
</pre>
 +
 
 +
Boot type is retrieved from syscon cmd 0x10, 0xFF14 on cold boot or 0xFF80 on resume boot.
 +
 
 +
=== TODO ===
 +
 
 +
<pre>
 +
  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);
 +
</pre>
 +
 
 +
=== Resume checks ===
 +
 
 +
<pre>
 +
  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);
 +
</pre>
 +
 
 +
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??? <code>sub_806B58(0x40000500LL, 0x1000LL);</code>???
 +
 
 +
=== Factory firmware check ===
 +
 
 +
<pre>
 +
  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);
 +
</pre>
 +
 
 +
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 ===
 +
 
 +
<pre>
 +
  ret = idps_and_openpsid_800B06();
 +
  v50 = ret;
 +
  if ( !ret )
 +
  {
 +
    set_status(95LL);
 +
</pre>
 +
 
 +
IDPS and OpenPSID are retrieved from idstorage and written to keyslots 0x509 and 0x50D.
 +
 
 +
=== TODO ===
 +
<pre>
 +
    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);
 +
</pre>
 +
 
 +
=== No-op ===
 +
 
 +
<pre>
 +
    ret = zero_801B0E();
 +
    v50 = ret;
 +
    if ( !ret )
 +
    {
 +
      set_status(71LL);
 +
</pre>
 +
 
 +
=== No-op ===
 +
 
 +
<pre>
 +
      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);
 +
</pre>
 +
 
 +
=== kbl decryption ===
 +
 
 +
<pre>
 +
      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);
 +
</pre>
 +
 
 +
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 ===
 +
 
 +
<pre>
 +
      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);
 +
</pre>
 +
 
 +
=== Check kbl version integrity ===
 +
 
 +
<pre>
 +
      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);
 +
</pre>
 +
 
 +
??? 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 ===
 +
 
 +
<pre>
 +
      if ( (_DWORD)is_resume || kbl_fw_version >= a3 )
 +
      {
 +
        set_status(90LL);
 +
</pre>
 +
 
 +
If coldboot, make sure that kbl version is not lower than factory firmware version.
 +
 
 +
=== Write KBL Param fields ===
 +
 
 +
<pre>
 +
        write_kbl_param_801C36((__int64)line_0x510, (__int64)line_0x50A, boot_type, is_resume, a3);
 +
        set_status(96LL);
 +
 
 +
</pre>
 +
 
 +
Writes most of KBL Param fields ???
 +
 
 +
=== TODO ===
 +
 
 +
<pre>
 +
        v29 = reads_pervasivevid_calls_syscon_0x88E_80899C(seven);
 +
        v50 = v29;
 +
        if ( (_DWORD)v29 )
 +
          report_error_808CAA(1LL, 76LL, v29, 0LL);
 +
        set_status(76LL);
 +
</pre>
 +
 
 +
=== Prepares to start ARM ===
 +
 
 +
<pre>
 +
        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);
 +
</pre>
 +
 
 +
Some dance with ARM clock/pervasive stuff ???
 +
 
 +
=== TODO ===
 +
 
 +
<pre>
 +
        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;
 +
}
 +
</pre>
 +
 
 +
== 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)
5,720

edits

Navigation menu