xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] svm: support VMCB cleanbits
@ 2010-12-15 10:52 Christoph Egger
  2010-12-15 11:27 ` Tim Deegan
  0 siblings, 1 reply; 6+ messages in thread
From: Christoph Egger @ 2010-12-15 10:52 UTC (permalink / raw)
  To: xen-devel@lists.xensource.com

[-- Attachment #1: Type: text/plain, Size: 804 bytes --]

 
Hi,

Attached patch implements the VMCB cleanbits   SVM feature.
Upcoming AMD CPUs introduce them and they are basically hints
for the CPU which vmcb values can be re-used from the previous
VMRUN instruction.

Each bit represents a certain set of fields in the VMCB.
Setting a bit tells the cpu it can re-use the cached value
from the previous VMRUN.
Clearing a bit tells the cpu to reload the values from the given VMCB.

Signed-off-by: Wei Huang <Wei.Huang2@amd.com>
Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>

Christoph


-- 
---to satisfy European Law for business letters:
Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach b. Muenchen
Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd
Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632

[-- Attachment #2: xen_vmcbcleanbits.diff --]
[-- Type: text/x-diff, Size: 31888 bytes --]

# HG changeset patch
# User cegger
# Date 1292410191 -3600
vmcb cleanbits

diff -r e31f18fff54c -r be72873a6f30 xen/arch/x86/hvm/svm/Makefile
--- a/xen/arch/x86/hvm/svm/Makefile
+++ b/xen/arch/x86/hvm/svm/Makefile
@@ -3,5 +3,6 @@ obj-y += emulate.o
 obj-y += entry.o
 obj-y += intr.o
 obj-y += svm.o
+obj-y += svmcleanbits.o
 obj-y += vmcb.o
 obj-y += vpmu.o
diff -r e31f18fff54c -r be72873a6f30 xen/arch/x86/hvm/svm/asid.c
--- a/xen/arch/x86/hvm/svm/asid.c
+++ b/xen/arch/x86/hvm/svm/asid.c
@@ -21,6 +21,7 @@
 #include <xen/lib.h>
 #include <xen/perfc.h>
 #include <asm/hvm/svm/asid.h>
+#include <asm/hvm/svm/svmcleanbits.h>
 #include <asm/amd.h>
 
 void svm_asid_init(struct cpuinfo_x86 *c)
@@ -41,18 +42,19 @@ void svm_asid_init(struct cpuinfo_x86 *c
 asmlinkage void svm_asid_handle_vmrun(void)
 {
     struct vcpu *curr = current;
+    struct vmcb_struct *vmcb = curr->arch.hvm_svm.vmcb;
     bool_t need_flush = hvm_asid_handle_vmenter();
 
     /* ASID 0 indicates that ASIDs are disabled. */
     if ( curr->arch.hvm_vcpu.asid == 0 )
     {
-        curr->arch.hvm_svm.vmcb->guest_asid  = 1;
-        curr->arch.hvm_svm.vmcb->tlb_control = 1;
+        svm_set_asid(vmcb, 1);
+        vmcb->tlb_control = 1;
         return;
     }
 
-    curr->arch.hvm_svm.vmcb->guest_asid  = curr->arch.hvm_vcpu.asid;
-    curr->arch.hvm_svm.vmcb->tlb_control = need_flush;
+    svm_set_asid(vmcb, curr->arch.hvm_vcpu.asid);
+    vmcb->tlb_control = need_flush;
 }
 
 /*
diff -r e31f18fff54c -r be72873a6f30 xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c
+++ b/xen/arch/x86/hvm/svm/intr.c
@@ -32,6 +32,7 @@
 #include <asm/hvm/support.h>
 #include <asm/hvm/vlapic.h>
 #include <asm/hvm/svm/svm.h>
+#include <asm/hvm/svm/svmcleanbits.h>
 #include <asm/hvm/svm/intr.h>
 #include <xen/event.h>
 #include <xen/kernel.h>
@@ -56,7 +57,7 @@ static void svm_inject_nmi(struct vcpu *
      * SVM does not virtualise the NMI mask, so we emulate it by intercepting
      * the next IRET and blocking NMI injection until the intercept triggers.
      */
-    vmcb->general1_intercepts |= GENERAL1_INTERCEPT_IRET;
+    svm_set_general1_intercept(vmcb, GENERAL1_INTERCEPT_IRET);
 }
     
 static void svm_inject_extint(struct vcpu *v, int vector)
@@ -108,8 +109,8 @@ static void enable_intr_window(struct vc
     intr.fields.vector  = 0;
     intr.fields.prio    = intack.vector >> 4;
     intr.fields.ign_tpr = (intack.source != hvm_intsrc_lapic);
-    vmcb->vintr = intr;
-    vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
+    svm_set_vintr(vmcb, vintr, intr);
+    svm_set_general1_intercept(vmcb, GENERAL1_INTERCEPT_VINTR);
 }
 
 asmlinkage void svm_intr_assist(void) 
diff -r e31f18fff54c -r be72873a6f30 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -46,6 +46,7 @@
 #include <asm/hvm/emulate.h>
 #include <asm/hvm/svm/asid.h>
 #include <asm/hvm/svm/svm.h>
+#include <asm/hvm/svm/svmcleanbits.h>
 #include <asm/hvm/svm/vmcb.h>
 #include <asm/hvm/svm/emulate.h>
 #include <asm/hvm/svm/intr.h>
@@ -115,7 +116,7 @@ static void svm_save_dr(struct vcpu *v)
 
     /* Clear the DR dirty flag and re-enable intercepts for DR accesses. */
     v->arch.hvm_vcpu.flag_dr_dirty = 0;
-    v->arch.hvm_svm.vmcb->dr_intercepts = ~0u;
+    svm_set_dr(vmcb, ~0u);
 
     v->arch.guest_context.debugreg[0] = read_debugreg(0);
     v->arch.guest_context.debugreg[1] = read_debugreg(1);
@@ -133,14 +134,14 @@ static void __restore_debug_registers(st
         return;
 
     v->arch.hvm_vcpu.flag_dr_dirty = 1;
-    vmcb->dr_intercepts = 0;
+    svm_set_dr(vmcb, 0);
 
     write_debugreg(0, v->arch.guest_context.debugreg[0]);
     write_debugreg(1, v->arch.guest_context.debugreg[1]);
     write_debugreg(2, v->arch.guest_context.debugreg[2]);
     write_debugreg(3, v->arch.guest_context.debugreg[3]);
-    vmcb->dr6 = v->arch.guest_context.debugreg[6];
-    vmcb->dr7 = v->arch.guest_context.debugreg[7];
+    svm_set_dr6(vmcb, v->arch.guest_context.debugreg[6]);
+    svm_set_dr7(vmcb, v->arch.guest_context.debugreg[7]);
 }
 
 /*
@@ -229,11 +230,8 @@ static int svm_vmcb_restore(struct vcpu 
     v->arch.hvm_svm.guest_sysenter_eip = c->sysenter_eip;
 
     if ( paging_mode_hap(v->domain) )
-    {
-        vmcb->np_enable = 1;
-        vmcb->g_pat = MSR_IA32_CR_PAT_RESET; /* guest PAT */
-        vmcb->h_cr3 = pagetable_get_paddr(p2m_get_pagetable(p2m));
-    }
+        svm_set_nested_paging(vmcb, 1, MSR_IA32_CR_PAT_RESET, 
+                              pagetable_get_paddr(p2m_get_pagetable(p2m)));
 
     if ( c->pending_valid ) 
     {
@@ -247,6 +245,7 @@ static int svm_vmcb_restore(struct vcpu 
         }
     }
 
+    vmcb->cleanbits.bytes = 0;
     paging_update_paging_modes(v);
 
     return 0;
@@ -307,7 +306,7 @@ static void svm_fpu_enter(struct vcpu *v
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
 
     setup_fpu(v);
-    vmcb->exception_intercepts &= ~(1U << TRAP_no_device);
+    svm_clear_exception_intercept(vmcb, TRAP_no_device);
 }
 
 static void svm_fpu_leave(struct vcpu *v)
@@ -325,8 +324,8 @@ static void svm_fpu_leave(struct vcpu *v
      */
     if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
     {
-        v->arch.hvm_svm.vmcb->exception_intercepts |= 1U << TRAP_no_device;
-        vmcb->cr0 |= X86_CR0_TS;
+        svm_set_cr0(vmcb, vmcb->cr0 | X86_CR0_TS);
+        svm_set_exception_intercept(vmcb, TRAP_no_device);
     }
 }
 
@@ -351,9 +350,8 @@ static void svm_set_interrupt_shadow(str
     vmcb->interrupt_shadow =
         !!(intr_shadow & (HVM_INTR_SHADOW_MOV_SS|HVM_INTR_SHADOW_STI));
 
-    vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_IRET;
-    if ( intr_shadow & HVM_INTR_SHADOW_NMI )
-        vmcb->general1_intercepts |= GENERAL1_INTERCEPT_IRET;
+    svm_general1_intercept(vmcb, GENERAL1_INTERCEPT_IRET,
+        (intr_shadow & HVM_INTR_SHADOW_NMI));
 }
 
 static int svm_guest_x86_mode(struct vcpu *v)
@@ -377,6 +375,7 @@ static void svm_update_host_cr3(struct v
 static void svm_update_guest_cr(struct vcpu *v, unsigned int cr)
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+    uint64_t value;
 
     switch ( cr )
     {
@@ -391,23 +390,25 @@ static void svm_update_guest_cr(struct v
                 svm_fpu_enter(v);
         }
 
-        vmcb->cr0 = v->arch.hvm_vcpu.guest_cr[0] | hw_cr0_mask;
+        value = v->arch.hvm_vcpu.guest_cr[0] | hw_cr0_mask;
         if ( !paging_mode_hap(v->domain) )
-            vmcb->cr0 |= X86_CR0_PG | X86_CR0_WP;
+            value |= X86_CR0_PG | X86_CR0_WP;
+        svm_set_cr0(vmcb, value);
         break;
     }
     case 2:
-        vmcb->cr2 = v->arch.hvm_vcpu.guest_cr[2];
+        svm_set_cr2(vmcb, v->arch.hvm_vcpu.guest_cr[2]);
         break;
     case 3:
-        vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3];
+        svm_set_cr3(vmcb, v->arch.hvm_vcpu.hw_cr[3]);
         hvm_asid_flush_vcpu(v);
         break;
     case 4:
-        vmcb->cr4 = HVM_CR4_HOST_MASK;
+        value = HVM_CR4_HOST_MASK;
         if ( paging_mode_hap(v->domain) )
-            vmcb->cr4 &= ~X86_CR4_PAE;
-        vmcb->cr4 |= v->arch.hvm_vcpu.guest_cr[4];
+            value &= ~X86_CR4_PAE;
+        value |= v->arch.hvm_vcpu.guest_cr[4];
+        svm_set_cr4(vmcb, value);
         break;
     default:
         BUG();
@@ -418,10 +419,12 @@ static void svm_update_guest_efer(struct
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     bool_t lma = !!(v->arch.hvm_vcpu.guest_efer & EFER_LMA);
+    uint64_t new_efer;
 
-    vmcb->efer = (v->arch.hvm_vcpu.guest_efer | EFER_SVME) & ~EFER_LME;
+    new_efer = (v->arch.hvm_vcpu.guest_efer | EFER_SVME) & ~EFER_LME;
     if ( lma )
-        vmcb->efer |= EFER_LME;
+        new_efer |= EFER_LME;
+    svm_set_efer(vmcb, new_efer);
 
     /*
      * In legacy mode (EFER.LMA=0) we natively support SYSENTER/SYSEXIT with
@@ -515,6 +518,12 @@ static void svm_set_segment_register(str
 
     switch ( seg )
     {
+    case x86_seg_cs:
+    case x86_seg_ds:
+    case x86_seg_es:
+    case x86_seg_ss: /* cpl */
+        vmcb->cleanbits.fields.seg = 0;
+        break;
     case x86_seg_fs:
     case x86_seg_gs:
     case x86_seg_tr:
@@ -553,12 +562,10 @@ static void svm_set_segment_register(str
         memcpy(&vmcb->tr, reg, sizeof(*reg));
         break;
     case x86_seg_gdtr:
-        vmcb->gdtr.base = reg->base;
-        vmcb->gdtr.limit = (uint16_t)reg->limit;
+        svm_set_gdt(vmcb, reg->base, reg->limit);
         break;
     case x86_seg_idtr:
-        vmcb->idtr.base = reg->base;
-        vmcb->idtr.limit = (uint16_t)reg->limit;
+        svm_set_idt(vmcb, reg->base, reg->limit);
         break;
     case x86_seg_ldtr:
         memcpy(&vmcb->ldtr, reg, sizeof(*reg));
@@ -571,17 +578,19 @@ static void svm_set_segment_register(str
         svm_vmload(vmcb);
 }
 
-static void svm_set_tsc_offset(struct vcpu *v, u64 offset)
+static void svm_set_tsc_offset(struct vcpu *v, uint64_t offset)
 {
-    v->arch.hvm_svm.vmcb->tsc_offset = offset;
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    vmcb->tsc_offset = offset;
+    vmcb->cleanbits.fields.intercepts = 0;
 }
 
 static void svm_set_rdtsc_exiting(struct vcpu *v, bool_t enable)
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-    vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_RDTSC;
-    if ( enable )
-        vmcb->general1_intercepts |= GENERAL1_INTERCEPT_RDTSC;
+
+    svm_general1_intercept(vmcb, GENERAL1_INTERCEPT_RDTSC, enable);
 }
 
 static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
@@ -626,6 +635,7 @@ static void svm_ctxt_switch_from(struct 
 
 static void svm_ctxt_switch_to(struct vcpu *v)
 {
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     int cpu = smp_processor_id();
 
 #ifdef  __x86_64__
@@ -651,7 +661,8 @@ static void svm_ctxt_switch_to(struct vc
     svm_restore_dr(v);
 
     svm_vmsave(per_cpu(root_vmcb, cpu));
-    svm_vmload(v->arch.hvm_svm.vmcb);
+    svm_vmload(vmcb);
+    vmcb->cleanbits.bytes = 0;
     vpmu_load(v);
 
     if ( cpu_has_rdtscp )
@@ -660,16 +671,17 @@ static void svm_ctxt_switch_to(struct vc
 
 static void svm_do_resume(struct vcpu *v) 
 {
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     bool_t debug_state = v->domain->debugger_attached;
 
     if ( unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
-        uint32_t mask = (1U << TRAP_debug) | (1U << TRAP_int3);
         v->arch.hvm_vcpu.debug_state_latch = debug_state;
         if ( debug_state )
-            v->arch.hvm_svm.vmcb->exception_intercepts |= mask;
-        else
-            v->arch.hvm_svm.vmcb->exception_intercepts &= ~mask;
+        {
+            svm_set_exception_intercept(vmcb, TRAP_debug);
+            svm_set_exception_intercept(vmcb, TRAP_int3);
+        }
     }
 
     if ( v->arch.hvm_svm.launch_core != smp_processor_id() )
@@ -682,8 +694,8 @@ static void svm_do_resume(struct vcpu *v
     }
 
     /* Reflect the vlapic's TPR in the hardware vtpr */
-    v->arch.hvm_svm.vmcb->vintr.fields.tpr = 
-        (vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xFF) >> 4;
+    svm_set_vintr(vmcb, vintr.fields.tpr,
+        (vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xFF) >> 4);
 
     hvm_do_resume(v);
     reset_stack_and_jump(svm_asm_do_resume);
@@ -740,7 +752,7 @@ static void svm_inject_exception(
         if ( guest_cpu_user_regs()->eflags & X86_EFLAGS_TF )
         {
             __restore_debug_registers(curr);
-            vmcb->dr6 |= 0x4000;
+            svm_set_dr6(vmcb, 0x4000);
         }
     case TRAP_int3:
         if ( curr->domain->debugger_attached )
@@ -770,7 +782,8 @@ static void svm_inject_exception(
 
     if ( trapnr == TRAP_page_fault )
     {
-        vmcb->cr2 = curr->arch.hvm_vcpu.guest_cr[2] = cr2;
+        curr->arch.hvm_vcpu.guest_cr[2] = cr2;
+        svm_set_cr2(vmcb, cr2);
         HVMTRACE_LONG_2D(PF_INJECT, errcode, TRC_PAR_LONG(cr2));
     }
     else
@@ -858,6 +871,10 @@ static int svm_cpu_up(void)
     /* Initialize core's ASID handling. */
     svm_asid_init(c);
 
+    if ( cpu_has_svm_cleanbits )
+        /* The real enablement happens in svm_vmexit_handler() */
+        printk("VMCB cleanbits: Enable mask = 0x%x\n", SVMCLEANBITS_INIT);
+
 #ifdef __x86_64__
     /*
      * Check whether EFER.LMSLE can be written.
@@ -950,7 +967,7 @@ static void svm_fpu_dirty_intercept(void
     svm_fpu_enter(curr);
 
     if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
-        vmcb->cr0 &= ~X86_CR0_TS;
+        svm_set_cr0(vmcb, vmcb->cr0 & ~X86_CR0_TS);
 }
 
 #define bitmaskof(idx)  (1U << ((idx) & 31))
@@ -1115,28 +1132,28 @@ static int svm_msr_write_intercept(unsig
         vmcb->debugctlmsr = msr_content;
         if ( !msr_content || !cpu_has_svm_lbrv )
             break;
-        vmcb->lbr_control.fields.enable = 1;
-        svm_disable_intercept_for_msr(v, MSR_IA32_DEBUGCTLMSR);
-        svm_disable_intercept_for_msr(v, MSR_IA32_LASTBRANCHFROMIP);
-        svm_disable_intercept_for_msr(v, MSR_IA32_LASTBRANCHTOIP);
-        svm_disable_intercept_for_msr(v, MSR_IA32_LASTINTFROMIP);
-        svm_disable_intercept_for_msr(v, MSR_IA32_LASTINTTOIP);
+        svm_set_lbr(vmcb, lbr_control.fields.enable, 1);
+        svm_clear_msr_intercept(v, MSR_IA32_DEBUGCTLMSR);
+        svm_clear_msr_intercept(v, MSR_IA32_LASTBRANCHFROMIP);
+        svm_clear_msr_intercept(v, MSR_IA32_LASTBRANCHTOIP);
+        svm_clear_msr_intercept(v, MSR_IA32_LASTINTFROMIP);
+        svm_clear_msr_intercept(v, MSR_IA32_LASTINTTOIP);
         break;
 
     case MSR_IA32_LASTBRANCHFROMIP:
-        vmcb->lastbranchfromip = msr_content;
+        svm_set_lbr(vmcb, lastbranchfromip, msr_content);
         break;
 
     case MSR_IA32_LASTBRANCHTOIP:
-        vmcb->lastbranchtoip = msr_content;
+        svm_set_lbr(vmcb, lastbranchtoip, msr_content);
         break;
 
     case MSR_IA32_LASTINTFROMIP:
-        vmcb->lastintfromip = msr_content;
+        svm_set_lbr(vmcb, lastintfromip, msr_content);
         break;
 
     case MSR_IA32_LASTINTTOIP:
-        vmcb->lastinttoip = msr_content;
+        svm_set_lbr(vmcb, lastinttoip, msr_content);
         break;
 
     case MSR_K7_PERFCTR0:
@@ -1415,6 +1432,11 @@ asmlinkage void svm_vmexit_handler(struc
 
     hvm_maybe_deassert_evtchn_irq();
 
+    if ( cpu_has_svm_cleanbits )
+        vmcb->cleanbits.bytes = SVMCLEANBITS_INIT;
+    else
+        vmcb->cleanbits.bytes = 0;
+
     /* Event delivery caused this intercept? Queue for redelivery. */
     eventinj = vmcb->exitintinfo;
     if ( unlikely(eventinj.fields.v) &&
@@ -1496,8 +1518,8 @@ asmlinkage void svm_vmexit_handler(struc
         break;
 
     case VMEXIT_VINTR:
-        vmcb->vintr.fields.irq = 0;
-        vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_VINTR;
+        svm_set_vintr(vmcb, vintr.fields.irq, 0);
+        svm_clear_general1_intercept(vmcb, GENERAL1_INTERCEPT_VINTR);
         break;
 
     case VMEXIT_INVD:
@@ -1622,8 +1644,8 @@ asmlinkage void svm_vmexit_handler(struc
          * may inject an NMI before the NMI handler's IRET instruction is
          * retired.
          */
-        vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_IRET;
         vmcb->interrupt_shadow = 1;
+        svm_clear_general1_intercept(vmcb, GENERAL1_INTERCEPT_IRET);
         break;
 
     case VMEXIT_PAUSE:
@@ -1641,8 +1663,8 @@ asmlinkage void svm_vmexit_handler(struc
     }
 
     /* The exit may have updated the TPR: reflect this in the hardware vtpr */
-    vmcb->vintr.fields.tpr = 
-        (vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xFF) >> 4;
+    svm_set_vintr(vmcb, vintr.fields.tpr,
+        (vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xFF) >> 4);
 }
 
 asmlinkage void svm_trace_vmentry(void)
diff -r e31f18fff54c -r be72873a6f30 xen/arch/x86/hvm/svm/svmcleanbits.c
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/svmcleanbits.c
@@ -0,0 +1,57 @@
+/*
+ * svmcleanbits.c: VMCB cleanbits management
+ * Copyright (c) 2010, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <asm/hvm/svm/svm.h>
+#include <asm/hvm/svm/svmcleanbits.h>
+
+/* VMCB MSR bitmap */
+void
+svm_intercept_msr(struct vcpu *v, uint32_t msr, bool_t enabled)
+{
+    unsigned long *msr_bitmap = v->arch.hvm_svm.msrpm;
+    unsigned long *msr_bit = NULL;
+
+    /*
+     * See AMD64 Programmers Manual, Vol 2, Section 15.10 (MSR-Bitmap Address).
+     */
+    if ( msr <= 0x1fff )
+        msr_bit = msr_bitmap + 0x0000 / BYTES_PER_LONG;
+    else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
+        msr_bit = msr_bitmap + 0x0800 / BYTES_PER_LONG;
+    else if ( (msr >= 0xc0010000) && (msr <= 0xc0011fff) )
+        msr_bit = msr_bitmap + 0x1000 / BYTES_PER_LONG;
+
+    BUG_ON(msr_bit == NULL);
+
+    msr &= 0x1fff;
+
+    if ( enabled )
+    {
+        __set_bit(msr * 2, msr_bit);
+        __set_bit(msr * 2 + 1, msr_bit);
+    }
+    else
+    {
+        __clear_bit(msr * 2, msr_bit);
+        __clear_bit(msr * 2 + 1, msr_bit);
+    }
+    v->arch.hvm_svm.vmcb->cleanbits.fields.iopm = 0;
+}
diff -r e31f18fff54c -r be72873a6f30 xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -31,6 +31,7 @@
 #include <asm/hvm/io.h>
 #include <asm/hvm/support.h>
 #include <asm/hvm/svm/svm.h>
+#include <asm/hvm/svm/svmcleanbits.h>
 #include <asm/hvm/svm/intr.h>
 #include <asm/hvm/svm/asid.h>
 #include <xen/event.h>
@@ -78,37 +79,6 @@ struct host_save_area *alloc_host_save_a
     return hsa;
 }
 
-void svm_intercept_msr(struct vcpu *v, uint32_t msr, int enable)
-{
-    unsigned long *msr_bitmap = v->arch.hvm_svm.msrpm;
-    unsigned long *msr_bit = NULL;
-
-    /*
-     * See AMD64 Programmers Manual, Vol 2, Section 15.10 (MSR-Bitmap Address).
-     */
-    if ( msr <= 0x1fff )
-        msr_bit = msr_bitmap + 0x0000 / BYTES_PER_LONG;
-    else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
-        msr_bit = msr_bitmap + 0x0800 / BYTES_PER_LONG;
-    else if ( (msr >= 0xc0010000) && (msr <= 0xc0011fff) )
-        msr_bit = msr_bitmap + 0x1000 / BYTES_PER_LONG;
-
-    BUG_ON(msr_bit == NULL);
-
-    msr &= 0x1fff;
-
-    if ( enable )
-    {
-        __set_bit(msr * 2, msr_bit);
-        __set_bit(msr * 2 + 1, msr_bit);
-    }
-    else
-    {
-        __clear_bit(msr * 2, msr_bit);
-        __clear_bit(msr * 2 + 1, msr_bit);
-    }
-}
-
 static int construct_vmcb(struct vcpu *v)
 {
     struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
@@ -145,13 +115,13 @@ static int construct_vmcb(struct vcpu *v
         return -ENOMEM;
     memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
 
-    svm_disable_intercept_for_msr(v, MSR_FS_BASE);
-    svm_disable_intercept_for_msr(v, MSR_GS_BASE);
-    svm_disable_intercept_for_msr(v, MSR_SHADOW_GS_BASE);
-    svm_disable_intercept_for_msr(v, MSR_CSTAR);
-    svm_disable_intercept_for_msr(v, MSR_LSTAR);
-    svm_disable_intercept_for_msr(v, MSR_STAR);
-    svm_disable_intercept_for_msr(v, MSR_SYSCALL_MASK);
+    svm_clear_msr_intercept(v, MSR_FS_BASE);
+    svm_clear_msr_intercept(v, MSR_GS_BASE);
+    svm_clear_msr_intercept(v, MSR_SHADOW_GS_BASE);
+    svm_clear_msr_intercept(v, MSR_CSTAR);
+    svm_clear_msr_intercept(v, MSR_LSTAR);
+    svm_clear_msr_intercept(v, MSR_STAR);
+    svm_clear_msr_intercept(v, MSR_SYSCALL_MASK);
 
     vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
     vmcb->iopm_base_pa  = (u64)virt_to_maddr(hvm_io_bitmap);
@@ -231,9 +201,9 @@ static int construct_vmcb(struct vcpu *v
 
     if ( paging_mode_hap(v->domain) )
     {
-        vmcb->np_enable = 1; /* enable nested paging */
-        vmcb->g_pat = MSR_IA32_CR_PAT_RESET; /* guest PAT */
-        vmcb->h_cr3 = pagetable_get_paddr(p2m_get_pagetable(p2m_get_hostp2m(v->domain)));
+        struct p2m_domain *p2m = p2m_get_hostp2m(v->domain);
+        svm_set_nested_paging(vmcb, 1, MSR_IA32_CR_PAT_RESET, 
+                              pagetable_get_paddr(p2m_get_pagetable(p2m)));
 
         /* No point in intercepting CR3 reads/writes. */
         vmcb->cr_intercepts &= ~(CR_INTERCEPT_CR3_READ|CR_INTERCEPT_CR3_WRITE);
@@ -245,7 +215,7 @@ static int construct_vmcb(struct vcpu *v
         vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_INVLPG;
 
         /* PAT is under complete control of SVM when using nested paging. */
-        svm_disable_intercept_for_msr(v, MSR_IA32_CR_PAT);
+        svm_clear_msr_intercept(v, MSR_IA32_CR_PAT);
     }
     else
     {
@@ -258,6 +228,8 @@ static int construct_vmcb(struct vcpu *v
         vmcb->general1_intercepts |= GENERAL1_INTERCEPT_PAUSE;
     }
 
+    vmcb->cleanbits.bytes = 0;
+
     return 0;
 }
 
@@ -357,7 +329,8 @@ void svm_dump_vmcb(const char *from, str
     printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n", 
            (unsigned long long) vmcb->kerngsbase,
            (unsigned long long) vmcb->g_pat);
-    printk("H_CR3 = 0x%016llx\n", (unsigned long long)vmcb->h_cr3);
+    printk("H_CR3 = 0x%016llx CleanBits = 0x%08x\n", 
+           (unsigned long long)vmcb->h_cr3, vmcb->cleanbits.bytes);
 
     /* print out all the selectors */
     svm_dump_sel("CS", &vmcb->cs);
diff -r e31f18fff54c -r be72873a6f30 xen/include/asm-x86/hvm/svm/svm.h
--- a/xen/include/asm-x86/hvm/svm/svm.h
+++ b/xen/include/asm-x86/hvm/svm/svm.h
@@ -68,12 +68,14 @@ extern u32 svm_feature_flags;
 #define SVM_FEATURE_LBRV    1
 #define SVM_FEATURE_SVML    2
 #define SVM_FEATURE_NRIPS   3
+#define SVM_FEATURE_CLEAN   5
 #define SVM_FEATURE_PAUSEF  10
 
 #define cpu_has_svm_npt     test_bit(SVM_FEATURE_NPT, &svm_feature_flags)
 #define cpu_has_svm_lbrv    test_bit(SVM_FEATURE_LBRV, &svm_feature_flags)
 #define cpu_has_svm_svml    test_bit(SVM_FEATURE_SVML, &svm_feature_flags)
 #define cpu_has_svm_nrips   test_bit(SVM_FEATURE_NRIPS, &svm_feature_flags)
+#define cpu_has_svm_cleanbits test_bit(SVM_FEATURE_CLEAN, &svm_feature_flags)
 #define cpu_has_pause_filter  test_bit(SVM_FEATURE_PAUSEF, &svm_feature_flags)
 
 #endif /* __ASM_X86_HVM_SVM_H__ */
diff -r e31f18fff54c -r be72873a6f30 xen/include/asm-x86/hvm/svm/svmcleanbits.h
--- /dev/null
+++ b/xen/include/asm-x86/hvm/svm/svmcleanbits.h
@@ -0,0 +1,192 @@
+/*
+ * svmcleanbits.h: SVM VMCB CleanBits
+ * Copyright (c) 2010, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#ifndef __ASM_X86_HVM_SVMCLEANBITS_H__
+#define __ASM_X86_HVM_SVMCLEANBITS_H__
+
+#include <asm/hvm/svm/vmcb.h>
+
+#define SVMCLEANBITS_INIT    ~0
+
+/* VMCB intercepts: covered by cleanbit 0 
+ * 
+ * The following functions cover VMCB dr_intercepts, exception_intercepts,
+ * general1_intercepts, general2_intercepts and tsc_offset. 
+ */
+#define svm_set_dr(vmcb, value)                 \
+    do {                                        \
+        vmcb->dr_intercepts = value;            \
+        vmcb->cleanbits.fields.intercepts = 0;  \
+    } while (0)
+
+static inline void
+svm_exception_intercept(struct vmcb_struct *vmcb, 
+                        unsigned int bit_pos, bool_t enabled)
+{
+    if (enabled)
+        vmcb->exception_intercepts |= (1U << bit_pos);
+    else
+        vmcb->exception_intercepts &= ~(1U << bit_pos);
+
+    vmcb->cleanbits.fields.intercepts = 0;
+}
+#define svm_set_exception_intercept(v, p)   svm_exception_intercept(v, p, 1)
+#define svm_clear_exception_intercept(v, p) svm_exception_intercept(v, p, 0)
+
+static inline void
+svm_general1_intercept(struct vmcb_struct *vmcb, 
+                       enum GenericIntercept1bits g1, bool_t enabled)
+{
+    if (enabled)
+        vmcb->general1_intercepts |= g1;
+    else
+        vmcb->general1_intercepts &= ~g1;
+
+    vmcb->cleanbits.fields.intercepts = 0;
+}
+#define svm_set_general1_intercept(v, g1)   svm_general1_intercept(v, g1, 1)
+#define svm_clear_general1_intercept(v, g1) svm_general1_intercept(v, g1, 0)
+
+static inline void
+svm_general2_intercept(struct vmcb_struct *vmcb, 
+                       enum GenericIntercept1bits g2, bool_t enabled)
+{
+    if (enabled)
+        vmcb->general2_intercepts |= g2;
+    else
+        vmcb->general2_intercepts &= ~g2;
+
+    vmcb->cleanbits.fields.intercepts = 0;
+}
+#define svm_set_general2_intercept(v, g2)   svm_general2_intercept(v, g2, 1)
+#define svm_clear_general2_intercept(v, g2) svm_general2_intercept(v, g2, 0)
+
+/* tsc_offset is capsulated hvm_funcs.set_tsc_offset(). Please use it. */
+
+/* VMCB I/O MSR permission map: covered by cleanbit 1 
+ * 
+ * The I/O permission map aren't changed. So hypervisor doesn't need to handle
+ * it. As for MSR permission map, its dirty bit is set in svm_intercept_msr().
+ * We define two macros to capsulate it.
+ */
+void svm_intercept_msr(struct vcpu *v, uint32_t msr, bool_t enable);
+#define svm_set_msr_intercept(v, msr) svm_intercept_msr((v), (msr), 1)
+#define svm_clear_msr_intercept(v, msr) svm_intercept_msr((v), (msr), 0)
+
+/* VMCB ASID: covered by cleanbit 2 */
+#define svm_set_asid(vmcb, value)               \
+    do {                                        \
+        if (vmcb->guest_asid != value)          \
+            vmcb->cleanbits.fields.asid = 0;    \
+                                                \
+        vmcb->guest_asid = value;               \
+    } while (0)
+
+/* VMCB VINTR: covered by cleanbit 3 */
+#define svm_set_vintr(vmcb, vintr_field, value) \
+    do {                                        \
+        vmcb->vintr_field = value;              \
+        vmcb->cleanbits.fields.tpr = 0;         \
+    } while (0)
+
+/* VMCB np_enable, h_cr3 and g_pat: covered by cleanbit 4 */
+#define svm_set_nested_paging(vmcb, enabled, guest_pat, host_cr3) \
+    do {                                                          \
+        vmcb->np_enable = enabled;                                \
+        vmcb->h_cr3 = host_cr3;                                   \
+        vmcb->g_pat = guest_pat;                                  \
+                                                                  \
+        vmcb->cleanbits.fields.np = 0;                            \
+    } while (0)
+
+/* VMCB CR0, CR3, CR4 and EFER: covered by cleanbit 5 */
+#define svm_set_cr0(vmcb, value)                \
+    do {                                        \
+        vmcb->cr0 = value;                      \
+        vmcb->cleanbits.fields.cr = 0;          \
+    } while (0)
+
+#define svm_set_cr3(vmcb, value)                \
+    do {                                        \
+        vmcb->cr3 = value;                      \
+        vmcb->cleanbits.fields.cr = 0;          \
+    } while (0)
+
+#define svm_set_cr4(vmcb, value)                \
+    do {                                        \
+        vmcb->cr4 = value;                      \
+        vmcb->cleanbits.fields.cr = 0;          \
+    } while (0)
+
+#define svm_set_efer(vmcb, value)               \
+    do {                                        \
+        vmcb->efer = value;                     \
+        vmcb->cleanbits.fields.cr = 0;          \
+    } while (0)
+
+/* VMCB DR6 and DR7: covered by cleanbit 6 */
+#define svm_set_dr6(vmcb, value)                \
+    do {                                        \
+        vmcb->dr6 = value;                      \
+        vmcb->cleanbits.fields.dr = 0;          \
+    } while (0)
+
+#define svm_set_dr7(vmcb, value)                \
+    do {                                        \
+        vmcb->dr7 = value;                      \
+        vmcb->cleanbits.fields.dr = 0;          \
+    } while (0)
+
+/* VMCB GDT and IDT: covered by cleanbit 7 */
+#define svm_set_gdt(vmcb, base_val, limit_val)  \
+    do {                                        \
+        vmcb->gdtr.base = base_val;             \
+        vmcb->gdtr.limit = (uint16_t)limit_val; \
+                                                \
+        vmcb->cleanbits.fields.dt = 0;          \
+    } while (0)
+
+#define svm_set_idt(vmcb, base_val, limit_val)  \
+    do {                                        \
+        vmcb->idtr.base = base_val;             \
+        vmcb->idtr.limit = (uint16_t)limit_val; \
+                                                \
+        vmcb->cleanbits.fields.dt = 0;          \
+    } while (0)
+
+/* VMCB segments: covered by cleanbit 8 
+ * 
+ * Please refer to hvm_set_segment_register(). The dirty bit was set in that
+ * function. Everyone is encouraged to use that in any case. */
+
+/* VMCB CR2: covered by cleanbit 9 */
+#define svm_set_cr2(vmcb, value)                \
+    do {                                        \
+        vmcb->cr2 = value;                      \
+        vmcb->cleanbits.fields.cr2 = 0;         \
+    } while (0)
+
+/* VMCB LBRV: covered by cleanbit 10 */
+#define svm_set_lbr(vmcb, lbr_field, value)     \
+    do {                                        \
+        vmcb->lbr_field = value;                \
+        vmcb->cleanbits.fields.lbr = 0;         \
+    } while (0)
+
+#endif /* __ASM_X86_HVM_SVMCLEANBITS_H__ */
diff -r e31f18fff54c -r be72873a6f30 xen/include/asm-x86/hvm/svm/vmcb.h
--- a/xen/include/asm-x86/hvm/svm/vmcb.h
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h
@@ -366,6 +366,26 @@ typedef union
     } fields;
 } __attribute__ ((packed)) lbrctrl_t;
 
+typedef union
+{
+    uint32_t bytes;
+    struct
+    {
+        uint32_t intercepts: 1;
+        uint32_t iopm: 1;
+        uint32_t asid: 1;
+        uint32_t tpr: 1;
+        uint32_t np: 1;
+        uint32_t cr: 1;
+        uint32_t dr: 1;
+        uint32_t dt: 1;
+        uint32_t seg: 1;
+        uint32_t cr2: 1;
+        uint32_t lbr: 1;
+        uint32_t resv: 21;
+    } fields;
+} __attribute__ ((packed)) vmcbcleanbits_t;
+
 struct vmcb_struct {
     u32 cr_intercepts;          /* offset 0x00 */
     u32 dr_intercepts;          /* offset 0x04 */
@@ -397,7 +417,8 @@ struct vmcb_struct {
     eventinj_t  eventinj;       /* offset 0xA8 */
     u64 h_cr3;                  /* offset 0xB0 */
     lbrctrl_t lbr_control;      /* offset 0xB8 */
-    u64 res09;                  /* offset 0xC0 */
+    vmcbcleanbits_t cleanbits;  /* offset 0xC0 */
+    u32 res09;                  /* offset 0xC4 */
     u64 nextrip;                /* offset 0xC8 */
     u64 res10a[102];            /* offset 0xD0 pad to save area */
 
@@ -481,11 +502,6 @@ int  svm_create_vmcb(struct vcpu *v);
 void svm_destroy_vmcb(struct vcpu *v);
 
 void setup_vmcb_dump(void);
-
-void svm_intercept_msr(struct vcpu *v, uint32_t msr, int enable);
-#define svm_disable_intercept_for_msr(v, msr) svm_intercept_msr((v), (msr), 0)
-#define svm_enable_intercept_for_msr(v, msr) svm_intercept_msr((v), (msr), 1)
-
 #endif /* ASM_X86_HVM_SVM_VMCS_H__ */
 
 /*

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-12-16  8:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-15 10:52 [PATCH] svm: support VMCB cleanbits Christoph Egger
2010-12-15 11:27 ` Tim Deegan
2010-12-15 12:36   ` Christoph Egger
2010-12-15 16:56     ` Keir Fraser
2010-12-15 23:04       ` Huang2, Wei
2010-12-16  8:47         ` Keir Fraser

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).