1bl Code
Jump to navigation
Jump to search
Pseudocode
Have not reversed all of the hardware error subroutines.
// version 0x583 #define STACK 0x800002000001F700 // r1 #define TOCP 0x8000020000000000 // r2 #define SRAM 0x8000020000010000 #define NAND 0x80000200C8000000 #define PCI 0x80000200D0000000 #define _HW_REG_POST 0x8000020000061010 #define _HW_REG_61008 0x8000020000061008 #define HW_REG_POST (*((volatile QWORD *)_HW_REG_POST)) #define HW_REG_61008 (*((volatile QWORD *)_HW_REG_61008)) #define BITMASK32(n) ((~0ul) >> 32-bits) #define BITMASK32_L(n) ~((~0ul) >> bits) // left justified bitmask, assumes the hardware makes bits shifted in 0 #define BITMASK64(n) ((~0ull) >> 64-bits) #define BITMASK64_L(n) ~((~0ull) >> bits) // left justified bitmask, assumes the hardware makes bits shifted in 0 #define ROTL32(data, bits) ((data << bits) | data >> 32-bits) & ~0ul #define ROTR32(data, bits) ((data >> bits) | data << 32-bits) & ~0ul #define ROTL64(data, bits) ((data << bits) | data >> 64-bits) & ~0ull #define ROTR64(data, bits) ((data >> bits) | data << 64-bits) & ~0ull BYTE Salt[0xB] = <redacted>; BYTE BLKey[0x10] = { <redacted> }; XECRYPT_RSAPUB_2048 xRSA; xRSA = <redacted> typedef struct _BLHeader { WORD Magic; // 0 : 2 WORD Version; // 2 : 2 DWORD Flags; // 4 : 4 DWORD EntryPoint; // 8 : 4 DWORD Size; // 0xC : 4 BYTE key[0x10]; // 0x10 : 0x10 QWORD Pad[4]; // 0x20 : 0x20 XECRYPT_SIG Sig; // 0x40 : 0x100 // Header: 0x140 }BLHeader, *PBLHeader; // write to the post bus void POST(QWORD postCode) { HW_REG_POST = (postCode << 56); } // outputs a given byte, then the same byte OR'ed with 0x80 // probably for their internal post sniffer void POST_DATA(BYTE outPost) { POST(outPost); POST(outPost | 0x80); } // outputs a given amount of bytes from a given address in high-low format void POST_ADDRESS(QWORD pqwAddy, DWORD cbAddy) { for(int i = 0;i < cbAddy;i++) { BYTE bData = *(BYTE*)pqwAddy+i; POST(data >> 4); // output high POST(data & 0xF); // output low } } void PanicGen() { while(1) continue; } void Panic(QWORD postCode) { POST(postCode); PanicGen(); } QWORD ReadHighestByte(QWORD Address) { return ((*(QWORD*)Address) >> 56); } DWORD sub_36A8() { DWORD ret = ReadHighestByte(HW_REG_61008); if((ret & 0x80) != 0) ret = (~ret) & 0xFF; return = ret & 0xF8; } // rough translation for the cntlzw instruction DWORD countLeadingZeros(DWORD data) { DWORD count = 0; for(int i = 0;i < 31;i++) { if(data >> 31-i) return count; count++; } } /* Basically this happens when its detected that the SOC doesn't carry correct values, it goes into a loop and starts outputting data from a certain SOC register (0x8000020000061008) - possibly error register? It doesn't repeat it's output unless the SOC register changes */ void HARDWARE_ERROR_PRINT(DWORD dwUnk1) { while(1) { BYTE bUnk1_p = ROTL32(dwUnk1, 3) & 0x1F; POST_DATA(bUnk1_p | 0x60); BYTE tmp = 0; BYTE bUnk1 = dwUnk1 & FF; if(bUnk1 == 0x78) tmp = 1; else { if(bUnk1 == 0) sub_3878(tmp); else if(bUnk1 == 8) sub_38B8(tmp); else if(bUnk1 == 0x10) sub_3AE0(tmp); else if(bUnk1 == 0x18) sub_3B30(tmp); else if(bUnk1 == 0x20) sub_3BB0(tmp); else if(bUnk1 == 0x28) sub_39C8(tmp); else if(bUnk1 == 0x30) sub_3F88(tmp, PCI + 0x8000); else if(bUnk1 == 0x38) sub_3C78(tmp); else if(bUnk1 == 0x40) sub_3D08(tmp); else if(bUnk1 == 0x48) sub_3DE0(tmp); else if(bUnk1 == 0x50) POST_ADDRESS(TOCP+2, 2); else if(bUnk1 == 0x58) sub_3F88(tmp, PCI); else if(bUnk1 == 0x60) sub_4008(tmp); tmp = 0; } POST_DATA(bUnk1_p | 0x70); DWORD r30 = (countLeadingZeros(bUnk1-0x50) >> 27) & 1; do { for(int i = 1;i < 6;i++) { DWORD dwUnk2 = sub_36A8(); if(dwUnk1 & 0xFF != dwUnk2 & 0xFF) { dwUnk1 = dwUnk2; i = 0; } } } while(((countLeadingZeros((dwUnk1 & 0xFF) - 0x50) >> 27) & 1) == r30); } } bool CB_VerifyOffset(DWORD offset, DWORD arg2) { if(offset != (offset + 0xF) & 0xFFFFFFF0) return false; if(offset - 0x80 > 0x7FFFF7F) return false; if((arg2 + 0xF) & 0xFFFFFFF0 >= offset - 0x8000000) return false; return true; } // Copies by 0x10 byte blocks // cBlocks: how many 0x10 byte blocks to copy void CB_Copy(QWORD dest, QWORD src, DWORD cBlocks) { for(int i = 0; i < cBlocks; i++) { *(QWORD*)dest+(i*0x10) = *(QWORD*)src+(i*0x10); *(QWORD*)dest+(i*0x10)+8 = *(QWORD*)src+(i*0x10)+8; } } void CB_Jump(QWORD address, QWORD arg2) { // grabs data from the CB before nulling the area QWORD r27 = *(QWORD*)SRAM+0x20; QWORD r28 = *(QWORD*)SRAM+0x28; QWORD r29 = *(QWORD*)SRAM+0x30; QWORD r30 = *(QWORD*)SRAM+0x38; // nulls 0x20-0x140(?) QWORD tmp = SRAM+0x20; for(int i = 0; i < 0x12; i++) { *tmp+(i*0x10) = 0ULL; *tmp+(i*0x10)+8 = 0ULL; } // check the size tmp = (((*(DWORD*)SRAM+0xC) + 0xF) & 0xFFFFFFF0); if(tmp >= 0x10000) Panic(0x98); // nulls the area after the CB QWORD addy = tmp + SRAM; for(int i = 0; i < (tmp - 0x10000) >> 4; i++) { *addy+(i*0x10) = 0ULL; *addy+(i*0x10)+8 = 0ULL; } // sets up tlb page // sets registers r0-r26 to 0 // jump to CB goto (address & 0xFFFF) + 0x2000000; return; } void CB_Load() { POST(0x11); FSB1(); // sub_3450 POST(0x12); FSB2(); // sub_34D0 POST(0x13); FSB3(); // sub_35A8 POST(0x14); FSB4(); // sub_3658 POST(0x15); DWORD cbOffset = *(DWORD*)NAND+8; // r25 if(!CB_VerifyOffset(cbOffset, 0x10)) Panic(0x94); POST(0x16); QWORD cbNAddy = NAND+cbOffset; // r26 CB_Copy(SRAM, cbNAddy, 1); POST(0x17); PBLHeader cbHeader = (PBLHeader)SRAM; if((cbHeader->Size - 0x264) > 0xBD9C || (cbHeader->Magic & 0xFFF) != 0x342 || (cbHeader->EntryPoint & 0x3) || (cbHeader->EntryPoint) < 0x264 // on slim its < 0x3B8 || (cbHeader->Size & 0xFFFFFFFC) >= (cbHeader->EntryPoint & 0x3) // doesn't make sense, check later offset 0x4340 - On slim it makes sense: if(entrypoint >= size & 0xFFFFFFFC) panic || !CB_VerifyOffset(cbOffset, cbHeader->Size)) Panic(0x95); POST(0x18); QWORD tmp = ((cbHeader->Size + 0xF) & 0xFFFFFFF0); CB_Copy(SRAM+0x10, cbNAddy+0x10, (tmp - 0x10) >> 4); POST(0x19); // overwrites the old key with the new one XeCryptHmacSha(BLKey, 0x10, &cbHeader->key, 0x10, 0, 0, 0, 0, &cbHeader->key, tmp); POST(0x1A); XECRYPT_RC4_STATE rc4; XeCryptRc4Key(&rc4, cbHeader->key, 0x10); // key = HmacSha(1BLKey, cbKey, 0x10) POST(0x1B); XeCryptRc4Ecb(&rc4, SRAM+0x20, tmp - 0x20); // Decrypts everything after the header POST(0x1C); BYTE Hash[0x14] = { 0 }; XeCryptRotSumSha(SRAM, 0x10, SRAM+0x140, tmp - 0x140, Hash, 0x14); // hashes everything after the sig POST(0x1D); if(XeCryptBnQwBeSigDifference(&cbHeader->Sig, Hash, Salt, &xRSA)) // checks sig against hash with public rsa key Panic(0x96); POST(0x1E); CB_Jump(cbHeader->EntryPoint, tmp+cbOffset); // sets up tbl page and loads some registers before jumping to cb return; } void BL_1() { // thread check? POST(0x10); // entered 1bl // null the sram area for(int i = 0; i < 0x1000; i++) { *(QWORD*)SRAM+(i*0x10) = 0ULL; *(QWORD*)SRAM+((i*0x10)+8) = 0ULL; } DWORD tmp = sub_36A8(); if((tmp & 0xFF) == 0x50) HARDWARE_ERROR_PRINT(tmp); // look into later // load and execute the CB CB_Load(); // CB_Load shouldn't return... PanicGen(); return; }