diff --git a/src/cpu/386.c b/src/cpu/386.c index 295f94056..c1e7b9285 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -240,6 +240,7 @@ exec386_2386(int32_t cycs) cycdiff = 0; oldcyc = cycles; while (cycdiff < cycle_period) { + int ins_fetch_fault = 0; ins_cycles = cycles; #ifndef USE_NEW_DYNAREC @@ -259,6 +260,14 @@ exec386_2386(int32_t cycs) fetchdat = fastreadl_fetch(cs + cpu_state.pc); ol = opcode_length[fetchdat & 0xff]; CHECK_READ_CS(MIN(ol, 4)); + ins_fetch_fault = cpu_386_check_instruction_fault(); + + if (!cpu_state.abrt && ins_fetch_fault) { + x86gen(); + ins_fetch_fault = 0; + /* No instructions executed at this point. */ + goto block_ended; + } if (!cpu_state.abrt) { #ifdef ENABLE_386_LOG @@ -287,6 +296,7 @@ exec386_2386(int32_t cycs) if (cpu_end_block_after_ins) cpu_end_block_after_ins--; +block_ended: if (cpu_state.abrt) { flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; @@ -309,9 +319,12 @@ exec386_2386(int32_t cycs) #endif } } + if (!x86_was_reset && ins_fetch_fault) + x86gen(); /* This is supposed to be the first one serviced by the processor according to the manual. */ } else if (trap) { flags_rebuild(); - dr[6] |= (trap == 2) ? 0x8000 : 0x4000; + if (trap != 4) + dr[6] |= (trap == 2) ? 0x8000 : 0x4000; trap = 0; #ifndef USE_NEW_DYNAREC oldcs = CS; diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 60ecd8954..b80716142 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -80,6 +80,7 @@ int smm_in_hlt = 0; int smi_block = 0; int prefetch_prefixes = 0; +int rf_flag_no_clear = 0; int tempc; int oldcpl; @@ -1655,6 +1656,38 @@ cpu_386_flags_rebuild(void) flags_rebuild(); } +int +cpu_386_check_instruction_fault(void) +{ + int i = 0; + int fault = 0; + /* Report no fault if RF is set. */ + if (cpu_state.eflags & RF_FLAG) + return 0; + + /* Make sure breakpoints are enabled. */ + if (!(dr[7] & 0xFF)) + return 0; + + for (i = 0; i < 4; i++) { + int breakpoint_enabled = !!(dr[7] & (0x3 << (2 * i))) && !(dr[7] & (0x30000 << (4 * i))); + uint64_t translated_addr = 0xffffffffffffffffULL; + if (!breakpoint_enabled) + continue; + if (!(cr0 >> 31)) + translated_addr = dr[i]; + else + translated_addr = mmutranslate_noabrt(dr[i], 0); + + if ((cs + cpu_state.pc) == translated_addr) { + dr[6] |= (1 << i); + fault = 1; + } + } + + return fault; +} + int sysenter(uint32_t fetchdat) { diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index 22fbd4bff..0478fe5c6 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -50,80 +50,80 @@ # define do_mmut_ww(s, a, b) do_mmutranslate_2386((s) + (a), b, 2, 1) # define do_mmut_wl(s, a, b) do_mmutranslate_2386((s) + (a), b, 4, 1) #else -# define readmemb_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) ? readmembl_no_mmut((s) + (a), b) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a)))) -# define readmemw_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) ? readmemwl_no_mmut((s) + (a), b) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) -# define readmeml_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) ? readmemll_no_mmut((s) + (a), b) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) -# define readmemb(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) ? readmembl((s) + (a)) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a)))) -# define readmemw(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) ? readmemwl((s) + (a)) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) -# define readmeml(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) ? readmemll((s) + (a)) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) -# define readmemq(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 7)) ? readmemql((s) + (a)) : *(uint64_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a)))) +# define readmemb_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) ? readmembl_no_mmut((s) + (a), b) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a)))) +# define readmemw_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 1)) ? readmemwl_no_mmut((s) + (a), b) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) +# define readmeml_n(s, a, b) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 3)) ? readmemll_no_mmut((s) + (a), b) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) +# define readmemb(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) ? readmembl((s) + (a)) : *(uint8_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a)))) +# define readmemw(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 1)) ? readmemwl((s) + (a)) : *(uint16_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) +# define readmeml(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 3)) ? readmemll((s) + (a)) : *(uint32_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uint32_t) ((s) + (a)))) +# define readmemq(s, a) ((readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF) || (((s) + (a)) & 7)) ? readmemql((s) + (a)) : *(uint64_t *) (readlookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a)))) -# define writememb_n(s, a, b, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) \ - writemembl_no_mmut((s) + (a), b, v); \ - else \ +# define writememb_n(s, a, b, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \ + writemembl_no_mmut((s) + (a), b, v); \ + else \ *(uint8_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define writememw_n(s, a, b, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) \ - writememwl_no_mmut((s) + (a), b, v); \ - else \ +# define writememw_n(s, a, b, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \ + writememwl_no_mmut((s) + (a), b, v); \ + else \ *(uint16_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define writememl_n(s, a, b, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \ - writememll_no_mmut((s) + (a), b, v); \ - else \ +# define writememl_n(s, a, b, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \ + writememll_no_mmut((s) + (a), b, v); \ + else \ *(uint32_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define writememb(s, a, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) \ - writemembl((s) + (a), v); \ - else \ +# define writememb(s, a, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \ + writemembl((s) + (a), v); \ + else \ *(uint8_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define writememw(s, a, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) \ - writememwl((s) + (a), v); \ - else \ +# define writememw(s, a, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \ + writememwl((s) + (a), v); \ + else \ *(uint16_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define writememl(s, a, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \ - writememll((s) + (a), v); \ - else \ +# define writememl(s, a, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \ + writememll((s) + (a), v); \ + else \ *(uint32_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define writememq(s, a, v) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 7)) \ - writememql((s) + (a), v); \ - else \ +# define writememq(s, a, v) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 7) || (dr[7] & 0xFF)) \ + writememql((s) + (a), v); \ + else \ *(uint64_t *) (writelookup2[(uint32_t) ((s) + (a)) >> 12] + (uintptr_t) ((s) + (a))) = v -# define do_mmut_rb(s, a, b) \ - if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) \ +# define do_mmut_rb(s, a, b) \ + if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 1, 0) -# define do_mmut_rw(s, a, b) \ - if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) \ +# define do_mmut_rw(s, a, b) \ + if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 2, 0) -# define do_mmut_rl(s, a, b) \ - if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \ +# define do_mmut_rl(s, a, b) \ + if (readlookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 4, 0) -# define do_mmut_rb2(s, a, b) \ - old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \ - if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) \ +# define do_mmut_rb2(s, a, b) \ + old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \ + if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 1, 0) -# define do_mmut_rw2(s, a, b) \ - old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \ - if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) \ +# define do_mmut_rw2(s, a, b) \ + old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \ + if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 2, 0) -# define do_mmut_rl2(s, a, b) \ - old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \ - if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \ +# define do_mmut_rl2(s, a, b) \ + old_rl2 = readlookup2[(uint32_t) ((s) + (a)) >> 12]; \ + if (old_rl2 == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 4, 0) -# define do_mmut_wb(s, a, b) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF) \ +# define do_mmut_wb(s, a, b) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 1, 1) -# define do_mmut_ww(s, a, b) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1)) \ +# define do_mmut_ww(s, a, b) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 1) || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 2, 1) -# define do_mmut_wl(s, a, b) \ - if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \ +# define do_mmut_wl(s, a, b) \ + if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3) || (dr[7] & 0xFF)) \ do_mmutranslate((s) + (a), b, 4, 1) #endif @@ -674,3 +674,8 @@ seteaq(uint64_t v) cpu_state.pc += 2 #endif + +/* Resume Flag handling. */ +extern int rf_flag_no_clear; + +int cpu_386_check_instruction_fault(void); \ No newline at end of file diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index e132c0300..16759634d 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -223,7 +223,7 @@ fetch_ea_16_long(uint32_t rmdat) #include "386_ops.h" -#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) +#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG) && !(dr[7] & 0xFF)) #ifdef USE_DYNAREC int32_t cycles_main = 0; @@ -285,6 +285,11 @@ exec386_dynarec_int(void) cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; + if (UNLIKELY(cpu_386_check_instruction_fault())) { + x86gen(); + goto block_ended; + } + fetchdat = fastreadl_fetch(cs + cpu_state.pc); # ifdef ENABLE_386_DYNAREC_LOG if (in_smm) @@ -306,6 +311,14 @@ exec386_dynarec_int(void) cpu_state.pc &= 0xffff; # endif + if (!cpu_state.abrt) { + if (!rf_flag_no_clear) { + cpu_state.eflags &= ~RF_FLAG; + } + + rf_flag_no_clear = 0; + } + if (((cs + cpu_state.pc) >> 12) != pccache) CPU_BLOCK_END(); @@ -329,7 +342,8 @@ exec386_dynarec_int(void) block_ended: if (!cpu_state.abrt && trap) { - dr[6] |= (trap == 2) ? 0x8000 : 0x4000; + if (trap != 4) + dr[6] |= (trap == 2) ? 0x8000 : 0x4000; trap = 0; # ifndef USE_NEW_DYNAREC oldcs = CS; diff --git a/src/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index f08b30fce..ba34ae5e7 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/x86_ops_flag.h @@ -178,6 +178,7 @@ opPOPF_186(uint32_t fetchdat) else cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; flags_extract(); + rf_flag_no_clear = 1; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1, 0, 0, 0, 0); @@ -211,6 +212,7 @@ opPOPF_286(uint32_t fetchdat) else cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; flags_extract(); + rf_flag_no_clear = 1; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1, 0, 0, 0, 0); @@ -264,6 +266,7 @@ opPOPF(uint32_t fetchdat) cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; } flags_extract(); + rf_flag_no_clear = 1; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1, 0, 0, 0, 0); @@ -307,6 +310,7 @@ opPOPFD(uint32_t fetchdat) cpu_state.eflags = (templ >> 16) & 3; flags_extract(); + rf_flag_no_clear = 1; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0, 1, 0, 0, 0); diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index b0c841f83..c57dc8226 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -87,6 +87,12 @@ opMOV_r_DRx_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + if (cpu_reg == 4 || cpu_reg == 5) { + if (cr4 & 0x8) + x86illegal(); + else + cpu_reg += 2; + } cpu_state.regs[cpu_rm].l = dr[cpu_reg] | (cpu_reg == 6 ? 0xffff0ff0u : 0); CLOCK_CYCLES(6); PREFETCH_RUN(6, 2, rmdat, 0, 0, 0, 0, 0); @@ -100,6 +106,12 @@ opMOV_r_DRx_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + if (cpu_reg == 4 || cpu_reg == 5) { + if (cr4 & 0x8) + x86illegal(); + else + cpu_reg += 2; + } cpu_state.regs[cpu_rm].l = dr[cpu_reg] | (cpu_reg == 6 ? 0xffff0ff0u : 0); CLOCK_CYCLES(6); PREFETCH_RUN(6, 2, rmdat, 0, 0, 0, 0, 1); @@ -228,10 +240,23 @@ opMOV_DRx_r_a16(uint32_t fetchdat) x86gpf(NULL, 0); return 1; } + if ((dr[6] & 0x2000) && !(cpu_state.eflags & RF_FLAG)) { + dr[7] |= 0x2000; + dr[6] &= ~0x2000; + x86gen(); + return 1; + } fetch_ea_16(fetchdat); + if (cpu_reg == 4 || cpu_reg == 5) { + if (cr4 & 0x8) + x86illegal(); + else + cpu_reg += 2; + } dr[cpu_reg] = cpu_state.regs[cpu_rm].l; CLOCK_CYCLES(6); PREFETCH_RUN(6, 2, rmdat, 0, 0, 0, 0, 0); + CPU_BLOCK_END(); return 0; } static int @@ -242,9 +267,16 @@ opMOV_DRx_r_a32(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + if (cpu_reg == 4 || cpu_reg == 5) { + if (cr4 & 0x8) + x86illegal(); + else + cpu_reg += 2; + } dr[cpu_reg] = cpu_state.regs[cpu_rm].l; CLOCK_CYCLES(6); PREFETCH_RUN(6, 2, rmdat, 0, 0, 0, 0, 1); + CPU_BLOCK_END(); return 0; } diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index 0d9a6370b..ca85bf2b0 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -135,6 +135,7 @@ opIRET_186(uint32_t fetchdat) } flags_extract(); nmi_enable = 1; + rf_flag_no_clear = 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old - cycles, 1, -1, 2, 0, 0, 0, 0); @@ -175,6 +176,7 @@ opIRET_286(uint32_t fetchdat) } flags_extract(); nmi_enable = 1; + rf_flag_no_clear = 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old - cycles, 1, -1, 2, 0, 0, 0, 0); @@ -243,6 +245,7 @@ opIRET(uint32_t fetchdat) } flags_extract(); nmi_enable = 1; + rf_flag_no_clear = 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old - cycles, 1, -1, 2, 0, 0, 0, 0); @@ -285,6 +288,7 @@ opIRETD(uint32_t fetchdat) } flags_extract(); nmi_enable = 1; + rf_flag_no_clear = 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old - cycles, 1, -1, 0, 2, 0, 0, 1); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index feaad5913..553e3dbc4 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -2286,6 +2286,8 @@ taskswitch286(uint16_t seg, uint16_t *segdat, int is32) op_loadseg(new_fs, &cpu_state.seg_fs); op_loadseg(new_gs, &cpu_state.seg_gs); + rf_flag_no_clear = 1; + if (t_bit) { trap = 2; #ifdef USE_DYNAREC diff --git a/src/cpu/x86seg_common.c b/src/cpu/x86seg_common.c index 8926af0d7..12b698b1a 100644 --- a/src/cpu/x86seg_common.c +++ b/src/cpu/x86seg_common.c @@ -87,6 +87,12 @@ x86de(UNUSED(char *s), UNUSED(uint16_t error)) #endif } +void +x86gen(void) +{ + x86_int(1); +} + void x86gpf(UNUSED(char *s), uint16_t error) { diff --git a/src/cpu/x86seg_common.h b/src/cpu/x86seg_common.h index f4bffed40..9f9049322 100644 --- a/src/cpu/x86seg_common.h +++ b/src/cpu/x86seg_common.h @@ -41,6 +41,7 @@ extern int cgate32; extern int intgatesize; extern void x86seg_reset(void); +extern void x86gen(void); extern void x86de(char *s, uint16_t error); extern void x86gpf(char *s, uint16_t error); extern void x86gpf_expected(char *s, uint16_t error); diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 69a2b5de8..db95d3f7b 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -439,6 +439,8 @@ extern void mem_reset_page_blocks(void); extern void flushmmucache(void); extern void flushmmucache_nopc(void); +extern void mem_debug_check_addr(uint32_t addr, int write); + extern void mem_a20_init(void); extern void mem_a20_recalc(void); diff --git a/src/io.c b/src/io.c index 0e68049c3..e6ab88453 100644 --- a/src/io.c +++ b/src/io.c @@ -279,6 +279,59 @@ io_handler_interleaved(int set, uint16_t base, int size, io_handler_common(set, base, size, inb, inw, inl, outb, outw, outl, priv, 2); } +extern int trap; +/* Set trap for I/O address breakpoints. */ +void +io_debug_check_addr(uint16_t addr) +{ + int i = 0; + int set_trap = 0; + + if (trap == 4) + return; /* Debug trap already pending. */ + + if (!(dr[7] & 0xFF)) + return; + + if (!(cr4 & 0x8)) + return; /* No I/O debug trap. */ + + for (i = 0; i < 4; i++) { + uint16_t dr_addr = dr[i] & 0xFFFF; + int breakpoint_enabled = !!(dr[7] & (0x3 << (2 * i))); + int len_type_pair = ((dr[7] >> 16) & (0xF << (4 * i))) >> (4 * i); + if (!breakpoint_enabled) + continue; + if ((len_type_pair & 3) != 2) + continue; + + switch ((len_type_pair >> 2) & 3) + { + case 0x00: + if (dr_addr == addr) { + set_trap = 1; + dr[6] |= (1 << i); + } + break; + case 0x01: + if ((dr_addr & ~1) == addr || ((dr_addr & ~1) + 1) == (addr + 1)) { + set_trap = 1; + dr[6] |= (1 << i); + } + break; + case 0x03: + dr_addr &= ~3; + if (addr >= dr_addr && addr < (dr_addr + 4)) { + set_trap = 1; + dr[6] |= (1 << i); + } + break; + } + } + if (set_trap) + trap = 4; +} + uint8_t inb(uint16_t port) { @@ -290,6 +343,8 @@ inb(uint16_t port) int qfound = 0; #endif + io_debug_check_addr(port); + if ((pci_flags & FLAG_CONFIG_IO_ON) && (port >= pci_base) && (port < (pci_base + pci_size))) { ret = pci_read(port, NULL); found = 1; @@ -350,6 +405,8 @@ outb(uint16_t port, uint8_t val) int qfound = 0; #endif + io_debug_check_addr(port); + if ((pci_flags & FLAG_CONFIG_IO_ON) && (port >= pci_base) && (port < (pci_base + pci_size))) { pci_write(port, val, NULL); found = 1; @@ -402,6 +459,8 @@ inw(uint16_t port) #endif uint8_t ret8[2]; + io_debug_check_addr(port); + if ((pci_flags & FLAG_CONFIG_IO_ON) && (port >= pci_base) && (port < (pci_base + pci_size))) { ret = pci_readw(port, NULL); found = 2; @@ -474,6 +533,8 @@ outw(uint16_t port, uint16_t val) int qfound = 0; #endif + io_debug_check_addr(port); + if ((pci_flags & FLAG_CONFIG_IO_ON) && (port >= pci_base) && (port < (pci_base + pci_size))) { pci_writew(port, val, NULL); found = 2; @@ -542,6 +603,8 @@ inl(uint16_t port) int qfound = 0; #endif + io_debug_check_addr(port); + if ((pci_flags & FLAG_CONFIG_IO_ON) && (port >= pci_base) && (port < (pci_base + pci_size))) { ret = pci_readl(port, NULL); found = 4; @@ -646,6 +709,8 @@ outl(uint16_t port, uint32_t val) #endif int i = 0; + io_debug_check_addr(port); + if ((pci_flags & FLAG_CONFIG_IO_ON) && (port >= pci_base) && (port < (pci_base + pci_size))) { pci_writel(port, val, NULL); found = 4; diff --git a/src/mem/mem.c b/src/mem/mem.c index 0b002b302..887720d3d 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -161,6 +161,57 @@ mem_log(const char *fmt, ...) # define mem_log(fmt, ...) #endif +/* Set trap for data address breakpoints. */ +void +mem_debug_check_addr(uint32_t addr, int write) +{ + int i = 0; + int set_trap = 0; + + if (trap == 4) + return; /* Debug trap already pending. */ + + if (!(dr[7] & 0xFF)) + return; + + for (i = 0; i < 4; i++) { + uint32_t dr_addr = dr[i]; + int breakpoint_enabled = !!(dr[7] & (0x3 << (2 * i))); + int len_type_pair = ((dr[7] >> 16) & (0xF << (4 * i))) >> (4 * i); + if (!breakpoint_enabled) + continue; + if (!write && (len_type_pair & 3) != 3) + continue; + if ((len_type_pair & 3) != 1) + continue; + + switch ((len_type_pair >> 2) & 3) + { + case 0x00: + if (dr_addr == addr) { + set_trap = 1; + dr[6] |= (1 << i); + } + break; + case 0x01: + if ((dr_addr & ~1) == addr || ((dr_addr & ~1) + 1) == (addr + 1)) { + set_trap = 1; + dr[6] |= (1 << i); + } + break; + case 0x03: + dr_addr &= ~3; + if (addr >= dr_addr && addr < (dr_addr + 4)) { + set_trap = 1; + dr[6] |= (1 << i); + } + break; + } + } + if (set_trap) + trap = 4; +} + int mem_addr_is_ram(uint32_t addr) { @@ -790,6 +841,7 @@ readmembl(uint32_t addr) uint64_t a; GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1); + mem_debug_check_addr(addr, 0); addr64 = (uint64_t) addr; mem_logical_addr = addr; @@ -819,6 +871,7 @@ writemembl(uint32_t addr, uint8_t val) uint64_t a; GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1); + mem_debug_check_addr(addr, 1); addr64 = (uint64_t) addr; mem_logical_addr = addr; @@ -905,6 +958,8 @@ readmemwl(uint32_t addr) addr64a[0] = addr; addr64a[1] = addr + 1; + mem_debug_check_addr(addr, 0); + mem_debug_check_addr(addr + 1, 0); GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 2); mem_logical_addr = addr; @@ -963,6 +1018,8 @@ writememwl(uint32_t addr, uint16_t val) addr64a[0] = addr; addr64a[1] = addr + 1; + mem_debug_check_addr(addr, 1); + mem_debug_check_addr(addr + 1, 1); GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 2); mem_logical_addr = addr; @@ -1139,8 +1196,10 @@ readmemll(uint32_t addr) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 0); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 4); mem_logical_addr = addr; @@ -1213,8 +1272,10 @@ writememll(uint32_t addr, uint32_t val) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 1); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 4); mem_logical_addr = addr; @@ -1417,8 +1478,10 @@ readmemql(uint32_t addr) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 0); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 8); mem_logical_addr = addr; @@ -1483,8 +1546,10 @@ writememql(uint32_t addr, uint64_t val) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 1); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 8); mem_logical_addr = addr; @@ -1582,8 +1647,10 @@ do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write) uint32_t last_addr = addr + (num - 1); uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < num; i++) + mem_debug_check_addr(addr, write); + for (i = 0; i < num; i++) { a64[i] = (uint64_t) addr; + } for (i = 0; i < num; i++) { if (cr0 >> 31) { diff --git a/src/mem/mmu_2386.c b/src/mem/mmu_2386.c index 21c62b833..fc2237bec 100644 --- a/src/mem/mmu_2386.c +++ b/src/mem/mmu_2386.c @@ -243,6 +243,7 @@ readmembl_2386(uint32_t addr) GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1); + mem_debug_check_addr(addr, 0); addr64 = (uint64_t) addr; mem_logical_addr = addr; @@ -270,6 +271,7 @@ writemembl_2386(uint32_t addr, uint8_t val) mem_mapping_t *map; uint64_t a; + mem_debug_check_addr(addr, 1); GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1); addr64 = (uint64_t) addr; @@ -347,6 +349,8 @@ readmemwl_2386(uint32_t addr) addr64a[0] = addr; addr64a[1] = addr + 1; + mem_debug_check_addr(addr, 0); + mem_debug_check_addr(addr + 1, 0); GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 2); mem_logical_addr = addr; @@ -402,6 +406,8 @@ writememwl_2386(uint32_t addr, uint16_t val) addr64a[0] = addr; addr64a[1] = addr + 1; + mem_debug_check_addr(addr, 1); + mem_debug_check_addr(addr + 1, 1); GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 2); mem_logical_addr = addr; @@ -555,8 +561,10 @@ readmemll_2386(uint32_t addr) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 0); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 4); mem_logical_addr = addr; @@ -626,8 +634,10 @@ writememll_2386(uint32_t addr, uint32_t val) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 1); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 4); mem_logical_addr = addr; @@ -807,8 +817,10 @@ readmemql_2386(uint32_t addr) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 0); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 8); mem_logical_addr = addr; @@ -870,8 +882,10 @@ writememql_2386(uint32_t addr, uint64_t val) int i; uint64_t a = 0x0000000000000000ULL; - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { addr64a[i] = (uint64_t) (addr + i); + mem_debug_check_addr(addr + i, 1); + } GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 8); mem_logical_addr = addr; @@ -957,32 +971,35 @@ do_mmutranslate_2386(uint32_t addr, uint32_t *a64, int num, int write) uint32_t last_addr = addr + (num - 1); uint64_t a = 0x0000000000000000ULL; + mem_debug_check_addr(addr, write); + for (i = 0; i < num; i++) a64[i] = (uint64_t) addr; - for (i = 0; i < num; i++) { - if (cr0 >> 31) { - /* If we have encountered at least one page fault, mark all subsequent addresses as - having page faulted, prevents false negatives in readmem*l_no_mmut. */ - if ((i > 0) && cpu_state.abrt && !high_page) - a64[i] = a64[i - 1]; - /* If we are on the same page, there is no need to translate again, as we can just - reuse the previous result. */ - else if (i == 0) { - a = mmutranslatereal_2386(addr, write); - a64[i] = (uint32_t) a; - } else if (!(addr & 0xfff)) { - a = mmutranslatereal_2386(last_addr, write); - a64[i] = (uint32_t) a; + if (!(cr0 >> 31)) + return; - if (!cpu_state.abrt) { - a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); - a64[i] = (uint32_t) a; - } - } else { + for (i = 0; i < num; i++) { + /* If we have encountered at least one page fault, mark all subsequent addresses as + having page faulted, prevents false negatives in readmem*l_no_mmut. */ + if ((i > 0) && cpu_state.abrt && !high_page) + a64[i] = a64[i - 1]; + /* If we are on the same page, there is no need to translate again, as we can just + reuse the previous result. */ + else if (i == 0) { + a = mmutranslatereal_2386(addr, write); + a64[i] = (uint32_t) a; + } else if (!(addr & 0xfff)) { + a = mmutranslatereal_2386(last_addr, write); + a64[i] = (uint32_t) a; + + if (!cpu_state.abrt) { a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); a64[i] = (uint32_t) a; } + } else { + a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); + a64[i] = (uint32_t) a; } addr++;