Second Loader: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
Line 291: Line 291:
     {
     {
       set_status(71LL);
       set_status(71LL);
</pre>
=== No-op ===
<pre>
       v50 = zero_801B24();
       v50 = zero_801B24();
       if ( v50 )
       if ( v50 )
Line 300: Line 305:
       }
       }
       set_status(73LL);
       set_status(73LL);
</pre>
=== kbl decryption ===
<pre>
       kbl_fw_version = 0;
       kbl_fw_version = 0;
       if ( (_DWORD)is_resume && (boot_type & 0x7F) != 0x17 )
       if ( (_DWORD)is_resume && (boot_type & 0x7F) != 0x17 )
Line 316: Line 326:
       }
       }
       set_status(89LL);
       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();
       syscon_unk_808C2A();
       print_info_log_800A5E();
       print_info_log_800A5E();

Revision as of 19:25, 22 June 2018

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.

TODO

  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);
  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_sysroot_801C0C();
    goto LBL_123;
  }
  if ( copy_sysroot_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, sysroot buffer 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_sysroot_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_sysroot_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);
    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);
      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 ( (_DWORD)is_resume || kbl_fw_version >= a3 )
      {
        set_status(90LL);
        write_sysroot_801C36((__int64)line_0x510, (__int64)line_0x50A, boot_type, is_resume, a3);
        set_status(96LL);
        v29 = reads_pervasivevid_calls_syscon_0x88E_80899C(seven);
        v50 = v29;
        if ( (_DWORD)v29 )
          report_error_808CAA(1LL, 0x4CLL, v29, 0LL);
        set_status(0x4CLL);
        v8 = prepare_to_start_arm_80878A(seven, *(unsigned int *)(unsigned int)&dword_80C698, 0LL);
        v50 = v8;
        if ( (_DWORD)v8 )
        {
          v9 = 0x4CLL;
          goto LABEL_21;
        }
        v30 = some_line;
        set_status(80LL);
        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;
}

eeprom protection

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

The protection it sets is 0x1C1F (so f00d read disabled).

Bypassing version checks

memeprom line 0x50B offset 0x4 bit 1 set = ignore version mismatch errors. This line itself is set from SNVS 0xD2 block 0. Alternatively set version to 0xDEADBEEF to skip.

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 sysroot buffer +0x100 (0x1F000200)