* [patch 0/3] task switch fixes
@ 2008-07-19 22:08 Marcelo Tosatti
2008-07-19 22:08 ` [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field Marcelo Tosatti
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Marcelo Tosatti @ 2008-07-19 22:08 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm
Some more fixes for the task switch emulation.
> I think the problem is in seg_desct_to_kvm_desct() (besides the extra
> T's). It copies the limit from the descriptor directly to the kvm_segment
> structure.
You're right.
After fixing that 2003 Server task switches successfully to an EIP that
contains junk, a few UD's are injected and then a GP, which BSOD's
asking for a reboot.
All task switch state is valid, can't find anything that would generate
any exception. And even if it did, #GP and #TS are handled with a BSOD.
Xen has this special case for when the TSS's first 104 bytes cross a page
boundary (docs mention this should be avoided since processor uses the
physical addresses as base), but not the case with 2003.
XP sets CR3 with invalid bits. Xen simply resets the guest in that case,
KVM could do the same.
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field 2008-07-19 22:08 [patch 0/3] task switch fixes Marcelo Tosatti @ 2008-07-19 22:08 ` Marcelo Tosatti 2008-07-20 9:22 ` Avi Kivity 2008-07-19 22:08 ` [patch 2/3] KVM: task switch: check task busy state Marcelo Tosatti 2008-07-19 22:08 ` [patch 3/3] KVM: task switch: check for segment base translation failure Marcelo Tosatti 2 siblings, 1 reply; 8+ messages in thread From: Marcelo Tosatti @ 2008-07-19 22:08 UTC (permalink / raw) To: Avi Kivity; +Cc: kvm, Marcelo Tosatti [-- Attachment #1: vmx-seg-limti --] [-- Type: text/plain, Size: 995 bytes --] If 'g' is one then limit is 4kb granular. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Index: kvm-vmx-checks/arch/x86/kvm/x86.c =================================================================== --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c +++ kvm-vmx-checks/arch/x86/kvm/x86.c @@ -3195,6 +3195,10 @@ static void seg_desct_to_kvm_desct(struc kvm_desct->base |= seg_desc->base2 << 24; kvm_desct->limit = seg_desc->limit0; kvm_desct->limit |= seg_desc->limit << 16; + if (seg_desc->g) { + kvm_desct->limit <<= 12; + kvm_desct->limit |= 0xfff; + } kvm_desct->selector = selector; kvm_desct->type = seg_desc->type; kvm_desct->present = seg_desc->p; @@ -3222,8 +3226,12 @@ static void get_segment_descritptor_dtab if (kvm_seg.unusable) dtable->limit = 0; - else - dtable->limit = kvm_seg.limit; + else { + if (kvm_seg.g) + dtable->limit = kvm_seg.limit >> 12; + else + dtable->limit = kvm_seg.limit; + } dtable->base = kvm_seg.base; } else -- ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field 2008-07-19 22:08 ` [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field Marcelo Tosatti @ 2008-07-20 9:22 ` Avi Kivity 2008-07-20 16:43 ` Marcelo Tosatti 0 siblings, 1 reply; 8+ messages in thread From: Avi Kivity @ 2008-07-20 9:22 UTC (permalink / raw) To: Marcelo Tosatti; +Cc: kvm Marcelo Tosatti wrote: > If 'g' is one then limit is 4kb granular. > > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> > > Index: kvm-vmx-checks/arch/x86/kvm/x86.c > =================================================================== > --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c > +++ kvm-vmx-checks/arch/x86/kvm/x86.c > @@ -3195,6 +3195,10 @@ static void seg_desct_to_kvm_desct(struc > kvm_desct->base |= seg_desc->base2 << 24; > kvm_desct->limit = seg_desc->limit0; > kvm_desct->limit |= seg_desc->limit << 16; > + if (seg_desc->g) { > + kvm_desct->limit <<= 12; > + kvm_desct->limit |= 0xfff; > + } > kvm_desct->selector = selector; > kvm_desct->type = seg_desc->type; > kvm_desct->present = seg_desc->p; > This looks good, > @@ -3222,8 +3226,12 @@ static void get_segment_descritptor_dtab > > if (kvm_seg.unusable) > dtable->limit = 0; > - else > - dtable->limit = kvm_seg.limit; > + else { > + if (kvm_seg.g) > + dtable->limit = kvm_seg.limit >> 12; > + else > + dtable->limit = kvm_seg.limit; > + } > dtable->base = kvm_seg.base; > But this doesn't. As far as I can tell, users of get_segment_descritptor_dtable() expect a normalized limit (always in bytes). -- error compiling committee.c: too many arguments to function ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field 2008-07-20 9:22 ` Avi Kivity @ 2008-07-20 16:43 ` Marcelo Tosatti 2008-07-21 8:14 ` Avi Kivity 0 siblings, 1 reply; 8+ messages in thread From: Marcelo Tosatti @ 2008-07-20 16:43 UTC (permalink / raw) To: Avi Kivity; +Cc: kvm On Sun, Jul 20, 2008 at 12:22:07PM +0300, Avi Kivity wrote: > Marcelo Tosatti wrote: >> If 'g' is one then limit is 4kb granular. >> >> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> >> >> Index: kvm-vmx-checks/arch/x86/kvm/x86.c >> =================================================================== >> --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c >> +++ kvm-vmx-checks/arch/x86/kvm/x86.c >> @@ -3195,6 +3195,10 @@ static void seg_desct_to_kvm_desct(struc >> kvm_desct->base |= seg_desc->base2 << 24; >> kvm_desct->limit = seg_desc->limit0; >> kvm_desct->limit |= seg_desc->limit << 16; >> + if (seg_desc->g) { >> + kvm_desct->limit <<= 12; >> + kvm_desct->limit |= 0xfff; >> + } >> kvm_desct->selector = selector; >> kvm_desct->type = seg_desc->type; >> kvm_desct->present = seg_desc->p; >> > > This looks good, > >> @@ -3222,8 +3226,12 @@ static void get_segment_descritptor_dtab >> if (kvm_seg.unusable) >> dtable->limit = 0; >> - else >> - dtable->limit = kvm_seg.limit; >> + else { >> + if (kvm_seg.g) >> + dtable->limit = kvm_seg.limit >> 12; >> + else >> + dtable->limit = kvm_seg.limit; >> + } >> dtable->base = kvm_seg.base; >> > > But this doesn't. As far as I can tell, users of > get_segment_descritptor_dtable() expect a normalized limit (always in > bytes). Ouch, yes. Here's it: KVM: task switch: translate guest segment limit to virt-extension byte granular field If 'g' is one then limit is 4kb granular. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Index: kvm-vmx-checks/arch/x86/kvm/x86.c =================================================================== --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c +++ kvm-vmx-checks/arch/x86/kvm/x86.c @@ -3195,6 +3195,10 @@ static void seg_desct_to_kvm_desct(struc kvm_desct->base |= seg_desc->base2 << 24; kvm_desct->limit = seg_desc->limit0; kvm_desct->limit |= seg_desc->limit << 16; + if (seg_desc->g) { + kvm_desct->limit <<= 12; + kvm_desct->limit |= 0xfff; + } kvm_desct->selector = selector; kvm_desct->type = seg_desc->type; kvm_desct->present = seg_desc->p; ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field 2008-07-20 16:43 ` Marcelo Tosatti @ 2008-07-21 8:14 ` Avi Kivity 0 siblings, 0 replies; 8+ messages in thread From: Avi Kivity @ 2008-07-21 8:14 UTC (permalink / raw) To: Marcelo Tosatti; +Cc: kvm Marcelo Tosatti wrote: > On Sun, Jul 20, 2008 at 12:22:07PM +0300, Avi Kivity wrote: > >> Marcelo Tosatti wrote: >> >>> If 'g' is one then limit is 4kb granular. >>> >>> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> >>> >>> Index: kvm-vmx-checks/arch/x86/kvm/x86.c >>> =================================================================== >>> --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c >>> +++ kvm-vmx-checks/arch/x86/kvm/x86.c >>> @@ -3195,6 +3195,10 @@ static void seg_desct_to_kvm_desct(struc >>> kvm_desct->base |= seg_desc->base2 << 24; >>> kvm_desct->limit = seg_desc->limit0; >>> kvm_desct->limit |= seg_desc->limit << 16; >>> + if (seg_desc->g) { >>> + kvm_desct->limit <<= 12; >>> + kvm_desct->limit |= 0xfff; >>> + } >>> kvm_desct->selector = selector; >>> kvm_desct->type = seg_desc->type; >>> kvm_desct->present = seg_desc->p; >>> >>> >> This looks good, >> >> >>> @@ -3222,8 +3226,12 @@ static void get_segment_descritptor_dtab >>> if (kvm_seg.unusable) >>> dtable->limit = 0; >>> - else >>> - dtable->limit = kvm_seg.limit; >>> + else { >>> + if (kvm_seg.g) >>> + dtable->limit = kvm_seg.limit >> 12; >>> + else >>> + dtable->limit = kvm_seg.limit; >>> + } >>> dtable->base = kvm_seg.base; >>> >>> >> But this doesn't. As far as I can tell, users of >> get_segment_descritptor_dtable() expect a normalized limit (always in >> bytes). >> > > Ouch, yes. Here's it: > > > KVM: task switch: translate guest segment limit to virt-extension byte granular field > > If 'g' is one then limit is 4kb granular. > > I already merged this bit (I guess I forgot to ack); aren't you reading kvm-commits@? -- error compiling committee.c: too many arguments to function ^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 2/3] KVM: task switch: check task busy state 2008-07-19 22:08 [patch 0/3] task switch fixes Marcelo Tosatti 2008-07-19 22:08 ` [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field Marcelo Tosatti @ 2008-07-19 22:08 ` Marcelo Tosatti 2008-07-19 22:08 ` [patch 3/3] KVM: task switch: check for segment base translation failure Marcelo Tosatti 2 siblings, 0 replies; 8+ messages in thread From: Marcelo Tosatti @ 2008-07-19 22:08 UTC (permalink / raw) To: Avi Kivity; +Cc: kvm, Marcelo Tosatti [-- Attachment #1: task-switch-checks --] [-- Type: text/plain, Size: 1433 bytes --] Checks that the new task is available (call, jump, exception, or interrupt) or busy (IRET return). Generate GP# or TS# otherwise. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Index: kvm-vmx-checks/arch/x86/kvm/x86.c =================================================================== --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c +++ kvm-vmx-checks/arch/x86/kvm/x86.c @@ -3519,6 +3519,11 @@ int kvm_task_switch(struct kvm_vcpu *vcp if (load_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc)) goto out; + if (!nseg_desc.p || (nseg_desc.limit0 | nseg_desc.limit << 16) < 0x67) { + kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc); + return 1; + } + if (reason != TASK_SWITCH_IRET) { int cpl; @@ -3527,12 +3532,19 @@ int kvm_task_switch(struct kvm_vcpu *vcp kvm_queue_exception_e(vcpu, GP_VECTOR, 0); return 1; } + if (nseg_desc.type & (1 << 1)) { + kvm_queue_exception_e(vcpu, GP_VECTOR, + old_tss_sel & 0xfffc); + return 1; + } + } else { + if (!(cseg_desc.type & (1 << 1))) { + kvm_queue_exception_e(vcpu, TS_VECTOR, + tss_selector & 0xfffc); + return 1; + } } - if (!nseg_desc.p || (nseg_desc.limit0 | nseg_desc.limit << 16) < 0x67) { - kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc); - return 1; - } if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) { cseg_desc.type &= ~(1 << 1); //clear the B flag -- ^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch 3/3] KVM: task switch: check for segment base translation failure 2008-07-19 22:08 [patch 0/3] task switch fixes Marcelo Tosatti 2008-07-19 22:08 ` [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field Marcelo Tosatti 2008-07-19 22:08 ` [patch 2/3] KVM: task switch: check task busy state Marcelo Tosatti @ 2008-07-19 22:08 ` Marcelo Tosatti 2008-07-20 9:24 ` Avi Kivity 2 siblings, 1 reply; 8+ messages in thread From: Marcelo Tosatti @ 2008-07-19 22:08 UTC (permalink / raw) To: Avi Kivity; +Cc: kvm, Marcelo Tosatti [-- Attachment #1: task-switch-checks-2 --] [-- Type: text/plain, Size: 2768 bytes --] Subject says it all. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Index: kvm-vmx-checks/arch/x86/kvm/x86.c =================================================================== --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c +++ kvm-vmx-checks/arch/x86/kvm/x86.c @@ -3253,6 +3253,8 @@ static int load_guest_segment_descriptor return 1; } gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base); + if (gpa == UNMAPPED_GVA) + return 1; gpa += index * 8; return kvm_read_guest(vcpu->kvm, gpa, seg_desc, 8); } @@ -3270,11 +3272,13 @@ static int save_guest_segment_descriptor if (dtable.limit < index * 8 + 7) return 1; gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base); + if (gpa == UNMAPPED_GVA) + return 1; gpa += index * 8; return kvm_write_guest(vcpu->kvm, gpa, seg_desc, 8); } -static u32 get_tss_base_addr(struct kvm_vcpu *vcpu, +static gpa_t get_tss_base_addr(struct kvm_vcpu *vcpu, struct desc_struct *seg_desc) { u32 base_addr; @@ -3446,8 +3450,13 @@ static int kvm_task_switch_16(struct kvm struct desc_struct *nseg_desc) { struct tss_segment_16 tss_segment_16; + gpa_t tss_base; int ret = 0; + tss_base = get_tss_base_addr(vcpu, nseg_desc); + if (tss_base == UNMAPPED_GVA) + goto out; + if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_16, sizeof tss_segment_16)) goto out; @@ -3458,8 +3467,8 @@ static int kvm_task_switch_16(struct kvm sizeof tss_segment_16)) goto out; - if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc), - &tss_segment_16, sizeof tss_segment_16)) + if (kvm_read_guest(vcpu->kvm, tss_base, &tss_segment_16, + sizeof tss_segment_16)) goto out; if (load_state_from_tss16(vcpu, &tss_segment_16)) @@ -3475,8 +3484,13 @@ static int kvm_task_switch_32(struct kvm struct desc_struct *nseg_desc) { struct tss_segment_32 tss_segment_32; + gpa_t tss_base; int ret = 0; + tss_base = get_tss_base_addr(vcpu, nseg_desc); + if (tss_base == UNMAPPED_GVA) + goto out; + if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_32, sizeof tss_segment_32)) goto out; @@ -3487,7 +3501,7 @@ static int kvm_task_switch_32(struct kvm sizeof tss_segment_32)) goto out; - if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc), + if (kvm_read_guest(vcpu->kvm, tss_base, &tss_segment_32, sizeof tss_segment_32)) goto out; @@ -3509,6 +3523,8 @@ int kvm_task_switch(struct kvm_vcpu *vcp u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR); old_tss_base = vcpu->arch.mmu.gva_to_gpa(vcpu, old_tss_base); + if (old_tss_base == UNMAPPED_GVA) + return 1; /* FIXME: Handle errors. Failure to read either TSS or their * descriptors should generate a pagefault. -- ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch 3/3] KVM: task switch: check for segment base translation failure 2008-07-19 22:08 ` [patch 3/3] KVM: task switch: check for segment base translation failure Marcelo Tosatti @ 2008-07-20 9:24 ` Avi Kivity 0 siblings, 0 replies; 8+ messages in thread From: Avi Kivity @ 2008-07-20 9:24 UTC (permalink / raw) To: Marcelo Tosatti; +Cc: kvm Marcelo Tosatti wrote: > Subject says it all. > > Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> > > Index: kvm-vmx-checks/arch/x86/kvm/x86.c > =================================================================== > --- kvm-vmx-checks.orig/arch/x86/kvm/x86.c > +++ kvm-vmx-checks/arch/x86/kvm/x86.c > @@ -3253,6 +3253,8 @@ static int load_guest_segment_descriptor > return 1; > } > gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base); > + if (gpa == UNMAPPED_GVA) > + return 1; > gpa += index * 8; > return kvm_read_guest(vcpu->kvm, gpa, seg_desc, 8); > } > This is wrong; if the descriptor table is long enough, the first page could be unmapped but the page(s) containing the segment could be mapped (and nothing guarantees the mapping is contiguous). We need to translate dtable.base + index * 8. What we really need is kvm_read_guest_virt() to take care of all of these things. The emulator callbacks come fairly close. -- error compiling committee.c: too many arguments to function ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-07-21 8:14 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-07-19 22:08 [patch 0/3] task switch fixes Marcelo Tosatti 2008-07-19 22:08 ` [patch 1/3] KVM: task switch: translate guest segment limit to virt-extension byte granular field Marcelo Tosatti 2008-07-20 9:22 ` Avi Kivity 2008-07-20 16:43 ` Marcelo Tosatti 2008-07-21 8:14 ` Avi Kivity 2008-07-19 22:08 ` [patch 2/3] KVM: task switch: check task busy state Marcelo Tosatti 2008-07-19 22:08 ` [patch 3/3] KVM: task switch: check for segment base translation failure Marcelo Tosatti 2008-07-20 9:24 ` Avi Kivity
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox