On 19/08/2025 17:54, Mukesh Ojha wrote:
Qualcomm SoCs running with QHEE (Qualcomm Hypervisor Execution
Environment—a library present in the Gunyah hypervisor) utilize the
Peripheral Authentication Service (PAS) from TrustZone (TZ) firmware to
securely authenticate and reset remote processors via a sequence of SMC
calls such as qcom_scm_pas_init_image(), qcom_scm_pas_mem_setup(), and
qcom_scm_pas_auth_and_reset().
For memory passed to Qualcomm TrustZone, it must either be part of a
pool registered with TZ or be directly registered via SHMbridge SMC
calls.
When QHEE is present, PAS SMC calls from Linux running at EL1 are
trapped by QHEE (running at EL2), which then creates or retrieves memory
from the SHMbridge for both metadata and remoteproc carveout memory
before passing them to TZ. However, when the SoC runs with a
non-QHEE-based hypervisor, Linux must create the SHM bridge for both
metadata (before it is passed to TZ in qcom_scm_pas_init_image()) and
for remoteproc memory (before the call is made to TZ in
qcom_scm_pas_auth_and_reset()).
For auth_and_reset() call, first it need to register remoteproc carveout
memory with TZ via SHMbridge SMC call and then it can trigger
auth_and_reset SMC call and once the call returns, remoteproc carveout
memory can be deregisterd with TZ.
Add qcom_scm_pas_prepare_and_auth_reset() function which does prepare
the SHMbridge over carveout memory and call auth_and_reset SMC call.
Signed-off-by: Mukesh Ojha <mukesh.o...@oss.qualcomm.com>
---
drivers/firmware/qcom/qcom_scm.c | 46 ++++++++++++++++++++++++++
include/linux/firmware/qcom/qcom_scm.h | 2 ++
2 files changed, 48 insertions(+)
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 33187d4f4aef..9a5b34f5bacb 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -759,6 +759,52 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral)
}
EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
+/**
+ * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset
the remote processor
+ *
+ * @ctx: Context saved during call to qcom_scm_pas_ctx_init()
+ *
+ * This function performs the necessary steps to prepare a PAS subsystem,
+ * authenticate it using the provided metadata, and initiate a reset sequence.
+ *
+ * It is typically used when Linux is in control setting up the IOMMU hardware
Is there a non-typical case ?
"This function is used"
+ * for remote subsystem during secure firmware loading processes. The
preparation
+ * step sets up shmbridge over the firmware memory before TrustZone access the
shmbridge -> "a shmbridge"
"access" -> "accesses"
+ * firmware memory region for authentication. The authentication step verifies
+ * the integrity and authenticity of the firmware or configuration using secure
+ * metadata. Finally, the reset step ensures the subsystem starts in a clean
and
+ * sane state.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_ctx *ctx)
+{
+ u64 handle;
+ int ret;
+
+ if (!ctx->has_iommu)
+ return qcom_scm_pas_auth_and_reset(ctx->peripheral);
+
+ /*
+ * When Linux running at EL1, Gunyah(EL2) traps auth_and_reset call and
creates
+ * shmbridge on subsystem memory region before it passes the call to
TrustZone
+ * to authenticate it while when Linux runs at EL2, it needs to create
shmbridge
+ * before this call goes to TrustZone.
+ */
If Linux is running at EL1, Gunyah running at EL2 traps the
auth_and_reset call, creates a shmbridge in "subsystem memory ? bod:
which subsystem do you mean here" and then passes the call to TrustZone.
If Linux is running at EL2 then Linux needs to create the shmbridge
before calling into TrustZone.
+ ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size,
&handle);
+ if (ret) {
+ dev_err(__scm->dev, "Failed to create shmbridge ret=%d %u\n",
+ ret, ctx->peripheral);
+ return ret;
+ }
+
+ ret = qcom_scm_pas_auth_and_reset(ctx->peripheral);
+ qcom_tzmem_shm_bridge_delete(handle);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
+
/**
* qcom_scm_pas_shutdown() - Shut down the remote processor
* @peripheral: peripheral id
diff --git a/include/linux/firmware/qcom/qcom_scm.h
b/include/linux/firmware/qcom/qcom_scm.h
index b7eb206561a9..a31006fe49a9 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -79,6 +79,7 @@ struct qcom_scm_pas_ctx {
size_t mem_size;
struct qcom_scm_pas_metadata *metadata;
bool save_mdt_ctx;
+ bool has_iommu;
};
void *qcom_scm_pas_ctx_init(struct device *dev, u32 peripheral, phys_addr_t mem_phys,
@@ -87,6 +88,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void
*metadata, size_t size,
struct qcom_scm_pas_metadata *ctx);
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx);
int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t
size);
+int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_ctx *ctx);
int qcom_scm_pas_auth_and_reset(u32 peripheral);
int qcom_scm_pas_shutdown(u32 peripheral);
bool qcom_scm_pas_supported(u32 peripheral);