mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-20 04:19:41 +00:00
Patch queue for ppc - 2014-05-30
In this round we have a few nice gems. PR KVM gains initial POWER8 support as well as LE host awareness, ihe e500 targets can now properly run u-boot, LE guests now work with PR KVM including KVM hypercalls and HV KVM guests can now use huge pages. On top of this there are some bug fixes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJTiHxMAAoJECszeR4D/txgGggQAL5rYpFkuU8+KiLd7uX4DasT DYrKxgOX/G8WRI0OJZpZHGdcw4fefBxHjY2ydnCSDk+EH2IPrlF6+aYnCwoarj3I L2Ji/OEfFZVgQtqNkqbuG5Z8onmrgZ86y5TFZKiMcDZe3zLnuGIP4fCLWEeWalor JQ9fE0z4WFkCtUD18/S/Cf6bOniGLdphUrmgECo+4SbSxUbixrckBEwuA7TjWure VrA0UX35l+VoVtYntKrQqYzsf+QSNWPzcDQnhlso+rz5ap6sB6rlC0PO8SHTPjk4 BXvHVvripVss7mGv7vZPizp52WXAFsNnVPj1tNSCu3Tn+gRBB8ChCV8xHIWYex8a nz8AvdUq1TdWmSy7NwJODjJfclauTVtrhPvrbLNSN3ksSzx4eLh8i+Lf8qe0SW7i 4oTfxG+PSDlF/ub8KX8BVfM0FpyvHdcR1h1ex3szPAQfiaAy+/ce9c3bB0xzXmLx sN3GX0BocdWejMo1U8+/+CVUngtol81BAb+k4GB5mPjW08u5jFVZu+XwxhK2ACx3 y3hAuaGd1d0YuTztYav7+wuu5gPwhYSA3/tmTR1+0jx9uCQbPpOyPJmprt/9A2DP TY0T0I3TUJqWZAtHOsY0P0hCGl+gZQJb8KhjVKHC6t6/ab3grMkpHgp9XDVvKpHJ u9lPDCuQRyJBSy9WI2Qa =t4YN -----END PGP SIGNATURE----- Merge tag 'signed-kvm-ppc-next' of git://github.com/agraf/linux-2.6 into kvm-next Patch queue for ppc - 2014-05-30 In this round we have a few nice gems. PR KVM gains initial POWER8 support as well as LE host awareness, ihe e500 targets can now properly run u-boot, LE guests now work with PR KVM including KVM hypercalls and HV KVM guests can now use huge pages. On top of this there are some bug fixes. Conflicts: include/uapi/linux/kvm.h
This commit is contained in:
commit
53ea2e462e
@ -1794,6 +1794,11 @@ registers, find a list below:
|
||||
PPC | KVM_REG_PPC_MMCR0 | 64
|
||||
PPC | KVM_REG_PPC_MMCR1 | 64
|
||||
PPC | KVM_REG_PPC_MMCRA | 64
|
||||
PPC | KVM_REG_PPC_MMCR2 | 64
|
||||
PPC | KVM_REG_PPC_MMCRS | 64
|
||||
PPC | KVM_REG_PPC_SIAR | 64
|
||||
PPC | KVM_REG_PPC_SDAR | 64
|
||||
PPC | KVM_REG_PPC_SIER | 64
|
||||
PPC | KVM_REG_PPC_PMC1 | 32
|
||||
PPC | KVM_REG_PPC_PMC2 | 32
|
||||
PPC | KVM_REG_PPC_PMC3 | 32
|
||||
@ -1868,6 +1873,7 @@ registers, find a list below:
|
||||
PPC | KVM_REG_PPC_PPR | 64
|
||||
PPC | KVM_REG_PPC_ARCH_COMPAT 32
|
||||
PPC | KVM_REG_PPC_DABRX | 32
|
||||
PPC | KVM_REG_PPC_WORT | 64
|
||||
PPC | KVM_REG_PPC_TM_GPR0 | 64
|
||||
...
|
||||
PPC | KVM_REG_PPC_TM_GPR31 | 64
|
||||
|
@ -94,10 +94,24 @@ a bitmap of available features inside the magic page.
|
||||
The following enhancements to the magic page are currently available:
|
||||
|
||||
KVM_MAGIC_FEAT_SR Maps SR registers r/w in the magic page
|
||||
KVM_MAGIC_FEAT_MAS0_TO_SPRG7 Maps MASn, ESR, PIR and high SPRGs
|
||||
|
||||
For enhanced features in the magic page, please check for the existence of the
|
||||
feature before using them!
|
||||
|
||||
Magic page flags
|
||||
================
|
||||
|
||||
In addition to features that indicate whether a host is capable of a particular
|
||||
feature we also have a channel for a guest to tell the guest whether it's capable
|
||||
of something. This is what we call "flags".
|
||||
|
||||
Flags are passed to the host in the low 12 bits of the Effective Address.
|
||||
|
||||
The following flags are currently available for a guest to expose:
|
||||
|
||||
MAGIC_PAGE_FLAG_NOT_MAPPED_NX Guest handles NX bits correclty wrt magic page
|
||||
|
||||
MSR bits
|
||||
========
|
||||
|
||||
|
@ -81,4 +81,38 @@ static inline unsigned int get_oc(u32 inst)
|
||||
{
|
||||
return (inst >> 11) & 0x7fff;
|
||||
}
|
||||
|
||||
#define IS_XFORM(inst) (get_op(inst) == 31)
|
||||
#define IS_DSFORM(inst) (get_op(inst) >= 56)
|
||||
|
||||
/*
|
||||
* Create a DSISR value from the instruction
|
||||
*/
|
||||
static inline unsigned make_dsisr(unsigned instr)
|
||||
{
|
||||
unsigned dsisr;
|
||||
|
||||
|
||||
/* bits 6:15 --> 22:31 */
|
||||
dsisr = (instr & 0x03ff0000) >> 16;
|
||||
|
||||
if (IS_XFORM(instr)) {
|
||||
/* bits 29:30 --> 15:16 */
|
||||
dsisr |= (instr & 0x00000006) << 14;
|
||||
/* bit 25 --> 17 */
|
||||
dsisr |= (instr & 0x00000040) << 8;
|
||||
/* bits 21:24 --> 18:21 */
|
||||
dsisr |= (instr & 0x00000780) << 3;
|
||||
} else {
|
||||
/* bit 5 --> 17 */
|
||||
dsisr |= (instr & 0x04000000) >> 12;
|
||||
/* bits 1: 4 --> 18:21 */
|
||||
dsisr |= (instr & 0x78000000) >> 17;
|
||||
/* bits 30:31 --> 12:13 */
|
||||
if (IS_DSFORM(instr))
|
||||
dsisr |= (instr & 0x00000003) << 18;
|
||||
}
|
||||
|
||||
return dsisr;
|
||||
}
|
||||
#endif /* __ASM_PPC_DISASSEMBLE_H__ */
|
||||
|
@ -102,6 +102,7 @@
|
||||
#define BOOK3S_INTERRUPT_PERFMON 0xf00
|
||||
#define BOOK3S_INTERRUPT_ALTIVEC 0xf20
|
||||
#define BOOK3S_INTERRUPT_VSX 0xf40
|
||||
#define BOOK3S_INTERRUPT_FAC_UNAVAIL 0xf60
|
||||
#define BOOK3S_INTERRUPT_H_FAC_UNAVAIL 0xf80
|
||||
|
||||
#define BOOK3S_IRQPRIO_SYSTEM_RESET 0
|
||||
@ -114,14 +115,15 @@
|
||||
#define BOOK3S_IRQPRIO_FP_UNAVAIL 7
|
||||
#define BOOK3S_IRQPRIO_ALTIVEC 8
|
||||
#define BOOK3S_IRQPRIO_VSX 9
|
||||
#define BOOK3S_IRQPRIO_SYSCALL 10
|
||||
#define BOOK3S_IRQPRIO_MACHINE_CHECK 11
|
||||
#define BOOK3S_IRQPRIO_DEBUG 12
|
||||
#define BOOK3S_IRQPRIO_EXTERNAL 13
|
||||
#define BOOK3S_IRQPRIO_DECREMENTER 14
|
||||
#define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15
|
||||
#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 16
|
||||
#define BOOK3S_IRQPRIO_MAX 17
|
||||
#define BOOK3S_IRQPRIO_FAC_UNAVAIL 10
|
||||
#define BOOK3S_IRQPRIO_SYSCALL 11
|
||||
#define BOOK3S_IRQPRIO_MACHINE_CHECK 12
|
||||
#define BOOK3S_IRQPRIO_DEBUG 13
|
||||
#define BOOK3S_IRQPRIO_EXTERNAL 14
|
||||
#define BOOK3S_IRQPRIO_DECREMENTER 15
|
||||
#define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 16
|
||||
#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 17
|
||||
#define BOOK3S_IRQPRIO_MAX 18
|
||||
|
||||
#define BOOK3S_HFLAG_DCBZ32 0x1
|
||||
#define BOOK3S_HFLAG_SLB 0x2
|
||||
|
@ -268,9 +268,10 @@ static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
|
||||
return vcpu->arch.pc;
|
||||
}
|
||||
|
||||
static inline u64 kvmppc_get_msr(struct kvm_vcpu *vcpu);
|
||||
static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return (vcpu->arch.shared->msr & MSR_LE) != (MSR_KERNEL & MSR_LE);
|
||||
return (kvmppc_get_msr(vcpu) & MSR_LE) != (MSR_KERNEL & MSR_LE);
|
||||
}
|
||||
|
||||
static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu, ulong pc)
|
||||
|
@ -77,34 +77,122 @@ static inline long try_lock_hpte(unsigned long *hpte, unsigned long bits)
|
||||
return old == 0;
|
||||
}
|
||||
|
||||
static inline int __hpte_actual_psize(unsigned int lp, int psize)
|
||||
{
|
||||
int i, shift;
|
||||
unsigned int mask;
|
||||
|
||||
/* start from 1 ignoring MMU_PAGE_4K */
|
||||
for (i = 1; i < MMU_PAGE_COUNT; i++) {
|
||||
|
||||
/* invalid penc */
|
||||
if (mmu_psize_defs[psize].penc[i] == -1)
|
||||
continue;
|
||||
/*
|
||||
* encoding bits per actual page size
|
||||
* PTE LP actual page size
|
||||
* rrrr rrrz >=8KB
|
||||
* rrrr rrzz >=16KB
|
||||
* rrrr rzzz >=32KB
|
||||
* rrrr zzzz >=64KB
|
||||
* .......
|
||||
*/
|
||||
shift = mmu_psize_defs[i].shift - LP_SHIFT;
|
||||
if (shift > LP_BITS)
|
||||
shift = LP_BITS;
|
||||
mask = (1 << shift) - 1;
|
||||
if ((lp & mask) == mmu_psize_defs[psize].penc[i])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
|
||||
unsigned long pte_index)
|
||||
{
|
||||
unsigned long rb, va_low;
|
||||
int b_psize, a_psize;
|
||||
unsigned int penc;
|
||||
unsigned long rb = 0, va_low, sllp;
|
||||
unsigned int lp = (r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
|
||||
|
||||
if (!(v & HPTE_V_LARGE)) {
|
||||
/* both base and actual psize is 4k */
|
||||
b_psize = MMU_PAGE_4K;
|
||||
a_psize = MMU_PAGE_4K;
|
||||
} else {
|
||||
for (b_psize = 0; b_psize < MMU_PAGE_COUNT; b_psize++) {
|
||||
|
||||
/* valid entries have a shift value */
|
||||
if (!mmu_psize_defs[b_psize].shift)
|
||||
continue;
|
||||
|
||||
a_psize = __hpte_actual_psize(lp, b_psize);
|
||||
if (a_psize != -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Ignore the top 14 bits of va
|
||||
* v have top two bits covering segment size, hence move
|
||||
* by 16 bits, Also clear the lower HPTE_V_AVPN_SHIFT (7) bits.
|
||||
* AVA field in v also have the lower 23 bits ignored.
|
||||
* For base page size 4K we need 14 .. 65 bits (so need to
|
||||
* collect extra 11 bits)
|
||||
* For others we need 14..14+i
|
||||
*/
|
||||
/* This covers 14..54 bits of va*/
|
||||
rb = (v & ~0x7fUL) << 16; /* AVA field */
|
||||
/*
|
||||
* AVA in v had cleared lower 23 bits. We need to derive
|
||||
* that from pteg index
|
||||
*/
|
||||
va_low = pte_index >> 3;
|
||||
if (v & HPTE_V_SECONDARY)
|
||||
va_low = ~va_low;
|
||||
/* xor vsid from AVA */
|
||||
/*
|
||||
* get the vpn bits from va_low using reverse of hashing.
|
||||
* In v we have va with 23 bits dropped and then left shifted
|
||||
* HPTE_V_AVPN_SHIFT (7) bits. Now to find vsid we need
|
||||
* right shift it with (SID_SHIFT - (23 - 7))
|
||||
*/
|
||||
if (!(v & HPTE_V_1TB_SEG))
|
||||
va_low ^= v >> 12;
|
||||
va_low ^= v >> (SID_SHIFT - 16);
|
||||
else
|
||||
va_low ^= v >> 24;
|
||||
va_low ^= v >> (SID_SHIFT_1T - 16);
|
||||
va_low &= 0x7ff;
|
||||
if (v & HPTE_V_LARGE) {
|
||||
rb |= 1; /* L field */
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_206) &&
|
||||
(r & 0xff000)) {
|
||||
/* non-16MB large page, must be 64k */
|
||||
/* (masks depend on page size) */
|
||||
rb |= 0x1000; /* page encoding in LP field */
|
||||
rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
|
||||
rb |= ((va_low << 4) & 0xf0); /* AVAL field (P7 doesn't seem to care) */
|
||||
}
|
||||
} else {
|
||||
/* 4kB page */
|
||||
rb |= (va_low & 0x7ff) << 12; /* remaining 11b of VA */
|
||||
|
||||
switch (b_psize) {
|
||||
case MMU_PAGE_4K:
|
||||
sllp = ((mmu_psize_defs[a_psize].sllp & SLB_VSID_L) >> 6) |
|
||||
((mmu_psize_defs[a_psize].sllp & SLB_VSID_LP) >> 4);
|
||||
rb |= sllp << 5; /* AP field */
|
||||
rb |= (va_low & 0x7ff) << 12; /* remaining 11 bits of AVA */
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int aval_shift;
|
||||
/*
|
||||
* remaining 7bits of AVA/LP fields
|
||||
* Also contain the rr bits of LP
|
||||
*/
|
||||
rb |= (va_low & 0x7f) << 16;
|
||||
/*
|
||||
* Now clear not needed LP bits based on actual psize
|
||||
*/
|
||||
rb &= ~((1ul << mmu_psize_defs[a_psize].shift) - 1);
|
||||
/*
|
||||
* AVAL field 58..77 - base_page_shift bits of va
|
||||
* we have space for 58..64 bits, Missing bits should
|
||||
* be zero filled. +1 is to take care of L bit shift
|
||||
*/
|
||||
aval_shift = 64 - (77 - mmu_psize_defs[b_psize].shift) + 1;
|
||||
rb |= ((va_low << aval_shift) & 0xfe);
|
||||
|
||||
rb |= 1; /* L field */
|
||||
penc = mmu_psize_defs[b_psize].penc[a_psize];
|
||||
rb |= penc << 12; /* LP field */
|
||||
break;
|
||||
}
|
||||
}
|
||||
rb |= (v >> 54) & 0x300; /* B field */
|
||||
return rb;
|
||||
@ -112,14 +200,26 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
|
||||
|
||||
static inline unsigned long hpte_page_size(unsigned long h, unsigned long l)
|
||||
{
|
||||
int size, a_psize;
|
||||
/* Look at the 8 bit LP value */
|
||||
unsigned int lp = (l >> LP_SHIFT) & ((1 << LP_BITS) - 1);
|
||||
|
||||
/* only handle 4k, 64k and 16M pages for now */
|
||||
if (!(h & HPTE_V_LARGE))
|
||||
return 1ul << 12; /* 4k page */
|
||||
if ((l & 0xf000) == 0x1000 && cpu_has_feature(CPU_FTR_ARCH_206))
|
||||
return 1ul << 16; /* 64k page */
|
||||
if ((l & 0xff000) == 0)
|
||||
return 1ul << 24; /* 16M page */
|
||||
return 0; /* error */
|
||||
return 1ul << 12;
|
||||
else {
|
||||
for (size = 0; size < MMU_PAGE_COUNT; size++) {
|
||||
/* valid entries have a shift value */
|
||||
if (!mmu_psize_defs[size].shift)
|
||||
continue;
|
||||
|
||||
a_psize = __hpte_actual_psize(lp, size);
|
||||
if (a_psize != -1)
|
||||
return 1ul << mmu_psize_defs[a_psize].shift;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long hpte_rpn(unsigned long ptel, unsigned long psize)
|
||||
|
@ -104,6 +104,7 @@ struct kvmppc_host_state {
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
u64 cfar;
|
||||
u64 ppr;
|
||||
u64 host_fscr;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -133,6 +134,7 @@ struct kvmppc_book3s_shadow_vcpu {
|
||||
u64 esid;
|
||||
u64 vsid;
|
||||
} slb[64]; /* guest SLB */
|
||||
u64 shadow_fscr;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -108,9 +108,4 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.fault_dear;
|
||||
}
|
||||
|
||||
static inline ulong kvmppc_get_msr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu->arch.shared->msr;
|
||||
}
|
||||
#endif /* __ASM_KVM_BOOKE_H__ */
|
||||
|
@ -449,7 +449,9 @@ struct kvm_vcpu_arch {
|
||||
ulong pc;
|
||||
ulong ctr;
|
||||
ulong lr;
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
ulong tar;
|
||||
#endif
|
||||
|
||||
ulong xer;
|
||||
u32 cr;
|
||||
@ -475,6 +477,7 @@ struct kvm_vcpu_arch {
|
||||
ulong ppr;
|
||||
ulong pspb;
|
||||
ulong fscr;
|
||||
ulong shadow_fscr;
|
||||
ulong ebbhr;
|
||||
ulong ebbrr;
|
||||
ulong bescr;
|
||||
@ -562,6 +565,7 @@ struct kvm_vcpu_arch {
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
ulong fault_dar;
|
||||
u32 fault_dsisr;
|
||||
unsigned long intr_msr;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOKE
|
||||
@ -622,8 +626,12 @@ struct kvm_vcpu_arch {
|
||||
wait_queue_head_t cpu_run;
|
||||
|
||||
struct kvm_vcpu_arch_shared *shared;
|
||||
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
|
||||
bool shared_big_endian;
|
||||
#endif
|
||||
unsigned long magic_page_pa; /* phys addr to map the magic page to */
|
||||
unsigned long magic_page_ea; /* effect. addr to map the magic page to */
|
||||
bool disable_kernel_nx;
|
||||
|
||||
int irq_type; /* one of KVM_IRQ_* */
|
||||
int irq_cpu_id;
|
||||
@ -654,7 +662,6 @@ struct kvm_vcpu_arch {
|
||||
spinlock_t tbacct_lock;
|
||||
u64 busy_stolen;
|
||||
u64 busy_preempt;
|
||||
unsigned long intr_msr;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -448,6 +448,84 @@ static inline void kvmppc_mmu_flush_icache(pfn_t pfn)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shared struct helpers. The shared struct can be little or big endian,
|
||||
* depending on the guest endianness. So expose helpers to all of them.
|
||||
*/
|
||||
static inline bool kvmppc_shared_big_endian(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
|
||||
/* Only Book3S_64 PR supports bi-endian for now */
|
||||
return vcpu->arch.shared_big_endian;
|
||||
#elif defined(CONFIG_PPC_BOOK3S_64) && defined(__LITTLE_ENDIAN__)
|
||||
/* Book3s_64 HV on little endian is always little endian */
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SHARED_WRAPPER_GET(reg, size) \
|
||||
static inline u##size kvmppc_get_##reg(struct kvm_vcpu *vcpu) \
|
||||
{ \
|
||||
if (kvmppc_shared_big_endian(vcpu)) \
|
||||
return be##size##_to_cpu(vcpu->arch.shared->reg); \
|
||||
else \
|
||||
return le##size##_to_cpu(vcpu->arch.shared->reg); \
|
||||
} \
|
||||
|
||||
#define SHARED_WRAPPER_SET(reg, size) \
|
||||
static inline void kvmppc_set_##reg(struct kvm_vcpu *vcpu, u##size val) \
|
||||
{ \
|
||||
if (kvmppc_shared_big_endian(vcpu)) \
|
||||
vcpu->arch.shared->reg = cpu_to_be##size(val); \
|
||||
else \
|
||||
vcpu->arch.shared->reg = cpu_to_le##size(val); \
|
||||
} \
|
||||
|
||||
#define SHARED_WRAPPER(reg, size) \
|
||||
SHARED_WRAPPER_GET(reg, size) \
|
||||
SHARED_WRAPPER_SET(reg, size) \
|
||||
|
||||
SHARED_WRAPPER(critical, 64)
|
||||
SHARED_WRAPPER(sprg0, 64)
|
||||
SHARED_WRAPPER(sprg1, 64)
|
||||
SHARED_WRAPPER(sprg2, 64)
|
||||
SHARED_WRAPPER(sprg3, 64)
|
||||
SHARED_WRAPPER(srr0, 64)
|
||||
SHARED_WRAPPER(srr1, 64)
|
||||
SHARED_WRAPPER(dar, 64)
|
||||
SHARED_WRAPPER_GET(msr, 64)
|
||||
static inline void kvmppc_set_msr_fast(struct kvm_vcpu *vcpu, u64 val)
|
||||
{
|
||||
if (kvmppc_shared_big_endian(vcpu))
|
||||
vcpu->arch.shared->msr = cpu_to_be64(val);
|
||||
else
|
||||
vcpu->arch.shared->msr = cpu_to_le64(val);
|
||||
}
|
||||
SHARED_WRAPPER(dsisr, 32)
|
||||
SHARED_WRAPPER(int_pending, 32)
|
||||
SHARED_WRAPPER(sprg4, 64)
|
||||
SHARED_WRAPPER(sprg5, 64)
|
||||
SHARED_WRAPPER(sprg6, 64)
|
||||
SHARED_WRAPPER(sprg7, 64)
|
||||
|
||||
static inline u32 kvmppc_get_sr(struct kvm_vcpu *vcpu, int nr)
|
||||
{
|
||||
if (kvmppc_shared_big_endian(vcpu))
|
||||
return be32_to_cpu(vcpu->arch.shared->sr[nr]);
|
||||
else
|
||||
return le32_to_cpu(vcpu->arch.shared->sr[nr]);
|
||||
}
|
||||
|
||||
static inline void kvmppc_set_sr(struct kvm_vcpu *vcpu, int nr, u32 val)
|
||||
{
|
||||
if (kvmppc_shared_big_endian(vcpu))
|
||||
vcpu->arch.shared->sr[nr] = cpu_to_be32(val);
|
||||
else
|
||||
vcpu->arch.shared->sr[nr] = cpu_to_le32(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Please call after prepare_to_enter. This function puts the lazy ee and irq
|
||||
* disabled tracking state back to normal mode, without actually enabling
|
||||
@ -485,7 +563,7 @@ static inline ulong kvmppc_get_ea_indexed(struct kvm_vcpu *vcpu, int ra, int rb)
|
||||
msr_64bit = MSR_SF;
|
||||
#endif
|
||||
|
||||
if (!(vcpu->arch.shared->msr & msr_64bit))
|
||||
if (!(kvmppc_get_msr(vcpu) & msr_64bit))
|
||||
ea = (uint32_t)ea;
|
||||
|
||||
return ea;
|
||||
|
@ -670,18 +670,20 @@
|
||||
#define MMCR0_PROBLEM_DISABLE MMCR0_FCP
|
||||
#define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */
|
||||
#define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */
|
||||
#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */
|
||||
#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */
|
||||
#define MMCR0_PMXE ASM_CONST(0x04000000) /* perf mon exception enable */
|
||||
#define MMCR0_FCECE ASM_CONST(0x02000000) /* freeze ctrs on enabled cond or event */
|
||||
#define MMCR0_TBEE 0x00400000UL /* time base exception enable */
|
||||
#define MMCR0_BHRBA 0x00200000UL /* BHRB Access allowed in userspace */
|
||||
#define MMCR0_EBE 0x00100000UL /* Event based branch enable */
|
||||
#define MMCR0_PMCC 0x000c0000UL /* PMC control */
|
||||
#define MMCR0_PMCC_U6 0x00080000UL /* PMC1-6 are R/W by user (PR) */
|
||||
#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
|
||||
#define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/
|
||||
#define MMCR0_PMCjCE ASM_CONST(0x00004000) /* PMCj count enable*/
|
||||
#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */
|
||||
#define MMCR0_PMAO_SYNC 0x00000800UL /* PMU interrupt is synchronous */
|
||||
#define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */
|
||||
#define MMCR0_PMAO_SYNC ASM_CONST(0x00000800) /* PMU intr is synchronous */
|
||||
#define MMCR0_C56RUN ASM_CONST(0x00000100) /* PMC5/6 count when RUN=0 */
|
||||
/* performance monitor alert has occurred, set to 0 after handling exception */
|
||||
#define MMCR0_PMAO ASM_CONST(0x00000080)
|
||||
#define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */
|
||||
#define MMCR0_FC56 0x00000010UL /* freeze counters 5 and 6 */
|
||||
#define MMCR0_FCTI 0x00000008UL /* freeze counters in tags inactive mode */
|
||||
|
@ -583,6 +583,7 @@
|
||||
|
||||
/* Bit definitions for L1CSR0. */
|
||||
#define L1CSR0_CPE 0x00010000 /* Data Cache Parity Enable */
|
||||
#define L1CSR0_CUL 0x00000400 /* Data Cache Unable to Lock */
|
||||
#define L1CSR0_CLFC 0x00000100 /* Cache Lock Bits Flash Clear */
|
||||
#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */
|
||||
#define L1CSR0_CFI 0x00000002 /* Cache Flash Invalidate */
|
||||
|
@ -545,7 +545,6 @@ struct kvm_get_htab_header {
|
||||
#define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1)
|
||||
#define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2)
|
||||
#define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3)
|
||||
#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb4)
|
||||
|
||||
#define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
|
||||
#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
|
||||
@ -555,6 +554,7 @@ struct kvm_get_htab_header {
|
||||
#define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
|
||||
|
||||
#define KVM_REG_PPC_DABRX (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8)
|
||||
#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9)
|
||||
|
||||
/* Transactional Memory checkpointed state:
|
||||
* This is all GPRs, all VSX regs and a subset of SPRs
|
||||
|
@ -82,10 +82,16 @@ struct kvm_vcpu_arch_shared {
|
||||
|
||||
#define KVM_FEATURE_MAGIC_PAGE 1
|
||||
|
||||
/* Magic page flags from host to guest */
|
||||
|
||||
#define KVM_MAGIC_FEAT_SR (1 << 0)
|
||||
|
||||
/* MASn, ESR, PIR, and high SPRGs */
|
||||
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
|
||||
|
||||
/* Magic page flags from guest to host */
|
||||
|
||||
#define MAGIC_PAGE_FLAG_NOT_MAPPED_NX (1 << 0)
|
||||
|
||||
|
||||
#endif /* _UAPI__POWERPC_KVM_PARA_H__ */
|
||||
|
@ -25,14 +25,13 @@
|
||||
#include <asm/cputable.h>
|
||||
#include <asm/emulated_ops.h>
|
||||
#include <asm/switch_to.h>
|
||||
#include <asm/disassemble.h>
|
||||
|
||||
struct aligninfo {
|
||||
unsigned char len;
|
||||
unsigned char flags;
|
||||
};
|
||||
|
||||
#define IS_XFORM(inst) (((inst) >> 26) == 31)
|
||||
#define IS_DSFORM(inst) (((inst) >> 26) >= 56)
|
||||
|
||||
#define INVALID { 0, 0 }
|
||||
|
||||
@ -191,37 +190,6 @@ static struct aligninfo aligninfo[128] = {
|
||||
INVALID, /* 11 1 1111 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a DSISR value from the instruction
|
||||
*/
|
||||
static inline unsigned make_dsisr(unsigned instr)
|
||||
{
|
||||
unsigned dsisr;
|
||||
|
||||
|
||||
/* bits 6:15 --> 22:31 */
|
||||
dsisr = (instr & 0x03ff0000) >> 16;
|
||||
|
||||
if (IS_XFORM(instr)) {
|
||||
/* bits 29:30 --> 15:16 */
|
||||
dsisr |= (instr & 0x00000006) << 14;
|
||||
/* bit 25 --> 17 */
|
||||
dsisr |= (instr & 0x00000040) << 8;
|
||||
/* bits 21:24 --> 18:21 */
|
||||
dsisr |= (instr & 0x00000780) << 3;
|
||||
} else {
|
||||
/* bit 5 --> 17 */
|
||||
dsisr |= (instr & 0x04000000) >> 12;
|
||||
/* bits 1: 4 --> 18:21 */
|
||||
dsisr |= (instr & 0x78000000) >> 17;
|
||||
/* bits 30:31 --> 12:13 */
|
||||
if (IS_DSFORM(instr))
|
||||
dsisr |= (instr & 0x00000003) << 18;
|
||||
}
|
||||
|
||||
return dsisr;
|
||||
}
|
||||
|
||||
/*
|
||||
* The dcbz (data cache block zero) instruction
|
||||
* gives an alignment fault if used on non-cacheable
|
||||
|
@ -54,6 +54,7 @@
|
||||
#endif
|
||||
#if defined(CONFIG_KVM) && defined(CONFIG_PPC_BOOK3S)
|
||||
#include <asm/kvm_book3s.h>
|
||||
#include <asm/kvm_ppc.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
@ -445,7 +446,9 @@ int main(void)
|
||||
DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
|
||||
DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
|
||||
DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
DEFINE(VCPU_TAR, offsetof(struct kvm_vcpu, arch.tar));
|
||||
#endif
|
||||
DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
|
||||
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
@ -467,6 +470,9 @@ int main(void)
|
||||
DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared));
|
||||
DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
|
||||
DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr));
|
||||
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
|
||||
DEFINE(VCPU_SHAREDBE, offsetof(struct kvm_vcpu, arch.shared_big_endian));
|
||||
#endif
|
||||
|
||||
DEFINE(VCPU_SHARED_MAS0, offsetof(struct kvm_vcpu_arch_shared, mas0));
|
||||
DEFINE(VCPU_SHARED_MAS1, offsetof(struct kvm_vcpu_arch_shared, mas1));
|
||||
@ -493,7 +499,6 @@ int main(void)
|
||||
DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
|
||||
DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
|
||||
DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty));
|
||||
DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
|
||||
@ -528,11 +533,13 @@ int main(void)
|
||||
DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
|
||||
DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
|
||||
DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
|
||||
DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
|
||||
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
|
||||
DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
|
||||
DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
|
||||
DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
|
||||
DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr));
|
||||
DEFINE(VCPU_SHADOW_FSCR, offsetof(struct kvm_vcpu, arch.shadow_fscr));
|
||||
DEFINE(VCPU_PSPB, offsetof(struct kvm_vcpu, arch.pspb));
|
||||
DEFINE(VCPU_EBBHR, offsetof(struct kvm_vcpu, arch.ebbhr));
|
||||
DEFINE(VCPU_EBBRR, offsetof(struct kvm_vcpu, arch.ebbrr));
|
||||
@ -614,6 +621,7 @@ int main(void)
|
||||
#ifdef CONFIG_PPC64
|
||||
SVCPU_FIELD(SVCPU_SLB, slb);
|
||||
SVCPU_FIELD(SVCPU_SLB_MAX, slb_max);
|
||||
SVCPU_FIELD(SVCPU_SHADOW_FSCR, shadow_fscr);
|
||||
#endif
|
||||
|
||||
HSTATE_FIELD(HSTATE_HOST_R1, host_r1);
|
||||
@ -649,6 +657,7 @@ int main(void)
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
HSTATE_FIELD(HSTATE_CFAR, cfar);
|
||||
HSTATE_FIELD(HSTATE_PPR, ppr);
|
||||
HSTATE_FIELD(HSTATE_HOST_FSCR, host_fscr);
|
||||
#endif /* CONFIG_PPC_BOOK3S_64 */
|
||||
|
||||
#else /* CONFIG_PPC_BOOK3S */
|
||||
|
@ -47,9 +47,10 @@ static int __init early_init_dt_scan_epapr(unsigned long node,
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < (len / 4); i++) {
|
||||
patch_instruction(epapr_hypercall_start + i, insts[i]);
|
||||
u32 inst = be32_to_cpu(insts[i]);
|
||||
patch_instruction(epapr_hypercall_start + i, inst);
|
||||
#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
|
||||
patch_instruction(epapr_ev_idle_start + i, insts[i]);
|
||||
patch_instruction(epapr_ev_idle_start + i, inst);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -417,7 +417,7 @@ static void kvm_map_magic_page(void *data)
|
||||
ulong out[8];
|
||||
|
||||
in[0] = KVM_MAGIC_PAGE;
|
||||
in[1] = KVM_MAGIC_PAGE;
|
||||
in[1] = KVM_MAGIC_PAGE | MAGIC_PAGE_FLAG_NOT_MAPPED_NX;
|
||||
|
||||
epapr_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE));
|
||||
|
||||
|
@ -98,6 +98,9 @@ static inline void free_lppacas(void) { }
|
||||
/*
|
||||
* 3 persistent SLBs are registered here. The buffer will be zero
|
||||
* initially, hence will all be invaild until we actually write them.
|
||||
*
|
||||
* If you make the number of persistent SLB entries dynamic, please also
|
||||
* update PR KVM to flush and restore them accordingly.
|
||||
*/
|
||||
static struct slb_shadow *slb_shadow;
|
||||
|
||||
|
@ -6,7 +6,6 @@ source "virt/kvm/Kconfig"
|
||||
|
||||
menuconfig VIRTUALIZATION
|
||||
bool "Virtualization"
|
||||
depends on !CPU_LITTLE_ENDIAN
|
||||
---help---
|
||||
Say Y here to get to see options for using your Linux host to run
|
||||
other operating systems inside virtual machines (guests).
|
||||
@ -76,6 +75,7 @@ config KVM_BOOK3S_64
|
||||
config KVM_BOOK3S_64_HV
|
||||
tristate "KVM support for POWER7 and PPC970 using hypervisor mode in host"
|
||||
depends on KVM_BOOK3S_64
|
||||
depends on !CPU_LITTLE_ENDIAN
|
||||
select KVM_BOOK3S_HV_POSSIBLE
|
||||
select MMU_NOTIFIER
|
||||
select CMA
|
||||
|
@ -85,9 +85,9 @@ static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu,
|
||||
if (is_kvmppc_hv_enabled(vcpu->kvm))
|
||||
return;
|
||||
if (pending_now)
|
||||
vcpu->arch.shared->int_pending = 1;
|
||||
kvmppc_set_int_pending(vcpu, 1);
|
||||
else if (old_pending)
|
||||
vcpu->arch.shared->int_pending = 0;
|
||||
kvmppc_set_int_pending(vcpu, 0);
|
||||
}
|
||||
|
||||
static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
|
||||
@ -99,11 +99,11 @@ static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
|
||||
if (is_kvmppc_hv_enabled(vcpu->kvm))
|
||||
return false;
|
||||
|
||||
crit_raw = vcpu->arch.shared->critical;
|
||||
crit_raw = kvmppc_get_critical(vcpu);
|
||||
crit_r1 = kvmppc_get_gpr(vcpu, 1);
|
||||
|
||||
/* Truncate crit indicators in 32 bit mode */
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF)) {
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_SF)) {
|
||||
crit_raw &= 0xffffffff;
|
||||
crit_r1 &= 0xffffffff;
|
||||
}
|
||||
@ -111,15 +111,15 @@ static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
|
||||
/* Critical section when crit == r1 */
|
||||
crit = (crit_raw == crit_r1);
|
||||
/* ... and we're in supervisor mode */
|
||||
crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
|
||||
crit = crit && !(kvmppc_get_msr(vcpu) & MSR_PR);
|
||||
|
||||
return crit;
|
||||
}
|
||||
|
||||
void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
|
||||
{
|
||||
vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu);
|
||||
vcpu->arch.shared->srr1 = vcpu->arch.shared->msr | flags;
|
||||
kvmppc_set_srr0(vcpu, kvmppc_get_pc(vcpu));
|
||||
kvmppc_set_srr1(vcpu, kvmppc_get_msr(vcpu) | flags);
|
||||
kvmppc_set_pc(vcpu, kvmppc_interrupt_offset(vcpu) + vec);
|
||||
vcpu->arch.mmu.reset_msr(vcpu);
|
||||
}
|
||||
@ -145,6 +145,7 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec)
|
||||
case 0xd00: prio = BOOK3S_IRQPRIO_DEBUG; break;
|
||||
case 0xf20: prio = BOOK3S_IRQPRIO_ALTIVEC; break;
|
||||
case 0xf40: prio = BOOK3S_IRQPRIO_VSX; break;
|
||||
case 0xf60: prio = BOOK3S_IRQPRIO_FAC_UNAVAIL; break;
|
||||
default: prio = BOOK3S_IRQPRIO_MAX; break;
|
||||
}
|
||||
|
||||
@ -225,12 +226,12 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
|
||||
|
||||
switch (priority) {
|
||||
case BOOK3S_IRQPRIO_DECREMENTER:
|
||||
deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
|
||||
deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit;
|
||||
vec = BOOK3S_INTERRUPT_DECREMENTER;
|
||||
break;
|
||||
case BOOK3S_IRQPRIO_EXTERNAL:
|
||||
case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
|
||||
deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
|
||||
deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit;
|
||||
vec = BOOK3S_INTERRUPT_EXTERNAL;
|
||||
break;
|
||||
case BOOK3S_IRQPRIO_SYSTEM_RESET:
|
||||
@ -275,6 +276,9 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
|
||||
case BOOK3S_IRQPRIO_PERFORMANCE_MONITOR:
|
||||
vec = BOOK3S_INTERRUPT_PERFMON;
|
||||
break;
|
||||
case BOOK3S_IRQPRIO_FAC_UNAVAIL:
|
||||
vec = BOOK3S_INTERRUPT_FAC_UNAVAIL;
|
||||
break;
|
||||
default:
|
||||
deliver = 0;
|
||||
printk(KERN_ERR "KVM: Unknown interrupt: 0x%x\n", priority);
|
||||
@ -343,7 +347,7 @@ pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, bool writing,
|
||||
{
|
||||
ulong mp_pa = vcpu->arch.magic_page_pa;
|
||||
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF))
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_SF))
|
||||
mp_pa = (uint32_t)mp_pa;
|
||||
|
||||
/* Magic page override */
|
||||
@ -367,7 +371,7 @@ EXPORT_SYMBOL_GPL(kvmppc_gfn_to_pfn);
|
||||
static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
|
||||
bool iswrite, struct kvmppc_pte *pte)
|
||||
{
|
||||
int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR));
|
||||
int relocated = (kvmppc_get_msr(vcpu) & (data ? MSR_DR : MSR_IR));
|
||||
int r;
|
||||
|
||||
if (relocated) {
|
||||
@ -498,18 +502,18 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
||||
regs->ctr = kvmppc_get_ctr(vcpu);
|
||||
regs->lr = kvmppc_get_lr(vcpu);
|
||||
regs->xer = kvmppc_get_xer(vcpu);
|
||||
regs->msr = vcpu->arch.shared->msr;
|
||||
regs->srr0 = vcpu->arch.shared->srr0;
|
||||
regs->srr1 = vcpu->arch.shared->srr1;
|
||||
regs->msr = kvmppc_get_msr(vcpu);
|
||||
regs->srr0 = kvmppc_get_srr0(vcpu);
|
||||
regs->srr1 = kvmppc_get_srr1(vcpu);
|
||||
regs->pid = vcpu->arch.pid;
|
||||
regs->sprg0 = vcpu->arch.shared->sprg0;
|
||||
regs->sprg1 = vcpu->arch.shared->sprg1;
|
||||
regs->sprg2 = vcpu->arch.shared->sprg2;
|
||||
regs->sprg3 = vcpu->arch.shared->sprg3;
|
||||
regs->sprg4 = vcpu->arch.shared->sprg4;
|
||||
regs->sprg5 = vcpu->arch.shared->sprg5;
|
||||
regs->sprg6 = vcpu->arch.shared->sprg6;
|
||||
regs->sprg7 = vcpu->arch.shared->sprg7;
|
||||
regs->sprg0 = kvmppc_get_sprg0(vcpu);
|
||||
regs->sprg1 = kvmppc_get_sprg1(vcpu);
|
||||
regs->sprg2 = kvmppc_get_sprg2(vcpu);
|
||||
regs->sprg3 = kvmppc_get_sprg3(vcpu);
|
||||
regs->sprg4 = kvmppc_get_sprg4(vcpu);
|
||||
regs->sprg5 = kvmppc_get_sprg5(vcpu);
|
||||
regs->sprg6 = kvmppc_get_sprg6(vcpu);
|
||||
regs->sprg7 = kvmppc_get_sprg7(vcpu);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
|
||||
regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
|
||||
@ -527,16 +531,16 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
||||
kvmppc_set_lr(vcpu, regs->lr);
|
||||
kvmppc_set_xer(vcpu, regs->xer);
|
||||
kvmppc_set_msr(vcpu, regs->msr);
|
||||
vcpu->arch.shared->srr0 = regs->srr0;
|
||||
vcpu->arch.shared->srr1 = regs->srr1;
|
||||
vcpu->arch.shared->sprg0 = regs->sprg0;
|
||||
vcpu->arch.shared->sprg1 = regs->sprg1;
|
||||
vcpu->arch.shared->sprg2 = regs->sprg2;
|
||||
vcpu->arch.shared->sprg3 = regs->sprg3;
|
||||
vcpu->arch.shared->sprg4 = regs->sprg4;
|
||||
vcpu->arch.shared->sprg5 = regs->sprg5;
|
||||
vcpu->arch.shared->sprg6 = regs->sprg6;
|
||||
vcpu->arch.shared->sprg7 = regs->sprg7;
|
||||
kvmppc_set_srr0(vcpu, regs->srr0);
|
||||
kvmppc_set_srr1(vcpu, regs->srr1);
|
||||
kvmppc_set_sprg0(vcpu, regs->sprg0);
|
||||
kvmppc_set_sprg1(vcpu, regs->sprg1);
|
||||
kvmppc_set_sprg2(vcpu, regs->sprg2);
|
||||
kvmppc_set_sprg3(vcpu, regs->sprg3);
|
||||
kvmppc_set_sprg4(vcpu, regs->sprg4);
|
||||
kvmppc_set_sprg5(vcpu, regs->sprg5);
|
||||
kvmppc_set_sprg6(vcpu, regs->sprg6);
|
||||
kvmppc_set_sprg7(vcpu, regs->sprg7);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
|
||||
kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
|
||||
@ -570,10 +574,10 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
||||
r = 0;
|
||||
switch (reg->id) {
|
||||
case KVM_REG_PPC_DAR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.shared->dar);
|
||||
val = get_reg_val(reg->id, kvmppc_get_dar(vcpu));
|
||||
break;
|
||||
case KVM_REG_PPC_DSISR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.shared->dsisr);
|
||||
val = get_reg_val(reg->id, kvmppc_get_dsisr(vcpu));
|
||||
break;
|
||||
case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
|
||||
i = reg->id - KVM_REG_PPC_FPR0;
|
||||
@ -627,6 +631,21 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
||||
val = get_reg_val(reg->id, kvmppc_xics_get_icp(vcpu));
|
||||
break;
|
||||
#endif /* CONFIG_KVM_XICS */
|
||||
case KVM_REG_PPC_FSCR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.fscr);
|
||||
break;
|
||||
case KVM_REG_PPC_TAR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.tar);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBHR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.ebbhr);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBRR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.ebbrr);
|
||||
break;
|
||||
case KVM_REG_PPC_BESCR:
|
||||
val = get_reg_val(reg->id, vcpu->arch.bescr);
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
break;
|
||||
@ -660,10 +679,10 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
||||
r = 0;
|
||||
switch (reg->id) {
|
||||
case KVM_REG_PPC_DAR:
|
||||
vcpu->arch.shared->dar = set_reg_val(reg->id, val);
|
||||
kvmppc_set_dar(vcpu, set_reg_val(reg->id, val));
|
||||
break;
|
||||
case KVM_REG_PPC_DSISR:
|
||||
vcpu->arch.shared->dsisr = set_reg_val(reg->id, val);
|
||||
kvmppc_set_dsisr(vcpu, set_reg_val(reg->id, val));
|
||||
break;
|
||||
case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
|
||||
i = reg->id - KVM_REG_PPC_FPR0;
|
||||
@ -716,6 +735,21 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
|
||||
set_reg_val(reg->id, val));
|
||||
break;
|
||||
#endif /* CONFIG_KVM_XICS */
|
||||
case KVM_REG_PPC_FSCR:
|
||||
vcpu->arch.fscr = set_reg_val(reg->id, val);
|
||||
break;
|
||||
case KVM_REG_PPC_TAR:
|
||||
vcpu->arch.tar = set_reg_val(reg->id, val);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBHR:
|
||||
vcpu->arch.ebbhr = set_reg_val(reg->id, val);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBRR:
|
||||
vcpu->arch.ebbrr = set_reg_val(reg->id, val);
|
||||
break;
|
||||
case KVM_REG_PPC_BESCR:
|
||||
vcpu->arch.bescr = set_reg_val(reg->id, val);
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
break;
|
||||
|
@ -91,7 +91,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
|
||||
static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr)
|
||||
{
|
||||
return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf];
|
||||
return kvmppc_get_sr(vcpu, (eaddr >> 28) & 0xf);
|
||||
}
|
||||
|
||||
static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
@ -131,7 +131,7 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvm_vcpu *vcpu,
|
||||
pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash;
|
||||
|
||||
dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n",
|
||||
kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg,
|
||||
kvmppc_get_pc(vcpu), eaddr, vcpu_book3s->sdr1, pteg,
|
||||
sr_vsid(sre));
|
||||
|
||||
r = gfn_to_hva(vcpu->kvm, pteg >> PAGE_SHIFT);
|
||||
@ -160,7 +160,7 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
else
|
||||
bat = &vcpu_book3s->ibat[i];
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR) {
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR) {
|
||||
if (!bat->vp)
|
||||
continue;
|
||||
} else {
|
||||
@ -208,6 +208,7 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
u32 sre;
|
||||
hva_t ptegp;
|
||||
u32 pteg[16];
|
||||
u32 pte0, pte1;
|
||||
u32 ptem = 0;
|
||||
int i;
|
||||
int found = 0;
|
||||
@ -233,14 +234,16 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
}
|
||||
|
||||
for (i=0; i<16; i+=2) {
|
||||
if (ptem == pteg[i]) {
|
||||
pte0 = be32_to_cpu(pteg[i]);
|
||||
pte1 = be32_to_cpu(pteg[i + 1]);
|
||||
if (ptem == pte0) {
|
||||
u8 pp;
|
||||
|
||||
pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF);
|
||||
pp = pteg[i+1] & 3;
|
||||
pte->raddr = (pte1 & ~(0xFFFULL)) | (eaddr & 0xFFF);
|
||||
pp = pte1 & 3;
|
||||
|
||||
if ((sr_kp(sre) && (vcpu->arch.shared->msr & MSR_PR)) ||
|
||||
(sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR)))
|
||||
if ((sr_kp(sre) && (kvmppc_get_msr(vcpu) & MSR_PR)) ||
|
||||
(sr_ks(sre) && !(kvmppc_get_msr(vcpu) & MSR_PR)))
|
||||
pp |= 4;
|
||||
|
||||
pte->may_write = false;
|
||||
@ -260,7 +263,7 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
}
|
||||
|
||||
dprintk_pte("MMU: Found PTE -> %x %x - %x\n",
|
||||
pteg[i], pteg[i+1], pp);
|
||||
pte0, pte1, pp);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@ -269,8 +272,8 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
/* Update PTE C and A bits, so the guest's swapper knows we used the
|
||||
page */
|
||||
if (found) {
|
||||
u32 pte_r = pteg[i+1];
|
||||
char __user *addr = (char __user *) &pteg[i+1];
|
||||
u32 pte_r = pte1;
|
||||
char __user *addr = (char __user *) (ptegp + (i+1) * sizeof(u32));
|
||||
|
||||
/*
|
||||
* Use single-byte writes to update the HPTE, to
|
||||
@ -296,7 +299,8 @@ no_page_found:
|
||||
to_book3s(vcpu)->sdr1, ptegp);
|
||||
for (i=0; i<16; i+=2) {
|
||||
dprintk_pte(" %02d: 0x%x - 0x%x (0x%x)\n",
|
||||
i, pteg[i], pteg[i+1], ptem);
|
||||
i, be32_to_cpu(pteg[i]),
|
||||
be32_to_cpu(pteg[i+1]), ptem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +320,7 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
/* Magic page override */
|
||||
if (unlikely(mp_ea) &&
|
||||
unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
!(kvmppc_get_msr(vcpu) & MSR_PR)) {
|
||||
pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
|
||||
pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff);
|
||||
pte->raddr &= KVM_PAM;
|
||||
@ -341,13 +345,13 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
|
||||
static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum)
|
||||
{
|
||||
return vcpu->arch.shared->sr[srnum];
|
||||
return kvmppc_get_sr(vcpu, srnum);
|
||||
}
|
||||
|
||||
static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
|
||||
ulong value)
|
||||
{
|
||||
vcpu->arch.shared->sr[srnum] = value;
|
||||
kvmppc_set_sr(vcpu, srnum, value);
|
||||
kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT);
|
||||
}
|
||||
|
||||
@ -367,8 +371,9 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
ulong ea = esid << SID_SHIFT;
|
||||
u32 sr;
|
||||
u64 gvsid = esid;
|
||||
u64 msr = kvmppc_get_msr(vcpu);
|
||||
|
||||
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
if (msr & (MSR_DR|MSR_IR)) {
|
||||
sr = find_sr(vcpu, ea);
|
||||
if (sr_valid(sr))
|
||||
gvsid = sr_vsid(sr);
|
||||
@ -377,7 +382,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
/* In case we only have one of MSR_IR or MSR_DR set, let's put
|
||||
that in the real-mode context (and hope RM doesn't access
|
||||
high memory) */
|
||||
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
switch (msr & (MSR_DR|MSR_IR)) {
|
||||
case 0:
|
||||
*vsid = VSID_REAL | esid;
|
||||
break;
|
||||
@ -397,7 +402,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
if (msr & MSR_PR)
|
||||
*vsid |= VSID_PR;
|
||||
|
||||
return 0;
|
||||
|
@ -92,7 +92,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
struct kvmppc_sid_map *map;
|
||||
u16 sid_map_mask;
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
|
||||
@ -279,7 +279,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
u16 sid_map_mask;
|
||||
static int backwards_map = 0;
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
/* We might get collisions that trap in preceding order, so let's
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvmppc_set_msr(vcpu, MSR_SF);
|
||||
kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
|
||||
}
|
||||
|
||||
static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
|
||||
@ -226,7 +226,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
/* Magic page override */
|
||||
if (unlikely(mp_ea) &&
|
||||
unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
!(kvmppc_get_msr(vcpu) & MSR_PR)) {
|
||||
gpte->eaddr = eaddr;
|
||||
gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);
|
||||
gpte->raddr = vcpu->arch.magic_page_pa | (gpte->raddr & 0xfff);
|
||||
@ -269,18 +269,21 @@ do_second:
|
||||
goto no_page_found;
|
||||
}
|
||||
|
||||
if ((vcpu->arch.shared->msr & MSR_PR) && slbe->Kp)
|
||||
if ((kvmppc_get_msr(vcpu) & MSR_PR) && slbe->Kp)
|
||||
key = 4;
|
||||
else if (!(vcpu->arch.shared->msr & MSR_PR) && slbe->Ks)
|
||||
else if (!(kvmppc_get_msr(vcpu) & MSR_PR) && slbe->Ks)
|
||||
key = 4;
|
||||
|
||||
for (i=0; i<16; i+=2) {
|
||||
u64 pte0 = be64_to_cpu(pteg[i]);
|
||||
u64 pte1 = be64_to_cpu(pteg[i + 1]);
|
||||
|
||||
/* Check all relevant fields of 1st dword */
|
||||
if ((pteg[i] & v_mask) == v_val) {
|
||||
if ((pte0 & v_mask) == v_val) {
|
||||
/* If large page bit is set, check pgsize encoding */
|
||||
if (slbe->large &&
|
||||
(vcpu->arch.hflags & BOOK3S_HFLAG_MULTI_PGSIZE)) {
|
||||
pgsize = decode_pagesize(slbe, pteg[i+1]);
|
||||
pgsize = decode_pagesize(slbe, pte1);
|
||||
if (pgsize < 0)
|
||||
continue;
|
||||
}
|
||||
@ -297,8 +300,8 @@ do_second:
|
||||
goto do_second;
|
||||
}
|
||||
|
||||
v = pteg[i];
|
||||
r = pteg[i+1];
|
||||
v = be64_to_cpu(pteg[i]);
|
||||
r = be64_to_cpu(pteg[i+1]);
|
||||
pp = (r & HPTE_R_PP) | key;
|
||||
if (r & HPTE_R_PP0)
|
||||
pp |= 8;
|
||||
@ -310,6 +313,9 @@ do_second:
|
||||
gpte->raddr = (r & HPTE_R_RPN & ~eaddr_mask) | (eaddr & eaddr_mask);
|
||||
gpte->page_size = pgsize;
|
||||
gpte->may_execute = ((r & HPTE_R_N) ? false : true);
|
||||
if (unlikely(vcpu->arch.disable_kernel_nx) &&
|
||||
!(kvmppc_get_msr(vcpu) & MSR_PR))
|
||||
gpte->may_execute = true;
|
||||
gpte->may_read = false;
|
||||
gpte->may_write = false;
|
||||
|
||||
@ -342,14 +348,14 @@ do_second:
|
||||
* non-PAPR platforms such as mac99, and this is
|
||||
* what real hardware does.
|
||||
*/
|
||||
char __user *addr = (char __user *) &pteg[i+1];
|
||||
char __user *addr = (char __user *) (ptegp + (i + 1) * sizeof(u64));
|
||||
r |= HPTE_R_R;
|
||||
put_user(r >> 8, addr + 6);
|
||||
}
|
||||
if (iswrite && gpte->may_write && !(r & HPTE_R_C)) {
|
||||
/* Set the dirty flag */
|
||||
/* Use a single byte write */
|
||||
char __user *addr = (char __user *) &pteg[i+1];
|
||||
char __user *addr = (char __user *) (ptegp + (i + 1) * sizeof(u64));
|
||||
r |= HPTE_R_C;
|
||||
put_user(r, addr + 7);
|
||||
}
|
||||
@ -479,7 +485,7 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
|
||||
vcpu->arch.slb[i].origv = 0;
|
||||
}
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_IR) {
|
||||
if (kvmppc_get_msr(vcpu) & MSR_IR) {
|
||||
kvmppc_mmu_flush_segments(vcpu);
|
||||
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
|
||||
}
|
||||
@ -563,7 +569,7 @@ static int segment_contains_magic_page(struct kvm_vcpu *vcpu, ulong esid)
|
||||
{
|
||||
ulong mp_ea = vcpu->arch.magic_page_ea;
|
||||
|
||||
return mp_ea && !(vcpu->arch.shared->msr & MSR_PR) &&
|
||||
return mp_ea && !(kvmppc_get_msr(vcpu) & MSR_PR) &&
|
||||
(mp_ea >> SID_SHIFT) == esid;
|
||||
}
|
||||
#endif
|
||||
@ -576,8 +582,9 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
u64 gvsid = esid;
|
||||
ulong mp_ea = vcpu->arch.magic_page_ea;
|
||||
int pagesize = MMU_PAGE_64K;
|
||||
u64 msr = kvmppc_get_msr(vcpu);
|
||||
|
||||
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
if (msr & (MSR_DR|MSR_IR)) {
|
||||
slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea);
|
||||
if (slb) {
|
||||
gvsid = slb->vsid;
|
||||
@ -590,7 +597,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
}
|
||||
}
|
||||
|
||||
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
switch (msr & (MSR_DR|MSR_IR)) {
|
||||
case 0:
|
||||
gvsid = VSID_REAL | esid;
|
||||
break;
|
||||
@ -623,7 +630,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
gvsid |= VSID_64K;
|
||||
#endif
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
*vsid = gvsid;
|
||||
@ -633,7 +640,7 @@ no_slb:
|
||||
/* Catch magic page case */
|
||||
if (unlikely(mp_ea) &&
|
||||
unlikely(esid == (mp_ea >> SID_SHIFT)) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
!(kvmppc_get_msr(vcpu) & MSR_PR)) {
|
||||
*vsid = VSID_REAL | esid;
|
||||
return 0;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
struct kvmppc_sid_map *map;
|
||||
u16 sid_map_mask;
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
|
||||
@ -230,7 +230,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
u16 sid_map_mask;
|
||||
static int backwards_map = 0;
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
/* We might get collisions that trap in preceding order, so let's
|
||||
@ -271,11 +271,8 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
|
||||
int found_inval = -1;
|
||||
int r;
|
||||
|
||||
if (!svcpu->slb_max)
|
||||
svcpu->slb_max = 1;
|
||||
|
||||
/* Are we overwriting? */
|
||||
for (i = 1; i < svcpu->slb_max; i++) {
|
||||
for (i = 0; i < svcpu->slb_max; i++) {
|
||||
if (!(svcpu->slb[i].esid & SLB_ESID_V))
|
||||
found_inval = i;
|
||||
else if ((svcpu->slb[i].esid & ESID_MASK) == esid) {
|
||||
@ -285,7 +282,7 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
|
||||
}
|
||||
|
||||
/* Found a spare entry that was invalidated before */
|
||||
if (found_inval > 0) {
|
||||
if (found_inval >= 0) {
|
||||
r = found_inval;
|
||||
goto out;
|
||||
}
|
||||
@ -359,7 +356,7 @@ void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong ea, ulong seg_size)
|
||||
ulong seg_mask = -seg_size;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < svcpu->slb_max; i++) {
|
||||
for (i = 0; i < svcpu->slb_max; i++) {
|
||||
if ((svcpu->slb[i].esid & SLB_ESID_V) &&
|
||||
(svcpu->slb[i].esid & seg_mask) == ea) {
|
||||
/* Invalidate this entry */
|
||||
@ -373,7 +370,7 @@ void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong ea, ulong seg_size)
|
||||
void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
|
||||
svcpu->slb_max = 1;
|
||||
svcpu->slb_max = 0;
|
||||
svcpu->slb[0].esid = 0;
|
||||
svcpu_put(svcpu);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ static void kvmppc_rmap_reset(struct kvm *kvm);
|
||||
|
||||
long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
|
||||
{
|
||||
unsigned long hpt;
|
||||
unsigned long hpt = 0;
|
||||
struct revmap_entry *rev;
|
||||
struct page *page = NULL;
|
||||
long order = KVM_DEFAULT_HPT_ORDER;
|
||||
@ -64,22 +64,11 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
|
||||
}
|
||||
|
||||
kvm->arch.hpt_cma_alloc = 0;
|
||||
/*
|
||||
* try first to allocate it from the kernel page allocator.
|
||||
* We keep the CMA reserved for failed allocation.
|
||||
*/
|
||||
hpt = __get_free_pages(GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT |
|
||||
__GFP_NOWARN, order - PAGE_SHIFT);
|
||||
|
||||
/* Next try to allocate from the preallocated pool */
|
||||
if (!hpt) {
|
||||
VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER);
|
||||
page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
|
||||
if (page) {
|
||||
hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
|
||||
kvm->arch.hpt_cma_alloc = 1;
|
||||
} else
|
||||
--order;
|
||||
VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER);
|
||||
page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
|
||||
if (page) {
|
||||
hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
|
||||
kvm->arch.hpt_cma_alloc = 1;
|
||||
}
|
||||
|
||||
/* Lastly try successively smaller sizes from the page allocator */
|
||||
@ -596,6 +585,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
unsigned long *hptep, hpte[3], r;
|
||||
unsigned long mmu_seq, psize, pte_size;
|
||||
unsigned long gpa_base, gfn_base;
|
||||
unsigned long gpa, gfn, hva, pfn;
|
||||
struct kvm_memory_slot *memslot;
|
||||
unsigned long *rmap;
|
||||
@ -634,7 +624,9 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
|
||||
/* Translate the logical address and get the page */
|
||||
psize = hpte_page_size(hpte[0], r);
|
||||
gpa = (r & HPTE_R_RPN & ~(psize - 1)) | (ea & (psize - 1));
|
||||
gpa_base = r & HPTE_R_RPN & ~(psize - 1);
|
||||
gfn_base = gpa_base >> PAGE_SHIFT;
|
||||
gpa = gpa_base | (ea & (psize - 1));
|
||||
gfn = gpa >> PAGE_SHIFT;
|
||||
memslot = gfn_to_memslot(kvm, gfn);
|
||||
|
||||
@ -646,6 +638,13 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
if (!kvm->arch.using_mmu_notifiers)
|
||||
return -EFAULT; /* should never get here */
|
||||
|
||||
/*
|
||||
* This should never happen, because of the slot_is_aligned()
|
||||
* check in kvmppc_do_h_enter().
|
||||
*/
|
||||
if (gfn_base < memslot->base_gfn)
|
||||
return -EFAULT;
|
||||
|
||||
/* used to check for invalidations in progress */
|
||||
mmu_seq = kvm->mmu_notifier_seq;
|
||||
smp_rmb();
|
||||
@ -738,7 +737,8 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
goto out_unlock;
|
||||
hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
|
||||
|
||||
rmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
|
||||
/* Always put the HPTE in the rmap chain for the page base address */
|
||||
rmap = &memslot->arch.rmap[gfn_base - memslot->base_gfn];
|
||||
lock_rmap(rmap);
|
||||
|
||||
/* Check if we might have been invalidated; let the guest retry if so */
|
||||
@ -1060,22 +1060,33 @@ void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte)
|
||||
kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
|
||||
}
|
||||
|
||||
static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
|
||||
static int vcpus_running(struct kvm *kvm)
|
||||
{
|
||||
return atomic_read(&kvm->arch.vcpus_running) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of system pages that are dirty.
|
||||
* This can be more than 1 if we find a huge-page HPTE.
|
||||
*/
|
||||
static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
|
||||
{
|
||||
struct revmap_entry *rev = kvm->arch.revmap;
|
||||
unsigned long head, i, j;
|
||||
unsigned long n;
|
||||
unsigned long v, r;
|
||||
unsigned long *hptep;
|
||||
int ret = 0;
|
||||
int npages_dirty = 0;
|
||||
|
||||
retry:
|
||||
lock_rmap(rmapp);
|
||||
if (*rmapp & KVMPPC_RMAP_CHANGED) {
|
||||
*rmapp &= ~KVMPPC_RMAP_CHANGED;
|
||||
ret = 1;
|
||||
npages_dirty = 1;
|
||||
}
|
||||
if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
|
||||
unlock_rmap(rmapp);
|
||||
return ret;
|
||||
return npages_dirty;
|
||||
}
|
||||
|
||||
i = head = *rmapp & KVMPPC_RMAP_INDEX;
|
||||
@ -1083,7 +1094,22 @@ static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
|
||||
hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
|
||||
j = rev[i].forw;
|
||||
|
||||
if (!(hptep[1] & HPTE_R_C))
|
||||
/*
|
||||
* Checking the C (changed) bit here is racy since there
|
||||
* is no guarantee about when the hardware writes it back.
|
||||
* If the HPTE is not writable then it is stable since the
|
||||
* page can't be written to, and we would have done a tlbie
|
||||
* (which forces the hardware to complete any writeback)
|
||||
* when making the HPTE read-only.
|
||||
* If vcpus are running then this call is racy anyway
|
||||
* since the page could get dirtied subsequently, so we
|
||||
* expect there to be a further call which would pick up
|
||||
* any delayed C bit writeback.
|
||||
* Otherwise we need to do the tlbie even if C==0 in
|
||||
* order to pick up any delayed writeback of C.
|
||||
*/
|
||||
if (!(hptep[1] & HPTE_R_C) &&
|
||||
(!hpte_is_writable(hptep[1]) || vcpus_running(kvm)))
|
||||
continue;
|
||||
|
||||
if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
|
||||
@ -1095,24 +1121,33 @@ static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
|
||||
}
|
||||
|
||||
/* Now check and modify the HPTE */
|
||||
if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_C)) {
|
||||
/* need to make it temporarily absent to clear C */
|
||||
hptep[0] |= HPTE_V_ABSENT;
|
||||
kvmppc_invalidate_hpte(kvm, hptep, i);
|
||||
hptep[1] &= ~HPTE_R_C;
|
||||
eieio();
|
||||
hptep[0] = (hptep[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
|
||||
if (!(hptep[0] & HPTE_V_VALID))
|
||||
continue;
|
||||
|
||||
/* need to make it temporarily absent so C is stable */
|
||||
hptep[0] |= HPTE_V_ABSENT;
|
||||
kvmppc_invalidate_hpte(kvm, hptep, i);
|
||||
v = hptep[0];
|
||||
r = hptep[1];
|
||||
if (r & HPTE_R_C) {
|
||||
hptep[1] = r & ~HPTE_R_C;
|
||||
if (!(rev[i].guest_rpte & HPTE_R_C)) {
|
||||
rev[i].guest_rpte |= HPTE_R_C;
|
||||
note_hpte_modification(kvm, &rev[i]);
|
||||
}
|
||||
ret = 1;
|
||||
n = hpte_page_size(v, r);
|
||||
n = (n + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
if (n > npages_dirty)
|
||||
npages_dirty = n;
|
||||
eieio();
|
||||
}
|
||||
hptep[0] &= ~HPTE_V_HVLOCK;
|
||||
v &= ~(HPTE_V_ABSENT | HPTE_V_HVLOCK);
|
||||
v |= HPTE_V_VALID;
|
||||
hptep[0] = v;
|
||||
} while ((i = j) != head);
|
||||
|
||||
unlock_rmap(rmapp);
|
||||
return ret;
|
||||
return npages_dirty;
|
||||
}
|
||||
|
||||
static void harvest_vpa_dirty(struct kvmppc_vpa *vpa,
|
||||
@ -1136,15 +1171,22 @@ static void harvest_vpa_dirty(struct kvmppc_vpa *vpa,
|
||||
long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long *map)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned long i, j;
|
||||
unsigned long *rmapp;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
preempt_disable();
|
||||
rmapp = memslot->arch.rmap;
|
||||
for (i = 0; i < memslot->npages; ++i) {
|
||||
if (kvm_test_clear_dirty(kvm, rmapp) && map)
|
||||
__set_bit_le(i, map);
|
||||
int npages = kvm_test_clear_dirty_npages(kvm, rmapp);
|
||||
/*
|
||||
* Note that if npages > 0 then i must be a multiple of npages,
|
||||
* since we always put huge-page HPTEs in the rmap chain
|
||||
* corresponding to their page base address.
|
||||
*/
|
||||
if (npages && map)
|
||||
for (j = i; npages; ++j, --npages)
|
||||
__set_bit_le(j, map);
|
||||
++rmapp;
|
||||
}
|
||||
|
||||
|
@ -17,30 +17,9 @@
|
||||
* Authors: Alexander Graf <agraf@suse.de>
|
||||
*/
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#error Need to fix SLB shadow accesses in little endian mode
|
||||
#endif
|
||||
|
||||
#define SHADOW_SLB_ESID(num) (SLBSHADOW_SAVEAREA + (num * 0x10))
|
||||
#define SHADOW_SLB_VSID(num) (SLBSHADOW_SAVEAREA + (num * 0x10) + 0x8)
|
||||
#define UNBOLT_SLB_ENTRY(num) \
|
||||
ld r9, SHADOW_SLB_ESID(num)(r12); \
|
||||
/* Invalid? Skip. */; \
|
||||
rldicl. r0, r9, 37, 63; \
|
||||
beq slb_entry_skip_ ## num; \
|
||||
xoris r9, r9, SLB_ESID_V@h; \
|
||||
std r9, SHADOW_SLB_ESID(num)(r12); \
|
||||
slb_entry_skip_ ## num:
|
||||
|
||||
#define REBOLT_SLB_ENTRY(num) \
|
||||
ld r10, SHADOW_SLB_ESID(num)(r11); \
|
||||
cmpdi r10, 0; \
|
||||
beq slb_exit_skip_ ## num; \
|
||||
oris r10, r10, SLB_ESID_V@h; \
|
||||
ld r9, SHADOW_SLB_VSID(num)(r11); \
|
||||
slbmte r9, r10; \
|
||||
std r10, SHADOW_SLB_ESID(num)(r11); \
|
||||
slb_exit_skip_ ## num:
|
||||
#define SHADOW_SLB_ENTRY_LEN 0x10
|
||||
#define OFFSET_ESID(x) (SHADOW_SLB_ENTRY_LEN * x)
|
||||
#define OFFSET_VSID(x) ((SHADOW_SLB_ENTRY_LEN * x) + 8)
|
||||
|
||||
/******************************************************************************
|
||||
* *
|
||||
@ -64,20 +43,15 @@ slb_exit_skip_ ## num:
|
||||
* SVCPU[LR] = guest LR
|
||||
*/
|
||||
|
||||
/* Remove LPAR shadow entries */
|
||||
BEGIN_FW_FTR_SECTION
|
||||
|
||||
#if SLB_NUM_BOLTED == 3
|
||||
/* Declare SLB shadow as 0 entries big */
|
||||
|
||||
ld r12, PACA_SLBSHADOWPTR(r13)
|
||||
ld r11, PACA_SLBSHADOWPTR(r13)
|
||||
li r8, 0
|
||||
stb r8, 3(r11)
|
||||
|
||||
/* Remove bolted entries */
|
||||
UNBOLT_SLB_ENTRY(0)
|
||||
UNBOLT_SLB_ENTRY(1)
|
||||
UNBOLT_SLB_ENTRY(2)
|
||||
|
||||
#else
|
||||
#error unknown number of bolted entries
|
||||
#endif
|
||||
END_FW_FTR_SECTION_IFSET(FW_FEATURE_LPAR)
|
||||
|
||||
/* Flush SLB */
|
||||
|
||||
@ -100,7 +74,7 @@ slb_loop_enter:
|
||||
|
||||
ld r10, 0(r11)
|
||||
|
||||
rldicl. r0, r10, 37, 63
|
||||
andis. r9, r10, SLB_ESID_V@h
|
||||
beq slb_loop_enter_skip
|
||||
|
||||
ld r9, 8(r11)
|
||||
@ -137,23 +111,42 @@ slb_do_enter:
|
||||
*
|
||||
*/
|
||||
|
||||
/* Restore bolted entries from the shadow and fix it along the way */
|
||||
/* Remove all SLB entries that are in use. */
|
||||
|
||||
/* We don't store anything in entry 0, so we don't need to take care of it */
|
||||
li r0, r0
|
||||
slbmte r0, r0
|
||||
slbia
|
||||
isync
|
||||
|
||||
#if SLB_NUM_BOLTED == 3
|
||||
/* Restore bolted entries from the shadow */
|
||||
|
||||
ld r11, PACA_SLBSHADOWPTR(r13)
|
||||
|
||||
REBOLT_SLB_ENTRY(0)
|
||||
REBOLT_SLB_ENTRY(1)
|
||||
REBOLT_SLB_ENTRY(2)
|
||||
|
||||
#else
|
||||
#error unknown number of bolted entries
|
||||
#endif
|
||||
BEGIN_FW_FTR_SECTION
|
||||
|
||||
/* Declare SLB shadow as SLB_NUM_BOLTED entries big */
|
||||
|
||||
li r8, SLB_NUM_BOLTED
|
||||
stb r8, 3(r11)
|
||||
|
||||
END_FW_FTR_SECTION_IFSET(FW_FEATURE_LPAR)
|
||||
|
||||
/* Manually load all entries from shadow SLB */
|
||||
|
||||
li r8, SLBSHADOW_SAVEAREA
|
||||
li r7, SLBSHADOW_SAVEAREA + 8
|
||||
|
||||
.rept SLB_NUM_BOLTED
|
||||
LDX_BE r10, r11, r8
|
||||
cmpdi r10, 0
|
||||
beq 1f
|
||||
LDX_BE r9, r11, r7
|
||||
slbmte r9, r10
|
||||
1: addi r7, r7, SHADOW_SLB_ENTRY_LEN
|
||||
addi r8, r8, SHADOW_SLB_ENTRY_LEN
|
||||
.endr
|
||||
|
||||
isync
|
||||
sync
|
||||
|
||||
slb_do_exit:
|
||||
|
||||
|
@ -80,7 +80,7 @@ static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level)
|
||||
return false;
|
||||
|
||||
/* Limit user space to its own small SPR set */
|
||||
if ((vcpu->arch.shared->msr & MSR_PR) && level > PRIV_PROBLEM)
|
||||
if ((kvmppc_get_msr(vcpu) & MSR_PR) && level > PRIV_PROBLEM)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -94,14 +94,31 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
int rs = get_rs(inst);
|
||||
int ra = get_ra(inst);
|
||||
int rb = get_rb(inst);
|
||||
u32 inst_sc = 0x44000002;
|
||||
|
||||
switch (get_op(inst)) {
|
||||
case 0:
|
||||
emulated = EMULATE_FAIL;
|
||||
if ((kvmppc_get_msr(vcpu) & MSR_LE) &&
|
||||
(inst == swab32(inst_sc))) {
|
||||
/*
|
||||
* This is the byte reversed syscall instruction of our
|
||||
* hypercall handler. Early versions of LE Linux didn't
|
||||
* swap the instructions correctly and ended up in
|
||||
* illegal instructions.
|
||||
* Just always fail hypercalls on these broken systems.
|
||||
*/
|
||||
kvmppc_set_gpr(vcpu, 3, EV_UNIMPLEMENTED);
|
||||
kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
|
||||
emulated = EMULATE_DONE;
|
||||
}
|
||||
break;
|
||||
case 19:
|
||||
switch (get_xop(inst)) {
|
||||
case OP_19_XOP_RFID:
|
||||
case OP_19_XOP_RFI:
|
||||
kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);
|
||||
kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
|
||||
kvmppc_set_pc(vcpu, kvmppc_get_srr0(vcpu));
|
||||
kvmppc_set_msr(vcpu, kvmppc_get_srr1(vcpu));
|
||||
*advance = 0;
|
||||
break;
|
||||
|
||||
@ -113,16 +130,16 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
case 31:
|
||||
switch (get_xop(inst)) {
|
||||
case OP_31_XOP_MFMSR:
|
||||
kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
|
||||
kvmppc_set_gpr(vcpu, rt, kvmppc_get_msr(vcpu));
|
||||
break;
|
||||
case OP_31_XOP_MTMSRD:
|
||||
{
|
||||
ulong rs_val = kvmppc_get_gpr(vcpu, rs);
|
||||
if (inst & 0x10000) {
|
||||
ulong new_msr = vcpu->arch.shared->msr;
|
||||
ulong new_msr = kvmppc_get_msr(vcpu);
|
||||
new_msr &= ~(MSR_RI | MSR_EE);
|
||||
new_msr |= rs_val & (MSR_RI | MSR_EE);
|
||||
vcpu->arch.shared->msr = new_msr;
|
||||
kvmppc_set_msr_fast(vcpu, new_msr);
|
||||
} else
|
||||
kvmppc_set_msr(vcpu, rs_val);
|
||||
break;
|
||||
@ -179,7 +196,7 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
ulong cmd = kvmppc_get_gpr(vcpu, 3);
|
||||
int i;
|
||||
|
||||
if ((vcpu->arch.shared->msr & MSR_PR) ||
|
||||
if ((kvmppc_get_msr(vcpu) & MSR_PR) ||
|
||||
!vcpu->arch.papr_enabled) {
|
||||
emulated = EMULATE_FAIL;
|
||||
break;
|
||||
@ -261,14 +278,14 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
ra_val = kvmppc_get_gpr(vcpu, ra);
|
||||
|
||||
addr = (ra_val + rb_val) & ~31ULL;
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF))
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_SF))
|
||||
addr &= 0xffffffff;
|
||||
vaddr = addr;
|
||||
|
||||
r = kvmppc_st(vcpu, &addr, 32, zeros, true);
|
||||
if ((r == -ENOENT) || (r == -EPERM)) {
|
||||
*advance = 0;
|
||||
vcpu->arch.shared->dar = vaddr;
|
||||
kvmppc_set_dar(vcpu, vaddr);
|
||||
vcpu->arch.fault_dar = vaddr;
|
||||
|
||||
dsisr = DSISR_ISSTORE;
|
||||
@ -277,7 +294,7 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
else if (r == -EPERM)
|
||||
dsisr |= DSISR_PROTFAULT;
|
||||
|
||||
vcpu->arch.shared->dsisr = dsisr;
|
||||
kvmppc_set_dsisr(vcpu, dsisr);
|
||||
vcpu->arch.fault_dsisr = dsisr;
|
||||
|
||||
kvmppc_book3s_queue_irqprio(vcpu,
|
||||
@ -356,10 +373,10 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
|
||||
to_book3s(vcpu)->sdr1 = spr_val;
|
||||
break;
|
||||
case SPRN_DSISR:
|
||||
vcpu->arch.shared->dsisr = spr_val;
|
||||
kvmppc_set_dsisr(vcpu, spr_val);
|
||||
break;
|
||||
case SPRN_DAR:
|
||||
vcpu->arch.shared->dar = spr_val;
|
||||
kvmppc_set_dar(vcpu, spr_val);
|
||||
break;
|
||||
case SPRN_HIOR:
|
||||
to_book3s(vcpu)->hior = spr_val;
|
||||
@ -438,6 +455,31 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
|
||||
case SPRN_GQR7:
|
||||
to_book3s(vcpu)->gqr[sprn - SPRN_GQR0] = spr_val;
|
||||
break;
|
||||
case SPRN_FSCR:
|
||||
vcpu->arch.fscr = spr_val;
|
||||
break;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
case SPRN_BESCR:
|
||||
vcpu->arch.bescr = spr_val;
|
||||
break;
|
||||
case SPRN_EBBHR:
|
||||
vcpu->arch.ebbhr = spr_val;
|
||||
break;
|
||||
case SPRN_EBBRR:
|
||||
vcpu->arch.ebbrr = spr_val;
|
||||
break;
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
case SPRN_TFHAR:
|
||||
vcpu->arch.tfhar = spr_val;
|
||||
break;
|
||||
case SPRN_TEXASR:
|
||||
vcpu->arch.texasr = spr_val;
|
||||
break;
|
||||
case SPRN_TFIAR:
|
||||
vcpu->arch.tfiar = spr_val;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case SPRN_ICTC:
|
||||
case SPRN_THRM1:
|
||||
case SPRN_THRM2:
|
||||
@ -455,6 +497,13 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
|
||||
case SPRN_WPAR_GEKKO:
|
||||
case SPRN_MSSSR0:
|
||||
case SPRN_DABR:
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
case SPRN_MMCRS:
|
||||
case SPRN_MMCRA:
|
||||
case SPRN_MMCR0:
|
||||
case SPRN_MMCR1:
|
||||
case SPRN_MMCR2:
|
||||
#endif
|
||||
break;
|
||||
unprivileged:
|
||||
default:
|
||||
@ -493,10 +542,10 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
|
||||
*spr_val = to_book3s(vcpu)->sdr1;
|
||||
break;
|
||||
case SPRN_DSISR:
|
||||
*spr_val = vcpu->arch.shared->dsisr;
|
||||
*spr_val = kvmppc_get_dsisr(vcpu);
|
||||
break;
|
||||
case SPRN_DAR:
|
||||
*spr_val = vcpu->arch.shared->dar;
|
||||
*spr_val = kvmppc_get_dar(vcpu);
|
||||
break;
|
||||
case SPRN_HIOR:
|
||||
*spr_val = to_book3s(vcpu)->hior;
|
||||
@ -538,6 +587,31 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
|
||||
case SPRN_GQR7:
|
||||
*spr_val = to_book3s(vcpu)->gqr[sprn - SPRN_GQR0];
|
||||
break;
|
||||
case SPRN_FSCR:
|
||||
*spr_val = vcpu->arch.fscr;
|
||||
break;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
case SPRN_BESCR:
|
||||
*spr_val = vcpu->arch.bescr;
|
||||
break;
|
||||
case SPRN_EBBHR:
|
||||
*spr_val = vcpu->arch.ebbhr;
|
||||
break;
|
||||
case SPRN_EBBRR:
|
||||
*spr_val = vcpu->arch.ebbrr;
|
||||
break;
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
case SPRN_TFHAR:
|
||||
*spr_val = vcpu->arch.tfhar;
|
||||
break;
|
||||
case SPRN_TEXASR:
|
||||
*spr_val = vcpu->arch.texasr;
|
||||
break;
|
||||
case SPRN_TFIAR:
|
||||
*spr_val = vcpu->arch.tfiar;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case SPRN_THRM1:
|
||||
case SPRN_THRM2:
|
||||
case SPRN_THRM3:
|
||||
@ -553,6 +627,14 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
|
||||
case SPRN_WPAR_GEKKO:
|
||||
case SPRN_MSSSR0:
|
||||
case SPRN_DABR:
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
case SPRN_MMCRS:
|
||||
case SPRN_MMCRA:
|
||||
case SPRN_MMCR0:
|
||||
case SPRN_MMCR1:
|
||||
case SPRN_MMCR2:
|
||||
case SPRN_TIR:
|
||||
#endif
|
||||
*spr_val = 0;
|
||||
break;
|
||||
default:
|
||||
@ -569,48 +651,17 @@ unprivileged:
|
||||
|
||||
u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst)
|
||||
{
|
||||
u32 dsisr = 0;
|
||||
|
||||
/*
|
||||
* This is what the spec says about DSISR bits (not mentioned = 0):
|
||||
*
|
||||
* 12:13 [DS] Set to bits 30:31
|
||||
* 15:16 [X] Set to bits 29:30
|
||||
* 17 [X] Set to bit 25
|
||||
* [D/DS] Set to bit 5
|
||||
* 18:21 [X] Set to bits 21:24
|
||||
* [D/DS] Set to bits 1:4
|
||||
* 22:26 Set to bits 6:10 (RT/RS/FRT/FRS)
|
||||
* 27:31 Set to bits 11:15 (RA)
|
||||
*/
|
||||
|
||||
switch (get_op(inst)) {
|
||||
/* D-form */
|
||||
case OP_LFS:
|
||||
case OP_LFD:
|
||||
case OP_STFD:
|
||||
case OP_STFS:
|
||||
dsisr |= (inst >> 12) & 0x4000; /* bit 17 */
|
||||
dsisr |= (inst >> 17) & 0x3c00; /* bits 18:21 */
|
||||
break;
|
||||
/* X-form */
|
||||
case 31:
|
||||
dsisr |= (inst << 14) & 0x18000; /* bits 15:16 */
|
||||
dsisr |= (inst << 8) & 0x04000; /* bit 17 */
|
||||
dsisr |= (inst << 3) & 0x03c00; /* bits 18:21 */
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);
|
||||
break;
|
||||
}
|
||||
|
||||
dsisr |= (inst >> 16) & 0x03ff; /* bits 22:31 */
|
||||
|
||||
return dsisr;
|
||||
return make_dsisr(inst);
|
||||
}
|
||||
|
||||
ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst)
|
||||
{
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
/*
|
||||
* Linux's fix_alignment() assumes that DAR is valid, so can we
|
||||
*/
|
||||
return vcpu->arch.fault_dar;
|
||||
#else
|
||||
ulong dar = 0;
|
||||
ulong ra = get_ra(inst);
|
||||
ulong rb = get_rb(inst);
|
||||
@ -635,4 +686,5 @@ ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst)
|
||||
}
|
||||
|
||||
return dar;
|
||||
#endif
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <asm/kvm_ppc.h>
|
||||
#include <asm/kvm_book3s.h>
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
|
@ -879,24 +879,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
|
||||
case KVM_REG_PPC_IAMR:
|
||||
*val = get_reg_val(id, vcpu->arch.iamr);
|
||||
break;
|
||||
case KVM_REG_PPC_FSCR:
|
||||
*val = get_reg_val(id, vcpu->arch.fscr);
|
||||
break;
|
||||
case KVM_REG_PPC_PSPB:
|
||||
*val = get_reg_val(id, vcpu->arch.pspb);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBHR:
|
||||
*val = get_reg_val(id, vcpu->arch.ebbhr);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBRR:
|
||||
*val = get_reg_val(id, vcpu->arch.ebbrr);
|
||||
break;
|
||||
case KVM_REG_PPC_BESCR:
|
||||
*val = get_reg_val(id, vcpu->arch.bescr);
|
||||
break;
|
||||
case KVM_REG_PPC_TAR:
|
||||
*val = get_reg_val(id, vcpu->arch.tar);
|
||||
break;
|
||||
case KVM_REG_PPC_DPDES:
|
||||
*val = get_reg_val(id, vcpu->arch.vcore->dpdes);
|
||||
break;
|
||||
@ -1091,24 +1076,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
|
||||
case KVM_REG_PPC_IAMR:
|
||||
vcpu->arch.iamr = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_FSCR:
|
||||
vcpu->arch.fscr = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_PSPB:
|
||||
vcpu->arch.pspb = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBHR:
|
||||
vcpu->arch.ebbhr = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_EBBRR:
|
||||
vcpu->arch.ebbrr = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_BESCR:
|
||||
vcpu->arch.bescr = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_TAR:
|
||||
vcpu->arch.tar = set_reg_val(id, *val);
|
||||
break;
|
||||
case KVM_REG_PPC_DPDES:
|
||||
vcpu->arch.vcore->dpdes = set_reg_val(id, *val);
|
||||
break;
|
||||
@ -1280,6 +1250,17 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
|
||||
goto free_vcpu;
|
||||
|
||||
vcpu->arch.shared = &vcpu->arch.shregs;
|
||||
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
|
||||
/*
|
||||
* The shared struct is never shared on HV,
|
||||
* so we can always use host endianness
|
||||
*/
|
||||
#ifdef __BIG_ENDIAN__
|
||||
vcpu->arch.shared_big_endian = true;
|
||||
#else
|
||||
vcpu->arch.shared_big_endian = false;
|
||||
#endif
|
||||
#endif
|
||||
vcpu->arch.mmcr[0] = MMCR0_FC;
|
||||
vcpu->arch.ctrl = CTRL_RUNLATCH;
|
||||
/* default to host PVR, since we can't spoof it */
|
||||
@ -1949,6 +1930,13 @@ static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps,
|
||||
* support pte_enc here
|
||||
*/
|
||||
(*sps)->enc[0].pte_enc = def->penc[linux_psize];
|
||||
/*
|
||||
* Add 16MB MPSS support if host supports it
|
||||
*/
|
||||
if (linux_psize != MMU_PAGE_16M && def->penc[MMU_PAGE_16M] != -1) {
|
||||
(*sps)->enc[1].page_shift = 24;
|
||||
(*sps)->enc[1].pte_enc = def->penc[MMU_PAGE_16M];
|
||||
}
|
||||
(*sps)++;
|
||||
}
|
||||
|
||||
|
@ -42,13 +42,14 @@ static int global_invalidates(struct kvm *kvm, unsigned long flags)
|
||||
|
||||
/*
|
||||
* If there is only one vcore, and it's currently running,
|
||||
* as indicated by local_paca->kvm_hstate.kvm_vcpu being set,
|
||||
* we can use tlbiel as long as we mark all other physical
|
||||
* cores as potentially having stale TLB entries for this lpid.
|
||||
* If we're not using MMU notifiers, we never take pages away
|
||||
* from the guest, so we can use tlbiel if requested.
|
||||
* Otherwise, don't use tlbiel.
|
||||
*/
|
||||
if (kvm->arch.online_vcores == 1 && local_paca->kvm_hstate.kvm_vcore)
|
||||
if (kvm->arch.online_vcores == 1 && local_paca->kvm_hstate.kvm_vcpu)
|
||||
global = 0;
|
||||
else if (kvm->arch.using_mmu_notifiers)
|
||||
global = 1;
|
||||
|
@ -86,6 +86,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
|
||||
lbz r4, LPPACA_PMCINUSE(r3)
|
||||
cmpwi r4, 0
|
||||
beq 23f /* skip if not */
|
||||
BEGIN_FTR_SECTION
|
||||
ld r3, HSTATE_MMCR(r13)
|
||||
andi. r4, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO
|
||||
cmpwi r4, MMCR0_PMAO
|
||||
beql kvmppc_fix_pmao
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG)
|
||||
lwz r3, HSTATE_PMC(r13)
|
||||
lwz r4, HSTATE_PMC + 4(r13)
|
||||
lwz r5, HSTATE_PMC + 8(r13)
|
||||
@ -726,6 +732,12 @@ skip_tm:
|
||||
sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */
|
||||
mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */
|
||||
isync
|
||||
BEGIN_FTR_SECTION
|
||||
ld r3, VCPU_MMCR(r4)
|
||||
andi. r5, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO
|
||||
cmpwi r5, MMCR0_PMAO
|
||||
beql kvmppc_fix_pmao
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG)
|
||||
lwz r3, VCPU_PMC(r4) /* always load up guest PMU registers */
|
||||
lwz r5, VCPU_PMC + 4(r4) /* to prevent information leak */
|
||||
lwz r6, VCPU_PMC + 8(r4)
|
||||
@ -1324,6 +1336,30 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
|
||||
25:
|
||||
/* Save PMU registers if requested */
|
||||
/* r8 and cr0.eq are live here */
|
||||
BEGIN_FTR_SECTION
|
||||
/*
|
||||
* POWER8 seems to have a hardware bug where setting
|
||||
* MMCR0[PMAE] along with MMCR0[PMC1CE] and/or MMCR0[PMCjCE]
|
||||
* when some counters are already negative doesn't seem
|
||||
* to cause a performance monitor alert (and hence interrupt).
|
||||
* The effect of this is that when saving the PMU state,
|
||||
* if there is no PMU alert pending when we read MMCR0
|
||||
* before freezing the counters, but one becomes pending
|
||||
* before we read the counters, we lose it.
|
||||
* To work around this, we need a way to freeze the counters
|
||||
* before reading MMCR0. Normally, freezing the counters
|
||||
* is done by writing MMCR0 (to set MMCR0[FC]) which
|
||||
* unavoidably writes MMCR0[PMA0] as well. On POWER8,
|
||||
* we can also freeze the counters using MMCR2, by writing
|
||||
* 1s to all the counter freeze condition bits (there are
|
||||
* 9 bits each for 6 counters).
|
||||
*/
|
||||
li r3, -1 /* set all freeze bits */
|
||||
clrrdi r3, r3, 10
|
||||
mfspr r10, SPRN_MMCR2
|
||||
mtspr SPRN_MMCR2, r3
|
||||
isync
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
li r3, 1
|
||||
sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */
|
||||
mfspr r4, SPRN_MMCR0 /* save MMCR0 */
|
||||
@ -1347,6 +1383,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
|
||||
std r4, VCPU_MMCR(r9)
|
||||
std r5, VCPU_MMCR + 8(r9)
|
||||
std r6, VCPU_MMCR + 16(r9)
|
||||
BEGIN_FTR_SECTION
|
||||
std r10, VCPU_MMCR + 24(r9)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
std r7, VCPU_SIAR(r9)
|
||||
std r8, VCPU_SDAR(r9)
|
||||
mfspr r3, SPRN_PMC1
|
||||
@ -1370,12 +1409,10 @@ BEGIN_FTR_SECTION
|
||||
stw r11, VCPU_PMC + 28(r9)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
|
||||
BEGIN_FTR_SECTION
|
||||
mfspr r4, SPRN_MMCR2
|
||||
mfspr r5, SPRN_SIER
|
||||
mfspr r6, SPRN_SPMC1
|
||||
mfspr r7, SPRN_SPMC2
|
||||
mfspr r8, SPRN_MMCRS
|
||||
std r4, VCPU_MMCR + 24(r9)
|
||||
std r5, VCPU_SIER(r9)
|
||||
stw r6, VCPU_PMC + 24(r9)
|
||||
stw r7, VCPU_PMC + 28(r9)
|
||||
@ -2107,6 +2144,7 @@ machine_check_realmode:
|
||||
beq mc_cont
|
||||
/* If not, deliver a machine check. SRR0/1 are already set */
|
||||
li r10, BOOK3S_INTERRUPT_MACHINE_CHECK
|
||||
ld r11, VCPU_MSR(r9)
|
||||
bl kvmppc_msr_interrupt
|
||||
b fast_interrupt_c_return
|
||||
|
||||
@ -2311,3 +2349,21 @@ kvmppc_msr_interrupt:
|
||||
li r0, 1
|
||||
1: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG
|
||||
blr
|
||||
|
||||
/*
|
||||
* This works around a hardware bug on POWER8E processors, where
|
||||
* writing a 1 to the MMCR0[PMAO] bit doesn't generate a
|
||||
* performance monitor interrupt. Instead, when we need to have
|
||||
* an interrupt pending, we have to arrange for a counter to overflow.
|
||||
*/
|
||||
kvmppc_fix_pmao:
|
||||
li r3, 0
|
||||
mtspr SPRN_MMCR2, r3
|
||||
lis r3, (MMCR0_PMXE | MMCR0_FCECE)@h
|
||||
ori r3, r3, MMCR0_PMCjCE | MMCR0_C56RUN
|
||||
mtspr SPRN_MMCR0, r3
|
||||
lis r3, 0x7fff
|
||||
ori r3, r3, 0xffff
|
||||
mtspr SPRN_PMC6, r3
|
||||
isync
|
||||
blr
|
||||
|
@ -104,8 +104,27 @@ kvm_start_lightweight:
|
||||
stb r3, HSTATE_RESTORE_HID5(r13)
|
||||
|
||||
/* Load up guest SPRG3 value, since it's user readable */
|
||||
ld r3, VCPU_SHARED(r4)
|
||||
ld r3, VCPU_SHARED_SPRG3(r3)
|
||||
lwz r3, VCPU_SHAREDBE(r4)
|
||||
cmpwi r3, 0
|
||||
ld r5, VCPU_SHARED(r4)
|
||||
beq sprg3_little_endian
|
||||
sprg3_big_endian:
|
||||
#ifdef __BIG_ENDIAN__
|
||||
ld r3, VCPU_SHARED_SPRG3(r5)
|
||||
#else
|
||||
addi r5, r5, VCPU_SHARED_SPRG3
|
||||
ldbrx r3, 0, r5
|
||||
#endif
|
||||
b after_sprg3_load
|
||||
sprg3_little_endian:
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
ld r3, VCPU_SHARED_SPRG3(r5)
|
||||
#else
|
||||
addi r5, r5, VCPU_SHARED_SPRG3
|
||||
ldbrx r3, 0, r5
|
||||
#endif
|
||||
|
||||
after_sprg3_load:
|
||||
mtspr SPRN_SPRG3, r3
|
||||
#endif /* CONFIG_PPC_BOOK3S_64 */
|
||||
|
||||
|
@ -165,16 +165,18 @@ static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
|
||||
|
||||
static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
|
||||
{
|
||||
u64 dsisr;
|
||||
struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared;
|
||||
u32 dsisr;
|
||||
u64 msr = kvmppc_get_msr(vcpu);
|
||||
|
||||
shared->msr = kvmppc_set_field(shared->msr, 33, 36, 0);
|
||||
shared->msr = kvmppc_set_field(shared->msr, 42, 47, 0);
|
||||
shared->dar = eaddr;
|
||||
msr = kvmppc_set_field(msr, 33, 36, 0);
|
||||
msr = kvmppc_set_field(msr, 42, 47, 0);
|
||||
kvmppc_set_msr(vcpu, msr);
|
||||
kvmppc_set_dar(vcpu, eaddr);
|
||||
/* Page Fault */
|
||||
dsisr = kvmppc_set_field(0, 33, 33, 1);
|
||||
if (is_store)
|
||||
shared->dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
|
||||
dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
|
||||
kvmppc_set_dsisr(vcpu, dsisr);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
|
||||
}
|
||||
|
||||
@ -660,7 +662,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
if (!kvmppc_inst_is_paired_single(vcpu, inst))
|
||||
return EMULATE_FAIL;
|
||||
|
||||
if (!(vcpu->arch.shared->msr & MSR_FP)) {
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_FP)) {
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL);
|
||||
return EMULATE_AGAIN;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@
|
||||
|
||||
static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
|
||||
ulong msr);
|
||||
static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac);
|
||||
|
||||
/* Some compatibility defines */
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
@ -89,6 +90,7 @@ static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
|
||||
#endif
|
||||
|
||||
kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
|
||||
kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
|
||||
vcpu->cpu = -1;
|
||||
}
|
||||
|
||||
@ -115,6 +117,9 @@ void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu,
|
||||
svcpu->ctr = vcpu->arch.ctr;
|
||||
svcpu->lr = vcpu->arch.lr;
|
||||
svcpu->pc = vcpu->arch.pc;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
svcpu->shadow_fscr = vcpu->arch.shadow_fscr;
|
||||
#endif
|
||||
svcpu->in_use = true;
|
||||
}
|
||||
|
||||
@ -158,6 +163,9 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
|
||||
vcpu->arch.fault_dar = svcpu->fault_dar;
|
||||
vcpu->arch.fault_dsisr = svcpu->fault_dsisr;
|
||||
vcpu->arch.last_inst = svcpu->last_inst;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
vcpu->arch.shadow_fscr = svcpu->shadow_fscr;
|
||||
#endif
|
||||
svcpu->in_use = false;
|
||||
|
||||
out:
|
||||
@ -246,14 +254,15 @@ static void kvm_set_spte_hva_pr(struct kvm *kvm, unsigned long hva, pte_t pte)
|
||||
|
||||
static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
ulong smsr = vcpu->arch.shared->msr;
|
||||
ulong guest_msr = kvmppc_get_msr(vcpu);
|
||||
ulong smsr = guest_msr;
|
||||
|
||||
/* Guest MSR values */
|
||||
smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE;
|
||||
smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE;
|
||||
/* Process MSR values */
|
||||
smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
|
||||
/* External providers the guest reserved */
|
||||
smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext);
|
||||
smsr |= (guest_msr & vcpu->arch.guest_owned_ext);
|
||||
/* 64-bit Process MSR values */
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
smsr |= MSR_ISF | MSR_HV;
|
||||
@ -263,14 +272,14 @@ static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
|
||||
|
||||
static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
|
||||
{
|
||||
ulong old_msr = vcpu->arch.shared->msr;
|
||||
ulong old_msr = kvmppc_get_msr(vcpu);
|
||||
|
||||
#ifdef EXIT_DEBUG
|
||||
printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr);
|
||||
#endif
|
||||
|
||||
msr &= to_book3s(vcpu)->msr_mask;
|
||||
vcpu->arch.shared->msr = msr;
|
||||
kvmppc_set_msr_fast(vcpu, msr);
|
||||
kvmppc_recalc_shadow_msr(vcpu);
|
||||
|
||||
if (msr & MSR_POW) {
|
||||
@ -281,11 +290,11 @@ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
|
||||
|
||||
/* Unset POW bit after we woke up */
|
||||
msr &= ~MSR_POW;
|
||||
vcpu->arch.shared->msr = msr;
|
||||
kvmppc_set_msr_fast(vcpu, msr);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) !=
|
||||
if ((kvmppc_get_msr(vcpu) & (MSR_PR|MSR_IR|MSR_DR)) !=
|
||||
(old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
|
||||
kvmppc_mmu_flush_segments(vcpu);
|
||||
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
|
||||
@ -317,7 +326,7 @@ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
|
||||
}
|
||||
|
||||
/* Preload FPU if it's enabled */
|
||||
if (vcpu->arch.shared->msr & MSR_FP)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_FP)
|
||||
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
|
||||
}
|
||||
|
||||
@ -427,8 +436,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
|
||||
|
||||
/* patch dcbz into reserved instruction, so we trap */
|
||||
for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++)
|
||||
if ((page[i] & 0xff0007ff) == INS_DCBZ)
|
||||
page[i] &= 0xfffffff7;
|
||||
if ((be32_to_cpu(page[i]) & 0xff0007ff) == INS_DCBZ)
|
||||
page[i] &= cpu_to_be32(0xfffffff7);
|
||||
|
||||
kunmap_atomic(page);
|
||||
put_page(hpage);
|
||||
@ -438,7 +447,7 @@ static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)
|
||||
{
|
||||
ulong mp_pa = vcpu->arch.magic_page_pa;
|
||||
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF))
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_SF))
|
||||
mp_pa = (uint32_t)mp_pa;
|
||||
|
||||
if (unlikely(mp_pa) &&
|
||||
@ -459,8 +468,8 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
int page_found = 0;
|
||||
struct kvmppc_pte pte;
|
||||
bool is_mmio = false;
|
||||
bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false;
|
||||
bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false;
|
||||
bool dr = (kvmppc_get_msr(vcpu) & MSR_DR) ? true : false;
|
||||
bool ir = (kvmppc_get_msr(vcpu) & MSR_IR) ? true : false;
|
||||
u64 vsid;
|
||||
|
||||
relocated = data ? dr : ir;
|
||||
@ -480,7 +489,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
pte.page_size = MMU_PAGE_64K;
|
||||
}
|
||||
|
||||
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
switch (kvmppc_get_msr(vcpu) & (MSR_DR|MSR_IR)) {
|
||||
case 0:
|
||||
pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
|
||||
break;
|
||||
@ -488,7 +497,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
case MSR_IR:
|
||||
vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
|
||||
|
||||
if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR)
|
||||
if ((kvmppc_get_msr(vcpu) & (MSR_DR|MSR_IR)) == MSR_DR)
|
||||
pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
|
||||
else
|
||||
pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
|
||||
@ -511,22 +520,25 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
|
||||
if (page_found == -ENOENT) {
|
||||
/* Page not found in guest PTE entries */
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
vcpu->arch.shared->dsisr = vcpu->arch.fault_dsisr;
|
||||
vcpu->arch.shared->msr |=
|
||||
vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL;
|
||||
u64 ssrr1 = vcpu->arch.shadow_srr1;
|
||||
u64 msr = kvmppc_get_msr(vcpu);
|
||||
kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
|
||||
kvmppc_set_dsisr(vcpu, vcpu->arch.fault_dsisr);
|
||||
kvmppc_set_msr_fast(vcpu, msr | (ssrr1 & 0xf8000000ULL));
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec);
|
||||
} else if (page_found == -EPERM) {
|
||||
/* Storage protection */
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
vcpu->arch.shared->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE;
|
||||
vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
|
||||
vcpu->arch.shared->msr |=
|
||||
vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL;
|
||||
u32 dsisr = vcpu->arch.fault_dsisr;
|
||||
u64 ssrr1 = vcpu->arch.shadow_srr1;
|
||||
u64 msr = kvmppc_get_msr(vcpu);
|
||||
kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
|
||||
dsisr = (dsisr & ~DSISR_NOHPTE) | DSISR_PROTFAULT;
|
||||
kvmppc_set_dsisr(vcpu, dsisr);
|
||||
kvmppc_set_msr_fast(vcpu, msr | (ssrr1 & 0xf8000000ULL));
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec);
|
||||
} else if (page_found == -EINVAL) {
|
||||
/* Page not found in guest SLB */
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
|
||||
} else if (!is_mmio &&
|
||||
kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
|
||||
@ -606,6 +618,25 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
|
||||
kvmppc_recalc_shadow_msr(vcpu);
|
||||
}
|
||||
|
||||
/* Give up facility (TAR / EBB / DSCR) */
|
||||
static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac)
|
||||
{
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
if (!(vcpu->arch.shadow_fscr & (1ULL << fac))) {
|
||||
/* Facility not available to the guest, ignore giveup request*/
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fac) {
|
||||
case FSCR_TAR_LG:
|
||||
vcpu->arch.tar = mfspr(SPRN_TAR);
|
||||
mtspr(SPRN_TAR, current->thread.tar);
|
||||
vcpu->arch.shadow_fscr &= ~FSCR_TAR;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
ulong srr0 = kvmppc_get_pc(vcpu);
|
||||
@ -614,11 +645,12 @@ static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
|
||||
|
||||
ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
|
||||
if (ret == -ENOENT) {
|
||||
ulong msr = vcpu->arch.shared->msr;
|
||||
ulong msr = kvmppc_get_msr(vcpu);
|
||||
|
||||
msr = kvmppc_set_field(msr, 33, 33, 1);
|
||||
msr = kvmppc_set_field(msr, 34, 36, 0);
|
||||
vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0);
|
||||
msr = kvmppc_set_field(msr, 42, 47, 0);
|
||||
kvmppc_set_msr_fast(vcpu, msr);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
|
||||
return EMULATE_AGAIN;
|
||||
}
|
||||
@ -651,7 +683,7 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
|
||||
if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)
|
||||
return RESUME_GUEST;
|
||||
|
||||
if (!(vcpu->arch.shared->msr & msr)) {
|
||||
if (!(kvmppc_get_msr(vcpu) & msr)) {
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
@ -683,16 +715,20 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
|
||||
#endif
|
||||
|
||||
if (msr & MSR_FP) {
|
||||
preempt_disable();
|
||||
enable_kernel_fp();
|
||||
load_fp_state(&vcpu->arch.fp);
|
||||
t->fp_save_area = &vcpu->arch.fp;
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
if (msr & MSR_VEC) {
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
preempt_disable();
|
||||
enable_kernel_altivec();
|
||||
load_vr_state(&vcpu->arch.vr);
|
||||
t->vr_save_area = &vcpu->arch.vr;
|
||||
preempt_enable();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -716,18 +752,90 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
|
||||
return;
|
||||
|
||||
if (lost_ext & MSR_FP) {
|
||||
preempt_disable();
|
||||
enable_kernel_fp();
|
||||
load_fp_state(&vcpu->arch.fp);
|
||||
preempt_enable();
|
||||
}
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
if (lost_ext & MSR_VEC) {
|
||||
preempt_disable();
|
||||
enable_kernel_altivec();
|
||||
load_vr_state(&vcpu->arch.vr);
|
||||
preempt_enable();
|
||||
}
|
||||
#endif
|
||||
current->thread.regs->msr |= lost_ext;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
|
||||
static void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac)
|
||||
{
|
||||
/* Inject the Interrupt Cause field and trigger a guest interrupt */
|
||||
vcpu->arch.fscr &= ~(0xffULL << 56);
|
||||
vcpu->arch.fscr |= (fac << 56);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FAC_UNAVAIL);
|
||||
}
|
||||
|
||||
static void kvmppc_emulate_fac(struct kvm_vcpu *vcpu, ulong fac)
|
||||
{
|
||||
enum emulation_result er = EMULATE_FAIL;
|
||||
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_PR))
|
||||
er = kvmppc_emulate_instruction(vcpu->run, vcpu);
|
||||
|
||||
if ((er != EMULATE_DONE) && (er != EMULATE_AGAIN)) {
|
||||
/* Couldn't emulate, trigger interrupt in guest */
|
||||
kvmppc_trigger_fac_interrupt(vcpu, fac);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable facilities (TAR, EBB, DSCR) for the guest */
|
||||
static int kvmppc_handle_fac(struct kvm_vcpu *vcpu, ulong fac)
|
||||
{
|
||||
bool guest_fac_enabled;
|
||||
BUG_ON(!cpu_has_feature(CPU_FTR_ARCH_207S));
|
||||
|
||||
/*
|
||||
* Not every facility is enabled by FSCR bits, check whether the
|
||||
* guest has this facility enabled at all.
|
||||
*/
|
||||
switch (fac) {
|
||||
case FSCR_TAR_LG:
|
||||
case FSCR_EBB_LG:
|
||||
guest_fac_enabled = (vcpu->arch.fscr & (1ULL << fac));
|
||||
break;
|
||||
case FSCR_TM_LG:
|
||||
guest_fac_enabled = kvmppc_get_msr(vcpu) & MSR_TM;
|
||||
break;
|
||||
default:
|
||||
guest_fac_enabled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!guest_fac_enabled) {
|
||||
/* Facility not enabled by the guest */
|
||||
kvmppc_trigger_fac_interrupt(vcpu, fac);
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
|
||||
switch (fac) {
|
||||
case FSCR_TAR_LG:
|
||||
/* TAR switching isn't lazy in Linux yet */
|
||||
current->thread.tar = mfspr(SPRN_TAR);
|
||||
mtspr(SPRN_TAR, vcpu->arch.tar);
|
||||
vcpu->arch.shadow_fscr |= FSCR_TAR;
|
||||
break;
|
||||
default:
|
||||
kvmppc_emulate_fac(vcpu, fac);
|
||||
break;
|
||||
}
|
||||
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
#endif
|
||||
|
||||
int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned int exit_nr)
|
||||
{
|
||||
@ -784,7 +892,9 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
|
||||
r = RESUME_GUEST;
|
||||
} else {
|
||||
vcpu->arch.shared->msr |= shadow_srr1 & 0x58000000;
|
||||
u64 msr = kvmppc_get_msr(vcpu);
|
||||
msr |= shadow_srr1 & 0x58000000;
|
||||
kvmppc_set_msr_fast(vcpu, msr);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
r = RESUME_GUEST;
|
||||
}
|
||||
@ -824,8 +934,8 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
} else {
|
||||
vcpu->arch.shared->dar = dar;
|
||||
vcpu->arch.shared->dsisr = fault_dsisr;
|
||||
kvmppc_set_dar(vcpu, dar);
|
||||
kvmppc_set_dsisr(vcpu, fault_dsisr);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
r = RESUME_GUEST;
|
||||
}
|
||||
@ -833,7 +943,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
}
|
||||
case BOOK3S_INTERRUPT_DATA_SEGMENT:
|
||||
if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) {
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
|
||||
kvmppc_book3s_queue_irqprio(vcpu,
|
||||
BOOK3S_INTERRUPT_DATA_SEGMENT);
|
||||
}
|
||||
@ -871,7 +981,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
program_interrupt:
|
||||
flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
|
||||
|
||||
if (vcpu->arch.shared->msr & MSR_PR) {
|
||||
if (kvmppc_get_msr(vcpu) & MSR_PR) {
|
||||
#ifdef EXIT_DEBUG
|
||||
printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
|
||||
#endif
|
||||
@ -913,7 +1023,7 @@ program_interrupt:
|
||||
case BOOK3S_INTERRUPT_SYSCALL:
|
||||
if (vcpu->arch.papr_enabled &&
|
||||
(kvmppc_get_last_sc(vcpu) == 0x44000022) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
!(kvmppc_get_msr(vcpu) & MSR_PR)) {
|
||||
/* SC 1 papr hypercalls */
|
||||
ulong cmd = kvmppc_get_gpr(vcpu, 3);
|
||||
int i;
|
||||
@ -945,7 +1055,7 @@ program_interrupt:
|
||||
gprs[i] = kvmppc_get_gpr(vcpu, i);
|
||||
vcpu->arch.osi_needed = 1;
|
||||
r = RESUME_HOST_NV;
|
||||
} else if (!(vcpu->arch.shared->msr & MSR_PR) &&
|
||||
} else if (!(kvmppc_get_msr(vcpu) & MSR_PR) &&
|
||||
(((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
|
||||
/* KVM PV hypercalls */
|
||||
kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
|
||||
@ -986,14 +1096,26 @@ program_interrupt:
|
||||
}
|
||||
case BOOK3S_INTERRUPT_ALIGNMENT:
|
||||
if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
|
||||
vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu,
|
||||
kvmppc_get_last_inst(vcpu));
|
||||
vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu,
|
||||
kvmppc_get_last_inst(vcpu));
|
||||
u32 last_inst = kvmppc_get_last_inst(vcpu);
|
||||
u32 dsisr;
|
||||
u64 dar;
|
||||
|
||||
dsisr = kvmppc_alignment_dsisr(vcpu, last_inst);
|
||||
dar = kvmppc_alignment_dar(vcpu, last_inst);
|
||||
|
||||
kvmppc_set_dsisr(vcpu, dsisr);
|
||||
kvmppc_set_dar(vcpu, dar);
|
||||
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
}
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
case BOOK3S_INTERRUPT_FAC_UNAVAIL:
|
||||
kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56);
|
||||
r = RESUME_GUEST;
|
||||
break;
|
||||
#endif
|
||||
case BOOK3S_INTERRUPT_MACHINE_CHECK:
|
||||
case BOOK3S_INTERRUPT_TRACE:
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
@ -1054,7 +1176,7 @@ static int kvm_arch_vcpu_ioctl_get_sregs_pr(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 16; i++)
|
||||
sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i];
|
||||
sregs->u.s.ppc32.sr[i] = kvmppc_get_sr(vcpu, i);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw;
|
||||
@ -1110,6 +1232,15 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
|
||||
case KVM_REG_PPC_HIOR:
|
||||
*val = get_reg_val(id, to_book3s(vcpu)->hior);
|
||||
break;
|
||||
case KVM_REG_PPC_LPCR:
|
||||
/*
|
||||
* We are only interested in the LPCR_ILE bit
|
||||
*/
|
||||
if (vcpu->arch.intr_msr & MSR_LE)
|
||||
*val = get_reg_val(id, LPCR_ILE);
|
||||
else
|
||||
*val = get_reg_val(id, 0);
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
break;
|
||||
@ -1118,6 +1249,14 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvmppc_set_lpcr_pr(struct kvm_vcpu *vcpu, u64 new_lpcr)
|
||||
{
|
||||
if (new_lpcr & LPCR_ILE)
|
||||
vcpu->arch.intr_msr |= MSR_LE;
|
||||
else
|
||||
vcpu->arch.intr_msr &= ~MSR_LE;
|
||||
}
|
||||
|
||||
static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
|
||||
union kvmppc_one_reg *val)
|
||||
{
|
||||
@ -1128,6 +1267,9 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
|
||||
to_book3s(vcpu)->hior = set_reg_val(id, *val);
|
||||
to_book3s(vcpu)->hior_explicit = true;
|
||||
break;
|
||||
case KVM_REG_PPC_LPCR:
|
||||
kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
break;
|
||||
@ -1170,8 +1312,14 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm,
|
||||
goto uninit_vcpu;
|
||||
/* the real shared page fills the last 4k of our page */
|
||||
vcpu->arch.shared = (void *)(p + PAGE_SIZE - 4096);
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
/* Always start the shared struct in native endian mode */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
vcpu->arch.shared_big_endian = true;
|
||||
#else
|
||||
vcpu->arch.shared_big_endian = false;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default to the same as the host if we're on sufficiently
|
||||
* recent machine that we have 1TB segments;
|
||||
@ -1180,6 +1328,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm,
|
||||
vcpu->arch.pvr = 0x3C0301;
|
||||
if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
|
||||
vcpu->arch.pvr = mfspr(SPRN_PVR);
|
||||
vcpu->arch.intr_msr = MSR_SF;
|
||||
#else
|
||||
/* default to book3s_32 (750) */
|
||||
vcpu->arch.pvr = 0x84202;
|
||||
@ -1187,7 +1336,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm,
|
||||
kvmppc_set_pvr_pr(vcpu, vcpu->arch.pvr);
|
||||
vcpu->arch.slb_nr = 64;
|
||||
|
||||
vcpu->arch.shadow_msr = MSR_USER64;
|
||||
vcpu->arch.shadow_msr = MSR_USER64 & ~MSR_LE;
|
||||
|
||||
err = kvmppc_mmu_init(vcpu);
|
||||
if (err < 0)
|
||||
@ -1264,7 +1413,7 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
||||
#endif
|
||||
|
||||
/* Preload FPU if it's enabled */
|
||||
if (vcpu->arch.shared->msr & MSR_FP)
|
||||
if (kvmppc_get_msr(vcpu) & MSR_FP)
|
||||
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
|
||||
|
||||
kvmppc_fix_ee_before_entry();
|
||||
@ -1277,6 +1426,9 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
||||
/* Make sure we save the guest FPU/Altivec/VSX state */
|
||||
kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
|
||||
|
||||
/* Make sure we save the guest TAR/EBB/DSCR state */
|
||||
kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
|
||||
|
||||
out:
|
||||
vcpu->mode = OUTSIDE_GUEST_MODE;
|
||||
return ret;
|
||||
|
@ -57,7 +57,7 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
|
||||
for (i = 0; ; ++i) {
|
||||
if (i == 8)
|
||||
goto done;
|
||||
if ((*hpte & HPTE_V_VALID) == 0)
|
||||
if ((be64_to_cpu(*hpte) & HPTE_V_VALID) == 0)
|
||||
break;
|
||||
hpte += 2;
|
||||
}
|
||||
@ -67,8 +67,8 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
|
||||
goto done;
|
||||
}
|
||||
|
||||
hpte[0] = kvmppc_get_gpr(vcpu, 6);
|
||||
hpte[1] = kvmppc_get_gpr(vcpu, 7);
|
||||
hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6));
|
||||
hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7));
|
||||
pteg_addr += i * HPTE_SIZE;
|
||||
copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
|
||||
kvmppc_set_gpr(vcpu, 4, pte_index | i);
|
||||
@ -93,6 +93,8 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
|
||||
pteg = get_pteg_addr(vcpu, pte_index);
|
||||
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
|
||||
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
|
||||
pte[0] = be64_to_cpu(pte[0]);
|
||||
pte[1] = be64_to_cpu(pte[1]);
|
||||
|
||||
ret = H_NOT_FOUND;
|
||||
if ((pte[0] & HPTE_V_VALID) == 0 ||
|
||||
@ -169,6 +171,8 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
|
||||
|
||||
pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
|
||||
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
|
||||
pte[0] = be64_to_cpu(pte[0]);
|
||||
pte[1] = be64_to_cpu(pte[1]);
|
||||
|
||||
/* tsl = AVPN */
|
||||
flags = (tsh & H_BULK_REMOVE_FLAGS) >> 26;
|
||||
@ -207,6 +211,8 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
|
||||
pteg = get_pteg_addr(vcpu, pte_index);
|
||||
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
|
||||
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
|
||||
pte[0] = be64_to_cpu(pte[0]);
|
||||
pte[1] = be64_to_cpu(pte[1]);
|
||||
|
||||
ret = H_NOT_FOUND;
|
||||
if ((pte[0] & HPTE_V_VALID) == 0 ||
|
||||
@ -225,6 +231,8 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
|
||||
|
||||
rb = compute_tlbie_rb(v, r, pte_index);
|
||||
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
|
||||
pte[0] = cpu_to_be64(pte[0]);
|
||||
pte[1] = cpu_to_be64(pte[1]);
|
||||
copy_to_user((void __user *)pteg, pte, sizeof(pte));
|
||||
ret = H_SUCCESS;
|
||||
|
||||
@ -270,7 +278,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
|
||||
case H_PUT_TCE:
|
||||
return kvmppc_h_pr_put_tce(vcpu);
|
||||
case H_CEDE:
|
||||
vcpu->arch.shared->msr |= MSR_EE;
|
||||
kvmppc_set_msr_fast(vcpu, kvmppc_get_msr(vcpu) | MSR_EE);
|
||||
kvm_vcpu_block(vcpu);
|
||||
clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
|
||||
vcpu->stat.halt_wakeup++;
|
||||
|
@ -205,6 +205,32 @@ int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void kvmppc_rtas_swap_endian_in(struct rtas_args *args)
|
||||
{
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
int i;
|
||||
|
||||
args->token = be32_to_cpu(args->token);
|
||||
args->nargs = be32_to_cpu(args->nargs);
|
||||
args->nret = be32_to_cpu(args->nret);
|
||||
for (i = 0; i < args->nargs; i++)
|
||||
args->args[i] = be32_to_cpu(args->args[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void kvmppc_rtas_swap_endian_out(struct rtas_args *args)
|
||||
{
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
int i;
|
||||
|
||||
for (i = 0; i < args->nret; i++)
|
||||
args->args[i] = cpu_to_be32(args->args[i]);
|
||||
args->token = cpu_to_be32(args->token);
|
||||
args->nargs = cpu_to_be32(args->nargs);
|
||||
args->nret = cpu_to_be32(args->nret);
|
||||
#endif
|
||||
}
|
||||
|
||||
int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct rtas_token_definition *d;
|
||||
@ -223,6 +249,8 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
kvmppc_rtas_swap_endian_in(&args);
|
||||
|
||||
/*
|
||||
* args->rets is a pointer into args->args. Now that we've
|
||||
* copied args we need to fix it up to point into our copy,
|
||||
@ -247,6 +275,7 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (rc == 0) {
|
||||
args.rets = orig_rets;
|
||||
kvmppc_rtas_swap_endian_out(&args);
|
||||
rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
@ -90,6 +90,15 @@ kvmppc_handler_trampoline_enter:
|
||||
LOAD_GUEST_SEGMENTS
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
BEGIN_FTR_SECTION
|
||||
/* Save host FSCR */
|
||||
mfspr r8, SPRN_FSCR
|
||||
std r8, HSTATE_HOST_FSCR(r13)
|
||||
/* Set FSCR during guest execution */
|
||||
ld r9, SVCPU_SHADOW_FSCR(r13)
|
||||
mtspr SPRN_FSCR, r9
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
|
||||
/* Some guests may need to have dcbz set to 32 byte length.
|
||||
*
|
||||
* Usually we ensure that by patching the guest's instructions
|
||||
@ -255,6 +264,10 @@ BEGIN_FTR_SECTION
|
||||
cmpwi r12, BOOK3S_INTERRUPT_H_EMUL_ASSIST
|
||||
beq- ld_last_inst
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
|
||||
BEGIN_FTR_SECTION
|
||||
cmpwi r12, BOOK3S_INTERRUPT_FAC_UNAVAIL
|
||||
beq- ld_last_inst
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
#endif
|
||||
|
||||
b no_ld_last_inst
|
||||
@ -311,6 +324,18 @@ no_ld_last_inst:
|
||||
|
||||
no_dcbz32_off:
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
/* Save guest FSCR on a FAC_UNAVAIL interrupt */
|
||||
cmpwi r12, BOOK3S_INTERRUPT_FAC_UNAVAIL
|
||||
bne+ no_fscr_save
|
||||
mfspr r7, SPRN_FSCR
|
||||
std r7, SVCPU_SHADOW_FSCR(r13)
|
||||
no_fscr_save:
|
||||
/* Restore host FSCR */
|
||||
ld r8, HSTATE_HOST_FSCR(r13)
|
||||
mtspr SPRN_FSCR, r8
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
|
||||
|
||||
#endif /* CONFIG_PPC_BOOK3S_64 */
|
||||
|
||||
/*
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "booke.h"
|
||||
#include "e500.h"
|
||||
|
||||
#define XOP_DCBTLS 166
|
||||
#define XOP_MSGSND 206
|
||||
#define XOP_MSGCLR 238
|
||||
#define XOP_TLBIVAX 786
|
||||
@ -103,6 +104,15 @@ static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
return emulated;
|
||||
}
|
||||
|
||||
static int kvmppc_e500_emul_dcbtls(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
|
||||
|
||||
/* Always fail to lock the cache */
|
||||
vcpu_e500->l1csr0 |= L1CSR0_CUL;
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
|
||||
int kvmppc_core_emulate_op_e500(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned int inst, int *advance)
|
||||
{
|
||||
@ -116,6 +126,10 @@ int kvmppc_core_emulate_op_e500(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
case 31:
|
||||
switch (get_xop(inst)) {
|
||||
|
||||
case XOP_DCBTLS:
|
||||
emulated = kvmppc_e500_emul_dcbtls(vcpu);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_KVM_E500MC
|
||||
case XOP_MSGSND:
|
||||
emulated = kvmppc_e500_emul_msgsnd(vcpu, rb);
|
||||
@ -222,6 +236,7 @@ int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_va
|
||||
break;
|
||||
case SPRN_L1CSR1:
|
||||
vcpu_e500->l1csr1 = spr_val;
|
||||
vcpu_e500->l1csr1 &= ~(L1CSR1_ICFI | L1CSR1_ICLFR);
|
||||
break;
|
||||
case SPRN_HID0:
|
||||
vcpu_e500->hid0 = spr_val;
|
||||
|
@ -97,10 +97,10 @@ static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
|
||||
|
||||
switch (sprn) {
|
||||
case SPRN_SRR0:
|
||||
vcpu->arch.shared->srr0 = spr_val;
|
||||
kvmppc_set_srr0(vcpu, spr_val);
|
||||
break;
|
||||
case SPRN_SRR1:
|
||||
vcpu->arch.shared->srr1 = spr_val;
|
||||
kvmppc_set_srr1(vcpu, spr_val);
|
||||
break;
|
||||
|
||||
/* XXX We need to context-switch the timebase for
|
||||
@ -114,16 +114,16 @@ static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
|
||||
break;
|
||||
|
||||
case SPRN_SPRG0:
|
||||
vcpu->arch.shared->sprg0 = spr_val;
|
||||
kvmppc_set_sprg0(vcpu, spr_val);
|
||||
break;
|
||||
case SPRN_SPRG1:
|
||||
vcpu->arch.shared->sprg1 = spr_val;
|
||||
kvmppc_set_sprg1(vcpu, spr_val);
|
||||
break;
|
||||
case SPRN_SPRG2:
|
||||
vcpu->arch.shared->sprg2 = spr_val;
|
||||
kvmppc_set_sprg2(vcpu, spr_val);
|
||||
break;
|
||||
case SPRN_SPRG3:
|
||||
vcpu->arch.shared->sprg3 = spr_val;
|
||||
kvmppc_set_sprg3(vcpu, spr_val);
|
||||
break;
|
||||
|
||||
/* PIR can legally be written, but we ignore it */
|
||||
@ -150,10 +150,10 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
|
||||
|
||||
switch (sprn) {
|
||||
case SPRN_SRR0:
|
||||
spr_val = vcpu->arch.shared->srr0;
|
||||
spr_val = kvmppc_get_srr0(vcpu);
|
||||
break;
|
||||
case SPRN_SRR1:
|
||||
spr_val = vcpu->arch.shared->srr1;
|
||||
spr_val = kvmppc_get_srr1(vcpu);
|
||||
break;
|
||||
case SPRN_PVR:
|
||||
spr_val = vcpu->arch.pvr;
|
||||
@ -173,16 +173,16 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
|
||||
break;
|
||||
|
||||
case SPRN_SPRG0:
|
||||
spr_val = vcpu->arch.shared->sprg0;
|
||||
spr_val = kvmppc_get_sprg0(vcpu);
|
||||
break;
|
||||
case SPRN_SPRG1:
|
||||
spr_val = vcpu->arch.shared->sprg1;
|
||||
spr_val = kvmppc_get_sprg1(vcpu);
|
||||
break;
|
||||
case SPRN_SPRG2:
|
||||
spr_val = vcpu->arch.shared->sprg2;
|
||||
spr_val = kvmppc_get_sprg2(vcpu);
|
||||
break;
|
||||
case SPRN_SPRG3:
|
||||
spr_val = vcpu->arch.shared->sprg3;
|
||||
spr_val = kvmppc_get_sprg3(vcpu);
|
||||
break;
|
||||
/* Note: SPRG4-7 are user-readable, so we don't get
|
||||
* a trap. */
|
||||
|
@ -126,6 +126,8 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
|
||||
u32 val, int idx);
|
||||
static int openpic_cpu_read_internal(void *opaque, gpa_t addr,
|
||||
u32 *ptr, int idx);
|
||||
static inline void write_IRQreg_idr(struct openpic *opp, int n_IRQ,
|
||||
uint32_t val);
|
||||
|
||||
enum irq_type {
|
||||
IRQ_TYPE_NORMAL = 0,
|
||||
@ -528,7 +530,6 @@ static void openpic_reset(struct openpic *opp)
|
||||
/* Initialise IRQ sources */
|
||||
for (i = 0; i < opp->max_irq; i++) {
|
||||
opp->src[i].ivpr = opp->ivpr_reset;
|
||||
opp->src[i].idr = opp->idr_reset;
|
||||
|
||||
switch (opp->src[i].type) {
|
||||
case IRQ_TYPE_NORMAL:
|
||||
@ -543,6 +544,8 @@ static void openpic_reset(struct openpic *opp)
|
||||
case IRQ_TYPE_FSLSPECIAL:
|
||||
break;
|
||||
}
|
||||
|
||||
write_IRQreg_idr(opp, i, opp->idr_reset);
|
||||
}
|
||||
/* Initialise IRQ destinations */
|
||||
for (i = 0; i < MAX_CPU; i++) {
|
||||
|
@ -125,6 +125,27 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter);
|
||||
|
||||
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
|
||||
static void kvmppc_swab_shared(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared;
|
||||
int i;
|
||||
|
||||
shared->sprg0 = swab64(shared->sprg0);
|
||||
shared->sprg1 = swab64(shared->sprg1);
|
||||
shared->sprg2 = swab64(shared->sprg2);
|
||||
shared->sprg3 = swab64(shared->sprg3);
|
||||
shared->srr0 = swab64(shared->srr0);
|
||||
shared->srr1 = swab64(shared->srr1);
|
||||
shared->dar = swab64(shared->dar);
|
||||
shared->msr = swab64(shared->msr);
|
||||
shared->dsisr = swab32(shared->dsisr);
|
||||
shared->int_pending = swab32(shared->int_pending);
|
||||
for (i = 0; i < ARRAY_SIZE(shared->sr); i++)
|
||||
shared->sr[i] = swab32(shared->sr[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int nr = kvmppc_get_gpr(vcpu, 11);
|
||||
@ -135,7 +156,7 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
|
||||
unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);
|
||||
unsigned long r2 = 0;
|
||||
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF)) {
|
||||
if (!(kvmppc_get_msr(vcpu) & MSR_SF)) {
|
||||
/* 32 bit mode */
|
||||
param1 &= 0xffffffff;
|
||||
param2 &= 0xffffffff;
|
||||
@ -146,8 +167,28 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
|
||||
switch (nr) {
|
||||
case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE):
|
||||
{
|
||||
vcpu->arch.magic_page_pa = param1;
|
||||
vcpu->arch.magic_page_ea = param2;
|
||||
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE)
|
||||
/* Book3S can be little endian, find it out here */
|
||||
int shared_big_endian = true;
|
||||
if (vcpu->arch.intr_msr & MSR_LE)
|
||||
shared_big_endian = false;
|
||||
if (shared_big_endian != vcpu->arch.shared_big_endian)
|
||||
kvmppc_swab_shared(vcpu);
|
||||
vcpu->arch.shared_big_endian = shared_big_endian;
|
||||
#endif
|
||||
|
||||
if (!(param2 & MAGIC_PAGE_FLAG_NOT_MAPPED_NX)) {
|
||||
/*
|
||||
* Older versions of the Linux magic page code had
|
||||
* a bug where they would map their trampoline code
|
||||
* NX. If that's the case, remove !PR NX capability.
|
||||
*/
|
||||
vcpu->arch.disable_kernel_nx = true;
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
|
||||
}
|
||||
|
||||
vcpu->arch.magic_page_pa = param1 & ~0xfffULL;
|
||||
vcpu->arch.magic_page_ea = param2 & ~0xfffULL;
|
||||
|
||||
r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
|
||||
|
||||
@ -375,6 +416,7 @@ int kvm_dev_ioctl_check_extension(long ext)
|
||||
case KVM_CAP_SPAPR_TCE:
|
||||
case KVM_CAP_PPC_ALLOC_HTAB:
|
||||
case KVM_CAP_PPC_RTAS:
|
||||
case KVM_CAP_PPC_FIXUP_HCALL:
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
case KVM_CAP_IRQ_XICS:
|
||||
#endif
|
||||
@ -1015,10 +1057,10 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
|
||||
u32 inst_nop = 0x60000000;
|
||||
#ifdef CONFIG_KVM_BOOKE_HV
|
||||
u32 inst_sc1 = 0x44000022;
|
||||
pvinfo->hcall[0] = inst_sc1;
|
||||
pvinfo->hcall[1] = inst_nop;
|
||||
pvinfo->hcall[2] = inst_nop;
|
||||
pvinfo->hcall[3] = inst_nop;
|
||||
pvinfo->hcall[0] = cpu_to_be32(inst_sc1);
|
||||
pvinfo->hcall[1] = cpu_to_be32(inst_nop);
|
||||
pvinfo->hcall[2] = cpu_to_be32(inst_nop);
|
||||
pvinfo->hcall[3] = cpu_to_be32(inst_nop);
|
||||
#else
|
||||
u32 inst_lis = 0x3c000000;
|
||||
u32 inst_ori = 0x60000000;
|
||||
@ -1034,10 +1076,10 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
|
||||
* sc
|
||||
* nop
|
||||
*/
|
||||
pvinfo->hcall[0] = inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask);
|
||||
pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
|
||||
pvinfo->hcall[2] = inst_sc;
|
||||
pvinfo->hcall[3] = inst_nop;
|
||||
pvinfo->hcall[0] = cpu_to_be32(inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask));
|
||||
pvinfo->hcall[1] = cpu_to_be32(inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask));
|
||||
pvinfo->hcall[2] = cpu_to_be32(inst_sc);
|
||||
pvinfo->hcall[3] = cpu_to_be32(inst_nop);
|
||||
#endif
|
||||
|
||||
pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE;
|
||||
|
@ -255,7 +255,7 @@ TRACE_EVENT(kvm_exit,
|
||||
__entry->exit_nr = exit_nr;
|
||||
__entry->pc = kvmppc_get_pc(vcpu);
|
||||
__entry->dar = kvmppc_get_fault_dar(vcpu);
|
||||
__entry->msr = vcpu->arch.shared->msr;
|
||||
__entry->msr = kvmppc_get_msr(vcpu);
|
||||
__entry->srr1 = vcpu->arch.shadow_srr1;
|
||||
__entry->last_inst = vcpu->arch.last_inst;
|
||||
),
|
||||
|
@ -97,7 +97,7 @@ static inline void create_shadowed_slbe(unsigned long ea, int ssize,
|
||||
static void __slb_flush_and_rebolt(void)
|
||||
{
|
||||
/* If you change this make sure you change SLB_NUM_BOLTED
|
||||
* appropriately too. */
|
||||
* and PR KVM appropriately too. */
|
||||
unsigned long linear_llp, vmalloc_llp, lflags, vflags;
|
||||
unsigned long ksp_esid_data, ksp_vsid_data;
|
||||
|
||||
|
@ -757,6 +757,7 @@ struct kvm_ppc_smmu_info {
|
||||
#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
|
||||
#define KVM_CAP_VM_ATTRIBUTES 101
|
||||
#define KVM_CAP_ARM_PSCI_0_2 102
|
||||
#define KVM_CAP_PPC_FIXUP_HCALL 103
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user