On Sun, Jun 13, 2010 at 03:27:41PM +0300, Nadav Har'El wrote:
> This patch implements the VMPTRLD instruction.
>
> Signed-off-by: Nadav Har'El <[email protected]>
> ---
> --- .before/arch/x86/kvm/vmx.c 2010-06-13 15:01:29.000000000 +0300
> +++ .after/arch/x86/kvm/vmx.c 2010-06-13 15:01:29.000000000 +0300
> @@ -3829,6 +3829,26 @@ static int read_guest_vmcs_gpa(struct kv
> return 0;
> }
>
> +static void set_rflags_to_vmx_fail_invalid(struct kvm_vcpu *vcpu)
> +{
> + unsigned long rflags;
> + rflags = vmx_get_rflags(vcpu);
> + rflags |= X86_EFLAGS_CF;
> + rflags &= ~X86_EFLAGS_PF & ~X86_EFLAGS_AF & ~X86_EFLAGS_ZF &
> + ~X86_EFLAGS_SF & ~X86_EFLAGS_OF;
> + vmx_set_rflags(vcpu, rflags);
> +}
> +
> +static void set_rflags_to_vmx_fail_valid(struct kvm_vcpu *vcpu)
> +{
> + unsigned long rflags;
> + rflags = vmx_get_rflags(vcpu);
> + rflags |= X86_EFLAGS_ZF;
> + rflags &= ~X86_EFLAGS_PF & ~X86_EFLAGS_AF & ~X86_EFLAGS_CF &
> + ~X86_EFLAGS_SF & ~X86_EFLAGS_OF;
> + vmx_set_rflags(vcpu, rflags);
> +}
> +
> static void clear_rflags_cf_zf(struct kvm_vcpu *vcpu)
> {
> unsigned long rflags;
> @@ -3869,6 +3889,57 @@ static int handle_vmclear(struct kvm_vcp
> return 1;
> }
>
> +static bool verify_vmcs12_revision(struct kvm_vcpu *vcpu, gpa_t
> guest_vmcs_addr)
> +{
> + bool ret;
> + struct vmcs12 *vmcs12;
> + struct page *vmcs_page = nested_get_page(vcpu, guest_vmcs_addr);
> + if (vmcs_page == NULL)
> + return 0;
> + vmcs12 = (struct vmcs12 *)kmap_atomic(vmcs_page, KM_USER0);
> + if (vmcs12->revision_id == VMCS12_REVISION)
> + ret = 1;
> + else {
> + set_rflags_to_vmx_fail_valid(vcpu);
Should set VM-Instruction Error Field accordingly.
> + ret = 0;
> + }
> + kunmap_atomic(vmcs12, KM_USER0);
> + kvm_release_page_dirty(vmcs_page);
> + return ret;
> +}
> +
> +/* Emulate the VMPTRLD instruction */
> +static int handle_vmptrld(struct kvm_vcpu *vcpu)
> +{
> + struct vcpu_vmx *vmx = to_vmx(vcpu);
> + gpa_t guest_vmcs_addr;
> +
> + if (!nested_vmx_check_permission(vcpu))
> + return 1;
> +
> + if (read_guest_vmcs_gpa(vcpu, &guest_vmcs_addr)) {
> + set_rflags_to_vmx_fail_invalid(vcpu);
> + return 1;
> + }
> +
> + if (!verify_vmcs12_revision(vcpu, guest_vmcs_addr))
> + return 1;
Should check that guest_vmcs_addr != VMXON address. I think this check
is missing from VMCLEAR too.
> +
> + if (vmx->nested.current_vmptr != guest_vmcs_addr) {
> + vmx->nested.current_vmptr = guest_vmcs_addr;
> +
> + if (nested_create_current_vmcs(vcpu)) {
> + printk(KERN_ERR "%s error could not allocate memory",
> + __func__);
> + return -ENOMEM;
> + }
> + }
> +
> + clear_rflags_cf_zf(vcpu);
> + skip_emulated_instruction(vcpu);
> + return 1;
> +}
> +
> static int handle_invlpg(struct kvm_vcpu *vcpu)
> {
> unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
> @@ -4153,7 +4224,7 @@ static int (*kvm_vmx_exit_handlers[])(st
> [EXIT_REASON_VMCALL] = handle_vmcall,
> [EXIT_REASON_VMCLEAR] = handle_vmclear,
> [EXIT_REASON_VMLAUNCH] = handle_vmx_insn,
> - [EXIT_REASON_VMPTRLD] = handle_vmx_insn,
> + [EXIT_REASON_VMPTRLD] = handle_vmptrld,
> [EXIT_REASON_VMPTRST] = handle_vmx_insn,
> [EXIT_REASON_VMREAD] = handle_vmx_insn,
> [EXIT_REASON_VMRESUME] = handle_vmx_insn,
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html