From mboxrd@z Thu Jan 1 00:00:00 1970 From: Avi Kivity Subject: Re: [PATCH 07/28] nVMX: Decoding memory operands of VMX instructions Date: Thu, 09 Dec 2010 13:08:37 +0200 Message-ID: <4D00B8B5.8070207@redhat.com> References: <1291827596-nyh@il.ibm.com> <201012081703.oB8H3XbJ008622@rice.haifa.ibm.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: kvm@vger.kernel.org, gleb@redhat.com To: "Nadav Har'El" Return-path: Received: from mx1.redhat.com ([209.132.183.28]:3514 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751082Ab0LILIz (ORCPT ); Thu, 9 Dec 2010 06:08:55 -0500 In-Reply-To: <201012081703.oB8H3XbJ008622@rice.haifa.ibm.com> Sender: kvm-owner@vger.kernel.org List-ID: On 12/08/2010 07:03 PM, Nadav Har'El wrote: > This patch includes a utility function for decoding pointer operands of VMX > instructions issued by L1 (a guest hypervisor) > > Signed-off-by: Nadav Har'El > --- > arch/x86/kvm/vmx.c | 59 +++++++++++++++++++++++++++++++++++++++++++ > arch/x86/kvm/x86.c | 3 +- > arch/x86/kvm/x86.h | 3 ++ > 3 files changed, 64 insertions(+), 1 deletion(-) > > --- .before/arch/x86/kvm/x86.c 2010-12-08 18:56:49.000000000 +0200 > +++ .after/arch/x86/kvm/x86.c 2010-12-08 18:56:49.000000000 +0200 > @@ -3688,7 +3688,7 @@ static int kvm_fetch_guest_virt(gva_t ad > exception); > } > > -static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes, > +int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes, > struct kvm_vcpu *vcpu, > struct x86_exception *exception) > { > @@ -3696,6 +3696,7 @@ static int kvm_read_guest_virt(gva_t add > return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, > exception); > } > +EXPORT_SYMBOL_GPL(kvm_read_guest_virt); > > static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes, > struct kvm_vcpu *vcpu, > --- .before/arch/x86/kvm/x86.h 2010-12-08 18:56:49.000000000 +0200 > +++ .after/arch/x86/kvm/x86.h 2010-12-08 18:56:49.000000000 +0200 > @@ -74,6 +74,9 @@ void kvm_before_handle_nmi(struct kvm_vc > void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); > int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq); > > +int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes, > + struct kvm_vcpu *vcpu, struct x86_exception *exception); > + > void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data); > > #endif > --- .before/arch/x86/kvm/vmx.c 2010-12-08 18:56:49.000000000 +0200 > +++ .after/arch/x86/kvm/vmx.c 2010-12-08 18:56:49.000000000 +0200 > @@ -3936,6 +3936,65 @@ static int handle_vmoff(struct kvm_vcpu > } > > /* > + * Decode the memory-address operand of a vmx instruction, as recorded on an > + * exit caused by such an instruction (run by a guest hypervisor). > + * On success, returns 0. When the operand is invalid, returns 1 and throws > + * #UD or #GP. > + */ > +static int get_vmx_mem_address(struct kvm_vcpu *vcpu, > + unsigned long exit_qualification, > + u32 vmx_instruction_info, gva_t *ret) > +{ > + /* > + * According to Vol. 3B, "Information for VM Exits Due to Instruction > + * Execution", on an exit, vmx_instruction_info holds most of the > + * addressing components of the operand. Only the displacement part > + * is put in exit_qualification (see 3B, "Basic VM-Exit Information"). > + * For how an actual address is calculated from all these components, > + * refer to Vol. 1, "Operand Addressing". > + */ > + int scaling = vmx_instruction_info& 3; > + int addr_size = (vmx_instruction_info>> 7)& 7; > + bool is_reg = vmx_instruction_info& (1u<< 10); > + int seg_reg = (vmx_instruction_info>> 15)& 7; > + int index_reg = (vmx_instruction_info>> 18)& 0xf; > + bool index_is_valid = !(vmx_instruction_info& (1u<< 22)); > + int base_reg = (vmx_instruction_info>> 23)& 0xf; > + bool base_is_valid = !(vmx_instruction_info& (1u<< 27)); > + > + if (is_reg) { > + kvm_queue_exception(vcpu, UD_VECTOR); > + return 1; > + } > + > + switch (addr_size) { > + case 1: /* 32 bit. high bits are undefined according to the spec: */ > + exit_qualification&= 0xffffffff; Best to do this at the end, on *ret, so that segment base + offset is subject to truncation. > + break; > + case 2: /* 64 bit */ > + break; > + default: /* 16 bit */ > + return 1; > + } > + > + /* Addr = segment_base + offset */ > + /* offset = base + [index * scale] + displacement */ > + *ret = vmx_get_segment_base(vcpu, seg_reg); > + if (base_is_valid) > + *ret += kvm_register_read(vcpu, base_reg); > + if (index_is_valid) > + *ret += kvm_register_read(vcpu, index_reg)< + *ret += exit_qualification; /* holds the displacement */ > + /* > + * TODO: throw #GP (and return 1) in various cases that the VM* > + * instructions require it - e.g., offset beyond segment limit, > + * unusable or unreadable/unwritable segment, non-canonical 64-bit > + * address, and so on. Currently these are not checked. > + */ > + return 0; > +} > + -- error compiling committee.c: too many arguments to function