target/i386/tcg: save current task state before loading new one
This is how the steps are ordered in the manual. EFLAGS.NT is overwritten after the fact in the saved image. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8b13106508
commit
6a079f2e68
@ -389,6 +389,42 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector,
|
||||
access_prepare_mmu(&new, env, tss_base, tss_limit,
|
||||
MMU_DATA_LOAD, mmu_index, retaddr);
|
||||
|
||||
/* save the current state in the old TSS */
|
||||
old_eflags = cpu_compute_eflags(env);
|
||||
if (old_type & 8) {
|
||||
/* 32 bit */
|
||||
access_stl(&old, env->tr.base + 0x20, next_eip);
|
||||
access_stl(&old, env->tr.base + 0x24, old_eflags);
|
||||
access_stl(&old, env->tr.base + (0x28 + 0 * 4), env->regs[R_EAX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 1 * 4), env->regs[R_ECX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 2 * 4), env->regs[R_EDX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 3 * 4), env->regs[R_EBX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 4 * 4), env->regs[R_ESP]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 5 * 4), env->regs[R_EBP]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 6 * 4), env->regs[R_ESI]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 7 * 4), env->regs[R_EDI]);
|
||||
for (i = 0; i < 6; i++) {
|
||||
access_stw(&old, env->tr.base + (0x48 + i * 4),
|
||||
env->segs[i].selector);
|
||||
}
|
||||
} else {
|
||||
/* 16 bit */
|
||||
access_stw(&old, env->tr.base + 0x0e, next_eip);
|
||||
access_stw(&old, env->tr.base + 0x10, old_eflags);
|
||||
access_stw(&old, env->tr.base + (0x12 + 0 * 2), env->regs[R_EAX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 1 * 2), env->regs[R_ECX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 2 * 2), env->regs[R_EDX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 3 * 2), env->regs[R_EBX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 4 * 2), env->regs[R_ESP]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 5 * 2), env->regs[R_EBP]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 6 * 2), env->regs[R_ESI]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 7 * 2), env->regs[R_EDI]);
|
||||
for (i = 0; i < 4; i++) {
|
||||
access_stw(&old, env->tr.base + (0x22 + i * 2),
|
||||
env->segs[i].selector);
|
||||
}
|
||||
}
|
||||
|
||||
/* read all the registers from the new TSS */
|
||||
if (type & 8) {
|
||||
/* 32 bit */
|
||||
@ -428,49 +464,16 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector,
|
||||
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
|
||||
tss_set_busy(env, env->tr.selector, 0, retaddr);
|
||||
}
|
||||
old_eflags = cpu_compute_eflags(env);
|
||||
|
||||
if (source == SWITCH_TSS_IRET) {
|
||||
old_eflags &= ~NT_MASK;
|
||||
if (old_type & 8) {
|
||||
access_stl(&old, env->tr.base + 0x24, old_eflags);
|
||||
} else {
|
||||
access_stw(&old, env->tr.base + 0x10, old_eflags);
|
||||
}
|
||||
}
|
||||
|
||||
/* save the current state in the old TSS */
|
||||
if (old_type & 8) {
|
||||
/* 32 bit */
|
||||
access_stl(&old, env->tr.base + 0x20, next_eip);
|
||||
access_stl(&old, env->tr.base + 0x24, old_eflags);
|
||||
access_stl(&old, env->tr.base + (0x28 + 0 * 4), env->regs[R_EAX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 1 * 4), env->regs[R_ECX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 2 * 4), env->regs[R_EDX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 3 * 4), env->regs[R_EBX]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 4 * 4), env->regs[R_ESP]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 5 * 4), env->regs[R_EBP]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 6 * 4), env->regs[R_ESI]);
|
||||
access_stl(&old, env->tr.base + (0x28 + 7 * 4), env->regs[R_EDI]);
|
||||
for (i = 0; i < 6; i++) {
|
||||
access_stw(&old, env->tr.base + (0x48 + i * 4),
|
||||
env->segs[i].selector);
|
||||
}
|
||||
} else {
|
||||
/* 16 bit */
|
||||
access_stw(&old, env->tr.base + 0x0e, next_eip);
|
||||
access_stw(&old, env->tr.base + 0x10, old_eflags);
|
||||
access_stw(&old, env->tr.base + (0x12 + 0 * 2), env->regs[R_EAX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 1 * 2), env->regs[R_ECX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 2 * 2), env->regs[R_EDX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 3 * 2), env->regs[R_EBX]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 4 * 2), env->regs[R_ESP]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 5 * 2), env->regs[R_EBP]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 6 * 2), env->regs[R_ESI]);
|
||||
access_stw(&old, env->tr.base + (0x12 + 7 * 2), env->regs[R_EDI]);
|
||||
for (i = 0; i < 4; i++) {
|
||||
access_stw(&old, env->tr.base + (0x22 + i * 2),
|
||||
env->segs[i].selector);
|
||||
}
|
||||
}
|
||||
|
||||
/* now if an exception occurs, it will occurs in the next task
|
||||
context */
|
||||
|
||||
if (source == SWITCH_TSS_CALL) {
|
||||
/*
|
||||
* Thanks to the probe_access above, we know the first two
|
||||
@ -486,7 +489,9 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector,
|
||||
}
|
||||
|
||||
/* set the new CPU state */
|
||||
/* from this point, any exception which occurs can give problems */
|
||||
|
||||
/* now if an exception occurs, it will occur in the next task context */
|
||||
|
||||
env->cr[0] |= CR0_TS_MASK;
|
||||
env->hflags |= HF_TS_MASK;
|
||||
env->tr.selector = tss_selector;
|
||||
|
Loading…
x
Reference in New Issue
Block a user