Received: by 2002:ab2:784b:0:b0:1fd:adc2:8405 with SMTP id m11csp371349lqp; Mon, 10 Jun 2024 06:48:37 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXfnQFisdCiwbrOh32mPkft5y8xz97zNYrSHwv+/7HQ7g0UGoK5qajtVR6Sy603I9/4wc/caiLJfUpQ3F9DnRoai3W3JBq2rc5+j55x4A== X-Google-Smtp-Source: AGHT+IFA2FsNgzxJEdWuO0HydlSs2fadAGhlcUusLvpepUK2yBjOIIcvGYnvJ+powAvvnliwwWBq X-Received: by 2002:a17:902:ce85:b0:1eb:e40:3f74 with SMTP id d9443c01a7336-1f6d01bbe78mr137346355ad.32.1718027316946; Mon, 10 Jun 2024 06:48:36 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718027316; cv=pass; d=google.com; s=arc-20160816; b=KIW7TzLKrjzCRjrp/vrx27Bl1Sq5eQvt9h1wMAi5te3lJhoXc0L7yPQF1JzbQiwhip NdrggL3P6tSqpIB/L1DZg1DfRuJQwX8EfECOpnT0CDmcmkgDf1NWHCiN4GHlXImFSIOe aWGJoMTk6lVjMR++BnhzzA1ER1PtiFZGnqQX3uA5x88DDTD33e6109WA4/Ezfte+bQEn FUp/Y5P7nXNvRvxrrpTpn1zjIRlAsBG89mAySf8oCt8vi32ddLdDXiO4VLkZ/0BF6vBm camdl2FaCr77x76Qy7RXoPMBRuPuQb9K8GPS7Ey2zZ4lkMUXodNcawy9/htYZ/goJ/vj 04qg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from; bh=HvGo1GLPbjRN8W0Xc2eax84XbQHz1KpQLJpQIOBryE0=; fh=NDCPdPn2hiqHaiIRDYQAzsW9PK20CTia4nECGof6enU=; b=JT4vlnN4fHgQvYHPudVFOBI/vHod46K30fvhmt8hEloLOJhimSsaE5JWwiukmEbCez cEZTJTZYI9TAFhu4XPnWckRutV0HzjuvJYTEJ4x23d5Nc65TifPd/Acy4giaMOeSPyqa a7S8jAhaE5uy1pwkn+xjBEgAnzJTuAgshEQKzVXSVx+JI3aFT3n+pa9RLzSl6HcgOZvQ wVmiTQ3D54tbeRoLkCNtnQZHr4+1vLNryWs4qI+4S1Vm018/sAq9fq2ICArt1YqSyMgc 6hHKO7JGLUdhZjZxoCh9mK8r6ky4r3/LBs0NGlcntqyzD6QcJ5/I+il6G0TXizPohN3Q edYw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; arc=pass (i=1 spf=pass spfdomain=arm.com dmarc=pass fromdomain=arm.com); spf=pass (google.com: domain of linux-kernel+bounces-208260-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-208260-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id d9443c01a7336-1f7174ce95fsi14928045ad.484.2024.06.10.06.48.36 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Jun 2024 06:48:36 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-208260-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; arc=pass (i=1 spf=pass spfdomain=arm.com dmarc=pass fromdomain=arm.com); spf=pass (google.com: domain of linux-kernel+bounces-208260-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-208260-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id BA36B2869B6 for ; Mon, 10 Jun 2024 13:46:32 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3C5C314C58C; Mon, 10 Jun 2024 13:43:05 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1848E14B95F; Mon, 10 Jun 2024 13:43:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718026984; cv=none; b=A4VHJo2XY2yH4QeBoR0L8ghBvXajRiVFbN9zbDoDsRkvRar2seIiNUEuefsF5YX4CD7UKiVjkx/TjK7SGjv5VVdPCbp9jCJKc6oaRIOaBTWvNw98FAsQK0hxPcnGtw344WSyTo58CYFY5qpp7QIuYtk1i5MkA2iOs6K1Psh35JE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718026984; c=relaxed/simple; bh=tNagJRTdXRfbeSZ/Hb2Pn6U6wbMJnLvGijOS8/kRUwA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MxLMrs06rYRbXJVh0x4w7a7vgRcqg76j+RSwBWbTWZRQLPI/wxFIRlYhycT0SVfAel9Z+Qhy3G4Ss/kX2sapVePX+unfMO2HuBlm1DyrscUxanBaCeo80+Aw7e7AMQo2uqTPIqRAundf89nwtL8CQC2NaNIR+GYS0H0/rc6/FvY= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3B55F12FC; Mon, 10 Jun 2024 06:43:27 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.35.41]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0EB3C3F58B; Mon, 10 Jun 2024 06:42:59 -0700 (PDT) From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni Subject: [PATCH v3 13/43] arm64: RME: RTT tear down Date: Mon, 10 Jun 2024 14:41:32 +0100 Message-Id: <20240610134202.54893-14-steven.price@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240610134202.54893-1-steven.price@arm.com> References: <20240610134202.54893-1-steven.price@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The RMM owns the stage 2 page tables for a realm, and KVM must request that the RMM creates/destroys entries as necessary. The physical pages to store the page tables are delegated to the realm as required, and can be undelegated when no longer used. Creating new RTTs is the easy part, tearing down is a little more tricky. The result of realm_rtt_destroy() can be used to effectively walk the tree and destroy the entries (undelegating pages that were given to the realm). Signed-off-by: Steven Price --- Changes since v2: * Moved {alloc,free}_delegated_page() and ensure_spare_page() to a later patch when they are actually used. * Some simplifications now rmi_xxx() functions allow NULL as an output parameter. * Improved comments and code layout. --- arch/arm64/include/asm/kvm_rme.h | 19 ++++++ arch/arm64/kvm/mmu.c | 6 +- arch/arm64/kvm/rme.c | 113 +++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h index bd306bd7b64b..e5704859a6e5 100644 --- a/arch/arm64/include/asm/kvm_rme.h +++ b/arch/arm64/include/asm/kvm_rme.h @@ -76,5 +76,24 @@ u32 kvm_realm_ipa_limit(void); int kvm_realm_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap); int kvm_init_realm_vm(struct kvm *kvm); void kvm_destroy_realm(struct kvm *kvm); +void kvm_realm_destroy_rtts(struct kvm *kvm, u32 ia_bits); + +#define RME_RTT_BLOCK_LEVEL 2 +#define RME_RTT_MAX_LEVEL 3 + +#define RME_PAGE_SHIFT 12 +#define RME_PAGE_SIZE BIT(RME_PAGE_SHIFT) +/* See ARM64_HW_PGTABLE_LEVEL_SHIFT() */ +#define RME_RTT_LEVEL_SHIFT(l) \ + ((RME_PAGE_SHIFT - 3) * (4 - (l)) + 3) +#define RME_L2_BLOCK_SIZE BIT(RME_RTT_LEVEL_SHIFT(2)) + +static inline unsigned long rme_rtt_level_mapsize(int level) +{ + if (WARN_ON(level > RME_RTT_MAX_LEVEL)) + return RME_PAGE_SIZE; + + return (1UL << RME_RTT_LEVEL_SHIFT(level)); +} #endif diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 93300491b31b..83bd10845efb 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1012,17 +1012,17 @@ void stage2_unmap_vm(struct kvm *kvm) void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu) { struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); - struct kvm_pgtable *pgt = NULL; + struct kvm_pgtable *pgt; write_lock(&kvm->mmu_lock); + pgt = mmu->pgt; if (kvm_is_realm(kvm) && (kvm_realm_state(kvm) != REALM_STATE_DEAD && kvm_realm_state(kvm) != REALM_STATE_NONE)) { - /* Tearing down RTTs will be added in a later patch */ write_unlock(&kvm->mmu_lock); + kvm_realm_destroy_rtts(kvm, pgt->ia_bits); return; } - pgt = mmu->pgt; if (pgt) { mmu->pgd_phys = 0; mmu->pgt = NULL; diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c index f6430d460519..7db405d2b2b2 100644 --- a/arch/arm64/kvm/rme.c +++ b/arch/arm64/kvm/rme.c @@ -125,6 +125,119 @@ static int realm_create_rd(struct kvm *kvm) return r; } +static int realm_rtt_destroy(struct realm *realm, unsigned long addr, + int level, phys_addr_t *rtt_granule, + unsigned long *next_addr) +{ + unsigned long out_rtt; + int ret; + + ret = rmi_rtt_destroy(virt_to_phys(realm->rd), addr, level, + &out_rtt, next_addr); + + *rtt_granule = out_rtt; + + return ret; +} + +static int realm_tear_down_rtt_level(struct realm *realm, int level, + unsigned long start, unsigned long end) +{ + ssize_t map_size; + unsigned long addr, next_addr; + + if (WARN_ON(level > RME_RTT_MAX_LEVEL)) + return -EINVAL; + + map_size = rme_rtt_level_mapsize(level - 1); + + for (addr = start; addr < end; addr = next_addr) { + phys_addr_t rtt_granule; + int ret; + unsigned long align_addr = ALIGN(addr, map_size); + + next_addr = ALIGN(addr + 1, map_size); + + if (next_addr > end || align_addr != addr) { + /* + * The target range is smaller than what this level + * covers, recurse deeper. + */ + ret = realm_tear_down_rtt_level(realm, + level + 1, + addr, + min(next_addr, end)); + if (ret) + return ret; + continue; + } + + ret = realm_rtt_destroy(realm, addr, level, + &rtt_granule, &next_addr); + + switch (RMI_RETURN_STATUS(ret)) { + case RMI_SUCCESS: + if (!WARN_ON(rmi_granule_undelegate(rtt_granule))) + free_page((unsigned long)phys_to_virt(rtt_granule)); + break; + case RMI_ERROR_RTT: + if (next_addr > addr) { + /* Missing RTT, skip */ + break; + } + if (WARN_ON(RMI_RETURN_INDEX(ret) != level)) + return -EBUSY; + /* + * We tear down the RTT range for the full IPA + * space, after everything is unmapped. Also we + * descend down only if we cannot tear down a + * top level RTT. Thus RMM must be able to walk + * to the requested level. e.g., a block mapping + * exists at L1 or L2. + */ + if (WARN_ON(level == RME_RTT_MAX_LEVEL)) + return -EBUSY; + + /* + * The table has active entries in it, recurse deeper + * and tear down the RTTs. + */ + next_addr = ALIGN(addr + 1, map_size); + ret = realm_tear_down_rtt_level(realm, + level + 1, + addr, + next_addr); + if (ret) + return ret; + /* + * Now that the child RTTs are destroyed, + * retry at this level. + */ + next_addr = addr; + break; + default: + WARN_ON(1); + return -ENXIO; + } + } + + return 0; +} + +static int realm_tear_down_rtt_range(struct realm *realm, + unsigned long start, unsigned long end) +{ + return realm_tear_down_rtt_level(realm, get_start_level(realm) + 1, + start, end); +} + +void kvm_realm_destroy_rtts(struct kvm *kvm, u32 ia_bits) +{ + struct realm *realm = &kvm->arch.realm; + + WARN_ON(realm_tear_down_rtt_range(realm, 0, (1UL << ia_bits))); +} + /* Protects access to rme_vmid_bitmap */ static DEFINE_SPINLOCK(rme_vmid_lock); static unsigned long *rme_vmid_bitmap; -- 2.34.1