diff mbox series

[v2,12/43] arm64: RME: Keep a spare page delegated to the RMM

Message ID 20240412084309.1733783-13-steven.price@arm.com (mailing list archive)
State New
Headers show
Series [v2,01/43] KVM: Prepare for handling only shared mappings in mmu_notifier events | expand

Commit Message

Steven Price April 12, 2024, 8:42 a.m. UTC
Pages can only be populated/destroyed on the RMM at the 4KB granule,
this requires creating the full depth of RTTs. However if the pages are
going to be combined into a 4MB huge page the last RTT is only
temporarily needed. Similarly when freeing memory the huge page must be
temporarily split requiring temporary usage of the full depth oF RTTs.

To avoid needing to perform a temporary allocation and delegation of a
page for this purpose we keep a spare delegated page around. In
particular this avoids the need for memory allocation while destroying
the realm guest.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 arch/arm64/include/asm/kvm_rme.h | 5 +++++
 arch/arm64/kvm/rme.c             | 8 ++++++++
 2 files changed, 13 insertions(+)

Comments

Suzuki K Poulose April 17, 2024, 10:19 a.m. UTC | #1
Hi Steven

On 12/04/2024 09:42, Steven Price wrote:
> Pages can only be populated/destroyed on the RMM at the 4KB granule,
> this requires creating the full depth of RTTs. However if the pages are
> going to be combined into a 4MB huge page the last RTT is only

minor nit: 2MB huge page.

> temporarily needed. Similarly when freeing memory the huge page must be
> temporarily split requiring temporary usage of the full depth oF RTTs.
> 
> To avoid needing to perform a temporary allocation and delegation of a
> page for this purpose we keep a spare delegated page around. In
> particular this avoids the need for memory allocation while destroying
> the realm guest.
> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>   arch/arm64/include/asm/kvm_rme.h | 5 +++++
>   arch/arm64/kvm/rme.c             | 8 ++++++++
>   2 files changed, 13 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
> index cf8cc4d30364..fba85e9ce3ae 100644
> --- a/arch/arm64/include/asm/kvm_rme.h
> +++ b/arch/arm64/include/asm/kvm_rme.h
> @@ -50,6 +50,9 @@ enum realm_state {
>    * @state: The lifetime state machine for the realm
>    * @rd: Kernel mapping of the Realm Descriptor (RD)
>    * @params: Parameters for the RMI_REALM_CREATE command
> + * @spare_page: A physical page that has been delegated to the Realm world but
> + *              is otherwise free. Used to avoid temporary allocation during
> + *              RTT operations.
>    * @num_aux: The number of auxiliary pages required by the RMM
>    * @vmid: VMID to be used by the RMM for the realm
>    * @ia_bits: Number of valid Input Address bits in the IPA
> @@ -60,6 +63,8 @@ struct realm {
>   	void *rd;
>   	struct realm_params *params;
>   
> +	phys_addr_t spare_page;
> +
>   	unsigned long num_aux;
>   	unsigned int vmid;
>   	unsigned int ia_bits;
> diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
> index 658d14e8d87d..9652ec6ab2fd 100644
> --- a/arch/arm64/kvm/rme.c
> +++ b/arch/arm64/kvm/rme.c
> @@ -103,6 +103,7 @@ static int realm_create_rd(struct kvm *kvm)
>   	}
>   
>   	realm->rd = rd;
> +	realm->spare_page = PHYS_ADDR_MAX;
>   
>   	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
>   		WARN_ON(rmi_realm_destroy(rd_phys));
> @@ -283,6 +284,13 @@ void kvm_destroy_realm(struct kvm *kvm)
>   
>   	rme_vmid_release(realm->vmid);
>   
> +	if (realm->spare_page != PHYS_ADDR_MAX) {
> +		/* Leak the page if the undelegate fails */
> +		if (!WARN_ON(rmi_granule_undelegate(realm->spare_page)))
> +			free_page((unsigned long)phys_to_virt(realm->spare_page));
> +		realm->spare_page = PHYS_ADDR_MAX;
> +	}
> +
>   	for (i = 0; i < pgt->pgd_pages; i++) {
>   		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;
>   

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/kvm_rme.h b/arch/arm64/include/asm/kvm_rme.h
index cf8cc4d30364..fba85e9ce3ae 100644
--- a/arch/arm64/include/asm/kvm_rme.h
+++ b/arch/arm64/include/asm/kvm_rme.h
@@ -50,6 +50,9 @@  enum realm_state {
  * @state: The lifetime state machine for the realm
  * @rd: Kernel mapping of the Realm Descriptor (RD)
  * @params: Parameters for the RMI_REALM_CREATE command
+ * @spare_page: A physical page that has been delegated to the Realm world but
+ *              is otherwise free. Used to avoid temporary allocation during
+ *              RTT operations.
  * @num_aux: The number of auxiliary pages required by the RMM
  * @vmid: VMID to be used by the RMM for the realm
  * @ia_bits: Number of valid Input Address bits in the IPA
@@ -60,6 +63,8 @@  struct realm {
 	void *rd;
 	struct realm_params *params;
 
+	phys_addr_t spare_page;
+
 	unsigned long num_aux;
 	unsigned int vmid;
 	unsigned int ia_bits;
diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
index 658d14e8d87d..9652ec6ab2fd 100644
--- a/arch/arm64/kvm/rme.c
+++ b/arch/arm64/kvm/rme.c
@@ -103,6 +103,7 @@  static int realm_create_rd(struct kvm *kvm)
 	}
 
 	realm->rd = rd;
+	realm->spare_page = PHYS_ADDR_MAX;
 
 	if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
 		WARN_ON(rmi_realm_destroy(rd_phys));
@@ -283,6 +284,13 @@  void kvm_destroy_realm(struct kvm *kvm)
 
 	rme_vmid_release(realm->vmid);
 
+	if (realm->spare_page != PHYS_ADDR_MAX) {
+		/* Leak the page if the undelegate fails */
+		if (!WARN_ON(rmi_granule_undelegate(realm->spare_page)))
+			free_page((unsigned long)phys_to_virt(realm->spare_page));
+		realm->spare_page = PHYS_ADDR_MAX;
+	}
+
 	for (i = 0; i < pgt->pgd_pages; i++) {
 		phys_addr_t pgd_phys = kvm->arch.mmu.pgd_phys + i * PAGE_SIZE;