mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 20:02:17 +00:00
powerpc/kvm: Sync guest visible MMU state
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>
This commit is contained in:
parent
c0cefebc0b
commit
e15a113700
8 changed files with 101 additions and 16 deletions
|
@ -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 {
|
||||
|
|
|
@ -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? */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue