KVM: PPC: e500: enable magic page
authorScott Wood <scottwood@freescale.com>
Tue, 14 Jun 2011 23:34:41 +0000 (18:34 -0500)
committerAvi Kivity <avi@redhat.com>
Tue, 12 Jul 2011 10:16:37 +0000 (13:16 +0300)
This is a shared page used for paravirtualization.  It is always present
in the guest kernel's effective address space at the address indicated
by the hypercall that enables it.

The physical address specified by the hypercall is not used, as
e500 does not have real mode.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Documentation/virtual/kvm/ppc-pv.txt
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/e500_tlb.c
arch/powerpc/kvm/powerpc.c

index 3ab969c5904646f342f67da59666ad390c5c5787..2b7ce190cde47041edfebbb66a6dc853327e8549 100644 (file)
@@ -68,9 +68,11 @@ page that contains parts of supervisor visible register state. The guest can
 map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE.
 
 With this hypercall issued the guest always gets the magic page mapped at the
-desired location in effective and physical address space. For now, we always
-map the page to -4096. This way we can access it using absolute load and store
-functions. The following instruction reads the first field of the magic page:
+desired location. The first parameter indicates the effective address when the
+MMU is enabled. The second parameter indicates the address in real mode, if
+applicable to the target. For now, we always map the page to -4096. This way we
+can access it using absolute load and store functions. The following
+instruction reads the first field of the magic page:
 
        ld      rX, -4096(0)
 
index 9345238edecfcd03d3aa6dfa0ddb8806294630e8..c662f140283a640b2ff7e4a59f0a8ed237f458b3 100644 (file)
@@ -109,6 +109,7 @@ extern void kvmppc_booke_exit(void);
 
 extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
 extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu);
+extern void kvmppc_map_magic(struct kvm_vcpu *vcpu);
 
 /*
  * Cuts out inst bits with ordering according to spec.
index 0ecbecb2f7cc83baba524ae782efd833c664cf84..4538956daecf71870e245f68005d99317fdfa390 100644 (file)
@@ -472,6 +472,17 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                gpa_t gpaddr;
                gfn_t gfn;
 
+#ifdef CONFIG_KVM_E500
+               if (!(vcpu->arch.shared->msr & MSR_PR) &&
+                   (eaddr & PAGE_MASK) == vcpu->arch.magic_page_ea) {
+                       kvmppc_map_magic(vcpu);
+                       kvmppc_account_exit(vcpu, DTLB_VIRT_MISS_EXITS);
+                       r = RESUME_GUEST;
+
+                       break;
+               }
+#endif
+
                /* Check the guest TLB. */
                gtlb_index = kvmppc_mmu_dtlb_index(vcpu, eaddr);
                if (gtlb_index < 0) {
index 7f808c52e64ab936660e1e50f98ff2291a0241f2..c09e642ee5373b95467db10942c8878f29d9177e 100644 (file)
@@ -76,7 +76,8 @@ static inline unsigned int tlb0_get_next_victim(
 
 static inline unsigned int tlb1_max_shadow_size(void)
 {
-       return tlb1_entry_num - tlbcam_index;
+       /* reserve one entry for magic page */
+       return tlb1_entry_num - tlbcam_index - 1;
 }
 
 static inline int tlbe_is_writable(struct tlbe *tlbe)
@@ -142,6 +143,25 @@ static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
        }
 }
 
+void kvmppc_map_magic(struct kvm_vcpu *vcpu)
+{
+       struct tlbe magic;
+       ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
+       pfn_t pfn;
+
+       pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
+       get_page(pfn_to_page(pfn));
+
+       magic.mas1 = MAS1_VALID | MAS1_TS |
+                    MAS1_TSIZE(BOOK3E_PAGESZ_4K);
+       magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M;
+       magic.mas3 = (pfn << PAGE_SHIFT) |
+                    MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
+       magic.mas7 = pfn >> (32 - PAGE_SHIFT);
+
+       __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index));
+}
+
 void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu)
 {
 }
index 616dd516ca1f7fc364de51957d17e5911cbe6135..24e2b64b6a484f21698ee9adc24f515b4028c833 100644 (file)
@@ -73,7 +73,8 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
        }
        case HC_VENDOR_KVM | KVM_HC_FEATURES:
                r = HC_EV_SUCCESS;
-#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */
+#if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500)
+               /* XXX Missing magic page on 44x */
                r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
 #endif