Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5deb8e7a authored by Alexander Graf's avatar Alexander Graf
Browse files

KVM: PPC: Make shared struct aka magic page guest endian



The shared (magic) page is a data structure that contains often used
supervisor privileged SPRs accessible via memory to the user to reduce
the number of exits we have to take to read/write them.

When we actually share this structure with the guest we have to maintain
it in guest endianness, because some of the patch tricks only work with
native endian load/store operations.

Since we only share the structure with either host or guest in little
endian on book3s_64 pr mode, we don't have to worry about booke or book3s hv.

For booke, the shared struct stays big endian. For book3s_64 hv we maintain
the struct in host native endian, since it never gets shared with the guest.

For book3s_64 pr we introduce a variable that tells us which endianness the
shared struct is in and route every access to it through helper inline
functions that evaluate this variable.

Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 2743103f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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)
+0 −5
Original line number Diff line number Diff line
@@ -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__ */
+3 −0
Original line number Diff line number Diff line
@@ -623,6 +623,9 @@ 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 */

+79 −1
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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
@@ -467,6 +468,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));
Loading