diff options
-rw-r--r-- | gdbstub.c | 48 | ||||
-rw-r--r-- | target-i386/cpu.h | 4 | ||||
-rw-r--r-- | target-i386/helper.c | 30 |
3 files changed, 65 insertions, 17 deletions
@@ -563,6 +563,31 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) return 0; } +static int cpu_x86_gdb_load_seg(CPUState *env, int sreg, uint8_t *mem_buf) +{ + uint16_t selector = ldl_p(mem_buf); + + if (selector != env->segs[sreg].selector) { +#if defined(CONFIG_USER_ONLY) + cpu_x86_load_seg(env, sreg, selector); +#else + unsigned int limit, flags; + target_ulong base; + + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + base = selector << 4; + limit = 0xffff; + flags = 0; + } else { + if (!cpu_x86_get_descr_debug(env, selector, &base, &limit, &flags)) + return 4; + } + cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags); +#endif + } + return 4; +} + static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { uint32_t tmp; @@ -590,23 +615,12 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) env->eflags = ldl_p(mem_buf); return 4; -#if defined(CONFIG_USER_ONLY) -#define LOAD_SEG(index, sreg)\ - tmp = ldl_p(mem_buf);\ - if (tmp != env->segs[sreg].selector)\ - cpu_x86_load_seg(env, sreg, tmp);\ - return 4 -#else -/* FIXME: Honor segment registers. Needs to avoid raising an exception - when the selector is invalid. */ -#define LOAD_SEG(index, sreg) return 4 -#endif - case IDX_SEG_REGS: LOAD_SEG(10, R_CS); - case IDX_SEG_REGS + 1: LOAD_SEG(11, R_SS); - case IDX_SEG_REGS + 2: LOAD_SEG(12, R_DS); - case IDX_SEG_REGS + 3: LOAD_SEG(13, R_ES); - case IDX_SEG_REGS + 4: LOAD_SEG(14, R_FS); - case IDX_SEG_REGS + 5: LOAD_SEG(15, R_GS); + case IDX_SEG_REGS: return cpu_x86_gdb_load_seg(env, R_CS, mem_buf); + case IDX_SEG_REGS + 1: return cpu_x86_gdb_load_seg(env, R_SS, mem_buf); + case IDX_SEG_REGS + 2: return cpu_x86_gdb_load_seg(env, R_DS, mem_buf); + case IDX_SEG_REGS + 3: return cpu_x86_gdb_load_seg(env, R_ES, mem_buf); + case IDX_SEG_REGS + 4: return cpu_x86_gdb_load_seg(env, R_FS, mem_buf); + case IDX_SEG_REGS + 5: return cpu_x86_gdb_load_seg(env, R_GS, mem_buf); case IDX_FP_REGS + 8: env->fpuc = ldl_p(mem_buf); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 372fe3169b..33555f8325 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -770,6 +770,10 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, } } +int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, + target_ulong *base, unsigned int *limit, + unsigned int *flags); + /* wrapper, just in case memory mappings must be changed */ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) { diff --git a/target-i386/helper.c b/target-i386/helper.c index ce5346c317..18c4befea8 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1782,6 +1782,36 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } } + +int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, + target_ulong *base, unsigned int *limit, + unsigned int *flags) +{ + SegmentCache *dt; + target_ulong ptr; + uint32_t e1, e2; + int index; + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + ptr = dt->base + index; + if ((index + 7) > dt->limit + || cpu_memory_rw_debug(env, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0 + || cpu_memory_rw_debug(env, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0) + return 0; + + *base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); + *limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & DESC_G_MASK) + *limit = (*limit << 12) | 0xfff; + *flags = e2; + + return 1; +} + CPUX86State *cpu_x86_init(const char *cpu_model) { CPUX86State *env; |