aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorNadav Amit <namit@cs.technion.ac.il>2014-04-07 11:37:47 -0400
committerMarcelo Tosatti <mtosatti@redhat.com>2014-04-21 16:33:49 -0400
commit5c7411e2937401bf4d024744032f879475364996 (patch)
tree87ac6d52c47934288b919da6ea7aa618e4a297fb /arch/x86/kvm
parent68c3b4d1676d870f0453c31d5a52e7e65c7448ae (diff)
KVM: x86: Fix CR3 and LDT sel should not be saved in TSS
According to Intel specifications, only general purpose registers and segment selectors should be saved in the old TSS during 32-bit task-switch. Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 205b17eed93c..0dec502d20be 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2496,7 +2496,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
2496static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, 2496static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt,
2497 struct tss_segment_32 *tss) 2497 struct tss_segment_32 *tss)
2498{ 2498{
2499 tss->cr3 = ctxt->ops->get_cr(ctxt, 3); 2499 /* CR3 and ldt selector are not saved intentionally */
2500 tss->eip = ctxt->_eip; 2500 tss->eip = ctxt->_eip;
2501 tss->eflags = ctxt->eflags; 2501 tss->eflags = ctxt->eflags;
2502 tss->eax = reg_read(ctxt, VCPU_REGS_RAX); 2502 tss->eax = reg_read(ctxt, VCPU_REGS_RAX);
@@ -2514,7 +2514,6 @@ static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt,
2514 tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS); 2514 tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS);
2515 tss->fs = get_segment_selector(ctxt, VCPU_SREG_FS); 2515 tss->fs = get_segment_selector(ctxt, VCPU_SREG_FS);
2516 tss->gs = get_segment_selector(ctxt, VCPU_SREG_GS); 2516 tss->gs = get_segment_selector(ctxt, VCPU_SREG_GS);
2517 tss->ldt_selector = get_segment_selector(ctxt, VCPU_SREG_LDTR);
2518} 2517}
2519 2518
2520static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, 2519static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
@@ -2604,6 +2603,8 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
2604 struct tss_segment_32 tss_seg; 2603 struct tss_segment_32 tss_seg;
2605 int ret; 2604 int ret;
2606 u32 new_tss_base = get_desc_base(new_desc); 2605 u32 new_tss_base = get_desc_base(new_desc);
2606 u32 eip_offset = offsetof(struct tss_segment_32, eip);
2607 u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector);
2607 2608
2608 ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, 2609 ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
2609 &ctxt->exception); 2610 &ctxt->exception);
@@ -2613,8 +2614,9 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
2613 2614
2614 save_state_to_tss32(ctxt, &tss_seg); 2615 save_state_to_tss32(ctxt, &tss_seg);
2615 2616
2616 ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, 2617 /* Only GP registers and segment selectors are saved */
2617 &ctxt->exception); 2618 ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip,
2619 ldt_sel_offset - eip_offset, &ctxt->exception);
2618 if (ret != X86EMUL_CONTINUE) 2620 if (ret != X86EMUL_CONTINUE)
2619 /* FIXME: need to provide precise fault address */ 2621 /* FIXME: need to provide precise fault address */
2620 return ret; 2622 return ret;