Re: [RFC PATCH 16/32] KVM: PPC: Book3S HV: Make kvmppc_mmu_radix_xlate process/partition table agnostic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Sep 21, 2018 at 08:01:47PM +1000, Paul Mackerras wrote:
> From: Suraj Jitindar Singh <sjitindarsingh@xxxxxxxxx>
> 
> kvmppc_mmu_radix_xlate() is used to translate an effective address
> through the process tables. The process table and partition tables have
> identical layout. Exploit this fact to make the kvmppc_mmu_radix_xlate()
> function able to translate either an effective address through the
> process tables or a guest real address through the partition tables.
> 
> [paulus@xxxxxxxxxx - reduced diffs from previous code]
> 
> Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@xxxxxxxxx>
> Signed-off-by: Paul Mackerras <paulus@xxxxxxxxxx>

Reviewed-by: David Gibson <david@xxxxxxxxxxxxxxxxxxxxx>

> ---
>  arch/powerpc/include/asm/kvm_book3s.h  |   3 +
>  arch/powerpc/kvm/book3s_64_mmu_radix.c | 109 +++++++++++++++++++++++----------
>  2 files changed, 78 insertions(+), 34 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
> index dd18d81..91c9779 100644
> --- a/arch/powerpc/include/asm/kvm_book3s.h
> +++ b/arch/powerpc/include/asm/kvm_book3s.h
> @@ -188,6 +188,9 @@ extern int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hc);
>  extern int kvmppc_book3s_radix_page_fault(struct kvm_run *run,
>  			struct kvm_vcpu *vcpu,
>  			unsigned long ea, unsigned long dsisr);
> +extern int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr,
> +			struct kvmppc_pte *gpte, u64 table,
> +			int table_index, u64 *pte_ret_p);
>  extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
>  			struct kvmppc_pte *gpte, bool data, bool iswrite);
>  extern int kvmppc_init_vm_radix(struct kvm *kvm);
> diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
> index 71951b5..f2976f4 100644
> --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
> +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
> @@ -29,83 +29,92 @@
>   */
>  static int p9_supported_radix_bits[4] = { 5, 9, 9, 13 };
>  
> -int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
> -			   struct kvmppc_pte *gpte, bool data, bool iswrite)
> +/*
> + * Used to walk a partition or process table radix tree in guest memory
> + * Note: We exploit the fact that a partition table and a process
> + * table have the same layout, a partition-scoped page table and a
> + * process-scoped page table have the same layout, and the 2nd
> + * doubleword of a partition table entry has the same layout as
> + * the PTCR register.
> + */
> +int kvmppc_mmu_radix_translate_table(struct kvm_vcpu *vcpu, gva_t eaddr,
> +				     struct kvmppc_pte *gpte, u64 table,
> +				     int table_index, u64 *pte_ret_p)
>  {
>  	struct kvm *kvm = vcpu->kvm;
> -	u32 pid;
>  	int ret, level, ps;
> -	__be64 prte, rpte;
> -	unsigned long ptbl;
> -	unsigned long root, pte, index;
> +	unsigned long ptbl, root;
>  	unsigned long rts, bits, offset;
> -	unsigned long gpa;
> -	unsigned long proc_tbl_size;
> +	unsigned long size, index;
> +	struct prtb_entry entry;
> +	u64 pte, base, gpa;
> +	__be64 rpte;
>  
> -	/* Work out effective PID */
> -	switch (eaddr >> 62) {
> -	case 0:
> -		pid = vcpu->arch.pid;
> -		break;
> -	case 3:
> -		pid = 0;
> -		break;
> -	default:
> +	if ((table & PRTS_MASK) > 24)
>  		return -EINVAL;
> -	}
> -	proc_tbl_size = 1 << ((kvm->arch.process_table & PRTS_MASK) + 12);
> -	if (pid * 16 >= proc_tbl_size)
> +	size = 1ul << ((table & PRTS_MASK) + 12);
> +
> +	/* Is the table big enough to contain this entry? */
> +	if ((table_index * sizeof(entry)) >= size)
>  		return -EINVAL;
>  
> -	/* Read partition table to find root of tree for effective PID */
> -	ptbl = (kvm->arch.process_table & PRTB_MASK) + (pid * 16);
> -	ret = kvm_read_guest(kvm, ptbl, &prte, sizeof(prte));
> +	/* Read the table to find the root of the radix tree */
> +	ptbl = (table & PRTB_MASK) + (table_index * sizeof(entry));
> +	ret = kvm_read_guest(kvm, ptbl, &entry, sizeof(entry));
>  	if (ret)
>  		return ret;
>  
> -	root = be64_to_cpu(prte);
> +	/* Root is stored in the first double word */
> +	root = be64_to_cpu(entry.prtb0);
>  	rts = ((root & RTS1_MASK) >> (RTS1_SHIFT - 3)) |
>  		((root & RTS2_MASK) >> RTS2_SHIFT);
>  	bits = root & RPDS_MASK;
> -	root = root & RPDB_MASK;
> +	base = root & RPDB_MASK;
>  
>  	offset = rts + 31;
>  
> -	/* current implementations only support 52-bit space */
> +	/* Current implementations only support 52-bit space */
>  	if (offset != 52)
>  		return -EINVAL;
>  
> +	/* Walk each level of the radix tree */
>  	for (level = 3; level >= 0; --level) {
> +		/* Check a valid size */
>  		if (level && bits != p9_supported_radix_bits[level])
>  			return -EINVAL;
>  		if (level == 0 && !(bits == 5 || bits == 9))
>  			return -EINVAL;
>  		offset -= bits;
>  		index = (eaddr >> offset) & ((1UL << bits) - 1);
> -		/* check that low bits of page table base are zero */
> -		if (root & ((1UL << (bits + 3)) - 1))
> +		/* Check that low bits of page table base are zero */
> +		if (base & ((1UL << (bits + 3)) - 1))
>  			return -EINVAL;
> -		ret = kvm_read_guest(kvm, root + index * 8,
> +		/* Read the entry from guest memory */
> +		ret = kvm_read_guest(kvm, base + (index * sizeof(rpte)),
>  				     &rpte, sizeof(rpte));
>  		if (ret)
>  			return ret;
>  		pte = __be64_to_cpu(rpte);
>  		if (!(pte & _PAGE_PRESENT))
>  			return -ENOENT;
> +		/* Check if a leaf entry */
>  		if (pte & _PAGE_PTE)
>  			break;
> -		bits = pte & 0x1f;
> -		root = pte & 0x0fffffffffffff00ul;
> +		/* Get ready to walk the next level */
> +		base = pte & RPDB_MASK;
> +		bits = pte & RPDS_MASK;
>  	}
> -	/* need a leaf at lowest level; 512GB pages not supported */
> +
> +	/* Need a leaf at lowest level; 512GB pages not supported */
>  	if (level < 0 || level == 3)
>  		return -EINVAL;
>  
> -	/* offset is now log base 2 of the page size */
> +	/* We found a valid leaf PTE */
> +	/* Offset is now log base 2 of the page size */
>  	gpa = pte & 0x01fffffffffff000ul;
>  	if (gpa & ((1ul << offset) - 1))
>  		return -EINVAL;
> -	gpa += eaddr & ((1ul << offset) - 1);
> +	gpa |= eaddr & ((1ul << offset) - 1);
>  	for (ps = MMU_PAGE_4K; ps < MMU_PAGE_COUNT; ++ps)
>  		if (offset == mmu_psize_defs[ps].shift)
>  			break;
> @@ -118,6 +127,38 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
>  	gpte->may_read = !!(pte & _PAGE_READ);
>  	gpte->may_write = !!(pte & _PAGE_WRITE);
>  	gpte->may_execute = !!(pte & _PAGE_EXEC);
> +
> +	if (pte_ret_p)
> +		*pte_ret_p = pte;
> +
> +	return 0;
> +}
> +
> +int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
> +			   struct kvmppc_pte *gpte, bool data, bool iswrite)
> +{
> +	u32 pid;
> +	u64 pte;
> +	int ret;
> +
> +	/* Work out effective PID */
> +	switch (eaddr >> 62) {
> +	case 0:
> +		pid = vcpu->arch.pid;
> +		break;
> +	case 3:
> +		pid = 0;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = kvmppc_mmu_radix_translate_table(vcpu, eaddr, gpte,
> +				vcpu->kvm->arch.process_table, pid, &pte);
> +	if (ret)
> +		return ret;
> +
> +	/* Check privilege (applies only to process scoped translations) */
>  	if (kvmppc_get_msr(vcpu) & MSR_PR) {
>  		if (pte & _PAGE_PRIVILEGED) {
>  			gpte->may_read = 0;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux