static void set_debug_next(uint32_t *next) { if (debug_next != NULL) RAM_FLAGS(debug_next) &= ~RF_EXEC_DEBUG_NEXT; if (next != NULL) { if (RAM_FLAGS(next) & RF_CODE_TRANSLATED) flush_translations(); RAM_FLAGS(next) |= RF_EXEC_DEBUG_NEXT; } debug_next = next; }
void write_action(void *ptr) { uint32_t addr = phys_mem_addr(ptr); volatile uint32_t *flags = &RAM_FLAGS((size_t)ptr & ~3); if (*flags & RF_WRITE_BREAKPOINT) { if (!gdb_connected) emuprintf("Hit write breakpoint at %08x. Entering debugger.\n", addr); debugger(DBG_WRITE_BREAKPOINT, addr); } #ifndef NO_TRANSLATION if (*flags & RF_CODE_TRANSLATED) { logprintf(LOG_CPU, "Wrote to translated code at %08x. Deleting translations.\n", addr); invalidate_translation(*flags >> RFS_TRANSLATION_INDEX); } else {
void gdbstub_loop(void) { int addr; int length; char *ptr, *ptr1; void *ramaddr; unsigned long regbuf[NUMREGS]; bool reply, set; while (1) { remcomOutBuffer[0] = 0; ptr = getpacket(); if (!ptr) { gdbstub_disconnect(); return; } reply = true; switch (*ptr++) { case '?': send_stop_reply(SIGNAL_TRAP, NULL, 0); reply = false; // already done break; case 'g': /* return the value of the CPU registers */ get_registers(regbuf); ptr = remcomOutBuffer; ptr = mem2hex(regbuf, ptr, NUMREGS * sizeof(unsigned long)); break; case 'G': /* set the value of the CPU registers - return OK */ hex2mem(ptr, regbuf, NUMREGS * sizeof(unsigned long)); set_registers(regbuf); strcpy(remcomOutBuffer,"OK"); break; case 'p': /* pn Read the value of register n */ if (hexToInt(&ptr, &addr) && (size_t)addr < sizeof(regbuf)) { mem2hex(get_registers(regbuf) + addr, remcomOutBuffer, sizeof(unsigned long)); } else { strcpy(remcomOutBuffer,"E01"); } break; case 'P': /* Pn=r Write register n with value r */ ptr = strtok(ptr, "="); if (hexToInt(&ptr, &addr) && (ptr=strtok(NULL, "")) && (size_t)addr < sizeof(regbuf) // TODO hex2mem doesn't check the format && hex2mem((char*)ptr, &get_registers(regbuf)[addr], sizeof(u32)) ) { set_registers(regbuf); strcpy(remcomOutBuffer, "OK"); } else { strcpy(remcomOutBuffer,"E01"); } break; case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ /* Try to read %x,%x */ if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length)) { ramaddr = virt_mem_ptr(addr, length); if (!ramaddr || mem2hex(ramaddr, remcomOutBuffer, length)) break; strcpy(remcomOutBuffer, "E03"); } else strcpy(remcomOutBuffer,"E01"); break; case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ /* Try to read '%x,%x:' */ if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length) && *ptr++ == ':') { ramaddr = virt_mem_ptr(addr, length); if (!ramaddr) { strcpy(remcomOutBuffer, "E03"); break; } if (range_translated((u32)ramaddr, (u32)((char *)ramaddr + length))) flush_translations(); if (hex2mem(ptr, ramaddr, length)) strcpy(remcomOutBuffer, "OK"); else strcpy(remcomOutBuffer, "E03"); } else strcpy(remcomOutBuffer, "E02"); break; case 'S': /* Ssig[;AA..AA] Step with signal at address AA..AA(optional). Same as 's' for us. */ ptr = strchr(ptr, ';'); /* skip the signal */ if (ptr) ptr++; case 's': /* s[AA..AA] Step at address AA..AA(optional) */ cpu_events |= EVENT_DEBUG_STEP; goto parse_new_pc; case 'C': /* Csig[;AA..AA] Continue with signal at address AA..AA(optional). Same as 'c' for us. */ ptr = strchr(ptr, ';'); /* skip the signal */ if (ptr) ptr++; case 'c': /* c[AA..AA] Continue at address AA..AA(optional) */ parse_new_pc: if (ptr && hexToInt(&ptr, &addr)) { arm.reg[15] = addr; } return; case 'q': if (!strcmp("Offsets", ptr)) { sprintf(remcomOutBuffer, "Text=%x;Data=%x;Bss=%x", ndls_debug_alloc_block, ndls_debug_alloc_block, ndls_debug_alloc_block); } break; case 'Z': /* 0|1|2|3|4,addr,kind */ set = true; goto z; case 'z': /* 0|1|2|3|4,addr,kind */ set = false; // kinds other than 4 aren't supported z: ptr1 = ptr++; ptr = strtok(ptr, ","); if (ptr && hexToInt(&ptr, &addr) && (ramaddr = virt_mem_ptr(addr & ~3, 4))) { u32 *flags = &RAM_FLAGS(ramaddr); switch (*ptr1) { case '0': // mem breakpoint case '1': // hw breakpoint if (set) { if (*flags & RF_CODE_TRANSLATED) flush_translations(); *flags |= RF_EXEC_BREAKPOINT; } else *flags &= ~RF_EXEC_BREAKPOINT; break; case '2': // write watchpoint case '4': // access watchpoint if (set) *flags |= RF_WRITE_BREAKPOINT; else *flags &= ~RF_WRITE_BREAKPOINT; if (*ptr1 != 4) break; case '3': // read watchpoint, access watchpoint if (set) *flags |= RF_READ_BREAKPOINT; else *flags &= ~RF_READ_BREAKPOINT; break; default: goto reply; } strcpy(remcomOutBuffer, "OK"); } else strcpy(remcomOutBuffer, "E01"); break; } /* switch */ reply: /* reply to the request */ if (reply) putpacket(remcomOutBuffer); } }
void translate(uint32_t start_pc, uint32_t *start_insnp) { out = insn_bufptr; outj = jtbl_bufptr; uint32_t pc = start_pc; uint32_t *insnp = start_insnp; if (next_index >= MAX_TRANSLATIONS) error("too many translations"); uint8_t *insn_start; int stop_here = 0; while (1) { if (out >= &insn_buffer[INSN_BUFFER_SIZE - 1000]) error("Out of instruction space"); if (outj >= &jtbl_buffer[sizeof jtbl_buffer / sizeof *jtbl_buffer]) error("Out of jump table space"); insn_start = out; if ((pc ^ start_pc) & ~0x3FF) { //printf("stopping translation - end of page\n"); goto branch_conditional; } if (RAM_FLAGS(insnp) & (RF_EXEC_BREAKPOINT | RF_EXEC_DEBUG_NEXT | RF_EXEC_HACK | RF_CODE_TRANSLATED | RF_CODE_NO_TRANSLATE)) { //printf("stopping translation - at breakpoint %x (%x)\n", pc); goto branch_conditional; } uint32_t insn = *insnp; /* Condition code */ int cond = insn >> 28; int jcc = JZ; uint8_t *cond_jmp_offset = NULL; switch (cond >> 1) { case 0: /* EQ (Z), NE (!Z) */ emit_cmp_flag_immediate(&arm.cpsr_z, 0); break; case 1: /* CS (C), CC (!C) */ emit_cmp_flag_immediate(&arm.cpsr_c, 0); break; case 2: /* MI (N), PL (!N) */ emit_cmp_flag_immediate(&arm.cpsr_n, 0); break; case 3: /* VS (V), VC (!V) */ emit_cmp_flag_immediate(&arm.cpsr_v, 0); break; case 4: /* HI (!Z & C), LS (Z | !C) */ emit_mov_x86reg8_flag(AL, &arm.cpsr_z); emit_alu_x86reg8_flag(CMP, AL, &arm.cpsr_c); jcc = JAE; // execute if Z is less than C break; case 5: /* GE (N = V), LT (N != V) */ emit_mov_x86reg8_flag(AL, &arm.cpsr_n); emit_alu_x86reg8_flag(CMP, AL, &arm.cpsr_v); jcc = JNZ; break; case 6: /* GT (!Z & N = V), LE (Z | N != V) */ emit_mov_x86reg8_flag(AL, &arm.cpsr_n); emit_alu_x86reg8_flag(XOR, AL, &arm.cpsr_v); emit_alu_x86reg8_flag(OR, AL, &arm.cpsr_z); jcc = JNZ; break; case 7: /* AL */ if (cond & 1) goto unimpl; goto no_condition; } /* If condition not met, jump around code. * (If ARM condition code is inverted, invert x86 code too) */ emit_byte(jcc ^ (cond & 1)); emit_byte(0); cond_jmp_offset = out; no_condition: if ((insn & 0xE000090) == 0x0000090) { if ((insn & 0xFC000F0) == 0x0000090) { /* MUL, MLA - 32x32->32 multiplications */ int left_reg = insn & 15; int right_reg = insn >> 8 & 15; int acc_reg = insn >> 12 & 15; int dest_reg = insn >> 16 & 15; if (left_reg == 15 || right_reg == 15 || acc_reg == 15 || dest_reg == 15) goto unimpl; emit_mov_x86reg_armreg(EAX, left_reg); emit_unary_armreg(MUL, right_reg); if (insn & 0x0200000) emit_alu_x86reg_armreg(ADD, EAX, acc_reg); emit_mov_armreg_x86reg(dest_reg, EAX); if (insn & 0x0100000) { if (!(insn & 0x0200000)) emit_test_x86reg_x86reg(EAX, EAX); emit_setcc_flag(SETS, &arm.cpsr_n); emit_setcc_flag(SETZ, &arm.cpsr_z); } } else if ((insn & 0xF8000F0) == 0x0800090) { /* UMULL, UMLAL, SMULL, SMLAL: 32x32 to 64 multiplications */ uint32_t left_reg = insn & 15; uint32_t right_reg = insn >> 8 & 15; uint32_t reg_lo = insn >> 12 & 15; uint32_t reg_hi = insn >> 16 & 15; if (left_reg == 15 || right_reg == 15 || reg_lo == 15 || reg_hi == 15) goto unimpl; if (reg_lo == reg_hi) goto unimpl; if (insn & 0x0100000) // set flags goto unimpl; emit_mov_x86reg_armreg(EAX, left_reg); emit_unary_armreg((insn & 0x0400000) ? IMUL : MUL, right_reg); if (insn & 0x0200000) { /* Accumulate */ emit_alu_armreg_x86reg(ADD, reg_lo, EAX); emit_alu_armreg_x86reg(ADC, reg_hi, EDX); } else { emit_mov_armreg_x86reg(reg_lo, EAX); emit_mov_armreg_x86reg(reg_hi, EDX); } } else {
bool emu_start(unsigned int port_gdb, unsigned int port_rdbg, const char *snapshot_file) { gui_busy_raii gui_busy; if(snapshot_file) { // Open snapshot size_t snapshot_size = gzip_filesize(snapshot_file); if(snapshot_size < sizeof(emu_snapshot)) return false; FILE *fp = fopen_utf8(snapshot_file, "rb"); if(!fp) return false; int dupfd = dup(fileno(fp)); fclose(fp); fp = nullptr; // gzdopen takes ownership of the fd gzFile gzf = gzdopen(dupfd, "r"); if(!gzf) { close(dupfd); return false; } auto snapshot = (struct emu_snapshot *) malloc(snapshot_size); if(!snapshot) { gzclose(gzf); return false; } if((size_t) gzread(gzf, snapshot, snapshot_size) != snapshot_size) { gzclose(gzf); free(snapshot); return false; } gzclose(gzf); //sched_reset(); sched.items[SCHED_THROTTLE].clock = CLOCK_27M; sched.items[SCHED_THROTTLE].proc = throttle_interval_event; // TODO: Max length path_boot1 = std::string(snapshot->path_boot1); path_flash = std::string(snapshot->path_flash); // TODO: Pass snapshot_size to flash_resume to avoid reading after the buffer // Resume components uint32_t sdram_size; if(snapshot->sig != SNAPSHOT_SIG || snapshot->version != SNAPSHOT_VER || !flash_resume(snapshot) || !flash_read_settings(&sdram_size, &product, &features, &asic_user_flags) || !cpu_resume(snapshot) || !memory_resume(snapshot) || !sched_resume(snapshot)) { emu_cleanup(); free(snapshot); return false; } free(snapshot); } else { if (!flash_open(path_flash.c_str())) return false; uint32_t sdram_size; flash_read_settings(&sdram_size, &product, &features, &asic_user_flags); flash_set_bootorder(boot_order); if(!memory_initialize(sdram_size)) { emu_cleanup(); return false; } } if(debug_on_start) cpu_events |= EVENT_DEBUG_STEP; uint8_t *rom = mem_areas[0].ptr; memset(rom, -1, 0x80000); for (int i = 0x00000; i < 0x80000; i += 4) RAM_FLAGS(&rom[i]) = RF_READ_ONLY; /* Load the ROM */ FILE *f = fopen_utf8(path_boot1.c_str(), "rb"); if (!f) { gui_perror(path_boot1.c_str()); emu_cleanup(); return false; } (void)fread(rom, 1, 0x80000, f); fclose(f); #ifndef NO_TRANSLATION if(!translate_init()) { gui_debug_printf("Could not init JIT, disabling translation.\n"); do_translate = false; } #endif addr_cache_init(); throttle_timer_on(); if(port_gdb) gdbstub_init(port_gdb); if(port_rdbg) rdebug_bind(port_rdbg); usblink_queue_reset(); if(!snapshot_file) emu_reset(); return true; }