Commit f2104bf2 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

KVM: e500: track host-writability of pages



Add the possibility of marking a page so that the UW and SW bits are
force-cleared.  This is stored in the private info so that it persists
across multiple calls to kvmppc_e500_setup_stlbe.

Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent e97fbb43
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ enum vcpu_ftr {
#define E500_TLB_BITMAP		(1 << 30)
/* TLB1 entry is mapped by host TLB0 */
#define E500_TLB_TLB0		(1 << 29)
/* entry is writable on the host */
#define E500_TLB_WRITABLE	(1 << 28)
/* bits [6-5] MAS2_X1 and MAS2_X0 and [4-0] bits for WIMGE */
#define E500_TLB_MAS2_ATTR	(0x7f)

+11 −4
Original line number Diff line number Diff line
@@ -45,11 +45,14 @@ static inline unsigned int tlb1_max_shadow_size(void)
	return host_tlb_params[1].entries - tlbcam_index - 1;
}

static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode)
static inline u32 e500_shadow_mas3_attrib(u32 mas3, bool writable, int usermode)
{
	/* Mask off reserved bits. */
	mas3 &= MAS3_ATTRIB_MASK;

	if (!writable)
		mas3 &= ~(MAS3_UW|MAS3_SW);

#ifndef CONFIG_KVM_BOOKE_HV
	if (!usermode) {
		/* Guest is in supervisor mode,
@@ -244,10 +247,13 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)

static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
					 struct kvm_book3e_206_tlb_entry *gtlbe,
					 kvm_pfn_t pfn, unsigned int wimg)
					 kvm_pfn_t pfn, unsigned int wimg,
					 bool writable)
{
	ref->pfn = pfn;
	ref->flags = E500_TLB_VALID;
	if (writable)
		ref->flags |= E500_TLB_WRITABLE;

	/* Use guest supplied MAS2_G and MAS2_E */
	ref->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg;
@@ -303,6 +309,7 @@ static void kvmppc_e500_setup_stlbe(
{
	kvm_pfn_t pfn = ref->pfn;
	u32 pr = vcpu->arch.shared->msr & MSR_PR;
	bool writable = !!(ref->flags & E500_TLB_WRITABLE);

	BUG_ON(!(ref->flags & E500_TLB_VALID));

@@ -310,7 +317,7 @@ static void kvmppc_e500_setup_stlbe(
	stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID;
	stlbe->mas2 = (gvaddr & MAS2_EPN) | (ref->flags & E500_TLB_MAS2_ATTR);
	stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) |
			e500_shadow_mas3_attrib(gtlbe->mas7_3, pr);
			e500_shadow_mas3_attrib(gtlbe->mas7_3, writable, pr);
}

static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
@@ -487,7 +494,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
	}
	local_irq_restore(flags);

	kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg);
	kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg, true);
	kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
				ref, gvaddr, stlbe);
	writable = tlbe_is_writable(stlbe);