On Wed, 2007-10-24 at 10:55 +0800, Yang, Sheng wrote:
> >From ac4dd1782b9f0f51e0c366a1b8db4515d6828df8 Mon Sep 17 00:00:00 2001
> From: Sheng Yang <[EMAIL PROTECTED]>
> Date: Tue, 23 Oct 2007 12:34:42 +0800
> Subject: [PATCH] Enable memory mapped TPR shadow(FlexPriority)
> 
> This patch based on CR8/TPR patch before, and enable the TPR
> shadow(FlexPriority) for 32bit Windows. Since TPR is accessed
> very frequently by 32bit Windows, especially SMP guest, with
> FlexPriority enabled, we saw significant performance gain.
> 
> BTW: The patch also using one memslot to get determined p2m
> relationship. But it's
> not elegant, which can be improved in the future.
> 
> Signed-off-by: Sheng Yang <[EMAIL PROTECTED]>
> ---
>  drivers/kvm/kvm.h         |    8 +++-
>  drivers/kvm/kvm_main.c    |   35 +++++++++++----
>  drivers/kvm/vmx.c         |  105
> +++++++++++++++++++++++++++++++++++++++++---
>  drivers/kvm/vmx.h         |    3 +
>  drivers/kvm/x86_emulate.c |   11 +++++
>  drivers/kvm/x86_emulate.h |    4 ++
>  6 files changed, 147 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
> index 08b5b21..0751f8e 100644
> --- a/drivers/kvm/kvm.h
> +++ b/drivers/kvm/kvm.h
> @@ -379,6 +379,7 @@ struct kvm {
>       struct kvm_pic *vpic;
>       struct kvm_ioapic *vioapic;
>       int round_robin_prev_vcpu;
> +     struct page *apic_access_page;
>  };
>  
>  static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
> @@ -503,6 +504,11 @@ void kvm_mmu_slot_remove_write_access(struct kvm
> *kvm, int slot);
>  void kvm_mmu_zap_all(struct kvm *kvm);
>  void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int
> kvm_nr_mmu_pages);
>  
> +int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
> +                               struct
> +                               kvm_userspace_memory_region *mem,
> +                               int user_alloc);
> +
>  hpa_t gpa_to_hpa(struct kvm *kvm, gpa_t gpa);
>  #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
>  #define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
> @@ -535,7 +541,7 @@ enum emulation_result {
>  };
>  
>  int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
> -                     unsigned long cr2, u16 error_code, int
> no_decode);
> +                     unsigned long cr2, u16 error_code, int
> cmd_type);
>  void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char
> *context);
>  void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long
> address);
>  void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long
> address);
> diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
> index 6f7b31e..afcd84b 100644
> --- a/drivers/kvm/kvm_main.c
> +++ b/drivers/kvm/kvm_main.c
> @@ -643,10 +643,10 @@ EXPORT_SYMBOL_GPL(fx_init);
>   *
>   * Discontiguous memory is allowed, mostly for framebuffers.
>   */
> -static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
> -                                       struct
> -                                       kvm_userspace_memory_region
> *mem,
> -                                       int user_alloc)
> +int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
> +                               struct
> +                               kvm_userspace_memory_region *mem,
> +                               int user_alloc)
>  {
>       int r;
>       gfn_t base_gfn;
> @@ -776,6 +776,7 @@ out_unlock:
>  out:
>       return r;
>  }
> +EXPORT_SYMBOL_GPL(kvm_vm_ioctl_set_memory_region);
>  
>  static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
>                                         u32 kvm_nr_mmu_pages)
> @@ -1252,14 +1253,21 @@ static int emulator_read_emulated(unsigned long
> addr,
>               memcpy(val, vcpu->mmio_data, bytes);
>               vcpu->mmio_read_completed = 0;
>               return X86EMUL_CONTINUE;
> -     } else if (emulator_read_std(addr, val, bytes, vcpu)
> -                == X86EMUL_CONTINUE)
> -             return X86EMUL_CONTINUE;
> +     }
>  
>       gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
> +
> +     /* For APIC access vmexit */
> +     if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
> +             goto mmio;
> +
> +     if (emulator_read_std(addr, val, bytes, vcpu)
> +                     == X86EMUL_CONTINUE)
> +             return X86EMUL_CONTINUE;
>       if (gpa == UNMAPPED_GVA)
>               return X86EMUL_PROPAGATE_FAULT;
>  
> +mmio:
>       /*
>        * Is this MMIO handled locally?
>        */
> @@ -1297,6 +1305,10 @@ static int
> emulator_write_emulated_onepage(unsigned long addr,
>       struct kvm_io_device *mmio_dev;
>       gpa_t                 gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
>  
> +     /* For APIC access vmexit */
> +     if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
> +             goto mmio;
> +
>       if (gpa == UNMAPPED_GVA) {
>               kvm_x86_ops->inject_page_fault(vcpu, addr, 2);
>               return X86EMUL_PROPAGATE_FAULT;
> @@ -1305,6 +1317,7 @@ static int
> emulator_write_emulated_onepage(unsigned long addr,
>       if (emulator_write_phys(vcpu, gpa, val, bytes))
>               return X86EMUL_CONTINUE;
>  
> +mmio:
>       /*
>        * Is this MMIO handled locally?
>        */
> @@ -1435,7 +1448,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
>                       struct kvm_run *run,
>                       unsigned long cr2,
>                       u16 error_code,
> -                     int no_decode)
> +                     int cmd_type)
>  {
>       int r;
>  
> @@ -1444,8 +1457,9 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
>  
>       vcpu->mmio_is_write = 0;
>       vcpu->pio.string = 0;
> +     vcpu->emulate_ctxt.cmd_type = cmd_type;
>  
> -     if (!no_decode) {
> +     if ((cmd_type & EMULCMD_NO_DECODE) == 0) {
>               int cs_db, cs_l;
>               kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
>  
> @@ -2262,7 +2276,8 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu
> *vcpu, struct kvm_run *kvm_run)
>               vcpu->mmio_read_completed = 1;
>               vcpu->mmio_needed = 0;
>               r = emulate_instruction(vcpu, kvm_run,
> -                                     vcpu->mmio_fault_cr2, 0, 1);
> +                                     vcpu->mmio_fault_cr2, 0,
> +                                     EMULCMD_NO_DECODE);
>               if (r == EMULATE_DO_MMIO) {
>                       /*
>                        * Read-modify-write.  Back to userspace.
> diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
> index 97814e4..d8155ee 100644
> --- a/drivers/kvm/vmx.c
> +++ b/drivers/kvm/vmx.c
> @@ -86,6 +86,7 @@ static struct vmcs_config {
>       u32 revision_id;
>       u32 pin_based_exec_ctrl;
>       u32 cpu_based_exec_ctrl;
> +     u32 cpu_based_2nd_exec_ctrl;
>       u32 vmexit_ctrl;
>       u32 vmentry_ctrl;
>  } vmcs_config;
> @@ -179,6 +180,29 @@ static inline int vm_need_tpr_shadow(struct kvm
> *kvm)
>       return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
>  }
>  
> +static inline int cpu_has_secondary_exec_ctrls(void)
> +{
> +     return (vmcs_config.cpu_based_exec_ctrl &
> +             CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
> +}
> +
> +static inline int vm_need_secondary_exec_ctrls(struct kvm *kvm)
> +{
> +     return ((cpu_has_secondary_exec_ctrls()) &&
> (irqchip_in_kernel(kvm)));
> +}
> +
> +static inline int cpu_has_vmx_virtualize_apic_accesses(void)
> +{
> +     return (vmcs_config.cpu_based_2nd_exec_ctrl &
> +             SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
> +}
> +
> +static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
> +{
> +     return ((cpu_has_vmx_virtualize_apic_accesses()) &&
> +             (irqchip_in_kernel(kvm)));
> +}
> +
>  static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
>  {
>       int i;
> @@ -916,6 +940,7 @@ static __init int setup_vmcs_config(struct
> vmcs_config *vmcs_conf)
>       u32 min, opt;
>       u32 _pin_based_exec_control = 0;
>       u32 _cpu_based_exec_control = 0;
> +     u32 _cpu_based_2nd_exec_control = 0;
>       u32 _vmexit_control = 0;
>       u32 _vmentry_control = 0;
>  
> @@ -933,11 +958,8 @@ static __init int setup_vmcs_config(struct
> vmcs_config *vmcs_conf)
>             CPU_BASED_USE_IO_BITMAPS |
>             CPU_BASED_MOV_DR_EXITING |
>             CPU_BASED_USE_TSC_OFFSETING;
> -#ifdef CONFIG_X86_64
> -     opt = CPU_BASED_TPR_SHADOW;
> -#else
> -     opt = 0;
> -#endif
> +     opt = CPU_BASED_TPR_SHADOW |
> +           CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
>       if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
>                               &_cpu_based_exec_control) < 0)
>               return -EIO;
> @@ -946,6 +968,18 @@ static __init int setup_vmcs_config(struct
> vmcs_config *vmcs_conf)
>               _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
>                                          ~CPU_BASED_CR8_STORE_EXITING;
>  #endif
> +     if (_cpu_based_exec_control &
> CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) {
> +             min = 0;
> +             opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
> +             if (adjust_vmx_controls(min, opt,
> MSR_IA32_VMX_PROCBASED_CTLS2,
> +                                     &_cpu_based_2nd_exec_control) <
> 0)
> +                     return -EIO;
> +     }
> +#ifndef CONFIG_X86_64
> +     if (!(_cpu_based_2nd_exec_control &
> +
> SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
> +             _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;
> +#endif
>  
>       min = 0;
>  #ifdef CONFIG_X86_64
> @@ -983,6 +1017,7 @@ static __init int setup_vmcs_config(struct
> vmcs_config *vmcs_conf)
>  
>       vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
>       vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
> +     vmcs_conf->cpu_based_2nd_exec_ctrl =
> _cpu_based_2nd_exec_control;
>       vmcs_conf->vmexit_ctrl         = _vmexit_control;
>       vmcs_conf->vmentry_ctrl        = _vmentry_control;
>  
> @@ -1421,6 +1456,26 @@ static void seg_setup(int seg)
>       vmcs_write32(sf->ar_bytes, 0x93);
>  }
>  
> +static int alloc_apic_access_page(struct kvm *kvm)
> +{
> +     struct kvm_userspace_memory_region kvm_userspace_mem;
> +     int r;
> +
> +     r = -EFAULT;
> +     /* Top memslot for apic access page */
> +     if (kvm->nmemslots == KVM_MEMORY_SLOTS)
> +             return r;
> +     kvm_userspace_mem.slot = kvm->nmemslots + 1;
> +     kvm_userspace_mem.flags = 0;
> +     kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL;
> +     kvm_userspace_mem.memory_size = PAGE_SIZE;
> +     r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
> +     if (r)
> +             return r;
> +     kvm->apic_access_page = gfn_to_page(kvm, 0xfee00);
> +     return 0;
> +}
> +
>  /*
>   * Sets up the vmcs for emulated real mode.
>   */
> @@ -1452,8 +1507,14 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
>                               CPU_BASED_CR8_LOAD_EXITING;
>  #endif
>       }
> +     if (!vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
> +             exec_control &= ~CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
>       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
>  
> +     if (vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
> +             vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
> +                          vmcs_config.cpu_based_2nd_exec_ctrl);
> +
>       vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf);
>       vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
>       vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
> @@ -1522,6 +1583,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
>       vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
>       vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
>  
> +     if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
> +             if (alloc_apic_access_page(vmx->vcpu.kvm) != 0)
> +                     return -ENOMEM;
> +
>       return 0;
>  }
>  
> @@ -1610,13 +1675,15 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
>  
>       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);  /* 22.2.1 */
>  
> -#ifdef CONFIG_X86_64
>       vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
>       if (vm_need_tpr_shadow(vmx->vcpu.kvm))
>               vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
>                            page_to_phys(vmx->vcpu.apic->regs_page));
>       vmcs_write32(TPR_THRESHOLD, 0);
> -#endif
> +
> +     if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
> +             vmcs_write64(APIC_ACCESS_ADDR,
> +
> page_to_phys(vmx->vcpu.kvm->apic_access_page));
>  
>       vmx->vcpu.cr0 = 0x60000010;
>       vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); /* enter rmode */
> @@ -2098,6 +2165,27 @@ static int handle_vmcall(struct kvm_vcpu *vcpu,
> struct kvm_run *kvm_run)
>       return 1;
>  }
>  
> +static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run
> *kvm_run)
> +{
> +     u64 exit_qualification;
> +     enum emulation_result er;
> +     unsigned long offset;
> +
> +     exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
> +     offset = exit_qualification & 0xffful;
> +
> +     er = emulate_instruction(vcpu, kvm_run, 0, 0,
> EMULCMD_DECODE_ADDR);
> +
> +     if (er !=  EMULATE_DONE) {
> +             printk(KERN_ERR
> +                    "Fail to handle apic access vmexit! Offset is
> 0x%lx\n",
> +                    offset);
> +             return -ENOTSUPP;
> +     }
> +     return 1;
> +}
> +
> +
>  /*
>   * The exit handlers return 1 if the exit was handled fully and guest
> execution
>   * may resume.  Otherwise they set the kvm_run parameter to indicate
> what needs
> @@ -2117,7 +2205,8 @@ static int (*kvm_vmx_exit_handlers[])(struct
> kvm_vcpu *vcpu,
>       [EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
>       [EXIT_REASON_HLT]                     = handle_halt,
>       [EXIT_REASON_VMCALL]                  = handle_vmcall,
> -     [EXIT_REASON_TPR_BELOW_THRESHOLD]     =
> handle_tpr_below_threshold
> +     [EXIT_REASON_TPR_BELOW_THRESHOLD]     =
> handle_tpr_below_threshold,
> +     [EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
>  };
>  
>  static const int kvm_vmx_max_exit_handlers =
> diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
> index 270d477..11d7341 100644
> --- a/drivers/kvm/vmx.h
> +++ b/drivers/kvm/vmx.h
> @@ -89,6 +89,8 @@ enum vmcs_field {
>       TSC_OFFSET_HIGH                 = 0x00002011,
>       VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
>       VIRTUAL_APIC_PAGE_ADDR_HIGH     = 0x00002013,
> +     APIC_ACCESS_ADDR                = 0x00002014,
> +     APIC_ACCESS_ADDR_HIGH           = 0x00002015,
>       VMCS_LINK_POINTER               = 0x00002800,
>       VMCS_LINK_POINTER_HIGH          = 0x00002801,
>       GUEST_IA32_DEBUGCTL             = 0x00002802,
> @@ -214,6 +216,7 @@ enum vmcs_field {
>  #define EXIT_REASON_MSR_WRITE           32
>  #define EXIT_REASON_MWAIT_INSTRUCTION   36
>  #define EXIT_REASON_TPR_BELOW_THRESHOLD 43
> +#define EXIT_REASON_APIC_ACCESS         44
>  
>  /*
>   * Interruption-information format
> diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
> index f858c01..d24166e 100644
> --- a/drivers/kvm/x86_emulate.c
> +++ b/drivers/kvm/x86_emulate.c
> @@ -845,6 +845,11 @@ modrm_done:
>                       c->src.type = OP_REG;
>                       break;
>               }
> +             if (((ctxt->cmd_type & EMULCMD_DECODE_ADDR) != 0) &&
> +                 (c->modrm_ea == 0)) {
> +                     ctxt->cr2 = insn_fetch(u32, c->src.bytes,
> c->eip);
> +                     c->eip -= c->src.bytes;
> +             }
>               c->src.type = OP_MEM;
>               break;
>       case SrcImm:
> @@ -906,6 +911,12 @@ modrm_done:
>               }
>               break;
>       case DstMem:
> +             c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
> +             if (((ctxt->cmd_type & EMULCMD_DECODE_ADDR) != 0) &&
> +                 (c->modrm_ea == 0)) {
> +                     ctxt->cr2 = insn_fetch(u32, c->dst.bytes,
> c->eip);
> +                     c->eip -= c->dst.bytes;
> +             }
>               /*
>                * For instructions with a ModR/M byte, switch to
> register
>                * access if Mod = 3.
> diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
> index f03b128..5185916 100644
> --- a/drivers/kvm/x86_emulate.h
> +++ b/drivers/kvm/x86_emulate.h
> @@ -153,6 +153,10 @@ struct x86_emulate_ctxt {
>       /* Emulated execution mode, represented by an X86EMUL_MODE
> value. */
>       int mode;
>  
> +#define EMULCMD_NO_DECODE   (1 << 0)
> +#define EMULCMD_DECODE_ADDR (1 << 1)
> +     int cmd_type;
> +
>       unsigned long cs_base;
>       unsigned long ds_base;
>       unsigned long es_base;
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Splunk Inc.
> Still grepping through log files to find problems?  Stop.
> Now Search log events and configuration files using AJAX and a browser.
> Download your FREE copy of Splunk now >> http://get.splunk.com/
> _______________________________________________ kvm-devel mailing list 
> kvm-devel@lists.sourceforge.net 
> https://lists.sourceforge.net/lists/listinfo/kvm-devel


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to