]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
KVM: powerpc: Map guest userspace with TID=0 mappings
authorHollis Blanchard <hollisb@us.ibm.com>
Fri, 25 Jul 2008 18:54:53 +0000 (13:54 -0500)
committerAvi Kivity <avi@qumranet.com>
Wed, 15 Oct 2008 08:15:16 +0000 (10:15 +0200)
When we use TID=N userspace mappings, we must ensure that kernel mappings have
been destroyed when entering userspace. Using TID=1/TID=0 for kernel/user
mappings and running userspace with PID=0 means that userspace can't access the
kernel mappings, but the kernel can directly access userspace.

The net is that we don't need to flush the TLB on privilege switches, but we do
on guest context switches (which are far more infrequent). Guest boot time
performance improvement: about 30%.

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kvm/44x_tlb.c
arch/powerpc/kvm/booke_guest.c
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/emulate.c

index 4338b03da8f9d582e8c39b8a1f0dba6c3a6f6103..34b52b7180cd52da00f31532cb956dff68923a86 100644 (file)
@@ -129,7 +129,11 @@ struct kvm_vcpu_arch {
        u32 ivor[16];
        u32 ivpr;
        u32 pir;
+
+       u32 shadow_pid;
        u32 pid;
+       u32 swap_pid;
+
        u32 pvr;
        u32 ccr0;
        u32 ccr1;
index 8e7e42959903ad1cd5588caa3ed29aa81daa4cec..8931ba729d2b519ec4d4efb1d0851301d96e1d3a 100644 (file)
@@ -64,6 +64,7 @@ extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn,
 extern void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
                                   gva_t eend, u32 asid);
 extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode);
+extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid);
 
 /* XXX Book E specific */
 extern void kvmppc_tlbe_set_modified(struct kvm_vcpu *vcpu, unsigned int i);
@@ -95,4 +96,12 @@ static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
                kvm_vcpu_block(vcpu);
 }
 
+static inline void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid)
+{
+       if (vcpu->arch.pid != new_pid) {
+               vcpu->arch.pid = new_pid;
+               vcpu->arch.swap_pid = 1;
+       }
+}
+
 #endif /* __POWERPC_KVM_PPC_H__ */
index 1631d670b9ede3599b799435a1b7765d7861f3f9..52649da344fb78c8142a328e5ede074965d112d5 100644 (file)
@@ -369,7 +369,7 @@ int main(void)
        DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
        DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
        DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
-       DEFINE(VCPU_PID, offsetof(struct kvm_vcpu, arch.pid));
+       DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
 
        DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
        DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
index 06a5fcfc4d33363ed51fd81547f58baebbaf510c..3594bbd1f6185d854730d867ed59c784b360bca3 100644 (file)
@@ -170,7 +170,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
 
        /* XXX what about AS? */
 
-       stlbe->tid = asid & 0xff;
+       stlbe->tid = !(asid & 0xff);
 
        /* Force TS=1 for all guest mappings. */
        /* For now we hardcode 4KB mappings, but it will be important to
@@ -190,7 +190,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
 void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
                            gva_t eend, u32 asid)
 {
-       unsigned int pid = asid & 0xff;
+       unsigned int pid = !(asid & 0xff);
        int i;
 
        /* XXX Replace loop with fancy data structures. */
@@ -222,23 +222,30 @@ void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
        up_write(&current->mm->mmap_sem);
 }
 
-/* Invalidate all mappings, so that when they fault back in they will get the
- * proper permission bits. */
+/* Invalidate all mappings on the privilege switch after PID has been changed.
+ * The guest always runs with PID=1, so we must clear the entire TLB when
+ * switching address spaces. */
 void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode)
 {
        int i;
 
-       /* XXX Replace loop with fancy data structures. */
-       down_write(&current->mm->mmap_sem);
-       for (i = 0; i <= tlb_44x_hwater; i++) {
-               struct tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
-
-               kvmppc_44x_shadow_release(vcpu, i);
-               stlbe->word0 = 0;
-               kvmppc_tlbe_set_modified(vcpu, i);
-               KVMTRACE_5D(STLB_INVAL, vcpu, i,
-                               stlbe->tid, stlbe->word0, stlbe->word1,
-                               stlbe->word2, handler);
+       if (vcpu->arch.swap_pid) {
+               /* XXX Replace loop with fancy data structures. */
+               down_write(&current->mm->mmap_sem);
+               for (i = 0; i <= tlb_44x_hwater; i++) {
+                       struct tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
+
+                       /* Future optimization: clear only userspace mappings. */
+                       kvmppc_44x_shadow_release(vcpu, i);
+                       stlbe->word0 = 0;
+                       kvmppc_tlbe_set_modified(vcpu, i);
+                       KVMTRACE_5D(STLB_INVAL, vcpu, i,
+                                   stlbe->tid, stlbe->word0, stlbe->word1,
+                                   stlbe->word2, handler);
+               }
+               up_write(&current->mm->mmap_sem);
+               vcpu->arch.swap_pid = 0;
        }
-       up_write(&current->mm->mmap_sem);
+
+       vcpu->arch.shadow_pid = !usermode;
 }
index 3cca079975e15541bcf82325d6a26c23beb21d75..7b2591e26bae3dc93dc7f002e833fd98de8288bb 100644 (file)
@@ -486,6 +486,8 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.msr = 0;
        vcpu->arch.gpr[1] = (16<<20) - 8; /* -8 for the callee-save LR slot */
 
+       vcpu->arch.shadow_pid = 1;
+
        /* Eye-catching number so we know if the guest takes an interrupt
         * before it's programmed its own IVPR. */
        vcpu->arch.ivpr = 0x55550000;
index 564ea32ecbacc1357896753432e31d19ef025f40..95e165baf85faee89b7dfa30e628b75778358618 100644 (file)
@@ -332,7 +332,7 @@ lightweight_exit:
 
        mfspr   r3, SPRN_PID
        stw     r3, VCPU_HOST_PID(r4)
-       lwz     r3, VCPU_PID(r4)
+       lwz     r3, VCPU_SHADOW_PID(r4)
        mtspr   SPRN_PID, r3
 
        /* Prevent all asynchronous TLB updates. */
index c3ed63b2221035aa98f69f488acd94cc82d8f780..0fce4fbdc20d2015f44ce3c2c8bfcef291bc82b9 100644 (file)
@@ -508,7 +508,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        case SPRN_MMUCR:
                                vcpu->arch.mmucr = vcpu->arch.gpr[rs]; break;
                        case SPRN_PID:
-                               vcpu->arch.pid = vcpu->arch.gpr[rs]; break;
+                               kvmppc_set_pid(vcpu, vcpu->arch.gpr[rs]); break;
                        case SPRN_CCR0:
                                vcpu->arch.ccr0 = vcpu->arch.gpr[rs]; break;
                        case SPRN_CCR1: