[PATCH v6 4/6] KVM: PPC: Book3S HV: Nested support in H_RPT_INVALIDATE
David Gibson
david at gibson.dropbear.id.au
Tue Mar 23 13:33:21 AEDT 2021
On Thu, Mar 11, 2021 at 02:09:37PM +0530, Bharata B Rao wrote:
> Enable support for process-scoped invalidations from nested
> guests and partition-scoped invalidations for nested guests.
>
> Process-scoped invalidations for any level of nested guests
> are handled by implementing H_RPT_INVALIDATE handler in the
> nested guest exit path in L0.
>
> Partition-scoped invalidation requests are forwarded to the
> right nested guest, handled there and passed down to L0
> for eventual handling.
>
> Signed-off-by: Bharata B Rao <bharata at linux.ibm.com>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.ibm.com>
> [Nested guest partition-scoped invalidation changes]
Reviewed-by: David Gibson <david at gibson.dropbear.id.au>
> ---
> arch/powerpc/include/asm/kvm_book3s.h | 3 +
> arch/powerpc/kvm/book3s_hv.c | 71 +++++++++++++++++-
> arch/powerpc/kvm/book3s_hv_nested.c | 104 ++++++++++++++++++++++++++
> 3 files changed, 175 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
> index 2f5f919f6cd3..de8fc5a4d19c 100644
> --- a/arch/powerpc/include/asm/kvm_book3s.h
> +++ b/arch/powerpc/include/asm/kvm_book3s.h
> @@ -305,6 +305,9 @@ void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1);
> void kvmhv_release_all_nested(struct kvm *kvm);
> long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu);
> long kvmhv_do_nested_tlbie(struct kvm_vcpu *vcpu);
> +long do_h_rpt_invalidate_pat(struct kvm_vcpu *vcpu, unsigned long lpid,
> + unsigned long type, unsigned long pg_sizes,
> + unsigned long start, unsigned long end);
> int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu,
> u64 time_limit, unsigned long lpcr);
> void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr);
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 5d008468347c..03755389efd1 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -922,6 +922,46 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu)
> return yield_count;
> }
>
> +/*
> + * H_RPT_INVALIDATE hcall handler for nested guests.
> + *
> + * Handles only nested process-scoped invalidation requests in L0.
> + */
> +static int kvmppc_nested_h_rpt_invalidate(struct kvm_vcpu *vcpu)
> +{
> + unsigned long type = kvmppc_get_gpr(vcpu, 6);
> + unsigned long pid, pg_sizes, start, end, psize;
> + struct kvm_nested_guest *gp;
> + struct mmu_psize_def *def;
> +
> + /*
> + * The partition-scoped invalidations aren't handled here in L0.
> + */
> + if (type & H_RPTI_TYPE_NESTED)
> + return RESUME_HOST;
> +
> + pid = kvmppc_get_gpr(vcpu, 4);
> + pg_sizes = kvmppc_get_gpr(vcpu, 7);
> + start = kvmppc_get_gpr(vcpu, 8);
> + end = kvmppc_get_gpr(vcpu, 9);
> +
> + gp = kvmhv_get_nested(vcpu->kvm, vcpu->kvm->arch.lpid, false);
> + if (!gp)
> + goto out;
> +
> + for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
> + def = &mmu_psize_defs[psize];
> + if (pg_sizes & def->h_rpt_pgsize)
> + do_h_rpt_invalidate_prt(pid, gp->shadow_lpid, type,
> + (1UL << def->shift), psize,
> + start, end);
> + }
> + kvmhv_put_nested(gp);
> +out:
> + kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
> + return RESUME_GUEST;
> +}
> +
> static long kvmppc_h_rpt_invalidate(struct kvm_vcpu *vcpu,
> unsigned long id, unsigned long target,
> unsigned long type, unsigned long pg_sizes,
> @@ -938,10 +978,18 @@ static long kvmppc_h_rpt_invalidate(struct kvm_vcpu *vcpu,
>
> /*
> * Partition-scoped invalidation for nested guests.
> - * Not yet supported
> */
> - if (type & H_RPTI_TYPE_NESTED)
> - return H_P3;
> + if (type & H_RPTI_TYPE_NESTED) {
> + if (!nesting_enabled(vcpu->kvm))
> + return H_FUNCTION;
> +
> + /* Support only cores as target */
> + if (target != H_RPTI_TARGET_CMMU)
> + return H_P2;
> +
> + return do_h_rpt_invalidate_pat(vcpu, id, type, pg_sizes,
> + start, end);
> + }
>
> /*
> * Process-scoped invalidation for L1 guests.
> @@ -1636,6 +1684,23 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
> if (!xics_on_xive())
> kvmppc_xics_rm_complete(vcpu, 0);
> break;
> + case BOOK3S_INTERRUPT_SYSCALL:
> + {
> + unsigned long req = kvmppc_get_gpr(vcpu, 3);
> +
> + /*
> + * The H_RPT_INVALIDATE hcalls issued by nested
> + * guests for process-scoped invalidations when
> + * GTSE=0, are handled here in L0.
> + */
> + if (req == H_RPT_INVALIDATE) {
> + r = kvmppc_nested_h_rpt_invalidate(vcpu);
> + break;
> + }
> +
> + r = RESUME_HOST;
> + break;
> + }
> default:
> r = RESUME_HOST;
> break;
> diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c
> index 0cd0e7aad588..adcc8e26ef22 100644
> --- a/arch/powerpc/kvm/book3s_hv_nested.c
> +++ b/arch/powerpc/kvm/book3s_hv_nested.c
> @@ -1191,6 +1191,110 @@ long kvmhv_do_nested_tlbie(struct kvm_vcpu *vcpu)
> return H_SUCCESS;
> }
>
> +static long do_tlb_invalidate_nested_tlb(struct kvm_vcpu *vcpu,
> + unsigned long lpid,
> + unsigned long page_size,
> + unsigned long ap,
> + unsigned long start,
> + unsigned long end)
> +{
> + unsigned long addr = start;
> + int ret;
> +
> + do {
> + ret = kvmhv_emulate_tlbie_tlb_addr(vcpu, lpid, ap,
> + get_epn(addr));
> + if (ret)
> + return ret;
> + addr += page_size;
> + } while (addr < end);
> +
> + return ret;
> +}
> +
> +static long do_tlb_invalidate_nested_all(struct kvm_vcpu *vcpu,
> + unsigned long lpid, unsigned long ric)
> +{
> + struct kvm *kvm = vcpu->kvm;
> + struct kvm_nested_guest *gp;
> +
> + gp = kvmhv_get_nested(kvm, lpid, false);
> + if (gp) {
> + kvmhv_emulate_tlbie_lpid(vcpu, gp, ric);
> + kvmhv_put_nested(gp);
> + }
> + return H_SUCCESS;
> +}
> +
> +/*
> + * Performs partition-scoped invalidations for nested guests
> + * as part of H_RPT_INVALIDATE hcall.
> + */
> +long do_h_rpt_invalidate_pat(struct kvm_vcpu *vcpu, unsigned long lpid,
> + unsigned long type, unsigned long pg_sizes,
> + unsigned long start, unsigned long end)
> +{
> + struct kvm_nested_guest *gp;
> + long ret;
> + unsigned long psize, ap;
> +
> + /*
> + * If L2 lpid isn't valid, we need to return H_PARAMETER.
> + *
> + * However, nested KVM issues a L2 lpid flush call when creating
> + * partition table entries for L2. This happens even before the
> + * corresponding shadow lpid is created in HV which happens in
> + * H_ENTER_NESTED call. Since we can't differentiate this case from
> + * the invalid case, we ignore such flush requests and return success.
> + */
> + gp = kvmhv_find_nested(vcpu->kvm, lpid);
> + if (!gp)
> + return H_SUCCESS;
> +
> + /*
> + * A flush all request can be handled by a full lpid flush only.
> + */
> + if ((type & H_RPTI_TYPE_NESTED_ALL) == H_RPTI_TYPE_NESTED_ALL)
> + return do_tlb_invalidate_nested_all(vcpu, lpid, RIC_FLUSH_ALL);
> +
> +#if 0
> + /*
> + * We don't need to handle a PWC flush like process table here,
> + * because intermediate partition scoped table in nested guest doesn't
> + * really have PWC. Only level we have PWC is in L0 and for nested
> + * invalidate at L0 we always do kvm_flush_lpid() which does
> + * radix__flush_all_lpid(). For range invalidate at any level, we
> + * are not removing the higher level page tables and hence there is
> + * no PWC invalidate needed.
> + */
> + if (type & H_RPTI_TYPE_PWC) {
> + ret = do_tlb_invalidate_nested_all(vcpu, lpid, RIC_FLUSH_PWC);
> + if (ret)
> + return H_P4;
> + }
> +#endif
> +
> + if (start == 0 && end == -1)
> + return do_tlb_invalidate_nested_all(vcpu, lpid, RIC_FLUSH_TLB);
> +
> + if (type & H_RPTI_TYPE_TLB) {
> + struct mmu_psize_def *def;
> +
> + for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
> + def = &mmu_psize_defs[psize];
> + if (!(pg_sizes & def->h_rpt_pgsize))
> + continue;
> +
> + ret = do_tlb_invalidate_nested_tlb(vcpu, lpid,
> + (1UL << def->shift),
> + ap, start, end);
> + if (ret)
> + return H_P4;
> + }
> + }
> + return H_SUCCESS;
> +}
> +
> /* Used to convert a nested guest real address to a L1 guest real address */
> static int kvmhv_translate_addr_nested(struct kvm_vcpu *vcpu,
> struct kvm_nested_guest *gp,
--
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/linuxppc-dev/attachments/20210323/00e8c581/attachment-0001.sig>
More information about the Linuxppc-dev
mailing list