From patchwork Sun Mar 6 12:42:38 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gleb Natapov X-Patchwork-Id: 613421 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p26CgnF6014370 for ; Sun, 6 Mar 2011 12:42:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751873Ab1CFMmm (ORCPT ); Sun, 6 Mar 2011 07:42:42 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53981 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751127Ab1CFMmm (ORCPT ); Sun, 6 Mar 2011 07:42:42 -0500 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p26Cgf2B031255 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sun, 6 Mar 2011 07:42:41 -0500 Received: from dhcp-1-237.tlv.redhat.com (dhcp-1-237.tlv.redhat.com [10.35.1.237]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p26Cgc4b014272; Sun, 6 Mar 2011 07:42:39 -0500 Received: by dhcp-1-237.tlv.redhat.com (Postfix, from userid 13519) id 4728B18D3E9; Sun, 6 Mar 2011 14:42:38 +0200 (IST) Date: Sun, 6 Mar 2011 14:42:38 +0200 From: Gleb Natapov To: Francis Moreau Cc: kvm@vger.kernel.org Subject: Re: 2.6.38-rc6: general protection error inside KVM 64 bits guest Message-ID: <20110306124238.GC25565@redhat.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sun, 06 Mar 2011 12:42:49 +0000 (UTC) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index 50ebc32..7ef5b86 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -142,10 +142,8 @@ struct x86_emulate_ops { int (*pio_out_emulated)(int size, unsigned short port, const void *val, unsigned int count, struct kvm_vcpu *vcpu); - bool (*get_cached_descriptor)(struct desc_struct *desc, - int seg, struct kvm_vcpu *vcpu); - void (*set_cached_descriptor)(struct desc_struct *desc, - int seg, struct kvm_vcpu *vcpu); + bool (*get_cached_descriptor)(void *p, int seg, struct kvm_vcpu *vcpu); + void (*set_cached_descriptor)(void *p, int seg, struct kvm_vcpu *vcpu); u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu); void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu); unsigned long (*get_cached_segment_base)(int seg, struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index ad46239..d7d8b63 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1764,25 +1764,35 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, u16 port, u16 len) { - struct desc_struct tr_seg; + union { + struct desc_struct tss32; +#ifdef CONFIG_X86_64 + struct ldttss_desc64 tss64; +#endif + } tr_seg; int r; u16 io_bitmap_ptr; u8 perm, bit_idx = port & 0x7; unsigned mask = (1 << len) - 1; + unsigned long base; ops->get_cached_descriptor(&tr_seg, VCPU_SREG_TR, ctxt->vcpu); - if (!tr_seg.p) + if (!tr_seg.tss32.p) return false; - if (desc_limit_scaled(&tr_seg) < 103) + if (desc_limit_scaled(&tr_seg.tss32) < 103) return false; - r = ops->read_std(get_desc_base(&tr_seg) + 102, &io_bitmap_ptr, 2, - ctxt->vcpu, NULL); + base = get_desc_base(&tr_seg.tss32); +#ifdef CONFIG_X86_64 + if (ctxt->mode == X86EMUL_MODE_PROT64) + base |= ((u64)tr_seg.tss64.base3) << 32; +#endif + r = ops->read_std(base + 102, &io_bitmap_ptr, 2, ctxt->vcpu, NULL); if (r != X86EMUL_CONTINUE) return false; - if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg)) + if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg.tss32)) return false; - r = ops->read_std(get_desc_base(&tr_seg) + io_bitmap_ptr + port/8, - &perm, 1, ctxt->vcpu, NULL); + r = ops->read_std(base + io_bitmap_ptr + port/8, &perm, 1, ctxt->vcpu, + NULL); if (r != X86EMUL_CONTINUE) return false; if ((perm >> bit_idx) & mask) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 785ae0c..e41e098 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4162,11 +4162,12 @@ static unsigned long emulator_get_cached_segment_base(int seg, return get_segment_base(vcpu, seg); } -static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg, +static bool emulator_get_cached_descriptor(void *p, int seg, struct kvm_vcpu *vcpu) { struct kvm_segment var; - + struct desc_struct *desc = p; + kvm_get_segment(vcpu, &var, seg); if (var.unusable) @@ -4185,13 +4186,22 @@ static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg, desc->d = var.db; desc->g = var.g; +#ifdef CONFIG_X86_64 + if (seg == VCPU_SREG_TR && is_long_mode(vcpu)) { + struct ldttss_desc64 *tss64 = p; + tss64->base3 = var.base >> 32; + tss64->zero1 = 0; + } +#endif + return true; } -static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg, +static void emulator_set_cached_descriptor(void *p, int seg, struct kvm_vcpu *vcpu) { struct kvm_segment var; + struct desc_struct *desc = p; /* needed to preserve selector */ kvm_get_segment(vcpu, &var, seg); @@ -4211,6 +4221,12 @@ static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg, var.present = desc->p; var.unusable = !var.present; var.padding = 0; +#ifdef CONFIG_X86_64 + if (seg == VCPU_SREG_TR && is_long_mode(vcpu)) { + struct ldttss_desc64 *tss64 = p; + var.base |= ((u64)tss64->base3) << 32; + } +#endif kvm_set_segment(vcpu, &var, seg); return;