If a guest happens to be unlucky enough to use an address such as 0xc0000000 in the CS base address field, the next attempt to VM enter will fail. This is because the vmcs_writel() that writes the base address into the VMCS will sign-extend the field to 64-bits, and the Intel manual states that bits 63:32 of this field *must* be 0. Use vmcs_write32() where appropriate. This fixes booting of an absolutely ancient Red Hat Linux 5.2 (not Enterprise Linux!) guest.
Signed-off-by: Chris Lalancette <clala...@redhat.com> --- arch/x86/kvm/vmx.c | 17 ++++++++++++++++- 1 files changed, 16 insertions(+), 1 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 364263a..311afd4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1846,7 +1846,22 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, vmx->rmode.tr.ar = vmx_segment_access_rights(var); return; } - vmcs_writel(sf->base, var->base); + + /* Intel 64 and IA-32 Architecture Software Developer's Manual Vol. 3b, + * section 22.3.1.2 states that VMENTRY will fail if bits 63:32 of the + * base address for CS, SS, DS, ES are not 0 and the register is usable. + * + * If var->base happens to have bit 31 set, then it will get sign + * extended on the vmcs_writel(), causing this check to fail. Make + * sure to use the 32-bit version where appropriate. + */ + if (sf->base == GUEST_CS_BASE || + ((~sf->ar_bytes & 0x00010000) && (sf->base == GUEST_SS_BASE || + sf->base == GUEST_DS_BASE || + sf->base == GUEST_ES_BASE))) + vmcs_write32(sf->base, var->base); + else + vmcs_writel(sf->base, var->base); vmcs_write32(sf->limit, var->limit); vmcs_write16(sf->selector, var->selector); if (vmx->rmode.vm86_active && var->s) { -- 1.6.0.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html