提交 100ec099 编写于 作者: P Pavel Dovgalyuk 提交者: Richard Henderson

target-i386: exception handling for seg_helper functions

This patch fixes exception handling for seg_helper functions.
Signed-off-by: NPavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Signed-off-by: NRichard Henderson <rth@twiddle.net>
上级 2afbdf84
...@@ -30,9 +30,9 @@ DEF_HELPER_2(verw, void, env, tl) ...@@ -30,9 +30,9 @@ DEF_HELPER_2(verw, void, env, tl)
DEF_HELPER_2(lldt, void, env, int) DEF_HELPER_2(lldt, void, env, int)
DEF_HELPER_2(ltr, void, env, int) DEF_HELPER_2(ltr, void, env, int)
DEF_HELPER_3(load_seg, void, env, int, int) DEF_HELPER_3(load_seg, void, env, int, int)
DEF_HELPER_4(ljmp_protected, void, env, int, tl, int) DEF_HELPER_4(ljmp_protected, void, env, int, tl, tl)
DEF_HELPER_5(lcall_real, void, env, int, tl, int, int) DEF_HELPER_5(lcall_real, void, env, int, tl, int, int)
DEF_HELPER_5(lcall_protected, void, env, int, tl, int, int) DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
DEF_HELPER_2(iret_real, void, env, int) DEF_HELPER_2(iret_real, void, env, int)
DEF_HELPER_3(iret_protected, void, env, int, int) DEF_HELPER_3(iret_protected, void, env, int, int)
DEF_HELPER_3(lret_protected, void, env, int, int) DEF_HELPER_3(lret_protected, void, env, int, int)
......
...@@ -67,8 +67,9 @@ ...@@ -67,8 +67,9 @@
#endif #endif
/* return non zero if error */ /* return non zero if error */
static inline int load_segment(CPUX86State *env, uint32_t *e1_ptr, static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr,
uint32_t *e2_ptr, int selector) uint32_t *e2_ptr, int selector,
uintptr_t retaddr)
{ {
SegmentCache *dt; SegmentCache *dt;
int index; int index;
...@@ -84,11 +85,17 @@ static inline int load_segment(CPUX86State *env, uint32_t *e1_ptr, ...@@ -84,11 +85,17 @@ static inline int load_segment(CPUX86State *env, uint32_t *e1_ptr,
return -1; return -1;
} }
ptr = dt->base + index; ptr = dt->base + index;
*e1_ptr = cpu_ldl_kernel(env, ptr); *e1_ptr = cpu_ldl_kernel_ra(env, ptr, retaddr);
*e2_ptr = cpu_ldl_kernel(env, ptr + 4); *e2_ptr = cpu_ldl_kernel_ra(env, ptr + 4, retaddr);
return 0; return 0;
} }
static inline int load_segment(CPUX86State *env, uint32_t *e1_ptr,
uint32_t *e2_ptr, int selector)
{
return load_segment_ra(env, e1_ptr, e2_ptr, selector, 0);
}
static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
{ {
unsigned int limit; unsigned int limit;
...@@ -124,7 +131,8 @@ static inline void load_seg_vm(CPUX86State *env, int seg, int selector) ...@@ -124,7 +131,8 @@ static inline void load_seg_vm(CPUX86State *env, int seg, int selector)
} }
static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr, static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
uint32_t *esp_ptr, int dpl) uint32_t *esp_ptr, int dpl,
uintptr_t retaddr)
{ {
X86CPU *cpu = x86_env_get_cpu(env); X86CPU *cpu = x86_env_get_cpu(env);
int type, index, shift; int type, index, shift;
...@@ -153,60 +161,61 @@ static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr, ...@@ -153,60 +161,61 @@ static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
shift = type >> 3; shift = type >> 3;
index = (dpl * 4 + 2) << shift; index = (dpl * 4 + 2) << shift;
if (index + (4 << shift) - 1 > env->tr.limit) { if (index + (4 << shift) - 1 > env->tr.limit) {
raise_exception_err(env, EXCP0A_TSS, env->tr.selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, env->tr.selector & 0xfffc, retaddr);
} }
if (shift == 0) { if (shift == 0) {
*esp_ptr = cpu_lduw_kernel(env, env->tr.base + index); *esp_ptr = cpu_lduw_kernel_ra(env, env->tr.base + index, retaddr);
*ss_ptr = cpu_lduw_kernel(env, env->tr.base + index + 2); *ss_ptr = cpu_lduw_kernel_ra(env, env->tr.base + index + 2, retaddr);
} else { } else {
*esp_ptr = cpu_ldl_kernel(env, env->tr.base + index); *esp_ptr = cpu_ldl_kernel_ra(env, env->tr.base + index, retaddr);
*ss_ptr = cpu_lduw_kernel(env, env->tr.base + index + 4); *ss_ptr = cpu_lduw_kernel_ra(env, env->tr.base + index + 4, retaddr);
} }
} }
static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl) static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl,
uintptr_t retaddr)
{ {
uint32_t e1, e2; uint32_t e1, e2;
int rpl, dpl; int rpl, dpl;
if ((selector & 0xfffc) != 0) { if ((selector & 0xfffc) != 0) {
if (load_segment(env, &e1, &e2, selector) != 0) { if (load_segment_ra(env, &e1, &e2, selector, retaddr) != 0) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
if (!(e2 & DESC_S_MASK)) { if (!(e2 & DESC_S_MASK)) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
rpl = selector & 3; rpl = selector & 3;
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (seg_reg == R_CS) { if (seg_reg == R_CS) {
if (!(e2 & DESC_CS_MASK)) { if (!(e2 & DESC_CS_MASK)) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
if (dpl != rpl) { if (dpl != rpl) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
} else if (seg_reg == R_SS) { } else if (seg_reg == R_SS) {
/* SS must be writable data */ /* SS must be writable data */
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
if (dpl != cpl || dpl != rpl) { if (dpl != cpl || dpl != rpl) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
} else { } else {
/* not readable code */ /* not readable code */
if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) { if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
/* if data or non conforming code, checks the rights */ /* if data or non conforming code, checks the rights */
if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
} }
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, retaddr);
} }
cpu_x86_load_seg_cache(env, seg_reg, selector, cpu_x86_load_seg_cache(env, seg_reg, selector,
get_seg_base(e1, e2), get_seg_base(e1, e2),
...@@ -214,7 +223,7 @@ static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl) ...@@ -214,7 +223,7 @@ static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl)
e2); e2);
} else { } else {
if (seg_reg == R_SS || seg_reg == R_CS) { if (seg_reg == R_SS || seg_reg == R_CS) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, selector & 0xfffc, retaddr);
} }
} }
} }
...@@ -224,9 +233,9 @@ static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl) ...@@ -224,9 +233,9 @@ static void tss_load_seg(CPUX86State *env, int seg_reg, int selector, int cpl)
#define SWITCH_TSS_CALL 2 #define SWITCH_TSS_CALL 2
/* XXX: restore CPU state in registers (PowerPC case) */ /* XXX: restore CPU state in registers (PowerPC case) */
static void switch_tss(CPUX86State *env, int tss_selector, static void switch_tss_ra(CPUX86State *env, int tss_selector,
uint32_t e1, uint32_t e2, int source, uint32_t e1, uint32_t e2, int source,
uint32_t next_eip) uint32_t next_eip, uintptr_t retaddr)
{ {
int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
target_ulong tss_base; target_ulong tss_base;
...@@ -244,26 +253,26 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -244,26 +253,26 @@ static void switch_tss(CPUX86State *env, int tss_selector,
/* if task gate, we read the TSS segment and we load it */ /* if task gate, we read the TSS segment and we load it */
if (type == 5) { if (type == 5) {
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, tss_selector & 0xfffc, retaddr);
} }
tss_selector = e1 >> 16; tss_selector = e1 >> 16;
if (tss_selector & 4) { if (tss_selector & 4) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, tss_selector & 0xfffc, retaddr);
} }
if (load_segment(env, &e1, &e2, tss_selector) != 0) { if (load_segment_ra(env, &e1, &e2, tss_selector, retaddr) != 0) {
raise_exception_err(env, EXCP0D_GPF, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, tss_selector & 0xfffc, retaddr);
} }
if (e2 & DESC_S_MASK) { if (e2 & DESC_S_MASK) {
raise_exception_err(env, EXCP0D_GPF, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, tss_selector & 0xfffc, retaddr);
} }
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
if ((type & 7) != 1) { if ((type & 7) != 1) {
raise_exception_err(env, EXCP0D_GPF, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, tss_selector & 0xfffc, retaddr);
} }
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, tss_selector & 0xfffc, retaddr);
} }
if (type & 8) { if (type & 8) {
...@@ -275,7 +284,7 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -275,7 +284,7 @@ static void switch_tss(CPUX86State *env, int tss_selector,
tss_base = get_seg_base(e1, e2); tss_base = get_seg_base(e1, e2);
if ((tss_selector & 4) != 0 || if ((tss_selector & 4) != 0 ||
tss_limit < tss_limit_max) { tss_limit < tss_limit_max) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, tss_selector & 0xfffc, retaddr);
} }
old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
if (old_type & 8) { if (old_type & 8) {
...@@ -287,30 +296,33 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -287,30 +296,33 @@ static void switch_tss(CPUX86State *env, int tss_selector,
/* read all the registers from the new TSS */ /* read all the registers from the new TSS */
if (type & 8) { if (type & 8) {
/* 32 bit */ /* 32 bit */
new_cr3 = cpu_ldl_kernel(env, tss_base + 0x1c); new_cr3 = cpu_ldl_kernel_ra(env, tss_base + 0x1c, retaddr);
new_eip = cpu_ldl_kernel(env, tss_base + 0x20); new_eip = cpu_ldl_kernel_ra(env, tss_base + 0x20, retaddr);
new_eflags = cpu_ldl_kernel(env, tss_base + 0x24); new_eflags = cpu_ldl_kernel_ra(env, tss_base + 0x24, retaddr);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
new_regs[i] = cpu_ldl_kernel(env, tss_base + (0x28 + i * 4)); new_regs[i] = cpu_ldl_kernel_ra(env, tss_base + (0x28 + i * 4),
retaddr);
} }
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
new_segs[i] = cpu_lduw_kernel(env, tss_base + (0x48 + i * 4)); new_segs[i] = cpu_lduw_kernel_ra(env, tss_base + (0x48 + i * 4),
retaddr);
} }
new_ldt = cpu_lduw_kernel(env, tss_base + 0x60); new_ldt = cpu_lduw_kernel_ra(env, tss_base + 0x60, retaddr);
new_trap = cpu_ldl_kernel(env, tss_base + 0x64); new_trap = cpu_ldl_kernel_ra(env, tss_base + 0x64, retaddr);
} else { } else {
/* 16 bit */ /* 16 bit */
new_cr3 = 0; new_cr3 = 0;
new_eip = cpu_lduw_kernel(env, tss_base + 0x0e); new_eip = cpu_lduw_kernel_ra(env, tss_base + 0x0e, retaddr);
new_eflags = cpu_lduw_kernel(env, tss_base + 0x10); new_eflags = cpu_lduw_kernel_ra(env, tss_base + 0x10, retaddr);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
new_regs[i] = cpu_lduw_kernel(env, tss_base + (0x12 + i * 2)) | new_regs[i] = cpu_lduw_kernel_ra(env, tss_base + (0x12 + i * 2),
0xffff0000; retaddr) | 0xffff0000;
} }
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
new_segs[i] = cpu_lduw_kernel(env, tss_base + (0x22 + i * 4)); new_segs[i] = cpu_lduw_kernel_ra(env, tss_base + (0x22 + i * 4),
retaddr);
} }
new_ldt = cpu_lduw_kernel(env, tss_base + 0x2a); new_ldt = cpu_lduw_kernel_ra(env, tss_base + 0x2a, retaddr);
new_segs[R_FS] = 0; new_segs[R_FS] = 0;
new_segs[R_GS] = 0; new_segs[R_GS] = 0;
new_trap = 0; new_trap = 0;
...@@ -325,10 +337,10 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -325,10 +337,10 @@ static void switch_tss(CPUX86State *env, int tss_selector,
/* XXX: it can still fail in some cases, so a bigger hack is /* XXX: it can still fail in some cases, so a bigger hack is
necessary to valid the TLB after having done the accesses */ necessary to valid the TLB after having done the accesses */
v1 = cpu_ldub_kernel(env, env->tr.base); v1 = cpu_ldub_kernel_ra(env, env->tr.base, retaddr);
v2 = cpu_ldub_kernel(env, env->tr.base + old_tss_limit_max); v2 = cpu_ldub_kernel_ra(env, env->tr.base + old_tss_limit_max, retaddr);
cpu_stb_kernel(env, env->tr.base, v1); cpu_stb_kernel_ra(env, env->tr.base, v1, retaddr);
cpu_stb_kernel(env, env->tr.base + old_tss_limit_max, v2); cpu_stb_kernel_ra(env, env->tr.base + old_tss_limit_max, v2, retaddr);
/* clear busy bit (it is restartable) */ /* clear busy bit (it is restartable) */
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
...@@ -336,9 +348,9 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -336,9 +348,9 @@ static void switch_tss(CPUX86State *env, int tss_selector,
uint32_t e2; uint32_t e2;
ptr = env->gdt.base + (env->tr.selector & ~7); ptr = env->gdt.base + (env->tr.selector & ~7);
e2 = cpu_ldl_kernel(env, ptr + 4); e2 = cpu_ldl_kernel_ra(env, ptr + 4, retaddr);
e2 &= ~DESC_TSS_BUSY_MASK; e2 &= ~DESC_TSS_BUSY_MASK;
cpu_stl_kernel(env, ptr + 4, e2); cpu_stl_kernel_ra(env, ptr + 4, e2, retaddr);
} }
old_eflags = cpu_compute_eflags(env); old_eflags = cpu_compute_eflags(env);
if (source == SWITCH_TSS_IRET) { if (source == SWITCH_TSS_IRET) {
...@@ -348,35 +360,35 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -348,35 +360,35 @@ static void switch_tss(CPUX86State *env, int tss_selector,
/* save the current state in the old TSS */ /* save the current state in the old TSS */
if (type & 8) { if (type & 8) {
/* 32 bit */ /* 32 bit */
cpu_stl_kernel(env, env->tr.base + 0x20, next_eip); cpu_stl_kernel_ra(env, env->tr.base + 0x20, next_eip, retaddr);
cpu_stl_kernel(env, env->tr.base + 0x24, old_eflags); cpu_stl_kernel_ra(env, env->tr.base + 0x24, old_eflags, retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 0 * 4), env->regs[R_EAX]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 0 * 4), env->regs[R_EAX], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 1 * 4), env->regs[R_ECX]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 1 * 4), env->regs[R_ECX], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 2 * 4), env->regs[R_EDX]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 2 * 4), env->regs[R_EDX], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 3 * 4), env->regs[R_EBX]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 3 * 4), env->regs[R_EBX], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 4 * 4), env->regs[R_ESP]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 4 * 4), env->regs[R_ESP], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 5 * 4), env->regs[R_EBP]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 5 * 4), env->regs[R_EBP], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 6 * 4), env->regs[R_ESI]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 6 * 4), env->regs[R_ESI], retaddr);
cpu_stl_kernel(env, env->tr.base + (0x28 + 7 * 4), env->regs[R_EDI]); cpu_stl_kernel_ra(env, env->tr.base + (0x28 + 7 * 4), env->regs[R_EDI], retaddr);
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
cpu_stw_kernel(env, env->tr.base + (0x48 + i * 4), cpu_stw_kernel_ra(env, env->tr.base + (0x48 + i * 4),
env->segs[i].selector); env->segs[i].selector, retaddr);
} }
} else { } else {
/* 16 bit */ /* 16 bit */
cpu_stw_kernel(env, env->tr.base + 0x0e, next_eip); cpu_stw_kernel_ra(env, env->tr.base + 0x0e, next_eip, retaddr);
cpu_stw_kernel(env, env->tr.base + 0x10, old_eflags); cpu_stw_kernel_ra(env, env->tr.base + 0x10, old_eflags, retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 0 * 2), env->regs[R_EAX]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 0 * 2), env->regs[R_EAX], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 1 * 2), env->regs[R_ECX]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 1 * 2), env->regs[R_ECX], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 2 * 2), env->regs[R_EDX]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 2 * 2), env->regs[R_EDX], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 3 * 2), env->regs[R_EBX]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 3 * 2), env->regs[R_EBX], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 4 * 2), env->regs[R_ESP]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 4 * 2), env->regs[R_ESP], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 5 * 2), env->regs[R_EBP]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 5 * 2), env->regs[R_EBP], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 6 * 2), env->regs[R_ESI]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 6 * 2), env->regs[R_ESI], retaddr);
cpu_stw_kernel(env, env->tr.base + (0x12 + 7 * 2), env->regs[R_EDI]); cpu_stw_kernel_ra(env, env->tr.base + (0x12 + 7 * 2), env->regs[R_EDI], retaddr);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
cpu_stw_kernel(env, env->tr.base + (0x22 + i * 4), cpu_stw_kernel_ra(env, env->tr.base + (0x22 + i * 4),
env->segs[i].selector); env->segs[i].selector, retaddr);
} }
} }
...@@ -384,7 +396,7 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -384,7 +396,7 @@ static void switch_tss(CPUX86State *env, int tss_selector,
context */ context */
if (source == SWITCH_TSS_CALL) { if (source == SWITCH_TSS_CALL) {
cpu_stw_kernel(env, tss_base, env->tr.selector); cpu_stw_kernel_ra(env, tss_base, env->tr.selector, retaddr);
new_eflags |= NT_MASK; new_eflags |= NT_MASK;
} }
...@@ -394,9 +406,9 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -394,9 +406,9 @@ static void switch_tss(CPUX86State *env, int tss_selector,
uint32_t e2; uint32_t e2;
ptr = env->gdt.base + (tss_selector & ~7); ptr = env->gdt.base + (tss_selector & ~7);
e2 = cpu_ldl_kernel(env, ptr + 4); e2 = cpu_ldl_kernel_ra(env, ptr + 4, retaddr);
e2 |= DESC_TSS_BUSY_MASK; e2 |= DESC_TSS_BUSY_MASK;
cpu_stl_kernel(env, ptr + 4, e2); cpu_stl_kernel_ra(env, ptr + 4, e2, retaddr);
} }
/* set the new CPU state */ /* set the new CPU state */
...@@ -448,23 +460,23 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -448,23 +460,23 @@ static void switch_tss(CPUX86State *env, int tss_selector,
/* load the LDT */ /* load the LDT */
if (new_ldt & 4) { if (new_ldt & 4) {
raise_exception_err(env, EXCP0A_TSS, new_ldt & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, new_ldt & 0xfffc, retaddr);
} }
if ((new_ldt & 0xfffc) != 0) { if ((new_ldt & 0xfffc) != 0) {
dt = &env->gdt; dt = &env->gdt;
index = new_ldt & ~7; index = new_ldt & ~7;
if ((index + 7) > dt->limit) { if ((index + 7) > dt->limit) {
raise_exception_err(env, EXCP0A_TSS, new_ldt & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, new_ldt & 0xfffc, retaddr);
} }
ptr = dt->base + index; ptr = dt->base + index;
e1 = cpu_ldl_kernel(env, ptr); e1 = cpu_ldl_kernel_ra(env, ptr, retaddr);
e2 = cpu_ldl_kernel(env, ptr + 4); e2 = cpu_ldl_kernel_ra(env, ptr + 4, retaddr);
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) { if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) {
raise_exception_err(env, EXCP0A_TSS, new_ldt & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, new_ldt & 0xfffc, retaddr);
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0A_TSS, new_ldt & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, new_ldt & 0xfffc, retaddr);
} }
load_seg_cache_raw_dt(&env->ldt, e1, e2); load_seg_cache_raw_dt(&env->ldt, e1, e2);
} }
...@@ -472,18 +484,18 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -472,18 +484,18 @@ static void switch_tss(CPUX86State *env, int tss_selector,
/* load the segments */ /* load the segments */
if (!(new_eflags & VM_MASK)) { if (!(new_eflags & VM_MASK)) {
int cpl = new_segs[R_CS] & 3; int cpl = new_segs[R_CS] & 3;
tss_load_seg(env, R_CS, new_segs[R_CS], cpl); tss_load_seg(env, R_CS, new_segs[R_CS], cpl, retaddr);
tss_load_seg(env, R_SS, new_segs[R_SS], cpl); tss_load_seg(env, R_SS, new_segs[R_SS], cpl, retaddr);
tss_load_seg(env, R_ES, new_segs[R_ES], cpl); tss_load_seg(env, R_ES, new_segs[R_ES], cpl, retaddr);
tss_load_seg(env, R_DS, new_segs[R_DS], cpl); tss_load_seg(env, R_DS, new_segs[R_DS], cpl, retaddr);
tss_load_seg(env, R_FS, new_segs[R_FS], cpl); tss_load_seg(env, R_FS, new_segs[R_FS], cpl, retaddr);
tss_load_seg(env, R_GS, new_segs[R_GS], cpl); tss_load_seg(env, R_GS, new_segs[R_GS], cpl, retaddr);
} }
/* check that env->eip is in the CS segment limits */ /* check that env->eip is in the CS segment limits */
if (new_eip > env->segs[R_CS].limit) { if (new_eip > env->segs[R_CS].limit) {
/* XXX: different exception if CALL? */ /* XXX: different exception if CALL? */
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
...@@ -500,6 +512,13 @@ static void switch_tss(CPUX86State *env, int tss_selector, ...@@ -500,6 +512,13 @@ static void switch_tss(CPUX86State *env, int tss_selector,
#endif #endif
} }
static void switch_tss(CPUX86State *env, int tss_selector,
uint32_t e1, uint32_t e2, int source,
uint32_t next_eip)
{
switch_tss_ra(env, tss_selector, e1, e2, source, next_eip, 0);
}
static inline unsigned int get_sp_mask(unsigned int e2) static inline unsigned int get_sp_mask(unsigned int e2)
{ {
if (e2 & DESC_B_MASK) { if (e2 & DESC_B_MASK) {
...@@ -549,30 +568,35 @@ static int exception_has_error_code(int intno) ...@@ -549,30 +568,35 @@ static int exception_has_error_code(int intno)
#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask)))) #define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
/* XXX: add a is_user flag to have proper security support */ /* XXX: add a is_user flag to have proper security support */
#define PUSHW(ssp, sp, sp_mask, val) \ #define PUSHW_RA(ssp, sp, sp_mask, val, ra) \
{ \ { \
sp -= 2; \ sp -= 2; \
cpu_stw_kernel(env, (ssp) + (sp & (sp_mask)), (val)); \ cpu_stw_kernel_ra(env, (ssp) + (sp & (sp_mask)), (val), ra); \
} }
#define PUSHL(ssp, sp, sp_mask, val) \ #define PUSHL_RA(ssp, sp, sp_mask, val, ra) \
{ \ { \
sp -= 4; \ sp -= 4; \
cpu_stl_kernel(env, SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val)); \ cpu_stl_kernel_ra(env, SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val), ra); \
} }
#define POPW(ssp, sp, sp_mask, val) \ #define POPW_RA(ssp, sp, sp_mask, val, ra) \
{ \ { \
val = cpu_lduw_kernel(env, (ssp) + (sp & (sp_mask))); \ val = cpu_lduw_kernel_ra(env, (ssp) + (sp & (sp_mask)), ra); \
sp += 2; \ sp += 2; \
} }
#define POPL(ssp, sp, sp_mask, val) \ #define POPL_RA(ssp, sp, sp_mask, val, ra) \
{ \ { \
val = (uint32_t)cpu_ldl_kernel(env, SEG_ADDL(ssp, sp, sp_mask)); \ val = (uint32_t)cpu_ldl_kernel_ra(env, SEG_ADDL(ssp, sp, sp_mask), ra); \
sp += 4; \ sp += 4; \
} }
#define PUSHW(ssp, sp, sp_mask, val) PUSHW_RA(ssp, sp, sp_mask, val, 0)
#define PUSHL(ssp, sp, sp_mask, val) PUSHL_RA(ssp, sp, sp_mask, val, 0)
#define POPW(ssp, sp, sp_mask, val) POPW_RA(ssp, sp, sp_mask, val, 0)
#define POPL(ssp, sp, sp_mask, val) POPL_RA(ssp, sp, sp_mask, val, 0)
/* protected mode interrupt */ /* protected mode interrupt */
static void do_interrupt_protected(CPUX86State *env, int intno, int is_int, static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
int error_code, unsigned int next_eip, int error_code, unsigned int next_eip,
...@@ -673,7 +697,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int, ...@@ -673,7 +697,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
} }
if (!(e2 & DESC_C_MASK) && dpl < cpl) { if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner privilege */ /* to inner privilege */
get_ss_esp_from_tss(env, &ss, &esp, dpl); get_ss_esp_from_tss(env, &ss, &esp, dpl, 0);
if ((ss & 0xfffc) == 0) { if ((ss & 0xfffc) == 0) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc);
} }
...@@ -791,18 +815,21 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int, ...@@ -791,18 +815,21 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
#define PUSHQ(sp, val) \ #define PUSHQ_RA(sp, val, ra) \
{ \ { \
sp -= 8; \ sp -= 8; \
cpu_stq_kernel(env, sp, (val)); \ cpu_stq_kernel_ra(env, sp, (val), ra); \
} }
#define POPQ(sp, val) \ #define POPQ_RA(sp, val, ra) \
{ \ { \
val = cpu_ldq_kernel(env, sp); \ val = cpu_ldq_kernel_ra(env, sp, ra); \
sp += 8; \ sp += 8; \
} }
#define PUSHQ(sp, val) PUSHQ_RA(sp, val, 0)
#define POPQ(sp, val) POPQ_RA(sp, val, 0)
static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level) static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
{ {
X86CPU *cpu = x86_env_get_cpu(env); X86CPU *cpu = x86_env_get_cpu(env);
...@@ -961,7 +988,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) ...@@ -961,7 +988,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
int selector; int selector;
if (!(env->efer & MSR_EFER_SCE)) { if (!(env->efer & MSR_EFER_SCE)) {
raise_exception_err(env, EXCP06_ILLOP, 0); raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
} }
selector = (env->star >> 32) & 0xffff; selector = (env->star >> 32) & 0xffff;
if (env->hflags & HF_LMA_MASK) { if (env->hflags & HF_LMA_MASK) {
...@@ -1016,11 +1043,11 @@ void helper_sysret(CPUX86State *env, int dflag) ...@@ -1016,11 +1043,11 @@ void helper_sysret(CPUX86State *env, int dflag)
int cpl, selector; int cpl, selector;
if (!(env->efer & MSR_EFER_SCE)) { if (!(env->efer & MSR_EFER_SCE)) {
raise_exception_err(env, EXCP06_ILLOP, 0); raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
} }
cpl = env->hflags & HF_CPL_MASK; cpl = env->hflags & HF_CPL_MASK;
if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
selector = (env->star >> 48) & 0xffff; selector = (env->star >> 48) & 0xffff;
if (env->hflags & HF_LMA_MASK) { if (env->hflags & HF_LMA_MASK) {
...@@ -1369,22 +1396,26 @@ void helper_enter_level(CPUX86State *env, int level, int data32, ...@@ -1369,22 +1396,26 @@ void helper_enter_level(CPUX86State *env, int level, int data32,
while (--level) { while (--level) {
esp -= 4; esp -= 4;
ebp -= 4; ebp -= 4;
cpu_stl_data(env, ssp + (esp & esp_mask), cpu_stl_data_ra(env, ssp + (esp & esp_mask),
cpu_ldl_data(env, ssp + (ebp & esp_mask))); cpu_ldl_data_ra(env, ssp + (ebp & esp_mask),
GETPC()),
GETPC());
} }
esp -= 4; esp -= 4;
cpu_stl_data(env, ssp + (esp & esp_mask), t1); cpu_stl_data_ra(env, ssp + (esp & esp_mask), t1, GETPC());
} else { } else {
/* 16 bit */ /* 16 bit */
esp -= 2; esp -= 2;
while (--level) { while (--level) {
esp -= 2; esp -= 2;
ebp -= 2; ebp -= 2;
cpu_stw_data(env, ssp + (esp & esp_mask), cpu_stw_data_ra(env, ssp + (esp & esp_mask),
cpu_lduw_data(env, ssp + (ebp & esp_mask))); cpu_lduw_data_ra(env, ssp + (ebp & esp_mask),
GETPC()),
GETPC());
} }
esp -= 2; esp -= 2;
cpu_stw_data(env, ssp + (esp & esp_mask), t1); cpu_stw_data_ra(env, ssp + (esp & esp_mask), t1, GETPC());
} }
} }
...@@ -1403,20 +1434,22 @@ void helper_enter64_level(CPUX86State *env, int level, int data64, ...@@ -1403,20 +1434,22 @@ void helper_enter64_level(CPUX86State *env, int level, int data64,
while (--level) { while (--level) {
esp -= 8; esp -= 8;
ebp -= 8; ebp -= 8;
cpu_stq_data(env, esp, cpu_ldq_data(env, ebp)); cpu_stq_data_ra(env, esp, cpu_ldq_data_ra(env, ebp, GETPC()),
GETPC());
} }
esp -= 8; esp -= 8;
cpu_stq_data(env, esp, t1); cpu_stq_data_ra(env, esp, t1, GETPC());
} else { } else {
/* 16 bit */ /* 16 bit */
esp -= 2; esp -= 2;
while (--level) { while (--level) {
esp -= 2; esp -= 2;
ebp -= 2; ebp -= 2;
cpu_stw_data(env, esp, cpu_lduw_data(env, ebp)); cpu_stw_data_ra(env, esp, cpu_lduw_data_ra(env, ebp, GETPC()),
GETPC());
} }
esp -= 2; esp -= 2;
cpu_stw_data(env, esp, t1); cpu_stw_data_ra(env, esp, t1, GETPC());
} }
} }
#endif #endif
...@@ -1435,7 +1468,7 @@ void helper_lldt(CPUX86State *env, int selector) ...@@ -1435,7 +1468,7 @@ void helper_lldt(CPUX86State *env, int selector)
env->ldt.limit = 0; env->ldt.limit = 0;
} else { } else {
if (selector & 0x4) { if (selector & 0x4) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
dt = &env->gdt; dt = &env->gdt;
index = selector & ~7; index = selector & ~7;
...@@ -1448,22 +1481,22 @@ void helper_lldt(CPUX86State *env, int selector) ...@@ -1448,22 +1481,22 @@ void helper_lldt(CPUX86State *env, int selector)
entry_limit = 7; entry_limit = 7;
} }
if ((index + entry_limit) > dt->limit) { if ((index + entry_limit) > dt->limit) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
ptr = dt->base + index; ptr = dt->base + index;
e1 = cpu_ldl_kernel(env, ptr); e1 = cpu_ldl_kernel_ra(env, ptr, GETPC());
e2 = cpu_ldl_kernel(env, ptr + 4); e2 = cpu_ldl_kernel_ra(env, ptr + 4, GETPC());
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) { if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, GETPC());
} }
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) { if (env->hflags & HF_LMA_MASK) {
uint32_t e3; uint32_t e3;
e3 = cpu_ldl_kernel(env, ptr + 8); e3 = cpu_ldl_kernel_ra(env, ptr + 8, GETPC());
load_seg_cache_raw_dt(&env->ldt, e1, e2); load_seg_cache_raw_dt(&env->ldt, e1, e2);
env->ldt.base |= (target_ulong)e3 << 32; env->ldt.base |= (target_ulong)e3 << 32;
} else } else
...@@ -1490,7 +1523,7 @@ void helper_ltr(CPUX86State *env, int selector) ...@@ -1490,7 +1523,7 @@ void helper_ltr(CPUX86State *env, int selector)
env->tr.flags = 0; env->tr.flags = 0;
} else { } else {
if (selector & 0x4) { if (selector & 0x4) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
dt = &env->gdt; dt = &env->gdt;
index = selector & ~7; index = selector & ~7;
...@@ -1503,27 +1536,27 @@ void helper_ltr(CPUX86State *env, int selector) ...@@ -1503,27 +1536,27 @@ void helper_ltr(CPUX86State *env, int selector)
entry_limit = 7; entry_limit = 7;
} }
if ((index + entry_limit) > dt->limit) { if ((index + entry_limit) > dt->limit) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
ptr = dt->base + index; ptr = dt->base + index;
e1 = cpu_ldl_kernel(env, ptr); e1 = cpu_ldl_kernel_ra(env, ptr, GETPC());
e2 = cpu_ldl_kernel(env, ptr + 4); e2 = cpu_ldl_kernel_ra(env, ptr + 4, GETPC());
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
if ((e2 & DESC_S_MASK) || if ((e2 & DESC_S_MASK) ||
(type != 1 && type != 9)) { (type != 1 && type != 9)) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, GETPC());
} }
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) { if (env->hflags & HF_LMA_MASK) {
uint32_t e3, e4; uint32_t e3, e4;
e3 = cpu_ldl_kernel(env, ptr + 8); e3 = cpu_ldl_kernel_ra(env, ptr + 8, GETPC());
e4 = cpu_ldl_kernel(env, ptr + 12); e4 = cpu_ldl_kernel_ra(env, ptr + 12, GETPC());
if ((e4 >> DESC_TYPE_SHIFT) & 0xf) { if ((e4 >> DESC_TYPE_SHIFT) & 0xf) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
load_seg_cache_raw_dt(&env->tr, e1, e2); load_seg_cache_raw_dt(&env->tr, e1, e2);
env->tr.base |= (target_ulong)e3 << 32; env->tr.base |= (target_ulong)e3 << 32;
...@@ -1533,7 +1566,7 @@ void helper_ltr(CPUX86State *env, int selector) ...@@ -1533,7 +1566,7 @@ void helper_ltr(CPUX86State *env, int selector)
load_seg_cache_raw_dt(&env->tr, e1, e2); load_seg_cache_raw_dt(&env->tr, e1, e2);
} }
e2 |= DESC_TSS_BUSY_MASK; e2 |= DESC_TSS_BUSY_MASK;
cpu_stl_kernel(env, ptr + 4, e2); cpu_stl_kernel_ra(env, ptr + 4, e2, GETPC());
} }
env->tr.selector = selector; env->tr.selector = selector;
} }
...@@ -1556,7 +1589,7 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) ...@@ -1556,7 +1589,7 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector)
&& (!(env->hflags & HF_CS64_MASK) || cpl == 3) && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
#endif #endif
) { ) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
} else { } else {
...@@ -1568,51 +1601,51 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) ...@@ -1568,51 +1601,51 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector)
} }
index = selector & ~7; index = selector & ~7;
if ((index + 7) > dt->limit) { if ((index + 7) > dt->limit) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
ptr = dt->base + index; ptr = dt->base + index;
e1 = cpu_ldl_kernel(env, ptr); e1 = cpu_ldl_kernel_ra(env, ptr, GETPC());
e2 = cpu_ldl_kernel(env, ptr + 4); e2 = cpu_ldl_kernel_ra(env, ptr + 4, GETPC());
if (!(e2 & DESC_S_MASK)) { if (!(e2 & DESC_S_MASK)) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
rpl = selector & 3; rpl = selector & 3;
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (seg_reg == R_SS) { if (seg_reg == R_SS) {
/* must be writable segment */ /* must be writable segment */
if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
if (rpl != cpl || dpl != cpl) { if (rpl != cpl || dpl != cpl) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
} else { } else {
/* must be readable segment */ /* must be readable segment */
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
/* if not conforming code, test rights */ /* if not conforming code, test rights */
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
} }
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
if (seg_reg == R_SS) { if (seg_reg == R_SS) {
raise_exception_err(env, EXCP0C_STACK, selector & 0xfffc); raise_exception_err_ra(env, EXCP0C_STACK, selector & 0xfffc, GETPC());
} else { } else {
raise_exception_err(env, EXCP0B_NOSEG, selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, GETPC());
} }
} }
/* set the access bit if not already set */ /* set the access bit if not already set */
if (!(e2 & DESC_A_MASK)) { if (!(e2 & DESC_A_MASK)) {
e2 |= DESC_A_MASK; e2 |= DESC_A_MASK;
cpu_stl_kernel(env, ptr + 4, e2); cpu_stl_kernel_ra(env, ptr + 4, e2, GETPC());
} }
cpu_x86_load_seg_cache(env, seg_reg, selector, cpu_x86_load_seg_cache(env, seg_reg, selector,
...@@ -1628,46 +1661,45 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) ...@@ -1628,46 +1661,45 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector)
/* protected mode jump */ /* protected mode jump */
void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip, void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
int next_eip_addend) target_ulong next_eip)
{ {
int gate_cs, type; int gate_cs, type;
uint32_t e1, e2, cpl, dpl, rpl, limit; uint32_t e1, e2, cpl, dpl, rpl, limit;
target_ulong next_eip;
if ((new_cs & 0xfffc) == 0) { if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
if (load_segment(env, &e1, &e2, new_cs) != 0) { if (load_segment_ra(env, &e1, &e2, new_cs, GETPC()) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
cpl = env->hflags & HF_CPL_MASK; cpl = env->hflags & HF_CPL_MASK;
if (e2 & DESC_S_MASK) { if (e2 & DESC_S_MASK) {
if (!(e2 & DESC_CS_MASK)) { if (!(e2 & DESC_CS_MASK)) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (e2 & DESC_C_MASK) { if (e2 & DESC_C_MASK) {
/* conforming code segment */ /* conforming code segment */
if (dpl > cpl) { if (dpl > cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
} else { } else {
/* non conforming code segment */ /* non conforming code segment */
rpl = new_cs & 3; rpl = new_cs & 3;
if (rpl > cpl) { if (rpl > cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
if (dpl != cpl) { if (dpl != cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GETPC());
} }
limit = get_seg_limit(e1, e2); limit = get_seg_limit(e1, e2);
if (new_eip > limit && if (new_eip > limit &&
!(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) { !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
get_seg_base(e1, e2), limit, e2); get_seg_base(e1, e2), limit, e2);
...@@ -1683,50 +1715,49 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip, ...@@ -1683,50 +1715,49 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
case 9: /* 386 TSS */ case 9: /* 386 TSS */
case 5: /* task gate */ case 5: /* task gate */
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
next_eip = env->eip + next_eip_addend; switch_tss_ra(env, new_cs, e1, e2, SWITCH_TSS_JMP, next_eip, GETPC());
switch_tss(env, new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
break; break;
case 4: /* 286 call gate */ case 4: /* 286 call gate */
case 12: /* 386 call gate */ case 12: /* 386 call gate */
if ((dpl < cpl) || (dpl < rpl)) { if ((dpl < cpl) || (dpl < rpl)) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GETPC());
} }
gate_cs = e1 >> 16; gate_cs = e1 >> 16;
new_eip = (e1 & 0xffff); new_eip = (e1 & 0xffff);
if (type == 12) { if (type == 12) {
new_eip |= (e2 & 0xffff0000); new_eip |= (e2 & 0xffff0000);
} }
if (load_segment(env, &e1, &e2, gate_cs) != 0) { if (load_segment_ra(env, &e1, &e2, gate_cs, GETPC()) != 0) {
raise_exception_err(env, EXCP0D_GPF, gate_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
} }
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
/* must be code segment */ /* must be code segment */
if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
(DESC_S_MASK | DESC_CS_MASK))) { (DESC_S_MASK | DESC_CS_MASK))) {
raise_exception_err(env, EXCP0D_GPF, gate_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
} }
if (((e2 & DESC_C_MASK) && (dpl > cpl)) || if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
(!(e2 & DESC_C_MASK) && (dpl != cpl))) { (!(e2 & DESC_C_MASK) && (dpl != cpl))) {
raise_exception_err(env, EXCP0D_GPF, gate_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0D_GPF, gate_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
} }
limit = get_seg_limit(e1, e2); limit = get_seg_limit(e1, e2);
if (new_eip > limit) { if (new_eip > limit) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
get_seg_base(e1, e2), limit, e2); get_seg_base(e1, e2), limit, e2);
env->eip = new_eip; env->eip = new_eip;
break; break;
default: default:
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
break; break;
} }
} }
...@@ -1745,11 +1776,11 @@ void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1, ...@@ -1745,11 +1776,11 @@ void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1,
esp_mask = get_sp_mask(env->segs[R_SS].flags); esp_mask = get_sp_mask(env->segs[R_SS].flags);
ssp = env->segs[R_SS].base; ssp = env->segs[R_SS].base;
if (shift) { if (shift) {
PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); PUSHL_RA(ssp, esp, esp_mask, env->segs[R_CS].selector, GETPC());
PUSHL(ssp, esp, esp_mask, next_eip); PUSHL_RA(ssp, esp, esp_mask, next_eip, GETPC());
} else { } else {
PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); PUSHW_RA(ssp, esp, esp_mask, env->segs[R_CS].selector, GETPC());
PUSHW(ssp, esp, esp_mask, next_eip); PUSHW_RA(ssp, esp, esp_mask, next_eip, GETPC());
} }
SET_ESP(esp, esp_mask); SET_ESP(esp, esp_mask);
...@@ -1760,47 +1791,46 @@ void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1, ...@@ -1760,47 +1791,46 @@ void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1,
/* protected mode call */ /* protected mode call */
void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
int shift, int next_eip_addend) int shift, target_ulong next_eip)
{ {
int new_stack, i; int new_stack, i;
uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask; uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
uint32_t val, limit, old_sp_mask; uint32_t val, limit, old_sp_mask;
target_ulong ssp, old_ssp, next_eip; target_ulong ssp, old_ssp;
next_eip = env->eip + next_eip_addend;
LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift); LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
LOG_PCALL_STATE(CPU(x86_env_get_cpu(env))); LOG_PCALL_STATE(CPU(x86_env_get_cpu(env)));
if ((new_cs & 0xfffc) == 0) { if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
if (load_segment(env, &e1, &e2, new_cs) != 0) { if (load_segment_ra(env, &e1, &e2, new_cs, GETPC()) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
cpl = env->hflags & HF_CPL_MASK; cpl = env->hflags & HF_CPL_MASK;
LOG_PCALL("desc=%08x:%08x\n", e1, e2); LOG_PCALL("desc=%08x:%08x\n", e1, e2);
if (e2 & DESC_S_MASK) { if (e2 & DESC_S_MASK) {
if (!(e2 & DESC_CS_MASK)) { if (!(e2 & DESC_CS_MASK)) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (e2 & DESC_C_MASK) { if (e2 & DESC_C_MASK) {
/* conforming code segment */ /* conforming code segment */
if (dpl > cpl) { if (dpl > cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
} else { } else {
/* non conforming code segment */ /* non conforming code segment */
rpl = new_cs & 3; rpl = new_cs & 3;
if (rpl > cpl) { if (rpl > cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
if (dpl != cpl) { if (dpl != cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GETPC());
} }
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
...@@ -1810,8 +1840,8 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, ...@@ -1810,8 +1840,8 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
/* 64 bit case */ /* 64 bit case */
rsp = env->regs[R_ESP]; rsp = env->regs[R_ESP];
PUSHQ(rsp, env->segs[R_CS].selector); PUSHQ_RA(rsp, env->segs[R_CS].selector, GETPC());
PUSHQ(rsp, next_eip); PUSHQ_RA(rsp, next_eip, GETPC());
/* from this point, not restartable */ /* from this point, not restartable */
env->regs[R_ESP] = rsp; env->regs[R_ESP] = rsp;
cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
...@@ -1825,16 +1855,16 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, ...@@ -1825,16 +1855,16 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
sp_mask = get_sp_mask(env->segs[R_SS].flags); sp_mask = get_sp_mask(env->segs[R_SS].flags);
ssp = env->segs[R_SS].base; ssp = env->segs[R_SS].base;
if (shift) { if (shift) {
PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); PUSHL_RA(ssp, sp, sp_mask, env->segs[R_CS].selector, GETPC());
PUSHL(ssp, sp, sp_mask, next_eip); PUSHL_RA(ssp, sp, sp_mask, next_eip, GETPC());
} else { } else {
PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); PUSHW_RA(ssp, sp, sp_mask, env->segs[R_CS].selector, GETPC());
PUSHW(ssp, sp, sp_mask, next_eip); PUSHW_RA(ssp, sp, sp_mask, next_eip, GETPC());
} }
limit = get_seg_limit(e1, e2); limit = get_seg_limit(e1, e2);
if (new_eip > limit) { if (new_eip > limit) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
/* from this point, not restartable */ /* from this point, not restartable */
SET_ESP(sp, sp_mask); SET_ESP(sp, sp_mask);
...@@ -1852,73 +1882,73 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, ...@@ -1852,73 +1882,73 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
case 9: /* available 386 TSS */ case 9: /* available 386 TSS */
case 5: /* task gate */ case 5: /* task gate */
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
switch_tss(env, new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); switch_tss_ra(env, new_cs, e1, e2, SWITCH_TSS_CALL, next_eip, GETPC());
return; return;
case 4: /* 286 call gate */ case 4: /* 286 call gate */
case 12: /* 386 call gate */ case 12: /* 386 call gate */
break; break;
default: default:
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
break; break;
} }
shift = type >> 3; shift = type >> 3;
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
} }
/* check valid bit */ /* check valid bit */
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GETPC());
} }
selector = e1 >> 16; selector = e1 >> 16;
offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
param_count = e2 & 0x1f; param_count = e2 & 0x1f;
if ((selector & 0xfffc) == 0) { if ((selector & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
if (load_segment(env, &e1, &e2, selector) != 0) { if (load_segment_ra(env, &e1, &e2, selector, GETPC()) != 0) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) { if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (dpl > cpl) { if (dpl > cpl) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, selector & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, GETPC());
} }
if (!(e2 & DESC_C_MASK) && dpl < cpl) { if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner privilege */ /* to inner privilege */
get_ss_esp_from_tss(env, &ss, &sp, dpl); get_ss_esp_from_tss(env, &ss, &sp, dpl, GETPC());
LOG_PCALL("new ss:esp=%04x:%08x param_count=%d env->regs[R_ESP]=" LOG_PCALL("new ss:esp=%04x:%08x param_count=%d env->regs[R_ESP]="
TARGET_FMT_lx "\n", ss, sp, param_count, TARGET_FMT_lx "\n", ss, sp, param_count,
env->regs[R_ESP]); env->regs[R_ESP]);
if ((ss & 0xfffc) == 0) { if ((ss & 0xfffc) == 0) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
} }
if ((ss & 3) != dpl) { if ((ss & 3) != dpl) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
} }
if (load_segment(env, &ss_e1, &ss_e2, ss) != 0) { if (load_segment_ra(env, &ss_e1, &ss_e2, ss, GETPC()) != 0) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
} }
ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
if (ss_dpl != dpl) { if (ss_dpl != dpl) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
} }
if (!(ss_e2 & DESC_S_MASK) || if (!(ss_e2 & DESC_S_MASK) ||
(ss_e2 & DESC_CS_MASK) || (ss_e2 & DESC_CS_MASK) ||
!(ss_e2 & DESC_W_MASK)) { !(ss_e2 & DESC_W_MASK)) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
} }
if (!(ss_e2 & DESC_P_MASK)) { if (!(ss_e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
} }
/* push_size = ((param_count * 2) + 8) << shift; */ /* push_size = ((param_count * 2) + 8) << shift; */
...@@ -1929,22 +1959,22 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, ...@@ -1929,22 +1959,22 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
sp_mask = get_sp_mask(ss_e2); sp_mask = get_sp_mask(ss_e2);
ssp = get_seg_base(ss_e1, ss_e2); ssp = get_seg_base(ss_e1, ss_e2);
if (shift) { if (shift) {
PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); PUSHL_RA(ssp, sp, sp_mask, env->segs[R_SS].selector, GETPC());
PUSHL(ssp, sp, sp_mask, env->regs[R_ESP]); PUSHL_RA(ssp, sp, sp_mask, env->regs[R_ESP], GETPC());
for (i = param_count - 1; i >= 0; i--) { for (i = param_count - 1; i >= 0; i--) {
val = cpu_ldl_kernel(env, old_ssp + val = cpu_ldl_kernel_ra(env, old_ssp +
((env->regs[R_ESP] + i * 4) & ((env->regs[R_ESP] + i * 4) &
old_sp_mask)); old_sp_mask), GETPC());
PUSHL(ssp, sp, sp_mask, val); PUSHL_RA(ssp, sp, sp_mask, val, GETPC());
} }
} else { } else {
PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); PUSHW_RA(ssp, sp, sp_mask, env->segs[R_SS].selector, GETPC());
PUSHW(ssp, sp, sp_mask, env->regs[R_ESP]); PUSHW_RA(ssp, sp, sp_mask, env->regs[R_ESP], GETPC());
for (i = param_count - 1; i >= 0; i--) { for (i = param_count - 1; i >= 0; i--) {
val = cpu_lduw_kernel(env, old_ssp + val = cpu_lduw_kernel_ra(env, old_ssp +
((env->regs[R_ESP] + i * 2) & ((env->regs[R_ESP] + i * 2) &
old_sp_mask)); old_sp_mask), GETPC());
PUSHW(ssp, sp, sp_mask, val); PUSHW_RA(ssp, sp, sp_mask, val, GETPC());
} }
} }
new_stack = 1; new_stack = 1;
...@@ -1958,11 +1988,11 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, ...@@ -1958,11 +1988,11 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
} }
if (shift) { if (shift) {
PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); PUSHL_RA(ssp, sp, sp_mask, env->segs[R_CS].selector, GETPC());
PUSHL(ssp, sp, sp_mask, next_eip); PUSHL_RA(ssp, sp, sp_mask, next_eip, GETPC());
} else { } else {
PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); PUSHW_RA(ssp, sp, sp_mask, env->segs[R_CS].selector, GETPC());
PUSHW(ssp, sp, sp_mask, next_eip); PUSHW_RA(ssp, sp, sp_mask, next_eip, GETPC());
} }
/* from this point, not restartable */ /* from this point, not restartable */
...@@ -1997,15 +2027,15 @@ void helper_iret_real(CPUX86State *env, int shift) ...@@ -1997,15 +2027,15 @@ void helper_iret_real(CPUX86State *env, int shift)
ssp = env->segs[R_SS].base; ssp = env->segs[R_SS].base;
if (shift == 1) { if (shift == 1) {
/* 32 bits */ /* 32 bits */
POPL(ssp, sp, sp_mask, new_eip); POPL_RA(ssp, sp, sp_mask, new_eip, GETPC());
POPL(ssp, sp, sp_mask, new_cs); POPL_RA(ssp, sp, sp_mask, new_cs, GETPC());
new_cs &= 0xffff; new_cs &= 0xffff;
POPL(ssp, sp, sp_mask, new_eflags); POPL_RA(ssp, sp, sp_mask, new_eflags, GETPC());
} else { } else {
/* 16 bits */ /* 16 bits */
POPW(ssp, sp, sp_mask, new_eip); POPW_RA(ssp, sp, sp_mask, new_eip, GETPC());
POPW(ssp, sp, sp_mask, new_cs); POPW_RA(ssp, sp, sp_mask, new_cs, GETPC());
POPW(ssp, sp, sp_mask, new_eflags); POPW_RA(ssp, sp, sp_mask, new_eflags, GETPC());
} }
env->regs[R_ESP] = (env->regs[R_ESP] & ~sp_mask) | (sp & sp_mask); env->regs[R_ESP] = (env->regs[R_ESP] & ~sp_mask) | (sp & sp_mask);
env->segs[R_CS].selector = new_cs; env->segs[R_CS].selector = new_cs;
...@@ -2050,7 +2080,8 @@ static inline void validate_seg(CPUX86State *env, int seg_reg, int cpl) ...@@ -2050,7 +2080,8 @@ static inline void validate_seg(CPUX86State *env, int seg_reg, int cpl)
/* protected mode iret */ /* protected mode iret */
static inline void helper_ret_protected(CPUX86State *env, int shift, static inline void helper_ret_protected(CPUX86State *env, int shift,
int is_iret, int addend) int is_iret, int addend,
uintptr_t retaddr)
{ {
uint32_t new_cs, new_eflags, new_ss; uint32_t new_cs, new_eflags, new_ss;
uint32_t new_es, new_ds, new_fs, new_gs; uint32_t new_es, new_ds, new_fs, new_gs;
...@@ -2071,32 +2102,32 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, ...@@ -2071,32 +2102,32 @@ static inline void helper_ret_protected(CPUX86State *env, int shift,
new_eflags = 0; /* avoid warning */ new_eflags = 0; /* avoid warning */
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (shift == 2) { if (shift == 2) {
POPQ(sp, new_eip); POPQ_RA(sp, new_eip, retaddr);
POPQ(sp, new_cs); POPQ_RA(sp, new_cs, retaddr);
new_cs &= 0xffff; new_cs &= 0xffff;
if (is_iret) { if (is_iret) {
POPQ(sp, new_eflags); POPQ_RA(sp, new_eflags, retaddr);
} }
} else } else
#endif #endif
{ {
if (shift == 1) { if (shift == 1) {
/* 32 bits */ /* 32 bits */
POPL(ssp, sp, sp_mask, new_eip); POPL_RA(ssp, sp, sp_mask, new_eip, retaddr);
POPL(ssp, sp, sp_mask, new_cs); POPL_RA(ssp, sp, sp_mask, new_cs, retaddr);
new_cs &= 0xffff; new_cs &= 0xffff;
if (is_iret) { if (is_iret) {
POPL(ssp, sp, sp_mask, new_eflags); POPL_RA(ssp, sp, sp_mask, new_eflags, retaddr);
if (new_eflags & VM_MASK) { if (new_eflags & VM_MASK) {
goto return_to_vm86; goto return_to_vm86;
} }
} }
} else { } else {
/* 16 bits */ /* 16 bits */
POPW(ssp, sp, sp_mask, new_eip); POPW_RA(ssp, sp, sp_mask, new_eip, retaddr);
POPW(ssp, sp, sp_mask, new_cs); POPW_RA(ssp, sp, sp_mask, new_cs, retaddr);
if (is_iret) { if (is_iret) {
POPW(ssp, sp, sp_mask, new_eflags); POPW_RA(ssp, sp, sp_mask, new_eflags, retaddr);
} }
} }
} }
...@@ -2104,32 +2135,32 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, ...@@ -2104,32 +2135,32 @@ static inline void helper_ret_protected(CPUX86State *env, int shift,
new_cs, new_eip, shift, addend); new_cs, new_eip, shift, addend);
LOG_PCALL_STATE(CPU(x86_env_get_cpu(env))); LOG_PCALL_STATE(CPU(x86_env_get_cpu(env)));
if ((new_cs & 0xfffc) == 0) { if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, retaddr);
} }
if (load_segment(env, &e1, &e2, new_cs) != 0) { if (load_segment_ra(env, &e1, &e2, new_cs, retaddr) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, retaddr);
} }
if (!(e2 & DESC_S_MASK) || if (!(e2 & DESC_S_MASK) ||
!(e2 & DESC_CS_MASK)) { !(e2 & DESC_CS_MASK)) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, retaddr);
} }
cpl = env->hflags & HF_CPL_MASK; cpl = env->hflags & HF_CPL_MASK;
rpl = new_cs & 3; rpl = new_cs & 3;
if (rpl < cpl) { if (rpl < cpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, retaddr);
} }
dpl = (e2 >> DESC_DPL_SHIFT) & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (e2 & DESC_C_MASK) { if (e2 & DESC_C_MASK) {
if (dpl > rpl) { if (dpl > rpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, retaddr);
} }
} else { } else {
if (dpl != rpl) { if (dpl != rpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, retaddr);
} }
} }
if (!(e2 & DESC_P_MASK)) { if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, new_cs & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, retaddr);
} }
sp += addend; sp += addend;
...@@ -2144,21 +2175,21 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, ...@@ -2144,21 +2175,21 @@ static inline void helper_ret_protected(CPUX86State *env, int shift,
/* return to different privilege level */ /* return to different privilege level */
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (shift == 2) { if (shift == 2) {
POPQ(sp, new_esp); POPQ_RA(sp, new_esp, retaddr);
POPQ(sp, new_ss); POPQ_RA(sp, new_ss, retaddr);
new_ss &= 0xffff; new_ss &= 0xffff;
} else } else
#endif #endif
{ {
if (shift == 1) { if (shift == 1) {
/* 32 bits */ /* 32 bits */
POPL(ssp, sp, sp_mask, new_esp); POPL_RA(ssp, sp, sp_mask, new_esp, retaddr);
POPL(ssp, sp, sp_mask, new_ss); POPL_RA(ssp, sp, sp_mask, new_ss, retaddr);
new_ss &= 0xffff; new_ss &= 0xffff;
} else { } else {
/* 16 bits */ /* 16 bits */
POPW(ssp, sp, sp_mask, new_esp); POPW_RA(ssp, sp, sp_mask, new_esp, retaddr);
POPW(ssp, sp, sp_mask, new_ss); POPW_RA(ssp, sp, sp_mask, new_ss, retaddr);
} }
} }
LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n", LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
...@@ -2177,26 +2208,26 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, ...@@ -2177,26 +2208,26 @@ static inline void helper_ret_protected(CPUX86State *env, int shift,
} else } else
#endif #endif
{ {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
} }
} else { } else {
if ((new_ss & 3) != rpl) { if ((new_ss & 3) != rpl) {
raise_exception_err(env, EXCP0D_GPF, new_ss & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_ss & 0xfffc, retaddr);
} }
if (load_segment(env, &ss_e1, &ss_e2, new_ss) != 0) { if (load_segment_ra(env, &ss_e1, &ss_e2, new_ss, retaddr) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_ss & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_ss & 0xfffc, retaddr);
} }
if (!(ss_e2 & DESC_S_MASK) || if (!(ss_e2 & DESC_S_MASK) ||
(ss_e2 & DESC_CS_MASK) || (ss_e2 & DESC_CS_MASK) ||
!(ss_e2 & DESC_W_MASK)) { !(ss_e2 & DESC_W_MASK)) {
raise_exception_err(env, EXCP0D_GPF, new_ss & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_ss & 0xfffc, retaddr);
} }
dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
if (dpl != rpl) { if (dpl != rpl) {
raise_exception_err(env, EXCP0D_GPF, new_ss & 0xfffc); raise_exception_err_ra(env, EXCP0D_GPF, new_ss & 0xfffc, retaddr);
} }
if (!(ss_e2 & DESC_P_MASK)) { if (!(ss_e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, new_ss & 0xfffc); raise_exception_err_ra(env, EXCP0B_NOSEG, new_ss & 0xfffc, retaddr);
} }
cpu_x86_load_seg_cache(env, R_SS, new_ss, cpu_x86_load_seg_cache(env, R_SS, new_ss,
get_seg_base(ss_e1, ss_e2), get_seg_base(ss_e1, ss_e2),
...@@ -2246,12 +2277,12 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, ...@@ -2246,12 +2277,12 @@ static inline void helper_ret_protected(CPUX86State *env, int shift,
return; return;
return_to_vm86: return_to_vm86:
POPL(ssp, sp, sp_mask, new_esp); POPL_RA(ssp, sp, sp_mask, new_esp, retaddr);
POPL(ssp, sp, sp_mask, new_ss); POPL_RA(ssp, sp, sp_mask, new_ss, retaddr);
POPL(ssp, sp, sp_mask, new_es); POPL_RA(ssp, sp, sp_mask, new_es, retaddr);
POPL(ssp, sp, sp_mask, new_ds); POPL_RA(ssp, sp, sp_mask, new_ds, retaddr);
POPL(ssp, sp, sp_mask, new_fs); POPL_RA(ssp, sp, sp_mask, new_fs, retaddr);
POPL(ssp, sp, sp_mask, new_gs); POPL_RA(ssp, sp, sp_mask, new_gs, retaddr);
/* modify processor state */ /* modify processor state */
cpu_load_eflags(env, new_eflags, TF_MASK | AC_MASK | ID_MASK | cpu_load_eflags(env, new_eflags, TF_MASK | AC_MASK | ID_MASK |
...@@ -2277,37 +2308,37 @@ void helper_iret_protected(CPUX86State *env, int shift, int next_eip) ...@@ -2277,37 +2308,37 @@ void helper_iret_protected(CPUX86State *env, int shift, int next_eip)
if (env->eflags & NT_MASK) { if (env->eflags & NT_MASK) {
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) { if (env->hflags & HF_LMA_MASK) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
#endif #endif
tss_selector = cpu_lduw_kernel(env, env->tr.base + 0); tss_selector = cpu_lduw_kernel_ra(env, env->tr.base + 0, GETPC());
if (tss_selector & 4) { if (tss_selector & 4) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, tss_selector & 0xfffc, GETPC());
} }
if (load_segment(env, &e1, &e2, tss_selector) != 0) { if (load_segment_ra(env, &e1, &e2, tss_selector, GETPC()) != 0) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, tss_selector & 0xfffc, GETPC());
} }
type = (e2 >> DESC_TYPE_SHIFT) & 0x17; type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
/* NOTE: we check both segment and busy TSS */ /* NOTE: we check both segment and busy TSS */
if (type != 3) { if (type != 3) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc); raise_exception_err_ra(env, EXCP0A_TSS, tss_selector & 0xfffc, GETPC());
} }
switch_tss(env, tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); switch_tss_ra(env, tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip, GETPC());
} else { } else {
helper_ret_protected(env, shift, 1, 0); helper_ret_protected(env, shift, 1, 0, GETPC());
} }
env->hflags2 &= ~HF2_NMI_MASK; env->hflags2 &= ~HF2_NMI_MASK;
} }
void helper_lret_protected(CPUX86State *env, int shift, int addend) void helper_lret_protected(CPUX86State *env, int shift, int addend)
{ {
helper_ret_protected(env, shift, 0, addend); helper_ret_protected(env, shift, 0, addend, GETPC());
} }
void helper_sysenter(CPUX86State *env) void helper_sysenter(CPUX86State *env)
{ {
if (env->sysenter_cs == 0) { if (env->sysenter_cs == 0) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
...@@ -2343,7 +2374,7 @@ void helper_sysexit(CPUX86State *env, int dflag) ...@@ -2343,7 +2374,7 @@ void helper_sysexit(CPUX86State *env, int dflag)
cpl = env->hflags & HF_CPL_MASK; cpl = env->hflags & HF_CPL_MASK;
if (env->sysenter_cs == 0 || cpl != 0) { if (env->sysenter_cs == 0 || cpl != 0) {
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
} }
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (dflag == 2) { if (dflag == 2) {
...@@ -2387,7 +2418,7 @@ target_ulong helper_lsl(CPUX86State *env, target_ulong selector1) ...@@ -2387,7 +2418,7 @@ target_ulong helper_lsl(CPUX86State *env, target_ulong selector1)
if ((selector & 0xfffc) == 0) { if ((selector & 0xfffc) == 0) {
goto fail; goto fail;
} }
if (load_segment(env, &e1, &e2, selector) != 0) { if (load_segment_ra(env, &e1, &e2, selector, GETPC()) != 0) {
goto fail; goto fail;
} }
rpl = selector & 3; rpl = selector & 3;
...@@ -2434,7 +2465,7 @@ target_ulong helper_lar(CPUX86State *env, target_ulong selector1) ...@@ -2434,7 +2465,7 @@ target_ulong helper_lar(CPUX86State *env, target_ulong selector1)
if ((selector & 0xfffc) == 0) { if ((selector & 0xfffc) == 0) {
goto fail; goto fail;
} }
if (load_segment(env, &e1, &e2, selector) != 0) { if (load_segment_ra(env, &e1, &e2, selector, GETPC()) != 0) {
goto fail; goto fail;
} }
rpl = selector & 3; rpl = selector & 3;
...@@ -2483,7 +2514,7 @@ void helper_verr(CPUX86State *env, target_ulong selector1) ...@@ -2483,7 +2514,7 @@ void helper_verr(CPUX86State *env, target_ulong selector1)
if ((selector & 0xfffc) == 0) { if ((selector & 0xfffc) == 0) {
goto fail; goto fail;
} }
if (load_segment(env, &e1, &e2, selector) != 0) { if (load_segment_ra(env, &e1, &e2, selector, GETPC()) != 0) {
goto fail; goto fail;
} }
if (!(e2 & DESC_S_MASK)) { if (!(e2 & DESC_S_MASK)) {
...@@ -2521,7 +2552,7 @@ void helper_verw(CPUX86State *env, target_ulong selector1) ...@@ -2521,7 +2552,7 @@ void helper_verw(CPUX86State *env, target_ulong selector1)
if ((selector & 0xfffc) == 0) { if ((selector & 0xfffc) == 0) {
goto fail; goto fail;
} }
if (load_segment(env, &e1, &e2, selector) != 0) { if (load_segment_ra(env, &e1, &e2, selector, GETPC()) != 0) {
goto fail; goto fail;
} }
if (!(e2 & DESC_S_MASK)) { if (!(e2 & DESC_S_MASK)) {
...@@ -2562,7 +2593,8 @@ void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector) ...@@ -2562,7 +2593,8 @@ void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector)
#endif #endif
/* check if Port I/O is allowed in TSS */ /* check if Port I/O is allowed in TSS */
static inline void check_io(CPUX86State *env, int addr, int size) static inline void check_io(CPUX86State *env, int addr, int size,
uintptr_t retaddr)
{ {
int io_offset, val, mask; int io_offset, val, mask;
...@@ -2572,33 +2604,33 @@ static inline void check_io(CPUX86State *env, int addr, int size) ...@@ -2572,33 +2604,33 @@ static inline void check_io(CPUX86State *env, int addr, int size)
env->tr.limit < 103) { env->tr.limit < 103) {
goto fail; goto fail;
} }
io_offset = cpu_lduw_kernel(env, env->tr.base + 0x66); io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr);
io_offset += (addr >> 3); io_offset += (addr >> 3);
/* Note: the check needs two bytes */ /* Note: the check needs two bytes */
if ((io_offset + 1) > env->tr.limit) { if ((io_offset + 1) > env->tr.limit) {
goto fail; goto fail;
} }
val = cpu_lduw_kernel(env, env->tr.base + io_offset); val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr);
val >>= (addr & 7); val >>= (addr & 7);
mask = (1 << size) - 1; mask = (1 << size) - 1;
/* all bits must be zero to allow the I/O */ /* all bits must be zero to allow the I/O */
if ((val & mask) != 0) { if ((val & mask) != 0) {
fail: fail:
raise_exception_err(env, EXCP0D_GPF, 0); raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
} }
} }
void helper_check_iob(CPUX86State *env, uint32_t t0) void helper_check_iob(CPUX86State *env, uint32_t t0)
{ {
check_io(env, t0, 1); check_io(env, t0, 1, GETPC());
} }
void helper_check_iow(CPUX86State *env, uint32_t t0) void helper_check_iow(CPUX86State *env, uint32_t t0)
{ {
check_io(env, t0, 2); check_io(env, t0, 2, GETPC());
} }
void helper_check_iol(CPUX86State *env, uint32_t t0) void helper_check_iol(CPUX86State *env, uint32_t t0)
{ {
check_io(env, t0, 4); check_io(env, t0, 4, GETPC());
} }
...@@ -663,14 +663,9 @@ static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n) ...@@ -663,14 +663,9 @@ static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n)
static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip, static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip,
uint32_t svm_flags) uint32_t svm_flags)
{ {
int state_saved;
target_ulong next_eip; target_ulong next_eip;
state_saved = 0;
if (s->pe && (s->cpl > s->iopl || s->vm86)) { if (s->pe && (s->cpl > s->iopl || s->vm86)) {
gen_update_cc_op(s);
gen_jmp_im(cur_eip);
state_saved = 1;
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
switch (ot) { switch (ot) {
case MO_8: case MO_8:
...@@ -687,10 +682,8 @@ static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip, ...@@ -687,10 +682,8 @@ static void gen_check_io(DisasContext *s, TCGMemOp ot, target_ulong cur_eip,
} }
} }
if(s->flags & HF_SVMI_MASK) { if(s->flags & HF_SVMI_MASK) {
if (!state_saved) { gen_update_cc_op(s);
gen_update_cc_op(s); gen_jmp_im(cur_eip);
gen_jmp_im(cur_eip);
}
svm_flags |= (1 << (4 + ot)); svm_flags |= (1 << (4 + ot));
next_eip = s->pc - s->cs_base; next_eip = s->pc - s->cs_base;
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
...@@ -2297,12 +2290,9 @@ static inline void gen_op_movl_seg_T0_vm(int seg_reg) ...@@ -2297,12 +2290,9 @@ static inline void gen_op_movl_seg_T0_vm(int seg_reg)
/* move T0 to seg_reg and compute if the CPU state may change. Never /* move T0 to seg_reg and compute if the CPU state may change. Never
call this function with seg_reg == R_CS */ call this function with seg_reg == R_CS */
static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
{ {
if (s->pe && !s->vm86) { if (s->pe && !s->vm86) {
/* XXX: optimize by finding processor state dynamically */
gen_update_cc_op(s);
gen_jmp_im(cur_eip);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), cpu_tmp2_i32); gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), cpu_tmp2_i32);
/* abort translation because the addseg value may change or /* abort translation because the addseg value may change or
...@@ -4943,12 +4933,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -4943,12 +4933,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_ld_v(s, MO_16, cpu_T[0], cpu_A0); gen_op_ld_v(s, MO_16, cpu_T[0], cpu_A0);
do_lcall: do_lcall:
if (s->pe && !s->vm86) { if (s->pe && !s->vm86) {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_lcall_protected(cpu_env, cpu_tmp2_i32, cpu_T[1], gen_helper_lcall_protected(cpu_env, cpu_tmp2_i32, cpu_T[1],
tcg_const_i32(dflag - 1), tcg_const_i32(dflag - 1),
tcg_const_i32(s->pc - pc_start)); tcg_const_tl(s->pc - s->cs_base));
} else { } else {
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_lcall_real(cpu_env, cpu_tmp2_i32, cpu_T[1], gen_helper_lcall_real(cpu_env, cpu_tmp2_i32, cpu_T[1],
...@@ -4970,11 +4958,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -4970,11 +4958,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_ld_v(s, MO_16, cpu_T[0], cpu_A0); gen_op_ld_v(s, MO_16, cpu_T[0], cpu_A0);
do_ljmp: do_ljmp:
if (s->pe && !s->vm86) { if (s->pe && !s->vm86) {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_ljmp_protected(cpu_env, cpu_tmp2_i32, cpu_T[1], gen_helper_ljmp_protected(cpu_env, cpu_tmp2_i32, cpu_T[1],
tcg_const_i32(s->pc - pc_start)); tcg_const_tl(s->pc - s->cs_base));
} else { } else {
gen_op_movl_seg_T0_vm(R_CS); gen_op_movl_seg_T0_vm(R_CS);
gen_op_jmp_v(cpu_T[1]); gen_op_jmp_v(cpu_T[1]);
...@@ -5311,7 +5297,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -5311,7 +5297,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
goto illegal_op; goto illegal_op;
reg = b >> 3; reg = b >> 3;
ot = gen_pop_T0(s); ot = gen_pop_T0(s);
gen_movl_seg_T0(s, reg, pc_start - s->cs_base); gen_movl_seg_T0(s, reg);
gen_pop_update(s, ot); gen_pop_update(s, ot);
if (reg == R_SS) { if (reg == R_SS) {
/* if reg == SS, inhibit interrupts/trace. */ /* if reg == SS, inhibit interrupts/trace. */
...@@ -5329,7 +5315,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -5329,7 +5315,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 0x1a1: /* pop fs */ case 0x1a1: /* pop fs */
case 0x1a9: /* pop gs */ case 0x1a9: /* pop gs */
ot = gen_pop_T0(s); ot = gen_pop_T0(s);
gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); gen_movl_seg_T0(s, (b >> 3) & 7);
gen_pop_update(s, ot); gen_pop_update(s, ot);
if (s->is_jmp) { if (s->is_jmp) {
gen_jmp_im(s->pc - s->cs_base); gen_jmp_im(s->pc - s->cs_base);
...@@ -5380,7 +5366,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -5380,7 +5366,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (reg >= 6 || reg == R_CS) if (reg >= 6 || reg == R_CS)
goto illegal_op; goto illegal_op;
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_movl_seg_T0(s, reg, pc_start - s->cs_base); gen_movl_seg_T0(s, reg);
if (reg == R_SS) { if (reg == R_SS) {
/* if reg == SS, inhibit interrupts/trace */ /* if reg == SS, inhibit interrupts/trace */
/* If several instructions disable interrupts, only the /* If several instructions disable interrupts, only the
...@@ -5592,7 +5578,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -5592,7 +5578,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_add_A0_im(s, 1 << ot); gen_add_A0_im(s, 1 << ot);
/* load the segment first to handle exceptions properly */ /* load the segment first to handle exceptions properly */
gen_op_ld_v(s, MO_16, cpu_T[0], cpu_A0); gen_op_ld_v(s, MO_16, cpu_T[0], cpu_A0);
gen_movl_seg_T0(s, op, pc_start - s->cs_base); gen_movl_seg_T0(s, op);
/* then put the data */ /* then put the data */
gen_op_mov_reg_v(ot, reg, cpu_T[1]); gen_op_mov_reg_v(ot, reg, cpu_T[1]);
if (s->is_jmp) { if (s->is_jmp) {
...@@ -6410,8 +6396,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -6410,8 +6396,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
set_cc_op(s, CC_OP_EFLAGS); set_cc_op(s, CC_OP_EFLAGS);
} }
} else { } else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1), gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1),
tcg_const_i32(s->pc - s->cs_base)); tcg_const_i32(s->pc - s->cs_base));
set_cc_op(s, CC_OP_EFLAGS); set_cc_op(s, CC_OP_EFLAGS);
...@@ -7060,8 +7044,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -7060,8 +7044,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!s->pe) { if (!s->pe) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else { } else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_sysenter(cpu_env); gen_helper_sysenter(cpu_env);
gen_eob(s); gen_eob(s);
} }
...@@ -7073,8 +7055,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -7073,8 +7055,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!s->pe) { if (!s->pe) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else { } else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1)); gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1));
gen_eob(s); gen_eob(s);
} }
...@@ -7091,8 +7071,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -7091,8 +7071,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!s->pe) { if (!s->pe) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else { } else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1)); gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1));
/* condition codes are modified only in long mode */ /* condition codes are modified only in long mode */
if (s->lma) { if (s->lma) {
...@@ -7138,7 +7116,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -7138,7 +7116,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} else { } else {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE); gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_lldt(cpu_env, cpu_tmp2_i32); gen_helper_lldt(cpu_env, cpu_tmp2_i32);
} }
...@@ -7159,7 +7136,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, ...@@ -7159,7 +7136,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} else { } else {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE); gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
gen_helper_ltr(cpu_env, cpu_tmp2_i32); gen_helper_ltr(cpu_env, cpu_tmp2_i32);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册