/* ras reference (ras2) -- named functions * generated by fw/ta_re.py -- do not edit * reference: ras2.elf * functions: 118 total in build, 116 named, 2 anonymous * porting tiers: {"DISPATCH": 0, "EXACT": 115, "FUZZY": 1, "MNEM": 0, "ambiguous": 2, "cmd_protos": 0, "comments": 133, "dispatch_conflict": 0, "none": 0, "protos": 114, "relabelled": 0, "types": 1} * * Addresses are omitted and functions are ordered by NAME so that the same * function lines up across versions. See the .index.json sidecar for * name -> address. * * CAUTION on ported names: a name is only an identity claim at tier=EXACT. * At tier=MNEM/FUZZY the bytes differ from the reference, so any ADDRESS or * CONTENT HASH embedded in the name (e.g. *_4025F8, gcp_lib__*) still * refers to the REFERENCE build and does not describe this one. */ /* ==== TA_CloseSessionEntryPoint [tier=EXACT size=18] ==== */ // GP command 4. Logs 'RAS deinitialized with status = 0x%x'. int __fastcall TA_CloseSessionEntryPoint() { int v0; // r0 v0 = ras_cb_4060A8(); return ras_log(a1: "RAS deinitialized with status = 0x%x", v0); } /* ==== TA_CreateEntryPoint [tier=EXACT size=4] ==== */ // GP command 1. Returns 0 (no per-instance init). int __fastcall TA_CreateEntryPoint() { return 0; } /* ==== TA_DestroyEntryPoint [tier=EXACT size=2] ==== */ // GP command 2. Empty (no teardown work). void __fastcall TA_DestroyEntryPoint() { ; } /* ==== TA_InvokeCommandEntryPoint [tier=EXACT size=184] ==== */ // GP command 5. Requires byte_4060E0 (initialised) else status 40974. // Commands: 0 ENABLE FEATURES, 1 DISABLE FEATURES, 2 TRIGGER ERROR, // 3 QUERY_BLOCK_INFO, 4 QUERY_SUB_BLOCK_INFO. int __fastcall TA_InvokeCommandEntryPoint(int a1, int a2, unsigned int a3, int a4) { int v6; // r0 int v7; // r5 int v8; // r4 int block_info; // r0 int v10; // r6 v6 = ras_map_shared_buffer(a1: a3, a2: a4, a3: off_402BC8); v7 = dword_402BCC; if ( v6 == 0 ) return dword_402BCC + 1; v8 = v6; ras_attach_response_buffer(a1: a3, a2: a4); if ( *off_402BD0 != 0 ) // switch 5 cases { // switch jump switch ( *(_DWORD *)v8 ) { case 0: ras_log(a1: off_402C44); // jumptable 00402B3E case 0 block_info = ras_cmd_enable_features(); goto LABEL_12; case 1: ras_log(a1: off_402C40[0]); // jumptable 00402B3E case 1 block_info = ras_cmd_disable_features(); goto LABEL_12; case 2: ras_log(a1: aInvokedCommand); // jumptable 00402B3E case 2 block_info = ras_cmd_trigger_error(); goto LABEL_12; case 3: ras_log(a1: aInvokedCommand_0); // jumptable 00402B3E case 3 block_info = ras_cmd_query_block_info(); goto LABEL_12; case 4: ras_log(a1: aInvokedCommand_1); // jumptable 00402B3E case 4 block_info = ras_cmd_query_sub_block_info(); LABEL_12: v10 = block_info; goto LABEL_13; default: v10 = 0; // jumptable 00402B3E default case goto LABEL_14; } } ras_log(a1: aRasTaNotInitia); v10 = 40974; LABEL_13: v7 = 0; LABEL_14: ras_log(a1: off_402C60, v10); *(_DWORD *)(v8 + 4) = *(_DWORD *)v8 | 0x80000000; *(_DWORD *)(v8 + 8) = v10; *(_DWORD *)(v8 + 12) = 0; ras_fill_response_footer(result: (_BYTE *)v8); ras_clear_reply_status(); return v7; } /* ==== TA_OpenSessionEntryPoint [tier=EXACT size=94] ==== */ // GP command 3. Maps the shared buffer, runs ras_device_register then ras_init; // sets the initialised flag byte_4060E0 on success. int __fastcall TA_OpenSessionEntryPoint(unsigned int a1, int a2) { int v4; // r0 int v5; // r4 int v6; // r0 int v7; // r5 v4 = ras_map_shared_buffer(a1, a2, a3: off_402CC4); if ( v4 == 0 ) return dword_402CC8; v5 = v4; ras_attach_response_buffer(a1, a2); ras_auth_check(); v6 = ras_device_register(); if ( v6 != 0 ) { v7 = v6; ras_log(a1: aRasCtxInitiali); } else { v7 = ras_init(); } ras_log(a1: "RAS initialized with status = 0x%X", v7); *(_DWORD *)(v5 + 8) = v7; *(_DWORD *)(v5 + 12) = 0; if ( v7 == 0 ) *off_402D10 = 1; ras_fill_response_footer(result: (_BYTE *)v5); ras_clear_reply_status(); return 0; } /* ==== aeabi_d2f_pack [tier=EXACT size=228] ==== */ // Double->float repacking helper (exponent bias 30720 adjust). unsigned int __fastcall aeabi_d2f_pack(int a1, unsigned int a2) { bool v2; // cf bool v3; // zf int v4; // r12 unsigned int v5; // r2 signed int v6; // r1 unsigned int v7; // r0 unsigned int result; // r0 int v9; // r12 int v10; // r12 unsigned int v11; // r1 int v12; // r12 v2 = __CFSHL__(a1, 1); v4 = 2 * a1; v3 = 2 * a1 == 0; if ( 2 * a1 == 0 ) v3 = a2 == 0; v5 = a2 << 11; v6 = (a1 << 11) | (a2 >> 21); v7 = (unsigned int)v4 >> 20; if ( !v3 ) v7 += 30720; result = (v7 >> 1) | (v2 << 31); if ( !v3 ) v6 |= 0x80000000; v9 = v4 >> 21; if ( v9 != 0 ) { if ( v9 == -1 ) result |= 0x40000000u; } else if ( v6 < 0 ) { v11 = v6 & 0x7FFFFFFF; if ( v11 != 0 ) { if ( HIWORD(v11) != 0 ) { v12 = 0; } else { v11 <<= 16; v12 = 16; } if ( HIBYTE(v11) == 0 ) { v11 <<= 8; v12 += 8; } if ( v11 >> 28 == 0 ) { v11 *= 16; v12 += 4; } if ( v11 >> 30 == 0 ) { v11 *= 4; v12 += 2; } if ( (v11 & 0x80000000) == 0 ) ++v12; return result - v12 + 1; } else { if ( HIWORD(v5) != 0 ) { v10 = 0; } else { v5 <<= 16; v10 = 16; } if ( HIBYTE(v5) == 0 ) { v5 <<= 8; v10 += 8; } if ( v5 >> 28 == 0 ) { v5 *= 16; v10 += 4; } if ( v5 >> 30 == 0 ) { v5 *= 4; v10 += 2; } if ( (v5 & 0x80000000) == 0 ) ++v10; return result - 31 - v10; } } return result; } /* ==== aeabi_dbl_classify [tier=EXACT size=48] ==== */ // Classifies an IEEE-754 double (zero / subnormal / infinity / NaN) into a small code. unsigned int __fastcall aeabi_dbl_classify(int a1, int a2) { unsigned int v2; // r1 unsigned int result; // r0 v2 = 2 * a2; result = a1 | (v2 << 11); if ( result != 0 ) result = 4; if ( v2 >> 21 != 0 ) result |= 1u; if ( v2 >> 21 == 2047 ) result |= 2u; if ( result == 1 ) return 5; return result; } /* ==== aeabi_dbl_decompose [tier=EXACT size=434] ==== */ // Decomposes an IEEE-754 double (exponent (hi>>20)&0x7FF, mantissa) for formatting. int *__fastcall aeabi_dbl_decompose(int *a1, _BYTE *a2, unsigned int *a3, int a4, int a5) { int v5; // r11 int v7; // r6 int v8; // r8 unsigned int v9; // r10 int v10; // r5 int v11; // r7 int v12; // r5 int v13; // r1 int *result; // r0 int v15; // r2 int *v16; // r1 unsigned int v17; // r0 int v18; // r1 int v19; // r2 unsigned __int64 v20; // r0 int v21; // r2 int j; // r5 int i; // r5 char v24; // r2 int v25; // r2 char v26; // r2 int v27; // r1 int k; // r0 char v29; // r2 int v30; // r2 unsigned __int64 v31; // [sp+0h] [bp-3Ch] BYREF int v32; // [sp+8h] [bp-34h] int v33[3]; // [sp+Ch] [bp-30h] BYREF _DWORD v34[3]; // [sp+18h] [bp-24h] BYREF int v35; // [sp+24h] [bp-18h] unsigned int v36; // [sp+28h] [bp-14h] int *v37; // [sp+2Ch] [bp-10h] _BYTE *v38; // [sp+30h] [bp-Ch] unsigned int *v39; // [sp+34h] [bp-8h] int v40; // [sp+38h] [bp-4h] v37 = a1; v38 = a2; v39 = a3; v40 = a4; v7 = a4; v8 = a5; v9 = a3[1]; v36 = *a3; v10 = (v9 >> 20) & 0x7FF; if ( v10 == 0 ) LOWORD(v10) = -1; if ( (v36 | (2 * v9)) != 0 ) { v11 = (19728 * (__int16)(v10 - 1023)) >> 16; while ( 1 ) { while ( 1 ) { if ( v8 != 0 ) v12 = -v7; else v12 = v11 - v7 + 1; v13 = v12; if ( v12 < 0 ) v13 = -v12; aeabi_dbl_scale(a1: (int)v34, a2: v13, a3: 0); v33[0] = v34[0]; v33[1] = v34[1]; v33[2] = v34[2]; v17 = aeabi_d2f_pack(a1: v9, a2: v36); HIDWORD(v31) = v18; v32 = v19; LODWORD(v31) = v17 - 8223; if ( v12 <= 0 ) { v33[0] -= 8223; LODWORD(v20) = aeabi_dbl_op_a(a1: (unsigned int *)&v31, a2: v33); } else { v33[0] += 8223; LODWORD(v20) = aeabi_dbl_op_b(a1: (unsigned int *)&v31, a2: v33); } v31 = v20; v32 = v21; if ( (_WORD)v20 != 0 ) v20 = 0x7FFFFFFFFFFFFFFFLL; else LODWORD(v20) = v21; if ( v8 != 0 ) break; for ( i = v7 - 1; i >= 0; --i ) { v20 = udiv10(a1: v20); a2[i] = v24 + 48; } v5 = v7; v25 = 1; if ( v20 != 0 ) { v25 = 0; ++v11; } else if ( *a2 == 48 ) { v25 = 0; --v11; } v35 = v11; if ( v25 != 0 ) goto LABEL_43; } LODWORD(v31) = 0; for ( j = 0; v20 != 0 && j < 17; ++j ) { v20 = udiv10(a1: v20); a2[j] = v26 + 48; } if ( v20 == 0 ) break; if ( (_DWORD)v31 != 0 ) goto LABEL_43; v7 = 17; v8 = 0; } v27 = 0; for ( k = j - 1; v27 < k; --k ) { v29 = a2[v27]; a2[v27] = a2[k]; a2[k] = v29; ++v27; } v5 = j; v35 = j - v7 - 1; LABEL_43: a2[v5] = 0; result = v37; v30 = v35; v37[2] = v8; *result = v30; result[1] = v5; } else { result = nullptr; if ( a5 == 1 ) { v15 = ~a4; } else { while ( (int)result < a4 ) { *((_BYTE *)result + (_DWORD)a2) = 48; result = (int *)((char *)result + 1); } result = (int *)a4; v15 = 0; } *((_BYTE *)result + (_DWORD)a2) = 0; v16 = v37; v37[2] = a5; *v16 = v15; v16[1] = (int)result; } return result; } /* ==== aeabi_dbl_op_a [tier=EXACT size=42] ==== */ // Soft-float double helper (checks the 0x40000000 exponent bit then combines via the sign // and shift helpers). unsigned int __fastcall aeabi_dbl_op_a(unsigned int *a1, int *a2) { int v2; // r3 unsigned int result; // r0 int v4; // r1 int v5; // r2 int *v6; // t0 bool v7; // zf unsigned int v8; // r0 unsigned int v9; // r1 unsigned int v10; // r2 int v11; // r3 v2 = *a2; v6 = (int *)a1; result = *a1; v4 = *++v6; v5 = v6[1]; v7 = (result & 0x40000000) == 0; if ( (result & 0x40000000) == 0 ) v7 = (v2 & 0x40000000) == 0; if ( v7 ) { v8 = aeabi_dcmp_sign(a1: result, a2: v4, a3: v5, a4: v2); return aeabi_lshift_merge(a1: v8, a2: v9, a3: v10, a4: v11); } return result; } /* ==== aeabi_dbl_op_b [tier=EXACT size=42] ==== */ // Soft-float double comparison/normalisation helper. unsigned int __fastcall aeabi_dbl_op_b(unsigned int *a1, int *a2) { int v2; // r3 int v3; // r4 unsigned int result; // r0 int v5; // r1 int v6; // r2 int *v7; // t0 bool v8; // nf unsigned int v9; // r0 unsigned int v10; // r1 unsigned int v11; // r2 int v12; // r3 v2 = *a2; v3 = a2[1]; v7 = (int *)a1; result = *a1; v5 = *++v7; v6 = v7[1]; v8 = (*v7 & ~(2 * result) & 0x80000000) != 0; if ( (*v7 & ~(2 * result) & 0x80000000) != 0 ) v8 = (v3 & ~(2 * v2)) < 0; if ( v8 ) { v9 = aeabi_fcmp_sign(a1: result, a2: v5, a3: v6, a4: v2); return aeabi_lshift_merge(a1: v9, a2: v10, a3: v11, a4: v12); } return result; } /* ==== aeabi_dbl_scale [tier=EXACT size=218] ==== */ // Scales a double by a power of ten for %f/%e formatting. int __fastcall aeabi_dbl_scale(int a1, int a2, int a3) { int v5; // r2 int v6; // r3 int *v7; // r2 unsigned int v8; // r0 unsigned int v9; // r2 int v10; // r3 int *v11; // t0 unsigned int v12; // r0 int v13; // r1 int v14; // r4 int v15; // r5 int v16; // r0 int v17; // r8 int v18; // r7 int *v19; // r10 __int64 v20; // r0 int v21; // r2 int *v22; // r7 int *v23; // r0 int v24; // r2 int v25; // r3 unsigned int v26; // r1 int v27; // r2 __int64 v28; // r0 int v29; // r2 __int64 v31; // [sp+0h] [bp-28h] BYREF int v32; // [sp+8h] [bp-20h] unsigned int v33[2]; // [sp+Ch] [bp-1Ch] BYREF int v34; // [sp+14h] [bp-14h] int v35[2]; // [sp+18h] [bp-10h] BYREF int v36; // [sp+20h] [bp-8h] v5 = (*off_4027AC)[1051065]; v6 = (*off_4027AC)[1051066]; LODWORD(v31) = (*off_4027AC)[1051064]; HIDWORD(v31) = v5; v32 = v6; v7 = &(*off_4027AC)[1051067]; v8 = *v7; v11 = v7 + 1; v9 = v7[1]; v10 = v11[1]; v33[0] = v8; v33[1] = v9; v34 = v10; v12 = (a2 + 7067) / 0x37u; v14 = v13 - 27; v15 = v12 - 128; if ( v13 - 27 >= 0 ) { v16 = 0; } else { v14 = 27 - v13; v16 = 1; } v17 = v16; v18 = 0; v19 = &(*off_4027AC)[1051033]; while ( v14 != 0 ) { if ( v14 << 31 != 0 ) { LODWORD(v20) = aeabi_dbl_op_a(a1: (unsigned int *)&v31, a2: &v19[3 * v18]); v31 = v20; v32 = v21; } v14 >>= 1; ++v18; } v22 = &(*off_4027AC)[1051048]; while ( v15 != 0 ) { if ( v15 << 31 != 0 ) { v23 = &v22[4 * v14]; v24 = v23[1]; v25 = v23[2]; v35[0] = *v23; v35[1] = v24; v36 = v25; if ( v23[3] + a3 == 0 ) v36 = v25 + a3; v33[0] = aeabi_dbl_op_a(a1: v33, a2: v35); v33[1] = v26; v34 = v27; } v15 >>= 1; ++v14; } if ( v17 != 0 ) LODWORD(v28) = aeabi_dbl_op_b(a1: v33, a2: (int *)&v31); else LODWORD(v28) = aeabi_dbl_op_a(a1: v33, a2: (int *)&v31); *(_QWORD *)a1 = v28; *(_DWORD *)(a1 + 8) = v29; return v28; } /* ==== aeabi_dbl_scale_thunk [tier=EXACT size=16] ==== */ // Sets the scale exponent then tail-calls aeabi_dbl_scale. int __fastcall aeabi_dbl_scale_thunk(int a1, int a2, int a3) { int v3; // r5 *(_DWORD *)(v3 + 20) = 2 * a2; return aeabi_dbl_scale(a1, a2: *(_DWORD *)(v3 + 100), a3); } /* ==== aeabi_dcmp_sign [tier=EXACT size=580] ==== */ // Double helper: returns the XOR of the sign bits. unsigned int __fastcall aeabi_dcmp_sign(int a1, int a2, int a3, int a4) { return (a1 ^ a4) & 0x80000000; } /* ==== aeabi_fcmp_sign [tier=EXACT size=696] ==== */ // Float helper: returns the XOR of the sign bits. unsigned int __fastcall aeabi_fcmp_sign(int a1, int a2, int a3, int a4) { return (a1 ^ a4) & 0x80000000; } /* ==== aeabi_llsl [tier=EXACT size=38] ==== */ // 64-bit logical left shift. int __fastcall aeabi_llsl(int a1, int a2, int a3) { if ( a3 - 32 >= 0 ) return 0; else return a1 << a3; } /* ==== aeabi_llsr [tier=EXACT size=38] ==== */ // 64-bit logical right shift. unsigned int __fastcall aeabi_llsr(unsigned int a1, unsigned int a2, int a3) { if ( a3 - 32 >= 0 ) return a2 >> (a3 - 32); else return (a1 >> a3) | (a2 << (32 - a3)); } /* ==== aeabi_lshift_merge [tier=EXACT size=220] ==== */ // Multi-word shift/merge helper used by the soft-float routines. unsigned int __fastcall aeabi_lshift_merge(int a1, unsigned int a2, unsigned int a3, int a4) { unsigned int v4; // r6 int v5; // r11 bool v6; // cf unsigned int v7; // r7 int v8; // r7 int v9; // r11 bool v10; // cf if ( a4 < 0 ) { v4 = (v4 | (v4 << 16)) >> 16; if ( a4 <= -64 ) { v4 = ((v4 | a3 | ((v4 | a3) << 16)) >> 16) | a2; if ( a4 < -64 ) v4 = (v4 | (v4 << 16)) >> 16; a4 = 0; a3 = 0; a2 = 0; } else { if ( a4 <= -32 ) { v4 |= a3; a3 = a2; a2 = 0; a4 += 32; } a4 = -a4; if ( a4 != 0 ) { v4 = ((v4 | (v4 << 16)) >> 16) | (a3 << (32 - a4)); a3 = (a3 >> a4) | (a2 << (32 - a4)); a2 >>= a4; a4 = 0; } } } v6 = __CFSHL__(v4, 1); v7 = 2 * v4; if ( 2 * v4 == 0 ) { if ( !__CFSHL__(v4, 1) ) return a4 | a1 & 0x80000000; v6 = a3 & 1; v7 = a3 >> 1; } v8 = (v7 >> 1) | (v6 << 31); v9 = v5 + 1; v10 = v9 != 0; if ( v9 == 1 ) v10 = __CFSHR__(v8, 32); if ( v10 ) { v10 = __CFADD__(a3, 1); if ( a3 == -1 ) v10 = __CFADD__(a2, 1); } a4 += v10; return a4 | a1 & 0x80000000; } /* ==== aeabi_uidiv [tier=EXACT size=392] ==== */ // Unsigned 32-bit division by shift/subtract. unsigned int __fastcall aeabi_uidiv(unsigned int a1, unsigned int a2) { unsigned int v2; // r2 int v3; // r12 bool v4; // cf BOOL v5; // r2 bool v6; // cf int v7; // r2 bool v8; // cf int v9; // r2 bool v10; // cf bool v11; // cf unsigned int v12; // r2 bool v13; // cf unsigned int v14; // r2 bool v15; // cf unsigned int result; // r0 char v17; // cf bool v18; // cf unsigned int v19; // r2 bool v20; // cf unsigned int v21; // r2 bool v22; // cf unsigned int v23; // r2 bool v24; // cf bool v25; // cf unsigned int v26; // r2 bool v27; // cf unsigned int v28; // off bool v29; // cf unsigned int v30; // r1 if ( ((a1 | a2) & 0x80000000) == 0 ) { v2 = 0; if ( a1 >> 1 >= a2 ) { if ( a1 >> 4 >= a2 ) { if ( a1 >> 8 >= a2 ) { v3 = 0; goto LABEL_29; } v4 = a1 >> 7 >= a2; if ( a1 >> 7 >= a2 ) a1 -= a2 << 7; v5 = v4; v6 = a1 >> 6 >= a2; if ( a1 >> 6 >= a2 ) a1 -= a2 << 6; v7 = v5 + v6 + v5; v8 = a1 >> 5 >= a2; if ( a1 >> 5 >= a2 ) a1 -= 32 * a2; v9 = v7 + v8 + v7; v10 = a1 >> 4 >= a2; if ( a1 >> 4 >= a2 ) a1 -= 16 * a2; v2 = v9 + v10 + v9; } v11 = a1 >> 3 >= a2; if ( a1 >> 3 >= a2 ) a1 -= 8 * a2; v12 = v2 + v11 + v2; v13 = a1 >> 2 >= a2; if ( a1 >> 2 >= a2 ) a1 -= 4 * a2; v14 = v12 + v13 + v12; v15 = a1 >> 1 >= a2; if ( a1 >> 1 >= a2 ) a1 -= 2 * a2; v2 = v14 + v15 + v14; } return v2 + (a1 >= a2) + v2; } v2 = a2 & 0x80000000; if ( (a2 & 0x80000000) != 0 ) a2 = -a2; v3 = v2 ^ ((int)a1 >> 31); if ( (a1 & 0x80000000) != 0 ) a1 = -a1; if ( a1 >> 4 < a2 ) goto LABEL_45; if ( a1 >> 8 < a2 ) goto LABEL_36; LABEL_29: a2 <<= 6; v2 |= 0xFC000000; if ( a1 >> 8 < a2 ) goto LABEL_36; a2 <<= 6; v2 |= 0x3F00000u; if ( a1 >> 8 < a2 ) goto LABEL_36; a2 <<= 6; v2 |= 0xFC000u; if ( a1 >> 8 >= a2 ) { a2 <<= 6; v2 |= 0x3F00u; } v17 = a2 == 0; if ( a2 != 0 ) { do { if ( v17 ) a2 >>= 6; LABEL_36: v18 = a1 >> 7 >= a2; if ( a1 >> 7 >= a2 ) a1 -= a2 << 7; v19 = v2 + v18 + v2; v20 = a1 >> 6 >= a2; if ( a1 >> 6 >= a2 ) a1 -= a2 << 6; v21 = v19 + v20 + v19; v22 = a1 >> 5 >= a2; if ( a1 >> 5 >= a2 ) a1 -= 32 * a2; v23 = v21 + v22 + v21; v24 = a1 >> 4 >= a2; if ( a1 >> 4 >= a2 ) a1 -= 16 * a2; v2 = v23 + v24 + v23; LABEL_45: v25 = a1 >> 3 >= a2; if ( a1 >> 3 >= a2 ) a1 -= 8 * a2; v26 = v2 + v25 + v2; v27 = a1 >> 2 >= a2; if ( a1 >> 2 >= a2 ) a1 -= 4 * a2; v28 = v27 + v26; v17 = __CFADD__(v27, v26) | __CFADD__(v26, v28); v2 = v26 + v28; } while ( v17 ); v29 = a1 >> 1 >= a2; if ( a1 >> 1 >= a2 ) a1 -= 2 * a2; result = v2 + v29 + v2 + (a1 >= a2) + v2 + v29 + v2; if ( v3 < 0 ) return -result; } else { if ( v3 < 0 ) a1 = -a1; v30 = a1 & 0x80000000; if ( (int)a1 > 0 ) return 0x7FFFFFFF; return v30; } return result; } /* ==== aeabi_uidiv_dispatch [tier=EXACT size=36] ==== */ // Selects the division shift-loop entry by operand magnitude. void __fastcall aeabi_uidiv_dispatch(unsigned int a1, unsigned int a2) { if ( a1 >> 2 >= a2 ) { if ( a1 >> 5 >= a2 ) { if ( a1 >> 8 >= a2 ) JUMPOUT(0x401668); JUMPOUT(0x4015E4); } JUMPOUT(0x401608); } JUMPOUT(0x40162C); } /* ==== aeabi_uldivmod [tier=EXACT size=756] ==== */ // Unsigned 64-bit divide/modulo (CLZ-normalised restoring division). int __fastcall aeabi_uldivmod(unsigned __int64 a1, unsigned int a2, unsigned int a3) { unsigned __int64 v5; // r2 bool v6; // zf bool v7; // nf unsigned int v8; // r12 int v9; // lr unsigned int v10; // r12 bool v11; // zf unsigned int v12; // r1 unsigned int v13; // r6 unsigned int v14; // r12 bool v15; // cc char v16; // r6 unsigned __int64 v17; // r0 unsigned int v18; // r1 unsigned int v19; // r12 unsigned __int64 v20; // r0 unsigned int v21; // r1 unsigned int v22; // r12 unsigned __int64 v23; // r0 unsigned int v24; // r1 __int64 v25; // r0 __int64 v26; // r0 unsigned __int64 v27; // r2 char v28; // cf unsigned int v29; // r4 unsigned int v30; // r6 unsigned int v31; // r2 unsigned int v32; // r2 unsigned __int64 v33; // r0 bool v34; // cf __int64 v35; // r0 __int64 v36; // r0 unsigned int v37; // r1 unsigned int v38; // r12 __int64 v39; // r0 __int64 v40; // r0 unsigned int v41; // r1 unsigned int v42; // r12 int v43; // r0 unsigned __int64 v44; // r2 bool v45; // cf unsigned int v46; // r6 unsigned __int64 v47; // r2 bool v48; // cf unsigned int v49; // r4 unsigned int i; // r5 bool v51; // cf v5 = a1; v6 = a3 == 0; v7 = (a3 & 0x80000000) != 0; if ( a3 != 0 ) v8 = a3; else v8 = a2; v9 = __clz(v8); v10 = v8 << (v9 + 1); if ( a3 != 0 ) { v9 = 63 - v9; v6 = v9 == 0; v7 = v9 < 0; } if ( v6 ) { v9 = 31 - v9; v7 = v9 < 0; } if ( v7 ) { if ( a1 != 0 ) HIDWORD(a1) = -1; LODWORD(a1) = HIDWORD(a1); } else { v11 = HIDWORD(a1) == 0; if ( HIDWORD(a1) != 0 ) { v12 = 63 - __clz(HIDWORD(a1)); v11 = v12 == 0; } else { v12 = __clz(a1); } if ( v11 ) v12 = 31 - v12; v13 = v12 - v9; if ( (int)(v12 - v9) < 0 ) { LODWORD(a1) = 0; } else if ( (int)(4 - v13) < 0 ) { if ( v9 - 32 <= 4 ) v10 |= a2 >> (v9 - 32); v14 = *((_DWORD *)&unk_401384 + (v10 >> 28)); v15 = (unsigned int)v9 > 0x1F; if ( (unsigned int)v9 > 0x1F ) LOBYTE(v9) = v9 - 32; v16 = 32 - v9; if ( v15 ) { LODWORD(v35) = 0; HIDWORD(v35) = v14 * a2; v36 = v14 * (unsigned __int64)a3 + v35; v37 = -((HIDWORD(v36) << v16) | ((unsigned int)v36 >> v9)); if ( (_DWORD)v36 << (32 - v9) != 0 ) --v37; v38 = v14 + ((v14 * (unsigned __int64)v37) >> 32); LODWORD(v39) = 0; HIDWORD(v39) = v38 * a2; v40 = v38 * (unsigned __int64)a3 + v39; v41 = -((HIDWORD(v40) << (32 - v9)) | ((unsigned int)v40 >> v9)); if ( (_DWORD)v40 << (32 - v9) != 0 ) --v41; v42 = v38 + ((v38 * (unsigned __int64)v41) >> 32) - 1; v43 = 0; HIDWORD(a1) = v42 * v5; LODWORD(a1) = (unsigned int)((v42 * (unsigned __int64)HIDWORD(v5) + a1) >> 32) >> v9; v44 = v5 - __PAIR64__(a3, a2) * (unsigned int)a1; v45 = HIDWORD(v44) >= a3; if ( HIDWORD(v44) == a3 ) v45 = (unsigned int)v44 >= a2; if ( v45 ) { v46 = (unsigned int)((v42 * (unsigned __int64)HIDWORD(v44) + ((v42 * (unsigned __int64)(unsigned int)v44) >> 32)) >> 32) >> v9; LODWORD(a1) = a1 + v46; v47 = v44 - __PAIR64__(a3, a2) * v46; v48 = HIDWORD(v47) >= a3; if ( HIDWORD(v47) == a3 ) v48 = (unsigned int)v47 >= a2; if ( v48 ) LODWORD(a1) = a1 + 1; } } else { v17 = v14 * (unsigned __int64)a2; v18 = -((HIDWORD(v17) << v16) | ((unsigned int)v17 >> v9)); if ( (_DWORD)v17 << v16 != 0 ) --v18; v19 = v14 + ((v14 * (unsigned __int64)v18) >> 32); v20 = v19 * (unsigned __int64)a2; v21 = -((HIDWORD(v20) << v16) | ((unsigned int)v20 >> v9)); if ( (_DWORD)v20 << v16 != 0 ) --v21; v22 = v19 + ((v19 * (unsigned __int64)v21) >> 32); if ( HIDWORD(v5) != 0 ) { v23 = v22 * (unsigned __int64)a2; v24 = -((HIDWORD(v23) << v16) | ((unsigned int)v23 >> v9)); if ( (_DWORD)v23 << v16 != 0 ) --v24; v22 += (v22 * (unsigned __int64)v24) >> 32; } LODWORD(v25) = 0; HIDWORD(v25) = v22 * v5; v26 = v22 * (unsigned __int64)HIDWORD(v5) + v25; LODWORD(a1) = ((unsigned int)v26 >> v9) | (HIDWORD(v26) << v16); HIDWORD(a1) = HIDWORD(v26) >> v9; v27 = v5 - a1 * a2; v28 = HIDWORD(v27) != 0; if ( HIDWORD(v27) == 0 ) v28 = (unsigned int)v27 >= a2; if ( v28 ) { v29 = (v22 * (unsigned __int64)HIDWORD(v27) + ((v22 * (unsigned __int64)(unsigned int)v27) >> 32)) >> 32; v30 = ((unsigned int)((v27 * v22) >> 32) >> v9) | (v29 << (32 - v9)); a1 += __PAIR64__(v29 >> v9, v30); v31 = v27 - v30 * a2; if ( v31 >= a2 ) { v32 = v31 - a2; v33 = a1 + 1; v34 = v32 >= a2; if ( v32 >= a2 ) v32 -= a2; return v33 + v34 + (v32 >= a2); } } } } else { LODWORD(a1) = 0; v49 = (a3 << v13) | (a2 >> (32 - v13)); for ( i = a2 << v13; ; i = (i >> 1) | (v28 << 31) ) { v51 = v5 >= __PAIR64__(v49, i); if ( v5 >= __PAIR64__(v49, i) ) v5 -= __PAIR64__(v49, i); LODWORD(a1) = a1 + v51 + (_DWORD)a1; v28 = v13-- != 0; if ( !v28 ) break; v28 = v49 & 1; v49 >>= 1; } } } return a1; } /* ==== bzero [tier=EXACT size=68] ==== */ // Byte-granular zero fill; aligns to 4 then tail-calls bzero_core. _BYTE *__fastcall bzero(_BYTE *result, unsigned int a2) { int v2; // r12 _BYTE *v3; // r0 if ( a2 >= 4 ) { if ( ((unsigned __int8)result & 3) != 0 ) { v2 = 4 - ((unsigned __int8)result & 3); if ( v2 != 2 ) *result++ = 0; if ( v2 >= 2 ) *(_WORD *)result = 0; } JUMPOUT(0x40156C); } if ( __CFSHL__(a2, 31) ) { *result = 0; v3 = result + 1; *v3 = 0; result = v3 + 1; } if ( (a2 & 1) != 0 ) *result++ = 0; return result; } /* ==== bzero_core [tier=EXACT size=78] ==== */ // Zero-fill helper (32-byte unrolled), same SDK routine as the other modules. _DWORD *__fastcall bzero_core(_DWORD *result, unsigned int a2) { bool v2; // cf unsigned int v3; // r1 _DWORD *v4; // r0 int v5; // r1 int v6; // r1 v2 = a2 >= 0x20; v3 = a2 - 32; do { if ( !v2 ) break; *result = 0; result[1] = 0; result[2] = 0; result[3] = 0; v4 = result + 4; *v4 = 0; v4[1] = 0; v4[2] = 0; v4[3] = 0; result = v4 + 4; v2 = v3 >= 0x20; v3 -= 32; } while ( v2 ); v2 = __CFSHL__(v3, 28); v5 = v3 << 28; if ( v2 ) { *result = 0; result[1] = 0; result[2] = 0; result[3] = 0; result += 4; } if ( v5 < 0 ) { *result = 0; result[1] = 0; result += 2; } v2 = __CFSHL__(v5, 2); v6 = 4 * v5; if ( v2 ) *result++ = 0; if ( v6 != 0 ) { if ( v6 < 0 ) { *(_WORD *)result = 0; result = (_DWORD *)((char *)result + 2); } if ( (v6 & 0x40000000) != 0 ) { *(_BYTE *)result = 0; return (_DWORD *)((char *)result + 1); } } return result; } /* ==== is_digit [tier=EXACT size=14] ==== */ // Returns true for ASCII '0'..'9'. BOOL __fastcall is_digit(int a1) { return (unsigned int)(a1 - 48) < 0xA; } /* ==== memcmp_be [tier=EXACT size=88] ==== */ // Big-endian memcmp, 4 bytes at a time via bswap32. Same SDK routine as in HDCP and ASD. int __fastcall memcmp_be(unsigned int *a1, unsigned int *a2, unsigned int a3) { unsigned int v3; // r4 unsigned int v4; // r3 int v6; // r3 int v7; // t1 int v8; // t1 int v9; // r3 int v10; // r3 int v11; // t1 int v12; // t1 if ( ((unsigned int)a1 | (unsigned int)a2) << 30 == 0 ) { while ( a3 >= 4 ) { v3 = *a1++; v4 = *a2++; a3 -= 4; if ( v3 != v4 ) { if ( bswap32(v3) <= bswap32(v4) ) return -1; else return 1; } } } if ( a3 == 0 ) return 0; if ( a3 << 31 == 0 ) goto LABEL_11; ++a3; do { v11 = *(unsigned __int8 *)a1; a1 = (unsigned int *)((char *)a1 + 1); v10 = v11; v12 = *(unsigned __int8 *)a2; a2 = (unsigned int *)((char *)a2 + 1); v9 = v10 - v12; if ( v9 != 0 ) break; a3 -= 2; if ( a3 == 0 ) break; LABEL_11: v7 = *(unsigned __int8 *)a1; a1 = (unsigned int *)((char *)a1 + 1); v6 = v7; v8 = *(unsigned __int8 *)a2; a2 = (unsigned int *)((char *)a2 + 1); v9 = v6 - v8; } while ( v9 == 0 ); return v9; } /* ==== ras_apply_gfx_feature [tier=EXACT size=38] ==== */ // Applies a GFX RAS feature when the request selector is 2 (via ras_gfx_mode_config); // returns 40962 on a null request. int __fastcall ras_apply_gfx_feature(_DWORD *a1) { int v2; // r4 if ( a1 == nullptr ) return 40962; if ( *a1 != 2 ) return 0; v2 = ras_gfx_mode_config(); ras_set_state_byte(result: 2u, a2: 0); return v2; } /* ==== ras_asic_name_lookup [tier=EXACT size=72] ==== */ // Resolves the ASIC name string (e.g. 'pGVega20'). BOOL __fastcall ras_asic_name_lookup(int a1, int a2, unsigned __int8 a3, _DWORD *a4) { *a4 = 1; return ras_cb_4060C4(a1: 2, a2, a3); } /* ==== ras_asic_name_lookup_v2 [tier=FUZZY size=56] ==== */ // switch 7 cases char *__fastcall ras_asic_name_lookup_v2(int a1) { char *result; // r0 switch ( a1 ) { case 22: result = aNavi12; // jumptable 00402E48 case 22 break; case 23: case 26: case 27: goto LABEL_7; // switch jump case 24: result = aMi100; // jumptable 00402E48 case 24 break; case 25: result = aNavi21; // jumptable 00402E48 case 25 break; case 28: result = aMi200; // jumptable 00402E48 case 28 break; default: if ( a1 == 5 ) // jumptable 00402E48 default case { result = aVega20; } else if ( a1 == 49 ) { result = aNavi31; } else { LABEL_7: result = (char *)ras_get_time_us_thunk; // jumptable 00402E48 cases 23,26,27 } break; } return result; } /* ==== ras_asic_tbl_lookup_404CE8 [tier=EXACT size=34] ==== */ // ASIC-table lookup against dword_404CE8. int *__fastcall ras_asic_tbl_lookup_404CE8(int a1, _BYTE *a2, unsigned __int8 a3, _DWORD *a4) { if ( a2 != nullptr && *a2 != 0 && ras_asic_name_lookup(a1: (int)&(*off_404700)[1053115] + 2, (int)a2, a3, a4) ) return nullptr; else return (int *)((char *)&(*off_404704)[1053119] + 2); } /* ==== ras_asic_tbl_lookup_404D04 [tier=EXACT size=34] ==== */ // ASIC-table lookup against dword_404D04; returns NULL on match. char *__fastcall ras_asic_tbl_lookup_404D04(int a1, _BYTE *a2, unsigned __int8 a3, _DWORD *a4) { if ( a2 != nullptr && *a2 != 0 && ras_asic_name_lookup(a1: (int)&(*off_40472C)[1053126] + 2, (int)a2, a3, a4) ) return nullptr; else return (char *)off_404730 + 4212522; } /* ==== ras_attach_response_buffer [tier=EXACT size=40] ==== */ // Maps the shared buffer then binds the response area at +2064 with the remaining length // (len - 2088). int __fastcall ras_attach_response_buffer(unsigned int a1, int a2) { int *v2; // r5 int result; // r0 __int64 v5; // r0 v2 = off_403C6C; result = ras_map_shared_buffer(a1, a2, a3: off_403C6C); if ( result != 0 ) { LODWORD(v5) = result + 2064; HIDWORD(v5) = *(_DWORD *)(a2 + 8 * *v2 + 4) - 2088; return ras_bind_response_area(a1: v5); } return result; } /* ==== ras_auth_check [tier=EXACT size=28] ==== */ // Runs the integrity check and latches the result via ras_set_auth_flag. int __fastcall ras_auth_check() { char *v0; // r4 v0 = off_403D9C; vsnprintf_reentry(); ras_set_auth_flag(a1: v0[7], a2: (unsigned int *)v0 + 2); return 0; } /* ==== ras_bind_response_area [tier=EXACT size=18] ==== */ // Records the response area pointer in off_406020 and clears its 0x14-byte header. int __fastcall ras_bind_response_area(__int64 a1) { *((_QWORD *)off_403D88 + 1) = a1; bzero(result: (_BYTE *)a1, a2: 0x14u); return 0; } /* ==== ras_block_config_405030 [tier=EXACT size=284] ==== */ // Programs the register pair dword_405030 / dword_405040 for modes other than 2. int __fastcall __spoils ras_block_config_405030(int a1, int a2, int a3, int a4) { int result; // r0 _DWORD *v6; // r9 int *v7; // r8 int *v8; // r7 int v9; // r7 _DWORD *v10; // r6 int v11; // r6 int v12; // r5 int *v13; // r7 int v14; // r4 int v15; // [sp+4h] [bp-8h] BYREF int v16; // [sp+8h] [bp-4h] BYREF v15 = a3; v16 = a4; result = 0; if ( a1 != 2 ) { v6 = (_DWORD *)off_4035A4[0]; v15 = 0; v16 = 0; v7 = (int *)off_4035AC; v8 = off_403144; result = ras_reg_access( a1: 0, a2: 4 * ((*off_4035AC)[*(_DWORD *)off_4035A4[0]] + *(_DWORD *)(off_4035A4[0] + 0x30)), a3: (int)&v16, a4: 4, a5: off_403144[4]); if ( result != 0 ) return result; result = ras_reg_access(a1: 0, a2: 4 * (v7[*v6] + v6[16]), a3: (int)&v15, a4: 4, a5: v8[4]); if ( result != 0 ) return result; v9 = 0; v16 &= 0xFFFFFFF8; v15 &= 0xFE000000; while ( v9 != 4 ) { v10 = &v6[v9]; result = ras_cb_4060D4(a1: 0, a2: 4 * (v7[*v10] + v10[12])); if ( result == 0 ) { result = ras_cb_4060D4(a1: 0, a2: 4 * (v7[v6[v9++]] + v10[16])); if ( result == 0 ) continue; } goto LABEL_2; } result = 0; } LABEL_2: if ( (result | a1) == 0 ) { v11 = off_403494[0]; v12 = 0; v13 = (int *)off_40349C; while ( v12 != 4 ) { result = ras_cb_4060D4(a1: 0, a2: 4 * (v13[*(_DWORD *)(v11 + 4 * v12)] + *(_DWORD *)(v11 + 4 * v12 + 16))); ++v12; if ( result != 0 ) return result; } v14 = dword_4034A0; result = ras_reg_write(a1: 8, a2: 2u, a3: dword_4034A0, a4: 0); if ( result == 0 ) return ras_reg_write(a1: 8, a2: 2u, a3: v14 + 4, a4: 0); } return result; } /* ==== ras_block_config_405030_v2 [tier=EXACT size=252] ==== */ // Second configuration path for dword_405030, selecting bit0/bit1 by mode. int __fastcall ras_block_config_405030_v2(int a1, int a2, unsigned int a3) { _DWORD *v3; // r6 int *v5; // r7 int *v7; // r5 int result; // r0 unsigned int v9; // r0 int v10; // r0 int i; // r4 int v12; // r1 int v13; // r2 int v14; // r3 unsigned int v15; // r0 int v16; // r0 int j; // r4 unsigned int v18; // [sp+4h] [bp-8h] BYREF int v19; // [sp+8h] [bp-4h] BYREF v18 = a3; v3 = (_DWORD *)off_4035A4[0]; v5 = (int *)off_4035AC; v19 = 0; v7 = off_403810; result = ras_reg_access( a1: 0, a2: 4 * ((*off_4035AC)[*(_DWORD *)off_4035A4[0]] + *(_DWORD *)(off_4035A4[0] + 0x30)), a3: (int)&v19, a4: 4, a5: off_403810[4]); if ( result != 0 ) return result; v9 = v19 & 0xFFFFFFF8; v19 &= 0xFFFFFFF8; if ( a2 == 2 ) { v10 = v9 | 1; goto LABEL_7; } if ( a2 == 1 ) { v10 = v9 | 2; LABEL_7: v19 = v10; } for ( i = 0; i != 4; ++i ) { result = ras_cb_4060D4(a1: 0, a2: 4 * (v5[v3[i]] + v3[i + 12])); if ( result != 0 ) return result; } v12 = v3[16]; v18 = 0; result = ras_reg_access(a1: 0, a2: 4 * (v5[*v3] + v12), a3: (int)&v18, a4: 4, a5: v7[4]); if ( result == 0 ) { v15 = v18 & 0xFE000000; v18 = (v18 & 0xFE000000) + 0x10000; if ( a1 == 2 ) { v16 = v15 | 0x10001; } else { if ( a1 != 4 ) goto LABEL_18; v16 = v15 | dword_4035B0; } v18 = v16; LABEL_18: for ( j = 0; j != 4; ++j ) { result = ras_cb_4060D4(a1: 0, a2: 4 * (v5[v3[j]] + v3[j + 16])); if ( result != 0 ) return result; } return ras_block_config_405030(a1: a2, a2: 0, a3: v13, a4: v14); } return result; } /* ==== ras_block_enable_405010 [tier=EXACT size=260] ==== */ // Programs the RAS block at dword_405010: reads the control register, ORs 0x200 and // iterates four sub-units. int __fastcall ras_block_enable_405010(int a1, int a2, int a3) { int *v3; // r6 int *v5; // r11 int *v6; // r7 int result; // r0 int v8; // r4 int v9; // r4 unsigned int i; // r9 int *v11; // r10 int v12; // r8 int v13; // [sp+4h] [bp-8h] BYREF int v14; // [sp+8h] [bp-4h] BYREF v13 = a3; v3 = off_403140[0]; v5 = (int *)off_4035AC; v14 = 0; v6 = off_403144; result = ras_reg_access( a1: 0, a2: 4 * ((*off_4035AC)[*off_403140[0]] + off_403140[0][4]), a3: (int)&v14, a4: 4, a5: off_403144[4]); if ( result != 0 ) return result; if ( a1 != 0 ) { v8 = 0; v14 |= 0x200u; while ( v8 != 4 ) { result = ras_cb_4060D4(a1: 0, a2: 4 * (v5[v3[v8]] + v3[v8 + 4])); ++v8; if ( result != 0 ) return result; } return 0; } v9 = 0; v14 &= ~0x200u; LABEL_9: if ( v9 == 4 ) return 0; for ( i = 0; ; ++i ) { if ( i >= v6[1] ) { ++v9; goto LABEL_9; } if ( (v6[3] & (1 << i)) != 0 ) break; LABEL_18: ; } v11 = &v3[v9]; result = ras_cb_4060D4(a1: 0, a2: 4 * (v5[*v11] + v11[4])); if ( result == 0 ) { v13 = 0; v12 = 1000; while ( 1 ) { result = ras_reg_access(a1: 0, a2: 4 * (v11[8] + v5[v3[v9]]), a3: (int)&v13, a4: 4, a5: 1 << i); if ( result != 0 ) break; if ( --v12 == 0 ) return 40968; if ( (unsigned __int8)v13 << 31 == 0 ) goto LABEL_18; } } return result; } /* ==== ras_cb_4060A8 [tier=EXACT size=12] ==== */ // Invokes the optional runtime callback off_4060A8. int __fastcall ras_cb_4060A8() { int (*v0)(void); // r0 v0 = (int (*)(void))off_403A60[18]; if ( v0 != nullptr ) return v0(); else return 0; } /* ==== ras_cb_4060C4 [tier=EXACT size=32] ==== */ // Invokes the runtime callback off_4060C4(2, ...) if installed. BOOL __fastcall ras_cb_4060C4(int a1, int a2, unsigned __int8 a3) { int (__fastcall *v3)(int, _DWORD, int, int); // r5 v3 = (int (__fastcall *)(int, _DWORD, int, int))off_403144[25]; return v3 != nullptr && v3(a1: 2, a2: a3, a3: a1, a4: a2) == 0; } /* ==== ras_cb_4060D4 [tier=EXACT size=30] ==== */ // Invokes the runtime callback off_4060D4; returns 40976 when not installed. int __fastcall ras_cb_4060D4(int a1, int a2) { int (__fastcall *v2)(int, _DWORD, int, int); // r5 v2 = (int (__fastcall *)(int, _DWORD, int, int))off_403E2C[29]; if ( v2 != nullptr ) return v2(a1, a2: 0, a3: 2, a4: a2); else return 40976; } /* ==== ras_clear_reply_status [tier=EXACT size=10] ==== */ // Zeroes the two status dwords of the reply block. int __fastcall ras_clear_reply_status() { *(_DWORD *)(loc_402E1C + 8) = 0; *(_DWORD *)(loc_402E1C + 8 + 4) = 0; return loc_402E1C; } /* ==== ras_cmd_disable_features [tier=EXACT size=12] ==== */ // Invoke command 1 - DISABLE FEATURES. int __fastcall ras_cmd_disable_features() { int (*v0)(void); // r1 v0 = (int (*)(void))off_403A60[20]; if ( v0 != nullptr ) return v0(); else return 0; } /* ==== ras_cmd_enable_features [tier=EXACT size=12] ==== */ // Invoke command 0 - ENABLE FEATURES. int __fastcall ras_cmd_enable_features() { int (*v0)(void); // r1 v0 = (int (*)(void))off_403A60[19]; if ( v0 != nullptr ) return v0(); else return 0; } /* ==== ras_cmd_query_block_info [tier=EXACT size=14] ==== */ // Invoke command 3 - QUERY_BLOCK_INFO. int __fastcall ras_cmd_query_block_info() { int (*v0)(void); // r1 v0 = (int (*)(void))off_403A60[22]; if ( v0 != nullptr ) return v0(); else return 40976; } /* ==== ras_cmd_query_sub_block_info [tier=EXACT size=14] ==== */ // Invoke command 4 - QUERY_SUB_BLOCK_INFO. int __fastcall ras_cmd_query_sub_block_info() { int (*v0)(void); // r1 v0 = (int (*)(void))off_403A60[23]; if ( v0 != nullptr ) return v0(); else return 40976; } /* ==== ras_cmd_trigger_error [tier=EXACT size=14] ==== */ // Invoke command 2 - TRIGGER ERROR (RAS error injection). int __fastcall ras_cmd_trigger_error() { int (*v0)(void); // r1 v0 = (int (*)(void))off_403E2C[21]; if ( v0 != nullptr ) return v0(); else return 40976; } /* ==== ras_configure_blocks [tier=EXACT size=844] ==== */ // Largest RAS routine (844 B): queries the feature mask (SYS_DRV RPC 0x1067) then walks // the per-block register offsets in DATA (dword_405010 etc.) programming RAS controls. int __fastcall ras_configure_blocks(int a1, int a2, unsigned __int64 *a3) { unsigned __int64 v5; // kr00_8 int v6; // r7 int v7; // r5 _DWORD *v8; // r11 int v9; // r1 int v10; // r2 int v11; // r2 int *v12; // r5 int v13; // r1 int v14; // r0 int v15; // r9 int v16; // r0 unsigned int v18; // r0 int v19; // r0 int v20; // r4 int v21; // r5 int v22; // r4 int v23; // r4 int v24; // r2 int v25; // r3 int v26; // r6 int *v27; // r5 int v28; // r4 int v29; // r9 int v30; // r7 unsigned __int64 v31; // r0 int v32; // r6 int v33; // r4 int v34; // r2 unsigned int v35; // r1 int v36; // r1 int v37; // r2 int v38; // r5 int v39; // r0 unsigned int v40; // [sp+Ch] [bp-18h] BYREF unsigned int v41; // [sp+10h] [bp-14h] BYREF unsigned int v42; // [sp+14h] [bp-10h] BYREF unsigned int v43; // [sp+18h] [bp-Ch] BYREF int v44; // [sp+1Ch] [bp-8h] BYREF int v45; // [sp+20h] [bp-4h] BYREF v5 = *a3; if ( sysdrv_rpc_1067() != 0 ) return 40967; v44 = 0; v7 = off_403498; v8 = (_DWORD *)off_4035A4[0]; v6 = ras_reg_access( a1: 0, a2: 4 * ((*off_40349C)[*(_DWORD *)off_4035A4[0]] + *(_DWORD *)(off_4035A4[0] + 0x10)), a3: (int)&v44, a4: 4, a5: *(_DWORD *)(off_403498 + 0x10)); if ( v6 != 0 ) goto LABEL_11; v6 = ras_block_enable_405010(a1: 0, a2: v9, a3: v10); if ( v6 != 0 ) goto LABEL_11; v11 = *(_DWORD *)(v7 + 0x10); v12 = (int *)off_40349C; v13 = v8[12]; v14 = (*off_40349C)[*v8]; v43 = 0; v6 = ras_reg_access(a1: 0, a2: 4 * (v14 + v13), a3: (int)&v43, a4: 4, a5: v11); if ( v6 != 0 ) goto LABEL_11; v15 = 0; v43 = v43 & 0xFFFFFFF8 | 4; while ( v15 != 4 ) { v16 = ras_cb_4060D4(a1: 0, a2: 4 * (v12[v8[v15]] + v8[v15 + 12])); ++v15; if ( v16 != 0 ) { LABEL_9: v6 = v16; goto LABEL_11; } } v42 = 0; v6 = ras_reg_access(a1: 0, a2: 4 * (v12[*v8] + v8[16]), a3: (int)&v42, a4: 4, a5: *(_DWORD *)(off_4035A8 + 0x10)); if ( v6 != 0 ) goto LABEL_11; v18 = v42 & 0xFE000000; v42 = (v42 & 0xFE000000) + 0x10000; if ( a2 == 2 ) { v19 = v18 | 0x10001; goto LABEL_18; } if ( a2 == 4 ) { v19 = v18 | dword_4035B0; LABEL_18: v42 = v19; } v20 = 0; while ( v20 != 4 ) { v16 = ras_cb_4060D4(a1: 0, a2: 4 * (v12[v8[v20]] + v8[v20 + 16])); ++v20; if ( v16 != 0 ) goto LABEL_9; } v21 = dword_4034A0; v41 = 0; v22 = dword_4034A0 + 4; v6 = ras_reg_read(a1: 8, a2: 2u, a3: dword_4034A0 + 4, a4: &v41); if ( v6 == 0 ) { v41 = v41 & 0xFFFFF000 | WORD2(v5) & 0xFFF; v6 = ras_reg_write(a1: 8, a2: 2u, a3: v22, a4: v41); if ( v6 == 0 ) { v40 = 0; v6 = ras_reg_read(a1: 8, a2: 2u, a3: v21, a4: &v40); if ( v6 == 0 ) { v40 = v5 & 0xFFFFFFC1 | (2 * ((v40 >> 1) & 0x1F)) | 1; v6 = ras_reg_write(a1: 8, a2: 2u, a3: v21, a4: v40); if ( v6 == 0 ) { v23 = 1000; do { v16 = ras_reg_read(a1: 8, a2: 2u, a3: v21, a4: &v40); if ( v16 != 0 ) goto LABEL_9; if ( --v23 == 0 ) { v6 = 40968; goto LABEL_11; } } while ( (v40 & 2) == 0 ); v40 &= 0xFFFFFFFC; v6 = ras_reg_write(a1: 8, a2: 2u, a3: v21, a4: v40); if ( v6 != 0 ) goto LABEL_11; if ( a1 == 0 ) { LABEL_50: v16 = ras_block_config_405030(a1: 0, a2: v44, a3: v24, a4: v25); goto LABEL_9; } v26 = 0; v27 = (int *)off_4034A4; v28 = 4 * off_403728[2]; while ( 1 ) { if ( v26 == 8 ) { v6 = 40962; goto LABEL_11; } if ( (*off_4034A4)[2 * v26] == v28 ) break; ++v26; } v45 = 0; v6 = ras_reg_access(a1: 0, a2: 4 * ((*off_4035AC)[*v8] + v8[20]), a3: (int)&v45, a4: 4, a5: off_403754[4]); if ( v6 == 0 ) { v29 = v27[2 * v26 + 1]; v30 = (unsigned __int8)(v29 - 8); LODWORD(v31) = ((__int64)v5 >> 8) & ~(unsigned int)(-1LL << v30) | (v5 >> ((unsigned __int8)v29 + 2) << v30); HIDWORD(v31) = ~((unsigned __int64)(-1LL << v30) >> 32) & (HIDWORD(v5) >> 8) | (v5 >> ((unsigned __int8)v29 + 2) << v30 >> 32); v32 = 0; v33 = v31 / (unsigned int)v28; v34 = v29; v35 = v45 & 0xF0000000; v45 = v45 & 0xF0000000 | ((v5 & 0xF0 | (((unsigned int)(v5 >> v29) & 3) << 8) | (unsigned int)(v33 << 10)) >> 4); while ( v32 != 4 ) { v16 = ras_cb_4060D4(a1: 0, a2: 4 * ((*off_4035AC)[v8[v32]] + v8[v32 + 20])); ++v32; if ( v16 != 0 ) goto LABEL_9; } v6 = ras_block_enable_405010(a1: 1, a2: v35, a3: v34); if ( v6 == 0 ) { v6 = ras_block_enable_405010(a1: 0, a2: v36, a3: v37); if ( v6 == 0 ) { v38 = 0; while ( v38 != 4 ) { v39 = ras_cb_4060D4(a1: 0, a2: 4 * ((*off_4035AC)[v8[v38]] + v8[v38 + 20])); ++v38; v6 = v39; if ( v39 != 0 ) goto LABEL_11; } goto LABEL_50; } } } } } } } LABEL_11: if ( sysdrv_rpc_1067() != 0 ) return 40967; return v6; } /* ==== ras_device_register [tier=EXACT size=96] ==== */ // Resolves the ASIC and registers the device; logs 'Device registered as: %s' or // 'invalid asic to support ras'. int __fastcall ras_device_register() { int *v0; // r4 int result; // r0 char *v2; // r0 int *v3; // r1 int v4; // r5 int v5; // r6 int v6; // r7 int *v7; // r0 _DWORD *v8; // r1 int v9; // r2 int v10; // r3 int v11; // r4 int v12; // r5 v0 = off_403810; bzero_core(result: off_403810, a2: 0x80u); result = ras_feature_reset(); if ( result == 0 ) { v2 = ras_asic_name_lookup_v2(a1: *v0); ras_log(a1: "Device registered as: %s", v2); if ( *v0 == 49 ) { v3 = (int *)off_403858; v0[21] = (int)off_40384C; v0[19] = (int)off_403850; v0[17] = (int)off_403854; v4 = v3[1]; v5 = v3[2]; v6 = v3[3]; v0[24] = *v3; v0[25] = v4; v0[26] = v5; v0[27] = v6; v7 = v3 + 4; v8 = v0 + 28; v9 = *v7; v10 = v7[1]; v11 = v7[2]; v12 = v7[3]; *v8 = v9; v8[1] = v10; v8[2] = v11; v8[3] = v12; return 0; } else { ras_log(a1: aInvalidAsicToS); return 40973; } } return result; } /* ==== ras_dram_range_config [tier=EXACT size=158] ==== */ // Configures the RAS DRAM range via SYS_DRV RPC 0x7008 (dram_range_register); // returns 40986 on failure. int __fastcall ras_dram_range_config(__int64 *a1, int a2, int a3, int a4) { __int64 v4; // kr00_8 __int64 v5; // kr08_8 int v6; // r3 int result; // r0 BOOL v8; // r1 BOOL v9; // r2 bool v10; // zf bool v11; // zf int v12; // r0 _DWORD v13[3]; // [sp+0h] [bp-Ch] BYREF v13[0] = a2; v13[1] = a3; v13[2] = a4; v4 = *a1; v5 = a1[2]; *(_QWORD *)v13 = a1[1]; if ( sysdrv_rpc_7008_dram_range() != 0 ) return 40986; v8 = v4 != 4; v9 = (v4 & 0xFFFFFFFD) != 0; v10 = !v8 || !v9; result = 40962; if ( !v8 || !v9 ) v10 = HIDWORD(v4) == 0; if ( v10 ) { v11 = (_DWORD)v4 == 4; if ( (_DWORD)v4 != 4 ) v11 = (_DWORD)v4 == 2; if ( v11 ) { if ( (unsigned __int64)(v5 - 1) < 2 ) return ras_block_config_405030_v2(a1: v4, a2: v5, a3: v9); if ( v5 == 4 ) { v12 = 0; } else { if ( v5 != 0 ) return 40962; v12 = 1; } return ras_configure_blocks(a1: v12, a2: v4, a3: (unsigned __int64 *)v13); } result = 40962; if ( (_DWORD)v4 == 0 && v5 == 3 ) return ras_block_config_405030(a1: 3, a2: 0, a3: v9, a4: v6); } return result; } /* ==== ras_feature_reset [tier=EXACT size=38] ==== */ // Issues SYS_DRV RPC 0x1077 and clears dword_406060; returns 40972 on failure. int __fastcall ras_feature_reset() { int _4; // [sp+4h] [bp+0h] int vars4; // [sp+8h] [bp+4h] int _C; // [sp+Ch] [bp+8h] vars4 = 0; _C = 0; _4 = 0; if ( sysdrv_rpc_1077() != 0 ) return 40972; *off_403A60 = 0; return 0; } /* ==== ras_fill_response_footer [tier=EXACT size=26] ==== */ // Appends the RAS state footer (byte_4060E0 initialised flag, dword_4060E4/E8) at // offset +1040 of the response buffer. _BYTE *__fastcall ras_fill_response_footer(_BYTE *result) { result[1040] = *off_403C8C[0]; result[1041] = *off_403C90[0]; result[1042] = *off_403C94; return result; } /* ==== ras_get_state_406038 [tier=EXACT size=6] ==== */ // Accessor: returns the byte_406038 state flag. int __fastcall ras_get_state_406038() { return (unsigned __int8)*off_403D9C; } /* ==== ras_get_time_us [tier=EXACT size=28] ==== */ // Reads the SYS_DRV counter pair and converts it to microseconds (1000*hi + 1000000*lo). __int64 __fastcall ras_get_time_us() { __int64 vars0; // [sp+0h] [bp+0h] BYREF sysdrv_rpc_gp_d(a1: &vars0); return 1000LL * HIDWORD(vars0) + (unsigned int)vars0 * (unsigned __int64)(unsigned int)dword_402ECC; } /* ==== ras_get_time_us_thunk [tier=EXACT size=8] ==== */ // Thunk to ras_get_time_us. __int64 __fastcall ras_get_time_us_thunk() { return ras_get_time_us(); } /* ==== ras_gfx_mode_config [tier=EXACT size=62] ==== */ // Handles the GFX_FUE_IS_FATAL_MODE and GFX_POISON_PROPOGATE_MODE feature knobs. int __fastcall ras_gfx_mode_config() { int state_406038; // r4 const char *v1; // r0 int v2; // r1 BOOL v3; // r0 int v4; // r1 state_406038 = ras_get_state_406038(); v1 = aGfxPoisonPropo; if ( state_406038 == 0 ) v1 = aGfxFueIsFatalM; ras_log(a1: v1, aGfxFueIsFatalM); v2 = dword_403628 + 0x100000; if ( state_406038 == 0 ) v2 = 538050560; v3 = ras_cb_4060C4(a1: 49656, a2: v2, a3: 0); v4 = 40978; if ( v3 ) return 0; return v4; } /* ==== ras_init [tier=EXACT size=14] ==== */ // Post-registration initialisation, called from TA_OpenSessionEntryPoint. int __fastcall ras_init() { int (*v0)(void); // r0 v0 = (int (*)(void))off_403A60[17]; if ( v0 != nullptr ) return v0(); else return 40976; } /* ==== ras_locale_base [tier=EXACT size=4] ==== */ // Returns the dword_406000 locale/format table base. int *__fastcall ras_locale_base() { return (int *)off_40264C; } /* ==== ras_locale_ptr [tier=EXACT size=10] ==== */ // Returns the locale/format table pointer + 4. int *__fastcall ras_locale_ptr() { return ras_locale_base() + 1; } /* ==== ras_log [tier=EXACT size=194] ==== */ // printf-style trace sink used throughout the RAS TA. int ras_log(const char *a1, ...) { char *v1; // r6 _DWORD *v2; // r1 int result; // r0 unsigned __int8 *v5; // r5 unsigned __int16 v6; // r0 __int64 v7; // kr00_8 int v8; // r1 unsigned __int16 v9; // r0 _DWORD *v10; // r1 int v11; // r3 __int64 time_us; // r0 va_list a4; // [sp+14h] [bp-Ch] BYREF va_start(a4, a1); v1 = off_403D88; v2 = *((_DWORD **)off_403D88 + 2); if ( v2 == nullptr ) return 0; result = 0; if ( *v2 < *((_DWORD *)off_403D88 + 3) && *off_403D88 != 0 ) { v5 = (unsigned __int8 *)v2 + *v2 + 8; v6 = vsnprintf_entry( a1: (struct tee_fmt_state *)((char *)v2 + *v2 + 18), a2: *((_DWORD *)off_403D88 + 3) - **((_DWORD **)off_403D88 + 2), a3: (int)a1, (char *)a4); *(_WORD *)v5 = v6; v7 = *((_QWORD *)v1 + 1); v8 = v6; if ( HIDWORD(v7) - *(_DWORD *)v7 <= (unsigned int)v6 ) { *v5 = 0; v5[1] = 0; *(_DWORD *)v7 = HIDWORD(v7); return 0; } else { result = 0; if ( v8 != 0 ) { v5[v8 + 10] = 0; v9 = v8 + 1; *(_WORD *)v5 = v8 + 1; v10 = *((_DWORD **)v1 + 2); v11 = v10[1] + 1; *v10 += v9 + 10; v10[1] = v11; time_us = ras_get_time_us(); v5[6] = BYTE4(time_us); v5[9] = HIBYTE(time_us); v5[8] = BYTE6(time_us); v5[7] = BYTE5(time_us); v5[2] = time_us; v5[5] = BYTE3(time_us); v5[4] = BYTE2(time_us); HIDWORD(time_us) = v5[1]; v5[3] = BYTE1(time_us); return *v5 | (HIDWORD(time_us) << 8); } } } return result; } /* ==== ras_log_chiplet_config [tier=EXACT size=84] ==== */ // Logs max_chiplets / chiplets_present_mask / first_chiplet_present_mask / chiplets_present. int __fastcall ras_log_chiplet_config(int a1) { int *v3; // r0 if ( sysdrv_rpc_109A_feature_mask() != 0 ) return 40970; v3 = &off_403A60[4 * a1]; v3[1] = 0; *(_QWORD *)(v3 + 3) = 0; ras_log(a1: off_4037AC); return 0; } /* ==== ras_map_shared_buffer [tier=EXACT size=64] ==== */ // Maps/validates the caller's shared parameter buffer (records it in dword_4060EC). int __fastcall ras_map_shared_buffer(unsigned int a1, int a2, _DWORD *a3) { int v3; // r3 int i; // r4 if ( a1 == 0 ) return 0; v3 = 0; for ( i = 0; i != 4; ++i ) { if ( a1 >> v3 << 28 != 0 ) { *a3 = i; break; } v3 += 4; } if ( ((a1 >> v3) & 0xF) - 5 <= 2 && *(_DWORD *)(a2 + 2 * v3 + 4) >= 0x828u ) return *(_DWORD *)(a2 + 2 * v3); else return 0; } /* ==== ras_parse_trigger_request [tier=EXACT size=50] ==== */ // Validates the TRIGGER ERROR request: rejects a null pointer (40962) and a non-zero // request type (40980), then unpacks the 8/16/20/24/28-byte fields into the internal // injection descriptor. int __fastcall ras_parse_trigger_request(int a1) { __int64 v2; // kr00_8 int v3; // r3 int v4; // r4 int v5; // r5 _DWORD v6[5]; // [sp+0h] [bp-18h] BYREF int v7; // [sp+14h] [bp-4h] if ( a1 == 0 ) return 40962; if ( *(_DWORD *)a1 != 0 ) return 40980; v2 = *(_QWORD *)(a1 + 4); v3 = *(_DWORD *)(a1 + 16); v4 = *(_DWORD *)(a1 + 20); v5 = *(_DWORD *)(a1 + 24); v7 = *(_DWORD *)(a1 + 28); *(_QWORD *)v6 = v2; v6[2] = v3; v6[3] = v4; v6[4] = v5; return ras_dram_range_config(a1: (__int64 *)v6, a2: v2, a3: SHIDWORD(v2), a4: v3); } /* ==== ras_probe_chiplets [tier=EXACT size=64] ==== */ // Queries the chiplet presence/count pair and records it via ras_reg_trace helpers, then // logs the configuration through ras_log_chiplet_config. int ras_probe_chiplets() { int v0; // r4 char v2; // [sp+7h] [bp-1h] BYREF v2 = 1; v0 = sub_402F18(a1: &v2); ras_set_state_byte(result: 0, a2: v2); if ( v0 == 0 ) { v0 = sub_402F10(a1: &v2); ras_set_state_byte(result: 2u, a2: v2); if ( v0 == 0 ) return ras_log_chiplet_config(a1: 0); } return v0; } /* ==== ras_reg_access [tier=EXACT size=38] ==== */ // Low-level register accessor used throughout: builds the SMN address as // 4 * (offset + 0xC400000) and performs the read/write through the SYS_DRV RPCs. int __fastcall ras_reg_access(int a1, int a2, int a3, int a4, int a5) { int (__fastcall *v5)(int, _DWORD, int, int, int, int, int, int); // r5 v5 = (int (__fastcall *)(int, _DWORD, int, int, int, int, int, int))off_403E2C[28]; if ( v5 != nullptr ) return v5(a1, a2: 0, a3: 2, a4: a2, a5: a3, a6: a4, a7: a5, a8: a4); else return 40976; } /* ==== ras_reg_read [tier=EXACT size=94] ==== */ // Register read via SYS_DRV; logs operation/address/value/sys_drv_ret. int __fastcall ras_reg_read(int a1, unsigned int a2, int a3, _DWORD *a4) { int v7; // r6 int v8; // r1 v7 = sysdrv_rpc_7002(); if ( v7 != 0 || (*a4 = 0, ras_reg_trace_gate() != 0) ) { if ( a2 <= 2 ) v8 = (*off_403C20)[(char)a2]; else v8 = 0; ras_log(a1: off_403A4C, v8, a3, 0, v7); } if ( v7 != 0 ) return 40977; return v7; } /* ==== ras_reg_read64 [tier=EXACT size=84] ==== */ // 64-bit register read via SYS_DRV RPC 0x7002; logs 'reg read 64b -> ...'. int __fastcall ras_reg_read64(int a1, unsigned int a2, int a3, _QWORD *a4) { int v7; // r3 int v8; // r7 int v9; // r1 v8 = sysdrv_rpc_7002(); if ( v8 != 0 || ras_reg_trace_gate() != 0 ) { if ( a2 <= 2 ) v9 = (*off_403C20)[(char)a2]; else v9 = 0; ras_log(a1: (const char *)dword_4039E8, v9, a3, v7, *(_DWORD *)a4, *((_DWORD *)a4 + 1), v8); } if ( v8 != 0 ) return 40977; return v8; } /* ==== ras_reg_read_chiplet [tier=EXACT size=108] ==== */ // Per-chiplet register read via SYS_DRV; logs operation/address/value/core_type/sys_drv_ret. int __fastcall ras_reg_read_chiplet(int a1, int a2, unsigned int a3, int a4, _DWORD *a5) { int v8; // r7 int v9; // r1 int v11; // [sp+38h] [bp+1Ch] v8 = sysdrv_rpc_7007(); if ( v8 != 0 || (*a5 = 0, ras_reg_trace_gate() != 0) ) { if ( a3 <= 2 ) v9 = (*off_403C20)[(char)a3]; else v9 = 0; ras_log(a1: off_403990, v9, a4, 0, a1, v8, v11); } if ( v8 != 0 ) return 40977; return v8; } /* ==== ras_reg_read_chiplet64 [tier=EXACT size=100] ==== */ // Per-chiplet 64-bit register read via SYS_DRV RPC 0x7007; logs 'reg read chiplet 64b -> ...'. int __fastcall ras_reg_read_chiplet64(int a1, int a2, unsigned int a3, int a4, _QWORD *a5) { int v8; // r3 int v9; // r7 int v10; // r1 v9 = sysdrv_rpc_7007(); if ( v9 != 0 || ras_reg_trace_gate() != 0 ) { if ( a3 <= 2 ) v10 = (*off_403C20)[(char)a3]; else v10 = 0; ras_log(a1: (const char *)dword_403920, v10, a4, v8, *(_DWORD *)a5, *((_DWORD *)a5 + 1), a1, v9); } if ( v9 != 0 ) return 40977; return v9; } /* ==== ras_reg_trace_gate [tier=EXACT size=6] ==== */ // Returns whether the register access should be traced (guards the ras_log calls in every // register wrapper). int __fastcall ras_reg_trace_gate() { return (unsigned __int8)off_403D9C[6]; } /* ==== ras_reg_write [tier=EXACT size=84] ==== */ // 32-bit register write via SYS_DRV RPC 0x7001; logs // 'reg write -> operation/address/value/sys_drv_ret'. Returns 40977 on RPC failure. int __fastcall ras_reg_write(int a1, unsigned int a2, int a3, int a4) { int v7; // r7 int v8; // r1 v7 = sysdrv_rpc_7001(); if ( v7 != 0 || ras_reg_trace_gate() != 0 ) { if ( a2 <= 2 ) v8 = (*off_403C20)[(char)a2]; else v8 = 0; ras_log(a1: (const char *)dword_403C24, v8, a3, a4, v7); } if ( v7 != 0 ) return 40977; return v7; } /* ==== ras_reg_write64 [tier=EXACT size=92] ==== */ // 64-bit register write via SYS_DRV. int __fastcall ras_reg_write64(int a1, unsigned int a2, int a3, int a4, __int64 a5) { int v7; // r3 int v8; // r6 int v9; // r1 v8 = sysdrv_rpc_7001(); if ( v8 != 0 || ras_reg_trace_gate() != 0 ) { if ( a2 <= 2 ) v9 = (*off_403C20)[(char)a2]; else v9 = 0; ras_log(a1: off_403BC8, v9, a3, v7, a5, v8, a4); } if ( v8 != 0 ) return 40977; return v8; } /* ==== ras_reg_write_chiplet [tier=EXACT size=100] ==== */ // Per-chiplet 32-bit register write via SYS_DRV RPC 0x7006; logs 'reg write chiplet -> ...'. // The core_type is resolved from dword_404838[a3] for a3 <= 2. int __fastcall ras_reg_write_chiplet(int a1, int a2, unsigned int a3, int a4, int a5) { int v8; // r5 int v9; // r1 int v11; // [sp+2Ch] [bp+1Ch] v8 = sysdrv_rpc_7006(); if ( v8 != 0 || ras_reg_trace_gate() != 0 ) { if ( a3 <= 2 ) v9 = (*off_403C20)[(char)a3]; else v9 = 0; ras_log(a1: (const char *)dword_403B68, v9, a4, a5, a1, v8, a1, v11); } if ( v8 != 0 ) return 40977; return v8; } /* ==== ras_reg_write_chiplet64 [tier=EXACT size=104] ==== */ // 64-bit per-chiplet register write via SYS_DRV. int __fastcall ras_reg_write_chiplet64(int a1, int a2, unsigned int a3, int a4, __int64 a5) { int v8; // r3 int v9; // r7 int v10; // r1 v9 = sysdrv_rpc_7006(); if ( v9 != 0 || ras_reg_trace_gate() != 0 ) { if ( a3 <= 2 ) v10 = (*off_403C20)[(char)a3]; else v10 = 0; ras_log(a1: off_403B00, v10, a4, v8, a5, a1, v9); } if ( v9 != 0 ) return 40977; return v9; } /* ==== ras_rpc_probe_chain [tier=EXACT size=48] ==== */ // Runs sysdrv_rpc_gp_a and, if it fails, the gp_b/gp_c pair; returns a pointer to the // result slot. int *__fastcall ras_rpc_probe_chain(int a1) { int v3; // [sp+Ch] [bp-4h] BYREF v3 = 0; if ( sysdrv_rpc_gp_a() != 0 ) return (int *)a1; sysdrv_rpc_gp_b(); sysdrv_rpc_gp_c(); return &v3; } /* ==== ras_set_auth_flag [tier=EXACT size=22] ==== */ // Sets the global byte_406018 to the caller's value only when ras_verify_digest accepts; // otherwise forces it to 0. char *__fastcall ras_set_auth_flag(char a1, unsigned int *a2) { char *result; // r0 if ( !ras_verify_digest(a1: a2) ) a1 = 0; result = off_403D88; *off_403D88 = a1; return result; } /* ==== ras_set_state_byte [tier=EXACT size=10] ==== */ // Stores a byte into the 15-entry state array at dword_406028 (index bounded to 0xE). unsigned int __fastcall ras_set_state_byte(unsigned int result, char a2) { if ( result <= 0xE ) *((_BYTE *)off_403DAC + result) = a2; return result; } /* ==== ras_ta_main_loop [tier=EXACT size=148] ==== */ // RAS TA entry loop (ARM mode): waits on SVC 0xF0, dispatches frame[0] 1..5 through the // GP entry points, replies with SVC 0xF1. Same shape as the HDCP/DTM TA loop. void __fastcall __noreturn ras_ta_main_loop(int *a1) { int v6; // r1 void (__fastcall *v7)(); // r12 while ( 1 ) { __asm { SVC 0xF0 } v6 = *a1; if ( *a1 == 1 ) { v7 = (void (__fastcall *)())off_404684; } else { switch ( v6 ) { case 2: v7 = (void (__fastcall *)())off_404688; break; case 3: v7 = (void (__fastcall *)())off_40468C; break; case 4: v7 = (void (__fastcall *)())off_404690; break; case 5: v7 = (void (__fastcall *)())off_404694; break; default: while ( 1 ) ; } } v7(); __asm { SVC 0xF1 } } } /* ==== ras_verify_digest [tier=EXACT size=26] ==== */ // Compares a caller-supplied 32-byte value against the constant at dword_402DF0 using // memcmp_be, after priming via ras_rpc_probe_chain. Returns true on an exact match. BOOL __fastcall ras_verify_digest(unsigned int *a1) { ras_rpc_probe_chain((int)a1); return memcmp_be(a1, a2: (unsigned int *)dword_402DF0, a3: 0x20u) == 0; } /* ==== strcmp_bounded [tier=EXACT size=48] ==== */ // Compares two sequences until a terminator or mismatch. int __fastcall strcmp_bounded(unsigned __int8 *a1, unsigned __int8 *a2) { unsigned __int8 *v2; // r0 int v3; // r2 int v4; // t1 unsigned __int8 *v5; // r1 int v6; // r3 int v7; // t1 bool v8; // zf int v9; // t1 int v10; // t1 bool v11; // zf do { v4 = *a1; v2 = a1 + 1; v3 = v4; v7 = *a2; v5 = a2 + 1; v6 = v7; v8 = v3 == 1; if ( v3 != 0 ) v8 = v3 == v6; if ( !v8 ) break; v9 = *v2; a1 = v2 + 1; v3 = v9; v10 = *v5; a2 = v5 + 1; v6 = v10; v11 = v3 == 1; if ( v3 != 0 ) v11 = v3 == v6; } while ( v11 ); return v3 - v6; } /* ==== sysdrv_rpc_1067 [tier=EXACT size=46] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x1067. int __fastcall sysdrv_rpc_1067() { _DWORD v5[12]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_1077 [tier=EXACT size=50] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x1077. int __fastcall sysdrv_rpc_1077() { _DWORD v5[30]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_109A_feature_mask [tier=EXACT size=52] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x109A (feature_mask_get). int __fastcall sysdrv_rpc_109A_feature_mask() { _DWORD v5[12]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_7001 [tier=EXACT size=60] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x7001. Used by the wrapper that logs 'reg write', so this is // the 32-bit register WRITE path (my earlier read/write guess was inverted). int __fastcall sysdrv_rpc_7001() { _DWORD v5[12]; // [sp+8h] [bp+8h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_7002 [tier=EXACT size=74] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x7002. Used by the wrapper that logs 'reg read 64b'. int __fastcall sysdrv_rpc_7002() { _DWORD v5[12]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_7006 [tier=EXACT size=68] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x7006. Used by the wrapper that logs 'reg write chiplet'. int __fastcall sysdrv_rpc_7006() { _DWORD v5[12]; // [sp+8h] [bp+8h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_7007 [tier=EXACT size=150] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x7007. Used by the wrapper that logs 'reg read chiplet 64b'. int __fastcall sysdrv_rpc_7007() { _DWORD v5[12]; // [sp+8h] [bp-74h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_7008_dram_range [tier=EXACT size=44] ==== */ // SVC 0xF2 -> SYS_DRV RPC 0x7008 (dram_range_register). int __fastcall sysdrv_rpc_7008_dram_range() { _DWORD v5[12]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_gp_a [tier=EXACT size=60] ==== */ // SVC 0xF2 -> SYS_DRV, GP-class opcode (frame[0] < 0x1000). int __fastcall sysdrv_rpc_gp_a() { _DWORD v5[12]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_gp_b [tier=EXACT size=50] ==== */ // SVC 0xF2 -> SYS_DRV, GP-class opcode 0xD. int __fastcall sysdrv_rpc_gp_b() { __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_gp_c [tier=EXACT size=36] ==== */ // SVC 0xF2 -> SYS_DRV, GP-class opcode. int __fastcall sysdrv_rpc_gp_c() { _DWORD v5[12]; // [sp+8h] [bp-78h] BYREF bzero_core(result: v5, a2: 0x20u); __asm { SVC 0xF2 } return 1; } /* ==== sysdrv_rpc_gp_d [tier=EXACT size=44] ==== */ // SVC 0xF2 -> SYS_DRV, GP-class opcode 0x42; returns a dword to the caller. __int64 __fastcall sysdrv_rpc_gp_d(__int64 *a1) { __int64 result; // r0 _DWORD v7[12]; // [sp+8h] [bp-78h] BYREF __int64 v8; // [sp+38h] [bp-48h] bzero_core(result: v7, a2: 0x20u); __asm { SVC 0xF2 } result = v8; *a1 = v8; return result; } /* ==== udiv10 [tier=EXACT size=152] ==== */ // Divide by 10 via reciprocal multiply, used by the integer formatter. unsigned __int64 __fastcall udiv10(unsigned __int64 a1) { unsigned __int64 v1; // r2 unsigned __int64 v2; // r0 unsigned __int64 result; // r0 v1 = a1 - 10; v2 = a1 - (a1 >> 2) + ((a1 - (a1 >> 2)) >> 4); result = (v2 + (v2 >> 8) + ((v2 + (v2 >> 8)) >> 16) + ((v2 + (v2 >> 8) + ((v2 + (v2 >> 8)) >> 16)) >> 32)) >> 3; if ( (((v1 - 10 * result) >> 32) & 0x80000000) == 0LL ) ++result; return result; } /* ==== udiv10_32 [tier=EXACT size=44] ==== */ // 32-bit divide-by-10 via reciprocal multiply. unsigned int __fastcall udiv10_32(unsigned int a1) { unsigned int v1; // r1 unsigned int v2; // r0 unsigned int result; // r0 v1 = a1 - 10; v2 = a1 - (a1 >> 2) + ((a1 - (a1 >> 2)) >> 4); result = (v2 + (v2 >> 8) + ((v2 + (v2 >> 8)) >> 16)) >> 3; if ( (int)(v1 - 10 * result) >= 0 ) ++result; return result; } /* ==== vsnprintf_conv_misc [tier=EXACT size=144] ==== */ // Handles the 'n' and related conversions for vsnprintf_core. void __fastcall vsnprintf_conv_misc(struct tee_fmt_state *a1, int *a2) { int *v2; // r2 _BYTE *v3; // r1 unsigned int unk00; // r2 signed int field20; // r0 unsigned __int8 v6; // r5 unsigned __int64 v7; // r2 int v8; // r1 int v9; // r3 int *v10; // r2 int *v11; // r5 char *v12; // r4 unsigned __int8 v13; // r7 unsigned __int64 v14; // r2 unsigned __int8 *p_field24; // r1 unsigned int v16; // r2 unsigned __int8 *v17; // r1 int v18; // r2 if ( a2 != (int *)110 ) { if ( a2 == (int *)112 ) { LODWORD(v14) = *v2; a1->unk00 |= 0x20u; a1->field1C = 8; v14 = (unsigned int)v14; } else { if ( a2 == (int *)102 || a2 == (int *)101 || a2 == (int *)103 ) { vsnprintf_fmt_ll(a1, (int)a2, a3: (int)v2); return; } if ( a2 == (int *)97 ) { vsnprintf_fmt_int(a1, a2: 97, a3: (int)v2); return; } if ( (a1->unk00 & 0x80) != 0 ) a2 = (int *)((unsigned int)a2 | 0x80); if ( a2 == (int *)105 || a2 == (int *)100 || a2 == (int *)117 ) { vsnprintf_conv_u(a1, (int)a2, a3: v2); return; } if ( a2 == (int *)111 ) { vsnprintf_fmt_octal(a1, a2: 111, a3: v2); return; } if ( a2 == (int *)120 ) { vsnprintf_fmt_hex(a1, a2: 120, a3: v2); return; } if ( a2 == (int *)233 || a2 == (int *)228 || a2 == (int *)245 ) { vsnprintf_fmt_signed(a1, (int)a2); return; } if ( a2 == (int *)239 ) { v7 = *(_QWORD *)(((unsigned int)v2 + 7) & 0xFFFFFFF8); v8 = 0; while ( v7 != 0 ) { v6 = (v7 & 7) + 48; v7 >>= 3; *(&a1->field24 + v8++) = v6; } v9 = 0; v10 = &dword_401A88; if ( (a1->unk00 & 8) != 0 && (a1->unk00 & 0x20 | v8) != 0 ) { v9 = 1; v10 = &dword_401A8C; --a1->field1C; } goto LABEL_42; } if ( a2 != (int *)248 ) { if ( (a1->unk00 & 0x40) != 0 ) a2 = (int *)((unsigned int)a2 | 0x80); if ( a2 == (int *)99 ) { p_field24 = &a1->field24; a1->field24 = *(_BYTE *)v2; a1->field25 = 0; v16 = 1; } else { if ( a2 != (int *)115 ) { if ( a2 == (int *)227 ) { v17 = &a1->field24; *(_WORD *)&a1->field24 = *(_WORD *)v2; a1->field26 = 0; v18 = 1; } else { if ( a2 != (int *)243 ) return; v17 = (unsigned __int8 *)*v2; v18 = -1; } vsnprintf_emit_wide(a1, a2: (int)v17, a3: v18); return; } p_field24 = (unsigned __int8 *)*v2; v16 = -1; } vsnprintf_emit_str(a1, a2: p_field24, a3: v16); return; } v14 = *(_QWORD *)(((unsigned int)v2 + 7) & 0xFFFFFFF8); } v11 = a2; if ( (a1->unk00 & 0x800) != 0 ) v12 = off_401B20 + 4201120; else v12 = off_401B20 + 4201140; v8 = 0; while ( v14 != 0 ) { v13 = v12[v14 & 0xF]; v14 >>= 4; *(&a1->field24 + v8++) = v13; } v9 = 0; if ( (a1->unk00 & 8) != 0 ) { if ( v11 == (int *)112 ) { v9 = 1; v12 += 16; } else if ( v8 != 0 ) { v9 = 2; v12 += 17; } } v10 = (int *)v12; LABEL_42: vsnprintf_pad(a1, a2: v8, a3: (int)v10, a4: v9); return; } v3 = (_BYTE *)*v2; unk00 = a1->unk00; field20 = a1->field20; if ( (unk00 & 0x400) != 0 ) { *v3 = field20; } else if ( (unk00 & 0x100) != 0 ) { *(_WORD *)v3 = field20; } else if ( (unk00 & 0x80) != 0 ) { *(_QWORD *)v3 = field20; } else { *(_DWORD *)v3 = field20; } } /* ==== vsnprintf_conv_u [tier=EXACT size=96] ==== */ // Unsigned ('u') conversion dispatch. int __fastcall vsnprintf_conv_u(struct tee_fmt_state *a1, int a2, int *a3) { int v4; // r5 struct tee_fmt_state *v5; // r0 int *v6; // r6 int v7; // r0 int v8; // r4 char v9; // r1 v4 = 0; v5 = (struct tee_fmt_state *)*a3; v6 = &dword_401864; if ( a2 == 117 ) { v7 = vsnprintf_narrow_u(result: v5, a2: (int *)a1); goto LABEL_10; } v7 = vsnprintf_narrow_s(result: v5, a2: (int *)a1); if ( v7 < 0 ) { v7 = -v7; v6 = &dword_401868; LABEL_8: v4 = 1; goto LABEL_10; } if ( (a1->unk00 & 2) != 0 ) { v6 = &dword_40186C; goto LABEL_8; } if ( (a1->unk00 & 4) != 0 ) { v6 = &dword_401870; goto LABEL_8; } LABEL_10: v8 = 0; while ( v7 != 0 ) { v7 = udiv10_32(a1: v7); *(&a1->field24 + v8++) = v9 + 48; } return vsnprintf_pad(a1, a2: v8, a3: (int)v6, a4: v4); } /* ==== vsnprintf_core [tier=EXACT size=388] ==== */ // printf engine: walks the format string via the callback at ctx+12, handling '%' (37) // conversions and accumulating the output length at ctx+32. int __fastcall vsnprintf_core(struct tee_fmt_state *a1, int *a2) { int *v4; // r11 int v5; // r0 unsigned int i; // r6 int v7; // r0 int *v8; // r5 int v9; // r7 unsigned int *v10; // r8 unsigned int v11; // t1 signed int field18; // r0 int *v13; // r7 int v14; // r0 int v15; // r0 int v16; // r0 v4 = &(*off_401CA8)[1050318]; a1->field20 = 0; while ( 2 ) { v5 = ((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); if ( v5 == 0 ) return a1->field20; if ( v5 != 37 ) goto LABEL_4; for ( i = 0; ; i |= *((unsigned __int8 *)v4 + v7 - 32) ) { v7 = ((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); v8 = (int *)v7; if ( v7 < 32 || (unsigned int)v7 >= 0x31 || *((_BYTE *)v4 + v7 - 32) == 0 ) break; } if ( (i & 2) != 0 ) i &= ~4u; a1->field1C = 0; v9 = 0; a1->field18 = 0; while ( v8 != (int *)42 ) { if ( is_digit(a1: (int)v8) ) { v10 = &a1->unk00 + v9; for ( v10[6] = (unsigned int)(v8 - 12); ; v10[6] = (unsigned int)v8 + 10 * v10[6] - 48 ) { v8 = (int *)((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); if ( !is_digit(a1: (int)v8) ) break; } } if ( v9 == 1 ) goto LABEL_24; LABEL_22: if ( v8 == (int *)46 ) { ++v9; v8 = (int *)((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); i |= 0x20u; if ( v9 < 2 ) continue; } goto LABEL_24; } v11 = *a2++; *(&a1->field18 + v9) = v11; v8 = (int *)((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); if ( v9 != 1 ) goto LABEL_22; if ( (a1->field1C & 0x80000000) != 0 ) i &= ~0x20u; LABEL_24: field18 = a1->field18; if ( field18 < 0 ) { i |= 1u; a1->field18 = -field18; } if ( i << 31 != 0 ) i &= ~0x10u; if ( v8 != (int *)108 && v8 != (int *)104 ) { if ( v8 == (int *)76 ) goto LABEL_51; if ( v8 != (int *)106 ) { if ( v8 != (int *)116 && v8 != (int *)122 ) goto LABEL_43; LABEL_51: v14 = 0; LABEL_39: i |= v14; v8 = (int *)((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); goto LABEL_43; } goto LABEL_50; } v13 = v8; v8 = (int *)((int (__fastcall *)(struct tee_fmt_state *))a1->unk0C)(a1); if ( v8 == v13 ) { if ( v13 != (int *)108 ) { v14 = 1024; goto LABEL_39; } LABEL_50: v14 = 128; goto LABEL_39; } if ( v13 == (int *)108 ) v15 = 64; else v15 = 256; i |= v15; LABEL_43: if ( v8 != nullptr ) { if ( (unsigned int)v8 - 65 <= 0x19 ) { v8 += 8; i |= 0x800u; } a1->unk00 = i; vsnprintf_conv_misc(a1, a2: v8); if ( v16 != 0 ) { if ( v16 == 1 ) ++a2; else a2 = (int *)((((unsigned int)a2 + 7) & 0xFFFFFFF8) + 8); continue; } LABEL_4: ((void (*)(void))a1->unk04)(); ++a1->field20; continue; } return a1->field20; } } /* ==== vsnprintf_emit_str [tier=EXACT size=20] ==== */ // Emits a string when the error flag at ctx+20 is clear. int __fastcall vsnprintf_emit_str(struct tee_fmt_state *a1, unsigned __int8 *a2, unsigned int a3) { if ( a1->field14 == 0 ) vsnprintf_out_str(a1, a2, a3); return 1; } /* ==== vsnprintf_emit_wide [tier=EXACT size=20] ==== */ // Emits a wide string when the error flag at ctx+20 is clear. int __fastcall vsnprintf_emit_wide(struct tee_fmt_state *a1, int a2, int a3) { if ( a1->field14 == 0 ) vsnprintf_out_wide(r0_0: a1, a2, a3, a4: 0); return 1; } /* ==== vsnprintf_entry [tier=EXACT size=48] ==== */ // Sets up the output cursor and invokes the formatting core. int __fastcall vsnprintf_entry(struct tee_fmt_state *a1, int a2, int a3, _BYTE *a4) { int v5; // r5 struct tee_fmt_state *v7; // [sp+0h] [bp-8h] BYREF void *v8; // [sp+4h] [bp-4h] v8 = a4; v7 = a1; if ( a2 != 0 ) a1 = (struct tee_fmt_state *)((char *)a1 + a2 - 1); v8 = a1; v5 = vsnprintf_setup(a1: (struct tee_fmt_state *)a3, a2: (int)&v7, a3: (_BYTE **)a4, a4: (int)off_401440 + 4199462); if ( a2 != 0 ) vsnprintf_put(result: nullptr, a2: (_BYTE **)&v7); return v5; } /* ==== vsnprintf_fill [tier=EXACT size=44] ==== */ // Emits the fill character (0x30 '0' when the zero-pad flag is set, else 0x20 space). int __fastcall vsnprintf_fill(struct tee_fmt_state *a1) { unsigned int field18; // r5 unsigned int unk00; // r0 int v4; // r6 int result; // r0 field18 = a1->field18; unk00 = a1->unk00; if ( (unk00 & 0x10) != 0 ) v4 = 48; else v4 = 32; result = unk00 << 31; if ( result == 0 ) { while ( (--field18 & 0x80000000) == 0 ) { ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v4, a2: a1->field08); result = a1->field20 + 1; a1->field20 = result; } } return result; } /* ==== vsnprintf_fmt_hex [tier=EXACT size=28] ==== */ // Hex conversion helper (uses the '0123456789ABCDEF@0X' digit table). int __fastcall vsnprintf_fmt_hex(struct tee_fmt_state *a1, int a2, int *a3) { char *v3; // r4 int v4; // r1 unsigned __int8 v5; // r7 int v6; // r3 unsigned __int64 v10; // r2 struct tee_fmt_state *v11; // r0 v10 = (unsigned int)vsnprintf_narrow_u(result: (struct tee_fmt_state *)*a3, a2: (int *)a1); v11 = a1; if ( (a1->unk00 & 0x800) != 0 ) v3 = off_401B20 + 4201120; else v3 = off_401B20 + 4201140; v4 = 0; while ( v10 != 0 ) { v5 = v3[v10 & 0xF]; v10 >>= 4; *(&v11->field24 + v4++) = v5; } v6 = 0; if ( (v11->unk00 & 8) != 0 ) { if ( a2 == 112 ) { v6 = 1; v3 += 16; } else if ( v4 != 0 ) { v6 = 2; v3 += 17; } } return vsnprintf_pad(a1: v11, a2: v4, a3: (int)v3, a4: v6); } /* ==== vsnprintf_fmt_int [tier=EXACT size=758] ==== */ // Integer/pointer conversion for vsnprintf_core (uses the '0123456789ABCDEFXP' digit table). int __fastcall vsnprintf_fmt_int(struct tee_fmt_state *a1, int a2, int a3) { unsigned int v5; // r6 unsigned int v6; // r7 signed int v7; // r2 unsigned int v8; // r3 BOOL v9; // r8 signed int field1C; // r5 int v11; // r10 unsigned int v12; // r9 __int64 v13; // r2 int v14; // r12 unsigned int v15; // r12 unsigned int v16; // r0 __int64 v17; // kr10_8 char *v18; // r0 int v19; // r11 char v20; // r1 int v21; // r8 int v22; // r1 int v23; // r3 int i; // r1 int v25; // r2 int j; // r1 char *v27; // r2 int v28; // r8 int v29; // r8 unsigned int v30; // r0 int v31; // r1 unsigned int v32; // r0 int v33; // r1 char v34; // r1 int v35; // r8 unsigned __int8 *v36; // r6 int v37; // t1 bool v38; // cf unsigned __int8 *k; // r6 int v40; // r0 int v41; // t1 _BYTE v43[32]; // [sp+0h] [bp-24h] BYREF _BYTE v44[4]; // [sp+20h] [bp-4h] BYREF v5 = *(_DWORD *)(((a3 + 7) & 0xFFFFFFF8) + 4); v6 = *(_DWORD *)((a3 + 7) & 0xFFFFFFF8); v7 = aeabi_dbl_classify(a1: v6, a2: v5); if ( (v5 & 0x80000000) == 0 ) { if ( (a1->unk00 & 2) != 0 ) v8 = 43; else v8 = (8 * a1->unk00) & 0x20; } else { v8 = 45; } v44[0] = v8; v9 = v8 != 0; if ( v7 == 3 || v7 >= 7 ) { vsnprintf_prefix(a1, a2, a3: v7, a4: v8); return 3; } if ( (a1->unk00 & 0x20) != 0 ) field1C = a1->field1C; else field1C = 13; v11 = (v5 >> 20) & 0x7FF; if ( field1C < 13 ) { v12 = v5 >> 20; LODWORD(v13) = 0; v14 = 4 * field1C; if ( (unsigned int)(4 * field1C) < 0x18 ) HIDWORD(v13) = 0x100000u >> v14; else v13 = 0x10000000u >> (v14 - 24); v15 = v14 + 12; v16 = v15 < 0x20 ? v5 << v15 : v6 << (v15 - 32); if ( v16 >= 0x80000000 ) { v17 = __PAIR64__(v5, v6) + v13; v5 = (__PAIR64__(v5, v6) + v13) >> 32; v6 = v17; if ( v16 == 0x80000000 ) { v6 = v17 & ~(_DWORD)v13; v5 &= ~HIDWORD(v13); } if ( v12 != v5 >> 20 ) ++v11; } } if ( (a1->unk00 & 0x800) != 0 ) v18 = off_402564 + 4203380; else v18 = off_402564 + 4203361; v44[v9] = 48; v19 = v9 + 2; v44[v9 + 1] = v18[16]; if ( v11 > 0 ) v20 = 49; else v20 = 48; v21 = 1; v43[0] = v20; if ( v11 != 0 ) { v22 = v11 - 1023; LABEL_34: v11 = v22; goto LABEL_35; } if ( (v6 | (2 * v5)) != 0 ) { v22 = dword_402568; goto LABEL_34; } LABEL_35: if ( field1C > 0 || (a1->unk00 & 8) != 0 ) { v21 = 2; v43[1] = 46; } v23 = v21; for ( i = 0; i < 5; ++i ) { if ( field1C <= 0 ) break; v25 = HIWORD(v5) & 0xF; v5 *= 16; --field1C; v43[v21++] = v18[v25]; } for ( j = 0; j < 8; ++j ) { if ( field1C <= 0 ) break; v27 = &v18[v6 >> 28]; v6 *= 16; --field1C; v43[v21++] = *v27; } if ( (a1->unk00 & 0x20) == 0 ) { while ( v21 > v23 && v43[v21 - 1] == 48 ) --v21; if ( v21 > 0 && v43[v21 - 1] == 46 && (a1->unk00 & 8) == 0 ) --v21; } if ( field1C > 0 ) { v43[v21] = 62; --field1C; ++v21; } v43[v21] = v18[17]; v28 = v21 + 1; if ( v11 >= 0 ) { v43[v28] = 43; } else { v11 = -v11; v43[v28] = 45; } v29 = v28 + 1; if ( v11 >= 1000 ) { v30 = v11 / 0x3E8u; v11 = v31; v43[v29++] = v30 + 48; LABEL_61: v32 = v11 / 0x64u; v11 = v33; v43[v29++] = v32 + 48; LABEL_63: v43[v29++] = v11 / 0xAu + 48; goto LABEL_64; } if ( v11 >= 100 ) goto LABEL_61; if ( v11 >= 10 ) goto LABEL_63; LABEL_64: v43[v29] = v34 + 48; v35 = v29 + 1; a1->field18 -= v35 + field1C + v19; if ( (a1->unk00 & 0x10) == 0 ) vsnprintf_fill(a1); v36 = v44; a1->field20 += v19; while ( 1 ) { v38 = v19-- != 0; if ( !v38 ) break; v37 = *v36++; ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v37, a2: a1->field08); } if ( (a1->unk00 & 0x10) != 0 ) vsnprintf_fill(a1); for ( k = v43; ; ++k ) { v38 = v35-- != 0; if ( !v38 ) break; v41 = *k; v40 = v41; if ( v41 == 62 ) { a1->field20 += field1C; while ( 1 ) { v38 = field1C-- != 0; if ( !v38 ) break; ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: 48, a2: a1->field08); } } else { ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v40, a2: a1->field08); ++a1->field20; } } vsnprintf_pad_left(a1); return 3; } /* ==== vsnprintf_fmt_ll [tier=EXACT size=606] ==== */ // 64-bit conversion for vsnprintf_core. void __fastcall vsnprintf_fmt_ll(struct tee_fmt_state *a1, int a2, int a3) { int v3; // r5 int v4; // r6 int v5; // r9 int v6; // r10 int v7; // r11 signed int v10; // r2 unsigned int v11; // r0 signed int field1C; // r7 int v13; // r3 int v14; // r0 int v15; // r0 int v16; // r3 unsigned __int8 *v17; // r7 int v18; // r8 char v19; // r1 bool v20; // cc unsigned __int8 *v21; // r7 char v22; // r0 _BYTE *v23; // r8 int v24; // r0 int v25; // r0 int *v26; // r0 int v27; // t1 int v28; // [sp+0h] [bp-44h] _BYTE v29[32]; // [sp+4h] [bp-40h] BYREF unsigned int v30; // [sp+24h] [bp-20h] unsigned int v31[2]; // [sp+28h] [bp-1Ch] BYREF int v32; // [sp+30h] [bp-14h] BYREF signed int v33; // [sp+34h] [bp-10h] int v34; // [sp+38h] [bp-Ch] _BYTE v35[7]; // [sp+3Ch] [bp-8h] BYREF char v36; // [sp+43h] [bp-1h] BYREF *(_QWORD *)v31 = *(_QWORD *)((a3 + 7) & 0xFFFFFFF8); v10 = aeabi_dbl_classify(a1: v31[0], a2: v31[1]); if ( (v31[1] & 0x80000000) == 0 ) { if ( (a1->unk00 & 2) != 0 ) v11 = 43; else v11 = (8 * a1->unk00) & 0x20; } else { v11 = 45; } v30 = v11; if ( v10 == 3 || v10 >= 7 ) { vsnprintf_prefix(a1, a2, a3: v10, a4: v11); goto LABEL_78; } if ( (a1->unk00 & 0x20) != 0 ) field1C = a1->field1C; else field1C = 6; switch ( a2 ) { case 'e': if ( field1C < 17 ) v13 = field1C + 1; else v13 = 17; aeabi_dbl_decompose(a1: &v32, a2: v29, a3: v31, a4: v13, a5: 0); v14 = v32; v4 = 0; v3 = field1C + 1; v7 = v33; break; case 'f': v5 = 0x80000000; aeabi_dbl_decompose(a1: &v32, a2: v29, a3: v31, a4: field1C, a5: 1); v7 = v33; v3 = v33; v4 = 0; if ( v34 == 0 ) v3 = v32 + field1C + 1; v15 = field1C - v3; if ( field1C - v3 >= 0 ) { v3 = field1C + 1; v4 = -1 - v15; } v6 = v3 - field1C; goto LABEL_45; case 'g': if ( field1C < 1 ) field1C = 1; if ( field1C <= 17 ) v16 = field1C; else v16 = 17; aeabi_dbl_decompose(a1: &v32, a2: v29, a3: v31, a4: v16, a5: 0); v14 = v32; v3 = field1C; v4 = 0; v7 = v33; if ( (a1->unk00 & 8) == 0 ) { if ( v33 < field1C ) v3 = v33; while ( v3 > 1 && v29[v3 - 1] == 48 ) --v3; } if ( v32 < field1C && v32 >= -4 ) { if ( v32 > 0 ) { if ( v32 + 1 > v3 ) v3 = v32 + 1; } else { v3 -= v32; v4 = v32; } v6 = v32 - v4 + 1; v14 = 0x80000000; goto LABEL_44; } break; default: LABEL_45: if ( (a1->unk00 & 8) == 0 && v6 >= v3 ) v6 = -1; v17 = (unsigned __int8 *)&v36; v36 = 0; if ( v5 != 0x80000000 ) { v18 = 2; v28 = 43; if ( v5 < 0 ) { v5 = -v5; v28 = 45; } while ( 1 ) { v20 = v18-- <= 0; if ( v20 && v5 == 0 ) break; v5 = udiv10_32(a1: v5); *--v17 = v19 + 48; } *(v17 - 1) = v28; v21 = v17 - 1; if ( (a1->unk00 & 0x800) != 0 ) v22 = 69; else v22 = 101; *(v21 - 1) = v22; v17 = v21 - 1; } v23 = (_BYTE *)(v35 - v17 + 7); v24 = v30; if ( v30 != 0 ) v24 = 1; a1->field18 = a1->field18 - (_DWORD)&v23[v24 + v3 + (v6 >> 31)] - 1; if ( (a1->unk00 & 0x10) == 0 ) vsnprintf_fill(a1); if ( v30 != 0 ) { ((void (__fastcall *)(unsigned int, unsigned int))a1->unk04)(a1: v30, a2: a1->field08); ++a1->field20; } if ( (a1->unk00 & 0x10) != 0 ) vsnprintf_fill(a1); while ( 1 ) { v20 = v3-- <= 0; if ( v20 ) break; if ( v4 < 0 || v7 <= v4 ) v25 = 48; else v25 = (unsigned __int8)v29[v4]; ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v25, a2: a1->field08); ++a1->field20; ++v4; if ( --v6 == 0 ) { v26 = ras_locale_base(); ((void (__fastcall *)(_DWORD, unsigned int))a1->unk04)( a1: *(unsigned __int8 *)(v26[3] + *(_DWORD *)v26[3]), a2: a1->field08); ++a1->field20; } } while ( 1 ) { v20 = (int)v23-- <= 0; if ( v20 ) break; v27 = *v17++; ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v27, a2: a1->field08); ++a1->field20; } vsnprintf_pad_left(a1); LABEL_78: JUMPOUT(0x401EFC); } v6 = 1; LABEL_44: v5 = v14; goto LABEL_45; } /* ==== vsnprintf_fmt_octal [tier=EXACT size=24] ==== */ // Octal conversion for vsnprintf_core. int __fastcall vsnprintf_fmt_octal(struct tee_fmt_state *a1, int a2, int *a3) { int v3; // r1 unsigned __int8 v4; // r5 unsigned int unk00; // r4 int v6; // r3 int *v7; // r2 unsigned __int64 v10; // r2 struct tee_fmt_state *v11; // r0 v10 = (unsigned int)vsnprintf_narrow_u(result: (struct tee_fmt_state *)*a3, a2: (int *)a1); v11 = a1; v3 = 0; while ( v10 != 0 ) { v4 = (v10 & 7) + 48; v10 >>= 3; *(&a1->field24 + v3++) = v4; } unk00 = a1->unk00; v6 = 0; v7 = &dword_401A88; if ( (v11->unk00 & 8) != 0 && (unk00 & 0x20 | v3) != 0 ) { v6 = 1; v7 = &dword_401A8C; --v11->field1C; } return vsnprintf_pad(a1: v11, a2: v3, a3: (int)v7, a4: v6); } /* ==== vsnprintf_fmt_signed [tier=EXACT size=108] ==== */ // Signed integer conversion for vsnprintf_core. // local variable allocation has failed, the output may be wrong! int __fastcall vsnprintf_fmt_signed(struct tee_fmt_state *a1, int a2) { int v2; // r2 struct tee_fmt_state *v3; // r8 int v4; // r5 int v5; // r2 __int64 v6; // kr00_8 int *v7; // r6 int v8; // r1 int v9; // r1 int v10; // r4 char v11; // r2 v3 = a1; v4 = 0; v6 = *(_QWORD *)((v2 + 7) & 0xFFFFFFF8); v5 = *(_DWORD *)(((v2 + 7) & 0xFFFFFFF8) + 4); a1 = (struct tee_fmt_state *)v6; v7 = &dword_401A10; if ( v8 != 245 ) { if ( v5 < 0 ) { a1 = (struct tee_fmt_state *)-(int)v6; v5 = (unsigned __int64)-__SPAIR64__(v5, v6) >> 32; v7 = &dword_401A14; LABEL_8: v4 = 1; goto LABEL_9; } if ( (v3->unk00 & 2) != 0 ) { v7 = &dword_401A18; goto LABEL_8; } if ( (v3->unk00 & 4) != 0 ) { v7 = &dword_401A1C; goto LABEL_8; } } LABEL_9: v9 = v5; v10 = 0; while ( *(_QWORD *)&a1 != 0 ) { *(_QWORD *)&a1 = udiv10(a1: *(unsigned __int64 *)&a1); *(&v3->field24 + v10++) = v11 + 48; } return vsnprintf_pad(a1: v3, a2: v10, a3: (int)v7, a4: v4); } /* ==== vsnprintf_getc [tier=EXACT size=10] ==== */ // Reads the next format-string byte and advances the cursor at ctx+16. int __fastcall vsnprintf_getc(struct tee_fmt_state *a1) { unsigned __int8 *field10; // r1 field10 = (unsigned __int8 *)a1->field10; a1->field10 = (unsigned int)(field10 + 1); return *field10; } /* ==== vsnprintf_narrow_s [tier=EXACT size=18] ==== */ // Narrows a signed argument to char/short per the length flags. int __fastcall vsnprintf_narrow_s(struct tee_fmt_state *result, int *a2) { int v2; // r1 v2 = *a2; if ( (v2 & 0x400) != 0 ) return (char)result; if ( (v2 & 0x100) != 0 ) return (__int16)result; return (int)result; } /* ==== vsnprintf_narrow_u [tier=EXACT size=18] ==== */ // Narrows an unsigned argument to char/short per the length flags. int __fastcall vsnprintf_narrow_u(struct tee_fmt_state *result, int *a2) { int v2; // r1 v2 = *a2; if ( (v2 & 0x400) != 0 ) return (unsigned __int8)result; if ( (v2 & 0x100) != 0 ) return (unsigned __int16)result; return (int)result; } /* ==== vsnprintf_out_str [tier=EXACT size=82] ==== */ // Emits a string, bounded by the precision at ctx+28. int __fastcall vsnprintf_out_str(struct tee_fmt_state *a1, unsigned __int8 *a2, unsigned int a3) { unsigned __int8 *v3; // r4 unsigned int i; // r3 unsigned __int8 *v6; // r6 int v7; // t1 v3 = a2; if ( a3 == 1 ) { i = 1; } else { if ( (a1->unk00 & 0x20) != 0 ) a3 = a1->field1C; for ( i = 0; i < a3 && a2[i] != 0; ++i ) ; } v6 = &a2[i]; a1->field18 -= i; a1->field20 += i; vsnprintf_fill(a1); while ( v3 < v6 ) { v7 = *v3++; ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v7, a2: a1->field08); } return vsnprintf_pad_left(a1); } /* ==== vsnprintf_out_wide [tier=EXACT size=182] ==== */ // Emits a wide/multi-byte string through the vsnprintf output callback, honouring the // precision limit at ctx+28. // local variable allocation has failed, the output may be wrong! __int64 __fastcall vsnprintf_out_wide(struct tee_fmt_state *r0_0, int a2, int a3, int a4) { int v5; // r1 int v6; // r10 __int64 *v8; // r8 signed int v9; // r7 int v10; // r6 int v11; // r0 int i; // r0 unsigned int v13; // r9 unsigned int j; // r5 int v15; // r8 __int64 v17; // [sp+0h] [bp-10h] BYREF struct tee_fmt_state a1; // [sp+8h] [bp-8h] BYREF v17 = *(_QWORD *)&r0_0; a1.unk00 = a3; a1.unk04 = a4; v6 = v5; v8 = (__int64 *)((char *)off_4019A0 + 4200698); v9 = 0; v10 = 0; v17 = *(_QWORD *)((char *)off_4019A0 + 4200698); while ( ((r0_0->unk00 & 0x20) == 0 || (signed int)r0_0->field1C > v9) && (v10 < a3 || *(_WORD *)(v6 + 2 * v10) != 0) ) { v11 = vsnprintf_wide_char(&a1, a2: *(unsigned __int16 *)(v6 + 2 * v10), a3: (int)&v17); if ( v11 != -1 ) { if ( (r0_0->unk00 & 0x20) != 0 && v9 + v11 > r0_0->field1C ) break; v9 += v11; } ++v10; } r0_0->field18 -= v9; vsnprintf_fill(a1: r0_0); v17 = *v8; for ( i = 0; ; i = v15 + 1 ) { v15 = i; if ( i >= v10 ) break; v13 = vsnprintf_wide_char(&a1, a2: *(unsigned __int16 *)(v6 + 2 * i), a3: (int)&v17); if ( v13 != -1 ) { for ( j = 0; j < v13; ++j ) ((void (__fastcall *)(_DWORD, unsigned int))r0_0->unk04)( a1: *((unsigned __int8 *)&a1.unk00 + j), a2: r0_0->field08); } } r0_0->field20 += v9; vsnprintf_pad_left(a1: r0_0); return v17; } /* ==== vsnprintf_pad [tier=EXACT size=178] ==== */ // Emits padding for the current conversion. int __fastcall vsnprintf_pad(struct tee_fmt_state *a1, int a2, int a3, int a4) { unsigned __int8 *p_field24; // r8 unsigned int unk00; // r1 signed int field1C; // r0 int v11; // r7 int i; // r6 bool v13; // cc p_field24 = &a1->field24; unk00 = a1->unk00; if ( (a1->unk00 & 0x20) != 0 ) { field1C = a1->field1C; a1->unk00 = unk00 & 0xFFFFFFEF; } else { field1C = 1; } if ( field1C <= a2 ) v11 = 0; else v11 = field1C - a2; a1->field18 -= v11 + a2 + a4; if ( (a1->unk00 & 0x10) == 0 ) vsnprintf_fill(a1); for ( i = 0; i < a4; ++i ) { ((void (__fastcall *)(_DWORD, unsigned int))a1->unk04)(a1: *(unsigned __int8 *)(a3 + i), a2: a1->field08); ++a1->field20; } if ( (a1->unk00 & 0x10) != 0 ) vsnprintf_fill(a1); while ( 1 ) { v13 = v11-- <= 0; if ( v13 ) break; ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: 48, a2: a1->field08); ++a1->field20; } while ( 1 ) { v13 = a2-- <= 0; if ( v13 ) break; ((void (__fastcall *)(_DWORD, unsigned int))a1->unk04)(a1: p_field24[a2], a2: a1->field08); ++a1->field20; } vsnprintf_pad_left(a1); if ( (a1->unk00 & 0x80) != 0 ) return 2; else return 1; } /* ==== vsnprintf_pad_left [tier=EXACT size=34] ==== */ // Emits left padding (spaces) through the output callback. int __fastcall vsnprintf_pad_left(struct tee_fmt_state *a1) { unsigned int field18; // r5 int result; // r0 field18 = a1->field18; result = LOBYTE(a1->unk00) << 31; if ( result != 0 ) { while ( (--field18 & 0x80000000) == 0 ) { ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: 32, a2: a1->field08); result = a1->field20 + 1; a1->field20 = result; } } return result; } /* ==== vsnprintf_prefix [tier=EXACT size=112] ==== */ // Selects the numeric prefix ('0x'/'0X'/sign) for the current conversion. int __fastcall vsnprintf_prefix(struct tee_fmt_state *a1, int a2, int a3, int a4) { int v6; // r6 unsigned int unk00; // r1 unsigned int v8; // r0 int (__fastcall *v9)(int, int, int); // r5 unsigned int v10; // r0 unsigned int field20; // r0 int v12; // t1 v6 = 3; unk00 = a1->unk00; v8 = a1->unk00 & 0x800; if ( a3 < 7 ) { if ( v8 != 0 ) v9 = (int (__fastcall *)(int, int, int))&loc_4026C8; else v9 = (int (__fastcall *)(int, int, int))&loc_4026CC; } else if ( v8 != 0 ) { v9 = aeabi_dbl_scale_thunk; } else { v9 = (int (__fastcall *)(int, int, int))&loc_4026C4; } a1->unk00 = unk00 & 0xFFFFFFEF; v10 = a1->field18 - 3; a1->field18 = v10; if ( a4 != 0 ) a1->field18 = v10 - 1; vsnprintf_fill(a1); if ( a4 != 0 ) { ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: a4, a2: a1->field08); field20 = a1->field20 + 1; a1->field20 = field20; } else { field20 = a1->field20; } a1->field20 = field20 + 3; while ( v6-- != 0 ) { v12 = *(unsigned __int8 *)v9; v9 = (int (__fastcall *)(int, int, int))((char *)v9 + 1); ((void (__fastcall *)(int, unsigned int))a1->unk04)(a1: v12, a2: a1->field08); } return vsnprintf_pad_left(a1); } /* ==== vsnprintf_put [tier=EXACT size=10] ==== */ // Writes one byte to the output cursor and advances it. char __fastcall vsnprintf_put(struct tee_fmt_state *result, _BYTE **a2) { _BYTE *v2; // r2 v2 = *a2; *v2 = (_BYTE)result; *a2 = v2 + 1; return (char)result; } /* ==== vsnprintf_put_bounded [tier=EXACT size=16] ==== */ // Writes one byte to the output cursor if it is below the limit. char __fastcall vsnprintf_put_bounded(struct tee_fmt_state *result, __int64 *a2) { __int64 v2; // r2 v2 = *a2; if ( (unsigned int)v2 < HIDWORD(v2) ) { *(_DWORD *)a2 = v2 + 1; *(_BYTE *)v2 = (_BYTE)result; } return (char)result; } /* ==== vsnprintf_reentry [tier=EXACT size=4] ==== */ // Tail-jump back into vsnprintf_core at 0x401B46. void __fastcall vsnprintf_reentry() { JUMPOUT(0x401B46); } /* ==== vsnprintf_setup [tier=EXACT size=32] ==== */ // Builds the vsnprintf context (output callback, cursor, limit) and runs vsnprintf_core. int __fastcall vsnprintf_setup(struct tee_fmt_state *a1, int a2, _BYTE **a3, int a4) { struct tee_fmt_state v5; // [sp+0h] [bp-3Ch] BYREF v5.unk04 = a4; v5.field08 = a2; v5.field14 = 0; v5.unk0C = (unsigned int)off_4018C8 + 4200632; v5.field10 = (unsigned int)a1; return vsnprintf_core(a1: &v5, a2: (int *)a3); } /* ==== vsnprintf_wide_char [tier=EXACT size=72] ==== */ // Converts one wide character to output bytes. int __fastcall vsnprintf_wide_char(struct tee_fmt_state *a1, unsigned int a2, int a3) { int *v6; // r0 int v7; // r3 v6 = ras_locale_ptr(); v7 = *v6; if ( *(_BYTE *)(*v6 + 257) == 1 ) return ((int (__fastcall *)(struct tee_fmt_state *, unsigned int, int, _DWORD))(*(_DWORD *)(v7 + 263) + v7 + 263))( a1, a2, a3, a4: 0); if ( a2 > 0xFF || *(_BYTE *)(v7 + a2) == 0 ) return -1; LOBYTE(a1->unk00) = a2; return 1; }