function_s findCfgCtrGetLanguage(u8* code_data, u32 code_size) { if(!code_data || !code_size)return (function_s){0,0}; u32* code_data32 = (u32*)code_data; u32 code_size32 = code_size / 4; int i, j; for(i=0; i<code_size32; i++) { if(code_data32[i] == 0x000A0002) { function_s c = findFunction(code_data32, code_size32, i-4); for(j=c.start; j<=c.end; j++) { darm_t d; if(!darm_armv7_disasm(&d, code_data32[j]) && (d.instr == I_LDR && d.Rn == PC && (i-j-2)*4 == d.imm)) { return c; } } } } return (function_s){0,0}; }
bool findNimCheckSysupdateAvailableSOAPCallback(u32* code_data32, u32 code_size32, function_s candidate, u32 ref) { int j; for(j=candidate.start; j<=candidate.end+1; j++) { darm_t d; if(!darm_armv7_disasm(&d, code_data32[j]) && (d.instr == I_B && d.cond >= C_AL)) { function_s c = findFunction(code_data32, code_size32, (d.imm / 4) + j + 2); int i, total = 0; for(i=c.start; i<c.end; i++) { if(!darm_armv7_disasm(&d, code_data32[i]) && (d.instr == I_MOV && d.imm == 0xA0000))total |= 1; if(!darm_armv7_disasm(&d, code_data32[i]) && (d.instr == I_SVC && d.imm == 0x32))total |= 2; } if(total == 3) nimCheckSysupdateAvailableSOAP = c; return total == 3; } } return false; }
void patchCfgCtrGetLanguage(u8* code_data, u32 code_size, function_s c, u8 language_code) { if(!code_data || !code_size || c.start == c.end || c.end == 0)return; u32* code_data32 = (u32*)code_data; int i; for(i = c.end; i>c.start; i--) { darm_t d; if(!darm_armv7_disasm(&d, code_data32[i]) && (d.instr == I_LDRB && d.Rt == 0)) { printf("%08X\n", i * 4 + 0x00100000); code_data32[i] = 0xE3A00000 | (d.Rt << 12) | language_code; break; } } }
void patchCfgSecureInfoGetRegion(u8* code_data, u32 code_size, function_s c, u8 region_code) { if(!code_data || !code_size || c.start == c.end || c.end == 0)return; u32* code_data32 = (u32*)code_data; int i; for(i = c.start; i<c.end; i++) { darm_t d; if(!darm_armv7_disasm(&d, code_data32[i]) && d.instr == I_LDRB) { printf("%08X %d\n", i * 4 + 0x00100000, d.Rt); code_data32[i] = 0xE3A00000 | (d.Rt << 12) | region_code; break; } } }
int darm_disasm(darm_t *d, uint16_t w, uint16_t w2, uint32_t addr) { // if the least significant bit is not set, then this is // an ARMv7 instruction if((addr & 1) == 0) { // disassemble and check for error return values if(darm_armv7_disasm(d, (w2 << 16) | w) < 0) { return 0; } else { return 2; } } // magic table constructed based on section A6.1 of the ARM manual static uint8_t is_thumb2[0x20] = { [b11101] = 1, [b11110] = 1, [b11111] = 1, }; // check whether this is a Thumb or Thumb2 instruction if(is_thumb2[w >> 11] == 0) { // this is a Thumb instruction if(darm_thumb_disasm(d, w) < 0) { return 0; } else { return 1; } } // this is a Thumb2 instruction if(darm_thumb2_disasm(d, w, w2) < 0) { return 0; } else { return 2; } }
void patchNimTitleVersion(u8* code_data, u32 code_size, u32 version) { if(!code_data || !code_size)return; function_s ltww = findNimListTitlesWrapperWrapper(code_data, code_size); if(ltww.start == ltww.end)return; u32 ref = 0; function_s ltwwr = findFunctionReferenceFunction(code_data, code_size, ltww, NULL, &ref); if(ltwwr.start == ltwwr.end)return; u32* code_data32 = (u32*)code_data; // u32 code_size32 = code_size / 4; u32 stub_offset = findFatalerr(code_data, code_size).start + 1 + STUB_NIM_OFFSET; u32 stub_size32 = nim_titleversion_stub_stub_size / 4; memcpy(&code_data32[stub_offset], nim_titleversion_stub_stub, stub_size32 * 4); code_data32[stub_offset + stub_size32 - 1] = version; // printf("yo %08X\n", ref * 4 + 0x00100000); int j; for(j=ref; j<=ltwwr.end+1; j++) { darm_t d; if(!darm_armv7_disasm(&d, code_data32[j]) && (d.instr == I_STM && d.cond >= C_AL)) { // printf("%08X - %08X - %d\n", j * 4 + 0x00100000, code_data32[j], getLowestRegister(&d)); code_data32[stub_offset + 0] = 0xE59F0000 | ((getLowestRegister(&d) & 0xf) << 12) | (code_data32[stub_offset + 0] & 0xfff); // overwritten with an ldr rX, [pc, #self] code_data32[stub_offset + 1] = code_data32[j]; code_data32[j] = 0xEB000000 | ((stub_offset - j - 2) & 0x00FFFFFF); // branch with link return; } } }
void arm2_execute_run(int tube_cycles) { #ifdef TRACE int i; #endif UINT32 pc; UINT32 insn; //int m_icount = number; do { //debugger_instruction_hook(this, R15 & ADDRESS_MASK); /* load instruction */ pc = R15; #ifdef INCLUDE_DEBUGGER if (arm2_debug_enabled) { debug_preexec(&arm2_cpu_debug, pc & ADDRESS_MASK); } #endif insn = cpu_read32( pc & ADDRESS_MASK ); #ifdef TRACE if ((pc & ADDRESS_MASK) == 0xa060) { m_trace = 1; } if (m_trace) { printf("%08X %08X ", pc, insn); for (i = eR0; i <= eR7; i++) { printf("%08X ", m_sArmRegister[i]); } if(darm_armv7_disasm(&d, insn) == 0 && darm_str2(&d, &str, 0) == 0) { printf("%s\r\n", str.total); } else { printf("***\r\n"); } } if ((pc & ADDRESS_MASK) == 0xa0c0) { m_trace = 0; } if ((pc & ADDRESS_MASK) == 0xa2ac) { m_trace = 0; } if ((insn & 0x0D900000) == 0x01000000) { printf("S bit not set in %08x at %08x\r\n", insn, pc & ADDRESS_MASK); insn |= INSN_S; } #endif switch (insn >> INSN_COND_SHIFT) { case COND_EQ: if (Z_IS_CLEAR(pc)) goto L_Next; break; case COND_NE: if (Z_IS_SET(pc)) goto L_Next; break; case COND_CS: if (C_IS_CLEAR(pc)) goto L_Next; break; case COND_CC: if (C_IS_SET(pc)) goto L_Next; break; case COND_MI: if (N_IS_CLEAR(pc)) goto L_Next; break; case COND_PL: if (N_IS_SET(pc)) goto L_Next; break; case COND_VS: if (V_IS_CLEAR(pc)) goto L_Next; break; case COND_VC: if (V_IS_SET(pc)) goto L_Next; break; case COND_HI: if (C_IS_CLEAR(pc) || Z_IS_SET(pc)) goto L_Next; break; case COND_LS: if (C_IS_SET(pc) && Z_IS_CLEAR(pc)) goto L_Next; break; case COND_GE: if (!(pc & N_MASK) != !(pc & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */ break; case COND_LT: if (!(pc & N_MASK) == !(pc & V_MASK)) goto L_Next; break; case COND_GT: if (Z_IS_SET(pc) || (!(pc & N_MASK) != !(pc & V_MASK))) goto L_Next; break; case COND_LE: if (Z_IS_CLEAR(pc) && (!(pc & N_MASK) == !(pc & V_MASK))) goto L_Next; break; case COND_NV: goto L_Next; } /* Condition satisfied, so decode the instruction */ if ((insn & 0x0fc000f0u) == 0x00000090u) /* Multiplication */ { HandleMul(insn); R15 += 4; } else if (!(insn & 0x0c000000u)) /* Data processing */ { HandleALU(insn); } else if ((insn & 0x0c000000u) == 0x04000000u) /* Single data access */ { HandleMemSingle(insn); R15 += 4; } else if ((insn & 0x0e000000u) == 0x08000000u ) /* Block data access */ { HandleMemBlock(insn); R15 += 4; } else if ((insn & 0x0e000000u) == 0x0a000000u) /* Branch */ { HandleBranch(insn); } else if ((insn & 0x0f000000u) == 0x0e000000u) /* Coprocessor */ { if (m_copro_type == ARM_COPRO_TYPE_VL86C020) HandleCoProVL86C020(insn); else HandleCoPro(insn); R15 += 4; } else if ((insn & 0x0f000000u) == 0x0f000000u) /* Software interrupt */ { pc=R15+4; R15 = eARM_MODE_SVC; /* Set SVC mode so PC is saved to correct R14 bank */ SetRegister( 14, pc ); /* save PC */ R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x8|eARM_MODE_SVC|I_MASK|(pc&MODE_MASK); CYCLE_COUNT(2 * S_CYCLE + N_CYCLE); } else /* Undefined */ { logerror("%08x: Undefined instruction\n",R15); L_Next: CYCLE_COUNT(S_CYCLE); R15 += 4; } //arm2_check_irq_state(); tubeUseCycles(1); } while (tubeContinueRunning()); //while( m_icount > 0 ); //while (number--); } /* arm_execute */