From patchwork Thu Apr 24 14:13:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Karim Manaouil X-Patchwork-Id: 884035 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7559291148 for ; Thu, 24 Apr 2025 14:14:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745504063; cv=none; b=r+ebFqmnBDmdIKkJKDJZZSNx1i5EMXyVj+zBkA47DemI3eA9WmnFgS3l/46AMfTk5FWD6Tl2F+7puQjRQDxUs5hSLrrEuxIj9H7f3pKrl/cjVCQCy01tpfjEHryHEhwvZLgiGrMO4S242olV4YSI6q8+z/au3iKq6IJOxb97YK8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745504063; c=relaxed/simple; bh=jJJ9JgoTw3N1VJhubYw/1Fl9AFSEgg6AWN3vhACh320=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SKfW8/vsRN+hX4Dc2XIcnROGTrnYNBeia2qEyksEEDxo9/0FiqEBjdDFOo+345G3zOoPfnRl124PHvgseUjBGHB+8rgdTfC6xvtt/fP2RCYDwbe/MiqPetd4zEVyUyjDq8TmilDWaKpB+7QU481osnodiyIfGePO9bxLMM9/qTs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=l2sDkHvc; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="l2sDkHvc" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-3913958ebf2so866742f8f.3 for ; Thu, 24 Apr 2025 07:14:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1745504059; x=1746108859; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JWj7uDN15UXCYW87dO7IIzOLdNiL+f7UvEUy/qTIHd4=; b=l2sDkHvcTVBFdmyOzriXRy7V+POCWjRrzn/Rwj7DOrq3S1JzIBaq3FrRtBcpA8OwMp Hir/SBUQIEXfJUrgAdjUlyNF563afxrDlJRhSr4WOfzLXQ2rK5TArXvAwDzZult/FV65 r6DDBHUY/qeAzFATXGba6ZBggzU9VoaB3DAyorTkS/mCC3BTqRiL8DiG6m53eEtZrwFJ l89nyucBkjfbwad8dYxizW4TuSDIOCmCHCx4QVWDoSWdokMSBungKMUDhFXwiwfG4Xhn CZOnmrDGcRcaau6dmfP0X/dN4oXzEgXEfA9EON6B3BMxVTgXNZST8w+6qss5uRZmoLmm 5KKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745504059; x=1746108859; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JWj7uDN15UXCYW87dO7IIzOLdNiL+f7UvEUy/qTIHd4=; b=xFxN5aKiWJPKkhHdwftYtrsES4R1FPLJNNiNyHLvLsDAz8b37W69LOn6npQZKIdrw1 5p1SJ+k6h+SuHyFKPRiLdD+BMQ4mbbwKCZhFiUHzABGoP6KI10mKqZGI/H9xwxDDwReZ ldyl9PBYjMUIpyj6vTvtaUbJbajuKtxxiMnhSX/G64jgR2R4deaNajI3MfiYTV/r52Dh Smd3255EEk6s0Sy7r/KDBwLeh1vCQvGgMfJZLNFvVoV+16rc7xEM5f2L05zAZ02OtPBl E9FG3aJI2rzPd8XV7irpEfD5OjoYJf+lCS2VcMvmwVCgNNfzVv2Z621Sw8mtFo24O0Ze LHNQ== X-Forwarded-Encrypted: i=1; AJvYcCUu9cQFqOWn2tpeK5WZ4/Hcim4tTnqplWKlvYvCzYsbs/5m6V+Y0ohMnA23blnemO6LtWB3cl3wXcapcqkf@vger.kernel.org X-Gm-Message-State: AOJu0YxLRlW2rOqQSSTNbVau4E/8oBwfn2u37Y7CYN3WwnpBvgVbu0Tf asWKHZH9u+7NlraD2R0vjZs6Ut1DfFyHs9fjJjixvmEUNGee07EPNaNrPpk+EqU= X-Gm-Gg: ASbGncsqKdzHfPeYZttWaVAbav2Dh5wt2C1cK1DBUkK5X2wf5+U+0J20U6au0GvetsY ejbbu1ibAGhNlwbdhQURmgPv/oilNBBPPcHc9xlDuWKyRKd9u9dDWU3GWUlDk9FIzvWMDzaZ1Vd /k1Fy4wRR6g9JL9iSihEYs4BjQkpypkee0YbTxeY6KBef2hXSIUza1RVHN+6J7nfWll8FsAbF9Y 2lE+SE5v89jFYp1S7wNZEjGIpSkvROy88Pttg0xmm2p8Bda4JtssWi2C6kX0Rzqx0dUimQj2FfR bOuYOBpNWxMp1TPFrNk1UccOvDf6I77ZxBl9HHbkiHqlkKt/sB0BiA/cCnNfxHrALmzRX8GoaoX sNx+s/28maIqZGDQ6rEHxgM/A8KE= X-Google-Smtp-Source: AGHT+IEZ62CGRLn02mw6Sp1FYoWsMMZ/LoDmb0ZQtBfZ0JQt0jIozyM3jnvRsN2MwUnOvlF4h+jCiw== X-Received: by 2002:a05:6000:184c:b0:39f:64ff:668d with SMTP id ffacd0b85a97d-3a06cfa5a65mr2546775f8f.40.1745504058677; Thu, 24 Apr 2025 07:14:18 -0700 (PDT) Received: from seksu.systems-nuts.com (stevens.inf.ed.ac.uk. [129.215.164.122]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a06d4a8150sm2199951f8f.7.2025.04.24.07.14.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Apr 2025 07:14:18 -0700 (PDT) From: Karim Manaouil To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-arm-msm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev Cc: Karim Manaouil , Alexander Graf , Alex Elder , Catalin Marinas , Fuad Tabba , Joey Gouly , Jonathan Corbet , Marc Zyngier , Mark Brown , Mark Rutland , Oliver Upton , Paolo Bonzini , Prakruthi Deepak Heragu , Quentin Perret , Rob Herring , Srinivas Kandagatla , Srivatsa Vaddagiri , Will Deacon , Haripranesh S , Carl van Schaik , Murali Nalajala , Sreenivasulu Chalamcharla , Trilok Soni , Stefan Schmidt , Elliot Berman , Alex Elder Subject: [RFC PATCH 25/34] gunyah: Add Qualcomm Gunyah platform ops Date: Thu, 24 Apr 2025 15:13:32 +0100 Message-Id: <20250424141341.841734-26-karim.manaouil@linaro.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250424141341.841734-1-karim.manaouil@linaro.org> References: <20250424141341.841734-1-karim.manaouil@linaro.org> Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Elliot Berman Qualcomm platforms have a firmware entity which performs access control to physical pages. Dynamically started Gunyah virtual machines use the QCOM_SCM_RM_MANAGED_VMID for access. Linux thus needs to assign access to the memory used by guest VMs. Gunyah doesn't do this operation for us since it is the current VM (typically VMID_HLOS) delegating the access and not Gunyah itself. Use the Gunyah platform ops to achieve this so that only Qualcomm platforms attempt to make the needed SCM calls. Reviewed-by: Alex Elder Co-developed-by: Prakruthi Deepak Heragu Signed-off-by: Prakruthi Deepak Heragu Signed-off-by: Elliot Berman Signed-off-by: Karim Manaouil --- drivers/virt/gunyah/Kconfig | 13 ++ drivers/virt/gunyah/Makefile | 1 + drivers/virt/gunyah/gunyah_qcom.c | 220 ++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 drivers/virt/gunyah/gunyah_qcom.c diff --git a/drivers/virt/gunyah/Kconfig b/drivers/virt/gunyah/Kconfig index 23ba523d25dc..fe2823dc48ba 100644 --- a/drivers/virt/gunyah/Kconfig +++ b/drivers/virt/gunyah/Kconfig @@ -4,6 +4,7 @@ config GUNYAH tristate "Gunyah Virtualization drivers" depends on ARM64 select GUNYAH_PLATFORM_HOOKS + imply GUNYAH_QCOM_PLATFORM if ARCH_QCOM help The Gunyah drivers are the helper interfaces that run in a guest VM such as basic inter-VM IPC and signaling mechanisms, and higher level @@ -14,3 +15,15 @@ config GUNYAH config GUNYAH_PLATFORM_HOOKS tristate + +config GUNYAH_QCOM_PLATFORM + tristate "Support for Gunyah on Qualcomm platforms" + depends on GUNYAH + select GUNYAH_PLATFORM_HOOKS + select QCOM_SCM + help + Enable support for interacting with Gunyah on Qualcomm + platforms. Interaction with Qualcomm firmware requires + extra platform-specific support. + + Say Y/M here to use Gunyah on Qualcomm platforms. diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile index 45cabba3110c..349c37e9f0ad 100644 --- a/drivers/virt/gunyah/Makefile +++ b/drivers/virt/gunyah/Makefile @@ -4,3 +4,4 @@ gunyah_rsc_mgr-y += rsc_mgr.o rsc_mgr_rpc.o obj-$(CONFIG_GUNYAH) += gunyah.o gunyah_rsc_mgr.o obj-$(CONFIG_GUNYAH_PLATFORM_HOOKS) += gunyah_platform_hooks.o +obj-$(CONFIG_GUNYAH_QCOM_PLATFORM) += gunyah_qcom.o diff --git a/drivers/virt/gunyah/gunyah_qcom.c b/drivers/virt/gunyah/gunyah_qcom.c new file mode 100644 index 000000000000..f2342d51a018 --- /dev/null +++ b/drivers/virt/gunyah/gunyah_qcom.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define QCOM_SCM_RM_MANAGED_VMID 0x3A +#define QCOM_SCM_MAX_MANAGED_VMID 0x3F + +static int +qcom_scm_gunyah_rm_pre_mem_share(struct gunyah_rm *rm, + struct gunyah_rm_mem_parcel *mem_parcel) +{ + struct qcom_scm_vmperm *new_perms __free(kfree) = NULL; + u64 src, src_cpy; + int ret = 0, i, n; + u16 vmid; + + new_perms = kcalloc(mem_parcel->n_acl_entries, sizeof(*new_perms), + GFP_KERNEL); + if (!new_perms) + return -ENOMEM; + + for (n = 0; n < mem_parcel->n_acl_entries; n++) { + vmid = le16_to_cpu(mem_parcel->acl_entries[n].vmid); + if (vmid <= QCOM_SCM_MAX_MANAGED_VMID) + new_perms[n].vmid = vmid; + else + new_perms[n].vmid = QCOM_SCM_RM_MANAGED_VMID; + if (mem_parcel->acl_entries[n].perms & GUNYAH_RM_ACL_X) + new_perms[n].perm |= QCOM_SCM_PERM_EXEC; + if (mem_parcel->acl_entries[n].perms & GUNYAH_RM_ACL_W) + new_perms[n].perm |= QCOM_SCM_PERM_WRITE; + if (mem_parcel->acl_entries[n].perms & GUNYAH_RM_ACL_R) + new_perms[n].perm |= QCOM_SCM_PERM_READ; + } + + src = BIT_ULL(QCOM_SCM_VMID_HLOS); + + for (i = 0; i < mem_parcel->n_mem_entries; i++) { + src_cpy = src; + ret = qcom_scm_assign_mem( + le64_to_cpu(mem_parcel->mem_entries[i].phys_addr), + le64_to_cpu(mem_parcel->mem_entries[i].size), &src_cpy, + new_perms, mem_parcel->n_acl_entries); + if (ret) + break; + } + + /* Did it work ok? */ + if (!ret) + return 0; + + src = 0; + for (n = 0; n < mem_parcel->n_acl_entries; n++) { + vmid = le16_to_cpu(mem_parcel->acl_entries[n].vmid); + if (vmid <= QCOM_SCM_MAX_MANAGED_VMID) + src |= BIT_ULL(vmid); + else + src |= BIT_ULL(QCOM_SCM_RM_MANAGED_VMID); + } + + new_perms[0].vmid = QCOM_SCM_VMID_HLOS; + new_perms[0].perm = QCOM_SCM_PERM_EXEC | QCOM_SCM_PERM_WRITE | + QCOM_SCM_PERM_READ; + + for (i--; i >= 0; i--) { + src_cpy = src; + WARN_ON_ONCE(qcom_scm_assign_mem( + le64_to_cpu(mem_parcel->mem_entries[i].phys_addr), + le64_to_cpu(mem_parcel->mem_entries[i].size), &src_cpy, + new_perms, 1)); + } + + return ret; +} + +static int +qcom_scm_gunyah_rm_post_mem_reclaim(struct gunyah_rm *rm, + struct gunyah_rm_mem_parcel *mem_parcel) +{ + struct qcom_scm_vmperm new_perms; + u64 src = 0, src_cpy; + int ret = 0, i, n; + u16 vmid; + + new_perms.vmid = QCOM_SCM_VMID_HLOS; + new_perms.perm = QCOM_SCM_PERM_EXEC | QCOM_SCM_PERM_WRITE | + QCOM_SCM_PERM_READ; + + for (n = 0; n < mem_parcel->n_acl_entries; n++) { + vmid = le16_to_cpu(mem_parcel->acl_entries[n].vmid); + if (vmid <= QCOM_SCM_MAX_MANAGED_VMID) + src |= (1ull << vmid); + else + src |= (1ull << QCOM_SCM_RM_MANAGED_VMID); + } + + for (i = 0; i < mem_parcel->n_mem_entries; i++) { + src_cpy = src; + ret = qcom_scm_assign_mem( + le64_to_cpu(mem_parcel->mem_entries[i].phys_addr), + le64_to_cpu(mem_parcel->mem_entries[i].size), &src_cpy, + &new_perms, 1); + WARN_ON_ONCE(ret); + } + + return ret; +} + +static int +qcom_scm_gunyah_rm_pre_demand_page(struct gunyah_rm *rm, u16 vmid, + enum gunyah_pagetable_access access, + struct folio *folio) +{ + struct qcom_scm_vmperm new_perms[2]; + unsigned int n = 1; + u64 src; + + new_perms[0].vmid = QCOM_SCM_RM_MANAGED_VMID; + new_perms[0].perm = QCOM_SCM_PERM_EXEC | QCOM_SCM_PERM_WRITE | + QCOM_SCM_PERM_READ; + if (access != GUNYAH_PAGETABLE_ACCESS_X && + access != GUNYAH_PAGETABLE_ACCESS_RX && + access != GUNYAH_PAGETABLE_ACCESS_RWX) { + new_perms[1].vmid = QCOM_SCM_VMID_HLOS; + new_perms[1].perm = QCOM_SCM_PERM_EXEC | QCOM_SCM_PERM_WRITE | + QCOM_SCM_PERM_READ; + n++; + } + + src = BIT_ULL(QCOM_SCM_VMID_HLOS); + + return qcom_scm_assign_mem(__pfn_to_phys(folio_pfn(folio)), + folio_size(folio), &src, new_perms, n); +} + +static int +qcom_scm_gunyah_rm_release_demand_page(struct gunyah_rm *rm, u16 vmid, + enum gunyah_pagetable_access access, + struct folio *folio) +{ + struct qcom_scm_vmperm new_perms; + u64 src; + + new_perms.vmid = QCOM_SCM_VMID_HLOS; + new_perms.perm = QCOM_SCM_PERM_EXEC | QCOM_SCM_PERM_WRITE | + QCOM_SCM_PERM_READ; + + src = BIT_ULL(QCOM_SCM_RM_MANAGED_VMID); + + if (access != GUNYAH_PAGETABLE_ACCESS_X && + access != GUNYAH_PAGETABLE_ACCESS_RX && + access != GUNYAH_PAGETABLE_ACCESS_RWX) + src |= BIT_ULL(QCOM_SCM_VMID_HLOS); + + return qcom_scm_assign_mem(__pfn_to_phys(folio_pfn(folio)), + folio_size(folio), &src, &new_perms, 1); +} + +static struct gunyah_rm_platform_ops qcom_scm_gunyah_rm_platform_ops = { + .pre_mem_share = qcom_scm_gunyah_rm_pre_mem_share, + .post_mem_reclaim = qcom_scm_gunyah_rm_post_mem_reclaim, + .pre_demand_page = qcom_scm_gunyah_rm_pre_demand_page, + .release_demand_page = qcom_scm_gunyah_rm_release_demand_page, +}; + +/* {19bd54bd-0b37-571b-946f-609b54539de6} */ +static const uuid_t QCOM_EXT_UUID = UUID_INIT(0x19bd54bd, 0x0b37, 0x571b, 0x94, + 0x6f, 0x60, 0x9b, 0x54, 0x53, + 0x9d, 0xe6); + +#define GUNYAH_QCOM_EXT_CALL_UUID_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_VENDOR_HYP, 0x3f01) + +static bool gunyah_has_qcom_extensions(void) +{ + struct arm_smccc_res res; + uuid_t uuid; + u32 *up; + + arm_smccc_1_1_smc(GUNYAH_QCOM_EXT_CALL_UUID_ID, &res); + + up = (u32 *)&uuid.b[0]; + up[0] = lower_32_bits(res.a0); + up[1] = lower_32_bits(res.a1); + up[2] = lower_32_bits(res.a2); + up[3] = lower_32_bits(res.a3); + + return uuid_equal(&uuid, &QCOM_EXT_UUID); +} + +static int __init qcom_gunyah_platform_hooks_register(void) +{ + if (!gunyah_has_qcom_extensions()) + return -ENODEV; + + pr_info("Enabling Gunyah hooks for Qualcomm platforms.\n"); + + return gunyah_rm_register_platform_ops( + &qcom_scm_gunyah_rm_platform_ops); +} + +static void __exit qcom_gunyah_platform_hooks_unregister(void) +{ + gunyah_rm_unregister_platform_ops(&qcom_scm_gunyah_rm_platform_ops); +} + +module_init(qcom_gunyah_platform_hooks_register); +module_exit(qcom_gunyah_platform_hooks_unregister); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Platform Hooks for Gunyah"); +MODULE_LICENSE("GPL");