aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-03-19 07:18:10 -0400
committerAvi Kivity <avi@qumranet.com>2007-03-27 11:54:38 -0400
commit6af11b9e827aac1d664ccd31e94f122c7698416b (patch)
tree469d01dce403c23a068d7f9e266d45b8ced80776 /drivers
parent703071b5b93d88d5acb0edd5b9dd86c69ad970f2 (diff)
KVM: Prevent system selectors leaking into guest on real->protected mode transition on vmx
Intel virtualization extensions do not support virtualizing real mode. So kvm uses virtualized vm86 mode to run real mode code. Unfortunately, this virtualized vm86 mode does not support the so called "big real" mode, where the segment selector and base do not agree with each other according to the real mode rules (base == selector << 4). To work around this, kvm checks whether a selector/base pair violates the virtualized vm86 rules, and if so, forces it into conformance. On a transition back to protected mode, if we see that the guest did not touch a forced segment, we restore it back to the original protected mode value. This pile of hacks breaks down if the gdt has changed in real mode, as it can cause a segment selector to point to a system descriptor instead of a normal data segment. In fact, this happens with the Windows bootloader and the qemu acpi bios, where a protected mode memcpy routine issues an innocent 'pop %es' and traps on an attempt to load a system descriptor. "Fix" by checking if the to-be-restored selector points at a system segment, and if so, coercing it into a normal data segment. The long term solution, of course, is to abandon vm86 mode and use emulation for big real mode. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/kvm/vmx.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index bfa0ce42ea92..25b247199224 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -618,7 +618,7 @@ static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
618{ 618{
619 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; 619 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
620 620
621 if (vmcs_readl(sf->base) == save->base) { 621 if (vmcs_readl(sf->base) == save->base && (save->base & AR_S_MASK)) {
622 vmcs_write16(sf->selector, save->selector); 622 vmcs_write16(sf->selector, save->selector);
623 vmcs_writel(sf->base, save->base); 623 vmcs_writel(sf->base, save->base);
624 vmcs_write32(sf->limit, save->limit); 624 vmcs_write32(sf->limit, save->limit);