powerpc/kvm: Sync guest visible MMU state
authorAlexander Graf <agraf@suse.de>
Mon, 30 Nov 2009 03:02:02 +0000 (03:02 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 8 Dec 2009 05:02:50 +0000 (16:02 +1100)
Currently userspace has no chance to find out which virtual address space we're
in and resolve addresses. While that is a big problem for migration, it's also
unpleasent when debugging, as gdb and the monitor don't work on virtual
addresses.

This patch exports enough of the MMU segment state to userspace to make
debugging work and thus also includes the groundwork for migration.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_asm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_64_emulate.c
arch/powerpc/kvm/book3s_64_mmu.c
arch/powerpc/kvm/powerpc.c
include/linux/kvm.h

index c9ca97f43bc1a55dbbfd3cf5d7f64bd64f884049..81f3b0b5601ecf8c113d1c457e68463ad3f94fa6 100644 (file)
@@ -47,7 +47,23 @@ struct kvm_regs {
 
 struct kvm_sregs {
        __u32 pvr;
-       char pad[1020];
+       union {
+               struct {
+                       __u64 sdr1;
+                       struct {
+                               struct {
+                                       __u64 slbe;
+                                       __u64 slbv;
+                               } slb[64];
+                       } ppc64;
+                       struct {
+                               __u32 sr[16];
+                               __u64 ibat[8]; 
+                               __u64 dbat[8]; 
+                       } ppc32;
+               } s;
+               __u8 pad[1020];
+       } u;
 };
 
 struct kvm_fpu {
index 19ddb352fd0fccaede75e4dde9aafd34ecfc4a93..af2abe74f54440199fdccfeccdd2de085ec7a203 100644 (file)
@@ -87,6 +87,7 @@
 #define BOOK3S_IRQPRIO_MAX                     16
 
 #define BOOK3S_HFLAG_DCBZ32                    0x1
+#define BOOK3S_HFLAG_SLB                       0x2
 
 #define RESUME_FLAG_NV          (1<<0)  /* Reload guest nonvolatile state? */
 #define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
index c6011336371e506829a54ed18a225d559c1e3b41..74b7369770d05b3f93a9c233e3815aef3ad51300 100644 (file)
@@ -46,6 +46,7 @@ struct kvmppc_sr {
 };
 
 struct kvmppc_bat {
+       u64 raw;
        u32 bepi;
        u32 bepi_mask;
        bool vs;
@@ -113,6 +114,8 @@ extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, boo
 extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, bool data);
 extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr);
 extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec);
+extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
+                          bool upper, u32 val);
 
 extern u32 kvmppc_trampoline_lowmem;
 extern u32 kvmppc_trampoline_enter;
index 42037d46a416e5f447e1c5ffe17ab5a705e106d8..3e294bd9b8c6d998ef262d013de4e02a3468fbca 100644 (file)
@@ -281,6 +281,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
 
 void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
 {
+       vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB;
        vcpu->arch.pvr = pvr;
        if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
                kvmppc_mmu_book3s_64_init(vcpu);
@@ -762,14 +763,62 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                                   struct kvm_sregs *sregs)
 {
+       struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+       int i;
+
        sregs->pvr = vcpu->arch.pvr;
+
+       sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1;
+       if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) {
+               for (i = 0; i < 64; i++) {
+                       sregs->u.s.ppc64.slb[i].slbe = vcpu3s->slb[i].orige | i;
+                       sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv;
+               }
+       } else {
+               for (i = 0; i < 16; i++) {
+                       sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
+                       sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
+               }
+               for (i = 0; i < 8; i++) {
+                       sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw;
+                       sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw;
+               }
+       }
        return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
                                   struct kvm_sregs *sregs)
 {
+       struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+       int i;
+
        kvmppc_set_pvr(vcpu, sregs->pvr);
+
+       vcpu3s->sdr1 = sregs->u.s.sdr1;
+       if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) {
+               for (i = 0; i < 64; i++) {
+                       vcpu->arch.mmu.slbmte(vcpu, sregs->u.s.ppc64.slb[i].slbv,
+                                                   sregs->u.s.ppc64.slb[i].slbe);
+               }
+       } else {
+               for (i = 0; i < 16; i++) {
+                       vcpu->arch.mmu.mtsrin(vcpu, i, sregs->u.s.ppc32.sr[i]);
+               }
+               for (i = 0; i < 8; i++) {
+                       kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), false,
+                                      (u32)sregs->u.s.ppc32.ibat[i]);
+                       kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), true,
+                                      (u32)(sregs->u.s.ppc32.ibat[i] >> 32));
+                       kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), false,
+                                      (u32)sregs->u.s.ppc32.dbat[i]);
+                       kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), true,
+                                      (u32)(sregs->u.s.ppc32.dbat[i] >> 32));
+               }
+       }
+
+       /* Flush the MMU after messing with the segments */
+       kvmppc_mmu_pte_flush(vcpu, 0, 0);
        return 0;
 }
 
index c343e67306e08e0c8b73ecfe7d43e5da009ee958..1027eac6d474fea3ae3a94efe6aca91cd48a594c 100644 (file)
@@ -185,7 +185,27 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
        return emulated;
 }
 
-static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u64 val)
+void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper,
+                    u32 val)
+{
+       if (upper) {
+               /* Upper BAT */
+               u32 bl = (val >> 2) & 0x7ff;
+               bat->bepi_mask = (~bl << 17);
+               bat->bepi = val & 0xfffe0000;
+               bat->vs = (val & 2) ? 1 : 0;
+               bat->vp = (val & 1) ? 1 : 0;
+               bat->raw = (bat->raw & 0xffffffff00000000ULL) | val;
+       } else {
+               /* Lower BAT */
+               bat->brpn = val & 0xfffe0000;
+               bat->wimg = (val >> 3) & 0xf;
+               bat->pp = val & 3;
+               bat->raw = (bat->raw & 0x00000000ffffffffULL) | ((u64)val << 32);
+       }
+}
+
+static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val)
 {
        struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
        struct kvmppc_bat *bat;
@@ -207,19 +227,7 @@ static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u64 val)
                BUG();
        }
 
-       if (!(sprn % 2)) {
-               /* Upper BAT */
-               u32 bl = (val >> 2) & 0x7ff;
-               bat->bepi_mask = (~bl << 17);
-               bat->bepi = val & 0xfffe0000;
-               bat->vs = (val & 2) ? 1 : 0;
-               bat->vp = (val & 1) ? 1 : 0;
-       } else {
-               /* Lower BAT */
-               bat->brpn = val & 0xfffe0000;
-               bat->wimg = (val >> 3) & 0xf;
-               bat->pp = val & 3;
-       }
+       kvmppc_set_bat(vcpu, bat, !(sprn % 2), val);
 }
 
 int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
@@ -243,7 +251,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
        case SPRN_IBAT4U ... SPRN_IBAT7L:
        case SPRN_DBAT0U ... SPRN_DBAT3L:
        case SPRN_DBAT4U ... SPRN_DBAT7L:
-               kvmppc_write_bat(vcpu, sprn, vcpu->arch.gpr[rs]);
+               kvmppc_write_bat(vcpu, sprn, (u32)vcpu->arch.gpr[rs]);
                /* BAT writes happen so rarely that we're ok to flush
                 * everything here */
                kvmppc_mmu_pte_flush(vcpu, 0, 0);
index a31f9c677d23318e3c4f797eed889530c9661757..5598f88f142e6332877e7a4a84947fbba93b9dc6 100644 (file)
@@ -473,4 +473,6 @@ void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu)
        mmu->esid_to_vsid = kvmppc_mmu_book3s_64_esid_to_vsid;
        mmu->ea_to_vp = kvmppc_mmu_book3s_64_ea_to_vp;
        mmu->is_dcbz32 = kvmppc_mmu_book3s_64_is_dcbz32;
+
+       vcpu->arch.hflags |= BOOK3S_HFLAG_SLB;
 }
index 692c3709011ee409d7f2a42607d28f2bff46b92f..d82551efbfbf33b8dc6afd68a50aea933aaf9287 100644 (file)
@@ -144,6 +144,9 @@ int kvm_dev_ioctl_check_extension(long ext)
        int r;
 
        switch (ext) {
+       case KVM_CAP_PPC_SEGSTATE:
+               r = 1;
+               break;
        case KVM_CAP_COALESCED_MMIO:
                r = KVM_COALESCED_MMIO_PAGE_OFFSET;
                break;
index f8f8900fc5ecbcdf22fe6ae274537830f5c2b181..caf6173bd2e8a34c9435b6ab33c35186d7abc6b5 100644 (file)
@@ -436,6 +436,9 @@ struct kvm_ioeventfd {
 #endif
 #define KVM_CAP_IOEVENTFD 36
 #define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
+/* KVM upstream has more features, but we synched this number.
+   Linux, please remove this comment on rebase. */
+#define KVM_CAP_PPC_SEGSTATE 43
 
 #ifdef KVM_CAP_IRQ_ROUTING