]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86: Make use of VMCB clean bits
authorValentine Sinitsyn <valentine.sinitsyn@gmail.com>
Tue, 5 Aug 2014 18:51:01 +0000 (00:51 +0600)
committerJan Kiszka <jan.kiszka@siemens.com>
Sat, 1 Nov 2014 19:10:09 +0000 (20:10 +0100)
After a cell is created, Jailhouse doesn't change its VMCB much.
This means VMCB Clean Bits (APMv2, Sect. 15.15.1) have a good
potential to reduce a world switch time.

This commit introduces VMCB Clean Bits support in Jailhouse. On each
VM exit, VMCB is marked as clean (unmodified), and each function that
changes guest state in VMCB is responsible for clearing the bit.

This is an optional feature, however it is cheap and harmless even
on CPUs that don't support it. So we use it unconditionally: CPUs
that do not support VMCB State Caching will simply ignore this.

Signed-off-by: Valentine Sinitsyn <valentine.sinitsyn@gmail.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/x86/include/asm/svm.h
hypervisor/arch/x86/svm.c

index a912f42499afa4fd35dc232f832308c4130f8832..89f88c65cb7b73624897924d85b9bdcc08cf4b60 100644 (file)
@@ -244,6 +244,21 @@ enum vm_exit_code {
        VMEXIT_INVALID                  =  -1
 };
 
+enum clean_bits {
+       CLEAN_BITS_I    = 1 << 0,
+       CLEAN_BITS_IOPM = 1 << 1,
+       CLEAN_BITS_ASID = 1 << 2,
+       CLEAN_BITS_TPR  = 1 << 3,
+       CLEAN_BITS_NP   = 1 << 4,
+       CLEAN_BITS_CRX  = 1 << 5,
+       CLEAN_BITS_DRX  = 1 << 6,
+       CLEAN_BITS_DT   = 1 << 7,
+       CLEAN_BITS_SEG  = 1 << 8,
+       CLEAN_BITS_CR2  = 1 << 9,
+       CLEAN_BITS_LBR  = 1 << 10,
+       CLEAN_BITS_AVIC = 1 << 11
+};
+
 typedef u64 vintr_t;
 typedef u64 eventinj_t;
 typedef u64 lbrctrl_t;
@@ -279,7 +294,7 @@ struct vmcb {
        eventinj_t      eventinj;       /* offset 0xA8 */
        u64 n_cr3;                      /* offset 0xB0 */
        lbrctrl_t lbr_control;          /* offset 0xB8 */
-       u64 res09;                      /* offset 0xC0 */
+       u64 clean_bits;                 /* offset 0xC0 */
        u64 nextrip;                    /* offset 0xC8 */
        u8 bytes_fetched;               /* offset 0xD0 */
        u8 guest_bytes[15];
index d9787fb6d8a859148f4a92417d1dafd1fcbf1b02..4f40344a778267760c5b9c5f675e175d41f93826 100644 (file)
@@ -229,6 +229,9 @@ static int vmcb_setup(struct per_cpu *cpu_data)
 
        /* TODO: Setup AVIC */
 
+       /* Explicitly mark all of the state as new */
+       vmcb->clean_bits = 0;
+
        return vcpu_set_cell_config(cpu_data->cell, vmcb);
 }
 
@@ -632,6 +635,9 @@ static void vcpu_reset(struct per_cpu *cpu_data, unsigned int sipi_vector)
 
        vmcb->dr7 = 0x00000400;
 
+       /* Almost all of the guest state changed */
+       vmcb->clean_bits = 0;
+
        ok &= vcpu_set_cell_config(cpu_data->cell, vmcb);
 
        /* This is always false, but to be consistent with vmx.c... */
@@ -663,6 +669,7 @@ static void update_efer(struct per_cpu *cpu_data)
                vcpu_tlb_flush();
 
        vmcb->efer = efer;
+       vmcb->clean_bits &= ~CLEAN_BITS_CRX;
 }
 
 bool vcpu_get_guest_paging_structs(struct guest_paging_structures *pg_structs)
@@ -808,6 +815,7 @@ static bool svm_handle_cr(struct registers *guest_regs,
        vmcb->cr0 = val & SVM_CR0_CLEARED_BITS;
        if (val & X86_CR0_PG)
                update_efer(cpu_data);
+       vmcb->clean_bits &= ~CLEAN_BITS_CRX;
 
 out:
        return ok;
@@ -848,6 +856,7 @@ static bool svm_handle_msr_write(struct registers *guest_regs,
                if ((efer ^ vmcb->efer) & (EFER_LME | EFER_NXE))
                        vcpu_tlb_flush();
                vmcb->efer = efer;
+               vmcb->clean_bits &= ~CLEAN_BITS_CRX;
                goto out;
        }
 
@@ -950,6 +959,11 @@ void vcpu_handle_exit(struct registers *guest_regs, struct per_cpu *cpu_data)
        write_msr(MSR_GS_BASE, (unsigned long)cpu_data);
 
        cpu_data->stats[JAILHOUSE_CPU_STAT_VMEXITS_TOTAL]++;
+       /*
+        * All guest state is marked unmodified; individual handlers must clear
+        * the bits as needed.
+        */
+       vmcb->clean_bits = 0xffffffff;
 
        switch (vmcb->exitcode) {
        case VMEXIT_INVALID:
@@ -1047,6 +1061,7 @@ void vcpu_park(struct per_cpu *cpu_data)
        struct vmcb *vmcb = &cpu_data->vmcb;
 
        vcpu_reset(cpu_data, APIC_BSP_PSEUDO_SIPI);
+       /* No need to clear VMCB Clean bit: vcpu_reset() already does this */
        vmcb->n_cr3 = paging_hvirt2phys(parked_mode_npt);
 
        vcpu_tlb_flush();