static void kvm_mmu_write(void *dest, u64 val) { __u64 pte_phys; struct kvm_mmu_op_write_pte wpte; #ifdef CONFIG_HIGHPTE struct page *page; unsigned long dst = (unsigned long) dest; page = kmap_atomic_to_page(dest); pte_phys = page_to_pfn(page); pte_phys <<= PAGE_SHIFT; pte_phys += (dst & ~(PAGE_MASK)); #else pte_phys = (unsigned long)__pa(dest); #endif wpte.header.op = KVM_MMU_OP_WRITE_PTE; wpte.pte_val = val; wpte.pte_phys = pte_phys; kvm_deferred_mmu_op(&wpte, sizeof wpte); }
static void kvm_flush_tlb(void) { struct kvm_mmu_op_flush_tlb ftlb = { .header.op = KVM_MMU_OP_FLUSH_TLB, }; kvm_deferred_mmu_op(&ftlb, sizeof ftlb); } static void kvm_release_pt(unsigned long pfn) { struct kvm_mmu_op_release_pt rpt = { .header.op = KVM_MMU_OP_RELEASE_PT, .pt_phys = (u64)pfn << PAGE_SHIFT, }; kvm_mmu_op(&rpt, sizeof rpt); } static void kvm_enter_lazy_mmu(void) { paravirt_enter_lazy_mmu(); } static void kvm_leave_lazy_mmu(void) { struct kvm_para_state *state = kvm_para_state(); mmu_queue_flush(state); paravirt_leave_lazy_mmu(); } static void __init paravirt_ops_setup(void) { pv_info.name = "KVM"; pv_info.paravirt_enabled = 1; if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY)) pv_cpu_ops.io_delay = kvm_io_delay; if (kvm_para_has_feature(KVM_FEATURE_MMU_OP)) { pv_mmu_ops.set_pte = kvm_set_pte; pv_mmu_ops.set_pte_at = kvm_set_pte_at; pv_mmu_ops.set_pmd = kvm_set_pmd; #if PAGETABLE_LEVELS >= 3 #ifdef CONFIG_X86_PAE pv_mmu_ops.set_pte_atomic = kvm_set_pte_atomic; pv_mmu_ops.pte_clear = kvm_pte_clear; pv_mmu_ops.pmd_clear = kvm_pmd_clear; #endif pv_mmu_ops.set_pud = kvm_set_pud; #if PAGETABLE_LEVELS == 4 pv_mmu_ops.set_pgd = kvm_set_pgd; #endif #endif pv_mmu_ops.flush_tlb_user = kvm_flush_tlb; pv_mmu_ops.release_pte = kvm_release_pt; pv_mmu_ops.release_pmd = kvm_release_pt; pv_mmu_ops.release_pud = kvm_release_pt; pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu; pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu; } #ifdef CONFIG_X86_IO_APIC no_timer_check = 1; #endif } void __init kvm_guest_init(void) { if (!kvm_para_available()) return; paravirt_ops_setup(); }
static void kvm_flush_tlb(void) { struct kvm_mmu_op_flush_tlb ftlb = { .header.op = KVM_MMU_OP_FLUSH_TLB, }; kvm_deferred_mmu_op(&ftlb, sizeof ftlb); } static void kvm_release_pt(unsigned long pfn) { struct kvm_mmu_op_release_pt rpt = { .header.op = KVM_MMU_OP_RELEASE_PT, .pt_phys = (u64)pfn << PAGE_SHIFT, }; kvm_mmu_op(&rpt, sizeof rpt); } static void kvm_enter_lazy_mmu(void) { paravirt_enter_lazy_mmu(); } static void kvm_leave_lazy_mmu(void) { struct kvm_para_state *state = kvm_para_state(); mmu_queue_flush(state); paravirt_leave_lazy_mmu(); } static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) = KVM_PV_EOI_DISABLED; static void kvm_guest_apic_eoi_write(u32 reg, u32 val) { /** * This relies on __test_and_clear_bit to modify the memory * in a way that is atomic with respect to the local CPU. * The hypervisor only accesses this memory from the local CPU so * there's no need for lock or memory barriers. * An optimization barrier is implied in apic write. */ if (__test_and_clear_bit(KVM_PV_EOI_BIT, &__get_cpu_var(kvm_apic_eoi))) return; apic_write(APIC_EOI, APIC_EOI_ACK); } static void __init paravirt_ops_setup(void) { pv_info.name = "KVM"; pv_info.paravirt_enabled = 1; if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY)) pv_cpu_ops.io_delay = kvm_io_delay; if (kvm_para_has_feature(KVM_FEATURE_MMU_OP)) { pv_mmu_ops.set_pte = kvm_set_pte; pv_mmu_ops.set_pte_at = kvm_set_pte_at; pv_mmu_ops.set_pmd = kvm_set_pmd; #if PAGETABLE_LEVELS >= 3 #ifdef CONFIG_X86_PAE pv_mmu_ops.set_pte_atomic = kvm_set_pte_atomic; pv_mmu_ops.pte_clear = kvm_pte_clear; pv_mmu_ops.pmd_clear = kvm_pmd_clear; #endif pv_mmu_ops.set_pud = kvm_set_pud; #if PAGETABLE_LEVELS == 4 pv_mmu_ops.set_pgd = kvm_set_pgd; #endif #endif pv_mmu_ops.flush_tlb_user = kvm_flush_tlb; pv_mmu_ops.release_pte = kvm_release_pt; pv_mmu_ops.release_pmd = kvm_release_pt; pv_mmu_ops.release_pud = kvm_release_pt; pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu; pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu; } #ifdef CONFIG_X86_IO_APIC no_timer_check = 1; #endif } static void kvm_register_steal_time(void) { int cpu = smp_processor_id(); struct kvm_steal_time *st = &per_cpu(steal_time, cpu); if (!has_steal_clock) return; memset(st, 0, sizeof(*st)); wrmsrl(MSR_KVM_STEAL_TIME, (__pa(st) | KVM_MSR_ENABLED)); printk(KERN_INFO "kvm-stealtime: cpu %d, msr %lx\n", cpu, __pa(st)); }