From patchwork Wed May 4 16:58:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7561 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D1E85C4332F for ; Wed, 4 May 2022 16:58:36 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web08.598.1651683510483219099 for ; Wed, 04 May 2022 09:58:30 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 779FE1042; Wed, 4 May 2022 09:58:29 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D953C3FA27; Wed, 4 May 2022 09:58:28 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 01/10] arm/optee: Add optee 3.14 recipes Date: Wed, 4 May 2022 17:58:11 +0100 Message-Id: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3357 Add back v3.14 optee-examples, optee-test, and optee-os-tadevkit for TC platform compatibility. These files were removed as part of v3.16 upgrade. Signed-off-by: Arunachalam Ganapathy Change-Id: Ia12774125909e7f8bfc20a9797c25b04dd850ae7 --- .../optee/optee-examples_3.14.0.bb | 4 ++++ .../optee/optee-os-tadevkit_3.14.0.bb | 20 +++++++++++++++++++ .../optee/optee-test_3.14.0.bb | 3 +++ 3 files changed, 27 insertions(+) create mode 100644 meta-arm/recipes-security/optee/optee-examples_3.14.0.bb create mode 100644 meta-arm/recipes-security/optee/optee-os-tadevkit_3.14.0.bb create mode 100644 meta-arm/recipes-security/optee/optee-test_3.14.0.bb diff --git a/meta-arm/recipes-security/optee/optee-examples_3.14.0.bb b/meta-arm/recipes-security/optee/optee-examples_3.14.0.bb new file mode 100644 index 00000000..f2b5f7dd --- /dev/null +++ b/meta-arm/recipes-security/optee/optee-examples_3.14.0.bb @@ -0,0 +1,4 @@ +require optee-examples.inc + +SRCREV = "e9c870525af8f7e7fccf575a0ca5394ce55adcec" + diff --git a/meta-arm/recipes-security/optee/optee-os-tadevkit_3.14.0.bb b/meta-arm/recipes-security/optee/optee-os-tadevkit_3.14.0.bb new file mode 100644 index 00000000..0d37a528 --- /dev/null +++ b/meta-arm/recipes-security/optee/optee-os-tadevkit_3.14.0.bb @@ -0,0 +1,20 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/optee-os:" +require optee-os_3.14.0.bb + +SUMMARY = "OP-TEE Trusted OS TA devkit" +DESCRIPTION = "OP-TEE TA devkit for build TAs" +HOMEPAGE = "https://www.op-tee.org/" + +do_install() { + #install TA devkit + install -d ${D}${includedir}/optee/export-user_ta/ + for f in ${B}/export-ta_${OPTEE_ARCH}/* ; do + cp -aR $f ${D}${includedir}/optee/export-user_ta/ + done +} + +do_deploy() { + echo "Do not inherit do_deploy from optee-os." +} + +FILES:${PN} = "${includedir}/optee/" diff --git a/meta-arm/recipes-security/optee/optee-test_3.14.0.bb b/meta-arm/recipes-security/optee/optee-test_3.14.0.bb new file mode 100644 index 00000000..6367c276 --- /dev/null +++ b/meta-arm/recipes-security/optee/optee-test_3.14.0.bb @@ -0,0 +1,3 @@ +require optee-test.inc + +SRCREV = "f2eb88affbb7f028561b4fd5cbd049d5d704f741" From patchwork Wed May 4 16:58:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7562 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D32DBC43217 for ; Wed, 4 May 2022 16:58:36 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web10.613.1651683511348012554 for ; Wed, 04 May 2022 09:58:31 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 4127111FB; Wed, 4 May 2022 09:58:30 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A229D3FA27; Wed, 4 May 2022 09:58:29 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 02/10] arm-bsp/optee: TC: Set preferred version of OP-TEE to v3.14 Date: Wed, 4 May 2022 17:58:12 +0100 Message-Id: <20220504165820.882784-2-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3358 This also adds missing optee-os-tadevkit, optee-test append files Signed-off-by: Arunachalam Ganapathy Change-Id: I1a217d9db7378f3ec711e984193b07ebb692e382 --- meta-arm-bsp/conf/machine/include/tc.inc | 5 +++++ .../optee/optee-os-tadevkit_3.14.0.bbappend | 6 ++++++ .../recipes-security/optee/optee-test_3.14.0.bbappend | 8 ++++++++ 3 files changed, 19 insertions(+) create mode 100644 meta-arm-bsp/recipes-security/optee/optee-os-tadevkit_3.14.0.bbappend create mode 100644 meta-arm-bsp/recipes-security/optee/optee-test_3.14.0.bbappend diff --git a/meta-arm-bsp/conf/machine/include/tc.inc b/meta-arm-bsp/conf/machine/include/tc.inc index 71cb17cd..0658dfbc 100644 --- a/meta-arm-bsp/conf/machine/include/tc.inc +++ b/meta-arm-bsp/conf/machine/include/tc.inc @@ -25,6 +25,11 @@ FIT_GENERATE_KEYS = "1" PREFERRED_PROVIDER_virtual/kernel ?= "linux-arm64-ack" PREFERRED_VERSION_linux-arm64-ack ?= "5.10" +# OP-TEE +PREFERRED_VERSION_optee-os ?= "3.14%" +PREFERRED_VERSION_optee-client ?= "3.14%" +PREFERRED_VERSION_optee-test ?= "3.14%" + # Cannot use the default zImage on arm64 KERNEL_IMAGETYPE = "Image" KERNEL_IMAGETYPES += "fitImage" diff --git a/meta-arm-bsp/recipes-security/optee/optee-os-tadevkit_3.14.0.bbappend b/meta-arm-bsp/recipes-security/optee/optee-os-tadevkit_3.14.0.bbappend new file mode 100644 index 00000000..6a22d47e --- /dev/null +++ b/meta-arm-bsp/recipes-security/optee/optee-os-tadevkit_3.14.0.bbappend @@ -0,0 +1,6 @@ +# Machine specific configurations + +MACHINE_OPTEE_OS_TADEVKIT_REQUIRE ?= "" +MACHINE_OPTEE_OS_TADEVKIT_REQUIRE:tc = "optee-os-generic-tc.inc" + +require ${MACHINE_OPTEE_OS_TADEVKIT_REQUIRE} diff --git a/meta-arm-bsp/recipes-security/optee/optee-test_3.14.0.bbappend b/meta-arm-bsp/recipes-security/optee/optee-test_3.14.0.bbappend new file mode 100644 index 00000000..f8194d0e --- /dev/null +++ b/meta-arm-bsp/recipes-security/optee/optee-test_3.14.0.bbappend @@ -0,0 +1,8 @@ +# Machine specific configurations + +DEPENDS = "optee-client optee-os-tadevkit python3-pycryptodome-native" + +MACHINE_OPTEE_TEST_REQUIRE ?= "" +MACHINE_OPTEE_TEST_REQUIRE:tc = "optee-test-tc.inc" + +require ${MACHINE_OPTEE_TEST_REQUIRE} From patchwork Wed May 4 16:58:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7563 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF5B1C433EF for ; Wed, 4 May 2022 16:58:36 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web08.599.1651683511394454668 for ; Wed, 04 May 2022 09:58:31 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 09A1712FC; Wed, 4 May 2022 09:58:31 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6CBFC3FA27; Wed, 4 May 2022 09:58:30 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 03/10] arm-bsp/u-boot: TC: Upgrade to 2022.01 and add patch for secure DRAM size Date: Wed, 4 May 2022 17:58:13 +0100 Message-Id: <20220504165820.882784-3-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3359 - Upgrade U-boot to 2022.01 - Remove 8GB DRAM increase patch that is merged - Add patch that update secure DRAM size Signed-off-by: Arunachalam Ganapathy Change-Id: I32735cb5e8cba67ac1c6082aadf9a55f7bf51e8a --- meta-arm-bsp/conf/machine/include/tc.inc | 2 +- ...m-total_compute-increase-DRAM-to-8GB.patch | 47 ------------------- ...otal_compute-update-secure-dram-size.patch | 33 +++++++++++++ .../recipes-bsp/u-boot/u-boot_%.bbappend | 2 +- 4 files changed, 35 insertions(+), 49 deletions(-) delete mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-increase-DRAM-to-8GB.patch create mode 100644 meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-update-secure-dram-size.patch diff --git a/meta-arm-bsp/conf/machine/include/tc.inc b/meta-arm-bsp/conf/machine/include/tc.inc index 0658dfbc..ed5ffa96 100644 --- a/meta-arm-bsp/conf/machine/include/tc.inc +++ b/meta-arm-bsp/conf/machine/include/tc.inc @@ -6,7 +6,7 @@ MACHINEOVERRIDES =. "tc:" # Das U-boot UBOOT_MACHINE ?= "total_compute_defconfig" -PREFERRED_VERSION_u-boot ?= "2021.10" +PREFERRED_VERSION_u-boot ?= "2022.01" UBOOT_RD_LOADADDRESS = "0x88000000" UBOOT_RD_ENTRYPOINT = "0x88000000" UBOOT_LOADADDRESS = "0x80080000" diff --git a/meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-increase-DRAM-to-8GB.patch b/meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-increase-DRAM-to-8GB.patch deleted file mode 100644 index d1cfcdba..00000000 --- a/meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-increase-DRAM-to-8GB.patch +++ /dev/null @@ -1,47 +0,0 @@ -From bdb7de7cdef6ece51dfcee927d3ce0c97fc431f0 Mon Sep 17 00:00:00 2001 -From: Usama Arif -Date: Tue, 12 Oct 2021 13:43:16 +0100 -Subject: [PATCH] arm: total_compute: increase DRAM to 8GB - -The extra 6GB start at 0x8080000000. - -Signed-off-by: Usama Arif - -Upstream-Status: Backport [https://github.com/u-boot/u-boot/commit/b20b16a794b073807ef8d6840772a92788b3e226] -Signed-off-by: Arunachalam Ganapathy ---- - board/armltd/total_compute/total_compute.c | 3 +++ - include/configs/total_compute.h | 3 +++ - 2 files changed, 6 insertions(+) - -diff --git a/board/armltd/total_compute/total_compute.c b/board/armltd/total_compute/total_compute.c -index b7eaab0851..b7772f79a3 100644 ---- a/board/armltd/total_compute/total_compute.c -+++ b/board/armltd/total_compute/total_compute.c -@@ -59,6 +59,9 @@ int dram_init_banksize(void) - gd->bd->bi_dram[0].start = PHYS_SDRAM_1; - gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; - -+ gd->bd->bi_dram[1].start = PHYS_SDRAM_2; -+ gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE; -+ - return 0; - } - -diff --git a/include/configs/total_compute.h b/include/configs/total_compute.h -index cc93f1930a..283268607a 100644 ---- a/include/configs/total_compute.h -+++ b/include/configs/total_compute.h -@@ -34,6 +34,9 @@ - #define PHYS_SDRAM_1_SIZE 0x80000000 - DRAM_SEC_SIZE - #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 - -+#define PHYS_SDRAM_2 0x8080000000 -+#define PHYS_SDRAM_2_SIZE 0x180000000 -+ - #define CONFIG_ARM_PL180_MMCI_BASE 0x001c050000 - #define CONFIG_SYS_MMC_MAX_BLK_COUNT 127 - #define CONFIG_ARM_PL180_MMCI_CLOCK_FREQ 12000000 --- -2.30.2 - diff --git a/meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-update-secure-dram-size.patch b/meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-update-secure-dram-size.patch new file mode 100644 index 00000000..657af223 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/u-boot/u-boot/tc/0001-arm-total_compute-update-secure-dram-size.patch @@ -0,0 +1,33 @@ +From 5f10bd9b64c745084292a7094af2e4c3d14c1ac5 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Tue, 12 Apr 2022 12:43:49 +0100 +Subject: [PATCH 1/3] arm: total_compute: update secure dram size + +Update secure DRAM size as it is increased by 64MB for additional +secure partitions. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Id8ce99c7a5330d3c28d473009c4db04141e6fa4d +Upstream-Status: Pending [Not submitted to upstream yet] +--- + include/configs/total_compute.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/configs/total_compute.h b/include/configs/total_compute.h +index 933a145f99..66de8ae239 100644 +--- a/include/configs/total_compute.h ++++ b/include/configs/total_compute.h +@@ -25,8 +25,8 @@ + + /* Physical Memory Map */ + #define PHYS_SDRAM_1 0x80000000 +-/* Top 48MB reserved for secure world use */ +-#define DRAM_SEC_SIZE 0x03000000 ++/* Top 112MB reserved for secure world use */ ++#define DRAM_SEC_SIZE 0x07000000 + #define PHYS_SDRAM_1_SIZE 0x80000000 - DRAM_SEC_SIZE + #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/u-boot/u-boot_%.bbappend b/meta-arm-bsp/recipes-bsp/u-boot/u-boot_%.bbappend index f7336ad2..7155226d 100644 --- a/meta-arm-bsp/recipes-bsp/u-boot/u-boot_%.bbappend +++ b/meta-arm-bsp/recipes-bsp/u-boot/u-boot_%.bbappend @@ -80,5 +80,5 @@ SRC_URI:append:fvp-baser-aemv8r64 = " \ # SRC_URI:append:tc = " \ file://bootargs.cfg \ - file://0001-arm-total_compute-increase-DRAM-to-8GB.patch \ + file://0001-arm-total_compute-update-secure-dram-size.patch \ " From patchwork Wed May 4 16:58:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7564 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id DD582C43219 for ; Wed, 4 May 2022 16:58:36 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web09.625.1651683512293632214 for ; Wed, 04 May 2022 09:58:32 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 E16AD1042; Wed, 4 May 2022 09:58:31 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 35CB33FA27; Wed, 4 May 2022 09:58:31 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 04/10] arm-bsp/hafnium: TC: update SHA and remove upstreamed patches Date: Wed, 4 May 2022 17:58:14 +0100 Message-Id: <20220504165820.882784-4-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3360 Signed-off-by: Arunachalam Ganapathy Change-Id: I33a7cc01040c6a2392d87763da9c0adc0c5bbe2d --- ...-if-start-address-exceeds-page-table.patch | 36 ---- .../0002-Extend-Stage-1-mapping-limit.patch | 197 ------------------ .../recipes-bsp/hafnium/hafnium-tc.inc | 13 +- 3 files changed, 9 insertions(+), 237 deletions(-) delete mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-fix-fail-mapping-if-start-address-exceeds-page-table.patch delete mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-Extend-Stage-1-mapping-limit.patch diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-fix-fail-mapping-if-start-address-exceeds-page-table.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-fix-fail-mapping-if-start-address-exceeds-page-table.patch deleted file mode 100644 index 79aee241..00000000 --- a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-fix-fail-mapping-if-start-address-exceeds-page-table.patch +++ /dev/null @@ -1,36 +0,0 @@ -From dace8802ae6332eb4ca29faf288b96c83fadb2ae Mon Sep 17 00:00:00 2001 -From: Arunachalam Ganapathy -Date: Tue, 28 Sep 2021 11:22:27 +0100 -Subject: [PATCH 1/2] fix: fail mapping if start address exceeds page table - mapping limit - -Currently the end address is capped to stay within bounds of page -table range. If in case the start address is beyond bounds of -page table then no mapping is made but the mm_map_root incorrectly -returns success. - -Signed-off-by: Arunachalam Ganapathy -Change-Id: I858ac653aafff62e9a2cf5771a32dc38690cd899 -Upstream-Status: Pending [Not submitted to upstream yet] ---- - src/mm.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/mm.c b/src/mm.c -index 6f15748..c57e24e 100644 ---- a/src/mm.c -+++ b/src/mm.c -@@ -472,6 +472,10 @@ static bool mm_ptable_identity_map(struct mm_ptable *t, paddr_t pa_begin, - */ - CHECK(root_level >= 2); - -+ if (begin >= ptable_end) { -+ return false; -+ } -+ - /* Cap end to stay within the bounds of the page table. */ - if (end > ptable_end) { - end = ptable_end; --- -2.30.2 - diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-Extend-Stage-1-mapping-limit.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-Extend-Stage-1-mapping-limit.patch deleted file mode 100644 index 8493310d..00000000 --- a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-Extend-Stage-1-mapping-limit.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 45187e2f9c73ea96e69d1f46f0c24ff31d7f9298 Mon Sep 17 00:00:00 2001 -From: Arunachalam Ganapathy -Date: Tue, 28 Sep 2021 11:25:25 +0100 -Subject: [PATCH 2/2] Extend Stage 1 mapping limit - -As Stage 1 mappings are limited to 512GB, registering FF-A RxTx buffers -fails when the physical address of these buffers exceeds 512GB. This -fix removes the limitation and allows Stage 1 mapping up to the -supported PA range. - -Signed-off-by: Arunachalam Ganapathy -Change-Id: I4cb8d68fc18e0edf4a7ee06ae636849d552d72a9 -Upstream-Status: Pending [Not submitted to upstream yet] ---- - inc/hf/arch/mm.h | 7 ++++++- - src/arch/aarch64/mm.c | 38 ++++++++++++++++++++++++++------------ - src/arch/fake/mm.c | 9 +++++++-- - src/mm.c | 8 +++++++- - 4 files changed, 46 insertions(+), 16 deletions(-) - -diff --git a/inc/hf/arch/mm.h b/inc/hf/arch/mm.h -index ef64dd3..d277369 100644 ---- a/inc/hf/arch/mm.h -+++ b/inc/hf/arch/mm.h -@@ -162,7 +162,12 @@ uint32_t arch_mm_stage1_attrs_to_mode(uint64_t attrs); - /** - * Initializes the arch specific memory management. - */ --bool arch_mm_init(paddr_t table); -+bool arch_mm_init(void); -+ -+/** -+ * Set ptable base address. -+ */ -+void arch_mm_set_ptable(paddr_t table); - - /** - * Return the arch specific mm mode for send/recv pages of given VM ID. -diff --git a/src/arch/aarch64/mm.c b/src/arch/aarch64/mm.c -index 7256c28..0ee0bb6 100644 ---- a/src/arch/aarch64/mm.c -+++ b/src/arch/aarch64/mm.c -@@ -141,6 +141,7 @@ struct arch_mm_config { - uintreg_t hcr_el2; - } arch_mm_config; - -+static uint8_t mm_s1_max_level; - static uint8_t mm_s2_max_level; - static uint8_t mm_s2_root_table_count; - -@@ -676,12 +677,7 @@ uint32_t arch_mm_stage2_attrs_to_mode(uint64_t attrs) - - uint8_t arch_mm_stage1_max_level(void) - { -- /* -- * For stage 1 we hard-code this to 2 for now so that we can -- * save one page table level at the expense of limiting the -- * physical memory to 512GB. -- */ -- return 2; -+ return mm_s1_max_level; - } - - uint8_t arch_mm_stage2_max_level(void) -@@ -735,10 +731,16 @@ uint64_t arch_mm_combine_table_entry_attrs(uint64_t table_attrs, - return block_attrs; - } - -+void -+arch_mm_set_ptable(paddr_t table) -+{ -+ arch_mm_config.ttbr0_el2 = pa_addr(table); -+} -+ - /** - * This is called early in initialization without MMU or caches enabled. - */ --bool arch_mm_init(paddr_t table) -+bool arch_mm_init(void) - { - static const int pa_bits_table[16] = {32, 36, 40, 42, 44, 48}; - uint64_t features = read_msr(id_aa64mmfr0_el1); -@@ -784,6 +786,13 @@ bool arch_mm_init(paddr_t table) - mm_s2_max_level = 1; - } - -+ if (pa_bits >= 40) { -+ mm_s1_max_level = 3; -+ } else { -+ /* Setting to 2 covers physical memory upto 512GB */ -+ mm_s1_max_level = 2; -+ } -+ - /* - * Since the shallowest possible tree is used, the maximum number of - * concatenated tables must be used. This means if no more than 4 bits -@@ -800,6 +809,10 @@ bool arch_mm_init(paddr_t table) - "Stage 2 has %d page table levels with %d pages at the root.\n", - mm_s2_max_level + 1, mm_s2_root_table_count); - -+ dlog_info("Stage 1 has %d page table levels with %d pages at the " -+ "root.\n", mm_s1_max_level + 1, -+ arch_mm_stage1_root_table_count()); -+ - /* - * If the PE implements S-EL2 then VTCR_EL2.NSA/NSW bits are significant - * in secure state. In non-secure state, NSA/NSW behave as if set to -@@ -818,8 +831,6 @@ bool arch_mm_init(paddr_t table) - } - - arch_mm_config = (struct arch_mm_config){ -- .ttbr0_el2 = pa_addr(table), -- - .vtcr_el2 = - (1U << 31) | /* RES1. */ - (nsa_nsw << 29) | /* NSA/NSW. */ -@@ -879,14 +890,16 @@ bool arch_mm_init(paddr_t table) - << 24) | /* IRGN1, normal mem, WB RA WA Cacheable. */ - (1UL << 23) | /* EPD1 - Disable TTBR1_EL2 translation */ - (0UL << 22) | /* TTBR0_EL2.ASID defines ASID */ -- (25UL << 16) | /* T1SZ, input address is 2^39 bytes. */ -+ ((64 - pa_bits) << 16) | /* T1SZ, input address is * -+ 2^pa_bits bytes. */ - (0UL << 14) | /* TG0, granule size, 4KB. */ - (3UL << 12) | /* SH0, inner shareable. */ - (1UL - << 10) | /* ORGN0, normal mem, WB RA WA Cacheable. */ - (1UL - << 8) | /* IRGN0, normal mem, WB RA WA Cacheable. */ -- (25UL << 0) | /* T0SZ, input address is 2^39 bytes. */ -+ ((64 - pa_bits) << 0) | /* T0SZ, input address is * -+ 2^pa_bits bytes. */ - 0; - } else { - arch_mm_config.tcr_el2 = -@@ -896,7 +909,8 @@ bool arch_mm_init(paddr_t table) - (3 << 12) | /* SH0, inner shareable. */ - (1 << 10) | /* ORGN0, normal mem, WB RA WA Cacheable. */ - (1 << 8) | /* IRGN0, normal mem, WB RA WA Cacheable. */ -- (25 << 0) | /* T0SZ, input address is 2^39 bytes. */ -+ ((64 - pa_bits) << 0) | /* T0SZ, input address is * -+ 2^pa_bits bytes. */ - 0; - } - return true; -diff --git a/src/arch/fake/mm.c b/src/arch/fake/mm.c -index e06a8b7..8ac63fa 100644 ---- a/src/arch/fake/mm.c -+++ b/src/arch/fake/mm.c -@@ -161,13 +161,18 @@ uint32_t arch_mm_stage1_attrs_to_mode(uint64_t attrs) - return attrs >> PTE_ATTR_MODE_SHIFT; - } - --bool arch_mm_init(paddr_t table) -+bool arch_mm_init(void) - { - /* No initialization required. */ -- (void)table; - return true; - } - -+void arch_mm_set_ptable(paddr_t table) -+{ -+ /* No initialization required. */ -+ (void)table; -+} -+ - uint32_t arch_mm_extra_attributes_from_vm(ffa_vm_id_t id) - { - (void)id; -diff --git a/src/mm.c b/src/mm.c -index c57e24e..aa0c512 100644 ---- a/src/mm.c -+++ b/src/mm.c -@@ -1114,6 +1114,10 @@ bool mm_init(struct mpool *ppool) - dlog_info("data: %#x - %#x\n", pa_addr(layout_data_begin()), - pa_addr(layout_data_end())); - -+ if (!arch_mm_init()) { -+ return false; -+ } -+ - /* ASID 0 is reserved for use by the hypervisor. */ - if (!mm_ptable_init(&ptable, 0, MM_FLAG_STAGE1, ppool)) { - dlog_error("Unable to allocate memory for page table.\n"); -@@ -1133,5 +1137,7 @@ bool mm_init(struct mpool *ppool) - mm_identity_map(stage1_locked, layout_data_begin(), layout_data_end(), - MM_MODE_R | MM_MODE_W, ppool); - -- return arch_mm_init(ptable.root); -+ arch_mm_set_ptable(ptable.root); -+ -+ return true; - } --- -2.30.2 - diff --git a/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc b/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc index 27f77773..14330856 100644 --- a/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc +++ b/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc @@ -3,8 +3,13 @@ COMPATIBLE_MACHINE = "(tc?)" HAFNIUM_PLATFORM = "secure_tc" +SRCREV = "4eb7b54348234d7f4bbac64bac28f683d6574ba9" FILESEXTRAPATHS:prepend:tc := "${THISDIR}/files/tc:" -SRC_URI:append = " \ - file://0001-fix-fail-mapping-if-start-address-exceeds-page-table.patch \ - file://0002-Extend-Stage-1-mapping-limit.patch \ - " + +SRC_URI:remove = " \ + file://host-ld.patch \ + file://native-dtc.patch" + +do_compile() { + PATH="${S}/prebuilts/linux-x64/clang/bin:$PATH" oe_runmake -C ${S} +} From patchwork Wed May 4 16:58:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7565 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1B45C4321E for ; Wed, 4 May 2022 16:58:36 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web12.632.1651683513567449572 for ; Wed, 04 May 2022 09:58:33 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 C5C5111FB; Wed, 4 May 2022 09:58:32 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 199683FA27; Wed, 4 May 2022 09:58:31 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 05/10] arm-bsp/trusted-firmware-a: TC: Add Trusty SP support Date: Wed, 4 May 2022 17:58:15 +0100 Message-Id: <20220504165820.882784-5-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3361 This patch updates the SHA and include patches that enables Trusty to run as SP on SEL2 SPMC. Signed-off-by: Arunachalam Ganapathy Change-Id: I5586bb3aa592658be9421a4de23f44a69bfb0b2e --- .../0002-Enable-CI-700-interconnect.patch | 34 ---- ...01-plat-tc-Increase-maximum-BL2-size.patch | 0 ...t-tc-enable-CI-700-PMU-for-profiling.patch | 32 ++++ ...add-trusty_sp_fw_config-build-option.patch | 46 +++++ ...-plat-arm-increase-sp-max-image-size.patch | 30 ++++ ...x-plat-tc-increase-tc_tzc_dram1_size.patch | 69 +++++++ ...-tc-add-spmc-manifest-with-trusty-sp.patch | 169 ++++++++++++++++++ ...ate-dts-with-trusty-compatible-strin.patch | 50 ++++++ .../tc/0008-fix-plat-tc-disable-smmu.patch | 64 +++++++ .../files/{ => tc}/generate_metadata.py | 0 .../trusted-firmware-a-tc.inc | 11 +- 11 files changed, 469 insertions(+), 36 deletions(-) delete mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/0002-Enable-CI-700-interconnect.patch rename meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/{ => tc}/0001-plat-tc-Increase-maximum-BL2-size.patch (100%) create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0002-feat-tc-enable-CI-700-PMU-for-profiling.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0003-Makefile-add-trusty_sp_fw_config-build-option.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0004-fix-plat-arm-increase-sp-max-image-size.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0005-fix-plat-tc-increase-tc_tzc_dram1_size.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0006-feat-plat-tc-add-spmc-manifest-with-trusty-sp.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0007-feat-plat-tc-update-dts-with-trusty-compatible-strin.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0008-fix-plat-tc-disable-smmu.patch rename meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/{ => tc}/generate_metadata.py (100%) diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/0002-Enable-CI-700-interconnect.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/0002-Enable-CI-700-interconnect.patch deleted file mode 100644 index 2add0af9..00000000 --- a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/0002-Enable-CI-700-interconnect.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 366215a3705228a12efe9f92f1d1033f34ee89fa Mon Sep 17 00:00:00 2001 -From: Rupinderjit Singh -Date: Thu, 21 Apr 2022 14:45:23 +0100 -Subject: [PATCH] Enable CI-700 interconnect - -Signed-off-by: Rupinderjit Singh -Change-Id: Ie56d47a0b65274a467e98b9ecd3caf25dfe10544 - -Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/14918] - ---- - fdts/tc.dts | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/fdts/tc.dts b/fdts/tc.dts -index 7c0e84260..d0985851d 100644 ---- a/fdts/tc.dts -+++ b/fdts/tc.dts -@@ -461,6 +461,12 @@ - status = "okay"; - }; - -+ cmn-pmu { -+ compatible = "arm,ci-700"; -+ reg = <0x0 0x50000000 0x0 0x10000000>; -+ interrupts = <0x0 460 0x4>; -+ }; -+ - dp0: display@2cc00000 { - #address-cells = <1>; - #size-cells = <0>; --- -2.25.1 - diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/0001-plat-tc-Increase-maximum-BL2-size.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0001-plat-tc-Increase-maximum-BL2-size.patch similarity index 100% rename from meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/0001-plat-tc-Increase-maximum-BL2-size.patch rename to meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0001-plat-tc-Increase-maximum-BL2-size.patch diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0002-feat-tc-enable-CI-700-PMU-for-profiling.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0002-feat-tc-enable-CI-700-PMU-for-profiling.patch new file mode 100644 index 00000000..c9016084 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0002-feat-tc-enable-CI-700-PMU-for-profiling.patch @@ -0,0 +1,32 @@ +From 1565ac8995f90113b2be5acddc86773bfe0a0ac9 Mon Sep 17 00:00:00 2001 +From: Rupinderjit Singh +Date: Tue, 22 Feb 2022 21:50:33 +0000 +Subject: [PATCH 1/7] feat(tc): enable CI-700 PMU for profiling + +Change-Id: Iaafdfc440b362022e6103eabf3fb2ebed85b6575 +Signed-off-by: Rupinderjit Singh +Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/14918] +--- + fdts/tc.dts | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fdts/tc.dts b/fdts/tc.dts +index 7c0e84260..20992294b 100644 +--- a/fdts/tc.dts ++++ b/fdts/tc.dts +@@ -261,6 +261,12 @@ + arm,mhuv2-protocols = <0 1>; + }; + ++ cmn-pmu { ++ compatible = "arm,ci-700"; ++ reg = <0x0 0x50000000 0x0 0x10000000>; ++ interrupts = <0x0 460 0x4>; ++ }; ++ + scmi { + compatible = "arm,scmi"; + mbox-names = "tx", "rx"; +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0003-Makefile-add-trusty_sp_fw_config-build-option.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0003-Makefile-add-trusty_sp_fw_config-build-option.patch new file mode 100644 index 00000000..f5ddb0f2 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0003-Makefile-add-trusty_sp_fw_config-build-option.patch @@ -0,0 +1,46 @@ +From f602df2563cbae1fce2559430a394180983fbbaf Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Mon, 11 Apr 2022 14:36:54 +0100 +Subject: [PATCH 2/7] Makefile: add trusty_sp_fw_config build option + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ief90ae9113d32265ee2200f35f3e517b7b9a4bea +Upstream-Status: Pending [Not submitted to upstream yet] +--- + Makefile | 4 ++++ + docs/plat/arm/arm-build-options.rst | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/Makefile b/Makefile +index f91699c44..f401a0010 100644 +--- a/Makefile ++++ b/Makefile +@@ -533,6 +533,10 @@ ifneq (${SPD},none) + DTC_CPPFLAGS += -DOPTEE_SP_FW_CONFIG + endif + ++ ifeq ($(findstring trusty_sp,$(ARM_SPMC_MANIFEST_DTS)),trusty_sp) ++ DTC_CPPFLAGS += -DTRUSTY_SP_FW_CONFIG ++ endif ++ + ifeq ($(TS_SP_FW_CONFIG),1) + DTC_CPPFLAGS += -DTS_SP_FW_CONFIG + endif +diff --git a/docs/plat/arm/arm-build-options.rst b/docs/plat/arm/arm-build-options.rst +index 339ebbe33..3c9a41fb8 100644 +--- a/docs/plat/arm/arm-build-options.rst ++++ b/docs/plat/arm/arm-build-options.rst +@@ -107,6 +107,10 @@ Arm Platform Build Options + device tree. This flag is defined only when ``ARM_SPMC_MANIFEST_DTS`` manifest + file name contains pattern optee_sp. + ++- ``TRUSTY_SP_FW_CONFIG``: DTC build flag to include Trusty as SP in ++ tb_fw_config device tree. This flag is defined only when ++ ``ARM_SPMC_MANIFEST_DTS`` manifest file name contains pattern trusty_sp. ++ + - ``TS_SP_FW_CONFIG``: DTC build flag to include Trusted Services (Crypto and + internal-trusted-storage) as SP in tb_fw_config device tree. + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0004-fix-plat-arm-increase-sp-max-image-size.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0004-fix-plat-arm-increase-sp-max-image-size.patch new file mode 100644 index 00000000..c61e9b58 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0004-fix-plat-arm-increase-sp-max-image-size.patch @@ -0,0 +1,30 @@ +From d5a8e035de394f7a8924151318abc094d9ae68ae Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Mon, 11 Apr 2022 18:31:01 +0100 +Subject: [PATCH 3/7] fix(plat/arm): increase sp max image size + +Increase ARM_SP_MAX_SIZE to support Trusty image. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: I9ef9e755769445aee998062a7fba508fad50b33e +Upstream-Status: Pending [Not submitted to upstream yet] +--- + include/plat/arm/common/fconf_arm_sp_getter.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/plat/arm/common/fconf_arm_sp_getter.h b/include/plat/arm/common/fconf_arm_sp_getter.h +index aa628dfd3..3ed953d1c 100644 +--- a/include/plat/arm/common/fconf_arm_sp_getter.h ++++ b/include/plat/arm/common/fconf_arm_sp_getter.h +@@ -13,7 +13,7 @@ + /* arm_sp getter */ + #define arm__sp_getter(prop) arm_sp.prop + +-#define ARM_SP_MAX_SIZE U(0xb0000) ++#define ARM_SP_MAX_SIZE U(0x2000000) + #define ARM_SP_OWNER_NAME_LEN U(8) + + struct arm_sp_t { +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0005-fix-plat-tc-increase-tc_tzc_dram1_size.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0005-fix-plat-tc-increase-tc_tzc_dram1_size.patch new file mode 100644 index 00000000..c6d4d862 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0005-fix-plat-tc-increase-tc_tzc_dram1_size.patch @@ -0,0 +1,69 @@ +From f6485e50af73c905faa0777e462ffdfa483d19da Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Mon, 11 Apr 2022 17:38:17 +0100 +Subject: [PATCH 4/7] fix(plat/tc): increase tc_tzc_dram1_size + +Increase TC_TZC_DRAM1_SIZE for Trusty image and its memory size. +Update OP-TEE reserved memory range in DTS + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Iad433c3c155f28860b15bde2398df653487189dd +Upstream-Status: Pending [Not submitted to upstream yet] +--- + fdts/tc.dts | 4 ++-- + plat/arm/board/tc/include/platform_def.h | 10 ++++++---- + 2 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/fdts/tc.dts b/fdts/tc.dts +index 20992294b..af64504a4 100644 +--- a/fdts/tc.dts ++++ b/fdts/tc.dts +@@ -213,8 +213,8 @@ + linux,cma-default; + }; + +- optee@0xfce00000 { +- reg = <0x00000000 0xfce00000 0 0x00200000>; ++ optee@0xf8e00000 { ++ reg = <0x00000000 0xf8e00000 0 0x00200000>; + no-map; + }; + }; +diff --git a/plat/arm/board/tc/include/platform_def.h b/plat/arm/board/tc/include/platform_def.h +index 745d91cab..73b984308 100644 +--- a/plat/arm/board/tc/include/platform_def.h ++++ b/plat/arm/board/tc/include/platform_def.h +@@ -31,7 +31,7 @@ + */ + #define TC_TZC_DRAM1_BASE (ARM_AP_TZC_DRAM1_BASE - \ + TC_TZC_DRAM1_SIZE) +-#define TC_TZC_DRAM1_SIZE UL(0x02000000) /* 32 MB */ ++#define TC_TZC_DRAM1_SIZE UL(0x06000000) /* 96 MB */ + #define TC_TZC_DRAM1_END (TC_TZC_DRAM1_BASE + \ + TC_TZC_DRAM1_SIZE - 1) + +@@ -68,7 +68,9 @@ + * max size of BL32 image. + */ + #if defined(SPD_spmd) +-#define PLAT_ARM_SPMC_BASE TC_TZC_DRAM1_BASE ++#define TC_EL2SPMC_LOAD_ADDR (TC_TZC_DRAM1_BASE + 0x04000000) ++ ++#define PLAT_ARM_SPMC_BASE TC_EL2SPMC_LOAD_ADDR + #define PLAT_ARM_SPMC_SIZE UL(0x200000) /* 2 MB */ + #endif + +@@ -259,8 +261,8 @@ + (TZC_REGION_ACCESS_RDWR(TZC_NSAID_DEFAULT)) + + /* +- * The first region below, TC_TZC_DRAM1_BASE (0xfd000000) to +- * ARM_SCP_TZC_DRAM1_END (0xffffffff) will mark the last 48 MB of DRAM as ++ * The first region below, TC_TZC_DRAM1_BASE (0xf9000000) to ++ * ARM_SCP_TZC_DRAM1_END (0xffffffff) will mark the last 112 MB of DRAM as + * secure. The second and third regions gives non secure access to rest of DRAM. + */ + #define TC_TZC_REGIONS_DEF \ +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0006-feat-plat-tc-add-spmc-manifest-with-trusty-sp.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0006-feat-plat-tc-add-spmc-manifest-with-trusty-sp.patch new file mode 100644 index 00000000..73a301b8 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0006-feat-plat-tc-add-spmc-manifest-with-trusty-sp.patch @@ -0,0 +1,169 @@ +From bdf66cf30ed4cb0c16a5335fbb68fa0b2e253f7c Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Mon, 11 Apr 2022 14:43:15 +0100 +Subject: [PATCH 5/7] feat(plat/tc): add spmc manifest with trusty sp + +Add SPMC manifest with Trusty SP. Define Trusty's load address, +vcpu count, memory size. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: If4363580a478776d233f7f391a30e1cb345453c2 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + .../tc/fdts/tc_spmc_trusty_sp_manifest.dts | 120 ++++++++++++++++++ + plat/arm/board/tc/fdts/tc_tb_fw_config.dts | 7 +- + 2 files changed, 126 insertions(+), 1 deletion(-) + create mode 100644 plat/arm/board/tc/fdts/tc_spmc_trusty_sp_manifest.dts + +diff --git a/plat/arm/board/tc/fdts/tc_spmc_trusty_sp_manifest.dts b/plat/arm/board/tc/fdts/tc_spmc_trusty_sp_manifest.dts +new file mode 100644 +index 000000000..e2ea7b811 +--- /dev/null ++++ b/plat/arm/board/tc/fdts/tc_spmc_trusty_sp_manifest.dts +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (c) 2022, Arm Limited. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++/dts-v1/; ++ ++/ { ++ compatible = "arm,ffa-core-manifest-1.0"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ attribute { ++ spmc_id = <0x8000>; ++ maj_ver = <0x1>; ++ min_ver = <0x1>; ++ exec_state = <0x0>; ++ load_address = <0x0 0xfd000000>; ++ entrypoint = <0x0 0xfd000000>; ++ binary_size = <0x80000>; ++ }; ++ ++ hypervisor { ++ compatible = "hafnium,hafnium"; ++ vm1 { ++ is_ffa_partition; ++ debug_name = "trusty"; ++ load_address = <0xf901f000>; ++ vcpu_count = <8>; ++ mem_size = <0x3f00000>; /* 64MB TZC DRAM - 1MB align */ ++ }; ++#ifdef TS_SP_FW_CONFIG ++ vm2 { ++ is_ffa_partition; ++ debug_name = "internal-trusted-storage"; ++ load_address = <0xfee00000>; ++ vcpu_count = <1>; ++ mem_size = <2097152>; /* 2MB TZC DRAM */ ++ }; ++ vm3 { ++ is_ffa_partition; ++ debug_name = "crypto"; ++ load_address = <0xfec00000>; ++ vcpu_count = <1>; ++ mem_size = <2097152>; /* 2MB TZC DRAM */ ++ }; ++#endif ++ }; ++ ++ cpus { ++ #address-cells = <0x2>; ++ #size-cells = <0x0>; ++ ++ CPU0:cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x0>; ++ enable-method = "psci"; ++ }; ++ ++ /* ++ * SPMC (Hafnium) requires secondary cpu nodes are declared in ++ * descending order ++ */ ++ CPU7:cpu@700 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x700>; ++ enable-method = "psci"; ++ }; ++ ++ CPU6:cpu@600 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x600>; ++ enable-method = "psci"; ++ }; ++ ++ CPU5:cpu@500 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x500>; ++ enable-method = "psci"; ++ }; ++ ++ CPU4:cpu@400 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x400>; ++ enable-method = "psci"; ++ }; ++ ++ CPU3:cpu@300 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x300>; ++ enable-method = "psci"; ++ }; ++ ++ CPU2:cpu@200 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x200>; ++ enable-method = "psci"; ++ }; ++ ++ CPU1:cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,armv8"; ++ reg = <0x0 0x100>; ++ enable-method = "psci"; ++ }; ++ }; ++ ++ /* 96MB of TC_TZC_DRAM1_BASE */ ++ memory@f9000000 { ++ device_type = "memory"; ++ reg = <0x0 0xf9000000 0x6000000>; ++ }; ++}; +diff --git a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts +index 4c6ccef25..a72772fb3 100644 +--- a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts ++++ b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2020-2021, Arm Limited. All rights reserved. ++ * Copyright (c) 2020-2022, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -47,6 +47,11 @@ + uuid = "486178e0-e7f8-11e3-bc5e-0002a5d5c51b"; + load-address = <0xfd280000>; + }; ++#elif TRUSTY_SP_FW_CONFIG ++ trusty { ++ uuid = "40ee25f0-a2bc-304c-8c4c-a173c57d8af1"; ++ load-address = <0xf901f000>; ++ }; + #else + cactus-primary { + uuid = "b4b5671e-4a90-4fe1-b81f-fb13dae1dacb"; +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0007-feat-plat-tc-update-dts-with-trusty-compatible-strin.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0007-feat-plat-tc-update-dts-with-trusty-compatible-strin.patch new file mode 100644 index 00000000..f623e4de --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0007-feat-plat-tc-update-dts-with-trusty-compatible-strin.patch @@ -0,0 +1,50 @@ +From c2f939891e46e2ef9b54ed5e270e42187fdc57b3 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Wed, 30 Mar 2022 12:14:49 +0000 +Subject: [PATCH 6/7] feat(plat/tc): update dts with trusty compatible string + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ic6661df479e114bf3f464165c14df5fa02dc0139 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + fdts/tc.dts | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/fdts/tc.dts b/fdts/tc.dts +index af64504a4..dc86958bf 100644 +--- a/fdts/tc.dts ++++ b/fdts/tc.dts +@@ -555,4 +555,30 @@ + compatible = "arm,trace-buffer-extension"; + interrupts = <1 2 4>; + }; ++ ++ trusty { ++ #size-cells = <0x02>; ++ #address-cells = <0x02>; ++ ranges = <0x00>; ++ compatible = "android,trusty-v1"; ++ ++ virtio { ++ compatible = "android,trusty-virtio-v1"; ++ }; ++ ++ test { ++ compatible = "android,trusty-test-v1"; ++ }; ++ ++ log { ++ compatible = "android,trusty-log-v1"; ++ }; ++ ++ irq { ++ ipi-range = <0x08 0x0f 0x08>; ++ interrupt-ranges = <0x00 0x0f 0x00 0x10 0x1f 0x01 0x20 0x3f 0x02>; ++ interrupt-templates = <0x01 0x00 0x8001 0x01 0x01 0x04 0x8001 0x01 0x00 0x04>; ++ compatible = "android,trusty-irq-v1"; ++ }; ++ }; + }; +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0008-fix-plat-tc-disable-smmu.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0008-fix-plat-tc-disable-smmu.patch new file mode 100644 index 00000000..50924869 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/0008-fix-plat-tc-disable-smmu.patch @@ -0,0 +1,64 @@ +From d67e1f76be37127b0fe2a84ee631c5a799c426ba Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Wed, 27 Apr 2022 18:15:47 +0100 +Subject: [PATCH 7/7] fix(plat/tc): disable smmu + +Reserve static shared-dma-pool below 4GB. This removes dependency on +SMMU driver. As there are stability issues in SMMU driver, it is +disabled. This change is temporary and will be reverted upon proper +fix and testing. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: I6b1b4c2a0acdf62df8c26007c7ca596774e13710 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + fdts/tc.dts | 16 +++------------- + 1 file changed, 3 insertions(+), 13 deletions(-) + +diff --git a/fdts/tc.dts b/fdts/tc.dts +index dc86958bf..fbae3e3e8 100644 +--- a/fdts/tc.dts ++++ b/fdts/tc.dts +@@ -209,12 +209,12 @@ + linux,cma { + compatible = "shared-dma-pool"; + reusable; +- size = <0x0 0x8000000>; ++ reg = <0x0 0xf1000000 0x0 0x8000000>; + linux,cma-default; + }; + +- optee@0xf8e00000 { +- reg = <0x00000000 0xf8e00000 0 0x00200000>; ++ optee@0xf0e00000 { ++ reg = <0x0 0xf0e00000 0 0x00200000>; + no-map; + }; + }; +@@ -460,13 +460,6 @@ + >; + }; + +- smmu: smmu@2ce00000 { +- #iommu-cells = <1>; +- compatible = "arm,smmu-v3"; +- reg = <0x0 0x2ce00000 0x0 0x20000>; +- status = "okay"; +- }; +- + dp0: display@2cc00000 { + #address-cells = <1>; + #size-cells = <0>; +@@ -476,9 +469,6 @@ + interrupt-names = "DPU"; + clocks = <&scmi_clk 0>; + clock-names = "aclk"; +- iommus = <&smmu 0>, <&smmu 1>, <&smmu 2>, <&smmu 3>, +- <&smmu 4>, <&smmu 5>, <&smmu 6>, <&smmu 7>, +- <&smmu 8>, <&smmu 9>; + pl0: pipeline@0 { + reg = <0>; + clocks = <&scmi_clk 1>; +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/generate_metadata.py b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/generate_metadata.py similarity index 100% rename from meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/generate_metadata.py rename to meta-arm-bsp/recipes-bsp/trusted-firmware-a/files/tc/generate_metadata.py diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc.inc b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc.inc index a54ccbd6..25f67160 100644 --- a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc.inc +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc.inc @@ -1,14 +1,21 @@ # TC0 specific TFA configuration # Intermediate SHA with 2.6 baseline version -SRCREV_tfa = "b06344a3f2c5a0fede3646627f37d1fce3d3d585" +SRCREV_tfa = "141791088eb846c55291b1664813710ed3b532a1" PV = "2.6+git${SRCPV}" DEPENDS += "scp-firmware util-linux-native gptfdisk-native" +FILESEXTRAPATHS:prepend := "${THISDIR}/files/tc:" SRC_URI:append = " \ file://0001-plat-tc-Increase-maximum-BL2-size.patch \ - file://0002-Enable-CI-700-interconnect.patch \ + file://0002-feat-tc-enable-CI-700-PMU-for-profiling.patch \ + file://0003-Makefile-add-trusty_sp_fw_config-build-option.patch \ + file://0004-fix-plat-arm-increase-sp-max-image-size.patch \ + file://0005-fix-plat-tc-increase-tc_tzc_dram1_size.patch \ + file://0006-feat-plat-tc-add-spmc-manifest-with-trusty-sp.patch \ + file://0007-feat-plat-tc-update-dts-with-trusty-compatible-strin.patch \ + file://0008-fix-plat-tc-disable-smmu.patch \ file://generate_metadata.py \ " From patchwork Wed May 4 16:58:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7567 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id F2E75C4167D for ; Wed, 4 May 2022 16:58:36 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web10.615.1651683514283639690 for ; Wed, 04 May 2022 09:58:34 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 AA6151042; Wed, 4 May 2022 09:58:33 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id F27FE3FA27; Wed, 4 May 2022 09:58:32 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Ben Horgan Subject: [PATCH 06/10] arm-bsp/hafnium: TC: Support for trusty as a secure partition Date: Wed, 4 May 2022 17:58:16 +0100 Message-Id: <20220504165820.882784-6-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3362 From: Ben Horgan Signed-off-by: Ben Horgan Change-Id: I2bbb77aa2f220f013cff53efe557df9960d237e3 --- ...p-timer-register-accesses-using-cnth.patch | 252 ++++++++++++++ ..._INTERRUPT-to-signal-an-interrupted-.patch | 152 +++++++++ ..._SECONDARY_EP_REGISTER_64-to-list-of.patch | 28 ++ ...interrupt-controller-register-access.patch | 159 +++++++++ ...check-receiver-s-attributes-on-memor.patch | 318 ++++++++++++++++++ .../tc/0006-tc-increase-heap-pages.patch | 26 ++ .../recipes-bsp/hafnium/hafnium-tc.inc | 9 + 7 files changed, 944 insertions(+) create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-feat-emulate-cntp-timer-register-accesses-using-cnth.patch create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-fix-ff-a-Use-FFA_INTERRUPT-to-signal-an-interrupted-.patch create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0003-fix-ff-a-Add-FFA_SECONDARY_EP_REGISTER_64-to-list-of.patch create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0004-feat-emulate-interrupt-controller-register-access.patch create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0005-Revert-fix-ff-a-check-receiver-s-attributes-on-memor.patch create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc/0006-tc-increase-heap-pages.patch diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-feat-emulate-cntp-timer-register-accesses-using-cnth.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-feat-emulate-cntp-timer-register-accesses-using-cnth.patch new file mode 100644 index 00000000..7094c8bc --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0001-feat-emulate-cntp-timer-register-accesses-using-cnth.patch @@ -0,0 +1,252 @@ +From c8bd941579fb062359b683b184b851eea2ddb761 Mon Sep 17 00:00:00 2001 +From: Ben Horgan +Date: Fri, 4 Mar 2022 16:48:14 +0000 +Subject: [PATCH 1/5] feat: emulate cntp timer register accesses using cnthps + +Upstream-Status: Inappropriate [Experimental feature] +Signed-off-by: Ben Horgan +Change-Id: I67508203273baf3bd8e6be2d99717028db945715 +--- + Makefile | 3 +- + src/arch/aarch64/hypervisor/BUILD.gn | 1 + + src/arch/aarch64/hypervisor/cpu.c | 11 ++- + src/arch/aarch64/hypervisor/handler.c | 6 ++ + src/arch/aarch64/hypervisor/timer_el1.c | 104 ++++++++++++++++++++++++ + src/arch/aarch64/hypervisor/timer_el1.h | 20 +++++ + src/arch/aarch64/msr.h | 8 ++ + 7 files changed, 150 insertions(+), 3 deletions(-) + create mode 100644 src/arch/aarch64/hypervisor/timer_el1.c + create mode 100644 src/arch/aarch64/hypervisor/timer_el1.h + +diff --git a/Makefile b/Makefile +index c9fb16f..6371a8a 100644 +--- a/Makefile ++++ b/Makefile +@@ -59,7 +59,8 @@ CHECKPATCH := $(CURDIR)/third_party/linux/scripts/checkpatch.pl \ + # debug_el1.c : uses XMACROS, which checkpatch doesn't understand. + # perfmon.c : uses XMACROS, which checkpatch doesn't understand. + # feature_id.c : uses XMACROS, which checkpatch doesn't understand. +-CHECKPATCH_IGNORE := "src/arch/aarch64/hypervisor/debug_el1.c\|src/arch/aarch64/hypervisor/perfmon.c\|src/arch/aarch64/hypervisor/feature_id.c" ++# timer_el1.c : uses XMACROS, which checkpatch doesn't understand. ++CHECKPATCH_IGNORE := "src/arch/aarch64/hypervisor/debug_el1.c\|src/arch/aarch64/hypervisor/perfmon.c\|src/arch/aarch64/hypervisor/feature_id.c\|src/arch/aarch64/hypervisor/timer_el1.c" + + OUT ?= out/$(PROJECT) + OUT_DIR = out/$(PROJECT) +diff --git a/src/arch/aarch64/hypervisor/BUILD.gn b/src/arch/aarch64/hypervisor/BUILD.gn +index 6068d1e..de1a414 100644 +--- a/src/arch/aarch64/hypervisor/BUILD.gn ++++ b/src/arch/aarch64/hypervisor/BUILD.gn +@@ -45,6 +45,7 @@ source_set("hypervisor") { + "handler.c", + "perfmon.c", + "psci_handler.c", ++ "timer_el1.c", + "vm.c", + ] + +diff --git a/src/arch/aarch64/hypervisor/cpu.c b/src/arch/aarch64/hypervisor/cpu.c +index c6cebdd..cb41e6e 100644 +--- a/src/arch/aarch64/hypervisor/cpu.c ++++ b/src/arch/aarch64/hypervisor/cpu.c +@@ -91,13 +91,20 @@ void arch_regs_reset(struct vcpu *vcpu) + if (is_primary) { + /* + * cnthctl_el2 is redefined when VHE is enabled. +- * EL1PCTEN, don't trap phys cnt access. +- * EL1PCEN, don't trap phys timer access. ++ * EL1PCTEN, don't trap phys cnt access. Except when in ++ * secure world without vhe. ++ * EL1PCEN, don't trap phys timer access. Except when in ++ * secure world without vhe. + */ + if (has_vhe_support()) { + cnthctl |= (1U << 10) | (1U << 11); + } else { ++#if SECURE_WORLD == 1 ++ cnthctl &= ~(1U << 0); ++ cnthctl &= ~(1U << 1); ++#else + cnthctl |= (1U << 0) | (1U << 1); ++#endif + } + } + +diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c +index cd64d68..c9068c5 100644 +--- a/src/arch/aarch64/hypervisor/handler.c ++++ b/src/arch/aarch64/hypervisor/handler.c +@@ -34,6 +34,7 @@ + #include "psci_handler.h" + #include "smc.h" + #include "sysregs.h" ++#include "timer_el1.h" + + /** + * Hypervisor Fault Address Register Non-Secure. +@@ -1276,6 +1277,11 @@ void handle_system_register_access(uintreg_t esr_el2) + inject_el1_unknown_exception(vcpu, esr_el2); + return; + } ++ } else if (timer_el1_is_register_access(esr_el2)) { ++ if (!timer_el1_process_access(vcpu, vm_id, esr_el2)) { ++ inject_el1_unknown_exception(vcpu, esr_el2); ++ return; ++ } + } else { + inject_el1_unknown_exception(vcpu, esr_el2); + return; +diff --git a/src/arch/aarch64/hypervisor/timer_el1.c b/src/arch/aarch64/hypervisor/timer_el1.c +new file mode 100644 +index 0000000..c30e554 +--- /dev/null ++++ b/src/arch/aarch64/hypervisor/timer_el1.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright 2022 The Hafnium Authors. ++ * ++ * Use of this source code is governed by a BSD-style ++ * license that can be found in the LICENSE file or at ++ * https://opensource.org/licenses/BSD-3-Clause. ++ */ ++ ++#include "timer_el1.h" ++ ++#include "hf/dlog.h" ++ ++#include "msr.h" ++#include "sysregs.h" ++ ++/* ++ * Physical timer (CNTP) register encodings as defined in ++ * table D13-8 of the ARMv8 ARM (DDI0487F). ++ * TYPE, op0, op1, crn, crm, op2 ++ * The register names are the concatenation of ++ * "CNTP_", TYPE and "_EL2". ++ */ ++#define CNTP_REGISTERS \ ++ X(CTL, 3, 3, 14, 2, 1) \ ++ X(CVAL, 3, 3, 14, 2, 2) \ ++ X(TVAL, 3, 3, 14, 2, 0) \ ++ ++bool timer_el1_is_register_access(uintreg_t esr) ++{ ++ uintreg_t sys_register = GET_ISS_SYSREG(esr); ++ bool is_timer_access; ++ switch (sys_register) { ++#define X(type, op0, op1, crn, crm, op2) \ ++ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ ++ is_timer_access = true; \ ++ break; ++ CNTP_REGISTERS ++#undef X ++ case (GET_ISS_ENCODING(3, 3, 14, 0, 1)): ++ is_timer_access = true; ++ break; ++ default: ++ is_timer_access = false; ++ } ++ ++ return is_timer_access; ++} ++ ++/* Accesses to CNTP timer emulated with CNTHPS */ ++bool timer_el1_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id, ++ uintreg_t esr) ++{ ++ uintreg_t sys_register = GET_ISS_SYSREG(esr); ++ uintreg_t rt_register = GET_ISS_RT(esr); ++ uintreg_t value; ++ ++ if (ISS_IS_READ(esr)) { ++ switch (sys_register) { ++#define X(type, op0, op1, crn, crm, op2) \ ++ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ ++ value = read_msr(MSR_CNTHPS_##type##_EL2); \ ++ vcpu->regs.r[rt_register] = value; \ ++ break; ++ CNTP_REGISTERS ++#undef X ++ case (GET_ISS_ENCODING(3, 3, 14, 0, 1)): ++ value = read_msr(cntpct_el0); ++ vcpu->regs.r[rt_register] = value; ++ break; ++ default: ++ dlog_notice( ++ "Unsupported timer register " ++ "read: " ++ "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, " ++ "rt=%d.\n", ++ GET_ISS_OP0(esr), GET_ISS_OP1(esr), ++ GET_ISS_CRN(esr), GET_ISS_CRM(esr), ++ GET_ISS_OP2(esr), GET_ISS_RT(esr)); ++ break; ++ } ++ } else { ++ value = vcpu->regs.r[rt_register]; ++ switch (sys_register) { ++#define X(type, op0, op1, crn, crm, op2) \ ++ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ ++ write_msr(MSR_CNTHPS_##type##_EL2, value); \ ++ break; ++ CNTP_REGISTERS ++#undef X ++ default: ++ dlog_notice( ++ "Unsupported timer register " ++ "write: " ++ "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, " ++ "rt=%d, value=%d.\n", ++ GET_ISS_OP0(esr), GET_ISS_OP1(esr), ++ GET_ISS_CRN(esr), GET_ISS_CRM(esr), ++ GET_ISS_OP2(esr), GET_ISS_RT(esr), value); ++ break; ++ } ++ } ++ ++ return true; ++} +diff --git a/src/arch/aarch64/hypervisor/timer_el1.h b/src/arch/aarch64/hypervisor/timer_el1.h +new file mode 100644 +index 0000000..04a43b6 +--- /dev/null ++++ b/src/arch/aarch64/hypervisor/timer_el1.h +@@ -0,0 +1,20 @@ ++/* ++ * Copyright 2022 The Hafnium Authors. ++ * ++ * Use of this source code is governed by a BSD-style ++ * license that can be found in the LICENSE file or at ++ * https://opensource.org/licenses/BSD-3-Clause. ++ */ ++ ++#pragma once ++ ++#include "hf/arch/types.h" ++ ++#include "hf/cpu.h" ++ ++#include "vmapi/hf/ffa.h" ++ ++bool timer_el1_is_register_access(uintreg_t esr); ++ ++bool timer_el1_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id, ++ uintreg_t esr); +diff --git a/src/arch/aarch64/msr.h b/src/arch/aarch64/msr.h +index cd6778b..55e7833 100644 +--- a/src/arch/aarch64/msr.h ++++ b/src/arch/aarch64/msr.h +@@ -126,3 +126,11 @@ + #define MSR_ELR_EL12 S3_5_C4_C0_1 + + #endif ++ ++/* ++ * Secure EL2 Physical timer (CNTHPS) register encodings as defined in ++ * table D13-8 of the ARMv8 ARM (DDI0487F). ++ */ ++#define MSR_CNTHPS_CTL_EL2 S3_4_C14_C5_1 ++#define MSR_CNTHPS_CVAL_EL2 S3_4_C14_C5_2 ++#define MSR_CNTHPS_TVAL_EL2 S3_4_C14_C5_0 +-- +2.17.1 + diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-fix-ff-a-Use-FFA_INTERRUPT-to-signal-an-interrupted-.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-fix-ff-a-Use-FFA_INTERRUPT-to-signal-an-interrupted-.patch new file mode 100644 index 00000000..2b57b239 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-fix-ff-a-Use-FFA_INTERRUPT-to-signal-an-interrupted-.patch @@ -0,0 +1,152 @@ +From e6bcc390749f0560b3bc92507ecbaaabc7145200 Mon Sep 17 00:00:00 2001 +From: Lucian Paul-Trifu +Date: Wed, 10 Mar 2021 11:31:02 +0000 +Subject: [PATCH 2/5] fix(ff-a): Use FFA_INTERRUPT to signal an interrupted + FFA_MSG_WAIT + +Rather than FFA_ERROR(INTERRUPTED). + +Change-Id: I6b23a442714852b6183e0e46af6f0504ec0ee8f4 +Signed-off-by: Ben Horgan +Upstream-Status: Pending [Not submitted to upstream yet] +--- + src/api.c | 2 +- + test/inc/test/vmapi/ffa.h | 7 +++++++ + test/vmapi/arch/aarch64/gicv3/services/common.c | 3 +-- + test/vmapi/arch/aarch64/gicv3/services/timer.c | 2 +- + test/vmapi/el0_partitions/services/interruptible.c | 3 +-- + test/vmapi/el0_partitions/services/interruptible_echo.c | 3 +-- + test/vmapi/el0_partitions/services/receive_block.c | 2 +- + .../primary_with_secondaries/services/interruptible.c | 3 +-- + .../primary_with_secondaries/services/receive_block.c | 2 +- + 9 files changed, 15 insertions(+), 12 deletions(-) + +diff --git a/src/api.c b/src/api.c +index b713b7c..00c4d44 100644 +--- a/src/api.c ++++ b/src/api.c +@@ -1588,7 +1588,7 @@ struct ffa_value api_ffa_msg_recv(bool block, struct vcpu *current, + * received. If a message is received the return value will be set at + * that time to FFA_SUCCESS. + */ +- return_code = ffa_error(FFA_INTERRUPTED); ++ return_code = (struct ffa_value){.func = FFA_INTERRUPT_32}; + if (api_ffa_msg_recv_block_interrupted(current)) { + goto out; + } +diff --git a/test/inc/test/vmapi/ffa.h b/test/inc/test/vmapi/ffa.h +index 8fc1223..f0f3e75 100644 +--- a/test/inc/test/vmapi/ffa.h ++++ b/test/inc/test/vmapi/ffa.h +@@ -24,6 +24,13 @@ + EXPECT_EQ(ffa_error_code(v), (ffa_error)); \ + } while (0) + ++#define EXPECT_FFA_INTERRUPT(value) \ ++ do { \ ++ struct ffa_value v = (value); \ ++ EXPECT_EQ(v.func, FFA_INTERRUPT_32); \ ++ } while (0) ++ ++ + /* + * The bit 15 of the FF-A ID indicates whether the partition is executing + * in the normal world, in case it is a Virtual Machine (VM); or in the +diff --git a/test/vmapi/arch/aarch64/gicv3/services/common.c b/test/vmapi/arch/aarch64/gicv3/services/common.c +index 06df28d..4ada9e2 100644 +--- a/test/vmapi/arch/aarch64/gicv3/services/common.c ++++ b/test/vmapi/arch/aarch64/gicv3/services/common.c +@@ -22,8 +22,7 @@ struct ffa_value mailbox_receive_retry(void) + + do { + received = ffa_msg_wait(); +- } while (received.func == FFA_ERROR_32 && +- received.arg2 == FFA_INTERRUPTED); ++ } while (received.func == FFA_INTERRUPT_32); + + return received; + } +diff --git a/test/vmapi/arch/aarch64/gicv3/services/timer.c b/test/vmapi/arch/aarch64/gicv3/services/timer.c +index 156f160..d5d2816 100644 +--- a/test/vmapi/arch/aarch64/gicv3/services/timer.c ++++ b/test/vmapi/arch/aarch64/gicv3/services/timer.c +@@ -104,7 +104,7 @@ TEST_SERVICE(timer) + } else if (receive) { + struct ffa_value res = ffa_msg_wait(); + +- EXPECT_FFA_ERROR(res, FFA_INTERRUPTED); ++ EXPECT_FFA_INTERRUPT(res); + } else { + /* Busy wait until the timer fires. */ + while (!timer_fired) { +diff --git a/test/vmapi/el0_partitions/services/interruptible.c b/test/vmapi/el0_partitions/services/interruptible.c +index 0d00b16..4c9f099 100644 +--- a/test/vmapi/el0_partitions/services/interruptible.c ++++ b/test/vmapi/el0_partitions/services/interruptible.c +@@ -50,8 +50,7 @@ static struct ffa_value mailbox_receive_retry() + do { + irq(); + received = ffa_msg_wait(); +- } while (received.func == FFA_ERROR_32 && +- ffa_error_code(received) == FFA_INTERRUPTED); ++ } while (received.func == FFA_INTERRUPT_32); + + return received; + } +diff --git a/test/vmapi/el0_partitions/services/interruptible_echo.c b/test/vmapi/el0_partitions/services/interruptible_echo.c +index b618cf2..a857783 100644 +--- a/test/vmapi/el0_partitions/services/interruptible_echo.c ++++ b/test/vmapi/el0_partitions/services/interruptible_echo.c +@@ -39,8 +39,7 @@ static struct ffa_value mailbox_receive_retry() + do { + irq(); + received = ffa_msg_wait(); +- } while (received.func == FFA_ERROR_32 && +- received.arg2 == FFA_INTERRUPTED); ++ } while (received.func == FFA_INTERRUPT_32); + + return received; + } +diff --git a/test/vmapi/el0_partitions/services/receive_block.c b/test/vmapi/el0_partitions/services/receive_block.c +index 05a22f3..60da28b 100644 +--- a/test/vmapi/el0_partitions/services/receive_block.c ++++ b/test/vmapi/el0_partitions/services/receive_block.c +@@ -27,7 +27,7 @@ TEST_SERVICE(receive_block) + + for (i = 0; i < 10; ++i) { + struct ffa_value res = ffa_msg_wait(); +- EXPECT_FFA_ERROR(res, FFA_INTERRUPTED); ++ EXPECT_FFA_INTERRUPT(res); + } + + memcpy_s(SERVICE_SEND_BUFFER(), FFA_MSG_PAYLOAD_MAX, message, +diff --git a/test/vmapi/primary_with_secondaries/services/interruptible.c b/test/vmapi/primary_with_secondaries/services/interruptible.c +index cc1c1f9..005d1ff 100644 +--- a/test/vmapi/primary_with_secondaries/services/interruptible.c ++++ b/test/vmapi/primary_with_secondaries/services/interruptible.c +@@ -46,8 +46,7 @@ struct ffa_value mailbox_receive_retry() + + do { + received = ffa_msg_wait(); +- } while (received.func == FFA_ERROR_32 && +- ffa_error_code(received) == FFA_INTERRUPTED); ++ } while (received.func == FFA_INTERRUPT_32); + + return received; + } +diff --git a/test/vmapi/primary_with_secondaries/services/receive_block.c b/test/vmapi/primary_with_secondaries/services/receive_block.c +index edb4e3c..a6805ae 100644 +--- a/test/vmapi/primary_with_secondaries/services/receive_block.c ++++ b/test/vmapi/primary_with_secondaries/services/receive_block.c +@@ -40,7 +40,7 @@ TEST_SERVICE(receive_block) + + for (i = 0; i < 10; ++i) { + struct ffa_value res = ffa_msg_wait(); +- EXPECT_FFA_ERROR(res, FFA_INTERRUPTED); ++ EXPECT_FFA_INTERRUPT(res); + } + + memcpy_s(SERVICE_SEND_BUFFER(), FFA_MSG_PAYLOAD_MAX, message, +-- +2.17.1 + diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0003-fix-ff-a-Add-FFA_SECONDARY_EP_REGISTER_64-to-list-of.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0003-fix-ff-a-Add-FFA_SECONDARY_EP_REGISTER_64-to-list-of.patch new file mode 100644 index 00000000..8d2cc139 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0003-fix-ff-a-Add-FFA_SECONDARY_EP_REGISTER_64-to-list-of.patch @@ -0,0 +1,28 @@ +From a6f466c2594b2f56d34fee72494fbd29ea9c7d21 Mon Sep 17 00:00:00 2001 +From: Ben Horgan +Date: Tue, 26 Apr 2022 12:59:42 +0000 +Subject: [PATCH 3/5] fix(ff-a): Add FFA_SECONDARY_EP_REGISTER_64 to list of + features + +Signed-off-by: Ben Horgan +Change-Id: Ic1344eb2c982c195210dc2c86aa6845f3e037077 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + src/api.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/api.c b/src/api.c +index 00c4d44..33a9b42 100644 +--- a/src/api.c ++++ b/src/api.c +@@ -2021,6 +2021,7 @@ struct ffa_value api_ffa_features(uint32_t feature_function_id) + case FFA_MEM_PERM_SET_32: + case FFA_MEM_PERM_GET_64: + case FFA_MEM_PERM_SET_64: ++ case FFA_SECONDARY_EP_REGISTER_64: + #endif + return (struct ffa_value){.func = FFA_SUCCESS_32}; + +-- +2.17.1 + diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0004-feat-emulate-interrupt-controller-register-access.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0004-feat-emulate-interrupt-controller-register-access.patch new file mode 100644 index 00000000..95f1651a --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0004-feat-emulate-interrupt-controller-register-access.patch @@ -0,0 +1,159 @@ +From 380f2cf944dd5db36c168a11d31a46ad14cdcb6d Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Tue, 26 Apr 2022 14:43:58 +0100 +Subject: [PATCH 4/5] feat: emulate interrupt controller register access + +This emulates ICC_SGI1R_EL1 and ICC_IGRPEN1_EL1 register + +Signed-off-by: Arunachalam Ganapathy +Change-Id: I0c11f034f3676067597461a183a341c809adcaa4 +Upstream-Status: Inappropriate [Experimental feature] +--- + src/arch/aarch64/hypervisor/handler.c | 5 ++ + src/arch/aarch64/hypervisor/perfmon.c | 84 +++++++++++++++++++++++++++ + src/arch/aarch64/hypervisor/perfmon.h | 5 ++ + src/arch/aarch64/msr.h | 3 + + 4 files changed, 97 insertions(+) + +diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c +index c9068c5..b9aa5d8 100644 +--- a/src/arch/aarch64/hypervisor/handler.c ++++ b/src/arch/aarch64/hypervisor/handler.c +@@ -1282,6 +1282,11 @@ void handle_system_register_access(uintreg_t esr_el2) + inject_el1_unknown_exception(vcpu, esr_el2); + return; + } ++ } else if (intr_ctrl_is_register_access(esr_el2)) { ++ if (!intr_ctrl_el1_process_access(vcpu, vm_id, esr_el2)) { ++ inject_el1_unknown_exception(vcpu, esr_el2); ++ return; ++ } + } else { + inject_el1_unknown_exception(vcpu, esr_el2); + return; +diff --git a/src/arch/aarch64/hypervisor/perfmon.c b/src/arch/aarch64/hypervisor/perfmon.c +index f13b035..05e216c 100644 +--- a/src/arch/aarch64/hypervisor/perfmon.c ++++ b/src/arch/aarch64/hypervisor/perfmon.c +@@ -116,6 +116,10 @@ + X(PMEVTYPER30_EL0 , 3, 3, 14, 15, 6) \ + X(PMCCFILTR_EL0 , 3, 3, 14, 15, 7) + ++#define INTR_CTRL_REGISTERS \ ++ X(ICC_IGRPEN1_EL1 , 3, 0, 12, 12, 7) \ ++ X(ICC_SGI1R_EL1 , 3, 0, 12, 11, 5) \ ++ + /* clang-format on */ + + /** +@@ -232,3 +236,83 @@ uintreg_t perfmon_get_pmccfiltr_el0_init_value(ffa_vm_id_t vm_id) + + return 0; + } ++ ++bool intr_ctrl_is_register_access(uintreg_t esr) ++{ ++ uintreg_t op0 = GET_ISS_OP0(esr); ++ uintreg_t op1 = GET_ISS_OP1(esr); ++ uintreg_t crn = GET_ISS_CRN(esr); ++ uintreg_t crm = GET_ISS_CRM(esr); ++ ++ if (op0 == 3 && op1 == 0 && crn == 12 && crm == 12) { ++ return true; ++ } ++ ++ if (op0 == 3 && op1 == 0 && crn == 12 && crm == 11) { ++ return true; ++ } ++ ++ return false; ++} ++ ++bool intr_ctrl_el1_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id, ++ uintreg_t esr) ++{ ++ uintreg_t sys_register = GET_ISS_SYSREG(esr); ++ uintreg_t rt_register = GET_ISS_RT(esr); ++ uintreg_t value; ++ ++ /* +1 because Rt can access register XZR */ ++ CHECK(rt_register < NUM_GP_REGS + 1); ++ ++ if (ISS_IS_READ(esr)) { ++ switch (sys_register) { ++#define X(reg_name, op0, op1, crn, crm, op2) \ ++ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ ++ value = read_msr(reg_name); \ ++ break; ++ INTR_CTRL_REGISTERS ++#undef X ++ default: ++ value = vcpu->regs.r[rt_register]; ++ dlog_notice( ++ "Unsupported interrupt control register " ++ "read: " ++ "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, " ++ "rt=%d.\n", ++ GET_ISS_OP0(esr), GET_ISS_OP1(esr), ++ GET_ISS_CRN(esr), GET_ISS_CRM(esr), ++ GET_ISS_OP2(esr), GET_ISS_RT(esr)); ++ break; ++ } ++ if (rt_register != RT_REG_XZR) { ++ vcpu->regs.r[rt_register] = value; ++ } ++ } else { ++ if (rt_register != RT_REG_XZR) { ++ value = vcpu->regs.r[rt_register]; ++ } else { ++ value = 0; ++ } ++ switch (sys_register) { ++#define X(reg_name, op0, op1, crn, crm, op2) \ ++ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ ++ write_msr(reg_name, value); \ ++ break; ++ INTR_CTRL_REGISTERS ++#undef X ++ default: ++ dlog_notice( ++ "Unsupported interrupt control register " ++ "write: " ++ "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, " ++ "rt=%d.\n", ++ GET_ISS_OP0(esr), GET_ISS_OP1(esr), ++ GET_ISS_CRN(esr), GET_ISS_CRM(esr), ++ GET_ISS_OP2(esr), GET_ISS_RT(esr)); ++ break; ++ } ++ } ++ ++ return true; ++} +diff --git a/src/arch/aarch64/hypervisor/perfmon.h b/src/arch/aarch64/hypervisor/perfmon.h +index 81669ba..c90d45b 100644 +--- a/src/arch/aarch64/hypervisor/perfmon.h ++++ b/src/arch/aarch64/hypervisor/perfmon.h +@@ -70,3 +70,8 @@ bool perfmon_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id, + uintreg_t esr_el2); + + uintreg_t perfmon_get_pmccfiltr_el0_init_value(ffa_vm_id_t vm_id); ++ ++bool intr_ctrl_is_register_access(uintreg_t esr); ++ ++bool intr_ctrl_el1_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id, ++ uintreg_t esr); +diff --git a/src/arch/aarch64/msr.h b/src/arch/aarch64/msr.h +index 55e7833..82aa884 100644 +--- a/src/arch/aarch64/msr.h ++++ b/src/arch/aarch64/msr.h +@@ -134,3 +134,6 @@ + #define MSR_CNTHPS_CTL_EL2 S3_4_C14_C5_1 + #define MSR_CNTHPS_CVAL_EL2 S3_4_C14_C5_2 + #define MSR_CNTHPS_TVAL_EL2 S3_4_C14_C5_0 ++ ++#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7 ++#define ICC_SGI1R_EL1 S3_0_C12_C11_5 +-- +2.17.1 + diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0005-Revert-fix-ff-a-check-receiver-s-attributes-on-memor.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0005-Revert-fix-ff-a-check-receiver-s-attributes-on-memor.patch new file mode 100644 index 00000000..e5f9489e --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0005-Revert-fix-ff-a-check-receiver-s-attributes-on-memor.patch @@ -0,0 +1,318 @@ +From 64d5628c8439e4649e9c1da9b9e02ebd5c7fb8cf Mon Sep 17 00:00:00 2001 +From: Ben Horgan +Date: Thu, 28 Apr 2022 15:53:31 +0000 +Subject: [PATCH 5/5] Revert "fix(ff-a): check receiver's attributes on memory + retrieve" + +This reverts commit a98603aa965e3ff3ca5383249213e2fd1a96d850. + +Change-Id: Ia71ce3ac52e9b2e85578372c24eb8d593b62435f +Signed-off-by: Ben Horgan +--- + src/ffa_memory.c | 76 ++++++----------- + test/vmapi/el0_partitions/memory_sharing.c | 81 ------------------- + .../primary_with_secondaries/memory_sharing.c | 81 ------------------- + 3 files changed, 25 insertions(+), 213 deletions(-) + +diff --git a/src/ffa_memory.c b/src/ffa_memory.c +index ab47929..2fcc386 100644 +--- a/src/ffa_memory.c ++++ b/src/ffa_memory.c +@@ -1344,42 +1344,6 @@ static struct ffa_value ffa_memory_send_complete( + return ffa_mem_success(share_state->memory_region->handle); + } + +-/** +- * Check that the memory attributes match Hafnium expectations: +- * Normal Memory, Inner shareable, Write-Back Read-Allocate +- * Write-Allocate Cacheable. +- */ +-static struct ffa_value ffa_memory_attributes_validate( +- ffa_memory_access_permissions_t attributes) +-{ +- enum ffa_memory_type memory_type; +- enum ffa_memory_cacheability cacheability; +- enum ffa_memory_shareability shareability; +- +- memory_type = ffa_get_memory_type_attr(attributes); +- if (memory_type != FFA_MEMORY_NORMAL_MEM) { +- dlog_verbose("Invalid memory type %#x, expected %#x.\n", +- memory_type, FFA_MEMORY_NORMAL_MEM); +- return ffa_error(FFA_DENIED); +- } +- +- cacheability = ffa_get_memory_cacheability_attr(attributes); +- if (cacheability != FFA_MEMORY_CACHE_WRITE_BACK) { +- dlog_verbose("Invalid cacheability %#x, expected %#x.\n", +- cacheability, FFA_MEMORY_CACHE_WRITE_BACK); +- return ffa_error(FFA_DENIED); +- } +- +- shareability = ffa_get_memory_shareability_attr(attributes); +- if (shareability != FFA_MEMORY_INNER_SHAREABLE) { +- dlog_verbose("Invalid shareability %#x, expected #%x.\n", +- shareability, FFA_MEMORY_INNER_SHAREABLE); +- return ffa_error(FFA_DENIED); +- } +- +- return (struct ffa_value){.func = FFA_SUCCESS_32}; +-} +- + /** + * Check that the given `memory_region` represents a valid memory send request + * of the given `share_func` type, return the clear flag and permissions via the +@@ -1400,7 +1364,10 @@ static struct ffa_value ffa_memory_send_validate( + uint32_t constituents_length; + enum ffa_data_access data_access; + enum ffa_instruction_access instruction_access; +- struct ffa_value ret; ++ ffa_memory_access_permissions_t attributes; ++ enum ffa_memory_type memory_type; ++ enum ffa_memory_cacheability memory_cacheability; ++ enum ffa_memory_shareability memory_shareability; + + assert(permissions != NULL); + +@@ -1536,9 +1503,26 @@ static struct ffa_value ffa_memory_send_validate( + * Normal Memory, Inner shareable, Write-Back Read-Allocate + * Write-Allocate Cacheable. + */ +- ret = ffa_memory_attributes_validate(memory_region->attributes); +- if (ret.func != FFA_SUCCESS_32) { +- return ret; ++ attributes = memory_region->attributes; ++ memory_type = ffa_get_memory_type_attr(attributes); ++ if (memory_type != FFA_MEMORY_NORMAL_MEM) { ++ dlog_verbose("Invalid memory type %#x, expected %#x.\n", ++ memory_type, FFA_MEMORY_NORMAL_MEM); ++ return ffa_error(FFA_INVALID_PARAMETERS); ++ } ++ ++ memory_cacheability = ffa_get_memory_cacheability_attr(attributes); ++ if (memory_cacheability != FFA_MEMORY_CACHE_WRITE_BACK) { ++ dlog_verbose("Invalid cacheability %#x, expected %#x.\n", ++ memory_cacheability, FFA_MEMORY_CACHE_WRITE_BACK); ++ return ffa_error(FFA_INVALID_PARAMETERS); ++ } ++ ++ memory_shareability = ffa_get_memory_shareability_attr(attributes); ++ if (memory_shareability != FFA_MEMORY_INNER_SHAREABLE) { ++ dlog_verbose("Invalid shareability %#x, expected %#x.\n", ++ memory_shareability, FFA_MEMORY_INNER_SHAREABLE); ++ return ffa_error(FFA_INVALID_PARAMETERS); + } + + return (struct ffa_value){.func = FFA_SUCCESS_32}; +@@ -2376,6 +2360,7 @@ struct ffa_value ffa_memory_retrieve(struct vm_locked to_locked, + * Check permissions from sender against permissions requested by + * receiver. + */ ++ /* TODO: Check attributes too. */ + sent_permissions = + memory_region->receivers[0].receiver_permissions.permissions; + sent_data_access = ffa_get_data_access_attr(sent_permissions); +@@ -2453,17 +2438,6 @@ struct ffa_value ffa_memory_retrieve(struct vm_locked to_locked, + panic("Got unexpected FFA_INSTRUCTION_ACCESS_RESERVED. Should " + "be checked before this point."); + } +- +- /* +- * Ensure receiver's attributes are compatible with how Hafnium maps +- * memory: Normal Memory, Inner shareable, Write-Back Read-Allocate +- * Write-Allocate Cacheable. +- */ +- ret = ffa_memory_attributes_validate(retrieve_request->attributes); +- if (ret.func != FFA_SUCCESS_32) { +- goto out; +- } +- + memory_to_attributes = ffa_memory_permissions_to_mode( + permissions, share_state->sender_orig_mode); + ret = ffa_retrieve_check_update( +diff --git a/test/vmapi/el0_partitions/memory_sharing.c b/test/vmapi/el0_partitions/memory_sharing.c +index 3756d7d..c29f029 100644 +--- a/test/vmapi/el0_partitions/memory_sharing.c ++++ b/test/vmapi/el0_partitions/memory_sharing.c +@@ -2160,87 +2160,6 @@ TEST(memory_sharing, ffa_validate_retrieve_req_mbz) + } + } + +-/** +- * Memory can't be shared with arbitrary attributes because Hafnium maps pages +- * with hardcoded values and doesn't support custom mappings. +- */ +-TEST(memory_sharing, ffa_validate_retrieve_req_attributes) +-{ +- struct ffa_value ret; +- struct mailbox_buffers mb = set_up_mailbox(); +- uint32_t msg_size; +- ffa_memory_handle_t handle; +- +- struct ffa_value (*send_function[])(uint32_t, uint32_t) = { +- ffa_mem_share, +- ffa_mem_lend, +- }; +- +- struct ffa_memory_region_constituent constituents[] = { +- {.address = (uint64_t)pages, .page_count = 2}, +- {.address = (uint64_t)pages + PAGE_SIZE * 3, .page_count = 1}, +- }; +- +- SERVICE_SELECT(SERVICE_VM1, "ffa_memory_share_fail", mb.send); +- +- struct { +- enum ffa_memory_type memory_type; +- enum ffa_memory_cacheability memory_cacheability; +- enum ffa_memory_shareability memory_shareability; +- } invalid_attributes[] = { +- /* Invalid memory type */ +- {FFA_MEMORY_DEVICE_MEM, FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_INNER_SHAREABLE}, +- /* Invalid cacheability */ +- {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_NON_CACHEABLE, +- FFA_MEMORY_INNER_SHAREABLE}, +- /* Invalid shareability */ +- {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_SHARE_NON_SHAREABLE}, +- {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_OUTER_SHAREABLE}}; +- +- for (uint32_t i = 0; i < ARRAY_SIZE(send_function); i++) { +- /* Prepare memory region, and set all flags */ +- EXPECT_EQ(ffa_memory_region_init( +- mb.send, HF_MAILBOX_SIZE, HF_PRIMARY_VM_ID, +- SERVICE_VM1, constituents, +- ARRAY_SIZE(constituents), 0, 0, +- FFA_DATA_ACCESS_RW, +- FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED, +- FFA_MEMORY_NORMAL_MEM, +- FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_INNER_SHAREABLE, NULL, &msg_size), +- 0); +- +- ret = send_function[i](msg_size, msg_size); +- EXPECT_EQ(ret.func, FFA_SUCCESS_32); +- +- handle = ffa_mem_success_handle(ret); +- +- for (uint32_t j = 0; j < ARRAY_SIZE(invalid_attributes); ++j) { +- msg_size = ffa_memory_retrieve_request_init( +- mb.send, handle, HF_PRIMARY_VM_ID, SERVICE_VM1, +- 0, 0, FFA_DATA_ACCESS_RW, +- FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED, +- invalid_attributes[j].memory_type, +- invalid_attributes[j].memory_cacheability, +- invalid_attributes[j].memory_shareability); +- +- EXPECT_LE(msg_size, HF_MAILBOX_SIZE); +- +- EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, +- msg_size, 0) +- .func, +- FFA_SUCCESS_32); +- +- ffa_run(SERVICE_VM1, 0); +- } +- +- EXPECT_EQ(ffa_mem_reclaim(handle, 0).func, FFA_SUCCESS_32); +- } +-} +- + /** + * If memory is shared can't request zeroing of memory at both send and + * relinquish. +diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c +index 6080709..4bcf252 100644 +--- a/test/vmapi/primary_with_secondaries/memory_sharing.c ++++ b/test/vmapi/primary_with_secondaries/memory_sharing.c +@@ -2307,87 +2307,6 @@ TEST(memory_sharing, ffa_validate_retrieve_req_mbz) + } + } + +-/** +- * Memory can't be shared with arbitrary attributes because Hafnium maps pages +- * with hardcoded values and doesn't support custom mappings. +- */ +-TEST(memory_sharing, ffa_validate_retrieve_req_attributes) +-{ +- struct ffa_value ret; +- struct mailbox_buffers mb = set_up_mailbox(); +- uint32_t msg_size; +- ffa_memory_handle_t handle; +- +- struct ffa_value (*send_function[])(uint32_t, uint32_t) = { +- ffa_mem_share, +- ffa_mem_lend, +- }; +- +- struct ffa_memory_region_constituent constituents[] = { +- {.address = (uint64_t)pages, .page_count = 2}, +- {.address = (uint64_t)pages + PAGE_SIZE * 3, .page_count = 1}, +- }; +- +- SERVICE_SELECT(SERVICE_VM1, "ffa_memory_share_fail_denied", mb.send); +- +- struct { +- enum ffa_memory_type memory_type; +- enum ffa_memory_cacheability memory_cacheability; +- enum ffa_memory_shareability memory_shareability; +- } invalid_attributes[] = { +- /* Invalid memory type */ +- {FFA_MEMORY_DEVICE_MEM, FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_INNER_SHAREABLE}, +- /* Invalid cacheability */ +- {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_NON_CACHEABLE, +- FFA_MEMORY_INNER_SHAREABLE}, +- /* Invalid shareability */ +- {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_SHARE_NON_SHAREABLE}, +- {FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_OUTER_SHAREABLE}}; +- +- for (uint32_t i = 0; i < ARRAY_SIZE(send_function); i++) { +- /* Prepare memory region, and set all flags */ +- EXPECT_EQ(ffa_memory_region_init( +- mb.send, HF_MAILBOX_SIZE, HF_PRIMARY_VM_ID, +- SERVICE_VM1, constituents, +- ARRAY_SIZE(constituents), 0, 0, +- FFA_DATA_ACCESS_RW, +- FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED, +- FFA_MEMORY_NORMAL_MEM, +- FFA_MEMORY_CACHE_WRITE_BACK, +- FFA_MEMORY_INNER_SHAREABLE, NULL, &msg_size), +- 0); +- +- ret = send_function[i](msg_size, msg_size); +- EXPECT_EQ(ret.func, FFA_SUCCESS_32); +- +- handle = ffa_mem_success_handle(ret); +- +- for (uint32_t j = 0; j < ARRAY_SIZE(invalid_attributes); ++j) { +- msg_size = ffa_memory_retrieve_request_init( +- mb.send, handle, HF_PRIMARY_VM_ID, SERVICE_VM1, +- 0, 0, FFA_DATA_ACCESS_RW, +- FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED, +- invalid_attributes[j].memory_type, +- invalid_attributes[j].memory_cacheability, +- invalid_attributes[j].memory_shareability); +- +- EXPECT_LE(msg_size, HF_MAILBOX_SIZE); +- +- EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, +- msg_size, 0) +- .func, +- FFA_SUCCESS_32); +- +- ffa_run(SERVICE_VM1, 0); +- } +- +- EXPECT_EQ(ffa_mem_reclaim(handle, 0).func, FFA_SUCCESS_32); +- } +-} +- + /** + * If memory is shared can't request zeroing of memory at both send and + * relinquish. +-- +2.17.1 + diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0006-tc-increase-heap-pages.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0006-tc-increase-heap-pages.patch new file mode 100644 index 00000000..671f6a5c --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0006-tc-increase-heap-pages.patch @@ -0,0 +1,26 @@ +From e918cc5179241e1d35ba4b465b035b74b88e55d2 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 29 Apr 2022 20:07:50 +0100 +Subject: [PATCH] tc: increase heap pages + +Signed-off-by: Arunachalam Ganapathy +--- + project/reference/BUILD.gn | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/project/reference/BUILD.gn b/project/reference/BUILD.gn +index 5d84d13..4ea0890 100644 +--- a/project/reference/BUILD.gn ++++ b/project/reference/BUILD.gn +@@ -233,7 +233,7 @@ aarch64_toolchains("secure_tc") { + gicd_base_address = "0x30000000" + gicr_base_address = "0x30080000" + gicr_frames = 8 +- heap_pages = 60 ++ heap_pages = 120 + max_cpus = 8 + max_vms = 16 + branch_protection = "standard" +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc b/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc index 14330856..c8f77dc6 100644 --- a/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc +++ b/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc.inc @@ -10,6 +10,15 @@ SRC_URI:remove = " \ file://host-ld.patch \ file://native-dtc.patch" +SRC_URI:append = " \ + file://0001-feat-emulate-cntp-timer-register-accesses-using-cnth.patch \ + file://0002-fix-ff-a-Use-FFA_INTERRUPT-to-signal-an-interrupted-.patch \ + file://0003-fix-ff-a-Add-FFA_SECONDARY_EP_REGISTER_64-to-list-of.patch \ + file://0004-feat-emulate-interrupt-controller-register-access.patch \ + file://0005-Revert-fix-ff-a-check-receiver-s-attributes-on-memor.patch \ + file://0006-tc-increase-heap-pages.patch \ + " + do_compile() { PATH="${S}/prebuilts/linux-x64/clang/bin:$PATH" oe_runmake -C ${S} } From patchwork Wed May 4 16:58:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7568 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0BBDCC4167B for ; Wed, 4 May 2022 16:58:37 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.620.1651683514994189842 for ; Wed, 04 May 2022 09:58:35 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 989E011FB; Wed, 4 May 2022 09:58:34 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DCAAC3FA27; Wed, 4 May 2022 09:58:33 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 07/10] arm-bsp/linux: TC: Update backport patches of FFA driver Date: Wed, 4 May 2022 17:58:17 +0100 Message-Id: <20220504165820.882784-7-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:36 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3363 This updates the existing FFA driver to the latest upstream version. Signed-off-by: Arunachalam Ganapathy Change-Id: Idabf2d97cd497edc6c41e7132e1e82be8e717c59 --- .../linux/linux-arm-platforms.inc | 52 +- ...support-for-SMCCCv1.2-extended-input.patch | 188 -- ...e-arm_ffa-Backport-of-arm_ffa-driver.patch | 1684 +++++++++++++++++ ...-Add-initial-FFA-bus-support-for-dev.patch | 420 ---- ...-add-sec_world_id-to-struct-tee_shm.patch} | 0 ...a-Add-initial-Arm-FFA-driver-support.patch | 415 ---- ...> 0010-optee-simplify-optee_release.patch} | 0 ...-Add-support-for-SMCCC-as-transport-.patch | 115 -- ...h => 0011-optee-sync-OP-TEE-headers.patch} | 0 ...-Setup-in-kernel-users-of-FFA-partit.patch | 398 ---- ...ctor-driver-with-internal-callbacks.patch} | 0 ..._ffa-Add-support-for-MEM_-interfaces.patch | 406 ---- ...> 0013-optee-add-a-FF-A-memory-pool.patch} | 0 ...atch => 0014-optee-add-FF-A-support.patch} | 0 ...esight-etm4x-Save-restore-TRFCR_EL1.patch} | 0 ...se-Trace-Filtering-controls-dynamic.patch} | 0 ...7-perf-arm-cmn-Use-irq_set_affinity.patch} | 0 ...-cmn-Fix-CPU-hotplug-unregistration.patch} | 0 ...f-arm-cmn-Account-for-NUMA-affinity.patch} | 0 ...m-cmn-Drop-compile-test-restriction.patch} | 0 ...021-arm_ffa-add-support-for-FFA-v1.1.patch | 37 - ...f-arm-cmn-Refactor-node-ID-handling.patch} | 0 ...f-arm-cmn-Streamline-node-iteration.patch} | 0 ...rivers-perf-arm-cmn-Add-space-after.patch} | 0 ...-perf-arm-cmn-Refactor-DTM-handling.patch} | 0 ...-arm-cmn-Optimise-DTM-counter-reads.patch} | 0 ...m-cmn-Optimise-DTC-counter-accesses.patch} | 0 ...ove-group-validation-data-off-stack.patch} | 0 ...arm-cmn-Demarcate-CMN-600-specifics.patch} | 0 ...erf-arm-cmn-Support-new-IP-features.patch} | 0 ...030-perf-arm-cmn-Add-CI-700-Support.patch} | 0 31 files changed, 1707 insertions(+), 2008 deletions(-) delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-arm64-smccc-Add-support-for-SMCCCv1.2-extended-input.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-firmware-arm_ffa-Backport-of-arm_ffa-driver.patch delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0009-firmware-arm_ffa-Add-initial-FFA-bus-support-for-dev.patch rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0014-tee-add-sec_world_id-to-struct-tee_shm.patch => 0009-tee-add-sec_world_id-to-struct-tee_shm.patch} (100%) delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0010-firmware-arm_ffa-Add-initial-Arm-FFA-driver-support.patch rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0015-optee-simplify-optee_release.patch => 0010-optee-simplify-optee_release.patch} (100%) delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0011-firmware-arm_ffa-Add-support-for-SMCCC-as-transport-.patch rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0016-optee-sync-OP-TEE-headers.patch => 0011-optee-sync-OP-TEE-headers.patch} (100%) delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0012-firmware-arm_ffa-Setup-in-kernel-users-of-FFA-partit.patch rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0017-optee-refactor-driver-with-internal-callbacks.patch => 0012-optee-refactor-driver-with-internal-callbacks.patch} (100%) delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0013-firmware-arm_ffa-Add-support-for-MEM_-interfaces.patch rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0018-optee-add-a-FF-A-memory-pool.patch => 0013-optee-add-a-FF-A-memory-pool.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0019-optee-add-FF-A-support.patch => 0014-optee-add-FF-A-support.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0022-coresight-etm4x-Save-restore-TRFCR_EL1.patch => 0015-coresight-etm4x-Save-restore-TRFCR_EL1.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0023-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch => 0016-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0024-perf-arm-cmn-Use-irq_set_affinity.patch => 0017-perf-arm-cmn-Use-irq_set_affinity.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0025-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch => 0018-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0026-perf-arm-cmn-Account-for-NUMA-affinity.patch => 0019-perf-arm-cmn-Account-for-NUMA-affinity.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0027-perf-arm-cmn-Drop-compile-test-restriction.patch => 0020-perf-arm-cmn-Drop-compile-test-restriction.patch} (100%) delete mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0021-arm_ffa-add-support-for-FFA-v1.1.patch rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0028-perf-arm-cmn-Refactor-node-ID-handling.patch => 0021-perf-arm-cmn-Refactor-node-ID-handling.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0029-perf-arm-cmn-Streamline-node-iteration.patch => 0022-perf-arm-cmn-Streamline-node-iteration.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0030-drivers-perf-arm-cmn-Add-space-after.patch => 0023-drivers-perf-arm-cmn-Add-space-after.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0031-perf-arm-cmn-Refactor-DTM-handling.patch => 0024-perf-arm-cmn-Refactor-DTM-handling.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0032-perf-arm-cmn-Optimise-DTM-counter-reads.patch => 0025-perf-arm-cmn-Optimise-DTM-counter-reads.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0033-perf-arm-cmn-Optimise-DTC-counter-accesses.patch => 0026-perf-arm-cmn-Optimise-DTC-counter-accesses.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0034-perf-arm-cmn-Move-group-validation-data-off-stack.patch => 0027-perf-arm-cmn-Move-group-validation-data-off-stack.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0035-perf-arm-cmn-Demarcate-CMN-600-specifics.patch => 0028-perf-arm-cmn-Demarcate-CMN-600-specifics.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0036-perf-arm-cmn-Support-new-IP-features.patch => 0029-perf-arm-cmn-Support-new-IP-features.patch} (100%) rename meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/{0037-perf-arm-cmn-Add-CI-700-Support.patch => 0030-perf-arm-cmn-Add-CI-700-Support.patch} (100%) diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc index fc7df03a..ce2c7f93 100644 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc @@ -143,35 +143,29 @@ SRC_URI:append:tc = " \ file://0005-mailbox-arm_mhuv2-Fix-sparse-warnings.patch \ file://0006-mailbox-arm_mhuv2-make-remove-callback-return-void.patch \ file://0007-mailbox-arm_mhuv2-Skip-calling-kfree-with-invalid-po.patch \ - file://0008-arm64-smccc-Add-support-for-SMCCCv1.2-extended-input.patch \ - file://0009-firmware-arm_ffa-Add-initial-FFA-bus-support-for-dev.patch \ - file://0010-firmware-arm_ffa-Add-initial-Arm-FFA-driver-support.patch \ - file://0011-firmware-arm_ffa-Add-support-for-SMCCC-as-transport-.patch \ - file://0012-firmware-arm_ffa-Setup-in-kernel-users-of-FFA-partit.patch \ - file://0013-firmware-arm_ffa-Add-support-for-MEM_-interfaces.patch \ - file://0014-tee-add-sec_world_id-to-struct-tee_shm.patch \ - file://0015-optee-simplify-optee_release.patch \ - file://0016-optee-sync-OP-TEE-headers.patch \ - file://0017-optee-refactor-driver-with-internal-callbacks.patch \ - file://0018-optee-add-a-FF-A-memory-pool.patch \ - file://0019-optee-add-FF-A-support.patch \ - file://0021-arm_ffa-add-support-for-FFA-v1.1.patch \ - file://0022-coresight-etm4x-Save-restore-TRFCR_EL1.patch \ - file://0023-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch \ - file://0024-perf-arm-cmn-Use-irq_set_affinity.patch \ - file://0025-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch \ - file://0026-perf-arm-cmn-Account-for-NUMA-affinity.patch \ - file://0027-perf-arm-cmn-Drop-compile-test-restriction.patch \ - file://0028-perf-arm-cmn-Refactor-node-ID-handling.patch \ - file://0029-perf-arm-cmn-Streamline-node-iteration.patch \ - file://0030-drivers-perf-arm-cmn-Add-space-after.patch \ - file://0031-perf-arm-cmn-Refactor-DTM-handling.patch \ - file://0032-perf-arm-cmn-Optimise-DTM-counter-reads.patch \ - file://0033-perf-arm-cmn-Optimise-DTC-counter-accesses.patch \ - file://0034-perf-arm-cmn-Move-group-validation-data-off-stack.patch \ - file://0035-perf-arm-cmn-Demarcate-CMN-600-specifics.patch \ - file://0036-perf-arm-cmn-Support-new-IP-features.patch \ - file://0037-perf-arm-cmn-Add-CI-700-Support.patch \ + file://0008-firmware-arm_ffa-Backport-of-arm_ffa-driver.patch \ + file://0009-tee-add-sec_world_id-to-struct-tee_shm.patch \ + file://0010-optee-simplify-optee_release.patch \ + file://0011-optee-sync-OP-TEE-headers.patch \ + file://0012-optee-refactor-driver-with-internal-callbacks.patch \ + file://0013-optee-add-a-FF-A-memory-pool.patch \ + file://0014-optee-add-FF-A-support.patch \ + file://0015-coresight-etm4x-Save-restore-TRFCR_EL1.patch \ + file://0016-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch \ + file://0017-perf-arm-cmn-Use-irq_set_affinity.patch \ + file://0018-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch \ + file://0019-perf-arm-cmn-Account-for-NUMA-affinity.patch \ + file://0020-perf-arm-cmn-Drop-compile-test-restriction.patch \ + file://0021-perf-arm-cmn-Refactor-node-ID-handling.patch \ + file://0022-perf-arm-cmn-Streamline-node-iteration.patch \ + file://0023-drivers-perf-arm-cmn-Add-space-after.patch \ + file://0024-perf-arm-cmn-Refactor-DTM-handling.patch \ + file://0025-perf-arm-cmn-Optimise-DTM-counter-reads.patch \ + file://0026-perf-arm-cmn-Optimise-DTC-counter-accesses.patch \ + file://0027-perf-arm-cmn-Move-group-validation-data-off-stack.patch \ + file://0028-perf-arm-cmn-Demarcate-CMN-600-specifics.patch \ + file://0029-perf-arm-cmn-Support-new-IP-features.patch \ + file://0030-perf-arm-cmn-Add-CI-700-Support.patch \ " KERNEL_FEATURES:append:tc = " bsp/arm-platforms/tc.scc" KERNEL_FEATURES:append:tc1 = " bsp/arm-platforms/tc-autofdo.scc" diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-arm64-smccc-Add-support-for-SMCCCv1.2-extended-input.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-arm64-smccc-Add-support-for-SMCCCv1.2-extended-input.patch deleted file mode 100644 index fdd74689..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-arm64-smccc-Add-support-for-SMCCCv1.2-extended-input.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 8f51e94b1c2c605fee7376fdb7ebac6a8fe16789 Mon Sep 17 00:00:00 2001 -From: Sudeep Holla -Date: Fri, 30 Apr 2021 11:24:24 +0100 -Subject: [PATCH 08/22] arm64: smccc: Add support for SMCCCv1.2 extended - input/output registers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -SMCCC v1.2 allows x8-x17 to be used as parameter registers and x4—x17 -to be used as result registers in SMC64/HVC64. Arm Firmware Framework -for Armv8-A specification makes use of x0-x7 as parameter and result -registers. There are other users like Hyper-V who intend to use beyond -x0-x7 as well. - -Current SMCCC interface in the kernel just use x0-x7 as parameter and -x0-x3 as result registers as required by SMCCCv1.0. Let us add new -interface to support this extended set of input/output registers namely -x0-x17 as both parameter and result registers. - -Acked-by: Mark Rutland -Tested-by: Michael Kelley -Reviewed-by: Michael Kelley -Cc: Will Deacon -Cc: Catalin Marinas -Signed-off-by: Sudeep Holla - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=d3d7f68912d370e80f7c293e04c8fecf76d704c5] ---- - arch/arm64/kernel/asm-offsets.c | 9 ++++++ - arch/arm64/kernel/smccc-call.S | 57 +++++++++++++++++++++++++++++++++ - include/linux/arm-smccc.h | 55 +++++++++++++++++++++++++++++++ - 3 files changed, 121 insertions(+) - -diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c -index 93da876a58e6..bad4a367da28 100644 ---- a/arch/arm64/kernel/asm-offsets.c -+++ b/arch/arm64/kernel/asm-offsets.c -@@ -139,6 +139,15 @@ int main(void) - DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); - DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); - DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X0_OFFS, offsetof(struct arm_smccc_1_2_regs, a0)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X2_OFFS, offsetof(struct arm_smccc_1_2_regs, a2)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X4_OFFS, offsetof(struct arm_smccc_1_2_regs, a4)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X6_OFFS, offsetof(struct arm_smccc_1_2_regs, a6)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X8_OFFS, offsetof(struct arm_smccc_1_2_regs, a8)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X10_OFFS, offsetof(struct arm_smccc_1_2_regs, a10)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X12_OFFS, offsetof(struct arm_smccc_1_2_regs, a12)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X14_OFFS, offsetof(struct arm_smccc_1_2_regs, a14)); -+ DEFINE(ARM_SMCCC_1_2_REGS_X16_OFFS, offsetof(struct arm_smccc_1_2_regs, a16)); - BLANK(); - DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); - DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address)); -diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S -index d62447964ed9..2def9d0dd3dd 100644 ---- a/arch/arm64/kernel/smccc-call.S -+++ b/arch/arm64/kernel/smccc-call.S -@@ -43,3 +43,60 @@ SYM_FUNC_START(__arm_smccc_hvc) - SMCCC hvc - SYM_FUNC_END(__arm_smccc_hvc) - EXPORT_SYMBOL(__arm_smccc_hvc) -+ -+ .macro SMCCC_1_2 instr -+ /* Save `res` and free a GPR that won't be clobbered */ -+ stp x1, x19, [sp, #-16]! -+ -+ /* Ensure `args` won't be clobbered while loading regs in next step */ -+ mov x19, x0 -+ -+ /* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */ -+ ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS] -+ ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS] -+ ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS] -+ ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS] -+ ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS] -+ ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS] -+ ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS] -+ ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS] -+ ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS] -+ -+ \instr #0 -+ -+ /* Load the `res` from the stack */ -+ ldr x19, [sp] -+ -+ /* Store the registers x0 - x17 into the result structure */ -+ stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS] -+ stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS] -+ stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS] -+ stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS] -+ stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS] -+ stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS] -+ stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS] -+ stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS] -+ stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS] -+ -+ /* Restore original x19 */ -+ ldp xzr, x19, [sp], #16 -+ ret -+.endm -+ -+/* -+ * void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args, -+ * struct arm_smccc_1_2_regs *res); -+ */ -+SYM_FUNC_START(arm_smccc_1_2_hvc) -+ SMCCC_1_2 hvc -+SYM_FUNC_END(arm_smccc_1_2_hvc) -+EXPORT_SYMBOL(arm_smccc_1_2_hvc) -+ -+/* -+ * void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args, -+ * struct arm_smccc_1_2_regs *res); -+ */ -+SYM_FUNC_START(arm_smccc_1_2_smc) -+ SMCCC_1_2 smc -+SYM_FUNC_END(arm_smccc_1_2_smc) -+EXPORT_SYMBOL(arm_smccc_1_2_smc) -diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h -index 62c54234576c..c8eb24af3c62 100644 ---- a/include/linux/arm-smccc.h -+++ b/include/linux/arm-smccc.h -@@ -186,6 +186,61 @@ struct arm_smccc_res { - unsigned long a3; - }; - -+#ifdef CONFIG_ARM64 -+/** -+ * struct arm_smccc_1_2_regs - Arguments for or Results from SMC/HVC call -+ * @a0-a17 argument values from registers 0 to 17 -+ */ -+struct arm_smccc_1_2_regs { -+ unsigned long a0; -+ unsigned long a1; -+ unsigned long a2; -+ unsigned long a3; -+ unsigned long a4; -+ unsigned long a5; -+ unsigned long a6; -+ unsigned long a7; -+ unsigned long a8; -+ unsigned long a9; -+ unsigned long a10; -+ unsigned long a11; -+ unsigned long a12; -+ unsigned long a13; -+ unsigned long a14; -+ unsigned long a15; -+ unsigned long a16; -+ unsigned long a17; -+}; -+ -+/** -+ * arm_smccc_1_2_hvc() - make HVC calls -+ * @args: arguments passed via struct arm_smccc_1_2_regs -+ * @res: result values via struct arm_smccc_1_2_regs -+ * -+ * This function is used to make HVC calls following SMC Calling Convention -+ * v1.2 or above. The content of the supplied param are copied from the -+ * structure to registers prior to the HVC instruction. The return values -+ * are updated with the content from registers on return from the HVC -+ * instruction. -+ */ -+asmlinkage void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args, -+ struct arm_smccc_1_2_regs *res); -+ -+/** -+ * arm_smccc_1_2_smc() - make SMC calls -+ * @args: arguments passed via struct arm_smccc_1_2_regs -+ * @res: result values via struct arm_smccc_1_2_regs -+ * -+ * This function is used to make SMC calls following SMC Calling Convention -+ * v1.2 or above. The content of the supplied param are copied from the -+ * structure to registers prior to the SMC instruction. The return values -+ * are updated with the content from registers on return from the SMC -+ * instruction. -+ */ -+asmlinkage void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args, -+ struct arm_smccc_1_2_regs *res); -+#endif -+ - /** - * struct arm_smccc_quirk - Contains quirk information - * @id: quirk identification --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-firmware-arm_ffa-Backport-of-arm_ffa-driver.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-firmware-arm_ffa-Backport-of-arm_ffa-driver.patch new file mode 100644 index 00000000..d91dbc57 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0008-firmware-arm_ffa-Backport-of-arm_ffa-driver.patch @@ -0,0 +1,1684 @@ +From 85df9333f0adf60fd76eb5ebb21b89c5b0a86c10 Mon Sep 17 00:00:00 2001 +From: Sudeep Holla +Date: Tue, 18 May 2021 17:36:18 +0100 +Subject: [PATCH 01/32] firmware: arm_ffa: Backport of arm_ffa driver + +This is a backport of upstream ARM FFA driver from: +https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=c0aff30cb9ad6a00c82acef0f2a48f99adf997c0 + +to branch=android12-5.10-lts + + arm64: smccc: Add support for SMCCCv1.2 extended input/output registers + commit 3fdc0cb59d97f87e2cc708d424f1538e31744286 upstream. + + firmware: arm_ffa: Add initial FFA bus support for device enumeration + commit e781858488b918e30a6ff28e9eab6058b787e3b3 upstream. + + firmware: arm_ffa: Add initial Arm FFA driver support + commit 3bbfe9871005f38df2955b2e125933edf1d2feef upstream. + + firmware: arm_ffa: Add support for SMCCC as transport to FFA driver + commit 714be77e976a4b013b935b3223b2ef68856084d0 upstream. + + firmware: arm_ffa: Setup in-kernel users of FFA partitions + commit d0c0bce831223b08e5bade2cefc93c3ddb790796 upstream. + + firmware: arm_ffa: Add support for MEM_* interfaces + commit cc2195fe536c28e192df5d07e6dd277af36814b4 upstream. + + firmware: arm_ffa: Ensure drivers provide a probe function + commit 92743071464fca5acbbe812d9a0d88de3eaaad36 upstream. + + firmware: arm_ffa: Simplify probe function + commit e362547addc39e4bb18ad5bdfd59ce4d512d0c08 upstream. + + firmware: arm_ffa: Fix the comment style + commit ba684a31d3626c86cd9097e12d6ed57d224d077d upstream. + + firmware: arm_ffa: Fix a possible ffa_linux_errmap buffer overflow + commit dd925db6f07556061c11ab1fbfa4a0145ae6b438 upstream. + + firmware: arm_ffa: Add missing remove callback to ffa_bus_type + commit 244f5d597e1ea519c2085fbd9819458688775e42 upstream. + + firmware: arm_ffa: Fix __ffa_devices_unregister + commit eb7b52e6db7c21400b9b2d539f9343fb6e94bd94 upstream. + + firmware: arm_ffa: Handle compatibility with different firmware versions + commit 8e3f9da608f14cfebac2659d8dd8737b79d01308 upstream. + + firmware: arm_ffa: Add support for MEM_LEND + commit 82a8daaecfd9382e9450a05f86be8a274cf69a27 upstream. + + firmware: arm_ffa: Remove unused 'compat_version' variable + commit 01537a078b86917c7bb69aa4b756b42b980c158b upstream. + +Signed-off-by: Sudeep Holla +Change-Id: If9df40d2d10be9e3c95298820bc20c201ea1774c +Signed-off-by: Arunachalam Ganapathy + +Upstream-Status: Backport +Change-Id: I8e6197d8b7ef6654dacd21450069b8e284a3cec5 +--- + MAINTAINERS | 7 + + arch/arm64/kernel/asm-offsets.c | 9 + + arch/arm64/kernel/smccc-call.S | 57 +++ + drivers/firmware/Kconfig | 1 + + drivers/firmware/Makefile | 1 + + drivers/firmware/arm_ffa/Kconfig | 21 + + drivers/firmware/arm_ffa/Makefile | 6 + + drivers/firmware/arm_ffa/bus.c | 220 +++++++++ + drivers/firmware/arm_ffa/common.h | 31 ++ + drivers/firmware/arm_ffa/driver.c | 776 ++++++++++++++++++++++++++++++ + drivers/firmware/arm_ffa/smccc.c | 39 ++ + include/linux/arm-smccc.h | 55 +++ + include/linux/arm_ffa.h | 269 +++++++++++ + 13 files changed, 1492 insertions(+) + create mode 100644 drivers/firmware/arm_ffa/Kconfig + create mode 100644 drivers/firmware/arm_ffa/Makefile + create mode 100644 drivers/firmware/arm_ffa/bus.c + create mode 100644 drivers/firmware/arm_ffa/common.h + create mode 100644 drivers/firmware/arm_ffa/driver.c + create mode 100644 drivers/firmware/arm_ffa/smccc.c + create mode 100644 include/linux/arm_ffa.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 5234423c477a..d5fdc9e68c89 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -6847,6 +6847,13 @@ F: include/linux/firewire.h + F: include/uapi/linux/firewire*.h + F: tools/firewire/ + ++FIRMWARE FRAMEWORK FOR ARMV8-A ++M: Sudeep Holla ++L: linux-arm-kernel@lists.infradead.org ++S: Maintained ++F: drivers/firmware/arm_ffa/ ++F: include/linux/arm_ffa.h ++ + FIRMWARE LOADER (request_firmware) + M: Luis Chamberlain + L: linux-kernel@vger.kernel.org +diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c +index 93da876a58e6..bad4a367da28 100644 +--- a/arch/arm64/kernel/asm-offsets.c ++++ b/arch/arm64/kernel/asm-offsets.c +@@ -139,6 +139,15 @@ int main(void) + DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); + DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); + DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X0_OFFS, offsetof(struct arm_smccc_1_2_regs, a0)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X2_OFFS, offsetof(struct arm_smccc_1_2_regs, a2)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X4_OFFS, offsetof(struct arm_smccc_1_2_regs, a4)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X6_OFFS, offsetof(struct arm_smccc_1_2_regs, a6)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X8_OFFS, offsetof(struct arm_smccc_1_2_regs, a8)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X10_OFFS, offsetof(struct arm_smccc_1_2_regs, a10)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X12_OFFS, offsetof(struct arm_smccc_1_2_regs, a12)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X14_OFFS, offsetof(struct arm_smccc_1_2_regs, a14)); ++ DEFINE(ARM_SMCCC_1_2_REGS_X16_OFFS, offsetof(struct arm_smccc_1_2_regs, a16)); + BLANK(); + DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); + DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address)); +diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S +index d62447964ed9..2def9d0dd3dd 100644 +--- a/arch/arm64/kernel/smccc-call.S ++++ b/arch/arm64/kernel/smccc-call.S +@@ -43,3 +43,60 @@ SYM_FUNC_START(__arm_smccc_hvc) + SMCCC hvc + SYM_FUNC_END(__arm_smccc_hvc) + EXPORT_SYMBOL(__arm_smccc_hvc) ++ ++ .macro SMCCC_1_2 instr ++ /* Save `res` and free a GPR that won't be clobbered */ ++ stp x1, x19, [sp, #-16]! ++ ++ /* Ensure `args` won't be clobbered while loading regs in next step */ ++ mov x19, x0 ++ ++ /* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */ ++ ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS] ++ ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS] ++ ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS] ++ ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS] ++ ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS] ++ ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS] ++ ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS] ++ ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS] ++ ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS] ++ ++ \instr #0 ++ ++ /* Load the `res` from the stack */ ++ ldr x19, [sp] ++ ++ /* Store the registers x0 - x17 into the result structure */ ++ stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS] ++ stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS] ++ stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS] ++ stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS] ++ stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS] ++ stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS] ++ stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS] ++ stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS] ++ stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS] ++ ++ /* Restore original x19 */ ++ ldp xzr, x19, [sp], #16 ++ ret ++.endm ++ ++/* ++ * void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args, ++ * struct arm_smccc_1_2_regs *res); ++ */ ++SYM_FUNC_START(arm_smccc_1_2_hvc) ++ SMCCC_1_2 hvc ++SYM_FUNC_END(arm_smccc_1_2_hvc) ++EXPORT_SYMBOL(arm_smccc_1_2_hvc) ++ ++/* ++ * void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args, ++ * struct arm_smccc_1_2_regs *res); ++ */ ++SYM_FUNC_START(arm_smccc_1_2_smc) ++ SMCCC_1_2 smc ++SYM_FUNC_END(arm_smccc_1_2_smc) ++EXPORT_SYMBOL(arm_smccc_1_2_smc) +diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig +index bfef3d8d14e7..90e6dd32f2cd 100644 +--- a/drivers/firmware/Kconfig ++++ b/drivers/firmware/Kconfig +@@ -296,6 +296,7 @@ config TURRIS_MOX_RWTM + other manufacturing data and also utilize the Entropy Bit Generator + for hardware random number generation. + ++source "drivers/firmware/arm_ffa/Kconfig" + source "drivers/firmware/broadcom/Kconfig" + source "drivers/firmware/google/Kconfig" + source "drivers/firmware/efi/Kconfig" +diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile +index 523173cbff33..3c2af2e98def 100644 +--- a/drivers/firmware/Makefile ++++ b/drivers/firmware/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o + obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o + obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o + ++obj-y += arm_ffa/ + obj-y += arm_scmi/ + obj-y += broadcom/ + obj-y += meson/ +diff --git a/drivers/firmware/arm_ffa/Kconfig b/drivers/firmware/arm_ffa/Kconfig +new file mode 100644 +index 000000000000..5e3ae5cf82e8 +--- /dev/null ++++ b/drivers/firmware/arm_ffa/Kconfig +@@ -0,0 +1,21 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config ARM_FFA_TRANSPORT ++ tristate "Arm Firmware Framework for Armv8-A" ++ depends on OF ++ depends on ARM64 ++ default n ++ help ++ This Firmware Framework(FF) for Arm A-profile processors describes ++ interfaces that standardize communication between the various ++ software images which includes communication between images in ++ the Secure world and Normal world. It also leverages the ++ virtualization extension to isolate software images provided ++ by an ecosystem of vendors from each other. ++ ++ This driver provides interface for all the client drivers making ++ use of the features offered by ARM FF-A. ++ ++config ARM_FFA_SMCCC ++ bool ++ default ARM_FFA_TRANSPORT ++ depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY +diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile +new file mode 100644 +index 000000000000..9d9f37523200 +--- /dev/null ++++ b/drivers/firmware/arm_ffa/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++ffa-bus-y = bus.o ++ffa-driver-y = driver.o ++ffa-transport-$(CONFIG_ARM_FFA_SMCCC) += smccc.o ++ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) $(ffa-transport-y) ++obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o +diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c +new file mode 100644 +index 000000000000..fca1e311ea6c +--- /dev/null ++++ b/drivers/firmware/arm_ffa/bus.c +@@ -0,0 +1,220 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 ARM Ltd. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++ ++static int ffa_device_match(struct device *dev, struct device_driver *drv) ++{ ++ const struct ffa_device_id *id_table; ++ struct ffa_device *ffa_dev; ++ ++ id_table = to_ffa_driver(drv)->id_table; ++ ffa_dev = to_ffa_dev(dev); ++ ++ while (!uuid_is_null(&id_table->uuid)) { ++ /* ++ * FF-A v1.0 doesn't provide discovery of UUIDs, just the ++ * partition IDs, so fetch the partitions IDs for this ++ * id_table UUID and assign the UUID to the device if the ++ * partition ID matches ++ */ ++ if (uuid_is_null(&ffa_dev->uuid)) ++ ffa_device_match_uuid(ffa_dev, &id_table->uuid); ++ ++ if (uuid_equal(&ffa_dev->uuid, &id_table->uuid)) ++ return 1; ++ id_table++; ++ } ++ ++ return 0; ++} ++ ++static int ffa_device_probe(struct device *dev) ++{ ++ struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); ++ struct ffa_device *ffa_dev = to_ffa_dev(dev); ++ ++ return ffa_drv->probe(ffa_dev); ++} ++ ++static int ffa_device_remove(struct device *dev) ++{ ++ struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); ++ ++ ffa_drv->remove(to_ffa_dev(dev)); ++ ++ return 0; ++} ++ ++static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct ffa_device *ffa_dev = to_ffa_dev(dev); ++ ++ return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb", ++ ffa_dev->vm_id, &ffa_dev->uuid); ++} ++ ++static ssize_t partition_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct ffa_device *ffa_dev = to_ffa_dev(dev); ++ ++ return sprintf(buf, "0x%04x\n", ffa_dev->vm_id); ++} ++static DEVICE_ATTR_RO(partition_id); ++ ++static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct ffa_device *ffa_dev = to_ffa_dev(dev); ++ ++ return sprintf(buf, "%pUb\n", &ffa_dev->uuid); ++} ++static DEVICE_ATTR_RO(uuid); ++ ++static struct attribute *ffa_device_attributes_attrs[] = { ++ &dev_attr_partition_id.attr, ++ &dev_attr_uuid.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(ffa_device_attributes); ++ ++struct bus_type ffa_bus_type = { ++ .name = "arm_ffa", ++ .match = ffa_device_match, ++ .probe = ffa_device_probe, ++ .remove = ffa_device_remove, ++ .uevent = ffa_device_uevent, ++ .dev_groups = ffa_device_attributes_groups, ++}; ++EXPORT_SYMBOL_GPL(ffa_bus_type); ++ ++int ffa_driver_register(struct ffa_driver *driver, struct module *owner, ++ const char *mod_name) ++{ ++ int ret; ++ ++ if (!driver->probe) ++ return -EINVAL; ++ ++ driver->driver.bus = &ffa_bus_type; ++ driver->driver.name = driver->name; ++ driver->driver.owner = owner; ++ driver->driver.mod_name = mod_name; ++ ++ ret = driver_register(&driver->driver); ++ if (!ret) ++ pr_debug("registered new ffa driver %s\n", driver->name); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ffa_driver_register); ++ ++void ffa_driver_unregister(struct ffa_driver *driver) ++{ ++ driver_unregister(&driver->driver); ++} ++EXPORT_SYMBOL_GPL(ffa_driver_unregister); ++ ++static void ffa_release_device(struct device *dev) ++{ ++ struct ffa_device *ffa_dev = to_ffa_dev(dev); ++ ++ kfree(ffa_dev); ++} ++ ++static int __ffa_devices_unregister(struct device *dev, void *data) ++{ ++ device_unregister(dev); ++ ++ return 0; ++} ++ ++static void ffa_devices_unregister(void) ++{ ++ bus_for_each_dev(&ffa_bus_type, NULL, NULL, ++ __ffa_devices_unregister); ++} ++ ++bool ffa_device_is_valid(struct ffa_device *ffa_dev) ++{ ++ bool valid = false; ++ struct device *dev = NULL; ++ struct ffa_device *tmp_dev; ++ ++ do { ++ dev = bus_find_next_device(&ffa_bus_type, dev); ++ tmp_dev = to_ffa_dev(dev); ++ if (tmp_dev == ffa_dev) { ++ valid = true; ++ break; ++ } ++ put_device(dev); ++ } while (dev); ++ ++ put_device(dev); ++ ++ return valid; ++} ++ ++struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) ++{ ++ int ret; ++ struct device *dev; ++ struct ffa_device *ffa_dev; ++ ++ ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); ++ if (!ffa_dev) ++ return NULL; ++ ++ dev = &ffa_dev->dev; ++ dev->bus = &ffa_bus_type; ++ dev->release = ffa_release_device; ++ dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id); ++ ++ ffa_dev->vm_id = vm_id; ++ uuid_copy(&ffa_dev->uuid, uuid); ++ ++ ret = device_register(&ffa_dev->dev); ++ if (ret) { ++ dev_err(dev, "unable to register device %s err=%d\n", ++ dev_name(dev), ret); ++ put_device(dev); ++ return NULL; ++ } ++ ++ return ffa_dev; ++} ++EXPORT_SYMBOL_GPL(ffa_device_register); ++ ++void ffa_device_unregister(struct ffa_device *ffa_dev) ++{ ++ if (!ffa_dev) ++ return; ++ ++ device_unregister(&ffa_dev->dev); ++} ++EXPORT_SYMBOL_GPL(ffa_device_unregister); ++ ++int arm_ffa_bus_init(void) ++{ ++ return bus_register(&ffa_bus_type); ++} ++ ++void arm_ffa_bus_exit(void) ++{ ++ ffa_devices_unregister(); ++ bus_unregister(&ffa_bus_type); ++} +diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h +new file mode 100644 +index 000000000000..d6eccf1fd3f6 +--- /dev/null ++++ b/drivers/firmware/arm_ffa/common.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 ARM Ltd. ++ */ ++ ++#ifndef _FFA_COMMON_H ++#define _FFA_COMMON_H ++ ++#include ++#include ++#include ++ ++typedef struct arm_smccc_1_2_regs ffa_value_t; ++ ++typedef void (ffa_fn)(ffa_value_t, ffa_value_t *); ++ ++int arm_ffa_bus_init(void); ++void arm_ffa_bus_exit(void); ++bool ffa_device_is_valid(struct ffa_device *ffa_dev); ++void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid); ++ ++#ifdef CONFIG_ARM_FFA_SMCCC ++int __init ffa_transport_init(ffa_fn **invoke_ffa_fn); ++#else ++static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ ++#endif /* _FFA_COMMON_H */ +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +new file mode 100644 +index 000000000000..14f900047ac0 +--- /dev/null ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -0,0 +1,776 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Arm Firmware Framework for ARMv8-A(FFA) interface driver ++ * ++ * The Arm FFA specification[1] describes a software architecture to ++ * leverages the virtualization extension to isolate software images ++ * provided by an ecosystem of vendors from each other and describes ++ * interfaces that standardize communication between the various software ++ * images including communication between images in the Secure world and ++ * Normal world. Any Hypervisor could use the FFA interfaces to enable ++ * communication between VMs it manages. ++ * ++ * The Hypervisor a.k.a Partition managers in FFA terminology can assign ++ * system resources(Memory regions, Devices, CPU cycles) to the partitions ++ * and manage isolation amongst them. ++ * ++ * [1] https://developer.arm.com/docs/den0077/latest ++ * ++ * Copyright (C) 2021 ARM Ltd. ++ */ ++ ++#define DRIVER_NAME "ARM FF-A" ++#define pr_fmt(fmt) DRIVER_NAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++ ++#define FFA_DRIVER_VERSION FFA_VERSION_1_0 ++ ++#define FFA_SMC(calling_convention, func_num) \ ++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \ ++ ARM_SMCCC_OWNER_STANDARD, (func_num)) ++ ++#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num)) ++#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num)) ++ ++#define FFA_ERROR FFA_SMC_32(0x60) ++#define FFA_SUCCESS FFA_SMC_32(0x61) ++#define FFA_INTERRUPT FFA_SMC_32(0x62) ++#define FFA_VERSION FFA_SMC_32(0x63) ++#define FFA_FEATURES FFA_SMC_32(0x64) ++#define FFA_RX_RELEASE FFA_SMC_32(0x65) ++#define FFA_RXTX_MAP FFA_SMC_32(0x66) ++#define FFA_FN64_RXTX_MAP FFA_SMC_64(0x66) ++#define FFA_RXTX_UNMAP FFA_SMC_32(0x67) ++#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68) ++#define FFA_ID_GET FFA_SMC_32(0x69) ++#define FFA_MSG_POLL FFA_SMC_32(0x6A) ++#define FFA_MSG_WAIT FFA_SMC_32(0x6B) ++#define FFA_YIELD FFA_SMC_32(0x6C) ++#define FFA_RUN FFA_SMC_32(0x6D) ++#define FFA_MSG_SEND FFA_SMC_32(0x6E) ++#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F) ++#define FFA_FN64_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F) ++#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70) ++#define FFA_FN64_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70) ++#define FFA_MEM_DONATE FFA_SMC_32(0x71) ++#define FFA_FN64_MEM_DONATE FFA_SMC_64(0x71) ++#define FFA_MEM_LEND FFA_SMC_32(0x72) ++#define FFA_FN64_MEM_LEND FFA_SMC_64(0x72) ++#define FFA_MEM_SHARE FFA_SMC_32(0x73) ++#define FFA_FN64_MEM_SHARE FFA_SMC_64(0x73) ++#define FFA_MEM_RETRIEVE_REQ FFA_SMC_32(0x74) ++#define FFA_FN64_MEM_RETRIEVE_REQ FFA_SMC_64(0x74) ++#define FFA_MEM_RETRIEVE_RESP FFA_SMC_32(0x75) ++#define FFA_MEM_RELINQUISH FFA_SMC_32(0x76) ++#define FFA_MEM_RECLAIM FFA_SMC_32(0x77) ++#define FFA_MEM_OP_PAUSE FFA_SMC_32(0x78) ++#define FFA_MEM_OP_RESUME FFA_SMC_32(0x79) ++#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A) ++#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B) ++#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C) ++ ++/* ++ * For some calls it is necessary to use SMC64 to pass or return 64-bit values. ++ * For such calls FFA_FN_NATIVE(name) will choose the appropriate ++ * (native-width) function ID. ++ */ ++#ifdef CONFIG_64BIT ++#define FFA_FN_NATIVE(name) FFA_FN64_##name ++#else ++#define FFA_FN_NATIVE(name) FFA_##name ++#endif ++ ++/* FFA error codes. */ ++#define FFA_RET_SUCCESS (0) ++#define FFA_RET_NOT_SUPPORTED (-1) ++#define FFA_RET_INVALID_PARAMETERS (-2) ++#define FFA_RET_NO_MEMORY (-3) ++#define FFA_RET_BUSY (-4) ++#define FFA_RET_INTERRUPTED (-5) ++#define FFA_RET_DENIED (-6) ++#define FFA_RET_RETRY (-7) ++#define FFA_RET_ABORTED (-8) ++ ++#define MAJOR_VERSION_MASK GENMASK(30, 16) ++#define MINOR_VERSION_MASK GENMASK(15, 0) ++#define MAJOR_VERSION(x) ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x)))) ++#define MINOR_VERSION(x) ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x)))) ++#define PACK_VERSION_INFO(major, minor) \ ++ (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \ ++ FIELD_PREP(MINOR_VERSION_MASK, (minor))) ++#define FFA_VERSION_1_0 PACK_VERSION_INFO(1, 0) ++#define FFA_MIN_VERSION FFA_VERSION_1_0 ++ ++#define SENDER_ID_MASK GENMASK(31, 16) ++#define RECEIVER_ID_MASK GENMASK(15, 0) ++#define SENDER_ID(x) ((u16)(FIELD_GET(SENDER_ID_MASK, (x)))) ++#define RECEIVER_ID(x) ((u16)(FIELD_GET(RECEIVER_ID_MASK, (x)))) ++#define PACK_TARGET_INFO(s, r) \ ++ (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r))) ++ ++/* ++ * FF-A specification mentions explicitly about '4K pages'. This should ++ * not be confused with the kernel PAGE_SIZE, which is the translation ++ * granule kernel is configured and may be one among 4K, 16K and 64K. ++ */ ++#define FFA_PAGE_SIZE SZ_4K ++/* ++ * Keeping RX TX buffer size as 4K for now ++ * 64K may be preferred to keep it min a page in 64K PAGE_SIZE config ++ */ ++#define RXTX_BUFFER_SIZE SZ_4K ++ ++static ffa_fn *invoke_ffa_fn; ++ ++static const int ffa_linux_errmap[] = { ++ /* better than switch case as long as return value is continuous */ ++ 0, /* FFA_RET_SUCCESS */ ++ -EOPNOTSUPP, /* FFA_RET_NOT_SUPPORTED */ ++ -EINVAL, /* FFA_RET_INVALID_PARAMETERS */ ++ -ENOMEM, /* FFA_RET_NO_MEMORY */ ++ -EBUSY, /* FFA_RET_BUSY */ ++ -EINTR, /* FFA_RET_INTERRUPTED */ ++ -EACCES, /* FFA_RET_DENIED */ ++ -EAGAIN, /* FFA_RET_RETRY */ ++ -ECANCELED, /* FFA_RET_ABORTED */ ++}; ++ ++static inline int ffa_to_linux_errno(int errno) ++{ ++ int err_idx = -errno; ++ ++ if (err_idx >= 0 && err_idx < ARRAY_SIZE(ffa_linux_errmap)) ++ return ffa_linux_errmap[err_idx]; ++ return -EINVAL; ++} ++ ++struct ffa_drv_info { ++ u32 version; ++ u16 vm_id; ++ struct mutex rx_lock; /* lock to protect Rx buffer */ ++ struct mutex tx_lock; /* lock to protect Tx buffer */ ++ void *rx_buffer; ++ void *tx_buffer; ++}; ++ ++static struct ffa_drv_info *drv_info; ++ ++/* ++ * The driver must be able to support all the versions from the earliest ++ * supported FFA_MIN_VERSION to the latest supported FFA_DRIVER_VERSION. ++ * The specification states that if firmware supports a FFA implementation ++ * that is incompatible with and at a greater version number than specified ++ * by the caller(FFA_DRIVER_VERSION passed as parameter to FFA_VERSION), ++ * it must return the NOT_SUPPORTED error code. ++ */ ++static u32 ffa_compatible_version_find(u32 version) ++{ ++ u16 major = MAJOR_VERSION(version), minor = MINOR_VERSION(version); ++ u16 drv_major = MAJOR_VERSION(FFA_DRIVER_VERSION); ++ u16 drv_minor = MINOR_VERSION(FFA_DRIVER_VERSION); ++ ++ if ((major < drv_major) || (major == drv_major && minor <= drv_minor)) ++ return version; ++ ++ pr_info("Firmware version higher than driver version, downgrading\n"); ++ return FFA_DRIVER_VERSION; ++} ++ ++static int ffa_version_check(u32 *version) ++{ ++ ffa_value_t ver; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_VERSION, .a1 = FFA_DRIVER_VERSION, ++ }, &ver); ++ ++ if (ver.a0 == FFA_RET_NOT_SUPPORTED) { ++ pr_info("FFA_VERSION returned not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (ver.a0 < FFA_MIN_VERSION) { ++ pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n", ++ MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0), ++ MAJOR_VERSION(FFA_MIN_VERSION), ++ MINOR_VERSION(FFA_MIN_VERSION)); ++ return -EINVAL; ++ } ++ ++ pr_info("Driver version %d.%d\n", MAJOR_VERSION(FFA_DRIVER_VERSION), ++ MINOR_VERSION(FFA_DRIVER_VERSION)); ++ pr_info("Firmware version %d.%d found\n", MAJOR_VERSION(ver.a0), ++ MINOR_VERSION(ver.a0)); ++ *version = ffa_compatible_version_find(ver.a0); ++ ++ return 0; ++} ++ ++static int ffa_rx_release(void) ++{ ++ ffa_value_t ret; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_RX_RELEASE, ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ /* check for ret.a0 == FFA_RX_RELEASE ? */ ++ ++ return 0; ++} ++ ++static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt) ++{ ++ ffa_value_t ret; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_FN_NATIVE(RXTX_MAP), ++ .a1 = tx_buf, .a2 = rx_buf, .a3 = pg_cnt, ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ return 0; ++} ++ ++static int ffa_rxtx_unmap(u16 vm_id) ++{ ++ ffa_value_t ret; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_RXTX_UNMAP, .a1 = PACK_TARGET_INFO(vm_id, 0), ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ return 0; ++} ++ ++/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */ ++static int ++__ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, ++ struct ffa_partition_info *buffer, int num_partitions) ++{ ++ int count; ++ ffa_value_t partition_info; ++ ++ mutex_lock(&drv_info->rx_lock); ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_PARTITION_INFO_GET, ++ .a1 = uuid0, .a2 = uuid1, .a3 = uuid2, .a4 = uuid3, ++ }, &partition_info); ++ ++ if (partition_info.a0 == FFA_ERROR) { ++ mutex_unlock(&drv_info->rx_lock); ++ return ffa_to_linux_errno((int)partition_info.a2); ++ } ++ ++ count = partition_info.a2; ++ ++ if (buffer && count <= num_partitions) ++ memcpy(buffer, drv_info->rx_buffer, sizeof(*buffer) * count); ++ ++ ffa_rx_release(); ++ ++ mutex_unlock(&drv_info->rx_lock); ++ ++ return count; ++} ++ ++/* buffer is allocated and caller must free the same if returned count > 0 */ ++static int ++ffa_partition_probe(const uuid_t *uuid, struct ffa_partition_info **buffer) ++{ ++ int count; ++ u32 uuid0_4[4]; ++ struct ffa_partition_info *pbuf; ++ ++ export_uuid((u8 *)uuid0_4, uuid); ++ count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], ++ uuid0_4[3], NULL, 0); ++ if (count <= 0) ++ return count; ++ ++ pbuf = kcalloc(count, sizeof(*pbuf), GFP_KERNEL); ++ if (!pbuf) ++ return -ENOMEM; ++ ++ count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], ++ uuid0_4[3], pbuf, count); ++ if (count <= 0) ++ kfree(pbuf); ++ else ++ *buffer = pbuf; ++ ++ return count; ++} ++ ++#define VM_ID_MASK GENMASK(15, 0) ++static int ffa_id_get(u16 *vm_id) ++{ ++ ffa_value_t id; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_ID_GET, ++ }, &id); ++ ++ if (id.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)id.a2); ++ ++ *vm_id = FIELD_GET(VM_ID_MASK, (id.a2)); ++ ++ return 0; ++} ++ ++static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, ++ struct ffa_send_direct_data *data) ++{ ++ u32 req_id, resp_id, src_dst_ids = PACK_TARGET_INFO(src_id, dst_id); ++ ffa_value_t ret; ++ ++ if (mode_32bit) { ++ req_id = FFA_MSG_SEND_DIRECT_REQ; ++ resp_id = FFA_MSG_SEND_DIRECT_RESP; ++ } else { ++ req_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_REQ); ++ resp_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_RESP); ++ } ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = req_id, .a1 = src_dst_ids, .a2 = 0, ++ .a3 = data->data0, .a4 = data->data1, .a5 = data->data2, ++ .a6 = data->data3, .a7 = data->data4, ++ }, &ret); ++ ++ while (ret.a0 == FFA_INTERRUPT) ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_RUN, .a1 = ret.a1, ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ if (ret.a0 == resp_id) { ++ data->data0 = ret.a3; ++ data->data1 = ret.a4; ++ data->data2 = ret.a5; ++ data->data3 = ret.a6; ++ data->data4 = ret.a7; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz, ++ u32 frag_len, u32 len, u64 *handle) ++{ ++ ffa_value_t ret; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = func_id, .a1 = len, .a2 = frag_len, ++ .a3 = buf, .a4 = buf_sz, ++ }, &ret); ++ ++ while (ret.a0 == FFA_MEM_OP_PAUSE) ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_MEM_OP_RESUME, ++ .a1 = ret.a1, .a2 = ret.a2, ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ if (ret.a0 != FFA_SUCCESS) ++ return -EOPNOTSUPP; ++ ++ if (handle) ++ *handle = PACK_HANDLE(ret.a2, ret.a3); ++ ++ return frag_len; ++} ++ ++static int ffa_mem_next_frag(u64 handle, u32 frag_len) ++{ ++ ffa_value_t ret; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_MEM_FRAG_TX, ++ .a1 = HANDLE_LOW(handle), .a2 = HANDLE_HIGH(handle), ++ .a3 = frag_len, ++ }, &ret); ++ ++ while (ret.a0 == FFA_MEM_OP_PAUSE) ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_MEM_OP_RESUME, ++ .a1 = ret.a1, .a2 = ret.a2, ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ if (ret.a0 != FFA_MEM_FRAG_RX) ++ return -EOPNOTSUPP; ++ ++ return ret.a3; ++} ++ ++static int ++ffa_transmit_fragment(u32 func_id, phys_addr_t buf, u32 buf_sz, u32 frag_len, ++ u32 len, u64 *handle, bool first) ++{ ++ if (!first) ++ return ffa_mem_next_frag(*handle, frag_len); ++ ++ return ffa_mem_first_frag(func_id, buf, buf_sz, frag_len, len, handle); ++} ++ ++static u32 ffa_get_num_pages_sg(struct scatterlist *sg) ++{ ++ u32 num_pages = 0; ++ ++ do { ++ num_pages += sg->length / FFA_PAGE_SIZE; ++ } while ((sg = sg_next(sg))); ++ ++ return num_pages; ++} ++ ++static int ++ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, ++ struct ffa_mem_ops_args *args) ++{ ++ int rc = 0; ++ bool first = true; ++ phys_addr_t addr = 0; ++ struct ffa_composite_mem_region *composite; ++ struct ffa_mem_region_addr_range *constituents; ++ struct ffa_mem_region_attributes *ep_mem_access; ++ struct ffa_mem_region *mem_region = buffer; ++ u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg); ++ ++ mem_region->tag = args->tag; ++ mem_region->flags = args->flags; ++ mem_region->sender_id = drv_info->vm_id; ++ mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | ++ FFA_MEM_INNER_SHAREABLE; ++ ep_mem_access = &mem_region->ep_mem_access[0]; ++ ++ for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) { ++ ep_mem_access->receiver = args->attrs[idx].receiver; ++ ep_mem_access->attrs = args->attrs[idx].attrs; ++ ep_mem_access->composite_off = COMPOSITE_OFFSET(args->nattrs); ++ } ++ mem_region->ep_count = args->nattrs; ++ ++ composite = buffer + COMPOSITE_OFFSET(args->nattrs); ++ composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg); ++ composite->addr_range_cnt = num_entries; ++ ++ length = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, num_entries); ++ frag_len = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, 0); ++ if (frag_len > max_fragsize) ++ return -ENXIO; ++ ++ if (!args->use_txbuf) { ++ addr = virt_to_phys(buffer); ++ buf_sz = max_fragsize / FFA_PAGE_SIZE; ++ } ++ ++ constituents = buffer + frag_len; ++ idx = 0; ++ do { ++ if (frag_len == max_fragsize) { ++ rc = ffa_transmit_fragment(func_id, addr, buf_sz, ++ frag_len, length, ++ &args->g_handle, first); ++ if (rc < 0) ++ return -ENXIO; ++ ++ first = false; ++ idx = 0; ++ frag_len = 0; ++ constituents = buffer; ++ } ++ ++ if ((void *)constituents - buffer > max_fragsize) { ++ pr_err("Memory Region Fragment > Tx Buffer size\n"); ++ return -EFAULT; ++ } ++ ++ constituents->address = sg_phys(args->sg); ++ constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE; ++ constituents++; ++ frag_len += sizeof(struct ffa_mem_region_addr_range); ++ } while ((args->sg = sg_next(args->sg))); ++ ++ return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len, ++ length, &args->g_handle, first); ++} ++ ++static int ffa_memory_ops(u32 func_id, struct ffa_mem_ops_args *args) ++{ ++ int ret; ++ void *buffer; ++ ++ if (!args->use_txbuf) { ++ buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ } else { ++ buffer = drv_info->tx_buffer; ++ mutex_lock(&drv_info->tx_lock); ++ } ++ ++ ret = ffa_setup_and_transmit(func_id, buffer, RXTX_BUFFER_SIZE, args); ++ ++ if (args->use_txbuf) ++ mutex_unlock(&drv_info->tx_lock); ++ else ++ free_pages_exact(buffer, RXTX_BUFFER_SIZE); ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static int ffa_memory_reclaim(u64 g_handle, u32 flags) ++{ ++ ffa_value_t ret; ++ ++ invoke_ffa_fn((ffa_value_t){ ++ .a0 = FFA_MEM_RECLAIM, ++ .a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle), ++ .a3 = flags, ++ }, &ret); ++ ++ if (ret.a0 == FFA_ERROR) ++ return ffa_to_linux_errno((int)ret.a2); ++ ++ return 0; ++} ++ ++static u32 ffa_api_version_get(void) ++{ ++ return drv_info->version; ++} ++ ++static int ffa_partition_info_get(const char *uuid_str, ++ struct ffa_partition_info *buffer) ++{ ++ int count; ++ uuid_t uuid; ++ struct ffa_partition_info *pbuf; ++ ++ if (uuid_parse(uuid_str, &uuid)) { ++ pr_err("invalid uuid (%s)\n", uuid_str); ++ return -ENODEV; ++ } ++ ++ count = ffa_partition_probe(&uuid_null, &pbuf); ++ if (count <= 0) ++ return -ENOENT; ++ ++ memcpy(buffer, pbuf, sizeof(*pbuf) * count); ++ kfree(pbuf); ++ return 0; ++} ++ ++static void ffa_mode_32bit_set(struct ffa_device *dev) ++{ ++ dev->mode_32bit = true; ++} ++ ++static int ffa_sync_send_receive(struct ffa_device *dev, ++ struct ffa_send_direct_data *data) ++{ ++ return ffa_msg_send_direct_req(drv_info->vm_id, dev->vm_id, ++ dev->mode_32bit, data); ++} ++ ++static int ++ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args) ++{ ++ if (dev->mode_32bit) ++ return ffa_memory_ops(FFA_MEM_SHARE, args); ++ ++ return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args); ++} ++ ++static int ++ffa_memory_lend(struct ffa_device *dev, struct ffa_mem_ops_args *args) ++{ ++ /* Note that upon a successful MEM_LEND request the caller ++ * must ensure that the memory region specified is not accessed ++ * until a successful MEM_RECALIM call has been made. ++ * On systems with a hypervisor present this will been enforced, ++ * however on systems without a hypervisor the responsibility ++ * falls to the calling kernel driver to prevent access. ++ */ ++ if (dev->mode_32bit) ++ return ffa_memory_ops(FFA_MEM_LEND, args); ++ ++ return ffa_memory_ops(FFA_FN_NATIVE(MEM_LEND), args); ++} ++ ++static const struct ffa_dev_ops ffa_ops = { ++ .api_version_get = ffa_api_version_get, ++ .partition_info_get = ffa_partition_info_get, ++ .mode_32bit_set = ffa_mode_32bit_set, ++ .sync_send_receive = ffa_sync_send_receive, ++ .memory_reclaim = ffa_memory_reclaim, ++ .memory_share = ffa_memory_share, ++ .memory_lend = ffa_memory_lend, ++}; ++ ++const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) ++{ ++ if (ffa_device_is_valid(dev)) ++ return &ffa_ops; ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(ffa_dev_ops_get); ++ ++void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) ++{ ++ int count, idx; ++ struct ffa_partition_info *pbuf, *tpbuf; ++ ++ count = ffa_partition_probe(uuid, &pbuf); ++ if (count <= 0) ++ return; ++ ++ for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) ++ if (tpbuf->id == ffa_dev->vm_id) ++ uuid_copy(&ffa_dev->uuid, uuid); ++ kfree(pbuf); ++} ++ ++static void ffa_setup_partitions(void) ++{ ++ int count, idx; ++ struct ffa_device *ffa_dev; ++ struct ffa_partition_info *pbuf, *tpbuf; ++ ++ count = ffa_partition_probe(&uuid_null, &pbuf); ++ if (count <= 0) { ++ pr_info("%s: No partitions found, error %d\n", __func__, count); ++ return; ++ } ++ ++ for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) { ++ /* Note that the &uuid_null parameter will require ++ * ffa_device_match() to find the UUID of this partition id ++ * with help of ffa_device_match_uuid(). Once the FF-A spec ++ * is updated to provide correct UUID here for each partition ++ * as part of the discovery API, we need to pass the ++ * discovered UUID here instead. ++ */ ++ ffa_dev = ffa_device_register(&uuid_null, tpbuf->id); ++ if (!ffa_dev) { ++ pr_err("%s: failed to register partition ID 0x%x\n", ++ __func__, tpbuf->id); ++ continue; ++ } ++ ++ ffa_dev_set_drvdata(ffa_dev, drv_info); ++ } ++ kfree(pbuf); ++} ++ ++static int __init ffa_init(void) ++{ ++ int ret; ++ ++ ret = ffa_transport_init(&invoke_ffa_fn); ++ if (ret) ++ return ret; ++ ++ ret = arm_ffa_bus_init(); ++ if (ret) ++ return ret; ++ ++ drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL); ++ if (!drv_info) { ++ ret = -ENOMEM; ++ goto ffa_bus_exit; ++ } ++ ++ ret = ffa_version_check(&drv_info->version); ++ if (ret) ++ goto free_drv_info; ++ ++ if (ffa_id_get(&drv_info->vm_id)) { ++ pr_err("failed to obtain VM id for self\n"); ++ ret = -ENODEV; ++ goto free_drv_info; ++ } ++ ++ drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); ++ if (!drv_info->rx_buffer) { ++ ret = -ENOMEM; ++ goto free_pages; ++ } ++ ++ drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); ++ if (!drv_info->tx_buffer) { ++ ret = -ENOMEM; ++ goto free_pages; ++ } ++ ++ ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), ++ virt_to_phys(drv_info->rx_buffer), ++ RXTX_BUFFER_SIZE / FFA_PAGE_SIZE); ++ if (ret) { ++ pr_err("failed to register FFA RxTx buffers\n"); ++ goto free_pages; ++ } ++ ++ mutex_init(&drv_info->rx_lock); ++ mutex_init(&drv_info->tx_lock); ++ ++ ffa_setup_partitions(); ++ ++ return 0; ++free_pages: ++ if (drv_info->tx_buffer) ++ free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); ++ free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); ++free_drv_info: ++ kfree(drv_info); ++ffa_bus_exit: ++ arm_ffa_bus_exit(); ++ return ret; ++} ++subsys_initcall(ffa_init); ++ ++static void __exit ffa_exit(void) ++{ ++ ffa_rxtx_unmap(drv_info->vm_id); ++ free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); ++ free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); ++ kfree(drv_info); ++ arm_ffa_bus_exit(); ++} ++module_exit(ffa_exit); ++ ++MODULE_ALIAS("arm-ffa"); ++MODULE_AUTHOR("Sudeep Holla "); ++MODULE_DESCRIPTION("Arm FF-A interface driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/firmware/arm_ffa/smccc.c b/drivers/firmware/arm_ffa/smccc.c +new file mode 100644 +index 000000000000..4d85bfff0a4e +--- /dev/null ++++ b/drivers/firmware/arm_ffa/smccc.c +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2021 ARM Ltd. ++ */ ++ ++#include ++ ++#include "common.h" ++ ++static void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res) ++{ ++ arm_smccc_1_2_smc(&args, res); ++} ++ ++static void __arm_ffa_fn_hvc(ffa_value_t args, ffa_value_t *res) ++{ ++ arm_smccc_1_2_hvc(&args, res); ++} ++ ++int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) ++{ ++ enum arm_smccc_conduit conduit; ++ ++ if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2) ++ return -EOPNOTSUPP; ++ ++ conduit = arm_smccc_1_1_get_conduit(); ++ if (conduit == SMCCC_CONDUIT_NONE) { ++ pr_err("%s: invalid SMCCC conduit\n", __func__); ++ return -EOPNOTSUPP; ++ } ++ ++ if (conduit == SMCCC_CONDUIT_SMC) ++ *invoke_ffa_fn = __arm_ffa_fn_smc; ++ else ++ *invoke_ffa_fn = __arm_ffa_fn_hvc; ++ ++ return 0; ++} +diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h +index 62c54234576c..c8eb24af3c62 100644 +--- a/include/linux/arm-smccc.h ++++ b/include/linux/arm-smccc.h +@@ -186,6 +186,61 @@ struct arm_smccc_res { + unsigned long a3; + }; + ++#ifdef CONFIG_ARM64 ++/** ++ * struct arm_smccc_1_2_regs - Arguments for or Results from SMC/HVC call ++ * @a0-a17 argument values from registers 0 to 17 ++ */ ++struct arm_smccc_1_2_regs { ++ unsigned long a0; ++ unsigned long a1; ++ unsigned long a2; ++ unsigned long a3; ++ unsigned long a4; ++ unsigned long a5; ++ unsigned long a6; ++ unsigned long a7; ++ unsigned long a8; ++ unsigned long a9; ++ unsigned long a10; ++ unsigned long a11; ++ unsigned long a12; ++ unsigned long a13; ++ unsigned long a14; ++ unsigned long a15; ++ unsigned long a16; ++ unsigned long a17; ++}; ++ ++/** ++ * arm_smccc_1_2_hvc() - make HVC calls ++ * @args: arguments passed via struct arm_smccc_1_2_regs ++ * @res: result values via struct arm_smccc_1_2_regs ++ * ++ * This function is used to make HVC calls following SMC Calling Convention ++ * v1.2 or above. The content of the supplied param are copied from the ++ * structure to registers prior to the HVC instruction. The return values ++ * are updated with the content from registers on return from the HVC ++ * instruction. ++ */ ++asmlinkage void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args, ++ struct arm_smccc_1_2_regs *res); ++ ++/** ++ * arm_smccc_1_2_smc() - make SMC calls ++ * @args: arguments passed via struct arm_smccc_1_2_regs ++ * @res: result values via struct arm_smccc_1_2_regs ++ * ++ * This function is used to make SMC calls following SMC Calling Convention ++ * v1.2 or above. The content of the supplied param are copied from the ++ * structure to registers prior to the SMC instruction. The return values ++ * are updated with the content from registers on return from the SMC ++ * instruction. ++ */ ++asmlinkage void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args, ++ struct arm_smccc_1_2_regs *res); ++#endif ++ + /** + * struct arm_smccc_quirk - Contains quirk information + * @id: quirk identification +diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h +new file mode 100644 +index 000000000000..85651e41ded8 +--- /dev/null ++++ b/include/linux/arm_ffa.h +@@ -0,0 +1,269 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2021 ARM Ltd. ++ */ ++ ++#ifndef _LINUX_ARM_FFA_H ++#define _LINUX_ARM_FFA_H ++ ++#include ++#include ++#include ++#include ++ ++/* FFA Bus/Device/Driver related */ ++struct ffa_device { ++ int vm_id; ++ bool mode_32bit; ++ uuid_t uuid; ++ struct device dev; ++}; ++ ++#define to_ffa_dev(d) container_of(d, struct ffa_device, dev) ++ ++struct ffa_device_id { ++ uuid_t uuid; ++}; ++ ++struct ffa_driver { ++ const char *name; ++ int (*probe)(struct ffa_device *sdev); ++ void (*remove)(struct ffa_device *sdev); ++ const struct ffa_device_id *id_table; ++ ++ struct device_driver driver; ++}; ++ ++#define to_ffa_driver(d) container_of(d, struct ffa_driver, driver) ++ ++static inline void ffa_dev_set_drvdata(struct ffa_device *fdev, void *data) ++{ ++ fdev->dev.driver_data = data; ++} ++ ++#if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT) ++struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id); ++void ffa_device_unregister(struct ffa_device *ffa_dev); ++int ffa_driver_register(struct ffa_driver *driver, struct module *owner, ++ const char *mod_name); ++void ffa_driver_unregister(struct ffa_driver *driver); ++bool ffa_device_is_valid(struct ffa_device *ffa_dev); ++const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev); ++ ++#else ++static inline ++struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) ++{ ++ return NULL; ++} ++ ++static inline void ffa_device_unregister(struct ffa_device *dev) {} ++ ++static inline int ++ffa_driver_register(struct ffa_driver *driver, struct module *owner, ++ const char *mod_name) ++{ ++ return -EINVAL; ++} ++ ++static inline void ffa_driver_unregister(struct ffa_driver *driver) {} ++ ++static inline ++bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } ++ ++static inline ++const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) ++{ ++ return NULL; ++} ++#endif /* CONFIG_ARM_FFA_TRANSPORT */ ++ ++#define ffa_register(driver) \ ++ ffa_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) ++#define ffa_unregister(driver) \ ++ ffa_driver_unregister(driver) ++ ++/** ++ * module_ffa_driver() - Helper macro for registering a psa_ffa driver ++ * @__ffa_driver: ffa_driver structure ++ * ++ * Helper macro for psa_ffa drivers to set up proper module init / exit ++ * functions. Replaces module_init() and module_exit() and keeps people from ++ * printing pointless things to the kernel log when their driver is loaded. ++ */ ++#define module_ffa_driver(__ffa_driver) \ ++ module_driver(__ffa_driver, ffa_register, ffa_unregister) ++ ++/* FFA transport related */ ++struct ffa_partition_info { ++ u16 id; ++ u16 exec_ctxt; ++/* partition supports receipt of direct requests */ ++#define FFA_PARTITION_DIRECT_RECV BIT(0) ++/* partition can send direct requests. */ ++#define FFA_PARTITION_DIRECT_SEND BIT(1) ++/* partition can send and receive indirect messages. */ ++#define FFA_PARTITION_INDIRECT_MSG BIT(2) ++ u32 properties; ++}; ++ ++/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */ ++struct ffa_send_direct_data { ++ unsigned long data0; /* w3/x3 */ ++ unsigned long data1; /* w4/x4 */ ++ unsigned long data2; /* w5/x5 */ ++ unsigned long data3; /* w6/x6 */ ++ unsigned long data4; /* w7/x7 */ ++}; ++ ++struct ffa_mem_region_addr_range { ++ /* The base IPA of the constituent memory region, aligned to 4 kiB */ ++ u64 address; ++ /* The number of 4 kiB pages in the constituent memory region. */ ++ u32 pg_cnt; ++ u32 reserved; ++}; ++ ++struct ffa_composite_mem_region { ++ /* ++ * The total number of 4 kiB pages included in this memory region. This ++ * must be equal to the sum of page counts specified in each ++ * `struct ffa_mem_region_addr_range`. ++ */ ++ u32 total_pg_cnt; ++ /* The number of constituents included in this memory region range */ ++ u32 addr_range_cnt; ++ u64 reserved; ++ /** An array of `addr_range_cnt` memory region constituents. */ ++ struct ffa_mem_region_addr_range constituents[]; ++}; ++ ++struct ffa_mem_region_attributes { ++ /* The ID of the VM to which the memory is being given or shared. */ ++ u16 receiver; ++ /* ++ * The permissions with which the memory region should be mapped in the ++ * receiver's page table. ++ */ ++#define FFA_MEM_EXEC BIT(3) ++#define FFA_MEM_NO_EXEC BIT(2) ++#define FFA_MEM_RW BIT(1) ++#define FFA_MEM_RO BIT(0) ++ u8 attrs; ++ /* ++ * Flags used during FFA_MEM_RETRIEVE_REQ and FFA_MEM_RETRIEVE_RESP ++ * for memory regions with multiple borrowers. ++ */ ++#define FFA_MEM_RETRIEVE_SELF_BORROWER BIT(0) ++ u8 flag; ++ u32 composite_off; ++ /* ++ * Offset in bytes from the start of the outer `ffa_memory_region` to ++ * an `struct ffa_mem_region_addr_range`. ++ */ ++ u64 reserved; ++}; ++ ++struct ffa_mem_region { ++ /* The ID of the VM/owner which originally sent the memory region */ ++ u16 sender_id; ++#define FFA_MEM_NORMAL BIT(5) ++#define FFA_MEM_DEVICE BIT(4) ++ ++#define FFA_MEM_WRITE_BACK (3 << 2) ++#define FFA_MEM_NON_CACHEABLE (1 << 2) ++ ++#define FFA_DEV_nGnRnE (0 << 2) ++#define FFA_DEV_nGnRE (1 << 2) ++#define FFA_DEV_nGRE (2 << 2) ++#define FFA_DEV_GRE (3 << 2) ++ ++#define FFA_MEM_NON_SHAREABLE (0) ++#define FFA_MEM_OUTER_SHAREABLE (2) ++#define FFA_MEM_INNER_SHAREABLE (3) ++ u8 attributes; ++ u8 reserved_0; ++/* ++ * Clear memory region contents after unmapping it from the sender and ++ * before mapping it for any receiver. ++ */ ++#define FFA_MEM_CLEAR BIT(0) ++/* ++ * Whether the hypervisor may time slice the memory sharing or retrieval ++ * operation. ++ */ ++#define FFA_TIME_SLICE_ENABLE BIT(1) ++ ++#define FFA_MEM_RETRIEVE_TYPE_IN_RESP (0 << 3) ++#define FFA_MEM_RETRIEVE_TYPE_SHARE (1 << 3) ++#define FFA_MEM_RETRIEVE_TYPE_LEND (2 << 3) ++#define FFA_MEM_RETRIEVE_TYPE_DONATE (3 << 3) ++ ++#define FFA_MEM_RETRIEVE_ADDR_ALIGN_HINT BIT(9) ++#define FFA_MEM_RETRIEVE_ADDR_ALIGN(x) ((x) << 5) ++ /* Flags to control behaviour of the transaction. */ ++ u32 flags; ++#define HANDLE_LOW_MASK GENMASK_ULL(31, 0) ++#define HANDLE_HIGH_MASK GENMASK_ULL(63, 32) ++#define HANDLE_LOW(x) ((u32)(FIELD_GET(HANDLE_LOW_MASK, (x)))) ++#define HANDLE_HIGH(x) ((u32)(FIELD_GET(HANDLE_HIGH_MASK, (x)))) ++ ++#define PACK_HANDLE(l, h) \ ++ (FIELD_PREP(HANDLE_LOW_MASK, (l)) | FIELD_PREP(HANDLE_HIGH_MASK, (h))) ++ /* ++ * A globally-unique ID assigned by the hypervisor for a region ++ * of memory being sent between VMs. ++ */ ++ u64 handle; ++ /* ++ * An implementation defined value associated with the receiver and the ++ * memory region. ++ */ ++ u64 tag; ++ u32 reserved_1; ++ /* ++ * The number of `ffa_mem_region_attributes` entries included in this ++ * transaction. ++ */ ++ u32 ep_count; ++ /* ++ * An array of endpoint memory access descriptors. ++ * Each one specifies a memory region offset, an endpoint and the ++ * attributes with which this memory region should be mapped in that ++ * endpoint's page table. ++ */ ++ struct ffa_mem_region_attributes ep_mem_access[]; ++}; ++ ++#define COMPOSITE_OFFSET(x) \ ++ (offsetof(struct ffa_mem_region, ep_mem_access[x])) ++#define CONSTITUENTS_OFFSET(x) \ ++ (offsetof(struct ffa_composite_mem_region, constituents[x])) ++#define COMPOSITE_CONSTITUENTS_OFFSET(x, y) \ ++ (COMPOSITE_OFFSET(x) + CONSTITUENTS_OFFSET(y)) ++ ++struct ffa_mem_ops_args { ++ bool use_txbuf; ++ u32 nattrs; ++ u32 flags; ++ u64 tag; ++ u64 g_handle; ++ struct scatterlist *sg; ++ struct ffa_mem_region_attributes *attrs; ++}; ++ ++struct ffa_dev_ops { ++ u32 (*api_version_get)(void); ++ int (*partition_info_get)(const char *uuid_str, ++ struct ffa_partition_info *buffer); ++ void (*mode_32bit_set)(struct ffa_device *dev); ++ int (*sync_send_receive)(struct ffa_device *dev, ++ struct ffa_send_direct_data *data); ++ int (*memory_reclaim)(u64 g_handle, u32 flags); ++ int (*memory_share)(struct ffa_device *dev, ++ struct ffa_mem_ops_args *args); ++ int (*memory_lend)(struct ffa_device *dev, ++ struct ffa_mem_ops_args *args); ++}; ++ ++#endif /* _LINUX_ARM_FFA_H */ +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0009-firmware-arm_ffa-Add-initial-FFA-bus-support-for-dev.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0009-firmware-arm_ffa-Add-initial-FFA-bus-support-for-dev.patch deleted file mode 100644 index fc53fccc..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0009-firmware-arm_ffa-Add-initial-FFA-bus-support-for-dev.patch +++ /dev/null @@ -1,420 +0,0 @@ -From 95591bf20e67a2f9635b7823baf7975946a630c2 Mon Sep 17 00:00:00 2001 -From: Sudeep Holla -Date: Fri, 30 Apr 2021 11:24:33 +0100 -Subject: [PATCH 09/22] firmware: arm_ffa: Add initial FFA bus support for - device enumeration - -The Arm FF for Armv8-A specification has concept of endpoints or -partitions. In the Normal world, a partition could be a VM when -the Virtualization extension is enabled or the kernel itself. - -In order to handle multiple partitions, we can create a FFA device for -each such partition on a dedicated FFA bus. Similarly, different drivers -requiring FFA transport can be registered on the same bus. We can match -the device and drivers using UUID. This is mostly for the in-kernel -users with FFA drivers. - -Signed-off-by: Sudeep Holla - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=6c31a912d7cf9042d80b24f431f0739d53a7262d] ---- - MAINTAINERS | 7 + - drivers/firmware/Kconfig | 1 + - drivers/firmware/Makefile | 1 + - drivers/firmware/arm_ffa/Kconfig | 16 +++ - drivers/firmware/arm_ffa/Makefile | 4 + - drivers/firmware/arm_ffa/bus.c | 207 ++++++++++++++++++++++++++++++ - include/linux/arm_ffa.h | 91 +++++++++++++ - 7 files changed, 327 insertions(+) - create mode 100644 drivers/firmware/arm_ffa/Kconfig - create mode 100644 drivers/firmware/arm_ffa/Makefile - create mode 100644 drivers/firmware/arm_ffa/bus.c - create mode 100644 include/linux/arm_ffa.h - -diff --git a/MAINTAINERS b/MAINTAINERS -index 5234423c477a..d5fdc9e68c89 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -6847,6 +6847,13 @@ F: include/linux/firewire.h - F: include/uapi/linux/firewire*.h - F: tools/firewire/ - -+FIRMWARE FRAMEWORK FOR ARMV8-A -+M: Sudeep Holla -+L: linux-arm-kernel@lists.infradead.org -+S: Maintained -+F: drivers/firmware/arm_ffa/ -+F: include/linux/arm_ffa.h -+ - FIRMWARE LOADER (request_firmware) - M: Luis Chamberlain - L: linux-kernel@vger.kernel.org -diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig -index bfef3d8d14e7..90e6dd32f2cd 100644 ---- a/drivers/firmware/Kconfig -+++ b/drivers/firmware/Kconfig -@@ -296,6 +296,7 @@ config TURRIS_MOX_RWTM - other manufacturing data and also utilize the Entropy Bit Generator - for hardware random number generation. - -+source "drivers/firmware/arm_ffa/Kconfig" - source "drivers/firmware/broadcom/Kconfig" - source "drivers/firmware/google/Kconfig" - source "drivers/firmware/efi/Kconfig" -diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile -index 523173cbff33..3c2af2e98def 100644 ---- a/drivers/firmware/Makefile -+++ b/drivers/firmware/Makefile -@@ -23,6 +23,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o - obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o - obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o - -+obj-y += arm_ffa/ - obj-y += arm_scmi/ - obj-y += broadcom/ - obj-y += meson/ -diff --git a/drivers/firmware/arm_ffa/Kconfig b/drivers/firmware/arm_ffa/Kconfig -new file mode 100644 -index 000000000000..261a3660650a ---- /dev/null -+++ b/drivers/firmware/arm_ffa/Kconfig -@@ -0,0 +1,16 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+config ARM_FFA_TRANSPORT -+ tristate "Arm Firmware Framework for Armv8-A" -+ depends on OF -+ depends on ARM64 -+ default n -+ help -+ This Firmware Framework(FF) for Arm A-profile processors describes -+ interfaces that standardize communication between the various -+ software images which includes communication between images in -+ the Secure world and Normal world. It also leverages the -+ virtualization extension to isolate software images provided -+ by an ecosystem of vendors from each other. -+ -+ This driver provides interface for all the client drivers making -+ use of the features offered by ARM FF-A. -diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile -new file mode 100644 -index 000000000000..bfe4323a8784 ---- /dev/null -+++ b/drivers/firmware/arm_ffa/Makefile -@@ -0,0 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ffa-bus-y = bus.o -+ffa-module-objs := $(ffa-bus-y) -+obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o -diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c -new file mode 100644 -index 000000000000..b743fb2256e9 ---- /dev/null -+++ b/drivers/firmware/arm_ffa/bus.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2020 ARM Ltd. -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int ffa_device_match(struct device *dev, struct device_driver *drv) -+{ -+ const struct ffa_device_id *id_table; -+ struct ffa_device *ffa_dev; -+ -+ id_table = to_ffa_driver(drv)->id_table; -+ ffa_dev = to_ffa_dev(dev); -+ -+ while (!uuid_is_null(&id_table->uuid)) { -+ if (uuid_equal(&ffa_dev->uuid, &id_table->uuid)) -+ return 1; -+ id_table++; -+ } -+ -+ return 0; -+} -+ -+static int ffa_device_probe(struct device *dev) -+{ -+ struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); -+ struct ffa_device *ffa_dev = to_ffa_dev(dev); -+ -+ if (!ffa_device_match(dev, dev->driver)) -+ return -ENODEV; -+ -+ return ffa_drv->probe(ffa_dev); -+} -+ -+static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env) -+{ -+ struct ffa_device *ffa_dev = to_ffa_dev(dev); -+ -+ return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb", -+ ffa_dev->vm_id, &ffa_dev->uuid); -+} -+ -+static ssize_t partition_id_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct ffa_device *ffa_dev = to_ffa_dev(dev); -+ -+ return sprintf(buf, "0x%04x\n", ffa_dev->vm_id); -+} -+static DEVICE_ATTR_RO(partition_id); -+ -+static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct ffa_device *ffa_dev = to_ffa_dev(dev); -+ -+ return sprintf(buf, "%pUb\n", &ffa_dev->uuid); -+} -+static DEVICE_ATTR_RO(uuid); -+ -+static struct attribute *ffa_device_attributes_attrs[] = { -+ &dev_attr_partition_id.attr, -+ &dev_attr_uuid.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(ffa_device_attributes); -+ -+struct bus_type ffa_bus_type = { -+ .name = "arm_ffa", -+ .match = ffa_device_match, -+ .probe = ffa_device_probe, -+ .uevent = ffa_device_uevent, -+ .dev_groups = ffa_device_attributes_groups, -+}; -+EXPORT_SYMBOL_GPL(ffa_bus_type); -+ -+int ffa_driver_register(struct ffa_driver *driver, struct module *owner, -+ const char *mod_name) -+{ -+ int ret; -+ -+ driver->driver.bus = &ffa_bus_type; -+ driver->driver.name = driver->name; -+ driver->driver.owner = owner; -+ driver->driver.mod_name = mod_name; -+ -+ ret = driver_register(&driver->driver); -+ if (!ret) -+ pr_debug("registered new ffa driver %s\n", driver->name); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(ffa_driver_register); -+ -+void ffa_driver_unregister(struct ffa_driver *driver) -+{ -+ driver_unregister(&driver->driver); -+} -+EXPORT_SYMBOL_GPL(ffa_driver_unregister); -+ -+static void ffa_release_device(struct device *dev) -+{ -+ struct ffa_device *ffa_dev = to_ffa_dev(dev); -+ -+ kfree(ffa_dev); -+} -+ -+static int __ffa_devices_unregister(struct device *dev, void *data) -+{ -+ ffa_release_device(dev); -+ -+ return 0; -+} -+ -+static void ffa_devices_unregister(void) -+{ -+ bus_for_each_dev(&ffa_bus_type, NULL, NULL, -+ __ffa_devices_unregister); -+} -+ -+bool ffa_device_is_valid(struct ffa_device *ffa_dev) -+{ -+ bool valid = false; -+ struct device *dev = NULL; -+ struct ffa_device *tmp_dev; -+ -+ do { -+ dev = bus_find_next_device(&ffa_bus_type, dev); -+ tmp_dev = to_ffa_dev(dev); -+ if (tmp_dev == ffa_dev) { -+ valid = true; -+ break; -+ } -+ put_device(dev); -+ } while (dev); -+ -+ put_device(dev); -+ -+ return valid; -+} -+ -+struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) -+{ -+ int ret; -+ struct device *dev; -+ struct ffa_device *ffa_dev; -+ -+ ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); -+ if (!ffa_dev) -+ return NULL; -+ -+ dev = &ffa_dev->dev; -+ dev->bus = &ffa_bus_type; -+ dev->release = ffa_release_device; -+ dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id); -+ -+ ffa_dev->vm_id = vm_id; -+ uuid_copy(&ffa_dev->uuid, uuid); -+ -+ ret = device_register(&ffa_dev->dev); -+ if (ret) { -+ dev_err(dev, "unable to register device %s err=%d\n", -+ dev_name(dev), ret); -+ put_device(dev); -+ return NULL; -+ } -+ -+ return ffa_dev; -+} -+EXPORT_SYMBOL_GPL(ffa_device_register); -+ -+void ffa_device_unregister(struct ffa_device *ffa_dev) -+{ -+ if (!ffa_dev) -+ return; -+ -+ device_unregister(&ffa_dev->dev); -+} -+EXPORT_SYMBOL_GPL(ffa_device_unregister); -+ -+static int __init arm_ffa_bus_init(void) -+{ -+ return bus_register(&ffa_bus_type); -+} -+module_init(arm_ffa_bus_init); -+ -+static void __exit arm_ffa_bus_exit(void) -+{ -+ ffa_devices_unregister(); -+ bus_unregister(&ffa_bus_type); -+} -+ -+module_exit(arm_ffa_bus_exit); -+ -+MODULE_ALIAS("arm-ffa-bus"); -+MODULE_AUTHOR("Sudeep Holla "); -+MODULE_DESCRIPTION("Arm FF-A bus driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h -new file mode 100644 -index 000000000000..aaff89364541 ---- /dev/null -+++ b/include/linux/arm_ffa.h -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Copyright (C) 2020 ARM Ltd. -+ */ -+ -+#ifndef _LINUX_ARM_FFA_H -+#define _LINUX_ARM_FFA_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* FFA Bus/Device/Driver related */ -+struct ffa_device { -+ int vm_id; -+ uuid_t uuid; -+ struct device dev; -+}; -+ -+#define to_ffa_dev(d) container_of(d, struct ffa_device, dev) -+ -+struct ffa_device_id { -+ uuid_t uuid; -+}; -+ -+struct ffa_driver { -+ const char *name; -+ int (*probe)(struct ffa_device *sdev); -+ void (*remove)(struct ffa_device *sdev); -+ const struct ffa_device_id *id_table; -+ -+ struct device_driver driver; -+}; -+ -+#define to_ffa_driver(d) container_of(d, struct ffa_driver, driver) -+ -+static inline void ffa_dev_set_drvdata(struct ffa_device *fdev, void *data) -+{ -+ fdev->dev.driver_data = data; -+} -+ -+#if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT) -+struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id); -+void ffa_device_unregister(struct ffa_device *ffa_dev); -+int ffa_driver_register(struct ffa_driver *driver, struct module *owner, -+ const char *mod_name); -+void ffa_driver_unregister(struct ffa_driver *driver); -+bool ffa_device_is_valid(struct ffa_device *ffa_dev); -+ -+#else -+static inline -+struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id) -+{ -+ return NULL; -+} -+ -+static inline void ffa_device_unregister(struct ffa_device *dev) {} -+ -+static inline int -+ffa_driver_register(struct ffa_driver *driver, struct module *owner, -+ const char *mod_name) -+{ -+ return -EINVAL; -+} -+ -+static inline void ffa_driver_unregister(struct ffa_driver *driver) {} -+ -+static inline -+bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } -+ -+#endif /* CONFIG_ARM_FFA_TRANSPORT */ -+ -+#define ffa_register(driver) \ -+ ffa_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) -+#define ffa_unregister(driver) \ -+ ffa_driver_unregister(driver) -+ -+/** -+ * module_ffa_driver() - Helper macro for registering a psa_ffa driver -+ * @__ffa_driver: ffa_driver structure -+ * -+ * Helper macro for psa_ffa drivers to set up proper module init / exit -+ * functions. Replaces module_init() and module_exit() and keeps people from -+ * printing pointless things to the kernel log when their driver is loaded. -+ */ -+#define module_ffa_driver(__ffa_driver) \ -+ module_driver(__ffa_driver, ffa_register, ffa_unregister) -+ -+#endif /* _LINUX_ARM_FFA_H */ --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0014-tee-add-sec_world_id-to-struct-tee_shm.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0009-tee-add-sec_world_id-to-struct-tee_shm.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0014-tee-add-sec_world_id-to-struct-tee_shm.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0009-tee-add-sec_world_id-to-struct-tee_shm.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0010-firmware-arm_ffa-Add-initial-Arm-FFA-driver-support.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0010-firmware-arm_ffa-Add-initial-Arm-FFA-driver-support.patch deleted file mode 100644 index 7bba11c3..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0010-firmware-arm_ffa-Add-initial-Arm-FFA-driver-support.patch +++ /dev/null @@ -1,415 +0,0 @@ -From b81111a9cdfc182fb0ee5f219ab16710cd9146cd Mon Sep 17 00:00:00 2001 -From: Sudeep Holla -Date: Fri, 30 Apr 2021 11:24:39 +0100 -Subject: [PATCH 10/22] firmware: arm_ffa: Add initial Arm FFA driver support - -This just add a basic driver that sets up the transport(e.g. SMCCC), -checks the FFA version implemented, get the partition ID for self and -sets up the Tx/Rx buffers for communication. - -Signed-off-by: Sudeep Holla - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=13201f9a97be567e8c18fec5e357561f41d9b5f6] ---- - drivers/firmware/arm_ffa/Makefile | 3 +- - drivers/firmware/arm_ffa/bus.c | 14 +- - drivers/firmware/arm_ffa/common.h | 24 +++ - drivers/firmware/arm_ffa/driver.c | 307 ++++++++++++++++++++++++++++++ - 4 files changed, 337 insertions(+), 11 deletions(-) - create mode 100644 drivers/firmware/arm_ffa/common.h - create mode 100644 drivers/firmware/arm_ffa/driver.c - -diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile -index bfe4323a8784..82d0d35c5324 100644 ---- a/drivers/firmware/arm_ffa/Makefile -+++ b/drivers/firmware/arm_ffa/Makefile -@@ -1,4 +1,5 @@ - # SPDX-License-Identifier: GPL-2.0-only - ffa-bus-y = bus.o --ffa-module-objs := $(ffa-bus-y) -+ffa-driver-y = driver.o -+ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) - obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o -diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c -index b743fb2256e9..58441266e60d 100644 ---- a/drivers/firmware/arm_ffa/bus.c -+++ b/drivers/firmware/arm_ffa/bus.c -@@ -13,6 +13,8 @@ - #include - #include - -+#include "common.h" -+ - static int ffa_device_match(struct device *dev, struct device_driver *drv) - { - const struct ffa_device_id *id_table; -@@ -187,21 +189,13 @@ void ffa_device_unregister(struct ffa_device *ffa_dev) - } - EXPORT_SYMBOL_GPL(ffa_device_unregister); - --static int __init arm_ffa_bus_init(void) -+int __init arm_ffa_bus_init(void) - { - return bus_register(&ffa_bus_type); - } --module_init(arm_ffa_bus_init); - --static void __exit arm_ffa_bus_exit(void) -+void __exit arm_ffa_bus_exit(void) - { - ffa_devices_unregister(); - bus_unregister(&ffa_bus_type); - } -- --module_exit(arm_ffa_bus_exit); -- --MODULE_ALIAS("arm-ffa-bus"); --MODULE_AUTHOR("Sudeep Holla "); --MODULE_DESCRIPTION("Arm FF-A bus driver"); --MODULE_LICENSE("GPL v2"); -diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h -new file mode 100644 -index 000000000000..9195f66f826c ---- /dev/null -+++ b/drivers/firmware/arm_ffa/common.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2020 ARM Ltd. -+ */ -+ -+#ifndef _FFA_COMMON_H -+#define _FFA_COMMON_H -+ -+#include -+#include -+ -+typedef struct arm_smccc_1_2_regs ffa_value_t; -+ -+typedef void (ffa_fn)(ffa_value_t, ffa_value_t *); -+ -+int __init arm_ffa_bus_init(void); -+void __exit arm_ffa_bus_exit(void); -+ -+static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) -+{ -+ return -EOPNOTSUPP; -+} -+ -+#endif /* _FFA_COMMON_H */ -diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c -new file mode 100644 -index 000000000000..d74f03b773d2 ---- /dev/null -+++ b/drivers/firmware/arm_ffa/driver.c -@@ -0,0 +1,307 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Arm Firmware Framework for ARMv8-A(FFA) interface driver -+ * -+ * The Arm FFA specification[1] describes a software architecture to -+ * leverages the virtualization extension to isolate software images -+ * provided by an ecosystem of vendors from each other and describes -+ * interfaces that standardize communication between the various software -+ * images including communication between images in the Secure world and -+ * Normal world. Any Hypervisor could use the FFA interfaces to enable -+ * communication between VMs it manages. -+ * -+ * The Hypervisor a.k.a Partition managers in FFA terminology can assign -+ * system resources(Memory regions, Devices, CPU cycles) to the partitions -+ * and manage isolation amongst them. -+ * -+ * [1] https://developer.arm.com/docs/den0077/latest -+ * -+ * Copyright (C) 2020 Arm Ltd. -+ */ -+ -+#define DRIVER_NAME "ARM FF-A" -+#define pr_fmt(fmt) DRIVER_NAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+ -+#define FFA_DRIVER_VERSION FFA_VERSION_1_0 -+ -+#define FFA_SMC(calling_convention, func_num) \ -+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \ -+ ARM_SMCCC_OWNER_STANDARD, (func_num)) -+ -+#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num)) -+#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num)) -+ -+#define FFA_ERROR FFA_SMC_32(0x60) -+#define FFA_SUCCESS FFA_SMC_32(0x61) -+#define FFA_INTERRUPT FFA_SMC_32(0x62) -+#define FFA_VERSION FFA_SMC_32(0x63) -+#define FFA_FEATURES FFA_SMC_32(0x64) -+#define FFA_RX_RELEASE FFA_SMC_32(0x65) -+#define FFA_RXTX_MAP FFA_SMC_32(0x66) -+#define FFA_FN64_RXTX_MAP FFA_SMC_64(0x66) -+#define FFA_RXTX_UNMAP FFA_SMC_32(0x67) -+#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68) -+#define FFA_ID_GET FFA_SMC_32(0x69) -+#define FFA_MSG_POLL FFA_SMC_32(0x6A) -+#define FFA_MSG_WAIT FFA_SMC_32(0x6B) -+#define FFA_YIELD FFA_SMC_32(0x6C) -+#define FFA_RUN FFA_SMC_32(0x6D) -+#define FFA_MSG_SEND FFA_SMC_32(0x6E) -+#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F) -+#define FFA_FN64_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F) -+#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70) -+#define FFA_FN64_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70) -+#define FFA_MEM_DONATE FFA_SMC_32(0x71) -+#define FFA_FN64_MEM_DONATE FFA_SMC_64(0x71) -+#define FFA_MEM_LEND FFA_SMC_32(0x72) -+#define FFA_FN64_MEM_LEND FFA_SMC_64(0x72) -+#define FFA_MEM_SHARE FFA_SMC_32(0x73) -+#define FFA_FN64_MEM_SHARE FFA_SMC_64(0x73) -+#define FFA_MEM_RETRIEVE_REQ FFA_SMC_32(0x74) -+#define FFA_FN64_MEM_RETRIEVE_REQ FFA_SMC_64(0x74) -+#define FFA_MEM_RETRIEVE_RESP FFA_SMC_32(0x75) -+#define FFA_MEM_RELINQUISH FFA_SMC_32(0x76) -+#define FFA_MEM_RECLAIM FFA_SMC_32(0x77) -+#define FFA_MEM_OP_PAUSE FFA_SMC_32(0x78) -+#define FFA_MEM_OP_RESUME FFA_SMC_32(0x79) -+#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A) -+#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B) -+#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C) -+ -+/* -+ * For some calls it is necessary to use SMC64 to pass or return 64-bit values. -+ * For such calls FFA_FN_NATIVE(name) will choose the appropriate -+ * (native-width) function ID. -+ */ -+#ifdef CONFIG_64BIT -+#define FFA_FN_NATIVE(name) FFA_FN64_##name -+#else -+#define FFA_FN_NATIVE(name) FFA_##name -+#endif -+ -+/* FFA error codes. */ -+#define FFA_RET_SUCCESS (0) -+#define FFA_RET_NOT_SUPPORTED (-1) -+#define FFA_RET_INVALID_PARAMETERS (-2) -+#define FFA_RET_NO_MEMORY (-3) -+#define FFA_RET_BUSY (-4) -+#define FFA_RET_INTERRUPTED (-5) -+#define FFA_RET_DENIED (-6) -+#define FFA_RET_RETRY (-7) -+#define FFA_RET_ABORTED (-8) -+ -+#define MAJOR_VERSION_MASK GENMASK(30, 16) -+#define MINOR_VERSION_MASK GENMASK(15, 0) -+#define MAJOR_VERSION(x) ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x)))) -+#define MINOR_VERSION(x) ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x)))) -+#define PACK_VERSION_INFO(major, minor) \ -+ (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \ -+ FIELD_PREP(MINOR_VERSION_MASK, (minor))) -+#define FFA_VERSION_1_0 PACK_VERSION_INFO(1, 0) -+#define FFA_MIN_VERSION FFA_VERSION_1_0 -+ -+#define SENDER_ID_MASK GENMASK(31, 16) -+#define RECEIVER_ID_MASK GENMASK(15, 0) -+#define SENDER_ID(x) ((u16)(FIELD_GET(SENDER_ID_MASK, (x)))) -+#define RECEIVER_ID(x) ((u16)(FIELD_GET(RECEIVER_ID_MASK, (x)))) -+#define PACK_TARGET_INFO(s, r) \ -+ (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r))) -+ -+/** -+ * FF-A specification mentions explicitly about '4K pages'. This should -+ * not be confused with the kernel PAGE_SIZE, which is the translation -+ * granule kernel is configured and may be one among 4K, 16K and 64K. -+ */ -+#define FFA_PAGE_SIZE SZ_4K -+/* -+ * Keeping RX TX buffer size as 4K for now -+ * 64K may be preferred to keep it min a page in 64K PAGE_SIZE config -+ */ -+#define RXTX_BUFFER_SIZE SZ_4K -+ -+static ffa_fn *invoke_ffa_fn; -+ -+static const int ffa_linux_errmap[] = { -+ /* better than switch case as long as return value is continuous */ -+ 0, /* FFA_RET_SUCCESS */ -+ -EOPNOTSUPP, /* FFA_RET_NOT_SUPPORTED */ -+ -EINVAL, /* FFA_RET_INVALID_PARAMETERS */ -+ -ENOMEM, /* FFA_RET_NO_MEMORY */ -+ -EBUSY, /* FFA_RET_BUSY */ -+ -EINTR, /* FFA_RET_INTERRUPTED */ -+ -EACCES, /* FFA_RET_DENIED */ -+ -EAGAIN, /* FFA_RET_RETRY */ -+ -ECANCELED, /* FFA_RET_ABORTED */ -+}; -+ -+static inline int ffa_to_linux_errno(int errno) -+{ -+ if (errno < FFA_RET_SUCCESS && errno >= -ARRAY_SIZE(ffa_linux_errmap)) -+ return ffa_linux_errmap[-errno]; -+ return -EINVAL; -+} -+ -+struct ffa_drv_info { -+ u32 version; -+ u16 vm_id; -+ struct mutex rx_lock; /* lock to protect Rx buffer */ -+ struct mutex tx_lock; /* lock to protect Tx buffer */ -+ void *rx_buffer; -+ void *tx_buffer; -+}; -+ -+static struct ffa_drv_info *drv_info; -+ -+static int ffa_version_check(u32 *version) -+{ -+ ffa_value_t ver; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_VERSION, .a1 = FFA_DRIVER_VERSION, -+ }, &ver); -+ -+ if (ver.a0 == FFA_RET_NOT_SUPPORTED) { -+ pr_info("FFA_VERSION returned not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) { -+ pr_err("Incompatible version %d.%d found\n", -+ MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0)); -+ return -EINVAL; -+ } -+ -+ *version = ver.a0; -+ pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0), -+ MINOR_VERSION(ver.a0)); -+ return 0; -+} -+ -+static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt) -+{ -+ ffa_value_t ret; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_FN_NATIVE(RXTX_MAP), -+ .a1 = tx_buf, .a2 = rx_buf, .a3 = pg_cnt, -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ return 0; -+} -+ -+static int ffa_rxtx_unmap(u16 vm_id) -+{ -+ ffa_value_t ret; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_RXTX_UNMAP, .a1 = PACK_TARGET_INFO(vm_id, 0), -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ return 0; -+} -+ -+#define VM_ID_MASK GENMASK(15, 0) -+static int ffa_id_get(u16 *vm_id) -+{ -+ ffa_value_t id; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_ID_GET, -+ }, &id); -+ -+ if (id.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)id.a2); -+ -+ *vm_id = FIELD_GET(VM_ID_MASK, (id.a2)); -+ -+ return 0; -+} -+ -+static int __init ffa_init(void) -+{ -+ int ret; -+ -+ ret = arm_ffa_bus_init(); -+ if (ret) -+ return ret; -+ -+ ret = ffa_transport_init(&invoke_ffa_fn); -+ if (ret) -+ return ret; -+ -+ drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL); -+ if (!drv_info) -+ return -ENOMEM; -+ -+ ret = ffa_version_check(&drv_info->version); -+ if (ret) -+ goto free_drv_info; -+ -+ if (ffa_id_get(&drv_info->vm_id)) { -+ pr_err("failed to obtain VM id for self\n"); -+ ret = -ENODEV; -+ goto free_drv_info; -+ } -+ -+ drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); -+ if (!drv_info->rx_buffer) { -+ ret = -ENOMEM; -+ goto free_pages; -+ } -+ -+ drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); -+ if (!drv_info->tx_buffer) { -+ ret = -ENOMEM; -+ goto free_pages; -+ } -+ -+ ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), -+ virt_to_phys(drv_info->rx_buffer), -+ RXTX_BUFFER_SIZE / FFA_PAGE_SIZE); -+ if (ret) { -+ pr_err("failed to register FFA RxTx buffers\n"); -+ goto free_pages; -+ } -+ -+ mutex_init(&drv_info->rx_lock); -+ mutex_init(&drv_info->tx_lock); -+ -+ return 0; -+free_pages: -+ if (drv_info->tx_buffer) -+ free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); -+ free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); -+free_drv_info: -+ kfree(drv_info); -+ return ret; -+} -+module_init(ffa_init); -+ -+static void __exit ffa_exit(void) -+{ -+ ffa_rxtx_unmap(drv_info->vm_id); -+ free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); -+ free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); -+ kfree(drv_info); -+ arm_ffa_bus_exit(); -+} -+module_exit(ffa_exit); -+ -+MODULE_ALIAS("arm-ffa"); -+MODULE_AUTHOR("Sudeep Holla "); -+MODULE_DESCRIPTION("Arm FF-A interface driver"); -+MODULE_LICENSE("GPL v2"); --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0015-optee-simplify-optee_release.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0010-optee-simplify-optee_release.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0015-optee-simplify-optee_release.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0010-optee-simplify-optee_release.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0011-firmware-arm_ffa-Add-support-for-SMCCC-as-transport-.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0011-firmware-arm_ffa-Add-support-for-SMCCC-as-transport-.patch deleted file mode 100644 index d62c4b62..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0011-firmware-arm_ffa-Add-support-for-SMCCC-as-transport-.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 22b6c0e78b031f97af093f4d2b26984c42cf4c22 Mon Sep 17 00:00:00 2001 -From: Sudeep Holla -Date: Fri, 30 Apr 2021 11:24:43 +0100 -Subject: [PATCH 11/22] firmware: arm_ffa: Add support for SMCCC as transport - to FFA driver - -There are requests to keep the transport separate in order to allow -other possible transports like virtio. So let us keep the SMCCC transport -specific routines abstracted. - -It is kept simple for now. Once we add another transport, we can develop -better abstraction. - -Signed-off-by: Sudeep Holla - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=ba0c60e85cb3773a9e172425bd14d76cf9d6e67b] ---- - drivers/firmware/arm_ffa/Kconfig | 5 ++++ - drivers/firmware/arm_ffa/Makefile | 3 ++- - drivers/firmware/arm_ffa/common.h | 4 ++++ - drivers/firmware/arm_ffa/smccc.c | 39 +++++++++++++++++++++++++++++++ - 4 files changed, 50 insertions(+), 1 deletion(-) - create mode 100644 drivers/firmware/arm_ffa/smccc.c - -diff --git a/drivers/firmware/arm_ffa/Kconfig b/drivers/firmware/arm_ffa/Kconfig -index 261a3660650a..5e3ae5cf82e8 100644 ---- a/drivers/firmware/arm_ffa/Kconfig -+++ b/drivers/firmware/arm_ffa/Kconfig -@@ -14,3 +14,8 @@ config ARM_FFA_TRANSPORT - - This driver provides interface for all the client drivers making - use of the features offered by ARM FF-A. -+ -+config ARM_FFA_SMCCC -+ bool -+ default ARM_FFA_TRANSPORT -+ depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY -diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile -index 82d0d35c5324..9d9f37523200 100644 ---- a/drivers/firmware/arm_ffa/Makefile -+++ b/drivers/firmware/arm_ffa/Makefile -@@ -1,5 +1,6 @@ - # SPDX-License-Identifier: GPL-2.0-only - ffa-bus-y = bus.o - ffa-driver-y = driver.o --ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) -+ffa-transport-$(CONFIG_ARM_FFA_SMCCC) += smccc.o -+ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) $(ffa-transport-y) - obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o -diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h -index 9195f66f826c..842451666827 100644 ---- a/drivers/firmware/arm_ffa/common.h -+++ b/drivers/firmware/arm_ffa/common.h -@@ -16,9 +16,13 @@ typedef void (ffa_fn)(ffa_value_t, ffa_value_t *); - int __init arm_ffa_bus_init(void); - void __exit arm_ffa_bus_exit(void); - -+#ifdef CONFIG_ARM_FFA_SMCCC -+int __init ffa_transport_init(ffa_fn **invoke_ffa_fn); -+#else - static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) - { - return -EOPNOTSUPP; - } -+#endif - - #endif /* _FFA_COMMON_H */ -diff --git a/drivers/firmware/arm_ffa/smccc.c b/drivers/firmware/arm_ffa/smccc.c -new file mode 100644 -index 000000000000..22c34b788769 ---- /dev/null -+++ b/drivers/firmware/arm_ffa/smccc.c -@@ -0,0 +1,39 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (C) 2020 ARM Ltd. -+ */ -+ -+#include -+ -+#include "common.h" -+ -+static void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res) -+{ -+ arm_smccc_1_2_smc(&args, res); -+} -+ -+static void __arm_ffa_fn_hvc(ffa_value_t args, ffa_value_t *res) -+{ -+ arm_smccc_1_2_hvc(&args, res); -+} -+ -+int __init ffa_transport_init(ffa_fn **invoke_ffa_fn) -+{ -+ enum arm_smccc_conduit conduit; -+ -+ if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2) -+ return -EOPNOTSUPP; -+ -+ conduit = arm_smccc_1_1_get_conduit(); -+ if (conduit == SMCCC_CONDUIT_NONE) { -+ pr_err("%s: invalid SMCCC conduit\n", __func__); -+ return -EOPNOTSUPP; -+ } -+ -+ if (conduit == SMCCC_CONDUIT_SMC) -+ *invoke_ffa_fn = __arm_ffa_fn_smc; -+ else -+ *invoke_ffa_fn = __arm_ffa_fn_hvc; -+ -+ return 0; -+} --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0016-optee-sync-OP-TEE-headers.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0011-optee-sync-OP-TEE-headers.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0016-optee-sync-OP-TEE-headers.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0011-optee-sync-OP-TEE-headers.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0012-firmware-arm_ffa-Setup-in-kernel-users-of-FFA-partit.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0012-firmware-arm_ffa-Setup-in-kernel-users-of-FFA-partit.patch deleted file mode 100644 index c747642e..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0012-firmware-arm_ffa-Setup-in-kernel-users-of-FFA-partit.patch +++ /dev/null @@ -1,398 +0,0 @@ -From c3da0efebc33b357c9fcf4c748c14167594e5c01 Mon Sep 17 00:00:00 2001 -From: Sudeep Holla -Date: Fri, 30 Apr 2021 11:24:48 +0100 -Subject: [PATCH 12/22] firmware: arm_ffa: Setup in-kernel users of FFA - partitions - -Parse the FFA nodes from the device-tree and register all the partitions -whose services will be used in the kernel. - -In order to also enable in-kernel users of FFA interface, let us add -simple set of operations for such devices. - -The in-kernel users are registered without the character device interface. - -Signed-off-by: Sudeep Holla - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=f9a344783c03e17cf58f9846e5f689cd5233a844] ---- - drivers/firmware/arm_ffa/bus.c | 9 ++ - drivers/firmware/arm_ffa/common.h | 3 + - drivers/firmware/arm_ffa/driver.c | 213 ++++++++++++++++++++++++++++++ - include/linux/arm_ffa.h | 38 +++++- - 4 files changed, 262 insertions(+), 1 deletion(-) - -diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c -index 58441266e60d..da23100c2e39 100644 ---- a/drivers/firmware/arm_ffa/bus.c -+++ b/drivers/firmware/arm_ffa/bus.c -@@ -24,6 +24,15 @@ static int ffa_device_match(struct device *dev, struct device_driver *drv) - ffa_dev = to_ffa_dev(dev); - - while (!uuid_is_null(&id_table->uuid)) { -+ /* -+ * FF-A v1.0 doesn't provide discovery of UUIDs, just the -+ * partition IDs, so fetch the partitions IDs for this -+ * id_table UUID and assign the UUID to the device if the -+ * partition ID matches -+ */ -+ if (uuid_is_null(&ffa_dev->uuid)) -+ ffa_device_match_uuid(ffa_dev, &id_table->uuid); -+ - if (uuid_equal(&ffa_dev->uuid, &id_table->uuid)) - return 1; - id_table++; -diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h -index 842451666827..80ad71f02235 100644 ---- a/drivers/firmware/arm_ffa/common.h -+++ b/drivers/firmware/arm_ffa/common.h -@@ -6,6 +6,7 @@ - #ifndef _FFA_COMMON_H - #define _FFA_COMMON_H - -+#include - #include - #include - -@@ -15,6 +16,8 @@ typedef void (ffa_fn)(ffa_value_t, ffa_value_t *); - - int __init arm_ffa_bus_init(void); - void __exit arm_ffa_bus_exit(void); -+bool ffa_device_is_valid(struct ffa_device *ffa_dev); -+void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid); - - #ifdef CONFIG_ARM_FFA_SMCCC - int __init ffa_transport_init(ffa_fn **invoke_ffa_fn); -diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c -index d74f03b773d2..cefbb3edf142 100644 ---- a/drivers/firmware/arm_ffa/driver.c -+++ b/drivers/firmware/arm_ffa/driver.c -@@ -24,9 +24,12 @@ - - #include - #include -+#include - #include -+#include - #include - #include -+#include - - #include "common.h" - -@@ -185,6 +188,22 @@ static int ffa_version_check(u32 *version) - return 0; - } - -+static int ffa_rx_release(void) -+{ -+ ffa_value_t ret; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_RX_RELEASE, -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ /* check for ret.a0 == FFA_RX_RELEASE ? */ -+ -+ return 0; -+} -+ - static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt) - { - ffa_value_t ret; -@@ -214,6 +233,64 @@ static int ffa_rxtx_unmap(u16 vm_id) - return 0; - } - -+/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */ -+static int -+__ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, -+ struct ffa_partition_info *buffer, int num_partitions) -+{ -+ int count; -+ ffa_value_t partition_info; -+ -+ mutex_lock(&drv_info->rx_lock); -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_PARTITION_INFO_GET, -+ .a1 = uuid0, .a2 = uuid1, .a3 = uuid2, .a4 = uuid3, -+ }, &partition_info); -+ -+ if (partition_info.a0 == FFA_ERROR) { -+ mutex_unlock(&drv_info->rx_lock); -+ return ffa_to_linux_errno((int)partition_info.a2); -+ } -+ -+ count = partition_info.a2; -+ -+ if (buffer && count <= num_partitions) -+ memcpy(buffer, drv_info->rx_buffer, sizeof(*buffer) * count); -+ -+ ffa_rx_release(); -+ -+ mutex_unlock(&drv_info->rx_lock); -+ -+ return count; -+} -+ -+/* buffer is allocated and caller must free the same if returned count > 0 */ -+static int -+ffa_partition_probe(const uuid_t *uuid, struct ffa_partition_info **buffer) -+{ -+ int count; -+ u32 uuid0_4[4]; -+ struct ffa_partition_info *pbuf; -+ -+ export_uuid((u8 *)uuid0_4, uuid); -+ count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], -+ uuid0_4[3], NULL, 0); -+ if (count <= 0) -+ return count; -+ -+ pbuf = kcalloc(count, sizeof(*pbuf), GFP_KERNEL); -+ if (!pbuf) -+ return -ENOMEM; -+ -+ count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], -+ uuid0_4[3], pbuf, count); -+ if (count <= 0) -+ kfree(pbuf); -+ -+ *buffer = pbuf; -+ return count; -+} -+ - #define VM_ID_MASK GENMASK(15, 0) - static int ffa_id_get(u16 *vm_id) - { -@@ -231,6 +308,140 @@ static int ffa_id_get(u16 *vm_id) - return 0; - } - -+static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, -+ struct ffa_send_direct_data *data) -+{ -+ u32 req_id, resp_id, src_dst_ids = PACK_TARGET_INFO(src_id, dst_id); -+ ffa_value_t ret; -+ -+ if (mode_32bit) { -+ req_id = FFA_MSG_SEND_DIRECT_REQ; -+ resp_id = FFA_MSG_SEND_DIRECT_RESP; -+ } else { -+ req_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_REQ); -+ resp_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_RESP); -+ } -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = req_id, .a1 = src_dst_ids, .a2 = 0, -+ .a3 = data->data0, .a4 = data->data1, .a5 = data->data2, -+ .a6 = data->data3, .a7 = data->data4, -+ }, &ret); -+ -+ while (ret.a0 == FFA_INTERRUPT) -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_RUN, .a1 = ret.a1, -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ if (ret.a0 == resp_id) { -+ data->data0 = ret.a3; -+ data->data1 = ret.a4; -+ data->data2 = ret.a5; -+ data->data3 = ret.a6; -+ data->data4 = ret.a7; -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static u32 ffa_api_version_get(void) -+{ -+ return drv_info->version; -+} -+ -+static int ffa_partition_info_get(const char *uuid_str, -+ struct ffa_partition_info *buffer) -+{ -+ int count; -+ uuid_t uuid; -+ struct ffa_partition_info *pbuf; -+ -+ if (uuid_parse(uuid_str, &uuid)) { -+ pr_err("invalid uuid (%s)\n", uuid_str); -+ return -ENODEV; -+ } -+ -+ count = ffa_partition_probe(&uuid_null, &pbuf); -+ if (count <= 0) -+ return -ENOENT; -+ -+ memcpy(buffer, pbuf, sizeof(*pbuf) * count); -+ kfree(pbuf); -+ return 0; -+} -+ -+static void ffa_mode_32bit_set(struct ffa_device *dev) -+{ -+ dev->mode_32bit = true; -+} -+ -+static int ffa_sync_send_receive(struct ffa_device *dev, -+ struct ffa_send_direct_data *data) -+{ -+ return ffa_msg_send_direct_req(drv_info->vm_id, dev->vm_id, -+ dev->mode_32bit, data); -+} -+ -+static const struct ffa_dev_ops ffa_ops = { -+ .api_version_get = ffa_api_version_get, -+ .partition_info_get = ffa_partition_info_get, -+ .mode_32bit_set = ffa_mode_32bit_set, -+ .sync_send_receive = ffa_sync_send_receive, -+}; -+ -+const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) -+{ -+ if (ffa_device_is_valid(dev)) -+ return &ffa_ops; -+ -+ return NULL; -+} -+EXPORT_SYMBOL_GPL(ffa_dev_ops_get); -+ -+void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) -+{ -+ int count, idx; -+ struct ffa_partition_info *pbuf, *tpbuf; -+ -+ count = ffa_partition_probe(uuid, &pbuf); -+ if (count <= 0) -+ return; -+ -+ for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) -+ if (tpbuf->id == ffa_dev->vm_id) -+ uuid_copy(&ffa_dev->uuid, uuid); -+ kfree(pbuf); -+} -+ -+static void ffa_setup_partitions(void) -+{ -+ int count, idx; -+ struct ffa_device *ffa_dev; -+ struct ffa_partition_info *pbuf, *tpbuf; -+ -+ count = ffa_partition_probe(&uuid_null, &pbuf); -+ if (count <= 0) { -+ pr_info("%s: No partitions found, error %d\n", __func__, count); -+ return; -+ } -+ -+ for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) { -+ ffa_dev = ffa_device_register(&uuid_null, tpbuf->id); -+ if (!ffa_dev) { -+ pr_err("%s: failed to register partition ID 0x%x\n", -+ __func__, tpbuf->id); -+ continue; -+ } -+ -+ ffa_dev_set_drvdata(ffa_dev, drv_info); -+ } -+ kfree(pbuf); -+} -+ - static int __init ffa_init(void) - { - int ret; -@@ -280,6 +491,8 @@ static int __init ffa_init(void) - mutex_init(&drv_info->rx_lock); - mutex_init(&drv_info->tx_lock); - -+ ffa_setup_partitions(); -+ - return 0; - free_pages: - if (drv_info->tx_buffer) -diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h -index aaff89364541..b242fbbce4f0 100644 ---- a/include/linux/arm_ffa.h -+++ b/include/linux/arm_ffa.h -@@ -6,7 +6,6 @@ - #ifndef _LINUX_ARM_FFA_H - #define _LINUX_ARM_FFA_H - --#include - #include - #include - #include -@@ -15,6 +14,7 @@ - /* FFA Bus/Device/Driver related */ - struct ffa_device { - int vm_id; -+ bool mode_32bit; - uuid_t uuid; - struct device dev; - }; -@@ -48,6 +48,7 @@ int ffa_driver_register(struct ffa_driver *driver, struct module *owner, - const char *mod_name); - void ffa_driver_unregister(struct ffa_driver *driver); - bool ffa_device_is_valid(struct ffa_device *ffa_dev); -+const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev); - - #else - static inline -@@ -70,6 +71,10 @@ static inline void ffa_driver_unregister(struct ffa_driver *driver) {} - static inline - bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } - -+const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) -+{ -+ return NULL; -+} - #endif /* CONFIG_ARM_FFA_TRANSPORT */ - - #define ffa_register(driver) \ -@@ -88,4 +93,35 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } - #define module_ffa_driver(__ffa_driver) \ - module_driver(__ffa_driver, ffa_register, ffa_unregister) - -+/* FFA transport related */ -+struct ffa_partition_info { -+ u16 id; -+ u16 exec_ctxt; -+/* partition supports receipt of direct requests */ -+#define FFA_PARTITION_DIRECT_RECV BIT(0) -+/* partition can send direct requests. */ -+#define FFA_PARTITION_DIRECT_SEND BIT(1) -+/* partition can send and receive indirect messages. */ -+#define FFA_PARTITION_INDIRECT_MSG BIT(2) -+ u32 properties; -+}; -+ -+/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */ -+struct ffa_send_direct_data { -+ unsigned long data0; /* w3/x3 */ -+ unsigned long data1; /* w4/x4 */ -+ unsigned long data2; /* w5/x5 */ -+ unsigned long data3; /* w6/x6 */ -+ unsigned long data4; /* w7/x7 */ -+}; -+ -+struct ffa_dev_ops { -+ u32 (*api_version_get)(void); -+ int (*partition_info_get)(const char *uuid_str, -+ struct ffa_partition_info *buffer); -+ void (*mode_32bit_set)(struct ffa_device *dev); -+ int (*sync_send_receive)(struct ffa_device *dev, -+ struct ffa_send_direct_data *data); -+}; -+ - #endif /* _LINUX_ARM_FFA_H */ --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0017-optee-refactor-driver-with-internal-callbacks.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0012-optee-refactor-driver-with-internal-callbacks.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0017-optee-refactor-driver-with-internal-callbacks.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0012-optee-refactor-driver-with-internal-callbacks.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0013-firmware-arm_ffa-Add-support-for-MEM_-interfaces.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0013-firmware-arm_ffa-Add-support-for-MEM_-interfaces.patch deleted file mode 100644 index 897ba0a2..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0013-firmware-arm_ffa-Add-support-for-MEM_-interfaces.patch +++ /dev/null @@ -1,406 +0,0 @@ -From f4b26dbe513b342f8774810f91d526f545a7202d Mon Sep 17 00:00:00 2001 -From: Sudeep Holla -Date: Fri, 30 Apr 2021 11:24:51 +0100 -Subject: [PATCH 13/22] firmware: arm_ffa: Add support for MEM_* interfaces - -Most of the MEM_* APIs share the same parameters, so they can be -generalised. Currently only MEM_SHARE is implemented and the user space -interface for that is not added yet. - -Signed-off-by: Sudeep Holla - -Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=v5.10/ffa&id=f27cbd0b3f83cb40ff7385f00d05afe1be7577b2] ---- - drivers/firmware/arm_ffa/driver.c | 199 ++++++++++++++++++++++++++++++ - include/linux/arm_ffa.h | 139 +++++++++++++++++++++ - 2 files changed, 338 insertions(+) - -diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c -index cefbb3edf142..056a3fca14d1 100644 ---- a/drivers/firmware/arm_ffa/driver.c -+++ b/drivers/firmware/arm_ffa/driver.c -@@ -28,6 +28,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - -@@ -348,6 +350,192 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, - return -EINVAL; - } - -+static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz, -+ u32 frag_len, u32 len, u64 *handle) -+{ -+ ffa_value_t ret; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = func_id, .a1 = len, .a2 = frag_len, -+ .a3 = buf, .a4 = buf_sz, -+ }, &ret); -+ -+ while (ret.a0 == FFA_MEM_OP_PAUSE) -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_MEM_OP_RESUME, -+ .a1 = ret.a1, .a2 = ret.a2, -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ if (ret.a0 != FFA_SUCCESS) -+ return -EOPNOTSUPP; -+ -+ if (handle) -+ *handle = PACK_HANDLE(ret.a2, ret.a3); -+ -+ return frag_len; -+} -+ -+static int ffa_mem_next_frag(u64 handle, u32 frag_len) -+{ -+ ffa_value_t ret; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_MEM_FRAG_TX, -+ .a1 = HANDLE_LOW(handle), .a2 = HANDLE_HIGH(handle), -+ .a3 = frag_len, -+ }, &ret); -+ -+ while (ret.a0 == FFA_MEM_OP_PAUSE) -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_MEM_OP_RESUME, -+ .a1 = ret.a1, .a2 = ret.a2, -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ if (ret.a0 != FFA_MEM_FRAG_RX) -+ return -EOPNOTSUPP; -+ -+ return ret.a3; -+} -+ -+static int -+ffa_transmit_fragment(u32 func_id, phys_addr_t buf, u32 buf_sz, u32 frag_len, -+ u32 len, u64 *handle, bool first) -+{ -+ if (!first) -+ return ffa_mem_next_frag(*handle, frag_len); -+ -+ return ffa_mem_first_frag(func_id, buf, buf_sz, frag_len, len, handle); -+} -+ -+static u32 ffa_get_num_pages_sg(struct scatterlist *sg) -+{ -+ u32 num_pages = 0; -+ -+ do { -+ num_pages += sg->length / FFA_PAGE_SIZE; -+ } while ((sg = sg_next(sg))); -+ -+ return num_pages; -+} -+ -+static int -+ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, -+ struct ffa_mem_ops_args *args) -+{ -+ int rc = 0; -+ bool first = true; -+ phys_addr_t addr = 0; -+ struct ffa_composite_mem_region *composite; -+ struct ffa_mem_region_addr_range *constituents; -+ struct ffa_mem_region_attributes *ep_mem_access; -+ struct ffa_mem_region *mem_region = buffer; -+ u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg); -+ -+ mem_region->tag = args->tag; -+ mem_region->flags = args->flags; -+ mem_region->sender_id = drv_info->vm_id; -+ mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | -+ FFA_MEM_INNER_SHAREABLE; -+ ep_mem_access = &mem_region->ep_mem_access[0]; -+ -+ for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) { -+ ep_mem_access->receiver = args->attrs[idx].receiver; -+ ep_mem_access->attrs = args->attrs[idx].attrs; -+ ep_mem_access->composite_off = COMPOSITE_OFFSET(args->nattrs); -+ } -+ mem_region->ep_count = args->nattrs; -+ -+ composite = buffer + COMPOSITE_OFFSET(args->nattrs); -+ composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg); -+ composite->addr_range_cnt = num_entries; -+ -+ length = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, num_entries); -+ frag_len = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, 0); -+ if (frag_len > max_fragsize) -+ return -ENXIO; -+ -+ if (!args->use_txbuf) { -+ addr = virt_to_phys(buffer); -+ buf_sz = max_fragsize / FFA_PAGE_SIZE; -+ } -+ -+ constituents = buffer + frag_len; -+ idx = 0; -+ do { -+ if (frag_len == max_fragsize) { -+ rc = ffa_transmit_fragment(func_id, addr, buf_sz, -+ frag_len, length, -+ &args->g_handle, first); -+ if (rc < 0) -+ return -ENXIO; -+ -+ first = false; -+ idx = 0; -+ frag_len = 0; -+ constituents = buffer; -+ } -+ -+ if ((void *)constituents - buffer > max_fragsize) { -+ pr_err("Memory Region Fragment > Tx Buffer size\n"); -+ return -EFAULT; -+ } -+ -+ constituents->address = sg_phys(args->sg); -+ constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE; -+ constituents++; -+ frag_len += sizeof(struct ffa_mem_region_addr_range); -+ } while ((args->sg = sg_next(args->sg))); -+ -+ return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len, -+ length, &args->g_handle, first); -+} -+ -+static int ffa_memory_ops(u32 func_id, struct ffa_mem_ops_args *args) -+{ -+ int ret; -+ void *buffer; -+ -+ if (!args->use_txbuf) { -+ buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ } else { -+ buffer = drv_info->tx_buffer; -+ mutex_lock(&drv_info->tx_lock); -+ } -+ -+ ret = ffa_setup_and_transmit(func_id, buffer, RXTX_BUFFER_SIZE, args); -+ -+ if (args->use_txbuf) -+ mutex_unlock(&drv_info->tx_lock); -+ else -+ free_pages_exact(buffer, RXTX_BUFFER_SIZE); -+ -+ return ret < 0 ? ret : 0; -+} -+ -+static int ffa_memory_reclaim(u64 g_handle, u32 flags) -+{ -+ ffa_value_t ret; -+ -+ invoke_ffa_fn((ffa_value_t){ -+ .a0 = FFA_MEM_RECLAIM, -+ .a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle), -+ .a3 = flags, -+ }, &ret); -+ -+ if (ret.a0 == FFA_ERROR) -+ return ffa_to_linux_errno((int)ret.a2); -+ -+ return 0; -+} -+ - static u32 ffa_api_version_get(void) - { - return drv_info->version; -@@ -386,11 +574,22 @@ static int ffa_sync_send_receive(struct ffa_device *dev, - dev->mode_32bit, data); - } - -+static int -+ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args) -+{ -+ if (dev->mode_32bit) -+ return ffa_memory_ops(FFA_MEM_SHARE, args); -+ -+ return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args); -+} -+ - static const struct ffa_dev_ops ffa_ops = { - .api_version_get = ffa_api_version_get, - .partition_info_get = ffa_partition_info_get, - .mode_32bit_set = ffa_mode_32bit_set, - .sync_send_receive = ffa_sync_send_receive, -+ .memory_reclaim = ffa_memory_reclaim, -+ .memory_share = ffa_memory_share, - }; - - const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) -diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h -index b242fbbce4f0..6dc0f4e425b9 100644 ---- a/include/linux/arm_ffa.h -+++ b/include/linux/arm_ffa.h -@@ -115,6 +115,142 @@ struct ffa_send_direct_data { - unsigned long data4; /* w7/x7 */ - }; - -+struct ffa_mem_region_addr_range { -+ /* The base IPA of the constituent memory region, aligned to 4 kiB */ -+ u64 address; -+ /* The number of 4 kiB pages in the constituent memory region. */ -+ u32 pg_cnt; -+ u32 reserved; -+}; -+ -+struct ffa_composite_mem_region { -+ /* -+ * The total number of 4 kiB pages included in this memory region. This -+ * must be equal to the sum of page counts specified in each -+ * `struct ffa_mem_region_addr_range`. -+ */ -+ u32 total_pg_cnt; -+ /* The number of constituents included in this memory region range */ -+ u32 addr_range_cnt; -+ u64 reserved; -+ /** An array of `addr_range_cnt` memory region constituents. */ -+ struct ffa_mem_region_addr_range constituents[]; -+}; -+ -+struct ffa_mem_region_attributes { -+ /* The ID of the VM to which the memory is being given or shared. */ -+ u16 receiver; -+ /* -+ * The permissions with which the memory region should be mapped in the -+ * receiver's page table. -+ */ -+#define FFA_MEM_EXEC BIT(3) -+#define FFA_MEM_NO_EXEC BIT(2) -+#define FFA_MEM_RW BIT(1) -+#define FFA_MEM_RO BIT(0) -+ u8 attrs; -+ /* -+ * Flags used during FFA_MEM_RETRIEVE_REQ and FFA_MEM_RETRIEVE_RESP -+ * for memory regions with multiple borrowers. -+ */ -+#define FFA_MEM_RETRIEVE_SELF_BORROWER BIT(0) -+ u8 flag; -+ u32 composite_off; -+ /* -+ * Offset in bytes from the start of the outer `ffa_memory_region` to -+ * an `struct ffa_mem_region_addr_range`. -+ */ -+ u64 reserved; -+}; -+ -+struct ffa_mem_region { -+ /* The ID of the VM/owner which originally sent the memory region */ -+ u16 sender_id; -+#define FFA_MEM_NORMAL BIT(5) -+#define FFA_MEM_DEVICE BIT(4) -+ -+#define FFA_MEM_WRITE_BACK (3 << 2) -+#define FFA_MEM_NON_CACHEABLE (1 << 2) -+ -+#define FFA_DEV_nGnRnE (0 << 2) -+#define FFA_DEV_nGnRE (1 << 2) -+#define FFA_DEV_nGRE (2 << 2) -+#define FFA_DEV_GRE (3 << 2) -+ -+#define FFA_MEM_NON_SHAREABLE (0) -+#define FFA_MEM_OUTER_SHAREABLE (2) -+#define FFA_MEM_INNER_SHAREABLE (3) -+ u8 attributes; -+ u8 reserved_0; -+/* -+ * Clear memory region contents after unmapping it from the sender and -+ * before mapping it for any receiver. -+ */ -+#define FFA_MEM_CLEAR BIT(0) -+/* -+ * Whether the hypervisor may time slice the memory sharing or retrieval -+ * operation. -+ */ -+#define FFA_TIME_SLICE_ENABLE BIT(1) -+ -+#define FFA_MEM_RETRIEVE_TYPE_IN_RESP (0 << 3) -+#define FFA_MEM_RETRIEVE_TYPE_SHARE (1 << 3) -+#define FFA_MEM_RETRIEVE_TYPE_LEND (2 << 3) -+#define FFA_MEM_RETRIEVE_TYPE_DONATE (3 << 3) -+ -+#define FFA_MEM_RETRIEVE_ADDR_ALIGN_HINT BIT(9) -+#define FFA_MEM_RETRIEVE_ADDR_ALIGN(x) ((x) << 5) -+ /* Flags to control behaviour of the transaction. */ -+ u32 flags; -+#define HANDLE_LOW_MASK GENMASK_ULL(31, 0) -+#define HANDLE_HIGH_MASK GENMASK_ULL(63, 32) -+#define HANDLE_LOW(x) ((u32)(FIELD_GET(HANDLE_LOW_MASK, (x)))) -+#define HANDLE_HIGH(x) ((u32)(FIELD_GET(HANDLE_HIGH_MASK, (x)))) -+ -+#define PACK_HANDLE(l, h) \ -+ (FIELD_PREP(HANDLE_LOW_MASK, (l)) | FIELD_PREP(HANDLE_HIGH_MASK, (h))) -+ /* -+ * A globally-unique ID assigned by the hypervisor for a region -+ * of memory being sent between VMs. -+ */ -+ u64 handle; -+ /* -+ * An implementation defined value associated with the receiver and the -+ * memory region. -+ */ -+ u64 tag; -+ u32 reserved_1; -+ /* -+ * The number of `ffa_mem_region_attributes` entries included in this -+ * transaction. -+ */ -+ u32 ep_count; -+ /* -+ * An array of endpoint memory access descriptors. -+ * Each one specifies a memory region offset, an endpoint and the -+ * attributes with which this memory region should be mapped in that -+ * endpoint's page table. -+ */ -+ struct ffa_mem_region_attributes ep_mem_access[]; -+}; -+ -+#define COMPOSITE_OFFSET(x) \ -+ (offsetof(struct ffa_mem_region, ep_mem_access[x])) -+#define CONSTITUENTS_OFFSET(x) \ -+ (offsetof(struct ffa_composite_mem_region, constituents[x])) -+#define COMPOSITE_CONSTITUENTS_OFFSET(x, y) \ -+ (COMPOSITE_OFFSET(x) + CONSTITUENTS_OFFSET(y)) -+ -+struct ffa_mem_ops_args { -+ bool use_txbuf; -+ u32 nattrs; -+ u32 flags; -+ u64 tag; -+ u64 g_handle; -+ struct scatterlist *sg; -+ struct ffa_mem_region_attributes *attrs; -+}; -+ - struct ffa_dev_ops { - u32 (*api_version_get)(void); - int (*partition_info_get)(const char *uuid_str, -@@ -122,6 +258,9 @@ struct ffa_dev_ops { - void (*mode_32bit_set)(struct ffa_device *dev); - int (*sync_send_receive)(struct ffa_device *dev, - struct ffa_send_direct_data *data); -+ int (*memory_reclaim)(u64 g_handle, u32 flags); -+ int (*memory_share)(struct ffa_device *dev, -+ struct ffa_mem_ops_args *args); - }; - - #endif /* _LINUX_ARM_FFA_H */ --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0018-optee-add-a-FF-A-memory-pool.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0013-optee-add-a-FF-A-memory-pool.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0018-optee-add-a-FF-A-memory-pool.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0013-optee-add-a-FF-A-memory-pool.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0019-optee-add-FF-A-support.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0014-optee-add-FF-A-support.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0019-optee-add-FF-A-support.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0014-optee-add-FF-A-support.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0022-coresight-etm4x-Save-restore-TRFCR_EL1.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0015-coresight-etm4x-Save-restore-TRFCR_EL1.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0022-coresight-etm4x-Save-restore-TRFCR_EL1.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0015-coresight-etm4x-Save-restore-TRFCR_EL1.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0023-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0016-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0023-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0016-coresight-etm4x-Use-Trace-Filtering-controls-dynamic.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0024-perf-arm-cmn-Use-irq_set_affinity.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0017-perf-arm-cmn-Use-irq_set_affinity.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0024-perf-arm-cmn-Use-irq_set_affinity.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0017-perf-arm-cmn-Use-irq_set_affinity.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0025-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0018-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0025-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0018-perf-arm-cmn-Fix-CPU-hotplug-unregistration.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0026-perf-arm-cmn-Account-for-NUMA-affinity.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0019-perf-arm-cmn-Account-for-NUMA-affinity.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0026-perf-arm-cmn-Account-for-NUMA-affinity.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0019-perf-arm-cmn-Account-for-NUMA-affinity.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0027-perf-arm-cmn-Drop-compile-test-restriction.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0020-perf-arm-cmn-Drop-compile-test-restriction.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0027-perf-arm-cmn-Drop-compile-test-restriction.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0020-perf-arm-cmn-Drop-compile-test-restriction.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0021-arm_ffa-add-support-for-FFA-v1.1.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0021-arm_ffa-add-support-for-FFA-v1.1.patch deleted file mode 100644 index bebac41c..00000000 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0021-arm_ffa-add-support-for-FFA-v1.1.patch +++ /dev/null @@ -1,37 +0,0 @@ -From abb29275dc4965e015f7719951645acfa58bcab4 Mon Sep 17 00:00:00 2001 -From: Usama Arif -Date: Wed, 11 Aug 2021 09:45:35 +0100 -Subject: [PATCH 21/22] arm_ffa: add support for FFA v1.1 - -Change-Id: I3d5a72981c6a66a0a034fd76d5e38eeb33318d20 -Signed-off-by: Usama Arif - -Upstream-Status: Pending [Not submitted to upstream yet] ---- - drivers/firmware/arm_ffa/driver.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c -index 82c84fe10be2..84d5a513fb94 100644 ---- a/drivers/firmware/arm_ffa/driver.c -+++ b/drivers/firmware/arm_ffa/driver.c -@@ -35,7 +35,7 @@ - - #include "common.h" - --#define FFA_DRIVER_VERSION FFA_VERSION_1_0 -+#define FFA_DRIVER_VERSION FFA_VERSION_1_1 - - #define FFA_SMC(calling_convention, func_num) \ - ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \ -@@ -111,6 +111,7 @@ - (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \ - FIELD_PREP(MINOR_VERSION_MASK, (minor))) - #define FFA_VERSION_1_0 PACK_VERSION_INFO(1, 0) -+#define FFA_VERSION_1_1 PACK_VERSION_INFO(1, 1) - #define FFA_MIN_VERSION FFA_VERSION_1_0 - - #define SENDER_ID_MASK GENMASK(31, 16) --- -2.17.1 - diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0028-perf-arm-cmn-Refactor-node-ID-handling.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0021-perf-arm-cmn-Refactor-node-ID-handling.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0028-perf-arm-cmn-Refactor-node-ID-handling.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0021-perf-arm-cmn-Refactor-node-ID-handling.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0029-perf-arm-cmn-Streamline-node-iteration.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0022-perf-arm-cmn-Streamline-node-iteration.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0029-perf-arm-cmn-Streamline-node-iteration.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0022-perf-arm-cmn-Streamline-node-iteration.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0030-drivers-perf-arm-cmn-Add-space-after.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0023-drivers-perf-arm-cmn-Add-space-after.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0030-drivers-perf-arm-cmn-Add-space-after.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0023-drivers-perf-arm-cmn-Add-space-after.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0031-perf-arm-cmn-Refactor-DTM-handling.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0024-perf-arm-cmn-Refactor-DTM-handling.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0031-perf-arm-cmn-Refactor-DTM-handling.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0024-perf-arm-cmn-Refactor-DTM-handling.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0032-perf-arm-cmn-Optimise-DTM-counter-reads.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0025-perf-arm-cmn-Optimise-DTM-counter-reads.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0032-perf-arm-cmn-Optimise-DTM-counter-reads.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0025-perf-arm-cmn-Optimise-DTM-counter-reads.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0033-perf-arm-cmn-Optimise-DTC-counter-accesses.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0026-perf-arm-cmn-Optimise-DTC-counter-accesses.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0033-perf-arm-cmn-Optimise-DTC-counter-accesses.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0026-perf-arm-cmn-Optimise-DTC-counter-accesses.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0034-perf-arm-cmn-Move-group-validation-data-off-stack.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0027-perf-arm-cmn-Move-group-validation-data-off-stack.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0034-perf-arm-cmn-Move-group-validation-data-off-stack.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0027-perf-arm-cmn-Move-group-validation-data-off-stack.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0035-perf-arm-cmn-Demarcate-CMN-600-specifics.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0028-perf-arm-cmn-Demarcate-CMN-600-specifics.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0035-perf-arm-cmn-Demarcate-CMN-600-specifics.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0028-perf-arm-cmn-Demarcate-CMN-600-specifics.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0036-perf-arm-cmn-Support-new-IP-features.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0029-perf-arm-cmn-Support-new-IP-features.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0036-perf-arm-cmn-Support-new-IP-features.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0029-perf-arm-cmn-Support-new-IP-features.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0037-perf-arm-cmn-Add-CI-700-Support.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0030-perf-arm-cmn-Add-CI-700-Support.patch similarity index 100% rename from meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0037-perf-arm-cmn-Add-CI-700-Support.patch rename to meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0030-perf-arm-cmn-Add-CI-700-Support.patch From patchwork Wed May 4 16:58:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7566 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0BE13C41535 for ; Wed, 4 May 2022 16:58:37 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web10.615.1651683514283639690 for ; Wed, 04 May 2022 09:58:35 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 60C7512FC; Wed, 4 May 2022 09:58:35 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C3D233FA27; Wed, 4 May 2022 09:58:34 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 08/10] arm-bsp/linux: TC: Add fixes in FFA driver Date: Wed, 4 May 2022 17:58:18 +0100 Message-Id: <20220504165820.882784-8-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:37 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3364 Signed-off-by: Arunachalam Ganapathy Change-Id: I43498b3e66651d4ed8d2cedb7455f678ddf012d1 --- .../linux/linux-arm-platforms.inc | 4 ++ ...-Fix-uuid-argument-passed-to-ffa_par.patch | 29 ++++++++++ ...ware-arm_ffa-Add-ffa_dev_get_drvdata.patch | 33 ++++++++++++ ...firmware-arm_ffa-extern-ffa_bus_type.patch | 30 +++++++++++ ...-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch | 54 +++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0031-firmware-arm_ffa-Fix-uuid-argument-passed-to-ffa_par.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0032-firmware-arm_ffa-Add-ffa_dev_get_drvdata.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0033-firmware-arm_ffa-extern-ffa_bus_type.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc index ce2c7f93..105b74ff 100644 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc @@ -166,6 +166,10 @@ SRC_URI:append:tc = " \ file://0028-perf-arm-cmn-Demarcate-CMN-600-specifics.patch \ file://0029-perf-arm-cmn-Support-new-IP-features.patch \ file://0030-perf-arm-cmn-Add-CI-700-Support.patch \ + file://0031-firmware-arm_ffa-Fix-uuid-argument-passed-to-ffa_par.patch \ + file://0032-firmware-arm_ffa-Add-ffa_dev_get_drvdata.patch \ + file://0033-firmware-arm_ffa-extern-ffa_bus_type.patch \ + file://0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch \ " KERNEL_FEATURES:append:tc = " bsp/arm-platforms/tc.scc" KERNEL_FEATURES:append:tc1 = " bsp/arm-platforms/tc-autofdo.scc" diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0031-firmware-arm_ffa-Fix-uuid-argument-passed-to-ffa_par.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0031-firmware-arm_ffa-Fix-uuid-argument-passed-to-ffa_par.patch new file mode 100644 index 00000000..35b4f10b --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0031-firmware-arm_ffa-Fix-uuid-argument-passed-to-ffa_par.patch @@ -0,0 +1,29 @@ +From 4d0a8147477699d40a02f121e7c72b21547273cf Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Thu, 13 Jan 2022 20:14:25 +0000 +Subject: [PATCH 19/32] firmware: arm_ffa: Fix uuid argument passed to + ffa_partition_probe + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ib2749ec3e02da5bb6d835f7dbf2d608c41fad1f2 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/firmware/arm_ffa/driver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 14f900047ac0..8fa1785afd42 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -582,7 +582,7 @@ static int ffa_partition_info_get(const char *uuid_str, + return -ENODEV; + } + +- count = ffa_partition_probe(&uuid_null, &pbuf); ++ count = ffa_partition_probe(&uuid, &pbuf); + if (count <= 0) + return -ENOENT; + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0032-firmware-arm_ffa-Add-ffa_dev_get_drvdata.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0032-firmware-arm_ffa-Add-ffa_dev_get_drvdata.patch new file mode 100644 index 00000000..52cf71be --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0032-firmware-arm_ffa-Add-ffa_dev_get_drvdata.patch @@ -0,0 +1,33 @@ +From 9acd4425667e240603ec196d8b64b2b25879805e Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Thu, 13 Jan 2022 22:22:28 +0000 +Subject: [PATCH 20/32] firmware: arm_ffa: Add ffa_dev_get_drvdata + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Icd09d686cab9922563b1deda5276307ea5d94923 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + include/linux/arm_ffa.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h +index 85651e41ded8..e5c76c1ef9ed 100644 +--- a/include/linux/arm_ffa.h ++++ b/include/linux/arm_ffa.h +@@ -38,7 +38,12 @@ struct ffa_driver { + + static inline void ffa_dev_set_drvdata(struct ffa_device *fdev, void *data) + { +- fdev->dev.driver_data = data; ++ dev_set_drvdata(&fdev->dev, data); ++} ++ ++static inline void *ffa_dev_get_drvdata(struct ffa_device *fdev) ++{ ++ return dev_get_drvdata(&fdev->dev); + } + + #if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT) +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0033-firmware-arm_ffa-extern-ffa_bus_type.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0033-firmware-arm_ffa-extern-ffa_bus_type.patch new file mode 100644 index 00000000..bbbc1783 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0033-firmware-arm_ffa-extern-ffa_bus_type.patch @@ -0,0 +1,30 @@ +From 7a9298916fe892ddac5fe4e0a13a566b1636f542 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Thu, 13 Jan 2022 22:23:52 +0000 +Subject: [PATCH 21/32] firmware: arm_ffa: extern ffa_bus_type + +extern ffa_bus_type so that SP driver can use it in bus_find_device call. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ib7a6a563aa35627a545f82c796816a5f72c80d70 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + include/linux/arm_ffa.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h +index e5c76c1ef9ed..4eb7e03ca560 100644 +--- a/include/linux/arm_ffa.h ++++ b/include/linux/arm_ffa.h +@@ -88,6 +88,8 @@ const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) + #define ffa_unregister(driver) \ + ffa_driver_unregister(driver) + ++extern struct bus_type ffa_bus_type; ++ + /** + * module_ffa_driver() - Helper macro for registering a psa_ffa driver + * @__ffa_driver: ffa_driver structure +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch new file mode 100644 index 00000000..977b550c --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch @@ -0,0 +1,54 @@ +From e0b9971db819fb9ed9b08a5d3f6f2a4565e92a1a Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 14 Jan 2022 12:23:04 +0000 +Subject: [PATCH 22/32] firmware: arm_ffa: Fix FFA_MEM_SHARE and + FFA_MEM_FRAG_TX + +FFA memory share on success might return FFA_MEM_FRAG_RX. In that case +set handle from w1/w2 from FFA return value. + +FFA_MEM_FRAG_TX call will return FFA_SUCCESS for the last fragment, so +check for this return code. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: I7ef44742d53a9e75d8587d1213be98a1352f16d4 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/firmware/arm_ffa/driver.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 8fa1785afd42..a3b1df6d7f3c 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -398,11 +398,15 @@ static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz, + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + +- if (ret.a0 != FFA_SUCCESS) ++ if (ret.a0 != FFA_SUCCESS && ret.a0 != FFA_MEM_FRAG_RX) + return -EOPNOTSUPP; + +- if (handle) +- *handle = PACK_HANDLE(ret.a2, ret.a3); ++ if (handle) { ++ if (ret.a0 == FFA_MEM_FRAG_RX) ++ *handle = PACK_HANDLE(ret.a1, ret.a2); ++ else ++ *handle = PACK_HANDLE(ret.a2, ret.a3); ++ } + + return frag_len; + } +@@ -426,7 +430,7 @@ static int ffa_mem_next_frag(u64 handle, u32 frag_len) + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + +- if (ret.a0 != FFA_MEM_FRAG_RX) ++ if (ret.a0 != FFA_SUCCESS && ret.a0 != FFA_MEM_FRAG_RX) + return -EOPNOTSUPP; + + return ret.a3; +-- +2.30.2 + From patchwork Wed May 4 16:58:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7570 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10608C43219 for ; Wed, 4 May 2022 16:58:47 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web10.616.1651683516681617123 for ; Wed, 04 May 2022 09:58:37 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 4FD3D1042; Wed, 4 May 2022 09:58:36 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 978BA3FA27; Wed, 4 May 2022 09:58:35 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 09/10] arm-bsp/linux: TC: Add backport of Trusty driver Date: Wed, 4 May 2022 17:58:19 +0100 Message-Id: <20220504165820.882784-9-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:47 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3365 Backport of trusty driver. This adds Trusty driver from android-trusty-5.10 Signed-off-by: Arunachalam Ganapathy Change-Id: I5477ecfc1b67fc3786dbd062711d8cc8d4963744 --- .../bsp/arm-platforms/tc.scc | 1 + .../bsp/arm-platforms/tc/trusty.cfg | 1 + .../linux/linux-arm-platforms.inc | 1 + ...OID-trusty-Backport-of-trusty-driver.patch | 8099 +++++++++++++++++ 4 files changed, 8102 insertions(+) create mode 100644 meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc/trusty.cfg create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0035-ANDROID-trusty-Backport-of-trusty-driver.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc.scc b/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc.scc index c1dffe79..43d2153d 100644 --- a/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc.scc +++ b/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc.scc @@ -6,3 +6,4 @@ kconf non-hardware tc/mali.cfg kconf non-hardware tc/tee.cfg kconf non-hardware tc/virtio.cfg kconf non-hardware tc/ci700.cfg +kconf non-hardware tc/trusty.cfg diff --git a/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc/trusty.cfg b/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc/trusty.cfg new file mode 100644 index 00000000..54e8657f --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/arm-platforms-kmeta/bsp/arm-platforms/tc/trusty.cfg @@ -0,0 +1 @@ +CONFIG_TRUSTY=y diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc index 105b74ff..4ebacd50 100644 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc @@ -170,6 +170,7 @@ SRC_URI:append:tc = " \ file://0032-firmware-arm_ffa-Add-ffa_dev_get_drvdata.patch \ file://0033-firmware-arm_ffa-extern-ffa_bus_type.patch \ file://0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch \ + file://0035-ANDROID-trusty-Backport-of-trusty-driver.patch \ " KERNEL_FEATURES:append:tc = " bsp/arm-platforms/tc.scc" KERNEL_FEATURES:append:tc1 = " bsp/arm-platforms/tc-autofdo.scc" diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0035-ANDROID-trusty-Backport-of-trusty-driver.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0035-ANDROID-trusty-Backport-of-trusty-driver.patch new file mode 100644 index 00000000..290de511 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0035-ANDROID-trusty-Backport-of-trusty-driver.patch @@ -0,0 +1,8099 @@ +From 3e1e61f54538e8ce4bcbb5a9a213624eafcae514 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= +Date: Mon, 18 Nov 2013 20:46:48 -0800 +Subject: [PATCH 18/32] ANDROID: trusty: Backport of trusty driver + +This adds Trusty driver from android-trusty-5.10 + +Original commits: +b60d55f33484 ANDROID: trusty-ipc: Allow registering multiple handles +629a4d3318cc ANDROID: trusty: Support setting trusty_shared_mem_id_t +94a36a1374e7 ANDROID: trusty-log: Don't copy Trusty logs to linux kernel log +efc21cced8af ANDROID: trusty-log: rework buffer allocation +8cb1a07ca814 ANDROID: trusty-ipc: Fix lock protection of shared_handles +52cdd137fae0 ANDROID: trusty-log: support poll() +24c3649dceb9 ANDROID: trusty-irq: enqueue work in trusty_irq_cpu_up +05a05bdd921e ANDROID: trusty: Add config TRUSTY_CRASH_IS_PANIC +b5fbdba2ec72 ANDROID: trusty-ipc: Fix crash when running out of txbuffers +46da5b95605e ANDROID: trusty: Allow TRUSTY_LEND of buffers +2ebfb16645af ANDROID: trusty-virtio: remove unnecessary include of dma-mapping.h +bf9d994a65a2 ANDROID: trusty-log: Complement logging sink with unthrottled virtual file +d5cb51d0365d ANDROID: trusty-log: Refactor logging state to support concurrent sinks +b421a5ad3eb3 ANDROID: trusty-log: Sanitize u32 overflow of the log ring buffer write index +58e9681c57af ANDROID: trusty-log: On trusty panic, unthrottle sink to the kernel log +ba12be0f203a ANDROID: trusty-log: Update trusty log buffer size to hold a complete Trusty crash logs +a8a3f83e52b6 ANDROID: trusty_qemu_defconfig: Enable dma-buf and ion system heaps +988b52b392a1 ANDROID: trusty: Support setting FF-A Tag +f544e96489aa ANDROID: Add trusty_qemu_defconfig +8a9b09317f29 ANDROID: trusty-ipc: Switch from memfd to dma_buf +5460418ec9a4 ANDROID: trusty-irq: document new way of specifying IPIs +da3c30b943c2 ANDROID: trusty-irq: specify IPIs in new way +5b5bb7f74856 ANDROID: trusty: Add trusty-test driver +e80d87f422fd ANDROID: trusty: Add trusty-ipc driver +03c248cbf693 ANDROID: trusty: Add trusty-virtio driver +1047661edb97 ANDROID: trusty: Add trusty-log driver +18fd5c59b423 ANDROID: trusty: Add trusty-irq driver +479c39a683f8 ANDROID: trusty: Add trusty-core driver + +Upstream-Status: Backport +Change-Id: I91f71b891a1091383a298e7fb2f9030382a19ca5 +Signed-off-by: Arunachalam Ganapathy +--- + .../devicetree/bindings/trusty/trusty-irq.txt | 67 + + .../devicetree/bindings/trusty/trusty-smc.txt | 6 + + arch/arm/configs/trusty_qemu_defconfig | 291 +++ + .../configs/trusty_qemu_defconfig.fragment | 26 + + drivers/Kconfig | 2 + + drivers/Makefile | 1 + + drivers/trusty/Kconfig | 116 + + drivers/trusty/Makefile | 14 + + drivers/trusty/trusty-ipc.c | 2256 +++++++++++++++++ + drivers/trusty/trusty-irq.c | 645 +++++ + drivers/trusty/trusty-log.c | 830 ++++++ + drivers/trusty/trusty-log.h | 28 + + drivers/trusty/trusty-mem.c | 139 + + drivers/trusty/trusty-smc-arm.S | 41 + + drivers/trusty/trusty-smc-arm64.S | 35 + + drivers/trusty/trusty-smc.h | 26 + + drivers/trusty/trusty-test.c | 440 ++++ + drivers/trusty/trusty-test.h | 13 + + drivers/trusty/trusty-virtio.c | 840 ++++++ + drivers/trusty/trusty.c | 981 +++++++ + include/linux/trusty/arm_ffa.h | 590 +++++ + include/linux/trusty/sm_err.h | 28 + + include/linux/trusty/smcall.h | 124 + + include/linux/trusty/trusty.h | 131 + + include/linux/trusty/trusty_ipc.h | 89 + + include/uapi/linux/trusty/ipc.h | 65 + + include/uapi/linux/virtio_ids.h | 1 + + 27 files changed, 7825 insertions(+) + create mode 100644 Documentation/devicetree/bindings/trusty/trusty-irq.txt + create mode 100644 Documentation/devicetree/bindings/trusty/trusty-smc.txt + create mode 100644 arch/arm/configs/trusty_qemu_defconfig + create mode 100644 arch/arm64/configs/trusty_qemu_defconfig.fragment + create mode 100644 drivers/trusty/Kconfig + create mode 100644 drivers/trusty/Makefile + create mode 100644 drivers/trusty/trusty-ipc.c + create mode 100644 drivers/trusty/trusty-irq.c + create mode 100644 drivers/trusty/trusty-log.c + create mode 100644 drivers/trusty/trusty-log.h + create mode 100644 drivers/trusty/trusty-mem.c + create mode 100644 drivers/trusty/trusty-smc-arm.S + create mode 100644 drivers/trusty/trusty-smc-arm64.S + create mode 100644 drivers/trusty/trusty-smc.h + create mode 100644 drivers/trusty/trusty-test.c + create mode 100644 drivers/trusty/trusty-test.h + create mode 100644 drivers/trusty/trusty-virtio.c + create mode 100644 drivers/trusty/trusty.c + create mode 100644 include/linux/trusty/arm_ffa.h + create mode 100644 include/linux/trusty/sm_err.h + create mode 100644 include/linux/trusty/smcall.h + create mode 100644 include/linux/trusty/trusty.h + create mode 100644 include/linux/trusty/trusty_ipc.h + create mode 100644 include/uapi/linux/trusty/ipc.h + +diff --git a/Documentation/devicetree/bindings/trusty/trusty-irq.txt b/Documentation/devicetree/bindings/trusty/trusty-irq.txt +new file mode 100644 +index 000000000000..cbb545ad452b +--- /dev/null ++++ b/Documentation/devicetree/bindings/trusty/trusty-irq.txt +@@ -0,0 +1,67 @@ ++Trusty irq interface ++ ++Trusty requires non-secure irqs to be forwarded to the secure OS. ++ ++Required properties: ++- compatible: "android,trusty-irq-v1" ++ ++Optional properties: ++ ++- interrupt-templates: is an optional property that works together ++ with "interrupt-ranges" to specify secure side to kernel IRQs mapping. ++ ++ It is a list of entries, each one of which defines a group of interrupts ++ having common properties, and has the following format: ++ < phandle irq_id_pos [templ_data]> ++ phandle - phandle of interrupt controller this template is for ++ irq_id_pos - the position of irq id in interrupt specifier array ++ for interrupt controller referenced by phandle. ++ templ_data - is an array of u32 values (could be empty) in the same ++ format as interrupt specifier for interrupt controller ++ referenced by phandle but with omitted irq id field. ++ ++- interrupt-ranges: list of entries that specifies secure side to kernel ++ IRQs mapping. ++ ++ Each entry in the "interrupt-ranges" list has the following format: ++ ++ beg - first entry in this range ++ end - last entry in this range ++ templ_idx - index of entry in "interrupt-templates" property ++ that must be used as a template for all interrupts ++ in this range ++ ++- ipi-range: optional mapping of a linear range of trusty IRQs to a linear range ++ of IPIs (inter-processor interrupts). This has the following format: ++ ++ beg - first trusty IRQ number that is an IPI ++ end - last trusty IRQ number that is an IPI ++ ipi_base - IPI number of 'beg' ++ ++Example: ++{ ++ gic: interrupt-controller@50041000 { ++ compatible = "arm,gic-400"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ ... ++ }; ++ ... ++ trusty { ++ compatible = "android,trusty-smc-v1"; ++ ranges; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ irq { ++ compatible = "android,trusty-irq-v1"; ++ interrupt-templates = <&gic 1 GIC_PPI 0>, ++ <&gic 1 GIC_SPI 0>; ++ interrupt-ranges = <16 31 0>, ++ <32 223 1>; ++ ipi-range = <8 15 8>; ++ }; ++ } ++} ++ ++Must be a child of the node that provides the trusty std/fast call interface. +diff --git a/Documentation/devicetree/bindings/trusty/trusty-smc.txt b/Documentation/devicetree/bindings/trusty/trusty-smc.txt +new file mode 100644 +index 000000000000..1b39ad317c67 +--- /dev/null ++++ b/Documentation/devicetree/bindings/trusty/trusty-smc.txt +@@ -0,0 +1,6 @@ ++Trusty smc interface ++ ++Trusty is running in secure mode on the same (arm) cpu(s) as the current os. ++ ++Required properties: ++- compatible: "android,trusty-smc-v1" +diff --git a/arch/arm/configs/trusty_qemu_defconfig b/arch/arm/configs/trusty_qemu_defconfig +new file mode 100644 +index 000000000000..46ad9504c23d +--- /dev/null ++++ b/arch/arm/configs/trusty_qemu_defconfig +@@ -0,0 +1,291 @@ ++# CONFIG_LOCALVERSION_AUTO is not set ++# CONFIG_SWAP is not set ++CONFIG_POSIX_MQUEUE=y ++CONFIG_AUDIT=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_PREEMPT=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++CONFIG_TASKSTATS=y ++CONFIG_TASK_DELAY_ACCT=y ++CONFIG_TASK_XACCT=y ++CONFIG_TASK_IO_ACCOUNTING=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_RT_GROUP_SCHED=y ++CONFIG_CGROUP_FREEZER=y ++CONFIG_CGROUP_CPUACCT=y ++CONFIG_CGROUP_DEBUG=y ++CONFIG_SCHED_AUTOGROUP=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_EMBEDDED=y ++# CONFIG_COMPAT_BRK is not set ++CONFIG_PROFILING=y ++CONFIG_ARCH_VIRT=y ++CONFIG_PCI=y ++CONFIG_PCI_HOST_GENERIC=y ++CONFIG_SMP=y ++CONFIG_HIGHMEM=y ++CONFIG_SECCOMP=y ++CONFIG_CMDLINE="console=ttyAMA0" ++CONFIG_PM_AUTOSLEEP=y ++CONFIG_PM_WAKELOCKS=y ++CONFIG_PM_WAKELOCKS_LIMIT=0 ++# CONFIG_PM_WAKELOCKS_GC is not set ++CONFIG_PM_DEBUG=y ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_KSM=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_XFRM_USER=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_INET_ESP=y ++CONFIG_INET_DIAG_DESTROY=y ++CONFIG_IPV6_ROUTER_PREF=y ++CONFIG_IPV6_ROUTE_INFO=y ++CONFIG_IPV6_OPTIMISTIC_DAD=y ++CONFIG_INET6_AH=y ++CONFIG_INET6_ESP=y ++CONFIG_INET6_IPCOMP=y ++CONFIG_IPV6_MIP6=y ++CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_NETFILTER=y ++CONFIG_NF_CONNTRACK=y ++CONFIG_NF_CONNTRACK_SECMARK=y ++CONFIG_NF_CONNTRACK_EVENTS=y ++CONFIG_NF_CONNTRACK_AMANDA=y ++CONFIG_NF_CONNTRACK_FTP=y ++CONFIG_NF_CONNTRACK_H323=y ++CONFIG_NF_CONNTRACK_IRC=y ++CONFIG_NF_CONNTRACK_NETBIOS_NS=y ++CONFIG_NF_CONNTRACK_PPTP=y ++CONFIG_NF_CONNTRACK_SANE=y ++CONFIG_NF_CONNTRACK_TFTP=y ++CONFIG_NF_CT_NETLINK=y ++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y ++CONFIG_NETFILTER_XT_TARGET_CONNMARK=y ++CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y ++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y ++CONFIG_NETFILTER_XT_TARGET_MARK=y ++CONFIG_NETFILTER_XT_TARGET_NFLOG=y ++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y ++CONFIG_NETFILTER_XT_TARGET_TPROXY=y ++CONFIG_NETFILTER_XT_TARGET_TRACE=y ++CONFIG_NETFILTER_XT_TARGET_SECMARK=y ++CONFIG_NETFILTER_XT_TARGET_TCPMSS=y ++CONFIG_NETFILTER_XT_MATCH_COMMENT=y ++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y ++CONFIG_NETFILTER_XT_MATCH_CONNMARK=y ++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y ++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y ++CONFIG_NETFILTER_XT_MATCH_HELPER=y ++CONFIG_NETFILTER_XT_MATCH_IPRANGE=y ++CONFIG_NETFILTER_XT_MATCH_LENGTH=y ++CONFIG_NETFILTER_XT_MATCH_LIMIT=y ++CONFIG_NETFILTER_XT_MATCH_MAC=y ++CONFIG_NETFILTER_XT_MATCH_MARK=y ++CONFIG_NETFILTER_XT_MATCH_POLICY=y ++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y ++CONFIG_NETFILTER_XT_MATCH_QUOTA=y ++CONFIG_NETFILTER_XT_MATCH_QUOTA2=y ++CONFIG_NETFILTER_XT_MATCH_SOCKET=y ++CONFIG_NETFILTER_XT_MATCH_STATE=y ++CONFIG_NETFILTER_XT_MATCH_STATISTIC=y ++CONFIG_NETFILTER_XT_MATCH_STRING=y ++CONFIG_NETFILTER_XT_MATCH_TIME=y ++CONFIG_NETFILTER_XT_MATCH_U32=y ++CONFIG_IP_NF_IPTABLES=y ++CONFIG_IP_NF_MATCH_AH=y ++CONFIG_IP_NF_MATCH_ECN=y ++CONFIG_IP_NF_MATCH_RPFILTER=y ++CONFIG_IP_NF_MATCH_TTL=y ++CONFIG_IP_NF_FILTER=y ++CONFIG_IP_NF_TARGET_REJECT=y ++CONFIG_IP_NF_MANGLE=y ++CONFIG_IP_NF_TARGET_ECN=y ++CONFIG_IP_NF_TARGET_TTL=y ++CONFIG_IP_NF_RAW=y ++CONFIG_IP_NF_SECURITY=y ++CONFIG_IP_NF_ARPTABLES=y ++CONFIG_IP_NF_ARPFILTER=y ++CONFIG_IP_NF_ARP_MANGLE=y ++CONFIG_IP6_NF_IPTABLES=y ++CONFIG_IP6_NF_MATCH_AH=y ++CONFIG_IP6_NF_MATCH_EUI64=y ++CONFIG_IP6_NF_MATCH_FRAG=y ++CONFIG_IP6_NF_MATCH_OPTS=y ++CONFIG_IP6_NF_MATCH_HL=y ++CONFIG_IP6_NF_MATCH_IPV6HEADER=y ++CONFIG_IP6_NF_MATCH_MH=y ++CONFIG_IP6_NF_MATCH_RT=y ++CONFIG_IP6_NF_TARGET_HL=y ++CONFIG_IP6_NF_FILTER=y ++CONFIG_IP6_NF_TARGET_REJECT=y ++CONFIG_IP6_NF_MANGLE=y ++CONFIG_IP6_NF_RAW=y ++CONFIG_BRIDGE=y ++CONFIG_NET_SCHED=y ++CONFIG_NET_SCH_HTB=y ++CONFIG_NET_CLS_U32=y ++CONFIG_NET_EMATCH=y ++CONFIG_NET_EMATCH_U32=y ++CONFIG_NET_CLS_ACT=y ++# CONFIG_WIRELESS is not set ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_VIRTIO_BLK=y ++CONFIG_SCSI=y ++# CONFIG_SCSI_PROC_FS is not set ++CONFIG_BLK_DEV_SD=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_MD=y ++CONFIG_BLK_DEV_DM=y ++CONFIG_DM_CRYPT=y ++CONFIG_DM_UEVENT=y ++CONFIG_DM_VERITY=y ++CONFIG_DM_VERITY_FEC=y ++CONFIG_NETDEVICES=y ++CONFIG_TUN=y ++CONFIG_VIRTIO_NET=y ++CONFIG_E1000=y ++CONFIG_E1000E=y ++CONFIG_PPP=y ++CONFIG_PPP_BSDCOMP=y ++CONFIG_PPP_DEFLATE=y ++CONFIG_PPP_MPPE=y ++# CONFIG_WLAN is not set ++CONFIG_INPUT_EVDEV=y ++CONFIG_KEYBOARD_GOLDFISH_EVENTS=y ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_JOYSTICK=y ++CONFIG_INPUT_TABLET=y ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_UINPUT=y ++# CONFIG_SERIO_SERPORT is not set ++# CONFIG_VT is not set ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_DEVMEM is not set ++CONFIG_SERIAL_AMBA_PL011=y ++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y ++CONFIG_VIRTIO_CONSOLE=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_BATTERY_GOLDFISH=y ++# CONFIG_HWMON is not set ++CONFIG_TRUSTY=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_FB=y ++CONFIG_FB_GOLDFISH=y ++CONFIG_FB_SIMPLE=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_LOGO=y ++# CONFIG_LOGO_LINUX_MONO is not set ++# CONFIG_LOGO_LINUX_VGA16 is not set ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_HIDRAW=y ++CONFIG_UHID=y ++CONFIG_HID_A4TECH=y ++CONFIG_HID_ACRUX=y ++CONFIG_HID_ACRUX_FF=y ++CONFIG_HID_APPLE=y ++CONFIG_HID_BELKIN=y ++CONFIG_HID_CHERRY=y ++CONFIG_HID_CHICONY=y ++CONFIG_HID_PRODIKEYS=y ++CONFIG_HID_CYPRESS=y ++CONFIG_HID_DRAGONRISE=y ++CONFIG_DRAGONRISE_FF=y ++CONFIG_HID_EMS_FF=y ++CONFIG_HID_ELECOM=y ++CONFIG_HID_EZKEY=y ++CONFIG_HID_KEYTOUCH=y ++CONFIG_HID_KYE=y ++CONFIG_HID_WALTOP=y ++CONFIG_HID_GYRATION=y ++CONFIG_HID_TWINHAN=y ++CONFIG_HID_KENSINGTON=y ++CONFIG_HID_LCPOWER=y ++CONFIG_HID_LOGITECH=y ++CONFIG_HID_LOGITECH_DJ=y ++CONFIG_LOGITECH_FF=y ++CONFIG_LOGIRUMBLEPAD2_FF=y ++CONFIG_LOGIG940_FF=y ++CONFIG_HID_MAGICMOUSE=y ++CONFIG_HID_MICROSOFT=y ++CONFIG_HID_MONTEREY=y ++CONFIG_HID_MULTITOUCH=y ++CONFIG_HID_ORTEK=y ++CONFIG_HID_PANTHERLORD=y ++CONFIG_PANTHERLORD_FF=y ++CONFIG_HID_PETALYNX=y ++CONFIG_HID_PICOLCD=y ++CONFIG_HID_PRIMAX=y ++CONFIG_HID_SAITEK=y ++CONFIG_HID_SAMSUNG=y ++CONFIG_HID_SPEEDLINK=y ++CONFIG_HID_SUNPLUS=y ++CONFIG_HID_GREENASIA=y ++CONFIG_GREENASIA_FF=y ++CONFIG_HID_SMARTJOYPLUS=y ++CONFIG_SMARTJOYPLUS_FF=y ++CONFIG_HID_TIVO=y ++CONFIG_HID_TOPSEED=y ++CONFIG_HID_THRUSTMASTER=y ++CONFIG_HID_ZEROPLUS=y ++CONFIG_HID_ZYDACRON=y ++# CONFIG_USB_SUPPORT is not set ++CONFIG_RTC_CLASS=y ++CONFIG_VIRTIO_PCI=y ++CONFIG_VIRTIO_MMIO=y ++CONFIG_STAGING=y ++CONFIG_ASHMEM=y ++CONFIG_ION=y ++CONFIG_GOLDFISH_AUDIO=y ++CONFIG_GOLDFISH=y ++CONFIG_GOLDFISH_PIPE=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_ANDROID=y ++CONFIG_ANDROID_BINDER_IPC=y ++CONFIG_EXT2_FS=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_SECURITY=y ++CONFIG_QUOTA=y ++CONFIG_FUSE_FS=y ++CONFIG_CUSE=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++# CONFIG_MISC_FILESYSTEMS is not set ++CONFIG_NFS_FS=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_SECURITY=y ++CONFIG_SECURITY_NETWORK=y ++CONFIG_SECURITY_SELINUX=y ++CONFIG_DYNAMIC_DEBUG=y ++CONFIG_DEBUG_INFO=y ++CONFIG_DEBUG_FS=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_PANIC_TIMEOUT=5 ++# CONFIG_SCHED_DEBUG is not set ++CONFIG_SCHEDSTATS=y ++# CONFIG_FTRACE is not set ++CONFIG_DMA_API_DEBUG=y ++CONFIG_ATOMIC64_SELFTEST=y +diff --git a/arch/arm64/configs/trusty_qemu_defconfig.fragment b/arch/arm64/configs/trusty_qemu_defconfig.fragment +new file mode 100644 +index 000000000000..166eef1797fd +--- /dev/null ++++ b/arch/arm64/configs/trusty_qemu_defconfig.fragment +@@ -0,0 +1,26 @@ ++# From goldfish ++CONFIG_VIRTIO_BLK=y ++CONFIG_VIRTIO_CONSOLE=y ++CONFIG_VIRTIO_INPUT=y ++CONFIG_VIRTIO_MMIO=y ++CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y ++CONFIG_VIRTIO_NET=y ++CONFIG_VIRTIO_PCI=y ++CONFIG_VIRTIO_PMEM=y ++# From Trusty ++CONFIG_TRUSTY=y ++CONFIG_DMA_API_DEBUG=y ++CONFIG_DYNAMIC_DEBUG=y ++CONFIG_PROVE_LOCKING=y ++CONFIG_DEBUG_ATOMIC_SLEEP=y ++CONFIG_SEMIHOSTING_EXIT=y ++CONFIG_E1000=y ++CONFIG_E1000E=y ++CONFIG_REBOOT_EMULATOR_EXIT=y ++CONFIG_DMABUF_HEAPS_SYSTEM=y ++# securefb test uses ION ++CONFIG_ION=y ++CONFIG_ION_SYSTEM_HEAP=y ++# LTO slows down build times considerably. Disable it. ++# CONFIG_LTO_CLANG is not set ++# CONFIG_LTO_CLANG_FULL is not set +diff --git a/drivers/Kconfig b/drivers/Kconfig +index dcecc9f6e33f..2e9abcc98126 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -86,6 +86,8 @@ source "drivers/hwmon/Kconfig" + + source "drivers/thermal/Kconfig" + ++source "drivers/trusty/Kconfig" ++ + source "drivers/watchdog/Kconfig" + + source "drivers/ssb/Kconfig" +diff --git a/drivers/Makefile b/drivers/Makefile +index 576228037718..7d15799dbe77 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -118,6 +118,7 @@ obj-$(CONFIG_W1) += w1/ + obj-y += power/ + obj-$(CONFIG_HWMON) += hwmon/ + obj-$(CONFIG_THERMAL) += thermal/ ++obj-$(CONFIG_TRUSTY) += trusty/ + obj-$(CONFIG_WATCHDOG) += watchdog/ + obj-$(CONFIG_MD) += md/ + obj-$(CONFIG_BT) += bluetooth/ +diff --git a/drivers/trusty/Kconfig b/drivers/trusty/Kconfig +new file mode 100644 +index 000000000000..fcde7f097acf +--- /dev/null ++++ b/drivers/trusty/Kconfig +@@ -0,0 +1,116 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Trusty driver ++# ++ ++menu "Trusty driver" ++ ++config TRUSTY ++ tristate "Trusty core driver" ++ depends on ARM || ARM64 ++ help ++ Trusty is a secure OS that provides a Trusted Execution Environment ++ (TEE) for Android. Trusty runs on the same processor as Linux but is ++ isolated from the rest of the system by both hardware and software. ++ ++ This option enables the core part of the Linux kernel driver for ++ Trusty. This doesn't do much by itself; you'll need to enable some of ++ the sub-modules too. ++ ++ If you build this as a module, it will be called trusty-core. ++ ++if TRUSTY ++ ++config TRUSTY_IRQ ++ tristate "Trusty IRQ support" ++ default y ++ help ++ Enable forwarding of IRQs from Linux to Trusty. This module retrieves ++ from Trusty a list of IRQs that Trusty uses, and it registers handlers ++ for them which notify Trusty that the IRQ has been received. ++ ++ If you build this as a module, it will be called trusty-irq. ++ ++ Usually this is needed for Trusty to work, so say 'y' or 'm'. ++ ++config TRUSTY_LOG ++ tristate "Trusty log support" ++ default y ++ help ++ Print log messages generated by the secure OS to the Linux kernel log. ++ ++ While this module is loaded, messages are retrieved and printed after ++ each call into Trusty, and also during Linux kernel panics. ++ ++ If you build this as a module, it will be called trusty-log. ++ ++config TRUSTY_TEST ++ tristate "Trusty stdcall test" ++ default y ++ help ++ Allow running tests of the Trusty stdcall interface. Running these ++ tests is initiated by userspace writing to a sysfs file. ++ ++ This depends on having a test sevice running on the Trusty side. ++ ++ If you build this as a module, it will be called trusty-test. ++ ++config TRUSTY_VIRTIO ++ tristate "Trusty virtio support" ++ select VIRTIO ++ default y ++ help ++ Enable the Trusty virtio driver, which is responsible for management ++ and interaction with virtio devices exposed by Trusty. This driver ++ requests the virtio device descriptors from Trusty, then parses them ++ and adds the corresponding virtio devices. ++ ++ If you build this as a module, it will be called trusty-virtio. ++ ++config TRUSTY_VIRTIO_IPC ++ tristate "Trusty Virtio IPC driver" ++ depends on TRUSTY_VIRTIO ++ default y ++ help ++ Enable support for communicating with Trusty services. ++ ++ If you build this as a module, it will be called trusty-ipc. ++ ++config TRUSTY_DMA_BUF_FFA_TAG ++ bool "Availability of trusty_dma_buf_get_ffa_tag" ++ default n ++ help ++ Whether trusty_dma_buf_get_ffa_tag is provided on this platform. ++ Providing this function will allow the platform to select what tag ++ should be passed to the SPM when attempting to transfer the buffer ++ to secure world. The value passed here is implementation defined and ++ may depend on your SPM. ++ ++ If set to N, a default implementation which returns 0 will be used. ++ ++config TRUSTY_DMA_BUF_SHARED_MEM_ID ++ bool "Availability of trusty_dma_buf_get_shared_mem_id" ++ default n ++ help ++ Whether trusty_dma_buf_get_shared_mem_id is provided on this platform. ++ Providing this function allows the platform to manage memory ++ transaction life cycle of DMA bufs independently of Trusty IPC driver. ++ The latter can query trusty_shared_mem_id_t value allocated for a ++ given DMA buf using trusty_dma_buf_get_shared_mem_id interface. ++ ++ If set to N, a default implementation which does not allocate any IDs ++ will be used. ++ ++config TRUSTY_CRASH_IS_PANIC ++ bool "When trusty panics, then panic the kernel" ++ help ++ This option will treat Trusty panics as fatal. This is useful if ++ your system cannot recover from Trusty panic/halt and you require ++ the system to reboot to recover. ++ ++ If N, it will contine to run the kernel, but trusty operations will ++ return errors. ++ ++endif # TRUSTY ++ ++endmenu +diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile +new file mode 100644 +index 000000000000..2cf1cfccf97b +--- /dev/null ++++ b/drivers/trusty/Makefile +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Makefile for trusty components ++# ++ ++obj-$(CONFIG_TRUSTY) += trusty-core.o ++trusty-core-objs += trusty.o trusty-mem.o ++trusty-core-$(CONFIG_ARM) += trusty-smc-arm.o ++trusty-core-$(CONFIG_ARM64) += trusty-smc-arm64.o ++obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o ++obj-$(CONFIG_TRUSTY_LOG) += trusty-log.o ++obj-$(CONFIG_TRUSTY_TEST) += trusty-test.o ++obj-$(CONFIG_TRUSTY_VIRTIO) += trusty-virtio.o ++obj-$(CONFIG_TRUSTY_VIRTIO_IPC) += trusty-ipc.o +diff --git a/drivers/trusty/trusty-ipc.c b/drivers/trusty/trusty-ipc.c +new file mode 100644 +index 000000000000..82d6ddeb41f4 +--- /dev/null ++++ b/drivers/trusty/trusty-ipc.c +@@ -0,0 +1,2256 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2020 Google, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#define MAX_DEVICES 4 ++ ++#define REPLY_TIMEOUT 5000 ++#define TXBUF_TIMEOUT 15000 ++ ++#define MAX_SRV_NAME_LEN 256 ++#define MAX_DEV_NAME_LEN 32 ++ ++#define DEFAULT_MSG_BUF_SIZE PAGE_SIZE ++#define DEFAULT_MSG_BUF_ALIGN PAGE_SIZE ++ ++#define TIPC_CTRL_ADDR 53 ++#define TIPC_ANY_ADDR 0xFFFFFFFF ++ ++#define TIPC_MIN_LOCAL_ADDR 1024 ++ ++#ifdef CONFIG_COMPAT ++#define TIPC_IOC32_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, compat_uptr_t) ++#endif ++ ++struct tipc_virtio_dev; ++ ++struct tipc_dev_config { ++ u32 msg_buf_max_size; ++ u32 msg_buf_alignment; ++ char dev_name[MAX_DEV_NAME_LEN]; ++} __packed; ++ ++struct tipc_shm { ++ trusty_shared_mem_id_t obj_id; ++ u64 size; ++ u64 tag; ++}; ++ ++struct tipc_msg_hdr { ++ u32 src; ++ u32 dst; ++ u16 reserved; ++ u16 shm_cnt; ++ u16 len; ++ u16 flags; ++ u8 data[]; ++} __packed; ++ ++enum tipc_ctrl_msg_types { ++ TIPC_CTRL_MSGTYPE_GO_ONLINE = 1, ++ TIPC_CTRL_MSGTYPE_GO_OFFLINE, ++ TIPC_CTRL_MSGTYPE_CONN_REQ, ++ TIPC_CTRL_MSGTYPE_CONN_RSP, ++ TIPC_CTRL_MSGTYPE_DISC_REQ, ++ TIPC_CTRL_MSGTYPE_RELEASE, ++}; ++ ++struct tipc_ctrl_msg { ++ u32 type; ++ u32 body_len; ++ u8 body[]; ++} __packed; ++ ++struct tipc_conn_req_body { ++ char name[MAX_SRV_NAME_LEN]; ++} __packed; ++ ++struct tipc_conn_rsp_body { ++ u32 target; ++ u32 status; ++ u32 remote; ++ u32 max_msg_size; ++ u32 max_msg_cnt; ++} __packed; ++ ++struct tipc_disc_req_body { ++ u32 target; ++} __packed; ++ ++struct tipc_release_body { ++ trusty_shared_mem_id_t id; ++} __packed; ++ ++struct tipc_cdev_node { ++ struct cdev cdev; ++ struct device *dev; ++ unsigned int minor; ++}; ++ ++enum tipc_device_state { ++ VDS_OFFLINE = 0, ++ VDS_ONLINE, ++ VDS_DEAD, ++}; ++ ++struct tipc_virtio_dev { ++ struct kref refcount; ++ struct mutex lock; /* protects access to this device */ ++ struct virtio_device *vdev; ++ struct virtqueue *rxvq; ++ struct virtqueue *txvq; ++ unsigned int msg_buf_cnt; ++ unsigned int msg_buf_max_cnt; ++ size_t msg_buf_max_sz; ++ unsigned int free_msg_buf_cnt; ++ struct list_head free_buf_list; ++ wait_queue_head_t sendq; ++ struct idr addr_idr; ++ enum tipc_device_state state; ++ struct tipc_cdev_node cdev_node; ++ /* protects shared_handles, dev lock never acquired while held */ ++ struct mutex shared_handles_lock; ++ struct rb_root shared_handles; ++ char cdev_name[MAX_DEV_NAME_LEN]; ++}; ++ ++enum tipc_chan_state { ++ TIPC_DISCONNECTED = 0, ++ TIPC_CONNECTING, ++ TIPC_CONNECTED, ++ TIPC_STALE, ++}; ++ ++struct tipc_chan { ++ struct mutex lock; /* protects channel state */ ++ struct kref refcount; ++ enum tipc_chan_state state; ++ struct tipc_virtio_dev *vds; ++ const struct tipc_chan_ops *ops; ++ void *ops_arg; ++ u32 remote; ++ u32 local; ++ u32 max_msg_size; ++ u32 max_msg_cnt; ++ char srv_name[MAX_SRV_NAME_LEN]; ++}; ++ ++struct tipc_shared_handle { ++ struct rb_node node; ++ struct tipc_shm tipc; ++ struct tipc_virtio_dev *vds; ++ struct dma_buf *dma_buf; ++ bool shared; ++ /* ++ * Following fields are only used if dma_buf does not own a ++ * trusty_shared_mem_id_t. ++ */ ++ struct dma_buf_attachment *attach; ++ struct sg_table *sgt; ++}; ++ ++static struct class *tipc_class; ++static unsigned int tipc_major; ++ ++static struct virtio_device *default_vdev; ++ ++static DEFINE_IDR(tipc_devices); ++static DEFINE_MUTEX(tipc_devices_lock); ++ ++static int _match_any(int id, void *p, void *data) ++{ ++ return id; ++} ++ ++static int _match_data(int id, void *p, void *data) ++{ ++ return (p == data); ++} ++ ++static void *_alloc_shareable_mem(size_t sz, gfp_t gfp) ++{ ++ return alloc_pages_exact(sz, gfp); ++} ++ ++static void _free_shareable_mem(size_t sz, void *va) ++{ ++ free_pages_exact(va, sz); ++} ++ ++static struct tipc_msg_buf *vds_alloc_msg_buf(struct tipc_virtio_dev *vds, ++ bool share_write) ++{ ++ int ret; ++ struct tipc_msg_buf *mb; ++ size_t sz = vds->msg_buf_max_sz; ++ pgprot_t pgprot = share_write ? PAGE_KERNEL : PAGE_KERNEL_RO; ++ ++ /* allocate tracking structure */ ++ mb = kzalloc(sizeof(struct tipc_msg_buf), GFP_KERNEL); ++ if (!mb) ++ return NULL; ++ ++ /* allocate buffer that can be shared with secure world */ ++ mb->buf_va = _alloc_shareable_mem(sz, GFP_KERNEL); ++ if (!mb->buf_va) ++ goto err_alloc; ++ ++ sg_init_one(&mb->sg, mb->buf_va, sz); ++ ret = trusty_share_memory_compat(vds->vdev->dev.parent->parent, ++ &mb->buf_id, &mb->sg, 1, pgprot); ++ if (ret) { ++ dev_err(&vds->vdev->dev, "trusty_share_memory failed: %d\n", ++ ret); ++ goto err_share; ++ } ++ ++ mb->buf_sz = sz; ++ mb->shm_cnt = 0; ++ ++ return mb; ++ ++err_share: ++ _free_shareable_mem(sz, mb->buf_va); ++err_alloc: ++ kfree(mb); ++ return NULL; ++} ++ ++static void vds_free_msg_buf(struct tipc_virtio_dev *vds, ++ struct tipc_msg_buf *mb) ++{ ++ int ret; ++ ++ ret = trusty_reclaim_memory(vds->vdev->dev.parent->parent, mb->buf_id, ++ &mb->sg, 1); ++ if (WARN_ON(ret)) { ++ dev_err(&vds->vdev->dev, ++ "trusty_revoke_memory failed: %d txbuf %lld\n", ++ ret, mb->buf_id); ++ ++ /* ++ * It is not safe to free this memory if trusty_revoke_memory ++ * fails. Leak it in that case. ++ */ ++ } else { ++ _free_shareable_mem(mb->buf_sz, mb->buf_va); ++ } ++ kfree(mb); ++} ++ ++static void vds_free_msg_buf_list(struct tipc_virtio_dev *vds, ++ struct list_head *list) ++{ ++ struct tipc_msg_buf *mb = NULL; ++ ++ mb = list_first_entry_or_null(list, struct tipc_msg_buf, node); ++ while (mb) { ++ list_del(&mb->node); ++ vds_free_msg_buf(vds, mb); ++ mb = list_first_entry_or_null(list, struct tipc_msg_buf, node); ++ } ++} ++ ++static inline void mb_reset(struct tipc_msg_buf *mb) ++{ ++ mb->wpos = 0; ++ mb->rpos = 0; ++} ++ ++static inline void mb_reset_read(struct tipc_msg_buf *mb) ++{ ++ mb->rpos = 0; ++} ++ ++static void _free_vds(struct kref *kref) ++{ ++ struct tipc_virtio_dev *vds = ++ container_of(kref, struct tipc_virtio_dev, refcount); ++ /* ++ * If this WARN triggers, we're leaking remote memory references. ++ * ++ * No need to lock shared_handles_lock. All references to this lock ++ * should already be gone by this point, since we are freeing it in this ++ * function. ++ */ ++ WARN_ON(!RB_EMPTY_ROOT(&vds->shared_handles)); ++ kfree(vds); ++} ++ ++static void _free_chan(struct kref *kref) ++{ ++ struct tipc_chan *ch = container_of(kref, struct tipc_chan, refcount); ++ ++ if (ch->ops && ch->ops->handle_release) ++ ch->ops->handle_release(ch->ops_arg); ++ ++ kref_put(&ch->vds->refcount, _free_vds); ++ kfree(ch); ++} ++ ++static bool _put_txbuf_locked(struct tipc_virtio_dev *vds, ++ struct tipc_msg_buf *mb) ++{ ++ list_add_tail(&mb->node, &vds->free_buf_list); ++ return vds->free_msg_buf_cnt++ == 0; ++} ++ ++static struct tipc_msg_buf *_get_txbuf_locked(struct tipc_virtio_dev *vds) ++{ ++ struct tipc_msg_buf *mb; ++ ++ if (vds->state != VDS_ONLINE) ++ return ERR_PTR(-ENODEV); ++ ++ if (vds->free_msg_buf_cnt) { ++ /* take it out of free list */ ++ mb = list_first_entry(&vds->free_buf_list, ++ struct tipc_msg_buf, node); ++ list_del(&mb->node); ++ mb->shm_cnt = 0; ++ vds->free_msg_buf_cnt--; ++ } else { ++ if (vds->msg_buf_cnt >= vds->msg_buf_max_cnt) ++ return ERR_PTR(-EAGAIN); ++ ++ /* try to allocate it */ ++ mb = vds_alloc_msg_buf(vds, false); ++ if (!mb) ++ return ERR_PTR(-ENOMEM); ++ ++ vds->msg_buf_cnt++; ++ } ++ return mb; ++} ++ ++static struct tipc_msg_buf *_vds_get_txbuf(struct tipc_virtio_dev *vds) ++{ ++ struct tipc_msg_buf *mb; ++ ++ mutex_lock(&vds->lock); ++ mb = _get_txbuf_locked(vds); ++ mutex_unlock(&vds->lock); ++ ++ return mb; ++} ++ ++static void vds_put_txbuf(struct tipc_virtio_dev *vds, struct tipc_msg_buf *mb) ++{ ++ mutex_lock(&vds->lock); ++ _put_txbuf_locked(vds, mb); ++ wake_up_interruptible(&vds->sendq); ++ mutex_unlock(&vds->lock); ++} ++ ++static struct tipc_msg_buf *vds_get_txbuf(struct tipc_virtio_dev *vds, ++ long timeout) ++{ ++ struct tipc_msg_buf *mb; ++ ++ mb = _vds_get_txbuf(vds); ++ ++ if ((PTR_ERR(mb) == -EAGAIN) && timeout) { ++ DEFINE_WAIT_FUNC(wait, woken_wake_function); ++ ++ timeout = msecs_to_jiffies(timeout); ++ add_wait_queue(&vds->sendq, &wait); ++ for (;;) { ++ timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, ++ timeout); ++ if (!timeout) { ++ mb = ERR_PTR(-ETIMEDOUT); ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ mb = ERR_PTR(-ERESTARTSYS); ++ break; ++ } ++ ++ mb = _vds_get_txbuf(vds); ++ if (PTR_ERR(mb) != -EAGAIN) ++ break; ++ } ++ remove_wait_queue(&vds->sendq, &wait); ++ } ++ ++ if (IS_ERR(mb)) ++ return mb; ++ ++ if (WARN_ON(!mb)) ++ return ERR_PTR(-EINVAL); ++ ++ /* reset and reserve space for message header */ ++ mb_reset(mb); ++ mb_put_data(mb, sizeof(struct tipc_msg_hdr)); ++ ++ return mb; ++} ++ ++static int vds_queue_txbuf(struct tipc_virtio_dev *vds, ++ struct tipc_msg_buf *mb) ++{ ++ int err; ++ struct scatterlist sg; ++ bool need_notify = false; ++ ++ mutex_lock(&vds->lock); ++ if (vds->state == VDS_ONLINE) { ++ sg_init_one(&sg, mb, mb->wpos); ++ err = virtqueue_add_outbuf(vds->txvq, &sg, 1, mb, GFP_KERNEL); ++ need_notify = virtqueue_kick_prepare(vds->txvq); ++ } else { ++ err = -ENODEV; ++ } ++ mutex_unlock(&vds->lock); ++ ++ if (need_notify) ++ virtqueue_notify(vds->txvq); ++ ++ return err; ++} ++ ++static int vds_add_channel(struct tipc_virtio_dev *vds, ++ struct tipc_chan *chan) ++{ ++ int ret; ++ ++ mutex_lock(&vds->lock); ++ if (vds->state == VDS_ONLINE) { ++ ret = idr_alloc(&vds->addr_idr, chan, ++ TIPC_MIN_LOCAL_ADDR, TIPC_ANY_ADDR - 1, ++ GFP_KERNEL); ++ if (ret > 0) { ++ chan->local = ret; ++ kref_get(&chan->refcount); ++ ret = 0; ++ } ++ } else { ++ ret = -EINVAL; ++ } ++ mutex_unlock(&vds->lock); ++ ++ return ret; ++} ++ ++static void vds_del_channel(struct tipc_virtio_dev *vds, ++ struct tipc_chan *chan) ++{ ++ mutex_lock(&vds->lock); ++ if (chan->local) { ++ idr_remove(&vds->addr_idr, chan->local); ++ chan->local = 0; ++ chan->remote = 0; ++ kref_put(&chan->refcount, _free_chan); ++ } ++ mutex_unlock(&vds->lock); ++} ++ ++static struct tipc_chan *vds_lookup_channel(struct tipc_virtio_dev *vds, ++ u32 addr) ++{ ++ int id; ++ struct tipc_chan *chan = NULL; ++ ++ mutex_lock(&vds->lock); ++ if (addr == TIPC_ANY_ADDR) { ++ id = idr_for_each(&vds->addr_idr, _match_any, NULL); ++ if (id > 0) ++ chan = idr_find(&vds->addr_idr, id); ++ } else { ++ chan = idr_find(&vds->addr_idr, addr); ++ } ++ if (chan) ++ kref_get(&chan->refcount); ++ mutex_unlock(&vds->lock); ++ ++ return chan; ++} ++ ++static struct tipc_chan *vds_create_channel(struct tipc_virtio_dev *vds, ++ const struct tipc_chan_ops *ops, ++ void *ops_arg) ++{ ++ int ret; ++ struct tipc_chan *chan = NULL; ++ ++ if (!vds) ++ return ERR_PTR(-ENOENT); ++ ++ if (!ops) ++ return ERR_PTR(-EINVAL); ++ ++ chan = kzalloc(sizeof(*chan), GFP_KERNEL); ++ if (!chan) ++ return ERR_PTR(-ENOMEM); ++ ++ kref_get(&vds->refcount); ++ chan->vds = vds; ++ chan->ops = ops; ++ chan->ops_arg = ops_arg; ++ mutex_init(&chan->lock); ++ kref_init(&chan->refcount); ++ chan->state = TIPC_DISCONNECTED; ++ ++ ret = vds_add_channel(vds, chan); ++ if (ret) { ++ kfree(chan); ++ kref_put(&vds->refcount, _free_vds); ++ return ERR_PTR(ret); ++ } ++ ++ return chan; ++} ++ ++static void fill_msg_hdr(struct tipc_msg_buf *mb, u32 src, u32 dst) ++{ ++ struct tipc_msg_hdr *hdr = mb_get_data(mb, sizeof(*hdr)); ++ ++ hdr->src = src; ++ hdr->dst = dst; ++ hdr->len = mb_avail_data(mb); ++ hdr->flags = 0; ++ hdr->shm_cnt = mb->shm_cnt; ++ hdr->reserved = 0; ++} ++ ++static int tipc_shared_handle_new(struct tipc_shared_handle **shared_handle, ++ struct tipc_virtio_dev *vds) ++{ ++ struct tipc_shared_handle *out = kzalloc(sizeof(*out), GFP_KERNEL); ++ ++ if (!out) ++ return -ENOMEM; ++ ++ out->vds = vds; ++ *shared_handle = out; ++ ++ return 0; ++} ++ ++static struct device *tipc_shared_handle_dev(struct tipc_shared_handle ++ *shared_handle) ++{ ++ return shared_handle->vds->vdev->dev.parent->parent; ++} ++ ++static bool is_same_memory_region(struct tipc_shared_handle *h1, ++ struct tipc_shared_handle *h2) ++{ ++ return h1->tipc.obj_id == h2->tipc.obj_id && ++ h1->tipc.size == h2->tipc.size && ++ h1->tipc.tag == h2->tipc.tag && ++ h1->dma_buf == h2->dma_buf && ++ h1->shared == h2->shared; ++} ++ ++static bool dma_buf_owns_shared_mem_id(struct tipc_shared_handle *h) ++{ ++ /* h->shared is true only if dma_buf did not own an shared memory ID */ ++ return !h->shared; ++} ++ ++static void tipc_shared_handle_register(struct tipc_shared_handle ++ *new_handle) ++{ ++ struct tipc_virtio_dev *vds = new_handle->vds; ++ struct rb_node **new; ++ struct rb_node *parent = NULL; ++ ++ mutex_lock(&vds->shared_handles_lock); ++ ++ new = &vds->shared_handles.rb_node; ++ while (*new) { ++ struct tipc_shared_handle *handle = ++ rb_entry(*new, struct tipc_shared_handle, node); ++ parent = *new; ++ /* ++ * An obj_id can be registered multiple times if it's owned by a ++ * dma_buf, because in this case we use the same obj_id across ++ * multiple memory transfer operations. ++ */ ++ if (handle->tipc.obj_id == new_handle->tipc.obj_id) { ++ if (dma_buf_owns_shared_mem_id(new_handle)) { ++ WARN_ON(!is_same_memory_region(handle, ++ new_handle)); ++ } else { ++ WARN(1, "This handle is already registered"); ++ goto already_registered; ++ } ++ } ++ ++ if (handle->tipc.obj_id > new_handle->tipc.obj_id) ++ new = &((*new)->rb_left); ++ else ++ new = &((*new)->rb_right); ++ } ++ ++ rb_link_node(&new_handle->node, parent, new); ++ rb_insert_color(&new_handle->node, &vds->shared_handles); ++ ++already_registered: ++ mutex_unlock(&vds->shared_handles_lock); ++} ++ ++static struct tipc_shared_handle *tipc_shared_handle_take(struct tipc_virtio_dev ++ *vds, ++ trusty_shared_mem_id_t ++ obj_id) ++{ ++ struct rb_node *node; ++ struct tipc_shared_handle *out = NULL; ++ ++ mutex_lock(&vds->shared_handles_lock); ++ ++ node = vds->shared_handles.rb_node; ++ while (node) { ++ struct tipc_shared_handle *handle = ++ rb_entry(node, struct tipc_shared_handle, node); ++ if (obj_id == handle->tipc.obj_id) { ++ rb_erase(node, &vds->shared_handles); ++ out = handle; ++ break; ++ } else if (obj_id < handle->tipc.obj_id) { ++ node = node->rb_left; ++ } else { ++ node = node->rb_right; ++ } ++ } ++ ++ mutex_unlock(&vds->shared_handles_lock); ++ ++ return out; ++} ++ ++static int tipc_shared_handle_drop(struct tipc_shared_handle *shared_handle) ++{ ++ int ret; ++ struct tipc_virtio_dev *vds = shared_handle->vds; ++ struct device *dev = tipc_shared_handle_dev(shared_handle); ++ ++ if (shared_handle->shared) { ++ /* ++ * If this warning fires, it means this shared handle was still ++ * in the set of active handles. This shouldn't happen (calling ++ * code should ensure it is out if the tree) but this serves as ++ * an extra check before it is released. ++ * ++ * However, the take itself should clean this incorrect state up ++ * by removing the handle from the tree. ++ * ++ * This warning is only applicable when registering a handle ++ * multiple times is not allowed, i.e. when dma_buf doesn't own ++ * the handle. ++ */ ++ WARN_ON(tipc_shared_handle_take(vds, ++ shared_handle->tipc.obj_id)); ++ ++ ret = trusty_reclaim_memory(dev, ++ shared_handle->tipc.obj_id, ++ shared_handle->sgt->sgl, ++ shared_handle->sgt->orig_nents); ++ if (ret) { ++ /* ++ * We can't safely release this, it may still be in ++ * use outside Linux. ++ */ ++ dev_warn(dev, "Failed to drop handle, leaking...\n"); ++ return ret; ++ } ++ } ++ ++ if (shared_handle->sgt) ++ dma_buf_unmap_attachment(shared_handle->attach, ++ shared_handle->sgt, DMA_BIDIRECTIONAL); ++ if (shared_handle->attach) ++ dma_buf_detach(shared_handle->dma_buf, shared_handle->attach); ++ if (shared_handle->dma_buf) ++ dma_buf_put(shared_handle->dma_buf); ++ ++ kfree(shared_handle); ++ ++ return 0; ++} ++ ++/*****************************************************************************/ ++ ++struct tipc_chan *tipc_create_channel(struct device *dev, ++ const struct tipc_chan_ops *ops, ++ void *ops_arg) ++{ ++ struct virtio_device *vd; ++ struct tipc_chan *chan; ++ struct tipc_virtio_dev *vds; ++ ++ mutex_lock(&tipc_devices_lock); ++ if (dev) { ++ vd = container_of(dev, struct virtio_device, dev); ++ } else { ++ vd = default_vdev; ++ if (!vd) { ++ mutex_unlock(&tipc_devices_lock); ++ return ERR_PTR(-ENOENT); ++ } ++ } ++ vds = vd->priv; ++ kref_get(&vds->refcount); ++ mutex_unlock(&tipc_devices_lock); ++ ++ chan = vds_create_channel(vds, ops, ops_arg); ++ kref_put(&vds->refcount, _free_vds); ++ return chan; ++} ++EXPORT_SYMBOL(tipc_create_channel); ++ ++struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan) ++{ ++ return vds_alloc_msg_buf(chan->vds, true); ++} ++EXPORT_SYMBOL(tipc_chan_get_rxbuf); ++ ++void tipc_chan_put_rxbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb) ++{ ++ vds_free_msg_buf(chan->vds, mb); ++} ++EXPORT_SYMBOL(tipc_chan_put_rxbuf); ++ ++struct tipc_msg_buf *tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, ++ long timeout) ++{ ++ return vds_get_txbuf(chan->vds, timeout); ++} ++EXPORT_SYMBOL(tipc_chan_get_txbuf_timeout); ++ ++void tipc_chan_put_txbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb) ++{ ++ vds_put_txbuf(chan->vds, mb); ++} ++EXPORT_SYMBOL(tipc_chan_put_txbuf); ++ ++int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb) ++{ ++ int err; ++ ++ mutex_lock(&chan->lock); ++ switch (chan->state) { ++ case TIPC_CONNECTED: ++ fill_msg_hdr(mb, chan->local, chan->remote); ++ err = vds_queue_txbuf(chan->vds, mb); ++ if (err) { ++ /* this should never happen */ ++ dev_err(&chan->vds->vdev->dev, ++ "%s: failed to queue tx buffer (%d)\n", ++ __func__, err); ++ } ++ break; ++ case TIPC_DISCONNECTED: ++ case TIPC_CONNECTING: ++ err = -ENOTCONN; ++ break; ++ case TIPC_STALE: ++ err = -ESHUTDOWN; ++ break; ++ default: ++ err = -EBADFD; ++ dev_err(&chan->vds->vdev->dev, ++ "%s: unexpected channel state %d\n", ++ __func__, chan->state); ++ } ++ mutex_unlock(&chan->lock); ++ return err; ++} ++EXPORT_SYMBOL(tipc_chan_queue_msg); ++ ++ ++int tipc_chan_connect(struct tipc_chan *chan, const char *name) ++{ ++ int err; ++ struct tipc_ctrl_msg *msg; ++ struct tipc_conn_req_body *body; ++ struct tipc_msg_buf *txbuf; ++ ++ txbuf = vds_get_txbuf(chan->vds, TXBUF_TIMEOUT); ++ if (IS_ERR(txbuf)) ++ return PTR_ERR(txbuf); ++ ++ /* reserve space for connection request control message */ ++ msg = mb_put_data(txbuf, sizeof(*msg) + sizeof(*body)); ++ body = (struct tipc_conn_req_body *)msg->body; ++ ++ /* fill message */ ++ msg->type = TIPC_CTRL_MSGTYPE_CONN_REQ; ++ msg->body_len = sizeof(*body); ++ ++ strncpy(body->name, name, sizeof(body->name)); ++ body->name[sizeof(body->name)-1] = '\0'; ++ ++ mutex_lock(&chan->lock); ++ switch (chan->state) { ++ case TIPC_DISCONNECTED: ++ /* save service name we are connecting to */ ++ strcpy(chan->srv_name, body->name); ++ ++ fill_msg_hdr(txbuf, chan->local, TIPC_CTRL_ADDR); ++ err = vds_queue_txbuf(chan->vds, txbuf); ++ if (err) { ++ /* this should never happen */ ++ dev_err(&chan->vds->vdev->dev, ++ "%s: failed to queue tx buffer (%d)\n", ++ __func__, err); ++ } else { ++ chan->state = TIPC_CONNECTING; ++ txbuf = NULL; /* prevents discarding buffer */ ++ } ++ break; ++ case TIPC_CONNECTED: ++ case TIPC_CONNECTING: ++ /* check if we are trying to connect to the same service */ ++ if (strcmp(chan->srv_name, body->name) == 0) ++ err = 0; ++ else ++ if (chan->state == TIPC_CONNECTING) ++ err = -EALREADY; /* in progress */ ++ else ++ err = -EISCONN; /* already connected */ ++ break; ++ ++ case TIPC_STALE: ++ err = -ESHUTDOWN; ++ break; ++ default: ++ err = -EBADFD; ++ dev_err(&chan->vds->vdev->dev, ++ "%s: unexpected channel state %d\n", ++ __func__, chan->state); ++ break; ++ } ++ mutex_unlock(&chan->lock); ++ ++ if (txbuf) ++ tipc_chan_put_txbuf(chan, txbuf); /* discard it */ ++ ++ return err; ++} ++EXPORT_SYMBOL(tipc_chan_connect); ++ ++int tipc_chan_shutdown(struct tipc_chan *chan) ++{ ++ int err; ++ struct tipc_ctrl_msg *msg; ++ struct tipc_disc_req_body *body; ++ struct tipc_msg_buf *txbuf = NULL; ++ ++ /* get tx buffer */ ++ txbuf = vds_get_txbuf(chan->vds, TXBUF_TIMEOUT); ++ if (IS_ERR(txbuf)) ++ return PTR_ERR(txbuf); ++ ++ mutex_lock(&chan->lock); ++ if (chan->state == TIPC_CONNECTED || chan->state == TIPC_CONNECTING) { ++ /* reserve space for disconnect request control message */ ++ msg = mb_put_data(txbuf, sizeof(*msg) + sizeof(*body)); ++ body = (struct tipc_disc_req_body *)msg->body; ++ ++ msg->type = TIPC_CTRL_MSGTYPE_DISC_REQ; ++ msg->body_len = sizeof(*body); ++ body->target = chan->remote; ++ ++ fill_msg_hdr(txbuf, chan->local, TIPC_CTRL_ADDR); ++ err = vds_queue_txbuf(chan->vds, txbuf); ++ if (err) { ++ /* this should never happen */ ++ dev_err(&chan->vds->vdev->dev, ++ "%s: failed to queue tx buffer (%d)\n", ++ __func__, err); ++ } ++ } else { ++ err = -ENOTCONN; ++ } ++ chan->state = TIPC_STALE; ++ mutex_unlock(&chan->lock); ++ ++ if (err) { ++ /* release buffer */ ++ tipc_chan_put_txbuf(chan, txbuf); ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL(tipc_chan_shutdown); ++ ++void tipc_chan_destroy(struct tipc_chan *chan) ++{ ++ vds_del_channel(chan->vds, chan); ++ kref_put(&chan->refcount, _free_chan); ++} ++EXPORT_SYMBOL(tipc_chan_destroy); ++ ++/***************************************************************************/ ++ ++struct tipc_dn_chan { ++ int state; ++ struct mutex lock; /* protects rx_msg_queue list and channel state */ ++ struct tipc_chan *chan; ++ wait_queue_head_t readq; ++ struct completion reply_comp; ++ struct list_head rx_msg_queue; ++}; ++ ++static int dn_wait_for_reply(struct tipc_dn_chan *dn, int timeout) ++{ ++ int ret; ++ ++ ret = wait_for_completion_interruptible_timeout(&dn->reply_comp, ++ msecs_to_jiffies(timeout)); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&dn->lock); ++ if (!ret) { ++ /* no reply from remote */ ++ dn->state = TIPC_STALE; ++ ret = -ETIMEDOUT; ++ } else { ++ /* got reply */ ++ if (dn->state == TIPC_CONNECTED) ++ ret = 0; ++ else if (dn->state == TIPC_DISCONNECTED) ++ if (!list_empty(&dn->rx_msg_queue)) ++ ret = 0; ++ else ++ ret = -ENOTCONN; ++ else ++ ret = -EIO; ++ } ++ mutex_unlock(&dn->lock); ++ ++ return ret; ++} ++ ++static struct tipc_msg_buf *dn_handle_msg(void *data, ++ struct tipc_msg_buf *rxbuf) ++{ ++ struct tipc_dn_chan *dn = data; ++ struct tipc_msg_buf *newbuf = rxbuf; ++ ++ mutex_lock(&dn->lock); ++ if (dn->state == TIPC_CONNECTED) { ++ /* get new buffer */ ++ newbuf = tipc_chan_get_rxbuf(dn->chan); ++ if (newbuf) { ++ /* queue an old buffer and return a new one */ ++ list_add_tail(&rxbuf->node, &dn->rx_msg_queue); ++ wake_up_interruptible(&dn->readq); ++ } else { ++ /* ++ * return an old buffer effectively discarding ++ * incoming message ++ */ ++ dev_err(&dn->chan->vds->vdev->dev, ++ "%s: discard incoming message\n", __func__); ++ newbuf = rxbuf; ++ } ++ } ++ mutex_unlock(&dn->lock); ++ ++ return newbuf; ++} ++ ++static void dn_connected(struct tipc_dn_chan *dn) ++{ ++ mutex_lock(&dn->lock); ++ dn->state = TIPC_CONNECTED; ++ ++ /* complete all pending */ ++ complete(&dn->reply_comp); ++ ++ mutex_unlock(&dn->lock); ++} ++ ++static void dn_disconnected(struct tipc_dn_chan *dn) ++{ ++ mutex_lock(&dn->lock); ++ dn->state = TIPC_DISCONNECTED; ++ ++ /* complete all pending */ ++ complete(&dn->reply_comp); ++ ++ /* wakeup all readers */ ++ wake_up_interruptible_all(&dn->readq); ++ ++ mutex_unlock(&dn->lock); ++} ++ ++static void dn_shutdown(struct tipc_dn_chan *dn) ++{ ++ mutex_lock(&dn->lock); ++ ++ /* set state to STALE */ ++ dn->state = TIPC_STALE; ++ ++ /* complete all pending */ ++ complete(&dn->reply_comp); ++ ++ /* wakeup all readers */ ++ wake_up_interruptible_all(&dn->readq); ++ ++ mutex_unlock(&dn->lock); ++} ++ ++static void dn_handle_event(void *data, int event) ++{ ++ struct tipc_dn_chan *dn = data; ++ ++ switch (event) { ++ case TIPC_CHANNEL_SHUTDOWN: ++ dn_shutdown(dn); ++ break; ++ ++ case TIPC_CHANNEL_DISCONNECTED: ++ dn_disconnected(dn); ++ break; ++ ++ case TIPC_CHANNEL_CONNECTED: ++ dn_connected(dn); ++ break; ++ ++ default: ++ dev_err(&dn->chan->vds->vdev->dev, ++ "%s: unhandled event %d\n", __func__, event); ++ break; ++ } ++} ++ ++static void dn_handle_release(void *data) ++{ ++ kfree(data); ++} ++ ++static const struct tipc_chan_ops _dn_ops = { ++ .handle_msg = dn_handle_msg, ++ .handle_event = dn_handle_event, ++ .handle_release = dn_handle_release, ++}; ++ ++#define cdev_to_cdn(c) container_of((c), struct tipc_cdev_node, cdev) ++#define cdn_to_vds(cdn) container_of((cdn), struct tipc_virtio_dev, cdev_node) ++ ++static struct tipc_virtio_dev *_dn_lookup_vds(struct tipc_cdev_node *cdn) ++{ ++ int ret; ++ struct tipc_virtio_dev *vds = NULL; ++ ++ mutex_lock(&tipc_devices_lock); ++ ret = idr_for_each(&tipc_devices, _match_data, cdn); ++ if (ret) { ++ vds = cdn_to_vds(cdn); ++ kref_get(&vds->refcount); ++ } ++ mutex_unlock(&tipc_devices_lock); ++ return vds; ++} ++ ++static int tipc_open(struct inode *inode, struct file *filp) ++{ ++ int ret; ++ struct tipc_virtio_dev *vds; ++ struct tipc_dn_chan *dn; ++ struct tipc_cdev_node *cdn = cdev_to_cdn(inode->i_cdev); ++ ++ vds = _dn_lookup_vds(cdn); ++ if (!vds) { ++ ret = -ENOENT; ++ goto err_vds_lookup; ++ } ++ ++ dn = kzalloc(sizeof(*dn), GFP_KERNEL); ++ if (!dn) { ++ ret = -ENOMEM; ++ goto err_alloc_chan; ++ } ++ ++ mutex_init(&dn->lock); ++ init_waitqueue_head(&dn->readq); ++ init_completion(&dn->reply_comp); ++ INIT_LIST_HEAD(&dn->rx_msg_queue); ++ ++ dn->state = TIPC_DISCONNECTED; ++ ++ dn->chan = vds_create_channel(vds, &_dn_ops, dn); ++ if (IS_ERR(dn->chan)) { ++ ret = PTR_ERR(dn->chan); ++ goto err_create_chan; ++ } ++ ++ filp->private_data = dn; ++ kref_put(&vds->refcount, _free_vds); ++ return 0; ++ ++err_create_chan: ++ kfree(dn); ++err_alloc_chan: ++ kref_put(&vds->refcount, _free_vds); ++err_vds_lookup: ++ return ret; ++} ++ ++ ++static int dn_connect_ioctl(struct tipc_dn_chan *dn, char __user *usr_name) ++{ ++ int ret; ++ char name[MAX_SRV_NAME_LEN]; ++ ++ /* copy in service name from user space */ ++ ret = strncpy_from_user(name, usr_name, sizeof(name)); ++ if (ret < 0) ++ return ret; ++ if (ret == sizeof(name)) ++ return -ENAMETOOLONG; ++ ++ /* send connect request */ ++ ret = tipc_chan_connect(dn->chan, name); ++ if (ret) ++ return ret; ++ ++ /* and wait for reply */ ++ return dn_wait_for_reply(dn, REPLY_TIMEOUT); ++} ++ ++static int dn_share_fd(struct tipc_dn_chan *dn, int fd, ++ enum transfer_kind transfer_kind, ++ struct tipc_shared_handle **out) ++{ ++ int ret = 0; ++ struct tipc_shared_handle *shared_handle = NULL; ++ struct file *file = NULL; ++ struct device *dev = &dn->chan->vds->vdev->dev; ++ bool writable = false; ++ pgprot_t prot; ++ u64 tag = 0; ++ trusty_shared_mem_id_t mem_id; ++ bool lend; ++ ++ if (dn->state != TIPC_CONNECTED) { ++ dev_dbg(dev, "Tried to share fd while not connected\n"); ++ return -ENOTCONN; ++ } ++ ++ file = fget(fd); ++ if (!file) { ++ dev_dbg(dev, "Invalid fd (%d)\n", fd); ++ return -EBADF; ++ } ++ ++ if (!(file->f_mode & FMODE_READ)) { ++ dev_dbg(dev, "Cannot create write-only mapping\n"); ++ fput(file); ++ return -EACCES; ++ } ++ ++ writable = file->f_mode & FMODE_WRITE; ++ prot = writable ? PAGE_KERNEL : PAGE_KERNEL_RO; ++ fput(file); ++ file = NULL; ++ ++ ret = tipc_shared_handle_new(&shared_handle, dn->chan->vds); ++ if (ret) ++ return ret; ++ ++ shared_handle->dma_buf = dma_buf_get(fd); ++ if (IS_ERR(shared_handle->dma_buf)) { ++ ret = PTR_ERR(shared_handle->dma_buf); ++ shared_handle->dma_buf = NULL; ++ dev_dbg(dev, "Unable to get dma buf from fd (%d)\n", ret); ++ goto cleanup_handle; ++ } ++ ++ tag = trusty_dma_buf_get_ffa_tag(shared_handle->dma_buf); ++ ret = trusty_dma_buf_get_shared_mem_id(shared_handle->dma_buf, &mem_id); ++ /* ++ * Buffers with a preallocated mem_id should only be sent to Trusty ++ * using TRUSTY_SEND_SECURE. And conversely, TRUSTY_SEND_SECURE should ++ * only be used to send buffers with preallcoated mem_id. ++ */ ++ if (!ret) { ++ /* Use shared memory ID owned by dma_buf */ ++ /* TODO: Enforce transfer_kind == TRUSTY_SEND_SECURE */ ++ WARN_ONCE(transfer_kind != TRUSTY_SEND_SECURE, ++ "Use TRUSTY_SEND_SECURE instead"); ++ goto mem_id_allocated; ++ } ++ ++ if (ret != -ENODATA) { ++ dev_err(dev, "dma_buf can't be transferred (%d)\n", ret); ++ goto cleanup_handle; ++ } ++ ++ if (transfer_kind == TRUSTY_SEND_SECURE) { ++ dev_err(dev, "No mem ID for TRUSTY_SEND_SECURE\n"); ++ goto cleanup_handle; ++ } ++ lend = (transfer_kind == TRUSTY_LEND); ++ ++ shared_handle->attach = dma_buf_attach(shared_handle->dma_buf, dev); ++ if (IS_ERR(shared_handle->attach)) { ++ ret = PTR_ERR(shared_handle->attach); ++ shared_handle->attach = NULL; ++ dev_dbg(dev, "Unable to attach to dma_buf (%d)\n", ret); ++ goto cleanup_handle; ++ } ++ ++ shared_handle->sgt = dma_buf_map_attachment(shared_handle->attach, ++ DMA_BIDIRECTIONAL); ++ if (IS_ERR(shared_handle->sgt)) { ++ ret = PTR_ERR(shared_handle->sgt); ++ shared_handle->sgt = NULL; ++ dev_dbg(dev, "Failed to match attachment (%d)\n", ret); ++ goto cleanup_handle; ++ } ++ ++ ret = trusty_transfer_memory(tipc_shared_handle_dev(shared_handle), ++ &mem_id, shared_handle->sgt->sgl, ++ shared_handle->sgt->orig_nents, prot, tag, ++ lend); ++ ++ if (ret < 0) { ++ dev_dbg(dev, "Transferring memory failed: %d\n", ret); ++ /* ++ * The handle now has a sgt containing the pages, so we no ++ * longer need to clean up the pages directly. ++ */ ++ goto cleanup_handle; ++ } ++ shared_handle->shared = true; ++ ++mem_id_allocated: ++ shared_handle->tipc.obj_id = mem_id; ++ shared_handle->tipc.size = shared_handle->dma_buf->size; ++ shared_handle->tipc.tag = tag; ++ *out = shared_handle; ++ return 0; ++ ++cleanup_handle: ++ tipc_shared_handle_drop(shared_handle); ++ return ret; ++} ++ ++static ssize_t txbuf_write_iter(struct tipc_msg_buf *txbuf, ++ struct iov_iter *iter) ++{ ++ size_t len; ++ /* message length */ ++ len = iov_iter_count(iter); ++ ++ /* check available space */ ++ if (len > mb_avail_space(txbuf)) ++ return -EMSGSIZE; ++ ++ /* copy in message data */ ++ if (copy_from_iter(mb_put_data(txbuf, len), len, iter) != len) ++ return -EFAULT; ++ ++ return len; ++} ++ ++static ssize_t txbuf_write_handles(struct tipc_msg_buf *txbuf, ++ struct tipc_shared_handle **shm_handles, ++ size_t shm_cnt) ++{ ++ size_t idx; ++ ++ /* message length */ ++ size_t len = shm_cnt * sizeof(struct tipc_shm); ++ ++ /* check available space */ ++ if (len > mb_avail_space(txbuf)) ++ return -EMSGSIZE; ++ ++ /* copy over handles */ ++ for (idx = 0; idx < shm_cnt; idx++) { ++ memcpy(mb_put_data(txbuf, sizeof(struct tipc_shm)), ++ &shm_handles[idx]->tipc, ++ sizeof(struct tipc_shm)); ++ } ++ ++ txbuf->shm_cnt += shm_cnt; ++ ++ return len; ++} ++ ++static long filp_send_ioctl(struct file *filp, ++ const struct tipc_send_msg_req __user *arg) ++{ ++ struct tipc_send_msg_req req; ++ struct iovec fast_iovs[UIO_FASTIOV]; ++ struct iovec *iov = fast_iovs; ++ struct iov_iter iter; ++ struct trusty_shm *shm = NULL; ++ struct tipc_shared_handle **shm_handles = NULL; ++ int shm_idx = 0; ++ int release_idx; ++ struct tipc_dn_chan *dn = filp->private_data; ++ struct tipc_virtio_dev *vds = dn->chan->vds; ++ struct device *dev = &vds->vdev->dev; ++ long timeout = TXBUF_TIMEOUT; ++ struct tipc_msg_buf *txbuf = NULL; ++ long ret = 0; ++ ssize_t data_len = 0; ++ ssize_t shm_len = 0; ++ ++ if (copy_from_user(&req, arg, sizeof(req))) ++ return -EFAULT; ++ ++ if (req.shm_cnt > U16_MAX) ++ return -E2BIG; ++ ++ shm = kmalloc_array(req.shm_cnt, sizeof(*shm), GFP_KERNEL); ++ if (!shm) ++ return -ENOMEM; ++ ++ shm_handles = kmalloc_array(req.shm_cnt, sizeof(*shm_handles), ++ GFP_KERNEL); ++ if (!shm_handles) { ++ ret = -ENOMEM; ++ goto shm_handles_alloc_failed; ++ } ++ ++ if (copy_from_user(shm, u64_to_user_ptr(req.shm), ++ req.shm_cnt * sizeof(struct trusty_shm))) { ++ ret = -EFAULT; ++ goto load_shm_args_failed; ++ } ++ ++ ret = import_iovec(READ, u64_to_user_ptr(req.iov), req.iov_cnt, ++ ARRAY_SIZE(fast_iovs), &iov, &iter); ++ if (ret < 0) { ++ dev_dbg(dev, "Failed to import iovec\n"); ++ goto iov_import_failed; ++ } ++ ++ for (shm_idx = 0; shm_idx < req.shm_cnt; shm_idx++) { ++ switch (shm[shm_idx].transfer) { ++ case TRUSTY_SHARE: ++ case TRUSTY_LEND: ++ case TRUSTY_SEND_SECURE: ++ break; ++ default: ++ dev_err(dev, "Unknown transfer type: 0x%x\n", ++ shm[shm_idx].transfer); ++ goto shm_share_failed; ++ } ++ ret = dn_share_fd(dn, shm[shm_idx].fd, shm[shm_idx].transfer, ++ &shm_handles[shm_idx]); ++ if (ret) { ++ dev_dbg(dev, "Forwarding memory failed\n" ++ ); ++ goto shm_share_failed; ++ } ++ } ++ ++ if (filp->f_flags & O_NONBLOCK) ++ timeout = 0; ++ ++ txbuf = tipc_chan_get_txbuf_timeout(dn->chan, timeout); ++ if (IS_ERR(txbuf)) { ++ dev_dbg(dev, "Failed to get txbuffer\n"); ++ ret = PTR_ERR(txbuf); ++ goto get_txbuf_failed; ++ } ++ ++ data_len = txbuf_write_iter(txbuf, &iter); ++ if (data_len < 0) { ++ ret = data_len; ++ goto txbuf_write_failed; ++ } ++ ++ shm_len = txbuf_write_handles(txbuf, shm_handles, req.shm_cnt); ++ if (shm_len < 0) { ++ ret = shm_len; ++ goto txbuf_write_failed; ++ } ++ ++ /* ++ * These need to be aded to the index before queueing the message. ++ * As soon as the message is sent, we may receive a message back from ++ * Trusty saying it's no longer in use, and the shared_handle needs ++ * to be there when that happens. ++ */ ++ for (shm_idx = 0; shm_idx < req.shm_cnt; shm_idx++) ++ tipc_shared_handle_register(shm_handles[shm_idx]); ++ ++ ret = tipc_chan_queue_msg(dn->chan, txbuf); ++ ++ if (ret) ++ goto queue_failed; ++ ++ ret = data_len; ++ ++common_cleanup: ++ kfree(iov); ++iov_import_failed: ++load_shm_args_failed: ++ kfree(shm_handles); ++shm_handles_alloc_failed: ++ kfree(shm); ++ return ret; ++ ++queue_failed: ++ for (release_idx = 0; release_idx < req.shm_cnt; release_idx++) ++ tipc_shared_handle_take(vds, ++ shm_handles[release_idx]->tipc.obj_id); ++txbuf_write_failed: ++ tipc_chan_put_txbuf(dn->chan, txbuf); ++get_txbuf_failed: ++shm_share_failed: ++ for (shm_idx--; shm_idx >= 0; shm_idx--) ++ tipc_shared_handle_drop(shm_handles[shm_idx]); ++ goto common_cleanup; ++} ++ ++static long tipc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct tipc_dn_chan *dn = filp->private_data; ++ ++ switch (cmd) { ++ case TIPC_IOC_CONNECT: ++ return dn_connect_ioctl(dn, (char __user *)arg); ++ case TIPC_IOC_SEND_MSG: ++ return filp_send_ioctl(filp, ++ (const struct tipc_send_msg_req __user *) ++ arg); ++ default: ++ dev_dbg(&dn->chan->vds->vdev->dev, ++ "Unhandled ioctl cmd: 0x%x\n", cmd); ++ return -ENOTTY; ++ } ++} ++ ++#ifdef CONFIG_COMPAT ++static long tipc_compat_ioctl(struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct tipc_dn_chan *dn = filp->private_data; ++ ++ switch (cmd) { ++ case TIPC_IOC32_CONNECT: ++ cmd = TIPC_IOC_CONNECT; ++ break; ++ default: ++ dev_dbg(&dn->chan->vds->vdev->dev, ++ "Unhandled compat ioctl command: 0x%x\n", cmd); ++ return -ENOTTY; ++ } ++ return tipc_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif ++ ++static inline bool _got_rx(struct tipc_dn_chan *dn) ++{ ++ if (dn->state != TIPC_CONNECTED) ++ return true; ++ ++ if (!list_empty(&dn->rx_msg_queue)) ++ return true; ++ ++ return false; ++} ++ ++static ssize_t tipc_read_iter(struct kiocb *iocb, struct iov_iter *iter) ++{ ++ ssize_t ret; ++ size_t len; ++ struct tipc_msg_buf *mb; ++ struct file *filp = iocb->ki_filp; ++ struct tipc_dn_chan *dn = filp->private_data; ++ ++ mutex_lock(&dn->lock); ++ ++ while (list_empty(&dn->rx_msg_queue)) { ++ if (dn->state != TIPC_CONNECTED) { ++ if (dn->state == TIPC_CONNECTING) ++ ret = -ENOTCONN; ++ else if (dn->state == TIPC_DISCONNECTED) ++ ret = -ENOTCONN; ++ else if (dn->state == TIPC_STALE) ++ ret = -ESHUTDOWN; ++ else ++ ret = -EBADFD; ++ goto out; ++ } ++ ++ mutex_unlock(&dn->lock); ++ ++ if (filp->f_flags & O_NONBLOCK) ++ return -EAGAIN; ++ ++ if (wait_event_interruptible(dn->readq, _got_rx(dn))) ++ return -ERESTARTSYS; ++ ++ mutex_lock(&dn->lock); ++ } ++ ++ mb = list_first_entry(&dn->rx_msg_queue, struct tipc_msg_buf, node); ++ ++ len = mb_avail_data(mb); ++ if (len > iov_iter_count(iter)) { ++ ret = -EMSGSIZE; ++ goto out; ++ } ++ ++ if (copy_to_iter(mb_get_data(mb, len), len, iter) != len) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = len; ++ list_del(&mb->node); ++ tipc_chan_put_rxbuf(dn->chan, mb); ++ ++out: ++ mutex_unlock(&dn->lock); ++ return ret; ++} ++ ++static ssize_t tipc_write_iter(struct kiocb *iocb, struct iov_iter *iter) ++{ ++ struct file *filp = iocb->ki_filp; ++ struct tipc_dn_chan *dn = filp->private_data; ++ long timeout = TXBUF_TIMEOUT; ++ struct tipc_msg_buf *txbuf = NULL; ++ ssize_t ret = 0; ++ ssize_t len = 0; ++ ++ if (filp->f_flags & O_NONBLOCK) ++ timeout = 0; ++ ++ txbuf = tipc_chan_get_txbuf_timeout(dn->chan, timeout); ++ ++ if (IS_ERR(txbuf)) ++ return PTR_ERR(txbuf); ++ ++ len = txbuf_write_iter(txbuf, iter); ++ if (len < 0) ++ goto err_out; ++ ++ /* queue message */ ++ ret = tipc_chan_queue_msg(dn->chan, txbuf); ++ if (ret) ++ goto err_out; ++ ++ return len; ++ ++err_out: ++ tipc_chan_put_txbuf(dn->chan, txbuf); ++ return ret; ++} ++ ++static __poll_t tipc_poll(struct file *filp, poll_table *wait) ++{ ++ __poll_t mask = 0; ++ struct tipc_dn_chan *dn = filp->private_data; ++ ++ mutex_lock(&dn->lock); ++ ++ poll_wait(filp, &dn->readq, wait); ++ ++ /* Writes always succeed for now */ ++ mask |= EPOLLOUT | EPOLLWRNORM; ++ ++ if (!list_empty(&dn->rx_msg_queue)) ++ mask |= EPOLLIN | EPOLLRDNORM; ++ ++ if (dn->state != TIPC_CONNECTED) ++ mask |= EPOLLERR; ++ ++ mutex_unlock(&dn->lock); ++ return mask; ++} ++ ++ ++static int tipc_release(struct inode *inode, struct file *filp) ++{ ++ struct tipc_dn_chan *dn = filp->private_data; ++ ++ dn_shutdown(dn); ++ ++ /* free all pending buffers */ ++ vds_free_msg_buf_list(dn->chan->vds, &dn->rx_msg_queue); ++ ++ /* shutdown channel */ ++ tipc_chan_shutdown(dn->chan); ++ ++ /* and destroy it */ ++ tipc_chan_destroy(dn->chan); ++ ++ return 0; ++} ++ ++static const struct file_operations tipc_fops = { ++ .open = tipc_open, ++ .release = tipc_release, ++ .unlocked_ioctl = tipc_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = tipc_compat_ioctl, ++#endif ++ .read_iter = tipc_read_iter, ++ .write_iter = tipc_write_iter, ++ .poll = tipc_poll, ++ .owner = THIS_MODULE, ++}; ++ ++/*****************************************************************************/ ++ ++static void chan_trigger_event(struct tipc_chan *chan, int event) ++{ ++ if (!event) ++ return; ++ ++ chan->ops->handle_event(chan->ops_arg, event); ++} ++ ++static void _cleanup_vq(struct tipc_virtio_dev *vds, struct virtqueue *vq) ++{ ++ struct tipc_msg_buf *mb; ++ ++ while ((mb = virtqueue_detach_unused_buf(vq)) != NULL) ++ vds_free_msg_buf(vds, mb); ++} ++ ++static int _create_cdev_node(struct device *parent, ++ struct tipc_cdev_node *cdn, ++ const char *name) ++{ ++ int ret; ++ dev_t devt; ++ ++ if (!name) { ++ dev_dbg(parent, "%s: cdev name has to be provided\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ /* allocate minor */ ++ ret = idr_alloc(&tipc_devices, cdn, 0, MAX_DEVICES, GFP_KERNEL); ++ if (ret < 0) { ++ dev_dbg(parent, "%s: failed (%d) to get id\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ cdn->minor = ret; ++ cdev_init(&cdn->cdev, &tipc_fops); ++ cdn->cdev.owner = THIS_MODULE; ++ ++ /* Add character device */ ++ devt = MKDEV(tipc_major, cdn->minor); ++ ret = cdev_add(&cdn->cdev, devt, 1); ++ if (ret) { ++ dev_dbg(parent, "%s: cdev_add failed (%d)\n", ++ __func__, ret); ++ goto err_add_cdev; ++ } ++ ++ /* Create a device node */ ++ cdn->dev = device_create(tipc_class, parent, ++ devt, NULL, "trusty-ipc-%s", name); ++ if (IS_ERR(cdn->dev)) { ++ ret = PTR_ERR(cdn->dev); ++ dev_dbg(parent, "%s: device_create failed: %d\n", ++ __func__, ret); ++ goto err_device_create; ++ } ++ ++ return 0; ++ ++err_device_create: ++ cdn->dev = NULL; ++ cdev_del(&cdn->cdev); ++err_add_cdev: ++ idr_remove(&tipc_devices, cdn->minor); ++ return ret; ++} ++ ++static void create_cdev_node(struct tipc_virtio_dev *vds, ++ struct tipc_cdev_node *cdn) ++{ ++ int err; ++ ++ mutex_lock(&tipc_devices_lock); ++ ++ if (!default_vdev) { ++ kref_get(&vds->refcount); ++ default_vdev = vds->vdev; ++ } ++ ++ if (vds->cdev_name[0] && !cdn->dev) { ++ kref_get(&vds->refcount); ++ err = _create_cdev_node(&vds->vdev->dev, cdn, vds->cdev_name); ++ if (err) { ++ dev_err(&vds->vdev->dev, ++ "failed (%d) to create cdev node\n", err); ++ kref_put(&vds->refcount, _free_vds); ++ } ++ } ++ mutex_unlock(&tipc_devices_lock); ++} ++ ++static void destroy_cdev_node(struct tipc_virtio_dev *vds, ++ struct tipc_cdev_node *cdn) ++{ ++ mutex_lock(&tipc_devices_lock); ++ if (cdn->dev) { ++ device_destroy(tipc_class, MKDEV(tipc_major, cdn->minor)); ++ cdev_del(&cdn->cdev); ++ idr_remove(&tipc_devices, cdn->minor); ++ cdn->dev = NULL; ++ kref_put(&vds->refcount, _free_vds); ++ } ++ ++ if (default_vdev == vds->vdev) { ++ default_vdev = NULL; ++ kref_put(&vds->refcount, _free_vds); ++ } ++ ++ mutex_unlock(&tipc_devices_lock); ++} ++ ++static void _go_online(struct tipc_virtio_dev *vds) ++{ ++ mutex_lock(&vds->lock); ++ if (vds->state == VDS_OFFLINE) ++ vds->state = VDS_ONLINE; ++ mutex_unlock(&vds->lock); ++ ++ create_cdev_node(vds, &vds->cdev_node); ++ ++ dev_info(&vds->vdev->dev, "is online\n"); ++} ++ ++static void _go_offline(struct tipc_virtio_dev *vds) ++{ ++ struct tipc_chan *chan; ++ ++ /* change state to OFFLINE */ ++ mutex_lock(&vds->lock); ++ if (vds->state != VDS_ONLINE) { ++ mutex_unlock(&vds->lock); ++ return; ++ } ++ vds->state = VDS_OFFLINE; ++ mutex_unlock(&vds->lock); ++ ++ /* wakeup all waiters */ ++ wake_up_interruptible_all(&vds->sendq); ++ ++ /* shutdown all channels */ ++ while ((chan = vds_lookup_channel(vds, TIPC_ANY_ADDR))) { ++ mutex_lock(&chan->lock); ++ chan->state = TIPC_STALE; ++ chan->remote = 0; ++ chan_trigger_event(chan, TIPC_CHANNEL_SHUTDOWN); ++ mutex_unlock(&chan->lock); ++ kref_put(&chan->refcount, _free_chan); ++ } ++ ++ /* shutdown device node */ ++ destroy_cdev_node(vds, &vds->cdev_node); ++ ++ dev_info(&vds->vdev->dev, "is offline\n"); ++} ++ ++static void _handle_conn_rsp(struct tipc_virtio_dev *vds, ++ struct tipc_conn_rsp_body *rsp, size_t len) ++{ ++ struct tipc_chan *chan; ++ ++ if (sizeof(*rsp) != len) { ++ dev_err(&vds->vdev->dev, "%s: Invalid response length %zd\n", ++ __func__, len); ++ return; ++ } ++ ++ dev_dbg(&vds->vdev->dev, ++ "%s: connection response: for addr 0x%x: status %d remote addr 0x%x\n", ++ __func__, rsp->target, rsp->status, rsp->remote); ++ ++ /* Lookup channel */ ++ chan = vds_lookup_channel(vds, rsp->target); ++ if (chan) { ++ mutex_lock(&chan->lock); ++ if (chan->state == TIPC_CONNECTING) { ++ if (!rsp->status) { ++ chan->state = TIPC_CONNECTED; ++ chan->remote = rsp->remote; ++ chan->max_msg_cnt = rsp->max_msg_cnt; ++ chan->max_msg_size = rsp->max_msg_size; ++ chan_trigger_event(chan, ++ TIPC_CHANNEL_CONNECTED); ++ } else { ++ chan->state = TIPC_DISCONNECTED; ++ chan->remote = 0; ++ chan_trigger_event(chan, ++ TIPC_CHANNEL_DISCONNECTED); ++ } ++ } ++ mutex_unlock(&chan->lock); ++ kref_put(&chan->refcount, _free_chan); ++ } ++} ++ ++static void _handle_disc_req(struct tipc_virtio_dev *vds, ++ struct tipc_disc_req_body *req, size_t len) ++{ ++ struct tipc_chan *chan; ++ ++ if (sizeof(*req) != len) { ++ dev_err(&vds->vdev->dev, "%s: Invalid request length %zd\n", ++ __func__, len); ++ return; ++ } ++ ++ dev_dbg(&vds->vdev->dev, "%s: disconnect request: for addr 0x%x\n", ++ __func__, req->target); ++ ++ chan = vds_lookup_channel(vds, req->target); ++ if (chan) { ++ mutex_lock(&chan->lock); ++ if (chan->state == TIPC_CONNECTED || ++ chan->state == TIPC_CONNECTING) { ++ chan->state = TIPC_DISCONNECTED; ++ chan->remote = 0; ++ chan_trigger_event(chan, TIPC_CHANNEL_DISCONNECTED); ++ } ++ mutex_unlock(&chan->lock); ++ kref_put(&chan->refcount, _free_chan); ++ } ++} ++ ++static void _handle_release(struct tipc_virtio_dev *vds, ++ struct tipc_release_body *req, size_t len) ++{ ++ struct tipc_shared_handle *handle = NULL; ++ struct device *dev = &vds->vdev->dev; ++ int ret = 0; ++ ++ if (len < sizeof(*req)) { ++ dev_err(dev, "Received undersized release control message\n"); ++ return; ++ } ++ ++ handle = tipc_shared_handle_take(vds, req->id); ++ if (!handle) { ++ dev_err(dev, ++ "Received release control message for untracked handle: 0x%llx\n", ++ req->id); ++ return; ++ } ++ ++ ret = tipc_shared_handle_drop(handle); ++ ++ if (ret) { ++ dev_err(dev, ++ "Failed to release handle 0x%llx upon request: (%d)\n", ++ req->id, ret); ++ /* ++ * Put the handle back in case we got a spurious release now and ++ * get a real one later. This path should not happen, we're ++ * just trying to be robust. ++ */ ++ tipc_shared_handle_register(handle); ++ } ++} ++ ++static void _handle_ctrl_msg(struct tipc_virtio_dev *vds, ++ void *data, int len, u32 src) ++{ ++ struct tipc_ctrl_msg *msg = data; ++ ++ if ((len < sizeof(*msg)) || (sizeof(*msg) + msg->body_len != len)) { ++ dev_err(&vds->vdev->dev, ++ "%s: Invalid message length ( %d vs. %d)\n", ++ __func__, (int)(sizeof(*msg) + msg->body_len), len); ++ return; ++ } ++ ++ dev_dbg(&vds->vdev->dev, ++ "%s: Incoming ctrl message: src 0x%x type %d len %d\n", ++ __func__, src, msg->type, msg->body_len); ++ ++ switch (msg->type) { ++ case TIPC_CTRL_MSGTYPE_GO_ONLINE: ++ _go_online(vds); ++ break; ++ ++ case TIPC_CTRL_MSGTYPE_GO_OFFLINE: ++ _go_offline(vds); ++ break; ++ ++ case TIPC_CTRL_MSGTYPE_CONN_RSP: ++ _handle_conn_rsp(vds, (struct tipc_conn_rsp_body *)msg->body, ++ msg->body_len); ++ break; ++ ++ case TIPC_CTRL_MSGTYPE_DISC_REQ: ++ _handle_disc_req(vds, (struct tipc_disc_req_body *)msg->body, ++ msg->body_len); ++ break; ++ ++ case TIPC_CTRL_MSGTYPE_RELEASE: ++ _handle_release(vds, (struct tipc_release_body *)msg->body, ++ msg->body_len); ++ break; ++ ++ default: ++ dev_warn(&vds->vdev->dev, ++ "%s: Unexpected message type: %d\n", ++ __func__, msg->type); ++ } ++} ++ ++static void handle_dropped_chan_msg(struct tipc_virtio_dev *vds, ++ struct tipc_msg_buf *mb, ++ struct tipc_msg_hdr *msg) ++{ ++ int shm_idx; ++ struct tipc_shm *shm; ++ struct tipc_shared_handle *shared_handle; ++ struct device *dev = &vds->vdev->dev; ++ size_t len; ++ ++ if (msg->len < msg->shm_cnt * sizeof(*shm)) { ++ dev_err(dev, "shm_cnt does not fit in dropped message"); ++ /* The message is corrupt, so we can't recover resources */ ++ return; ++ } ++ ++ len = msg->len - msg->shm_cnt * sizeof(*shm); ++ /* skip normal data */ ++ (void)mb_get_data(mb, len); ++ ++ for (shm_idx = 0; shm_idx < msg->shm_cnt; shm_idx++) { ++ shm = mb_get_data(mb, sizeof(*shm)); ++ shared_handle = tipc_shared_handle_take(vds, shm->obj_id); ++ if (shared_handle) { ++ if (tipc_shared_handle_drop(shared_handle)) ++ dev_err(dev, ++ "Failed to drop handle found in dropped buffer"); ++ } else { ++ dev_err(dev, ++ "Found handle in dropped buffer which was not registered to tipc device..."); ++ } ++ } ++} ++ ++static void handle_dropped_mb(struct tipc_virtio_dev *vds, ++ struct tipc_msg_buf *mb) ++{ ++ struct tipc_msg_hdr *msg; ++ ++ mb_reset_read(mb); ++ msg = mb_get_data(mb, sizeof(*msg)); ++ if (msg->dst != TIPC_CTRL_ADDR) { ++ handle_dropped_chan_msg(vds, mb, msg); ++ } ++} ++ ++static int _handle_rxbuf(struct tipc_virtio_dev *vds, ++ struct tipc_msg_buf *rxbuf, size_t rxlen) ++{ ++ int err; ++ struct scatterlist sg; ++ struct tipc_msg_hdr *msg; ++ struct device *dev = &vds->vdev->dev; ++ ++ /* message sanity check */ ++ if (rxlen > rxbuf->buf_sz) { ++ dev_warn(dev, "inbound msg is too big: %zd\n", rxlen); ++ goto drop_it; ++ } ++ ++ if (rxlen < sizeof(*msg)) { ++ dev_warn(dev, "inbound msg is too short: %zd\n", rxlen); ++ goto drop_it; ++ } ++ ++ /* reset buffer and put data */ ++ mb_reset(rxbuf); ++ mb_put_data(rxbuf, rxlen); ++ ++ /* get message header */ ++ msg = mb_get_data(rxbuf, sizeof(*msg)); ++ if (mb_avail_data(rxbuf) != msg->len) { ++ dev_warn(dev, "inbound msg length mismatch: (%zu vs. %d)\n", ++ mb_avail_data(rxbuf), msg->len); ++ goto drop_it; ++ } ++ ++ dev_dbg(dev, "From: %d, To: %d, Len: %d, Flags: 0x%x, Reserved: %d, shm_cnt: %d\n", ++ msg->src, msg->dst, msg->len, msg->flags, msg->reserved, ++ msg->shm_cnt); ++ ++ /* message directed to control endpoint is a special case */ ++ if (msg->dst == TIPC_CTRL_ADDR) { ++ _handle_ctrl_msg(vds, msg->data, msg->len, msg->src); ++ } else { ++ struct tipc_chan *chan = NULL; ++ /* Lookup channel */ ++ chan = vds_lookup_channel(vds, msg->dst); ++ if (chan) { ++ /* handle it */ ++ rxbuf = chan->ops->handle_msg(chan->ops_arg, rxbuf); ++ kref_put(&chan->refcount, _free_chan); ++ if (WARN_ON(!rxbuf)) ++ return -EINVAL; ++ } ++ } ++ ++drop_it: ++ /* add the buffer back to the virtqueue */ ++ sg_init_one(&sg, rxbuf, rxbuf->buf_sz); ++ err = virtqueue_add_inbuf(vds->rxvq, &sg, 1, rxbuf, GFP_KERNEL); ++ if (err < 0) { ++ dev_err(dev, "failed to add a virtqueue buffer: %d\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void _rxvq_cb(struct virtqueue *rxvq) ++{ ++ unsigned int len; ++ struct tipc_msg_buf *mb; ++ unsigned int msg_cnt = 0; ++ struct tipc_virtio_dev *vds = rxvq->vdev->priv; ++ ++ while ((mb = virtqueue_get_buf(rxvq, &len)) != NULL) { ++ if (_handle_rxbuf(vds, mb, len)) ++ break; ++ msg_cnt++; ++ } ++ ++ /* tell the other size that we added rx buffers */ ++ if (msg_cnt) ++ virtqueue_kick(rxvq); ++} ++ ++static void _txvq_cb(struct virtqueue *txvq) ++{ ++ unsigned int len; ++ struct tipc_msg_buf *mb; ++ bool need_wakeup = false; ++ struct tipc_virtio_dev *vds = txvq->vdev->priv; ++ ++ /* detach all buffers */ ++ mutex_lock(&vds->lock); ++ while ((mb = virtqueue_get_buf(txvq, &len)) != NULL) { ++ if ((int)len < 0) ++ handle_dropped_mb(vds, mb); ++ need_wakeup |= _put_txbuf_locked(vds, mb); ++ } ++ mutex_unlock(&vds->lock); ++ ++ if (need_wakeup) { ++ /* wake up potential senders waiting for a tx buffer */ ++ wake_up_interruptible_all(&vds->sendq); ++ } ++} ++ ++static int tipc_virtio_probe(struct virtio_device *vdev) ++{ ++ int err, i; ++ struct tipc_virtio_dev *vds; ++ struct tipc_dev_config config; ++ struct virtqueue *vqs[2]; ++ vq_callback_t *vq_cbs[] = {_rxvq_cb, _txvq_cb}; ++ static const char * const vq_names[] = { "rx", "tx" }; ++ ++ vds = kzalloc(sizeof(*vds), GFP_KERNEL); ++ if (!vds) ++ return -ENOMEM; ++ ++ vds->vdev = vdev; ++ ++ mutex_init(&vds->lock); ++ mutex_init(&vds->shared_handles_lock); ++ kref_init(&vds->refcount); ++ init_waitqueue_head(&vds->sendq); ++ INIT_LIST_HEAD(&vds->free_buf_list); ++ idr_init(&vds->addr_idr); ++ vds->shared_handles = RB_ROOT; ++ dma_coerce_mask_and_coherent(&vds->vdev->dev, ++ *vds->vdev->dev.parent->parent->dma_mask); ++ ++ /* set default max message size and alignment */ ++ memset(&config, 0, sizeof(config)); ++ config.msg_buf_max_size = DEFAULT_MSG_BUF_SIZE; ++ config.msg_buf_alignment = DEFAULT_MSG_BUF_ALIGN; ++ ++ /* get configuration if present */ ++ vdev->config->get(vdev, 0, &config, sizeof(config)); ++ ++ /* copy dev name */ ++ strncpy(vds->cdev_name, config.dev_name, sizeof(vds->cdev_name)); ++ vds->cdev_name[sizeof(vds->cdev_name)-1] = '\0'; ++ ++ /* find tx virtqueues (rx and tx and in this order) */ ++ err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, vq_names, NULL, ++ NULL); ++ if (err) ++ goto err_find_vqs; ++ ++ vds->rxvq = vqs[0]; ++ vds->txvq = vqs[1]; ++ ++ /* save max buffer size and count */ ++ vds->msg_buf_max_sz = config.msg_buf_max_size; ++ vds->msg_buf_max_cnt = virtqueue_get_vring_size(vds->txvq); ++ ++ /* set up the receive buffers */ ++ for (i = 0; i < virtqueue_get_vring_size(vds->rxvq); i++) { ++ struct scatterlist sg; ++ struct tipc_msg_buf *rxbuf; ++ ++ rxbuf = vds_alloc_msg_buf(vds, true); ++ if (!rxbuf) { ++ dev_err(&vdev->dev, "failed to allocate rx buffer\n"); ++ err = -ENOMEM; ++ goto err_free_rx_buffers; ++ } ++ ++ sg_init_one(&sg, rxbuf, rxbuf->buf_sz); ++ err = virtqueue_add_inbuf(vds->rxvq, &sg, 1, rxbuf, GFP_KERNEL); ++ WARN_ON(err); /* sanity check; this can't really happen */ ++ } ++ ++ vdev->priv = vds; ++ vds->state = VDS_OFFLINE; ++ ++ dev_dbg(&vdev->dev, "%s: done\n", __func__); ++ return 0; ++ ++err_free_rx_buffers: ++ _cleanup_vq(vds, vds->rxvq); ++err_find_vqs: ++ kref_put(&vds->refcount, _free_vds); ++ return err; ++} ++ ++static void tipc_virtio_remove(struct virtio_device *vdev) ++{ ++ struct tipc_virtio_dev *vds = vdev->priv; ++ ++ _go_offline(vds); ++ ++ mutex_lock(&vds->lock); ++ vds->state = VDS_DEAD; ++ vds->vdev = NULL; ++ mutex_unlock(&vds->lock); ++ ++ vdev->config->reset(vdev); ++ ++ idr_destroy(&vds->addr_idr); ++ ++ _cleanup_vq(vds, vds->rxvq); ++ _cleanup_vq(vds, vds->txvq); ++ vds_free_msg_buf_list(vds, &vds->free_buf_list); ++ ++ vdev->config->del_vqs(vds->vdev); ++ ++ kref_put(&vds->refcount, _free_vds); ++} ++ ++static const struct virtio_device_id tipc_virtio_id_table[] = { ++ { VIRTIO_ID_TRUSTY_IPC, VIRTIO_DEV_ANY_ID }, ++ { 0 }, ++}; ++ ++static const unsigned int features[] = { ++ 0, ++}; ++ ++static struct virtio_driver virtio_tipc_driver = { ++ .feature_table = features, ++ .feature_table_size = ARRAY_SIZE(features), ++ .driver.name = KBUILD_MODNAME, ++ .driver.owner = THIS_MODULE, ++ .id_table = tipc_virtio_id_table, ++ .probe = tipc_virtio_probe, ++ .remove = tipc_virtio_remove, ++}; ++ ++static int __init tipc_init(void) ++{ ++ int ret; ++ dev_t dev; ++ ++ ret = alloc_chrdev_region(&dev, 0, MAX_DEVICES, KBUILD_MODNAME); ++ if (ret) { ++ pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ tipc_major = MAJOR(dev); ++ tipc_class = class_create(THIS_MODULE, KBUILD_MODNAME); ++ if (IS_ERR(tipc_class)) { ++ ret = PTR_ERR(tipc_class); ++ pr_err("%s: class_create failed: %d\n", __func__, ret); ++ goto err_class_create; ++ } ++ ++ ret = register_virtio_driver(&virtio_tipc_driver); ++ if (ret) { ++ pr_err("failed to register virtio driver: %d\n", ret); ++ goto err_register_virtio_drv; ++ } ++ ++ return 0; ++ ++err_register_virtio_drv: ++ class_destroy(tipc_class); ++ ++err_class_create: ++ unregister_chrdev_region(dev, MAX_DEVICES); ++ return ret; ++} ++ ++static void __exit tipc_exit(void) ++{ ++ unregister_virtio_driver(&virtio_tipc_driver); ++ class_destroy(tipc_class); ++ unregister_chrdev_region(MKDEV(tipc_major, 0), MAX_DEVICES); ++} ++ ++/* We need to init this early */ ++subsys_initcall(tipc_init); ++module_exit(tipc_exit); ++ ++MODULE_DEVICE_TABLE(tipc, tipc_virtio_id_table); ++MODULE_DESCRIPTION("Trusty IPC driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/trusty/trusty-irq.c b/drivers/trusty/trusty-irq.c +new file mode 100644 +index 000000000000..5c6076108d0e +--- /dev/null ++++ b/drivers/trusty/trusty-irq.c +@@ -0,0 +1,645 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2013 Google, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct trusty_irq { ++ struct trusty_irq_state *is; ++ struct hlist_node node; ++ unsigned int irq; ++ bool percpu; ++ bool enable; ++ bool doorbell; ++ struct trusty_irq __percpu *percpu_ptr; ++}; ++ ++struct trusty_irq_irqset { ++ struct hlist_head pending; ++ struct hlist_head inactive; ++}; ++ ++struct trusty_irq_state { ++ struct device *dev; ++ struct device *trusty_dev; ++ struct trusty_irq_irqset normal_irqs; ++ spinlock_t normal_irqs_lock; ++ struct trusty_irq_irqset __percpu *percpu_irqs; ++ struct notifier_block trusty_call_notifier; ++ struct hlist_node cpuhp_node; ++}; ++ ++static int trusty_irq_cpuhp_slot = -1; ++ ++static void trusty_irq_enable_pending_irqs(struct trusty_irq_state *is, ++ struct trusty_irq_irqset *irqset, ++ bool percpu) ++{ ++ struct hlist_node *n; ++ struct trusty_irq *trusty_irq; ++ ++ hlist_for_each_entry_safe(trusty_irq, n, &irqset->pending, node) { ++ dev_dbg(is->dev, ++ "%s: enable pending irq %d, percpu %d, cpu %d\n", ++ __func__, trusty_irq->irq, percpu, smp_processor_id()); ++ if (percpu) ++ enable_percpu_irq(trusty_irq->irq, 0); ++ else ++ enable_irq(trusty_irq->irq); ++ hlist_del(&trusty_irq->node); ++ hlist_add_head(&trusty_irq->node, &irqset->inactive); ++ } ++} ++ ++static void trusty_irq_enable_irqset(struct trusty_irq_state *is, ++ struct trusty_irq_irqset *irqset) ++{ ++ struct trusty_irq *trusty_irq; ++ ++ hlist_for_each_entry(trusty_irq, &irqset->inactive, node) { ++ if (trusty_irq->enable) { ++ dev_warn(is->dev, ++ "%s: percpu irq %d already enabled, cpu %d\n", ++ __func__, trusty_irq->irq, smp_processor_id()); ++ continue; ++ } ++ dev_dbg(is->dev, "%s: enable percpu irq %d, cpu %d\n", ++ __func__, trusty_irq->irq, smp_processor_id()); ++ enable_percpu_irq(trusty_irq->irq, 0); ++ trusty_irq->enable = true; ++ } ++} ++ ++static void trusty_irq_disable_irqset(struct trusty_irq_state *is, ++ struct trusty_irq_irqset *irqset) ++{ ++ struct hlist_node *n; ++ struct trusty_irq *trusty_irq; ++ ++ hlist_for_each_entry(trusty_irq, &irqset->inactive, node) { ++ if (!trusty_irq->enable) { ++ dev_warn(is->dev, ++ "irq %d already disabled, percpu %d, cpu %d\n", ++ trusty_irq->irq, trusty_irq->percpu, ++ smp_processor_id()); ++ continue; ++ } ++ dev_dbg(is->dev, "%s: disable irq %d, percpu %d, cpu %d\n", ++ __func__, trusty_irq->irq, trusty_irq->percpu, ++ smp_processor_id()); ++ trusty_irq->enable = false; ++ if (trusty_irq->percpu) ++ disable_percpu_irq(trusty_irq->irq); ++ else ++ disable_irq_nosync(trusty_irq->irq); ++ } ++ hlist_for_each_entry_safe(trusty_irq, n, &irqset->pending, node) { ++ if (!trusty_irq->enable) { ++ dev_warn(is->dev, ++ "pending irq %d already disabled, percpu %d, cpu %d\n", ++ trusty_irq->irq, trusty_irq->percpu, ++ smp_processor_id()); ++ } ++ dev_dbg(is->dev, ++ "%s: disable pending irq %d, percpu %d, cpu %d\n", ++ __func__, trusty_irq->irq, trusty_irq->percpu, ++ smp_processor_id()); ++ trusty_irq->enable = false; ++ hlist_del(&trusty_irq->node); ++ hlist_add_head(&trusty_irq->node, &irqset->inactive); ++ } ++} ++ ++static int trusty_irq_call_notify(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct trusty_irq_state *is; ++ ++ if (WARN_ON(!irqs_disabled())) ++ return NOTIFY_DONE; ++ ++ if (action != TRUSTY_CALL_PREPARE) ++ return NOTIFY_DONE; ++ ++ is = container_of(nb, struct trusty_irq_state, trusty_call_notifier); ++ ++ spin_lock(&is->normal_irqs_lock); ++ trusty_irq_enable_pending_irqs(is, &is->normal_irqs, false); ++ spin_unlock(&is->normal_irqs_lock); ++ trusty_irq_enable_pending_irqs(is, this_cpu_ptr(is->percpu_irqs), true); ++ ++ return NOTIFY_OK; ++} ++ ++static irqreturn_t trusty_irq_handler(int irq, void *data) ++{ ++ struct trusty_irq *trusty_irq = data; ++ struct trusty_irq_state *is = trusty_irq->is; ++ struct trusty_irq_irqset *irqset; ++ ++ dev_dbg(is->dev, "%s: irq %d, percpu %d, cpu %d, enable %d\n", ++ __func__, irq, trusty_irq->irq, smp_processor_id(), ++ trusty_irq->enable); ++ ++ if (!trusty_irq->doorbell) { ++ if (trusty_irq->percpu) { ++ disable_percpu_irq(irq); ++ irqset = this_cpu_ptr(is->percpu_irqs); ++ } else { ++ disable_irq_nosync(irq); ++ irqset = &is->normal_irqs; ++ } ++ ++ spin_lock(&is->normal_irqs_lock); ++ if (trusty_irq->enable) { ++ hlist_del(&trusty_irq->node); ++ hlist_add_head(&trusty_irq->node, &irqset->pending); ++ } ++ spin_unlock(&is->normal_irqs_lock); ++ } ++ ++ trusty_enqueue_nop(is->trusty_dev, NULL); ++ ++ dev_dbg(is->dev, "%s: irq %d done\n", __func__, irq); ++ ++ return IRQ_HANDLED; ++} ++ ++static int trusty_irq_cpu_up(unsigned int cpu, struct hlist_node *node) ++{ ++ unsigned long irq_flags; ++ struct trusty_irq_state *is; ++ ++ is = container_of(node, struct trusty_irq_state, cpuhp_node); ++ ++ dev_dbg(is->dev, "%s: cpu %d\n", __func__, cpu); ++ ++ local_irq_save(irq_flags); ++ trusty_irq_enable_irqset(is, this_cpu_ptr(is->percpu_irqs)); ++ local_irq_restore(irq_flags); ++ ++ /* ++ * Temporary workaround blindly enqueuing work to force trusty scheduler ++ * to run after a cpu suspend. ++ * Root causing the workqueue being inappropriately empty ++ * (e.g. loss of an IPI) may make this workaround unnecessary ++ * in the future. ++ */ ++ trusty_enqueue_nop(is->trusty_dev, NULL); ++ ++ return 0; ++} ++ ++static int trusty_irq_cpu_down(unsigned int cpu, struct hlist_node *node) ++{ ++ unsigned long irq_flags; ++ struct trusty_irq_state *is; ++ ++ is = container_of(node, struct trusty_irq_state, cpuhp_node); ++ ++ dev_dbg(is->dev, "%s: cpu %d\n", __func__, cpu); ++ ++ local_irq_save(irq_flags); ++ trusty_irq_disable_irqset(is, this_cpu_ptr(is->percpu_irqs)); ++ local_irq_restore(irq_flags); ++ ++ return 0; ++} ++ ++static int trusty_irq_map_ipi(struct trusty_irq_state *is, int irq) ++{ ++ int ret; ++ u32 ipi_range[3]; ++ struct device_node *gic; ++ struct of_phandle_args oirq = {}; ++ u32 beg, end, ipi_base; ++ ++ ret = of_property_read_u32_array(is->dev->of_node, "ipi-range", ++ ipi_range, ARRAY_SIZE(ipi_range)); ++ if (ret != 0) ++ return -ENODATA; ++ beg = ipi_range[0]; ++ end = ipi_range[1]; ++ ipi_base = ipi_range[2]; ++ ++ if (irq < beg || irq > end) ++ return -ENODATA; ++ ++ gic = of_irq_find_parent(is->dev->of_node); ++ if (!gic) ++ return -ENXIO; ++ ++ oirq.np = gic; ++ oirq.args_count = 1; ++ oirq.args[0] = ipi_base + (irq - beg); ++ ++ ret = irq_create_of_mapping(&oirq); ++ ++ of_node_put(gic); ++ return (!ret) ? -EINVAL : ret; ++} ++ ++static int trusty_irq_create_irq_mapping(struct trusty_irq_state *is, int irq) ++{ ++ int ret; ++ int index; ++ u32 irq_pos; ++ u32 templ_idx; ++ u32 range_base; ++ u32 range_end; ++ struct of_phandle_args oirq; ++ ++ /* check if this is an IPI (inter-processor interrupt) */ ++ ret = trusty_irq_map_ipi(is, irq); ++ if (ret != -ENODATA) ++ return ret; ++ ++ /* check if "interrupt-ranges" property is present */ ++ if (!of_find_property(is->dev->of_node, "interrupt-ranges", NULL)) { ++ /* fallback to old behavior to be backward compatible with ++ * systems that do not need IRQ domains. ++ */ ++ return irq; ++ } ++ ++ /* find irq range */ ++ for (index = 0;; index += 3) { ++ ret = of_property_read_u32_index(is->dev->of_node, ++ "interrupt-ranges", ++ index, &range_base); ++ if (ret) ++ return ret; ++ ++ ret = of_property_read_u32_index(is->dev->of_node, ++ "interrupt-ranges", ++ index + 1, &range_end); ++ if (ret) ++ return ret; ++ ++ if (irq >= range_base && irq <= range_end) ++ break; ++ } ++ ++ /* read the rest of range entry: template index and irq_pos */ ++ ret = of_property_read_u32_index(is->dev->of_node, ++ "interrupt-ranges", ++ index + 2, &templ_idx); ++ if (ret) ++ return ret; ++ ++ /* read irq template */ ++ ret = of_parse_phandle_with_args(is->dev->of_node, ++ "interrupt-templates", ++ "#interrupt-cells", ++ templ_idx, &oirq); ++ if (ret) ++ return ret; ++ ++ WARN_ON(!oirq.np); ++ WARN_ON(!oirq.args_count); ++ ++ /* ++ * An IRQ template is a non empty array of u32 values describing group ++ * of interrupts having common properties. The u32 entry with index ++ * zero contains the position of irq_id in interrupt specifier array ++ * followed by data representing interrupt specifier array with irq id ++ * field omitted, so to convert irq template to interrupt specifier ++ * array we have to move down one slot the first irq_pos entries and ++ * replace the resulting gap with real irq id. ++ */ ++ irq_pos = oirq.args[0]; ++ ++ if (irq_pos >= oirq.args_count) { ++ dev_err(is->dev, "irq pos is out of range: %d\n", irq_pos); ++ return -EINVAL; ++ } ++ ++ for (index = 1; index <= irq_pos; index++) ++ oirq.args[index - 1] = oirq.args[index]; ++ ++ oirq.args[irq_pos] = irq - range_base; ++ ++ ret = irq_create_of_mapping(&oirq); ++ ++ return (!ret) ? -EINVAL : ret; ++} ++ ++static int trusty_irq_init_normal_irq(struct trusty_irq_state *is, int tirq) ++{ ++ int ret; ++ int irq; ++ unsigned long irq_flags; ++ struct trusty_irq *trusty_irq; ++ ++ dev_dbg(is->dev, "%s: irq %d\n", __func__, tirq); ++ ++ irq = trusty_irq_create_irq_mapping(is, tirq); ++ if (irq < 0) { ++ dev_err(is->dev, ++ "trusty_irq_create_irq_mapping failed (%d)\n", irq); ++ return irq; ++ } ++ ++ trusty_irq = kzalloc(sizeof(*trusty_irq), GFP_KERNEL); ++ if (!trusty_irq) ++ return -ENOMEM; ++ ++ trusty_irq->is = is; ++ trusty_irq->irq = irq; ++ trusty_irq->enable = true; ++ ++ spin_lock_irqsave(&is->normal_irqs_lock, irq_flags); ++ hlist_add_head(&trusty_irq->node, &is->normal_irqs.inactive); ++ spin_unlock_irqrestore(&is->normal_irqs_lock, irq_flags); ++ ++ ret = request_irq(irq, trusty_irq_handler, IRQF_NO_THREAD, ++ "trusty", trusty_irq); ++ if (ret) { ++ dev_err(is->dev, "request_irq failed %d\n", ret); ++ goto err_request_irq; ++ } ++ return 0; ++ ++err_request_irq: ++ spin_lock_irqsave(&is->normal_irqs_lock, irq_flags); ++ hlist_del(&trusty_irq->node); ++ spin_unlock_irqrestore(&is->normal_irqs_lock, irq_flags); ++ kfree(trusty_irq); ++ return ret; ++} ++ ++static int trusty_irq_init_per_cpu_irq(struct trusty_irq_state *is, int tirq, ++ unsigned int type) ++{ ++ int ret; ++ int irq; ++ unsigned int cpu; ++ struct trusty_irq __percpu *trusty_irq_handler_data; ++ ++ dev_dbg(is->dev, "%s: irq %d\n", __func__, tirq); ++ ++ irq = trusty_irq_create_irq_mapping(is, tirq); ++ if (irq <= 0) { ++ dev_err(is->dev, ++ "trusty_irq_create_irq_mapping failed (%d)\n", irq); ++ return irq; ++ } ++ ++ trusty_irq_handler_data = alloc_percpu(struct trusty_irq); ++ if (!trusty_irq_handler_data) ++ return -ENOMEM; ++ ++ for_each_possible_cpu(cpu) { ++ struct trusty_irq *trusty_irq; ++ struct trusty_irq_irqset *irqset; ++ ++ trusty_irq = per_cpu_ptr(trusty_irq_handler_data, cpu); ++ irqset = per_cpu_ptr(is->percpu_irqs, cpu); ++ ++ trusty_irq->is = is; ++ hlist_add_head(&trusty_irq->node, &irqset->inactive); ++ trusty_irq->irq = irq; ++ trusty_irq->percpu = true; ++ trusty_irq->doorbell = type == TRUSTY_IRQ_TYPE_DOORBELL; ++ trusty_irq->percpu_ptr = trusty_irq_handler_data; ++ } ++ ++ ret = request_percpu_irq(irq, trusty_irq_handler, "trusty", ++ trusty_irq_handler_data); ++ if (ret) { ++ dev_err(is->dev, "request_percpu_irq failed %d\n", ret); ++ goto err_request_percpu_irq; ++ } ++ ++ return 0; ++ ++err_request_percpu_irq: ++ for_each_possible_cpu(cpu) { ++ struct trusty_irq *trusty_irq; ++ ++ trusty_irq = per_cpu_ptr(trusty_irq_handler_data, cpu); ++ hlist_del(&trusty_irq->node); ++ } ++ ++ free_percpu(trusty_irq_handler_data); ++ return ret; ++} ++ ++static int trusty_smc_get_next_irq(struct trusty_irq_state *is, ++ unsigned long min_irq, unsigned int type) ++{ ++ return trusty_fast_call32(is->trusty_dev, SMC_FC_GET_NEXT_IRQ, ++ min_irq, type, 0); ++} ++ ++static int trusty_irq_init_one(struct trusty_irq_state *is, ++ int irq, unsigned int type) ++{ ++ int ret; ++ ++ irq = trusty_smc_get_next_irq(is, irq, type); ++ if (irq < 0) ++ return irq; ++ ++ if (type != TRUSTY_IRQ_TYPE_NORMAL) ++ ret = trusty_irq_init_per_cpu_irq(is, irq, type); ++ else ++ ret = trusty_irq_init_normal_irq(is, irq); ++ ++ if (ret) { ++ dev_warn(is->dev, ++ "failed to initialize irq %d, irq will be ignored\n", ++ irq); ++ } ++ ++ return irq + 1; ++} ++ ++static void trusty_irq_free_irqs(struct trusty_irq_state *is) ++{ ++ struct trusty_irq *irq; ++ struct hlist_node *n; ++ unsigned int cpu; ++ ++ hlist_for_each_entry_safe(irq, n, &is->normal_irqs.inactive, node) { ++ dev_dbg(is->dev, "%s: irq %d\n", __func__, irq->irq); ++ free_irq(irq->irq, irq); ++ hlist_del(&irq->node); ++ kfree(irq); ++ } ++ hlist_for_each_entry_safe(irq, n, ++ &this_cpu_ptr(is->percpu_irqs)->inactive, ++ node) { ++ struct trusty_irq __percpu *trusty_irq_handler_data; ++ ++ dev_dbg(is->dev, "%s: percpu irq %d\n", __func__, irq->irq); ++ trusty_irq_handler_data = irq->percpu_ptr; ++ free_percpu_irq(irq->irq, trusty_irq_handler_data); ++ for_each_possible_cpu(cpu) { ++ struct trusty_irq *irq_tmp; ++ ++ irq_tmp = per_cpu_ptr(trusty_irq_handler_data, cpu); ++ hlist_del(&irq_tmp->node); ++ } ++ free_percpu(trusty_irq_handler_data); ++ } ++} ++ ++static int trusty_irq_probe(struct platform_device *pdev) ++{ ++ int ret; ++ int irq; ++ unsigned long irq_flags; ++ struct trusty_irq_state *is; ++ ++ is = kzalloc(sizeof(*is), GFP_KERNEL); ++ if (!is) { ++ ret = -ENOMEM; ++ goto err_alloc_is; ++ } ++ ++ is->dev = &pdev->dev; ++ is->trusty_dev = is->dev->parent; ++ spin_lock_init(&is->normal_irqs_lock); ++ is->percpu_irqs = alloc_percpu(struct trusty_irq_irqset); ++ if (!is->percpu_irqs) { ++ ret = -ENOMEM; ++ goto err_alloc_pending_percpu_irqs; ++ } ++ ++ platform_set_drvdata(pdev, is); ++ ++ is->trusty_call_notifier.notifier_call = trusty_irq_call_notify; ++ ret = trusty_call_notifier_register(is->trusty_dev, ++ &is->trusty_call_notifier); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "failed to register trusty call notifier\n"); ++ goto err_trusty_call_notifier_register; ++ } ++ ++ for (irq = 0; irq >= 0;) ++ irq = trusty_irq_init_one(is, irq, TRUSTY_IRQ_TYPE_PER_CPU); ++ for (irq = 0; irq >= 0;) ++ irq = trusty_irq_init_one(is, irq, TRUSTY_IRQ_TYPE_NORMAL); ++ for (irq = 0; irq >= 0;) ++ irq = trusty_irq_init_one(is, irq, TRUSTY_IRQ_TYPE_DOORBELL); ++ ++ ret = cpuhp_state_add_instance(trusty_irq_cpuhp_slot, &is->cpuhp_node); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "cpuhp_state_add_instance failed %d\n", ++ ret); ++ goto err_add_cpuhp_instance; ++ } ++ ++ return 0; ++ ++err_add_cpuhp_instance: ++ spin_lock_irqsave(&is->normal_irqs_lock, irq_flags); ++ trusty_irq_disable_irqset(is, &is->normal_irqs); ++ spin_unlock_irqrestore(&is->normal_irqs_lock, irq_flags); ++ trusty_irq_free_irqs(is); ++ trusty_call_notifier_unregister(is->trusty_dev, ++ &is->trusty_call_notifier); ++err_trusty_call_notifier_register: ++ free_percpu(is->percpu_irqs); ++err_alloc_pending_percpu_irqs: ++ kfree(is); ++err_alloc_is: ++ return ret; ++} ++ ++static int trusty_irq_remove(struct platform_device *pdev) ++{ ++ int ret; ++ unsigned long irq_flags; ++ struct trusty_irq_state *is = platform_get_drvdata(pdev); ++ ++ ret = cpuhp_state_remove_instance(trusty_irq_cpuhp_slot, ++ &is->cpuhp_node); ++ if (WARN_ON(ret)) ++ return ret; ++ ++ spin_lock_irqsave(&is->normal_irqs_lock, irq_flags); ++ trusty_irq_disable_irqset(is, &is->normal_irqs); ++ spin_unlock_irqrestore(&is->normal_irqs_lock, irq_flags); ++ ++ trusty_irq_free_irqs(is); ++ ++ trusty_call_notifier_unregister(is->trusty_dev, ++ &is->trusty_call_notifier); ++ free_percpu(is->percpu_irqs); ++ kfree(is); ++ ++ return 0; ++} ++ ++static const struct of_device_id trusty_test_of_match[] = { ++ { .compatible = "android,trusty-irq-v1", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(trusty, trusty_test_of_match); ++ ++static struct platform_driver trusty_irq_driver = { ++ .probe = trusty_irq_probe, ++ .remove = trusty_irq_remove, ++ .driver = { ++ .name = "trusty-irq", ++ .of_match_table = trusty_test_of_match, ++ }, ++}; ++ ++static int __init trusty_irq_driver_init(void) ++{ ++ int ret; ++ ++ /* allocate dynamic cpuhp state slot */ ++ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, ++ "trusty-irq:cpu:online", ++ trusty_irq_cpu_up, ++ trusty_irq_cpu_down); ++ if (ret < 0) ++ return ret; ++ trusty_irq_cpuhp_slot = ret; ++ ++ /* Register platform driver */ ++ ret = platform_driver_register(&trusty_irq_driver); ++ if (ret < 0) ++ goto err_driver_register; ++ ++ return ret; ++ ++err_driver_register: ++ /* undo cpuhp slot allocation */ ++ cpuhp_remove_multi_state(trusty_irq_cpuhp_slot); ++ trusty_irq_cpuhp_slot = -1; ++ ++ return ret; ++} ++ ++static void __exit trusty_irq_driver_exit(void) ++{ ++ platform_driver_unregister(&trusty_irq_driver); ++ cpuhp_remove_multi_state(trusty_irq_cpuhp_slot); ++ trusty_irq_cpuhp_slot = -1; ++} ++ ++module_init(trusty_irq_driver_init); ++module_exit(trusty_irq_driver_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Trusty IRQ driver"); +diff --git a/drivers/trusty/trusty-log.c b/drivers/trusty/trusty-log.c +new file mode 100644 +index 000000000000..7b279fe63766 +--- /dev/null ++++ b/drivers/trusty/trusty-log.c +@@ -0,0 +1,830 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2015 Google, Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "trusty-log.h" ++ ++/* ++ * Rationale for the chosen default log buffer size: ++ * - the log buffer shall contain unthrottled Trusty crash dump. ++ * - the register list portion of a crash dump is about 1KB ++ * - the memory-around-registers portion of a crash dump can be up to 12 KB ++ * - an average size backtrace is about 1 KB ++ * - average length of non-crash trusty logs during boot is about 85 characters ++ * - a crash dump with 50 lines of context therefore requires up to 18 KB ++ * - buffer size needs to be power-of-two number of bytes ++ * - rounding up to power of two from 18 KB gives 32 KB ++ * The log size can be adjusted by setting the "trusty_log.log_size" parameter ++ * on the kernel command line. The specified value will be adjusted as needed. ++ */ ++ ++#define TRUSTY_LOG_DEFAULT_SIZE (32768) ++#define TRUSTY_LOG_MIN_SIZE (PAGE_SIZE / 2) ++#define TRUSTY_LOG_MAX_SIZE (1 * 1024 * 1024 * 1024) ++#define TRUSTY_LINE_BUFFER_SIZE (256) ++ ++static size_t log_size_param = TRUSTY_LOG_DEFAULT_SIZE; ++ ++static int trusty_log_size_set(const char *val, const struct kernel_param *kp) ++{ ++ unsigned long long requested = memparse(val, NULL); ++ ++ if (requested < TRUSTY_LOG_MIN_SIZE) ++ requested = TRUSTY_LOG_MIN_SIZE; ++ if (requested > TRUSTY_LOG_MAX_SIZE) ++ requested = TRUSTY_LOG_MAX_SIZE; ++ requested = rounddown_pow_of_two(requested); ++ log_size_param = requested; ++ return 0; ++} ++ ++static int trusty_log_size_get(char *buffer, const struct kernel_param *kp) ++{ ++ sprintf(buffer, "%zu", log_size_param); ++ return strlen(buffer); ++} ++ ++module_param_call(log_size, trusty_log_size_set, trusty_log_size_get, NULL, ++ 0644); ++/* ++ * If we log too much and a UART or other slow source is connected, we can stall ++ * out another thread which is doing printk. ++ * ++ * Trusty crash logs are currently ~16 lines, so 100 should include context and ++ * the crash most of the time. ++ */ ++static struct ratelimit_state trusty_log_rate_limit = ++ RATELIMIT_STATE_INIT("trusty_log", 1 * HZ, 100); ++ ++/** ++ * struct trusty_log_sfile - trusty log misc device state ++ * ++ * @misc: misc device created for the trusty log virtual file ++ * @device_name: misc device name following the convention ++ * "trusty-" ++ */ ++struct trusty_log_sfile { ++ struct miscdevice misc; ++ char device_name[64]; ++}; ++ ++/** ++ * struct trusty_log_sink_state - trusty log sink state ++ * ++ * @get: current read unwrapped index ++ * @trusty_panicked: trusty panic status at the start of the sink interation ++ * (only used for kernel log sink) ++ * @sfile: seq_file used for sinking to a virtual file (misc device); ++ * set to NULL for the kernel log sink. ++ * @ignore_overflow: ignore_overflow used to coalesce overflow messages and ++ * avoid reporting an overflow when sinking the oldest ++ * line to the virtual file (only used for virtual file sink) ++ * ++ * A sink state structure is used for both the kernel log sink ++ * and the virtual device sink. ++ * An instance of the sink state structure is dynamically created ++ * for each read iteration of the trusty log virtual file (misc device). ++ * ++ */ ++struct trusty_log_sink_state { ++ u32 get; ++ bool trusty_panicked; ++ ++ /* virtual file sink specific attributes */ ++ struct seq_file *sfile; ++ bool ignore_overflow; ++}; ++ ++struct trusty_log_state { ++ struct device *dev; ++ struct device *trusty_dev; ++ struct trusty_log_sfile log_sfile; ++ ++ struct log_rb *log; ++ struct trusty_log_sink_state klog_sink; ++ ++ u32 log_num_pages; ++ struct scatterlist *sg; ++ trusty_shared_mem_id_t log_pages_shared_mem_id; ++ ++ struct notifier_block call_notifier; ++ struct notifier_block panic_notifier; ++ char line_buffer[TRUSTY_LINE_BUFFER_SIZE]; ++ wait_queue_head_t poll_waiters; ++ /* this lock protects access to wake_put */ ++ spinlock_t wake_up_lock; ++ u32 last_wake_put; ++}; ++ ++static inline u32 u32_add_overflow(u32 a, u32 b) ++{ ++ u32 d; ++ ++ if (check_add_overflow(a, b, &d)) { ++ /* ++ * silence the overflow, ++ * what matters in the log buffer context ++ * is the casted addition ++ */ ++ } ++ return d; ++} ++ ++static inline u32 u32_sub_overflow(u32 a, u32 b) ++{ ++ u32 d; ++ ++ if (check_sub_overflow(a, b, &d)) { ++ /* ++ * silence the overflow, ++ * what matters in the log buffer context ++ * is the casted substraction ++ */ ++ } ++ return d; ++} ++ ++static int log_read_line(struct trusty_log_state *s, u32 put, u32 get) ++{ ++ struct log_rb *log = s->log; ++ int i; ++ char c = '\0'; ++ size_t max_to_read = ++ min_t(size_t, ++ u32_sub_overflow(put, get), ++ sizeof(s->line_buffer) - 1); ++ size_t mask = log->sz - 1; ++ ++ for (i = 0; i < max_to_read && c != '\n';) { ++ c = log->data[get & mask]; ++ s->line_buffer[i++] = c; ++ get = u32_add_overflow(get, 1); ++ } ++ s->line_buffer[i] = '\0'; ++ ++ return i; ++} ++ ++/** ++ * trusty_log_has_data() - returns true when more data is available to sink ++ * @s: Current log state. ++ * @sink: trusty_log_sink_state holding the get index on a given sink ++ * ++ * Return: true if data is available. ++ */ ++static bool trusty_log_has_data(struct trusty_log_state *s, ++ struct trusty_log_sink_state *sink) ++{ ++ struct log_rb *log = s->log; ++ ++ return (log->put != sink->get); ++} ++ ++/** ++ * trusty_log_start() - initialize the sink iteration either to kernel log ++ * or to secondary log_sfile ++ * @s: Current log state. ++ * @sink: trusty_log_sink_state holding the get index on a given sink ++ * @index: Unwrapped ring buffer index from where iteration shall start ++ * ++ * Return: 0 if successful, negative error code otherwise ++ */ ++static int trusty_log_start(struct trusty_log_state *s, ++ struct trusty_log_sink_state *sink, ++ u32 index) ++{ ++ struct log_rb *log; ++ ++ if (WARN_ON(!s)) ++ return -EINVAL; ++ ++ log = s->log; ++ if (WARN_ON(!is_power_of_2(log->sz))) ++ return -EINVAL; ++ ++ sink->get = index; ++ return 0; ++} ++ ++/** ++ * trusty_log_show() - sink log entry at current iteration ++ * @s: Current log state. ++ * @sink: trusty_log_sink_state holding the get index on a given sink ++ */ ++static void trusty_log_show(struct trusty_log_state *s, ++ struct trusty_log_sink_state *sink) ++{ ++ struct log_rb *log = s->log; ++ u32 alloc, put, get; ++ int read_chars; ++ ++ /* ++ * For this ring buffer, at any given point, alloc >= put >= get. ++ * The producer side of the buffer is not locked, so the put and alloc ++ * pointers must be read in a defined order (put before alloc) so ++ * that the above condition is maintained. A read barrier is needed ++ * to make sure the hardware and compiler keep the reads ordered. ++ */ ++ get = sink->get; ++ put = log->put; ++ ++ /* Make sure that the read of put occurs before the read of log data */ ++ rmb(); ++ ++ /* Read a line from the log */ ++ read_chars = log_read_line(s, put, get); ++ ++ /* Force the loads from log_read_line to complete. */ ++ rmb(); ++ alloc = log->alloc; ++ ++ /* ++ * Discard the line that was just read if the data could ++ * have been corrupted by the producer. ++ */ ++ if (u32_sub_overflow(alloc, get) > log->sz) { ++ /* ++ * this condition is acceptable in the case of the sfile sink ++ * when attempting to read the oldest entry (at alloc-log->sz) ++ * which may be overrun by a new one when ring buffer write ++ * index wraps around. ++ * So the overrun is not reported in case the oldest line ++ * was being read. ++ */ ++ if (sink->sfile) { ++ if (!sink->ignore_overflow) ++ seq_puts(sink->sfile, "log overflow.\n"); ++ /* coalesce subsequent contiguous overflows. */ ++ sink->ignore_overflow = true; ++ } else { ++ dev_err(s->dev, "log overflow.\n"); ++ } ++ sink->get = u32_sub_overflow(alloc, log->sz); ++ return; ++ } ++ /* compute next line index */ ++ sink->get = u32_add_overflow(get, read_chars); ++ /* once a line is valid, ignore_overflow must be disabled */ ++ sink->ignore_overflow = false; ++ if (sink->sfile) { ++ seq_printf(sink->sfile, "%s", s->line_buffer); ++ } else { ++ if (sink->trusty_panicked || ++ __ratelimit(&trusty_log_rate_limit)) { ++ dev_info(s->dev, "%s", s->line_buffer); ++ } ++ } ++} ++ ++static void *trusty_log_seq_start(struct seq_file *sfile, loff_t *pos) ++{ ++ struct trusty_log_sfile *lb; ++ struct trusty_log_state *s; ++ struct log_rb *log; ++ struct trusty_log_sink_state *log_sfile_sink; ++ u32 index; ++ int rc; ++ ++ if (WARN_ON(!pos)) ++ return ERR_PTR(-EINVAL); ++ ++ lb = sfile->private; ++ if (WARN_ON(!lb)) ++ return ERR_PTR(-EINVAL); ++ ++ log_sfile_sink = kzalloc(sizeof(*log_sfile_sink), GFP_KERNEL); ++ if (!log_sfile_sink) ++ return ERR_PTR(-ENOMEM); ++ ++ s = container_of(lb, struct trusty_log_state, log_sfile); ++ log_sfile_sink->sfile = sfile; ++ log = s->log; ++ if (*pos == 0) { ++ /* start at the oldest line */ ++ index = 0; ++ if (log->alloc > log->sz) ++ index = u32_sub_overflow(log->alloc, log->sz); ++ } else { ++ /* ++ * '*pos>0': pos hold the 32bits unwrapped index from where ++ * to start iterating ++ */ ++ index = (u32)*pos; ++ } ++ pr_debug("%s start=%u\n", __func__, index); ++ ++ log_sfile_sink->ignore_overflow = true; ++ rc = trusty_log_start(s, log_sfile_sink, index); ++ if (rc < 0) ++ goto free_sink; ++ ++ if (!trusty_log_has_data(s, log_sfile_sink)) ++ goto free_sink; ++ ++ return log_sfile_sink; ++ ++free_sink: ++ pr_debug("%s kfree\n", __func__); ++ kfree(log_sfile_sink); ++ return rc < 0 ? ERR_PTR(rc) : NULL; ++} ++ ++static void *trusty_log_seq_next(struct seq_file *sfile, void *v, loff_t *pos) ++{ ++ struct trusty_log_sfile *lb; ++ struct trusty_log_state *s; ++ struct trusty_log_sink_state *log_sfile_sink = v; ++ int rc = 0; ++ ++ if (WARN_ON(!log_sfile_sink)) ++ return ERR_PTR(-EINVAL); ++ ++ lb = sfile->private; ++ if (WARN_ON(!lb)) { ++ rc = -EINVAL; ++ goto end_of_iter; ++ } ++ s = container_of(lb, struct trusty_log_state, log_sfile); ++ ++ if (WARN_ON(!pos)) { ++ rc = -EINVAL; ++ goto end_of_iter; ++ } ++ /* ++ * When starting a virtual file sink, the start function is invoked ++ * with a pos argument which value is set to zero. ++ * Subsequent starts are invoked with pos being set to ++ * the unwrapped read index (get). ++ * Upon u32 wraparound, the get index could be reset to zero. ++ * Thus a msb is used to distinguish the `get` zero value ++ * from the `start of file` zero value. ++ */ ++ *pos = (1UL << 32) + log_sfile_sink->get; ++ if (!trusty_log_has_data(s, log_sfile_sink)) ++ goto end_of_iter; ++ ++ return log_sfile_sink; ++ ++end_of_iter: ++ pr_debug("%s kfree\n", __func__); ++ kfree(log_sfile_sink); ++ return rc < 0 ? ERR_PTR(rc) : NULL; ++} ++ ++static void trusty_log_seq_stop(struct seq_file *sfile, void *v) ++{ ++ /* ++ * When iteration completes or on error, the next callback frees ++ * the sink structure and returns NULL/error-code. ++ * In that case stop (being invoked with void* v set to the last next ++ * return value) would be invoked with v == NULL or error code. ++ * When user space stops the iteration earlier than the end ++ * (in case of user-space memory allocation limit for example) ++ * then the stop function receives a non NULL get pointer ++ * and is in charge or freeing the sink structure. ++ */ ++ struct trusty_log_sink_state *log_sfile_sink = v; ++ ++ /* nothing to do - sink structure already freed */ ++ if (IS_ERR_OR_NULL(log_sfile_sink)) ++ return; ++ ++ kfree(log_sfile_sink); ++ ++ pr_debug("%s kfree\n", __func__); ++} ++ ++static int trusty_log_seq_show(struct seq_file *sfile, void *v) ++{ ++ struct trusty_log_sfile *lb; ++ struct trusty_log_state *s; ++ struct trusty_log_sink_state *log_sfile_sink = v; ++ ++ if (WARN_ON(!log_sfile_sink)) ++ return -EINVAL; ++ ++ lb = sfile->private; ++ if (WARN_ON(!lb)) ++ return -EINVAL; ++ ++ s = container_of(lb, struct trusty_log_state, log_sfile); ++ ++ trusty_log_show(s, log_sfile_sink); ++ return 0; ++} ++ ++static void trusty_dump_logs(struct trusty_log_state *s) ++{ ++ int rc; ++ /* ++ * note: klog_sink.get initialized to zero by kzalloc ++ */ ++ s->klog_sink.trusty_panicked = trusty_get_panic_status(s->trusty_dev); ++ ++ rc = trusty_log_start(s, &s->klog_sink, s->klog_sink.get); ++ if (rc < 0) ++ return; ++ ++ while (trusty_log_has_data(s, &s->klog_sink)) ++ trusty_log_show(s, &s->klog_sink); ++} ++ ++static int trusty_log_call_notify(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct trusty_log_state *s; ++ unsigned long flags; ++ u32 cur_put; ++ ++ if (action != TRUSTY_CALL_RETURNED) ++ return NOTIFY_DONE; ++ ++ s = container_of(nb, struct trusty_log_state, call_notifier); ++ spin_lock_irqsave(&s->wake_up_lock, flags); ++ cur_put = s->log->put; ++ if (cur_put != s->last_wake_put) { ++ s->last_wake_put = cur_put; ++ wake_up_all(&s->poll_waiters); ++ } ++ spin_unlock_irqrestore(&s->wake_up_lock, flags); ++ return NOTIFY_OK; ++} ++ ++static int trusty_log_panic_notify(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct trusty_log_state *s; ++ ++ /* ++ * Don't grab the spin lock to hold up the panic notifier, even ++ * though this is racy. ++ */ ++ s = container_of(nb, struct trusty_log_state, panic_notifier); ++ dev_info(s->dev, "panic notifier - trusty version %s", ++ trusty_version_str_get(s->trusty_dev)); ++ trusty_dump_logs(s); ++ return NOTIFY_OK; ++} ++ ++const struct seq_operations trusty_log_seq_ops = { ++ .start = trusty_log_seq_start, ++ .stop = trusty_log_seq_stop, ++ .next = trusty_log_seq_next, ++ .show = trusty_log_seq_show, ++}; ++ ++static int trusty_log_sfile_dev_open(struct inode *inode, struct file *file) ++{ ++ struct trusty_log_sfile *ls; ++ struct seq_file *sfile; ++ int rc; ++ ++ /* ++ * file->private_data contains a pointer to the misc_device struct ++ * passed to misc_register() ++ */ ++ if (WARN_ON(!file->private_data)) ++ return -EINVAL; ++ ++ ls = container_of(file->private_data, struct trusty_log_sfile, misc); ++ ++ /* ++ * seq_open uses file->private_data to store the seq_file associated ++ * with the struct file, but it must be NULL when seq_open is called ++ */ ++ file->private_data = NULL; ++ rc = seq_open(file, &trusty_log_seq_ops); ++ if (rc < 0) ++ return rc; ++ ++ sfile = file->private_data; ++ if (WARN_ON(!sfile)) ++ return -EINVAL; ++ ++ sfile->private = ls; ++ return 0; ++} ++ ++static unsigned int trusty_log_sfile_dev_poll(struct file *filp, ++ struct poll_table_struct *wait) ++{ ++ struct seq_file *sfile; ++ struct trusty_log_sfile *lb; ++ struct trusty_log_state *s; ++ struct log_rb *log; ++ ++ /* ++ * trusty_log_sfile_dev_open() pointed filp->private_data to a ++ * seq_file, and that seq_file->private to the trusty_log_sfile ++ * field of a trusty_log_state ++ */ ++ sfile = filp->private_data; ++ lb = sfile->private; ++ s = container_of(lb, struct trusty_log_state, log_sfile); ++ poll_wait(filp, &s->poll_waiters, wait); ++ log = s->log; ++ ++ /* ++ * Userspace has read up to filp->f_pos so far. Update klog_sink ++ * to indicate that, so that we don't end up dumping the entire ++ * Trusty log in case of panic. ++ */ ++ s->klog_sink.get = (u32)filp->f_pos; ++ ++ if (log->put != (u32)filp->f_pos) { ++ /* data ready to read */ ++ return EPOLLIN | EPOLLRDNORM; ++ } ++ /* no data available, go to sleep */ ++ return 0; ++} ++ ++static const struct file_operations log_sfile_dev_operations = { ++ .owner = THIS_MODULE, ++ .open = trusty_log_sfile_dev_open, ++ .poll = trusty_log_sfile_dev_poll, ++ .read = seq_read, ++ .release = seq_release, ++}; ++ ++static int trusty_log_sfile_register(struct trusty_log_state *s) ++{ ++ int ret; ++ struct trusty_log_sfile *ls = &s->log_sfile; ++ ++ if (WARN_ON(!ls)) ++ return -EINVAL; ++ ++ snprintf(ls->device_name, sizeof(ls->device_name), ++ "trusty-log%d", s->dev->id); ++ ls->misc.minor = MISC_DYNAMIC_MINOR; ++ ls->misc.name = ls->device_name; ++ ls->misc.fops = &log_sfile_dev_operations; ++ ++ ret = misc_register(&ls->misc); ++ if (ret) { ++ dev_err(s->dev, ++ "log_sfile error while doing misc_register ret=%d\n", ++ ret); ++ return ret; ++ } ++ dev_info(s->dev, "/dev/%s registered\n", ++ ls->device_name); ++ return 0; ++} ++ ++static void trusty_log_sfile_unregister(struct trusty_log_state *s) ++{ ++ struct trusty_log_sfile *ls = &s->log_sfile; ++ ++ misc_deregister(&ls->misc); ++ if (s->dev) { ++ dev_info(s->dev, "/dev/%s unregistered\n", ++ ls->misc.name); ++ } ++} ++ ++static bool trusty_supports_logging(struct device *device) ++{ ++ int result; ++ ++ result = trusty_std_call32(device, SMC_SC_SHARED_LOG_VERSION, ++ TRUSTY_LOG_API_VERSION, 0, 0); ++ if (result == SM_ERR_UNDEFINED_SMC) { ++ dev_info(device, "trusty-log not supported on secure side.\n"); ++ return false; ++ } else if (result < 0) { ++ dev_err(device, ++ "trusty std call (SMC_SC_SHARED_LOG_VERSION) failed: %d\n", ++ result); ++ return false; ++ } ++ ++ if (result != TRUSTY_LOG_API_VERSION) { ++ dev_info(device, "unsupported api version: %d, supported: %d\n", ++ result, TRUSTY_LOG_API_VERSION); ++ return false; ++ } ++ return true; ++} ++ ++static int trusty_log_init(struct platform_device *pdev) ++{ ++ struct trusty_log_state *s; ++ struct scatterlist *sg; ++ unsigned char *mem; ++ int i; ++ int result; ++ trusty_shared_mem_id_t mem_id; ++ int log_size; ++ ++ s = kzalloc(sizeof(*s), GFP_KERNEL); ++ if (!s) { ++ result = -ENOMEM; ++ goto error_alloc_state; ++ } ++ ++ s->dev = &pdev->dev; ++ s->trusty_dev = s->dev->parent; ++ ++ s->log_num_pages = DIV_ROUND_UP(log_size_param + sizeof(struct log_rb), ++ PAGE_SIZE); ++ s->sg = kcalloc(s->log_num_pages, sizeof(*s->sg), GFP_KERNEL); ++ if (!s->sg) { ++ result = -ENOMEM; ++ goto error_alloc_sg; ++ } ++ ++ log_size = s->log_num_pages * PAGE_SIZE; ++ mem = vzalloc(log_size); ++ if (!mem) { ++ result = -ENOMEM; ++ goto error_alloc_log; ++ } ++ ++ s->log = (struct log_rb *)mem; ++ ++ sg_init_table(s->sg, s->log_num_pages); ++ for_each_sg(s->sg, sg, s->log_num_pages, i) { ++ struct page *pg = vmalloc_to_page(mem + (i * PAGE_SIZE)); ++ ++ if (!pg) { ++ result = -ENOMEM; ++ goto err_share_memory; ++ } ++ sg_set_page(sg, pg, PAGE_SIZE, 0); ++ } ++ /* ++ * This will fail for Trusty api version < TRUSTY_API_VERSION_MEM_OBJ ++ * if s->log_num_pages > 1 ++ * Use trusty_share_memory_compat instead of trusty_share_memory in case ++ * s->log_num_pages == 1 and api version < TRUSTY_API_VERSION_MEM_OBJ, ++ * In that case SMC_SC_SHARED_LOG_ADD expects a different value than ++ * what trusty_share_memory returns ++ */ ++ result = trusty_share_memory_compat(s->trusty_dev, &mem_id, s->sg, ++ s->log_num_pages, PAGE_KERNEL); ++ if (result) { ++ dev_err(s->dev, "trusty_share_memory failed: %d\n", result); ++ goto err_share_memory; ++ } ++ s->log_pages_shared_mem_id = mem_id; ++ ++ result = trusty_std_call32(s->trusty_dev, ++ SMC_SC_SHARED_LOG_ADD, ++ (u32)(mem_id), (u32)(mem_id >> 32), ++ log_size); ++ if (result < 0) { ++ dev_err(s->dev, ++ "trusty std call (SMC_SC_SHARED_LOG_ADD) failed: %d 0x%llx\n", ++ result, mem_id); ++ goto error_std_call; ++ } ++ ++ init_waitqueue_head(&s->poll_waiters); ++ spin_lock_init(&s->wake_up_lock); ++ ++ s->call_notifier.notifier_call = trusty_log_call_notify; ++ result = trusty_call_notifier_register(s->trusty_dev, ++ &s->call_notifier); ++ if (result < 0) { ++ dev_err(&pdev->dev, ++ "failed to register trusty call notifier\n"); ++ goto error_call_notifier; ++ } ++ ++ s->panic_notifier.notifier_call = trusty_log_panic_notify; ++ result = atomic_notifier_chain_register(&panic_notifier_list, ++ &s->panic_notifier); ++ if (result < 0) { ++ dev_err(&pdev->dev, ++ "failed to register panic notifier\n"); ++ goto error_panic_notifier; ++ } ++ ++ result = trusty_log_sfile_register(s); ++ if (result < 0) { ++ dev_err(&pdev->dev, "failed to register log_sfile\n"); ++ goto error_log_sfile; ++ } ++ ++ platform_set_drvdata(pdev, s); ++ ++ return 0; ++ ++error_log_sfile: ++ atomic_notifier_chain_unregister(&panic_notifier_list, ++ &s->panic_notifier); ++error_panic_notifier: ++ trusty_call_notifier_unregister(s->trusty_dev, &s->call_notifier); ++error_call_notifier: ++ trusty_std_call32(s->trusty_dev, SMC_SC_SHARED_LOG_RM, ++ (u32)mem_id, (u32)(mem_id >> 32), 0); ++error_std_call: ++ if (WARN_ON(trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg, ++ s->log_num_pages))) { ++ dev_err(&pdev->dev, "trusty_revoke_memory failed: %d 0x%llx\n", ++ result, mem_id); ++ /* ++ * It is not safe to free this memory if trusty_revoke_memory ++ * fails. Leak it in that case. ++ */ ++ } else { ++err_share_memory: ++ vfree(s->log); ++ } ++error_alloc_log: ++ kfree(s->sg); ++error_alloc_sg: ++ kfree(s); ++error_alloc_state: ++ return result; ++} ++ ++static int trusty_log_probe(struct platform_device *pdev) ++{ ++ int rc; ++ ++ if (!trusty_supports_logging(pdev->dev.parent)) ++ return -ENXIO; ++ ++ rc = trusty_log_init(pdev); ++ if (rc && log_size_param > TRUSTY_LOG_MIN_SIZE) { ++ dev_warn(&pdev->dev, "init failed, retrying with 1-page log\n"); ++ log_size_param = TRUSTY_LOG_MIN_SIZE; ++ rc = trusty_log_init(pdev); ++ } ++ return rc; ++} ++ ++static int trusty_log_remove(struct platform_device *pdev) ++{ ++ int result; ++ struct trusty_log_state *s = platform_get_drvdata(pdev); ++ trusty_shared_mem_id_t mem_id = s->log_pages_shared_mem_id; ++ ++ trusty_log_sfile_unregister(s); ++ atomic_notifier_chain_unregister(&panic_notifier_list, ++ &s->panic_notifier); ++ trusty_call_notifier_unregister(s->trusty_dev, &s->call_notifier); ++ ++ result = trusty_std_call32(s->trusty_dev, SMC_SC_SHARED_LOG_RM, ++ (u32)mem_id, (u32)(mem_id >> 32), 0); ++ if (result) { ++ dev_err(&pdev->dev, ++ "trusty std call (SMC_SC_SHARED_LOG_RM) failed: %d\n", ++ result); ++ } ++ result = trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg, ++ s->log_num_pages); ++ if (WARN_ON(result)) { ++ dev_err(&pdev->dev, ++ "trusty failed to remove shared memory: %d\n", result); ++ } else { ++ /* ++ * It is not safe to free this memory if trusty_revoke_memory ++ * fails. Leak it in that case. ++ */ ++ vfree(s->log); ++ } ++ kfree(s->sg); ++ kfree(s); ++ ++ return 0; ++} ++ ++static const struct of_device_id trusty_test_of_match[] = { ++ { .compatible = "android,trusty-log-v1", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(trusty, trusty_test_of_match); ++ ++static struct platform_driver trusty_log_driver = { ++ .probe = trusty_log_probe, ++ .remove = trusty_log_remove, ++ .driver = { ++ .name = "trusty-log", ++ .of_match_table = trusty_test_of_match, ++ }, ++}; ++ ++module_platform_driver(trusty_log_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Trusty logging driver"); +diff --git a/drivers/trusty/trusty-log.h b/drivers/trusty/trusty-log.h +new file mode 100644 +index 000000000000..7b5e6096b51e +--- /dev/null ++++ b/drivers/trusty/trusty-log.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright (c) 2015 Google, Inc. ++ * ++ * Trusty also has a copy of this header. Please keep the copies in sync. ++ */ ++#ifndef _TRUSTY_LOG_H_ ++#define _TRUSTY_LOG_H_ ++ ++/* ++ * Ring buffer that supports one secure producer thread and one ++ * linux side consumer thread. ++ */ ++struct log_rb { ++ volatile uint32_t alloc; ++ volatile uint32_t put; ++ uint32_t sz; ++ volatile char data[]; ++} __packed; ++ ++#define SMC_SC_SHARED_LOG_VERSION SMC_STDCALL_NR(SMC_ENTITY_LOGGING, 0) ++#define SMC_SC_SHARED_LOG_ADD SMC_STDCALL_NR(SMC_ENTITY_LOGGING, 1) ++#define SMC_SC_SHARED_LOG_RM SMC_STDCALL_NR(SMC_ENTITY_LOGGING, 2) ++ ++#define TRUSTY_LOG_API_VERSION 1 ++ ++#endif ++ +diff --git a/drivers/trusty/trusty-mem.c b/drivers/trusty/trusty-mem.c +new file mode 100644 +index 000000000000..8a360298e501 +--- /dev/null ++++ b/drivers/trusty/trusty-mem.c +@@ -0,0 +1,139 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2015 Google, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define MEM_ATTR_STRONGLY_ORDERED (0x00U) ++#define MEM_ATTR_DEVICE (0x04U) ++#define MEM_ATTR_NORMAL_NON_CACHEABLE (0x44U) ++#define MEM_ATTR_NORMAL_WRITE_THROUGH (0xAAU) ++#define MEM_ATTR_NORMAL_WRITE_BACK_READ_ALLOCATE (0xEEU) ++#define MEM_ATTR_NORMAL_WRITE_BACK_WRITE_ALLOCATE (0xFFU) ++ ++#define ATTR_RDONLY (1U << 7) ++#define ATTR_INNER_SHAREABLE (3U << 8) ++ ++static int get_mem_attr(struct page *page, pgprot_t pgprot) ++{ ++#if defined(CONFIG_ARM64) ++ u64 mair; ++ unsigned int attr_index = (pgprot_val(pgprot) & PTE_ATTRINDX_MASK) >> 2; ++ ++ asm ("mrs %0, mair_el1\n" : "=&r" (mair)); ++ return (mair >> (attr_index * 8)) & 0xff; ++ ++#elif defined(CONFIG_ARM_LPAE) ++ u32 mair; ++ unsigned int attr_index = ((pgprot_val(pgprot) & L_PTE_MT_MASK) >> 2); ++ ++ if (attr_index >= 4) { ++ attr_index -= 4; ++ asm volatile("mrc p15, 0, %0, c10, c2, 1\n" : "=&r" (mair)); ++ } else { ++ asm volatile("mrc p15, 0, %0, c10, c2, 0\n" : "=&r" (mair)); ++ } ++ return (mair >> (attr_index * 8)) & 0xff; ++ ++#elif defined(CONFIG_ARM) ++ /* check memory type */ ++ switch (pgprot_val(pgprot) & L_PTE_MT_MASK) { ++ case L_PTE_MT_WRITEALLOC: ++ return MEM_ATTR_NORMAL_WRITE_BACK_WRITE_ALLOCATE; ++ ++ case L_PTE_MT_BUFFERABLE: ++ return MEM_ATTR_NORMAL_NON_CACHEABLE; ++ ++ case L_PTE_MT_WRITEBACK: ++ return MEM_ATTR_NORMAL_WRITE_BACK_READ_ALLOCATE; ++ ++ case L_PTE_MT_WRITETHROUGH: ++ return MEM_ATTR_NORMAL_WRITE_THROUGH; ++ ++ case L_PTE_MT_UNCACHED: ++ return MEM_ATTR_STRONGLY_ORDERED; ++ ++ case L_PTE_MT_DEV_SHARED: ++ case L_PTE_MT_DEV_NONSHARED: ++ return MEM_ATTR_DEVICE; ++ ++ default: ++ return -EINVAL; ++ } ++#else ++ return 0; ++#endif ++} ++ ++int trusty_encode_page_info(struct ns_mem_page_info *inf, ++ struct page *page, pgprot_t pgprot) ++{ ++ int mem_attr; ++ u64 pte; ++ u8 ffa_mem_attr; ++ u8 ffa_mem_perm = 0; ++ ++ if (!inf || !page) ++ return -EINVAL; ++ ++ /* get physical address */ ++ pte = (u64)page_to_phys(page); ++ ++ /* get memory attributes */ ++ mem_attr = get_mem_attr(page, pgprot); ++ if (mem_attr < 0) ++ return mem_attr; ++ ++ switch (mem_attr) { ++ case MEM_ATTR_STRONGLY_ORDERED: ++ ffa_mem_attr = FFA_MEM_ATTR_DEVICE_NGNRNE; ++ break; ++ ++ case MEM_ATTR_DEVICE: ++ ffa_mem_attr = FFA_MEM_ATTR_DEVICE_NGNRE; ++ break; ++ ++ case MEM_ATTR_NORMAL_NON_CACHEABLE: ++ ffa_mem_attr = FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED; ++ break; ++ ++ case MEM_ATTR_NORMAL_WRITE_BACK_READ_ALLOCATE: ++ case MEM_ATTR_NORMAL_WRITE_BACK_WRITE_ALLOCATE: ++ ffa_mem_attr = FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ inf->paddr = pte; ++ ++ /* add other attributes */ ++#if defined(CONFIG_ARM64) || defined(CONFIG_ARM_LPAE) ++ pte |= pgprot_val(pgprot); ++#elif defined(CONFIG_ARM) ++ if (pgprot_val(pgprot) & L_PTE_RDONLY) ++ pte |= ATTR_RDONLY; ++ if (pgprot_val(pgprot) & L_PTE_SHARED) ++ pte |= ATTR_INNER_SHAREABLE; /* inner sharable */ ++#endif ++ ++ if (!(pte & ATTR_RDONLY)) ++ ffa_mem_perm |= FFA_MEM_PERM_RW; ++ else ++ ffa_mem_perm |= FFA_MEM_PERM_RO; ++ ++ if ((pte & ATTR_INNER_SHAREABLE) == ATTR_INNER_SHAREABLE) ++ ffa_mem_attr |= FFA_MEM_ATTR_INNER_SHAREABLE; ++ ++ inf->ffa_mem_attr = ffa_mem_attr; ++ inf->ffa_mem_perm = ffa_mem_perm; ++ inf->compat_attr = (pte & 0x0000FFFFFFFFFFFFull) | ++ ((u64)mem_attr << 48); ++ return 0; ++} +diff --git a/drivers/trusty/trusty-smc-arm.S b/drivers/trusty/trusty-smc-arm.S +new file mode 100644 +index 000000000000..8ff83547d33f +--- /dev/null ++++ b/drivers/trusty/trusty-smc-arm.S +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2020 Google, Inc. ++ */ ++ ++#include ++ ++.arch_extension sec ++ ++ENTRY(trusty_smc8) ++ /* Save stack location where r3-r7 smc arguments are stored */ ++ mov r12, sp ++ ++ /* Save original r4-r7 values as caller expects these to be preserved */ ++ push {r4-r7} ++ ++ /* Save return value pointer and return address */ ++ push {r0, lr} ++ ++ /* arm abi shifts arguments when returning a struct, shift them back */ ++ mov r0, r1 ++ mov r1, r2 ++ mov r2, r3 ++ ++ /* Load stack based arguments */ ++ ldmia r12, {r3-r7} ++ ++ smc #0 ++ ++ /* Restore return address and get return value pointer */ ++ pop {r12, lr} ++ ++ /* Copy 8-register smc return value to struct smc_ret8 return value */ ++ stmia r12, {r0-r7} ++ ++ /* Restore original r4-r7 values */ ++ pop {r4-r7} ++ ++ /* Return */ ++ bx lr ++ENDPROC(trusty_smc8) +diff --git a/drivers/trusty/trusty-smc-arm64.S b/drivers/trusty/trusty-smc-arm64.S +new file mode 100644 +index 000000000000..14c8fed28a5e +--- /dev/null ++++ b/drivers/trusty/trusty-smc-arm64.S +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2020 Google, Inc. ++ */ ++ ++#include ++ ++.macro push ra, rb ++stp \ra, \rb, [sp,#-16]! ++.endm ++ ++.macro pop ra, rb ++ldp \ra, \rb, [sp], #16 ++.endm ++ ++lr .req x30 ++ ++SYM_FUNC_START(trusty_smc8) ++ /* ++ * Save x8 (return value ptr) and lr. The SMC calling convention says el3 ++ * does not need to preserve x8. The normal ABI does not require either x8 ++ * or lr to be preserved. ++ */ ++ push x8, lr ++ smc #0 ++ pop x8, lr ++ ++ /* Copy 8-register smc return value to struct smc_ret8 return value */ ++ stp x0, x1, [x8], #16 ++ stp x2, x3, [x8], #16 ++ stp x4, x5, [x8], #16 ++ stp x6, x7, [x8], #16 ++ ++ ret ++SYM_FUNC_END(trusty_smc8) +diff --git a/drivers/trusty/trusty-smc.h b/drivers/trusty/trusty-smc.h +new file mode 100644 +index 000000000000..b53e5abb4d05 +--- /dev/null ++++ b/drivers/trusty/trusty-smc.h +@@ -0,0 +1,26 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2020 Google, Inc. ++ */ ++#ifndef _TRUSTY_SMC_H ++#define _TRUSTY_SMC_H ++ ++#include ++ ++struct smc_ret8 { ++ unsigned long r0; ++ unsigned long r1; ++ unsigned long r2; ++ unsigned long r3; ++ unsigned long r4; ++ unsigned long r5; ++ unsigned long r6; ++ unsigned long r7; ++}; ++ ++struct smc_ret8 trusty_smc8(unsigned long r0, unsigned long r1, ++ unsigned long r2, unsigned long r3, ++ unsigned long r4, unsigned long r5, ++ unsigned long r6, unsigned long r7); ++ ++#endif /* _TRUSTY_SMC_H */ +diff --git a/drivers/trusty/trusty-test.c b/drivers/trusty/trusty-test.c +new file mode 100644 +index 000000000000..844868981fa5 +--- /dev/null ++++ b/drivers/trusty/trusty-test.c +@@ -0,0 +1,440 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2020 Google, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "trusty-test.h" ++ ++struct trusty_test_state { ++ struct device *dev; ++ struct device *trusty_dev; ++}; ++ ++struct trusty_test_shmem_obj { ++ struct list_head node; ++ size_t page_count; ++ struct page **pages; ++ void *buf; ++ struct sg_table sgt; ++ trusty_shared_mem_id_t mem_id; ++}; ++ ++/* ++ * Allocate a test object with @page_count number of pages, map it and add it to ++ * @list. ++ * For multi-page allocations, order the pages so they are not contiguous. ++ */ ++static int trusty_test_alloc_obj(struct trusty_test_state *s, ++ size_t page_count, ++ struct list_head *list) ++{ ++ size_t i; ++ int ret = -ENOMEM; ++ struct trusty_test_shmem_obj *obj; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ goto err_alloc_obj; ++ obj->page_count = page_count; ++ ++ obj->pages = kmalloc_array(page_count, sizeof(*obj->pages), GFP_KERNEL); ++ if (!obj->pages) { ++ ret = -ENOMEM; ++ dev_err(s->dev, "failed to allocate page array, count %zd\n", ++ page_count); ++ goto err_alloc_pages; ++ } ++ ++ for (i = 0; i < page_count; i++) { ++ obj->pages[i] = alloc_page(GFP_KERNEL); ++ if (!obj->pages[i]) { ++ ret = -ENOMEM; ++ dev_err(s->dev, "failed to allocate page %zd/%zd\n", ++ i, page_count); ++ goto err_alloc_page; ++ } ++ if (i > 0 && obj->pages[i - 1] + 1 == obj->pages[i]) { ++ /* swap adacent pages to increase fragmentation */ ++ swap(obj->pages[i - 1], obj->pages[i]); ++ } ++ } ++ ++ obj->buf = vmap(obj->pages, page_count, VM_MAP, PAGE_KERNEL); ++ if (!obj->buf) { ++ ret = -ENOMEM; ++ dev_err(s->dev, "failed to map test buffer page count %zd\n", ++ page_count); ++ goto err_map_pages; ++ } ++ ++ ret = sg_alloc_table_from_pages(&obj->sgt, obj->pages, page_count, ++ 0, page_count * PAGE_SIZE, GFP_KERNEL); ++ if (ret) { ++ dev_err(s->dev, "sg_alloc_table_from_pages failed: %d\n", ret); ++ goto err_alloc_sgt; ++ } ++ list_add_tail(&obj->node, list); ++ dev_dbg(s->dev, "buffer has %d page runs\n", obj->sgt.nents); ++ return 0; ++ ++err_alloc_sgt: ++ vunmap(obj->buf); ++err_map_pages: ++ for (i = page_count; i > 0; i--) { ++ __free_page(obj->pages[i - 1]); ++err_alloc_page: ++ ; ++ } ++ kfree(obj->pages); ++err_alloc_pages: ++ kfree(obj); ++err_alloc_obj: ++ return ret; ++} ++ ++/* Unlink, unmap and free a test object and its pages */ ++static void trusty_test_free_obj(struct trusty_test_state *s, ++ struct trusty_test_shmem_obj *obj) ++{ ++ size_t i; ++ ++ list_del(&obj->node); ++ sg_free_table(&obj->sgt); ++ vunmap(obj->buf); ++ for (i = obj->page_count; i > 0; i--) ++ __free_page(obj->pages[i - 1]); ++ kfree(obj->pages); ++ kfree(obj); ++} ++ ++/* ++ * Share all the pages of all the test object in &obj_list. ++ * If sharing a test object fails, free it so that every test object that ++ * remains in @obj_list has been shared when this function returns. ++ * Return a error if any test object failed to be shared. ++ */ ++static int trusty_test_share_objs(struct trusty_test_state *s, ++ struct list_head *obj_list, size_t size) ++{ ++ int ret = 0; ++ int tmpret; ++ struct trusty_test_shmem_obj *obj; ++ struct trusty_test_shmem_obj *next_obj; ++ ktime_t t1; ++ ktime_t t2; ++ ++ list_for_each_entry_safe(obj, next_obj, obj_list, node) { ++ t1 = ktime_get(); ++ tmpret = trusty_share_memory(s->trusty_dev, &obj->mem_id, ++ obj->sgt.sgl, obj->sgt.nents, ++ PAGE_KERNEL); ++ t2 = ktime_get(); ++ if (tmpret) { ++ ret = tmpret; ++ dev_err(s->dev, ++ "trusty_share_memory failed: %d, size=%zd\n", ++ ret, size); ++ ++ /* ++ * Free obj and continue, so we can revoke the ++ * whole list in trusty_test_reclaim_objs. ++ */ ++ trusty_test_free_obj(s, obj); ++ } ++ dev_dbg(s->dev, "share id=0x%llx, size=%zu took %lld ns\n", ++ obj->mem_id, size, ++ ktime_to_ns(ktime_sub(t2, t1))); ++ } ++ ++ return ret; ++} ++ ++/* Reclaim memory shared with trusty for all test objects in @obj_list. */ ++static int trusty_test_reclaim_objs(struct trusty_test_state *s, ++ struct list_head *obj_list, size_t size) ++{ ++ int ret = 0; ++ int tmpret; ++ struct trusty_test_shmem_obj *obj; ++ struct trusty_test_shmem_obj *next_obj; ++ ktime_t t1; ++ ktime_t t2; ++ ++ list_for_each_entry_safe(obj, next_obj, obj_list, node) { ++ t1 = ktime_get(); ++ tmpret = trusty_reclaim_memory(s->trusty_dev, obj->mem_id, ++ obj->sgt.sgl, obj->sgt.nents); ++ t2 = ktime_get(); ++ if (tmpret) { ++ ret = tmpret; ++ dev_err(s->dev, ++ "trusty_reclaim_memory failed: %d, id=0x%llx\n", ++ ret, obj->mem_id); ++ ++ /* ++ * It is not safe to free this memory if ++ * trusty_reclaim_memory fails. Leak it in that ++ * case. ++ */ ++ list_del(&obj->node); ++ } ++ dev_dbg(s->dev, "revoke id=0x%llx, size=%zu took %lld ns\n", ++ obj->mem_id, size, ++ ktime_to_ns(ktime_sub(t2, t1))); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Test a test object. First, initialize the memory, then make a std call into ++ * trusty which will read it and return an error if the initialized value does ++ * not match what it expects. If trusty reads the correct values, it will modify ++ * the memory and return 0. This function then checks that it can read the ++ * correct modified value. ++ */ ++static int trusty_test_rw(struct trusty_test_state *s, ++ struct trusty_test_shmem_obj *obj) ++{ ++ size_t size = obj->page_count * PAGE_SIZE; ++ int ret; ++ size_t i; ++ u64 *buf = obj->buf; ++ ktime_t t1; ++ ktime_t t2; ++ ++ for (i = 0; i < size / sizeof(*buf); i++) ++ buf[i] = i; ++ ++ t1 = ktime_get(); ++ ret = trusty_std_call32(s->trusty_dev, SMC_SC_TEST_SHARED_MEM_RW, ++ (u32)(obj->mem_id), (u32)(obj->mem_id >> 32), ++ size); ++ t2 = ktime_get(); ++ if (ret < 0) { ++ dev_err(s->dev, ++ "trusty std call (SMC_SC_TEST_SHARED_MEM_RW) failed: %d 0x%llx\n", ++ ret, obj->mem_id); ++ return ret; ++ } ++ ++ for (i = 0; i < size / sizeof(*buf); i++) { ++ if (buf[i] != size - i) { ++ dev_err(s->dev, ++ "input mismatch at %zd, got 0x%llx instead of 0x%zx\n", ++ i, buf[i], size - i); ++ return -EIO; ++ } ++ } ++ ++ dev_dbg(s->dev, "rw id=0x%llx, size=%zu took %lld ns\n", obj->mem_id, ++ size, ktime_to_ns(ktime_sub(t2, t1))); ++ ++ return 0; ++} ++ ++/* ++ * Run test on every test object in @obj_list. Repeat @repeat_access times. ++ */ ++static int trusty_test_rw_objs(struct trusty_test_state *s, ++ struct list_head *obj_list, ++ size_t repeat_access) ++{ ++ int ret; ++ size_t i; ++ struct trusty_test_shmem_obj *obj; ++ ++ for (i = 0; i < repeat_access; i++) { ++ /* ++ * Repeat test in case the memory attributes don't match ++ * and either side see old data. ++ */ ++ list_for_each_entry(obj, obj_list, node) { ++ ret = trusty_test_rw(s, obj); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Allocate @obj_count test object that each have @page_count pages. Share each ++ * object @repeat_share times, each time running tests on every object ++ * @repeat_access times. ++ */ ++static int trusty_test_run(struct trusty_test_state *s, size_t page_count, ++ size_t obj_count, size_t repeat_share, ++ size_t repeat_access) ++{ ++ int ret = 0; ++ int tmpret; ++ size_t i; ++ size_t size = page_count * PAGE_SIZE; ++ LIST_HEAD(obj_list); ++ struct trusty_test_shmem_obj *obj; ++ struct trusty_test_shmem_obj *next_obj; ++ ++ for (i = 0; i < obj_count && !ret; i++) ++ ret = trusty_test_alloc_obj(s, page_count, &obj_list); ++ ++ for (i = 0; i < repeat_share && !ret; i++) { ++ ret = trusty_test_share_objs(s, &obj_list, size); ++ if (ret) { ++ dev_err(s->dev, ++ "trusty_share_memory failed: %d, i=%zd/%zd, size=%zd\n", ++ ret, i, repeat_share, size); ++ } else { ++ ret = trusty_test_rw_objs(s, &obj_list, repeat_access); ++ if (ret) ++ dev_err(s->dev, ++ "test failed: %d, i=%zd/%zd, size=%zd\n", ++ ret, i, repeat_share, size); ++ } ++ tmpret = trusty_test_reclaim_objs(s, &obj_list, size); ++ if (tmpret) { ++ ret = tmpret; ++ dev_err(s->dev, ++ "trusty_reclaim_memory failed: %d, i=%zd/%zd\n", ++ ret, i, repeat_share); ++ } ++ } ++ ++ list_for_each_entry_safe(obj, next_obj, &obj_list, node) ++ trusty_test_free_obj(s, obj); ++ ++ dev_info(s->dev, "[ %s ] size %zd, obj_count %zd, repeat_share %zd, repeat_access %zd\n", ++ ret ? "FAILED" : "PASSED", size, obj_count, repeat_share, ++ repeat_access); ++ ++ return ret; ++} ++ ++/* ++ * Get an optional numeric argument from @buf, update @buf and return the value. ++ * If @buf does not start with ",", return @default_val instead. ++ */ ++static size_t trusty_test_get_arg(const char **buf, size_t default_val) ++{ ++ char *buf_next; ++ size_t ret; ++ ++ if (**buf != ',') ++ return default_val; ++ ++ (*buf)++; ++ ret = simple_strtoul(*buf, &buf_next, 0); ++ if (buf_next == *buf) ++ return default_val; ++ ++ *buf = buf_next; ++ ++ return ret; ++} ++ ++/* ++ * Run tests described by a string in this format: ++ * ,,, ++ */ ++static ssize_t trusty_test_run_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct trusty_test_state *s = platform_get_drvdata(pdev); ++ size_t size; ++ size_t obj_count; ++ size_t repeat_share; ++ size_t repeat_access; ++ int ret; ++ char *buf_next; ++ ++ while (true) { ++ while (isspace(*buf)) ++ buf++; ++ size = simple_strtoul(buf, &buf_next, 0); ++ if (buf_next == buf) ++ return count; ++ buf = buf_next; ++ obj_count = trusty_test_get_arg(&buf, 1); ++ repeat_share = trusty_test_get_arg(&buf, 1); ++ repeat_access = trusty_test_get_arg(&buf, 3); ++ ++ ret = trusty_test_run(s, DIV_ROUND_UP(size, PAGE_SIZE), ++ obj_count, repeat_share, repeat_access); ++ if (ret) ++ return ret; ++ } ++} ++ ++static DEVICE_ATTR_WO(trusty_test_run); ++ ++static struct attribute *trusty_test_attrs[] = { ++ &dev_attr_trusty_test_run.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(trusty_test); ++ ++static int trusty_test_probe(struct platform_device *pdev) ++{ ++ struct trusty_test_state *s; ++ int ret; ++ ++ ret = trusty_std_call32(pdev->dev.parent, SMC_SC_TEST_VERSION, ++ TRUSTY_STDCALLTEST_API_VERSION, 0, 0); ++ if (ret != TRUSTY_STDCALLTEST_API_VERSION) ++ return -ENOENT; ++ ++ s = kzalloc(sizeof(*s), GFP_KERNEL); ++ if (!s) ++ return -ENOMEM; ++ ++ s->dev = &pdev->dev; ++ s->trusty_dev = s->dev->parent; ++ ++ platform_set_drvdata(pdev, s); ++ ++ return 0; ++} ++ ++static int trusty_test_remove(struct platform_device *pdev) ++{ ++ struct trusty_log_state *s = platform_get_drvdata(pdev); ++ ++ kfree(s); ++ return 0; ++} ++ ++static const struct of_device_id trusty_test_of_match[] = { ++ { .compatible = "android,trusty-test-v1", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(trusty, trusty_test_of_match); ++ ++static struct platform_driver trusty_test_driver = { ++ .probe = trusty_test_probe, ++ .remove = trusty_test_remove, ++ .driver = { ++ .name = "trusty-test", ++ .of_match_table = trusty_test_of_match, ++ .dev_groups = trusty_test_groups, ++ }, ++}; ++ ++module_platform_driver(trusty_test_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Trusty test driver"); +diff --git a/drivers/trusty/trusty-test.h b/drivers/trusty/trusty-test.h +new file mode 100644 +index 000000000000..eea7beb96876 +--- /dev/null ++++ b/drivers/trusty/trusty-test.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (c) 2020 Google, Inc. ++ */ ++#ifndef _TRUSTY_TEST_H ++#define _TRUSTY_TEST_H ++ ++#define SMC_SC_TEST_VERSION SMC_STDCALL_NR(SMC_ENTITY_TEST, 0) ++#define SMC_SC_TEST_SHARED_MEM_RW SMC_STDCALL_NR(SMC_ENTITY_TEST, 1) ++ ++#define TRUSTY_STDCALLTEST_API_VERSION 1 ++ ++#endif /* _TRUSTY_TEST_H */ +diff --git a/drivers/trusty/trusty-virtio.c b/drivers/trusty/trusty-virtio.c +new file mode 100644 +index 000000000000..fea59cd2e218 +--- /dev/null ++++ b/drivers/trusty/trusty-virtio.c +@@ -0,0 +1,840 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Trusty Virtio driver ++ * ++ * Copyright (C) 2015 Google, Inc. ++ */ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define RSC_DESCR_VER 1 ++ ++struct trusty_vdev; ++ ++struct trusty_ctx { ++ struct device *dev; ++ void *shared_va; ++ struct scatterlist shared_sg; ++ trusty_shared_mem_id_t shared_id; ++ size_t shared_sz; ++ struct work_struct check_vqs; ++ struct work_struct kick_vqs; ++ struct notifier_block call_notifier; ++ struct list_head vdev_list; ++ struct mutex mlock; /* protects vdev_list */ ++ struct workqueue_struct *kick_wq; ++ struct workqueue_struct *check_wq; ++}; ++ ++struct trusty_vring { ++ void *vaddr; ++ struct scatterlist sg; ++ trusty_shared_mem_id_t shared_mem_id; ++ size_t size; ++ unsigned int align; ++ unsigned int elem_num; ++ u32 notifyid; ++ atomic_t needs_kick; ++ struct fw_rsc_vdev_vring *vr_descr; ++ struct virtqueue *vq; ++ struct trusty_vdev *tvdev; ++ struct trusty_nop kick_nop; ++}; ++ ++struct trusty_vdev { ++ struct list_head node; ++ struct virtio_device vdev; ++ struct trusty_ctx *tctx; ++ u32 notifyid; ++ unsigned int config_len; ++ void *config; ++ struct fw_rsc_vdev *vdev_descr; ++ unsigned int vring_num; ++ struct trusty_vring vrings[]; ++}; ++ ++#define vdev_to_tvdev(vd) container_of((vd), struct trusty_vdev, vdev) ++ ++static void check_all_vqs(struct work_struct *work) ++{ ++ unsigned int i; ++ struct trusty_ctx *tctx = container_of(work, struct trusty_ctx, ++ check_vqs); ++ struct trusty_vdev *tvdev; ++ ++ list_for_each_entry(tvdev, &tctx->vdev_list, node) { ++ for (i = 0; i < tvdev->vring_num; i++) ++ if (tvdev->vrings[i].vq) ++ vring_interrupt(0, tvdev->vrings[i].vq); ++ } ++} ++ ++static int trusty_call_notify(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct trusty_ctx *tctx; ++ ++ if (action != TRUSTY_CALL_RETURNED) ++ return NOTIFY_DONE; ++ ++ tctx = container_of(nb, struct trusty_ctx, call_notifier); ++ queue_work(tctx->check_wq, &tctx->check_vqs); ++ ++ return NOTIFY_OK; ++} ++ ++static void kick_vq(struct trusty_ctx *tctx, ++ struct trusty_vdev *tvdev, ++ struct trusty_vring *tvr) ++{ ++ int ret; ++ ++ dev_dbg(tctx->dev, "%s: vdev_id=%d: vq_id=%d\n", ++ __func__, tvdev->notifyid, tvr->notifyid); ++ ++ ret = trusty_std_call32(tctx->dev->parent, SMC_SC_VDEV_KICK_VQ, ++ tvdev->notifyid, tvr->notifyid, 0); ++ if (ret) { ++ dev_err(tctx->dev, "vq notify (%d, %d) returned %d\n", ++ tvdev->notifyid, tvr->notifyid, ret); ++ } ++} ++ ++static void kick_vqs(struct work_struct *work) ++{ ++ unsigned int i; ++ struct trusty_vdev *tvdev; ++ struct trusty_ctx *tctx = container_of(work, struct trusty_ctx, ++ kick_vqs); ++ mutex_lock(&tctx->mlock); ++ list_for_each_entry(tvdev, &tctx->vdev_list, node) { ++ for (i = 0; i < tvdev->vring_num; i++) { ++ struct trusty_vring *tvr = &tvdev->vrings[i]; ++ ++ if (atomic_xchg(&tvr->needs_kick, 0)) ++ kick_vq(tctx, tvdev, tvr); ++ } ++ } ++ mutex_unlock(&tctx->mlock); ++} ++ ++static bool trusty_virtio_notify(struct virtqueue *vq) ++{ ++ struct trusty_vring *tvr = vq->priv; ++ struct trusty_vdev *tvdev = tvr->tvdev; ++ struct trusty_ctx *tctx = tvdev->tctx; ++ u32 api_ver = trusty_get_api_version(tctx->dev->parent); ++ ++ if (api_ver < TRUSTY_API_VERSION_SMP_NOP) { ++ atomic_set(&tvr->needs_kick, 1); ++ queue_work(tctx->kick_wq, &tctx->kick_vqs); ++ } else { ++ trusty_enqueue_nop(tctx->dev->parent, &tvr->kick_nop); ++ } ++ ++ return true; ++} ++ ++static int trusty_load_device_descr(struct trusty_ctx *tctx, ++ trusty_shared_mem_id_t id, size_t sz) ++{ ++ int ret; ++ ++ dev_dbg(tctx->dev, "%s: %zu bytes @ id %llu\n", __func__, sz, id); ++ ++ ret = trusty_std_call32(tctx->dev->parent, SMC_SC_VIRTIO_GET_DESCR, ++ (u32)id, id >> 32, sz); ++ if (ret < 0) { ++ dev_err(tctx->dev, "%s: virtio get descr returned (%d)\n", ++ __func__, ret); ++ return -ENODEV; ++ } ++ return ret; ++} ++ ++static void trusty_virtio_stop(struct trusty_ctx *tctx, ++ trusty_shared_mem_id_t id, size_t sz) ++{ ++ int ret; ++ ++ dev_dbg(tctx->dev, "%s: %zu bytes @ id %llu\n", __func__, sz, id); ++ ++ ret = trusty_std_call32(tctx->dev->parent, SMC_SC_VIRTIO_STOP, ++ (u32)id, id >> 32, sz); ++ if (ret) { ++ dev_err(tctx->dev, "%s: virtio done returned (%d)\n", ++ __func__, ret); ++ return; ++ } ++} ++ ++static int trusty_virtio_start(struct trusty_ctx *tctx, ++ trusty_shared_mem_id_t id, size_t sz) ++{ ++ int ret; ++ ++ dev_dbg(tctx->dev, "%s: %zu bytes @ id %llu\n", __func__, sz, id); ++ ++ ret = trusty_std_call32(tctx->dev->parent, SMC_SC_VIRTIO_START, ++ (u32)id, id >> 32, sz); ++ if (ret) { ++ dev_err(tctx->dev, "%s: virtio start returned (%d)\n", ++ __func__, ret); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++static void trusty_virtio_reset(struct virtio_device *vdev) ++{ ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ struct trusty_ctx *tctx = tvdev->tctx; ++ ++ dev_dbg(&vdev->dev, "reset vdev_id=%d\n", tvdev->notifyid); ++ trusty_std_call32(tctx->dev->parent, SMC_SC_VDEV_RESET, ++ tvdev->notifyid, 0, 0); ++} ++ ++static u64 trusty_virtio_get_features(struct virtio_device *vdev) ++{ ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ ++ return tvdev->vdev_descr->dfeatures | ++ (1ULL << VIRTIO_F_ACCESS_PLATFORM); ++} ++ ++static int trusty_virtio_finalize_features(struct virtio_device *vdev) ++{ ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ u64 features = vdev->features; ++ ++ /* ++ * We set VIRTIO_F_ACCESS_PLATFORM to enable the dma mapping hooks. ++ * The other side does not need to know. ++ */ ++ features &= ~(1ULL << VIRTIO_F_ACCESS_PLATFORM); ++ ++ /* Make sure we don't have any features > 32 bits! */ ++ if (WARN_ON((u32)vdev->features != features)) ++ return -EINVAL; ++ ++ tvdev->vdev_descr->gfeatures = vdev->features; ++ return 0; ++} ++ ++static void trusty_virtio_get_config(struct virtio_device *vdev, ++ unsigned int offset, void *buf, ++ unsigned int len) ++{ ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ ++ dev_dbg(&vdev->dev, "%s: %d bytes @ offset %d\n", ++ __func__, len, offset); ++ ++ if (tvdev->config) { ++ if (offset + len <= tvdev->config_len) ++ memcpy(buf, tvdev->config + offset, len); ++ } ++} ++ ++static void trusty_virtio_set_config(struct virtio_device *vdev, ++ unsigned int offset, const void *buf, ++ unsigned int len) ++{ ++} ++ ++static u8 trusty_virtio_get_status(struct virtio_device *vdev) ++{ ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ ++ return tvdev->vdev_descr->status; ++} ++ ++static void trusty_virtio_set_status(struct virtio_device *vdev, u8 status) ++{ ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ ++ tvdev->vdev_descr->status = status; ++} ++ ++static void _del_vqs(struct virtio_device *vdev) ++{ ++ unsigned int i; ++ int ret; ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ struct trusty_vring *tvr = &tvdev->vrings[0]; ++ ++ for (i = 0; i < tvdev->vring_num; i++, tvr++) { ++ /* dequeue kick_nop */ ++ trusty_dequeue_nop(tvdev->tctx->dev->parent, &tvr->kick_nop); ++ ++ /* delete vq */ ++ if (tvr->vq) { ++ vring_del_virtqueue(tvr->vq); ++ tvr->vq = NULL; ++ } ++ /* delete vring */ ++ if (tvr->vaddr) { ++ ret = trusty_reclaim_memory(tvdev->tctx->dev->parent, ++ tvr->shared_mem_id, ++ &tvr->sg, 1); ++ if (WARN_ON(ret)) { ++ dev_err(&vdev->dev, ++ "trusty_revoke_memory failed: %d 0x%llx\n", ++ ret, tvr->shared_mem_id); ++ /* ++ * It is not safe to free this memory if ++ * trusty_revoke_memory fails. Leak it in that ++ * case. ++ */ ++ } else { ++ free_pages_exact(tvr->vaddr, tvr->size); ++ } ++ tvr->vaddr = NULL; ++ } ++ } ++} ++ ++static void trusty_virtio_del_vqs(struct virtio_device *vdev) ++{ ++ _del_vqs(vdev); ++} ++ ++ ++static struct virtqueue *_find_vq(struct virtio_device *vdev, ++ unsigned int id, ++ void (*callback)(struct virtqueue *vq), ++ const char *name, ++ bool ctx) ++{ ++ struct trusty_vring *tvr; ++ struct trusty_vdev *tvdev = vdev_to_tvdev(vdev); ++ phys_addr_t pa; ++ int ret; ++ ++ if (!name) ++ return ERR_PTR(-EINVAL); ++ ++ if (id >= tvdev->vring_num) ++ return ERR_PTR(-EINVAL); ++ ++ tvr = &tvdev->vrings[id]; ++ ++ /* actual size of vring (in bytes) */ ++ tvr->size = PAGE_ALIGN(vring_size(tvr->elem_num, tvr->align)); ++ ++ /* allocate memory for the vring. */ ++ tvr->vaddr = alloc_pages_exact(tvr->size, GFP_KERNEL | __GFP_ZERO); ++ if (!tvr->vaddr) { ++ dev_err(&vdev->dev, "vring alloc failed\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sg_init_one(&tvr->sg, tvr->vaddr, tvr->size); ++ ret = trusty_share_memory_compat(tvdev->tctx->dev->parent, ++ &tvr->shared_mem_id, &tvr->sg, 1, ++ PAGE_KERNEL); ++ if (ret) { ++ pa = virt_to_phys(tvr->vaddr); ++ dev_err(&vdev->dev, "trusty_share_memory failed: %d %pa\n", ++ ret, &pa); ++ goto err_share_memory; ++ } ++ ++ /* save vring address to shared structure */ ++ tvr->vr_descr->da = (u32)tvr->shared_mem_id; ++ ++ /* da field is only 32 bit wide. Use previously unused 'reserved' field ++ * to store top 32 bits of 64-bit shared_mem_id ++ */ ++ tvr->vr_descr->pa = (u32)(tvr->shared_mem_id >> 32); ++ ++ dev_info(&vdev->dev, "vring%d: va(id) %p(%llx) qsz %d notifyid %d\n", ++ id, tvr->vaddr, (u64)tvr->shared_mem_id, tvr->elem_num, ++ tvr->notifyid); ++ ++ tvr->vq = vring_new_virtqueue(id, tvr->elem_num, tvr->align, ++ vdev, true, ctx, tvr->vaddr, ++ trusty_virtio_notify, callback, name); ++ if (!tvr->vq) { ++ dev_err(&vdev->dev, "vring_new_virtqueue %s failed\n", ++ name); ++ goto err_new_virtqueue; ++ } ++ ++ tvr->vq->priv = tvr; ++ ++ return tvr->vq; ++ ++err_new_virtqueue: ++ ret = trusty_reclaim_memory(tvdev->tctx->dev->parent, ++ tvr->shared_mem_id, &tvr->sg, 1); ++ if (WARN_ON(ret)) { ++ dev_err(&vdev->dev, "trusty_revoke_memory failed: %d 0x%llx\n", ++ ret, tvr->shared_mem_id); ++ /* ++ * It is not safe to free this memory if trusty_revoke_memory ++ * fails. Leak it in that case. ++ */ ++ } else { ++err_share_memory: ++ free_pages_exact(tvr->vaddr, tvr->size); ++ } ++ tvr->vaddr = NULL; ++ return ERR_PTR(-ENOMEM); ++} ++ ++static int trusty_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, ++ struct virtqueue *vqs[], ++ vq_callback_t *callbacks[], ++ const char * const names[], ++ const bool *ctxs, ++ struct irq_affinity *desc) ++{ ++ unsigned int i; ++ int ret; ++ bool ctx = false; ++ ++ for (i = 0; i < nvqs; i++) { ++ ctx = false; ++ if (ctxs) ++ ctx = ctxs[i]; ++ vqs[i] = _find_vq(vdev, i, callbacks[i], names[i], ctx); ++ if (IS_ERR(vqs[i])) { ++ ret = PTR_ERR(vqs[i]); ++ _del_vqs(vdev); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static const char *trusty_virtio_bus_name(struct virtio_device *vdev) ++{ ++ return "trusty-virtio"; ++} ++ ++/* The ops structure which hooks everything together. */ ++static const struct virtio_config_ops trusty_virtio_config_ops = { ++ .get_features = trusty_virtio_get_features, ++ .finalize_features = trusty_virtio_finalize_features, ++ .get = trusty_virtio_get_config, ++ .set = trusty_virtio_set_config, ++ .get_status = trusty_virtio_get_status, ++ .set_status = trusty_virtio_set_status, ++ .reset = trusty_virtio_reset, ++ .find_vqs = trusty_virtio_find_vqs, ++ .del_vqs = trusty_virtio_del_vqs, ++ .bus_name = trusty_virtio_bus_name, ++}; ++ ++static int trusty_virtio_add_device(struct trusty_ctx *tctx, ++ struct fw_rsc_vdev *vdev_descr, ++ struct fw_rsc_vdev_vring *vr_descr, ++ void *config) ++{ ++ int i, ret; ++ struct trusty_vdev *tvdev; ++ ++ tvdev = kzalloc(struct_size(tvdev, vrings, vdev_descr->num_of_vrings), ++ GFP_KERNEL); ++ if (!tvdev) ++ return -ENOMEM; ++ ++ /* setup vdev */ ++ tvdev->tctx = tctx; ++ tvdev->vdev.dev.parent = tctx->dev; ++ tvdev->vdev.id.device = vdev_descr->id; ++ tvdev->vdev.config = &trusty_virtio_config_ops; ++ tvdev->vdev_descr = vdev_descr; ++ tvdev->notifyid = vdev_descr->notifyid; ++ ++ /* setup config */ ++ tvdev->config = config; ++ tvdev->config_len = vdev_descr->config_len; ++ ++ /* setup vrings and vdev resource */ ++ tvdev->vring_num = vdev_descr->num_of_vrings; ++ ++ for (i = 0; i < tvdev->vring_num; i++, vr_descr++) { ++ struct trusty_vring *tvr = &tvdev->vrings[i]; ++ ++ tvr->tvdev = tvdev; ++ tvr->vr_descr = vr_descr; ++ tvr->align = vr_descr->align; ++ tvr->elem_num = vr_descr->num; ++ tvr->notifyid = vr_descr->notifyid; ++ trusty_nop_init(&tvr->kick_nop, SMC_NC_VDEV_KICK_VQ, ++ tvdev->notifyid, tvr->notifyid); ++ } ++ ++ /* register device */ ++ ret = register_virtio_device(&tvdev->vdev); ++ if (ret) { ++ dev_err(tctx->dev, ++ "Failed (%d) to register device dev type %u\n", ++ ret, vdev_descr->id); ++ goto err_register; ++ } ++ ++ /* add it to tracking list */ ++ list_add_tail(&tvdev->node, &tctx->vdev_list); ++ ++ return 0; ++ ++err_register: ++ kfree(tvdev); ++ return ret; ++} ++ ++static int trusty_parse_device_descr(struct trusty_ctx *tctx, ++ void *descr_va, size_t descr_sz) ++{ ++ u32 i; ++ struct resource_table *descr = descr_va; ++ ++ if (descr_sz < sizeof(*descr)) { ++ dev_err(tctx->dev, "descr table is too small (0x%x)\n", ++ (int)descr_sz); ++ return -ENODEV; ++ } ++ ++ if (descr->ver != RSC_DESCR_VER) { ++ dev_err(tctx->dev, "unexpected descr ver (0x%x)\n", ++ (int)descr->ver); ++ return -ENODEV; ++ } ++ ++ if (descr_sz < (sizeof(*descr) + descr->num * sizeof(u32))) { ++ dev_err(tctx->dev, "descr table is too small (0x%x)\n", ++ (int)descr->ver); ++ return -ENODEV; ++ } ++ ++ for (i = 0; i < descr->num; i++) { ++ struct fw_rsc_hdr *hdr; ++ struct fw_rsc_vdev *vd; ++ struct fw_rsc_vdev_vring *vr; ++ void *cfg; ++ size_t vd_sz; ++ ++ u32 offset = descr->offset[i]; ++ ++ if (offset >= descr_sz) { ++ dev_err(tctx->dev, "offset is out of bounds (%u)\n", ++ offset); ++ return -ENODEV; ++ } ++ ++ /* check space for rsc header */ ++ if ((descr_sz - offset) < sizeof(struct fw_rsc_hdr)) { ++ dev_err(tctx->dev, "no space for rsc header (%u)\n", ++ offset); ++ return -ENODEV; ++ } ++ hdr = (struct fw_rsc_hdr *)((u8 *)descr + offset); ++ offset += sizeof(struct fw_rsc_hdr); ++ ++ /* check type */ ++ if (hdr->type != RSC_VDEV) { ++ dev_err(tctx->dev, "unsupported rsc type (%u)\n", ++ hdr->type); ++ continue; ++ } ++ ++ /* got vdev: check space for vdev */ ++ if ((descr_sz - offset) < sizeof(struct fw_rsc_vdev)) { ++ dev_err(tctx->dev, "no space for vdev descr (%u)\n", ++ offset); ++ return -ENODEV; ++ } ++ vd = (struct fw_rsc_vdev *)((u8 *)descr + offset); ++ ++ /* check space for vrings and config area */ ++ vd_sz = sizeof(struct fw_rsc_vdev) + ++ vd->num_of_vrings * sizeof(struct fw_rsc_vdev_vring) + ++ vd->config_len; ++ ++ if ((descr_sz - offset) < vd_sz) { ++ dev_err(tctx->dev, "no space for vdev (%u)\n", offset); ++ return -ENODEV; ++ } ++ vr = (struct fw_rsc_vdev_vring *)vd->vring; ++ cfg = (void *)(vr + vd->num_of_vrings); ++ ++ trusty_virtio_add_device(tctx, vd, vr, cfg); ++ } ++ ++ return 0; ++} ++ ++static void _remove_devices_locked(struct trusty_ctx *tctx) ++{ ++ struct trusty_vdev *tvdev, *next; ++ ++ list_for_each_entry_safe(tvdev, next, &tctx->vdev_list, node) { ++ list_del(&tvdev->node); ++ unregister_virtio_device(&tvdev->vdev); ++ kfree(tvdev); ++ } ++} ++ ++static void trusty_virtio_remove_devices(struct trusty_ctx *tctx) ++{ ++ mutex_lock(&tctx->mlock); ++ _remove_devices_locked(tctx); ++ mutex_unlock(&tctx->mlock); ++} ++ ++static int trusty_virtio_add_devices(struct trusty_ctx *tctx) ++{ ++ int ret; ++ int ret_tmp; ++ void *descr_va; ++ trusty_shared_mem_id_t descr_id; ++ size_t descr_sz; ++ size_t descr_buf_sz; ++ ++ /* allocate buffer to load device descriptor into */ ++ descr_buf_sz = PAGE_SIZE; ++ descr_va = alloc_pages_exact(descr_buf_sz, GFP_KERNEL | __GFP_ZERO); ++ if (!descr_va) { ++ dev_err(tctx->dev, "Failed to allocate shared area\n"); ++ return -ENOMEM; ++ } ++ ++ sg_init_one(&tctx->shared_sg, descr_va, descr_buf_sz); ++ ret = trusty_share_memory(tctx->dev->parent, &descr_id, ++ &tctx->shared_sg, 1, PAGE_KERNEL); ++ if (ret) { ++ dev_err(tctx->dev, "trusty_share_memory failed: %d\n", ret); ++ goto err_share_memory; ++ } ++ ++ /* load device descriptors */ ++ ret = trusty_load_device_descr(tctx, descr_id, descr_buf_sz); ++ if (ret < 0) { ++ dev_err(tctx->dev, "failed (%d) to load device descr\n", ret); ++ goto err_load_descr; ++ } ++ ++ descr_sz = (size_t)ret; ++ ++ mutex_lock(&tctx->mlock); ++ ++ /* parse device descriptor and add virtio devices */ ++ ret = trusty_parse_device_descr(tctx, descr_va, descr_sz); ++ if (ret) { ++ dev_err(tctx->dev, "failed (%d) to parse device descr\n", ret); ++ goto err_parse_descr; ++ } ++ ++ /* register call notifier */ ++ ret = trusty_call_notifier_register(tctx->dev->parent, ++ &tctx->call_notifier); ++ if (ret) { ++ dev_err(tctx->dev, "%s: failed (%d) to register notifier\n", ++ __func__, ret); ++ goto err_register_notifier; ++ } ++ ++ /* start virtio */ ++ ret = trusty_virtio_start(tctx, descr_id, descr_sz); ++ if (ret) { ++ dev_err(tctx->dev, "failed (%d) to start virtio\n", ret); ++ goto err_start_virtio; ++ } ++ ++ /* attach shared area */ ++ tctx->shared_va = descr_va; ++ tctx->shared_id = descr_id; ++ tctx->shared_sz = descr_buf_sz; ++ ++ mutex_unlock(&tctx->mlock); ++ ++ return 0; ++ ++err_start_virtio: ++ trusty_call_notifier_unregister(tctx->dev->parent, ++ &tctx->call_notifier); ++ cancel_work_sync(&tctx->check_vqs); ++err_register_notifier: ++err_parse_descr: ++ _remove_devices_locked(tctx); ++ mutex_unlock(&tctx->mlock); ++ cancel_work_sync(&tctx->kick_vqs); ++ trusty_virtio_stop(tctx, descr_id, descr_sz); ++err_load_descr: ++ ret_tmp = trusty_reclaim_memory(tctx->dev->parent, descr_id, ++ &tctx->shared_sg, 1); ++ if (WARN_ON(ret_tmp)) { ++ dev_err(tctx->dev, "trusty_revoke_memory failed: %d 0x%llx\n", ++ ret_tmp, tctx->shared_id); ++ /* ++ * It is not safe to free this memory if trusty_revoke_memory ++ * fails. Leak it in that case. ++ */ ++ } else { ++err_share_memory: ++ free_pages_exact(descr_va, descr_buf_sz); ++ } ++ return ret; ++} ++ ++static dma_addr_t trusty_virtio_dma_map_page(struct device *dev, ++ struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction dir, ++ unsigned long attrs) ++{ ++ struct tipc_msg_buf *buf = page_to_virt(page) + offset; ++ ++ return buf->buf_id; ++} ++ ++static const struct dma_map_ops trusty_virtio_dma_map_ops = { ++ .map_page = trusty_virtio_dma_map_page, ++}; ++ ++static int trusty_virtio_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct trusty_ctx *tctx; ++ ++ tctx = kzalloc(sizeof(*tctx), GFP_KERNEL); ++ if (!tctx) ++ return -ENOMEM; ++ ++ tctx->dev = &pdev->dev; ++ tctx->call_notifier.notifier_call = trusty_call_notify; ++ mutex_init(&tctx->mlock); ++ INIT_LIST_HEAD(&tctx->vdev_list); ++ INIT_WORK(&tctx->check_vqs, check_all_vqs); ++ INIT_WORK(&tctx->kick_vqs, kick_vqs); ++ platform_set_drvdata(pdev, tctx); ++ ++ set_dma_ops(&pdev->dev, &trusty_virtio_dma_map_ops); ++ ++ tctx->check_wq = alloc_workqueue("trusty-check-wq", WQ_UNBOUND, 0); ++ if (!tctx->check_wq) { ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "Failed create trusty-check-wq\n"); ++ goto err_create_check_wq; ++ } ++ ++ tctx->kick_wq = alloc_workqueue("trusty-kick-wq", ++ WQ_UNBOUND | WQ_CPU_INTENSIVE, 0); ++ if (!tctx->kick_wq) { ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "Failed create trusty-kick-wq\n"); ++ goto err_create_kick_wq; ++ } ++ ++ ret = trusty_virtio_add_devices(tctx); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to add virtio devices\n"); ++ goto err_add_devices; ++ } ++ ++ dev_info(&pdev->dev, "initializing done\n"); ++ return 0; ++ ++err_add_devices: ++ destroy_workqueue(tctx->kick_wq); ++err_create_kick_wq: ++ destroy_workqueue(tctx->check_wq); ++err_create_check_wq: ++ kfree(tctx); ++ return ret; ++} ++ ++static int trusty_virtio_remove(struct platform_device *pdev) ++{ ++ struct trusty_ctx *tctx = platform_get_drvdata(pdev); ++ int ret; ++ ++ /* unregister call notifier and wait until workqueue is done */ ++ trusty_call_notifier_unregister(tctx->dev->parent, ++ &tctx->call_notifier); ++ cancel_work_sync(&tctx->check_vqs); ++ ++ /* remove virtio devices */ ++ trusty_virtio_remove_devices(tctx); ++ cancel_work_sync(&tctx->kick_vqs); ++ ++ /* destroy workqueues */ ++ destroy_workqueue(tctx->kick_wq); ++ destroy_workqueue(tctx->check_wq); ++ ++ /* notify remote that shared area goes away */ ++ trusty_virtio_stop(tctx, tctx->shared_id, tctx->shared_sz); ++ ++ /* free shared area */ ++ ret = trusty_reclaim_memory(tctx->dev->parent, tctx->shared_id, ++ &tctx->shared_sg, 1); ++ if (WARN_ON(ret)) { ++ dev_err(tctx->dev, "trusty_revoke_memory failed: %d 0x%llx\n", ++ ret, tctx->shared_id); ++ /* ++ * It is not safe to free this memory if trusty_revoke_memory ++ * fails. Leak it in that case. ++ */ ++ } else { ++ free_pages_exact(tctx->shared_va, tctx->shared_sz); ++ } ++ ++ /* free context */ ++ kfree(tctx); ++ return 0; ++} ++ ++static const struct of_device_id trusty_of_match[] = { ++ { ++ .compatible = "android,trusty-virtio-v1", ++ }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, trusty_of_match); ++ ++static struct platform_driver trusty_virtio_driver = { ++ .probe = trusty_virtio_probe, ++ .remove = trusty_virtio_remove, ++ .driver = { ++ .name = "trusty-virtio", ++ .of_match_table = trusty_of_match, ++ }, ++}; ++ ++module_platform_driver(trusty_virtio_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Trusty virtio driver"); ++/* ++ * TODO(b/168322325): trusty-virtio and trusty-ipc should be independent. ++ * However, trusty-virtio is not completely generic and is aware of trusty-ipc. ++ * See header includes. Particularly, trusty-virtio.ko can't be loaded before ++ * trusty-ipc.ko. ++ */ ++MODULE_SOFTDEP("pre: trusty-ipc"); +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +new file mode 100644 +index 000000000000..265eab52aea0 +--- /dev/null ++++ b/drivers/trusty/trusty.c +@@ -0,0 +1,981 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2013 Google, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "trusty-smc.h" ++ ++struct trusty_state; ++static struct platform_driver trusty_driver; ++ ++struct trusty_work { ++ struct trusty_state *ts; ++ struct work_struct work; ++}; ++ ++struct trusty_state { ++ struct mutex smc_lock; ++ struct atomic_notifier_head notifier; ++ struct completion cpu_idle_completion; ++ char *version_str; ++ u32 api_version; ++ bool trusty_panicked; ++ struct device *dev; ++ struct workqueue_struct *nop_wq; ++ struct trusty_work __percpu *nop_works; ++ struct list_head nop_queue; ++ spinlock_t nop_lock; /* protects nop_queue */ ++ struct device_dma_parameters dma_parms; ++ void *ffa_tx; ++ void *ffa_rx; ++ u16 ffa_local_id; ++ u16 ffa_remote_id; ++ struct mutex share_memory_msg_lock; /* protects share_memory_msg */ ++}; ++ ++static inline unsigned long smc(unsigned long r0, unsigned long r1, ++ unsigned long r2, unsigned long r3) ++{ ++ return trusty_smc8(r0, r1, r2, r3, 0, 0, 0, 0).r0; ++} ++ ++s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (WARN_ON(!s)) ++ return SM_ERR_INVALID_PARAMETERS; ++ if (WARN_ON(!SMC_IS_FASTCALL(smcnr))) ++ return SM_ERR_INVALID_PARAMETERS; ++ if (WARN_ON(SMC_IS_SMC64(smcnr))) ++ return SM_ERR_INVALID_PARAMETERS; ++ ++ return smc(smcnr, a0, a1, a2); ++} ++EXPORT_SYMBOL(trusty_fast_call32); ++ ++#ifdef CONFIG_64BIT ++s64 trusty_fast_call64(struct device *dev, u64 smcnr, u64 a0, u64 a1, u64 a2) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (WARN_ON(!s)) ++ return SM_ERR_INVALID_PARAMETERS; ++ if (WARN_ON(!SMC_IS_FASTCALL(smcnr))) ++ return SM_ERR_INVALID_PARAMETERS; ++ if (WARN_ON(!SMC_IS_SMC64(smcnr))) ++ return SM_ERR_INVALID_PARAMETERS; ++ ++ return smc(smcnr, a0, a1, a2); ++} ++EXPORT_SYMBOL(trusty_fast_call64); ++#endif ++ ++static unsigned long trusty_std_call_inner(struct device *dev, ++ unsigned long smcnr, ++ unsigned long a0, unsigned long a1, ++ unsigned long a2) ++{ ++ unsigned long ret; ++ int retry = 5; ++ ++ dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx)\n", ++ __func__, smcnr, a0, a1, a2); ++ while (true) { ++ ret = smc(smcnr, a0, a1, a2); ++ while ((s32)ret == SM_ERR_FIQ_INTERRUPTED) ++ ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0); ++ if ((int)ret != SM_ERR_BUSY || !retry) ++ break; ++ ++ dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, retry\n", ++ __func__, smcnr, a0, a1, a2); ++ retry--; ++ } ++ ++ return ret; ++} ++ ++static unsigned long trusty_std_call_helper(struct device *dev, ++ unsigned long smcnr, ++ unsigned long a0, unsigned long a1, ++ unsigned long a2) ++{ ++ unsigned long ret; ++ int sleep_time = 1; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ while (true) { ++ local_irq_disable(); ++ atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_PREPARE, ++ NULL); ++ ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2); ++ if (ret == SM_ERR_PANIC) { ++ s->trusty_panicked = true; ++ if (IS_ENABLED(CONFIG_TRUSTY_CRASH_IS_PANIC)) ++ panic("trusty crashed"); ++ else ++ WARN_ONCE(1, "trusty crashed"); ++ } ++ ++ atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_RETURNED, ++ NULL); ++ if (ret == SM_ERR_INTERRUPTED) { ++ /* ++ * Make sure this cpu will eventually re-enter trusty ++ * even if the std_call resumes on another cpu. ++ */ ++ trusty_enqueue_nop(dev, NULL); ++ } ++ local_irq_enable(); ++ ++ if ((int)ret != SM_ERR_BUSY) ++ break; ++ ++ if (sleep_time == 256) ++ dev_warn(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy\n", ++ __func__, smcnr, a0, a1, a2); ++ dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, wait %d ms\n", ++ __func__, smcnr, a0, a1, a2, sleep_time); ++ ++ msleep(sleep_time); ++ if (sleep_time < 1000) ++ sleep_time <<= 1; ++ ++ dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) retry\n", ++ __func__, smcnr, a0, a1, a2); ++ } ++ ++ if (sleep_time > 256) ++ dev_warn(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) busy cleared\n", ++ __func__, smcnr, a0, a1, a2); ++ ++ return ret; ++} ++ ++static void trusty_std_call_cpu_idle(struct trusty_state *s) ++{ ++ int ret; ++ ++ ret = wait_for_completion_timeout(&s->cpu_idle_completion, HZ * 10); ++ if (!ret) { ++ dev_warn(s->dev, ++ "%s: timed out waiting for cpu idle to clear, retry anyway\n", ++ __func__); ++ } ++} ++ ++s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2) ++{ ++ int ret; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (WARN_ON(SMC_IS_FASTCALL(smcnr))) ++ return SM_ERR_INVALID_PARAMETERS; ++ ++ if (WARN_ON(SMC_IS_SMC64(smcnr))) ++ return SM_ERR_INVALID_PARAMETERS; ++ ++ if (s->trusty_panicked) { ++ /* ++ * Avoid calling the notifiers if trusty has panicked as they ++ * can trigger more calls. ++ */ ++ return SM_ERR_PANIC; ++ } ++ ++ if (smcnr != SMC_SC_NOP) { ++ mutex_lock(&s->smc_lock); ++ reinit_completion(&s->cpu_idle_completion); ++ } ++ ++ dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) started\n", ++ __func__, smcnr, a0, a1, a2); ++ ++ ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2); ++ while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) { ++ dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) interrupted\n", ++ __func__, smcnr, a0, a1, a2); ++ if (ret == SM_ERR_CPU_IDLE) ++ trusty_std_call_cpu_idle(s); ++ ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0); ++ } ++ dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n", ++ __func__, smcnr, a0, a1, a2, ret); ++ ++ if (smcnr == SMC_SC_NOP) ++ complete(&s->cpu_idle_completion); ++ else ++ mutex_unlock(&s->smc_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(trusty_std_call32); ++ ++int trusty_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot) ++{ ++ return trusty_transfer_memory(dev, id, sglist, nents, pgprot, 0, ++ false); ++} ++EXPORT_SYMBOL(trusty_share_memory); ++ ++int trusty_transfer_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag, bool lend) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ int ret; ++ struct ns_mem_page_info pg_inf; ++ struct scatterlist *sg; ++ size_t count; ++ size_t i; ++ size_t len; ++ u64 ffa_handle = 0; ++ size_t total_len; ++ size_t endpoint_count = 1; ++ struct ffa_mtd *mtd = s->ffa_tx; ++ size_t comp_mrd_offset = offsetof(struct ffa_mtd, emad[endpoint_count]); ++ struct ffa_comp_mrd *comp_mrd = s->ffa_tx + comp_mrd_offset; ++ struct ffa_cons_mrd *cons_mrd = comp_mrd->address_range_array; ++ size_t cons_mrd_offset = (void *)cons_mrd - s->ffa_tx; ++ struct smc_ret8 smc_ret; ++ u32 cookie_low; ++ u32 cookie_high; ++ ++ if (WARN_ON(dev->driver != &trusty_driver.driver)) ++ return -EINVAL; ++ ++ if (WARN_ON(nents < 1)) ++ return -EINVAL; ++ ++ if (nents != 1 && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { ++ dev_err(s->dev, "%s: old trusty version does not support non-contiguous memory objects\n", ++ __func__); ++ return -EOPNOTSUPP; ++ } ++ ++ count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ if (count != nents) { ++ dev_err(s->dev, "failed to dma map sg_table\n"); ++ return -EINVAL; ++ } ++ ++ sg = sglist; ++ ret = trusty_encode_page_info(&pg_inf, phys_to_page(sg_dma_address(sg)), ++ pgprot); ++ if (ret) { ++ dev_err(s->dev, "%s: trusty_encode_page_info failed\n", ++ __func__); ++ goto err_encode_page_info; ++ } ++ ++ if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { ++ *id = pg_inf.compat_attr; ++ return 0; ++ } ++ ++ len = 0; ++ for_each_sg(sglist, sg, nents, i) ++ len += sg_dma_len(sg); ++ ++ mutex_lock(&s->share_memory_msg_lock); ++ ++ mtd->sender_id = s->ffa_local_id; ++ mtd->memory_region_attributes = pg_inf.ffa_mem_attr; ++ mtd->reserved_3 = 0; ++ mtd->flags = 0; ++ mtd->handle = 0; ++ mtd->tag = tag; ++ mtd->reserved_24_27 = 0; ++ mtd->emad_count = endpoint_count; ++ for (i = 0; i < endpoint_count; i++) { ++ struct ffa_emad *emad = &mtd->emad[i]; ++ /* TODO: support stream ids */ ++ emad->mapd.endpoint_id = s->ffa_remote_id; ++ emad->mapd.memory_access_permissions = pg_inf.ffa_mem_perm; ++ emad->mapd.flags = 0; ++ emad->comp_mrd_offset = comp_mrd_offset; ++ emad->reserved_8_15 = 0; ++ } ++ comp_mrd->total_page_count = len / PAGE_SIZE; ++ comp_mrd->address_range_count = nents; ++ comp_mrd->reserved_8_15 = 0; ++ ++ total_len = cons_mrd_offset + nents * sizeof(*cons_mrd); ++ sg = sglist; ++ while (count) { ++ size_t lcount = ++ min_t(size_t, count, (PAGE_SIZE - cons_mrd_offset) / ++ sizeof(*cons_mrd)); ++ size_t fragment_len = lcount * sizeof(*cons_mrd) + ++ cons_mrd_offset; ++ ++ for (i = 0; i < lcount; i++) { ++ cons_mrd[i].address = sg_dma_address(sg); ++ cons_mrd[i].page_count = sg_dma_len(sg) / PAGE_SIZE; ++ cons_mrd[i].reserved_12_15 = 0; ++ sg = sg_next(sg); ++ } ++ count -= lcount; ++ if (cons_mrd_offset) { ++ u32 smc = lend ? SMC_FC_FFA_MEM_LEND : ++ SMC_FC_FFA_MEM_SHARE; ++ /* First fragment */ ++ smc_ret = trusty_smc8(smc, total_len, ++ fragment_len, 0, 0, 0, 0, 0); ++ } else { ++ smc_ret = trusty_smc8(SMC_FC_FFA_MEM_FRAG_TX, ++ cookie_low, cookie_high, ++ fragment_len, 0, 0, 0, 0); ++ } ++ if (smc_ret.r0 == SMC_FC_FFA_MEM_FRAG_RX) { ++ cookie_low = smc_ret.r1; ++ cookie_high = smc_ret.r2; ++ dev_dbg(s->dev, "cookie %x %x", cookie_low, ++ cookie_high); ++ if (!count) { ++ /* ++ * We have sent all our descriptors. Expected ++ * SMC_FC_FFA_SUCCESS, not a request to send ++ * another fragment. ++ */ ++ dev_err(s->dev, "%s: fragment_len %zd/%zd, unexpected SMC_FC_FFA_MEM_FRAG_RX\n", ++ __func__, fragment_len, total_len); ++ ret = -EIO; ++ break; ++ } ++ } else if (smc_ret.r0 == SMC_FC_FFA_SUCCESS) { ++ ffa_handle = smc_ret.r2 | (u64)smc_ret.r3 << 32; ++ dev_dbg(s->dev, "%s: fragment_len %zu/%zu, got handle 0x%llx\n", ++ __func__, fragment_len, total_len, ++ ffa_handle); ++ if (count) { ++ /* ++ * We have not sent all our descriptors. ++ * Expected SMC_FC_FFA_MEM_FRAG_RX not ++ * SMC_FC_FFA_SUCCESS. ++ */ ++ dev_err(s->dev, "%s: fragment_len %zu/%zu, unexpected SMC_FC_FFA_SUCCESS, count %zu != 0\n", ++ __func__, fragment_len, total_len, ++ count); ++ ret = -EIO; ++ break; ++ } ++ } else { ++ dev_err(s->dev, "%s: fragment_len %zu/%zu, SMC_FC_FFA_MEM_SHARE failed 0x%lx 0x%lx 0x%lx", ++ __func__, fragment_len, total_len, ++ smc_ret.r0, smc_ret.r1, smc_ret.r2); ++ ret = -EIO; ++ break; ++ } ++ ++ cons_mrd = s->ffa_tx; ++ cons_mrd_offset = 0; ++ } ++ ++ mutex_unlock(&s->share_memory_msg_lock); ++ ++ if (!ret) { ++ *id = ffa_handle; ++ dev_dbg(s->dev, "%s: done\n", __func__); ++ return 0; ++ } ++ ++ dev_err(s->dev, "%s: failed %d", __func__, ret); ++ ++err_encode_page_info: ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ return ret; ++} ++EXPORT_SYMBOL(trusty_transfer_memory); ++ ++/* ++ * trusty_share_memory_compat - trusty_share_memory wrapper for old apis ++ * ++ * Call trusty_share_memory and filter out memory attributes if trusty version ++ * is old. Used by clients that used to pass just a physical address to trusty ++ * instead of a physical address plus memory attributes value. ++ */ ++int trusty_share_memory_compat(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot) ++{ ++ int ret; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ ret = trusty_share_memory(dev, id, sglist, nents, pgprot); ++ if (!ret && s->api_version < TRUSTY_API_VERSION_PHYS_MEM_OBJ) ++ *id &= 0x0000FFFFFFFFF000ull; ++ ++ return ret; ++} ++EXPORT_SYMBOL(trusty_share_memory_compat); ++ ++int trusty_reclaim_memory(struct device *dev, u64 id, ++ struct scatterlist *sglist, unsigned int nents) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ int ret = 0; ++ struct smc_ret8 smc_ret; ++ ++ if (WARN_ON(dev->driver != &trusty_driver.driver)) ++ return -EINVAL; ++ ++ if (WARN_ON(nents < 1)) ++ return -EINVAL; ++ ++ if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { ++ if (nents != 1) { ++ dev_err(s->dev, "%s: not supported\n", __func__); ++ return -EOPNOTSUPP; ++ } ++ ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ ++ dev_dbg(s->dev, "%s: done\n", __func__); ++ return 0; ++ } ++ ++ mutex_lock(&s->share_memory_msg_lock); ++ ++ smc_ret = trusty_smc8(SMC_FC_FFA_MEM_RECLAIM, (u32)id, id >> 32, 0, 0, ++ 0, 0, 0); ++ if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { ++ dev_err(s->dev, "%s: SMC_FC_FFA_MEM_RECLAIM failed 0x%lx 0x%lx 0x%lx", ++ __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); ++ if (smc_ret.r0 == SMC_FC_FFA_ERROR && ++ smc_ret.r2 == FFA_ERROR_DENIED) ++ ret = -EBUSY; ++ else ++ ret = -EIO; ++ } ++ ++ mutex_unlock(&s->share_memory_msg_lock); ++ ++ if (ret != 0) ++ return ret; ++ ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ ++ dev_dbg(s->dev, "%s: done\n", __func__); ++ return 0; ++} ++EXPORT_SYMBOL(trusty_reclaim_memory); ++ ++int trusty_call_notifier_register(struct device *dev, struct notifier_block *n) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ return atomic_notifier_chain_register(&s->notifier, n); ++} ++EXPORT_SYMBOL(trusty_call_notifier_register); ++ ++int trusty_call_notifier_unregister(struct device *dev, ++ struct notifier_block *n) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ return atomic_notifier_chain_unregister(&s->notifier, n); ++} ++EXPORT_SYMBOL(trusty_call_notifier_unregister); ++ ++static int trusty_remove_child(struct device *dev, void *data) ++{ ++ platform_device_unregister(to_platform_device(dev)); ++ return 0; ++} ++ ++static ssize_t trusty_version_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ return scnprintf(buf, PAGE_SIZE, "%s\n", s->version_str ?: "unknown"); ++} ++ ++static DEVICE_ATTR(trusty_version, 0400, trusty_version_show, NULL); ++ ++static struct attribute *trusty_attrs[] = { ++ &dev_attr_trusty_version.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(trusty); ++ ++const char *trusty_version_str_get(struct device *dev) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ return s->version_str; ++} ++EXPORT_SYMBOL(trusty_version_str_get); ++ ++static int trusty_init_msg_buf(struct trusty_state *s, struct device *dev) ++{ ++ phys_addr_t tx_paddr; ++ phys_addr_t rx_paddr; ++ int ret; ++ struct smc_ret8 smc_ret; ++ ++ if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) ++ return 0; ++ ++ /* Get supported FF-A version and check if it is compatible */ ++ smc_ret = trusty_smc8(SMC_FC_FFA_VERSION, FFA_CURRENT_VERSION, 0, 0, ++ 0, 0, 0, 0); ++ if (FFA_VERSION_TO_MAJOR(smc_ret.r0) != FFA_CURRENT_VERSION_MAJOR) { ++ dev_err(s->dev, ++ "%s: Unsupported FF-A version 0x%lx, expected 0x%x\n", ++ __func__, smc_ret.r0, FFA_CURRENT_VERSION); ++ ret = -EIO; ++ goto err_version; ++ } ++ ++ /* Check that SMC_FC_FFA_MEM_SHARE is implemented */ ++ smc_ret = trusty_smc8(SMC_FC_FFA_FEATURES, SMC_FC_FFA_MEM_SHARE, 0, 0, ++ 0, 0, 0, 0); ++ if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { ++ dev_err(s->dev, ++ "%s: SMC_FC_FFA_FEATURES(SMC_FC_FFA_MEM_SHARE) failed 0x%lx 0x%lx 0x%lx\n", ++ __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); ++ ret = -EIO; ++ goto err_features; ++ } ++ ++ /* ++ * Set FF-A endpoint IDs. ++ * ++ * Hardcode 0x8000 for the secure os. ++ * TODO: Use FF-A call or device tree to configure this dynamically ++ */ ++ smc_ret = trusty_smc8(SMC_FC_FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0); ++ if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { ++ dev_err(s->dev, ++ "%s: SMC_FC_FFA_ID_GET failed 0x%lx 0x%lx 0x%lx\n", ++ __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); ++ ret = -EIO; ++ goto err_id_get; ++ } ++ ++ s->ffa_local_id = smc_ret.r2; ++ s->ffa_remote_id = 0x8000; ++ ++ s->ffa_tx = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ if (!s->ffa_tx) { ++ ret = -ENOMEM; ++ goto err_alloc_tx; ++ } ++ tx_paddr = virt_to_phys(s->ffa_tx); ++ if (WARN_ON(tx_paddr & (PAGE_SIZE - 1))) { ++ ret = -EINVAL; ++ goto err_unaligned_tx_buf; ++ } ++ ++ s->ffa_rx = kmalloc(PAGE_SIZE, GFP_KERNEL); ++ if (!s->ffa_rx) { ++ ret = -ENOMEM; ++ goto err_alloc_rx; ++ } ++ rx_paddr = virt_to_phys(s->ffa_rx); ++ if (WARN_ON(rx_paddr & (PAGE_SIZE - 1))) { ++ ret = -EINVAL; ++ goto err_unaligned_rx_buf; ++ } ++ ++ smc_ret = trusty_smc8(SMC_FCZ_FFA_RXTX_MAP, tx_paddr, rx_paddr, 1, 0, ++ 0, 0, 0); ++ if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { ++ dev_err(s->dev, "%s: SMC_FCZ_FFA_RXTX_MAP failed 0x%lx 0x%lx 0x%lx\n", ++ __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); ++ ret = -EIO; ++ goto err_rxtx_map; ++ } ++ ++ return 0; ++ ++err_rxtx_map: ++err_unaligned_rx_buf: ++ kfree(s->ffa_rx); ++ s->ffa_rx = NULL; ++err_alloc_rx: ++err_unaligned_tx_buf: ++ kfree(s->ffa_tx); ++ s->ffa_tx = NULL; ++err_alloc_tx: ++err_id_get: ++err_features: ++err_version: ++ return ret; ++} ++ ++static void trusty_free_msg_buf(struct trusty_state *s, struct device *dev) ++{ ++ struct smc_ret8 smc_ret; ++ ++ smc_ret = trusty_smc8(SMC_FC_FFA_RXTX_UNMAP, 0, 0, 0, 0, 0, 0, 0); ++ if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { ++ dev_err(s->dev, "%s: SMC_FC_FFA_RXTX_UNMAP failed 0x%lx 0x%lx 0x%lx\n", ++ __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); ++ } else { ++ kfree(s->ffa_rx); ++ kfree(s->ffa_tx); ++ } ++} ++ ++static void trusty_init_version(struct trusty_state *s, struct device *dev) ++{ ++ int ret; ++ int i; ++ int version_str_len; ++ ++ ret = trusty_fast_call32(dev, SMC_FC_GET_VERSION_STR, -1, 0, 0); ++ if (ret <= 0) ++ goto err_get_size; ++ ++ version_str_len = ret; ++ ++ s->version_str = kmalloc(version_str_len + 1, GFP_KERNEL); ++ for (i = 0; i < version_str_len; i++) { ++ ret = trusty_fast_call32(dev, SMC_FC_GET_VERSION_STR, i, 0, 0); ++ if (ret < 0) ++ goto err_get_char; ++ s->version_str[i] = ret; ++ } ++ s->version_str[i] = '\0'; ++ ++ dev_info(dev, "trusty version: %s\n", s->version_str); ++ return; ++ ++err_get_char: ++ kfree(s->version_str); ++ s->version_str = NULL; ++err_get_size: ++ dev_err(dev, "failed to get version: %d\n", ret); ++} ++ ++u32 trusty_get_api_version(struct device *dev) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ return s->api_version; ++} ++EXPORT_SYMBOL(trusty_get_api_version); ++ ++bool trusty_get_panic_status(struct device *dev) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ if (WARN_ON(dev->driver != &trusty_driver.driver)) ++ return false; ++ return s->trusty_panicked; ++} ++EXPORT_SYMBOL(trusty_get_panic_status); ++ ++static int trusty_init_api_version(struct trusty_state *s, struct device *dev) ++{ ++ u32 api_version; ++ ++ api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION, ++ TRUSTY_API_VERSION_CURRENT, 0, 0); ++ if (api_version == SM_ERR_UNDEFINED_SMC) ++ api_version = 0; ++ ++ if (api_version > TRUSTY_API_VERSION_CURRENT) { ++ dev_err(dev, "unsupported api version %u > %u\n", ++ api_version, TRUSTY_API_VERSION_CURRENT); ++ return -EINVAL; ++ } ++ ++ dev_info(dev, "selected api version: %u (requested %u)\n", ++ api_version, TRUSTY_API_VERSION_CURRENT); ++ s->api_version = api_version; ++ ++ return 0; ++} ++ ++static bool dequeue_nop(struct trusty_state *s, u32 *args) ++{ ++ unsigned long flags; ++ struct trusty_nop *nop = NULL; ++ ++ spin_lock_irqsave(&s->nop_lock, flags); ++ if (!list_empty(&s->nop_queue)) { ++ nop = list_first_entry(&s->nop_queue, ++ struct trusty_nop, node); ++ list_del_init(&nop->node); ++ args[0] = nop->args[0]; ++ args[1] = nop->args[1]; ++ args[2] = nop->args[2]; ++ } else { ++ args[0] = 0; ++ args[1] = 0; ++ args[2] = 0; ++ } ++ spin_unlock_irqrestore(&s->nop_lock, flags); ++ return nop; ++} ++ ++static void locked_nop_work_func(struct work_struct *work) ++{ ++ int ret; ++ struct trusty_work *tw = container_of(work, struct trusty_work, work); ++ struct trusty_state *s = tw->ts; ++ ++ ret = trusty_std_call32(s->dev, SMC_SC_LOCKED_NOP, 0, 0, 0); ++ if (ret != 0) ++ dev_err(s->dev, "%s: SMC_SC_LOCKED_NOP failed %d", ++ __func__, ret); ++ ++ dev_dbg(s->dev, "%s: done\n", __func__); ++} ++ ++static void nop_work_func(struct work_struct *work) ++{ ++ int ret; ++ bool next; ++ u32 args[3]; ++ u32 last_arg0; ++ struct trusty_work *tw = container_of(work, struct trusty_work, work); ++ struct trusty_state *s = tw->ts; ++ ++ dequeue_nop(s, args); ++ do { ++ dev_dbg(s->dev, "%s: %x %x %x\n", ++ __func__, args[0], args[1], args[2]); ++ ++ last_arg0 = args[0]; ++ ret = trusty_std_call32(s->dev, SMC_SC_NOP, ++ args[0], args[1], args[2]); ++ ++ next = dequeue_nop(s, args); ++ ++ if (ret == SM_ERR_NOP_INTERRUPTED) { ++ next = true; ++ } else if (ret != SM_ERR_NOP_DONE) { ++ dev_err(s->dev, "%s: SMC_SC_NOP %x failed %d", ++ __func__, last_arg0, ret); ++ if (last_arg0) { ++ /* ++ * Don't break out of the loop if a non-default ++ * nop-handler returns an error. ++ */ ++ next = true; ++ } ++ } ++ } while (next); ++ ++ dev_dbg(s->dev, "%s: done\n", __func__); ++} ++ ++void trusty_enqueue_nop(struct device *dev, struct trusty_nop *nop) ++{ ++ unsigned long flags; ++ struct trusty_work *tw; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ preempt_disable(); ++ tw = this_cpu_ptr(s->nop_works); ++ if (nop) { ++ WARN_ON(s->api_version < TRUSTY_API_VERSION_SMP_NOP); ++ ++ spin_lock_irqsave(&s->nop_lock, flags); ++ if (list_empty(&nop->node)) ++ list_add_tail(&nop->node, &s->nop_queue); ++ spin_unlock_irqrestore(&s->nop_lock, flags); ++ } ++ queue_work(s->nop_wq, &tw->work); ++ preempt_enable(); ++} ++EXPORT_SYMBOL(trusty_enqueue_nop); ++ ++void trusty_dequeue_nop(struct device *dev, struct trusty_nop *nop) ++{ ++ unsigned long flags; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (WARN_ON(!nop)) ++ return; ++ ++ spin_lock_irqsave(&s->nop_lock, flags); ++ if (!list_empty(&nop->node)) ++ list_del_init(&nop->node); ++ spin_unlock_irqrestore(&s->nop_lock, flags); ++} ++EXPORT_SYMBOL(trusty_dequeue_nop); ++ ++static int trusty_probe(struct platform_device *pdev) ++{ ++ int ret; ++ unsigned int cpu; ++ work_func_t work_func; ++ struct trusty_state *s; ++ struct device_node *node = pdev->dev.of_node; ++ ++ if (!node) { ++ dev_err(&pdev->dev, "of_node required\n"); ++ return -EINVAL; ++ } ++ ++ s = kzalloc(sizeof(*s), GFP_KERNEL); ++ if (!s) { ++ ret = -ENOMEM; ++ goto err_allocate_state; ++ } ++ ++ s->dev = &pdev->dev; ++ spin_lock_init(&s->nop_lock); ++ INIT_LIST_HEAD(&s->nop_queue); ++ mutex_init(&s->smc_lock); ++ mutex_init(&s->share_memory_msg_lock); ++ ATOMIC_INIT_NOTIFIER_HEAD(&s->notifier); ++ init_completion(&s->cpu_idle_completion); ++ ++ s->dev->dma_parms = &s->dma_parms; ++ dma_set_max_seg_size(s->dev, 0xfffff000); /* dma_parms limit */ ++ /* ++ * Set dma mask to 48 bits. This is the current limit of ++ * trusty_encode_page_info. ++ */ ++ dma_coerce_mask_and_coherent(s->dev, DMA_BIT_MASK(48)); ++ ++ platform_set_drvdata(pdev, s); ++ ++ trusty_init_version(s, &pdev->dev); ++ ++ ret = trusty_init_api_version(s, &pdev->dev); ++ if (ret < 0) ++ goto err_api_version; ++ ++ ret = trusty_init_msg_buf(s, &pdev->dev); ++ if (ret < 0) ++ goto err_init_msg_buf; ++ ++ s->nop_wq = alloc_workqueue("trusty-nop-wq", WQ_CPU_INTENSIVE, 0); ++ if (!s->nop_wq) { ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "Failed create trusty-nop-wq\n"); ++ goto err_create_nop_wq; ++ } ++ ++ s->nop_works = alloc_percpu(struct trusty_work); ++ if (!s->nop_works) { ++ ret = -ENOMEM; ++ dev_err(&pdev->dev, "Failed to allocate works\n"); ++ goto err_alloc_works; ++ } ++ ++ if (s->api_version < TRUSTY_API_VERSION_SMP) ++ work_func = locked_nop_work_func; ++ else ++ work_func = nop_work_func; ++ ++ for_each_possible_cpu(cpu) { ++ struct trusty_work *tw = per_cpu_ptr(s->nop_works, cpu); ++ ++ tw->ts = s; ++ INIT_WORK(&tw->work, work_func); ++ } ++ ++ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to add children: %d\n", ret); ++ goto err_add_children; ++ } ++ ++ return 0; ++ ++err_add_children: ++ for_each_possible_cpu(cpu) { ++ struct trusty_work *tw = per_cpu_ptr(s->nop_works, cpu); ++ ++ flush_work(&tw->work); ++ } ++ free_percpu(s->nop_works); ++err_alloc_works: ++ destroy_workqueue(s->nop_wq); ++err_create_nop_wq: ++ trusty_free_msg_buf(s, &pdev->dev); ++err_init_msg_buf: ++err_api_version: ++ s->dev->dma_parms = NULL; ++ kfree(s->version_str); ++ device_for_each_child(&pdev->dev, NULL, trusty_remove_child); ++ mutex_destroy(&s->share_memory_msg_lock); ++ mutex_destroy(&s->smc_lock); ++ kfree(s); ++err_allocate_state: ++ return ret; ++} ++ ++static int trusty_remove(struct platform_device *pdev) ++{ ++ unsigned int cpu; ++ struct trusty_state *s = platform_get_drvdata(pdev); ++ ++ device_for_each_child(&pdev->dev, NULL, trusty_remove_child); ++ ++ for_each_possible_cpu(cpu) { ++ struct trusty_work *tw = per_cpu_ptr(s->nop_works, cpu); ++ ++ flush_work(&tw->work); ++ } ++ free_percpu(s->nop_works); ++ destroy_workqueue(s->nop_wq); ++ ++ mutex_destroy(&s->share_memory_msg_lock); ++ mutex_destroy(&s->smc_lock); ++ trusty_free_msg_buf(s, &pdev->dev); ++ s->dev->dma_parms = NULL; ++ kfree(s->version_str); ++ kfree(s); ++ return 0; ++} ++ ++static const struct of_device_id trusty_of_match[] = { ++ { .compatible = "android,trusty-smc-v1", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(trusty, trusty_of_match); ++ ++static struct platform_driver trusty_driver = { ++ .probe = trusty_probe, ++ .remove = trusty_remove, ++ .driver = { ++ .name = "trusty", ++ .of_match_table = trusty_of_match, ++ .dev_groups = trusty_groups, ++ }, ++}; ++ ++static int __init trusty_driver_init(void) ++{ ++ return platform_driver_register(&trusty_driver); ++} ++ ++static void __exit trusty_driver_exit(void) ++{ ++ platform_driver_unregister(&trusty_driver); ++} ++ ++subsys_initcall(trusty_driver_init); ++module_exit(trusty_driver_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Trusty core driver"); +diff --git a/include/linux/trusty/arm_ffa.h b/include/linux/trusty/arm_ffa.h +new file mode 100644 +index 000000000000..ab7b2afb794c +--- /dev/null ++++ b/include/linux/trusty/arm_ffa.h +@@ -0,0 +1,590 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright (C) 2020 Google, Inc. ++ * ++ * Trusty and TF-A also have a copy of this header. ++ * Please keep the copies in sync. ++ */ ++#ifndef __LINUX_TRUSTY_ARM_FFA_H ++#define __LINUX_TRUSTY_ARM_FFA_H ++ ++/* ++ * Subset of Arm PSA Firmware Framework for Arm v8-A 1.0 EAC 1_0 ++ * (https://developer.arm.com/docs/den0077/a) needed for shared memory. ++ */ ++ ++#include "smcall.h" ++ ++#ifndef STATIC_ASSERT ++#define STATIC_ASSERT(e) _Static_assert(e, #e) ++#endif ++ ++#define FFA_CURRENT_VERSION_MAJOR (1U) ++#define FFA_CURRENT_VERSION_MINOR (0U) ++ ++#define FFA_VERSION_TO_MAJOR(version) ((version) >> 16) ++#define FFA_VERSION_TO_MINOR(version) ((version) & (0xffff)) ++#define FFA_VERSION(major, minor) (((major) << 16) | (minor)) ++#define FFA_CURRENT_VERSION \ ++ FFA_VERSION(FFA_CURRENT_VERSION_MAJOR, FFA_CURRENT_VERSION_MINOR) ++ ++#define SMC_ENTITY_SHARED_MEMORY 4 ++ ++#define SMC_FASTCALL_NR_SHARED_MEMORY(nr) \ ++ SMC_FASTCALL_NR(SMC_ENTITY_SHARED_MEMORY, nr) ++#define SMC_FASTCALL64_NR_SHARED_MEMORY(nr) \ ++ SMC_FASTCALL64_NR(SMC_ENTITY_SHARED_MEMORY, nr) ++ ++/** ++ * typedef ffa_endpoint_id16_t - Endpoint ID ++ * ++ * Current implementation only supports VMIDs. FFA spec also support stream ++ * endpoint ids. ++ */ ++typedef uint16_t ffa_endpoint_id16_t; ++ ++/** ++ * struct ffa_cons_mrd - Constituent memory region descriptor ++ * @address: ++ * Start address of contiguous memory region. Must be 4K page aligned. ++ * @page_count: ++ * Number of 4K pages in region. ++ * @reserved_12_15: ++ * Reserve bytes 12-15 to pad struct size to 16 bytes. ++ */ ++struct ffa_cons_mrd { ++ uint64_t address; ++ uint32_t page_count; ++ uint32_t reserved_12_15; ++}; ++STATIC_ASSERT(sizeof(struct ffa_cons_mrd) == 16); ++ ++/** ++ * struct ffa_comp_mrd - Composite memory region descriptor ++ * @total_page_count: ++ * Number of 4k pages in memory region. Must match sum of ++ * @address_range_array[].page_count. ++ * @address_range_count: ++ * Number of entries in @address_range_array. ++ * @reserved_8_15: ++ * Reserve bytes 8-15 to pad struct size to 16 byte alignment and ++ * make @address_range_array 16 byte aligned. ++ * @address_range_array: ++ * Array of &struct ffa_cons_mrd entries. ++ */ ++struct ffa_comp_mrd { ++ uint32_t total_page_count; ++ uint32_t address_range_count; ++ uint64_t reserved_8_15; ++ struct ffa_cons_mrd address_range_array[]; ++}; ++STATIC_ASSERT(sizeof(struct ffa_comp_mrd) == 16); ++ ++/** ++ * typedef ffa_mem_attr8_t - Memory region attributes ++ * ++ * * @FFA_MEM_ATTR_DEVICE_NGNRNE: ++ * Device-nGnRnE. ++ * * @FFA_MEM_ATTR_DEVICE_NGNRE: ++ * Device-nGnRE. ++ * * @FFA_MEM_ATTR_DEVICE_NGRE: ++ * Device-nGRE. ++ * * @FFA_MEM_ATTR_DEVICE_GRE: ++ * Device-GRE. ++ * * @FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED ++ * Normal memory. Non-cacheable. ++ * * @FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB ++ * Normal memory. Write-back cached. ++ * * @FFA_MEM_ATTR_NON_SHAREABLE ++ * Non-shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*. ++ * * @FFA_MEM_ATTR_OUTER_SHAREABLE ++ * Outer Shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*. ++ * * @FFA_MEM_ATTR_INNER_SHAREABLE ++ * Inner Shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*. ++ */ ++typedef uint8_t ffa_mem_attr8_t; ++#define FFA_MEM_ATTR_DEVICE_NGNRNE ((1U << 4) | (0x0U << 2)) ++#define FFA_MEM_ATTR_DEVICE_NGNRE ((1U << 4) | (0x1U << 2)) ++#define FFA_MEM_ATTR_DEVICE_NGRE ((1U << 4) | (0x2U << 2)) ++#define FFA_MEM_ATTR_DEVICE_GRE ((1U << 4) | (0x3U << 2)) ++#define FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED ((2U << 4) | (0x1U << 2)) ++#define FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB ((2U << 4) | (0x3U << 2)) ++#define FFA_MEM_ATTR_NON_SHAREABLE (0x0U << 0) ++#define FFA_MEM_ATTR_OUTER_SHAREABLE (0x2U << 0) ++#define FFA_MEM_ATTR_INNER_SHAREABLE (0x3U << 0) ++ ++/** ++ * typedef ffa_mem_perm8_t - Memory access permissions ++ * ++ * * @FFA_MEM_ATTR_RO ++ * Request or specify read-only mapping. ++ * * @FFA_MEM_ATTR_RW ++ * Request or allow read-write mapping. ++ * * @FFA_MEM_PERM_NX ++ * Deny executable mapping. ++ * * @FFA_MEM_PERM_X ++ * Request executable mapping. ++ */ ++typedef uint8_t ffa_mem_perm8_t; ++#define FFA_MEM_PERM_RO (1U << 0) ++#define FFA_MEM_PERM_RW (1U << 1) ++#define FFA_MEM_PERM_NX (1U << 2) ++#define FFA_MEM_PERM_X (1U << 3) ++ ++/** ++ * typedef ffa_mem_flag8_t - Endpoint memory flags ++ * ++ * * @FFA_MEM_FLAG_OTHER ++ * Other borrower. Memory region must not be or was not retrieved on behalf ++ * of this endpoint. ++ */ ++typedef uint8_t ffa_mem_flag8_t; ++#define FFA_MEM_FLAG_OTHER (1U << 0) ++ ++/** ++ * typedef ffa_mtd_flag32_t - Memory transaction descriptor flags ++ * ++ * * @FFA_MTD_FLAG_ZERO_MEMORY ++ * Zero memory after unmapping from sender (must be 0 for share). ++ * * @FFA_MTD_FLAG_TIME_SLICING ++ * Not supported by this implementation. ++ * * @FFA_MTD_FLAG_ZERO_MEMORY_AFTER_RELINQUISH ++ * Zero memory after unmapping from borrowers (must be 0 for share). ++ * * @FFA_MTD_FLAG_TYPE_MASK ++ * Bit-mask to extract memory management transaction type from flags. ++ * * @FFA_MTD_FLAG_TYPE_SHARE_MEMORY ++ * Share memory transaction flag. ++ * Used by @SMC_FC_FFA_MEM_RETRIEVE_RESP to indicate that memory came from ++ * @SMC_FC_FFA_MEM_SHARE and by @SMC_FC_FFA_MEM_RETRIEVE_REQ to specify that ++ * it must have. ++ * * @FFA_MTD_FLAG_ADDRESS_RANGE_ALIGNMENT_HINT_MASK ++ * Not supported by this implementation. ++ */ ++typedef uint32_t ffa_mtd_flag32_t; ++#define FFA_MTD_FLAG_ZERO_MEMORY (1U << 0) ++#define FFA_MTD_FLAG_TIME_SLICING (1U << 1) ++#define FFA_MTD_FLAG_ZERO_MEMORY_AFTER_RELINQUISH (1U << 2) ++#define FFA_MTD_FLAG_TYPE_MASK (3U << 3) ++#define FFA_MTD_FLAG_TYPE_SHARE_MEMORY (1U << 3) ++#define FFA_MTD_FLAG_ADDRESS_RANGE_ALIGNMENT_HINT_MASK (0x1FU << 5) ++ ++/** ++ * struct ffa_mapd - Memory access permissions descriptor ++ * @endpoint_id: ++ * Endpoint id that @memory_access_permissions and @flags apply to. ++ * (&typedef ffa_endpoint_id16_t). ++ * @memory_access_permissions: ++ * FFA_MEM_PERM_* values or'ed together (&typedef ffa_mem_perm8_t). ++ * @flags: ++ * FFA_MEM_FLAG_* values or'ed together (&typedef ffa_mem_flag8_t). ++ */ ++struct ffa_mapd { ++ ffa_endpoint_id16_t endpoint_id; ++ ffa_mem_perm8_t memory_access_permissions; ++ ffa_mem_flag8_t flags; ++}; ++STATIC_ASSERT(sizeof(struct ffa_mapd) == 4); ++ ++/** ++ * struct ffa_emad - Endpoint memory access descriptor. ++ * @mapd: &struct ffa_mapd. ++ * @comp_mrd_offset: ++ * Offset of &struct ffa_comp_mrd form start of &struct ffa_mtd. ++ * @reserved_8_15: ++ * Reserved bytes 8-15. Must be 0. ++ */ ++struct ffa_emad { ++ struct ffa_mapd mapd; ++ uint32_t comp_mrd_offset; ++ uint64_t reserved_8_15; ++}; ++STATIC_ASSERT(sizeof(struct ffa_emad) == 16); ++ ++/** ++ * struct ffa_mtd - Memory transaction descriptor. ++ * @sender_id: ++ * Sender endpoint id. ++ * @memory_region_attributes: ++ * FFA_MEM_ATTR_* values or'ed together (&typedef ffa_mem_attr8_t). ++ * @reserved_3: ++ * Reserved bytes 3. Must be 0. ++ * @flags: ++ * FFA_MTD_FLAG_* values or'ed together (&typedef ffa_mtd_flag32_t). ++ * @handle: ++ * Id of shared memory object. Most be 0 for MEM_SHARE. ++ * @tag: Client allocated tag. Must match original value. ++ * @reserved_24_27: ++ * Reserved bytes 24-27. Must be 0. ++ * @emad_count: ++ * Number of entries in @emad. Must be 1 in current implementation. ++ * FFA spec allows more entries. ++ * @emad: ++ * Endpoint memory access descriptor array (see @struct ffa_emad). ++ */ ++struct ffa_mtd { ++ ffa_endpoint_id16_t sender_id; ++ ffa_mem_attr8_t memory_region_attributes; ++ uint8_t reserved_3; ++ ffa_mtd_flag32_t flags; ++ uint64_t handle; ++ uint64_t tag; ++ uint32_t reserved_24_27; ++ uint32_t emad_count; ++ struct ffa_emad emad[]; ++}; ++STATIC_ASSERT(sizeof(struct ffa_mtd) == 32); ++ ++/** ++ * struct ffa_mem_relinquish_descriptor - Relinquish request descriptor. ++ * @handle: ++ * Id of shared memory object to relinquish. ++ * @flags: ++ * If bit 0 is set clear memory after unmapping from borrower. Must be 0 ++ * for share. Bit[1]: Time slicing. Not supported, must be 0. All other ++ * bits are reserved 0. ++ * @endpoint_count: ++ * Number of entries in @endpoint_array. ++ * @endpoint_array: ++ * Array of endpoint ids. ++ */ ++struct ffa_mem_relinquish_descriptor { ++ uint64_t handle; ++ uint32_t flags; ++ uint32_t endpoint_count; ++ ffa_endpoint_id16_t endpoint_array[]; ++}; ++STATIC_ASSERT(sizeof(struct ffa_mem_relinquish_descriptor) == 16); ++ ++/** ++ * enum ffa_error - FF-A error code ++ * @FFA_ERROR_NOT_SUPPORTED: ++ * Operation contained possibly valid parameters not supported by the ++ * current implementation. Does not match FF-A 1.0 EAC 1_0 definition. ++ * @FFA_ERROR_INVALID_PARAMETERS: ++ * Invalid parameters. Conditions function specific. ++ * @FFA_ERROR_NO_MEMORY: ++ * Not enough memory. ++ * @FFA_ERROR_DENIED: ++ * Operation not allowed. Conditions function specific. ++ * ++ * FF-A 1.0 EAC 1_0 defines other error codes as well but the current ++ * implementation does not use them. ++ */ ++enum ffa_error { ++ FFA_ERROR_NOT_SUPPORTED = -1, ++ FFA_ERROR_INVALID_PARAMETERS = -2, ++ FFA_ERROR_NO_MEMORY = -3, ++ FFA_ERROR_DENIED = -6, ++}; ++ ++/** ++ * SMC_FC32_FFA_MIN - First 32 bit SMC opcode reserved for FFA ++ */ ++#define SMC_FC32_FFA_MIN SMC_FASTCALL_NR_SHARED_MEMORY(0x60) ++ ++/** ++ * SMC_FC32_FFA_MAX - Last 32 bit SMC opcode reserved for FFA ++ */ ++#define SMC_FC32_FFA_MAX SMC_FASTCALL_NR_SHARED_MEMORY(0x7F) ++ ++/** ++ * SMC_FC64_FFA_MIN - First 64 bit SMC opcode reserved for FFA ++ */ ++#define SMC_FC64_FFA_MIN SMC_FASTCALL64_NR_SHARED_MEMORY(0x60) ++ ++/** ++ * SMC_FC64_FFA_MAX - Last 64 bit SMC opcode reserved for FFA ++ */ ++#define SMC_FC64_FFA_MAX SMC_FASTCALL64_NR_SHARED_MEMORY(0x7F) ++ ++/** ++ * SMC_FC_FFA_ERROR - SMC error return opcode ++ * ++ * Register arguments: ++ * ++ * * w1: VMID in [31:16], vCPU in [15:0] ++ * * w2: Error code (&enum ffa_error) ++ */ ++#define SMC_FC_FFA_ERROR SMC_FASTCALL_NR_SHARED_MEMORY(0x60) ++ ++/** ++ * SMC_FC_FFA_SUCCESS - 32 bit SMC success return opcode ++ * ++ * Register arguments: ++ * ++ * * w1: VMID in [31:16], vCPU in [15:0] ++ * * w2-w7: Function specific ++ */ ++#define SMC_FC_FFA_SUCCESS SMC_FASTCALL_NR_SHARED_MEMORY(0x61) ++ ++/** ++ * SMC_FC64_FFA_SUCCESS - 64 bit SMC success return opcode ++ * ++ * Register arguments: ++ * ++ * * w1: VMID in [31:16], vCPU in [15:0] ++ * * w2/x2-w7/x7: Function specific ++ */ ++#define SMC_FC64_FFA_SUCCESS SMC_FASTCALL64_NR_SHARED_MEMORY(0x61) ++ ++/** ++ * SMC_FC_FFA_VERSION - SMC opcode to return supported FF-A version ++ * ++ * Register arguments: ++ * ++ * * w1: Major version bit[30:16] and minor version in bit[15:0] supported ++ * by caller. Bit[31] must be 0. ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ * * w2: Major version bit[30:16], minor version in bit[15:0], bit[31] must ++ * be 0. ++ * ++ * or ++ * ++ * * w0: SMC_FC_FFA_ERROR ++ * * w2: FFA_ERROR_NOT_SUPPORTED if major version passed in is less than the ++ * minimum major version supported. ++ */ ++#define SMC_FC_FFA_VERSION SMC_FASTCALL_NR_SHARED_MEMORY(0x63) ++ ++/** ++ * SMC_FC_FFA_FEATURES - SMC opcode to check optional feature support ++ * ++ * Register arguments: ++ * ++ * * w1: FF-A function ID ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ * * w2: Bit[0]: Supports custom buffers for memory transactions. ++ * Bit[1:0]: For RXTX_MAP min buffer size and alignment boundary. ++ * Other bits must be 0. ++ * * w3: For FFA_MEM_RETRIEVE_REQ, bit[7-0]: Number of times receiver can ++ * retrieve each memory region before relinquishing it specified as ++ * ((1U << (value + 1)) - 1 (or value = bits in reference count - 1). ++ * For all other bits and commands: must be 0. ++ * or ++ * ++ * * w0: SMC_FC_FFA_ERROR ++ * * w2: FFA_ERROR_NOT_SUPPORTED if function is not implemented, or ++ * FFA_ERROR_INVALID_PARAMETERS if function id is not valid. ++ */ ++#define SMC_FC_FFA_FEATURES SMC_FASTCALL_NR_SHARED_MEMORY(0x64) ++ ++/** ++ * SMC_FC_FFA_RXTX_MAP - 32 bit SMC opcode to map message buffers ++ * ++ * Register arguments: ++ * ++ * * w1: TX address ++ * * w2: RX address ++ * * w3: RX/TX page count in bit[5:0] ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ */ ++#define SMC_FC_FFA_RXTX_MAP SMC_FASTCALL_NR_SHARED_MEMORY(0x66) ++ ++/** ++ * SMC_FC64_FFA_RXTX_MAP - 64 bit SMC opcode to map message buffers ++ * ++ * Register arguments: ++ * ++ * * x1: TX address ++ * * x2: RX address ++ * * x3: RX/TX page count in bit[5:0] ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ */ ++#define SMC_FC64_FFA_RXTX_MAP SMC_FASTCALL64_NR_SHARED_MEMORY(0x66) ++#ifdef CONFIG_64BIT ++#define SMC_FCZ_FFA_RXTX_MAP SMC_FC64_FFA_RXTX_MAP ++#else ++#define SMC_FCZ_FFA_RXTX_MAP SMC_FC_FFA_RXTX_MAP ++#endif ++ ++/** ++ * SMC_FC_FFA_RXTX_UNMAP - SMC opcode to unmap message buffers ++ * ++ * Register arguments: ++ * ++ * * w1: ID in [31:16] ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ */ ++#define SMC_FC_FFA_RXTX_UNMAP SMC_FASTCALL_NR_SHARED_MEMORY(0x67) ++ ++/** ++ * SMC_FC_FFA_ID_GET - SMC opcode to get endpoint id of caller ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ * * w2: ID in bit[15:0], bit[31:16] must be 0. ++ */ ++#define SMC_FC_FFA_ID_GET SMC_FASTCALL_NR_SHARED_MEMORY(0x69) ++ ++/** ++ * SMC_FC_FFA_MEM_DONATE - 32 bit SMC opcode to donate memory ++ * ++ * Not supported. ++ */ ++#define SMC_FC_FFA_MEM_DONATE SMC_FASTCALL_NR_SHARED_MEMORY(0x71) ++ ++/** ++ * SMC_FC_FFA_MEM_LEND - 32 bit SMC opcode to lend memory ++ * ++ * Not currently supported. ++ */ ++#define SMC_FC_FFA_MEM_LEND SMC_FASTCALL_NR_SHARED_MEMORY(0x72) ++ ++/** ++ * SMC_FC_FFA_MEM_SHARE - 32 bit SMC opcode to share memory ++ * ++ * Register arguments: ++ * ++ * * w1: Total length ++ * * w2: Fragment length ++ * * w3: Address ++ * * w4: Page count ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ * * w2/w3: Handle ++ * ++ * or ++ * ++ * * w0: &SMC_FC_FFA_MEM_FRAG_RX ++ * * w1-: See &SMC_FC_FFA_MEM_FRAG_RX ++ * ++ * or ++ * ++ * * w0: SMC_FC_FFA_ERROR ++ * * w2: Error code (&enum ffa_error) ++ */ ++#define SMC_FC_FFA_MEM_SHARE SMC_FASTCALL_NR_SHARED_MEMORY(0x73) ++ ++/** ++ * SMC_FC64_FFA_MEM_SHARE - 64 bit SMC opcode to share memory ++ * ++ * Register arguments: ++ * ++ * * w1: Total length ++ * * w2: Fragment length ++ * * x3: Address ++ * * w4: Page count ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ * * w2/w3: Handle ++ * ++ * or ++ * ++ * * w0: &SMC_FC_FFA_MEM_FRAG_RX ++ * * w1-: See &SMC_FC_FFA_MEM_FRAG_RX ++ * ++ * or ++ * ++ * * w0: SMC_FC_FFA_ERROR ++ * * w2: Error code (&enum ffa_error) ++ */ ++#define SMC_FC64_FFA_MEM_SHARE SMC_FASTCALL64_NR_SHARED_MEMORY(0x73) ++ ++/** ++ * SMC_FC_FFA_MEM_RETRIEVE_REQ - 32 bit SMC opcode to retrieve shared memory ++ * ++ * Register arguments: ++ * ++ * * w1: Total length ++ * * w2: Fragment length ++ * * w3: Address ++ * * w4: Page count ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_MEM_RETRIEVE_RESP ++ * * w1/x1-w5/x5: See &SMC_FC_FFA_MEM_RETRIEVE_RESP ++ */ ++#define SMC_FC_FFA_MEM_RETRIEVE_REQ SMC_FASTCALL_NR_SHARED_MEMORY(0x74) ++ ++/** ++ * SMC_FC64_FFA_MEM_RETRIEVE_REQ - 64 bit SMC opcode to retrieve shared memory ++ * ++ * Register arguments: ++ * ++ * * w1: Total length ++ * * w2: Fragment length ++ * * x3: Address ++ * * w4: Page count ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_MEM_RETRIEVE_RESP ++ * * w1/x1-w5/x5: See &SMC_FC_FFA_MEM_RETRIEVE_RESP ++ */ ++#define SMC_FC64_FFA_MEM_RETRIEVE_REQ SMC_FASTCALL64_NR_SHARED_MEMORY(0x74) ++ ++/** ++ * SMC_FC_FFA_MEM_RETRIEVE_RESP - Retrieve 32 bit SMC return opcode ++ * ++ * Register arguments: ++ * ++ * * w1: Total length ++ * * w2: Fragment length ++ */ ++#define SMC_FC_FFA_MEM_RETRIEVE_RESP SMC_FASTCALL_NR_SHARED_MEMORY(0x75) ++ ++/** ++ * SMC_FC_FFA_MEM_RELINQUISH - SMC opcode to relinquish shared memory ++ * ++ * Input in &struct ffa_mem_relinquish_descriptor format in message buffer. ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ */ ++#define SMC_FC_FFA_MEM_RELINQUISH SMC_FASTCALL_NR_SHARED_MEMORY(0x76) ++ ++/** ++ * SMC_FC_FFA_MEM_RECLAIM - SMC opcode to reclaim shared memory ++ * ++ * Register arguments: ++ * ++ * * w1/w2: Handle ++ * * w3: Flags ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_SUCCESS ++ */ ++#define SMC_FC_FFA_MEM_RECLAIM SMC_FASTCALL_NR_SHARED_MEMORY(0x77) ++ ++/** ++ * SMC_FC_FFA_MEM_FRAG_RX - SMC opcode to request next fragment. ++ * ++ * Register arguments: ++ * ++ * * w1/w2: Cookie ++ * * w3: Fragment offset. ++ * * w4: Endpoint id ID in [31:16], if client is hypervisor. ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_MEM_FRAG_TX ++ * * w1/x1-w5/x5: See &SMC_FC_FFA_MEM_FRAG_TX ++ */ ++#define SMC_FC_FFA_MEM_FRAG_RX SMC_FASTCALL_NR_SHARED_MEMORY(0x7A) ++ ++/** ++ * SMC_FC_FFA_MEM_FRAG_TX - SMC opcode to transmit next fragment ++ * ++ * Register arguments: ++ * ++ * * w1/w2: Cookie ++ * * w3: Fragment length. ++ * * w4: Sender endpoint id ID in [31:16], if client is hypervisor. ++ * ++ * Return: ++ * * w0: &SMC_FC_FFA_MEM_FRAG_RX or &SMC_FC_FFA_SUCCESS. ++ * * w1/x1-w5/x5: See opcode in w0. ++ */ ++#define SMC_FC_FFA_MEM_FRAG_TX SMC_FASTCALL_NR_SHARED_MEMORY(0x7B) ++ ++#endif /* __LINUX_TRUSTY_ARM_FFA_H */ +diff --git a/include/linux/trusty/sm_err.h b/include/linux/trusty/sm_err.h +new file mode 100644 +index 000000000000..f6504448c6c3 +--- /dev/null ++++ b/include/linux/trusty/sm_err.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright (c) 2013 Google Inc. All rights reserved ++ * ++ * Trusty and TF-A also have a copy of this header. ++ * Please keep the copies in sync. ++ */ ++#ifndef __LINUX_TRUSTY_SM_ERR_H ++#define __LINUX_TRUSTY_SM_ERR_H ++ ++/* Errors from the secure monitor */ ++#define SM_ERR_UNDEFINED_SMC 0xFFFFFFFF /* Unknown SMC (defined by ARM DEN 0028A(0.9.0) */ ++#define SM_ERR_INVALID_PARAMETERS -2 ++#define SM_ERR_INTERRUPTED -3 /* Got interrupted. Call back with restart SMC */ ++#define SM_ERR_UNEXPECTED_RESTART -4 /* Got an restart SMC when we didn't expect it */ ++#define SM_ERR_BUSY -5 /* Temporarily busy. Call back with original args */ ++#define SM_ERR_INTERLEAVED_SMC -6 /* Got a trusted_service SMC when a restart SMC is required */ ++#define SM_ERR_INTERNAL_FAILURE -7 /* Unknown error */ ++#define SM_ERR_NOT_SUPPORTED -8 ++#define SM_ERR_NOT_ALLOWED -9 /* SMC call not allowed */ ++#define SM_ERR_END_OF_INPUT -10 ++#define SM_ERR_PANIC -11 /* Secure OS crashed */ ++#define SM_ERR_FIQ_INTERRUPTED -12 /* Got interrupted by FIQ. Call back with SMC_SC_RESTART_FIQ on same CPU */ ++#define SM_ERR_CPU_IDLE -13 /* SMC call waiting for another CPU */ ++#define SM_ERR_NOP_INTERRUPTED -14 /* Got interrupted. Call back with new SMC_SC_NOP */ ++#define SM_ERR_NOP_DONE -15 /* Cpu idle after SMC_SC_NOP (not an error) */ ++ ++#endif +diff --git a/include/linux/trusty/smcall.h b/include/linux/trusty/smcall.h +new file mode 100644 +index 000000000000..aea3f6068593 +--- /dev/null ++++ b/include/linux/trusty/smcall.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright (c) 2013-2014 Google Inc. All rights reserved ++ * ++ * Trusty and TF-A also have a copy of this header. ++ * Please keep the copies in sync. ++ */ ++#ifndef __LINUX_TRUSTY_SMCALL_H ++#define __LINUX_TRUSTY_SMCALL_H ++ ++#define SMC_NUM_ENTITIES 64 ++#define SMC_NUM_ARGS 4 ++#define SMC_NUM_PARAMS (SMC_NUM_ARGS - 1) ++ ++#define SMC_IS_FASTCALL(smc_nr) ((smc_nr) & 0x80000000) ++#define SMC_IS_SMC64(smc_nr) ((smc_nr) & 0x40000000) ++#define SMC_ENTITY(smc_nr) (((smc_nr) & 0x3F000000) >> 24) ++#define SMC_FUNCTION(smc_nr) ((smc_nr) & 0x0000FFFF) ++ ++#define SMC_NR(entity, fn, fastcall, smc64) ((((fastcall) & 0x1U) << 31) | \ ++ (((smc64) & 0x1U) << 30) | \ ++ (((entity) & 0x3FU) << 24) | \ ++ ((fn) & 0xFFFFU) \ ++ ) ++ ++#define SMC_FASTCALL_NR(entity, fn) SMC_NR((entity), (fn), 1, 0) ++#define SMC_STDCALL_NR(entity, fn) SMC_NR((entity), (fn), 0, 0) ++#define SMC_FASTCALL64_NR(entity, fn) SMC_NR((entity), (fn), 1, 1) ++#define SMC_STDCALL64_NR(entity, fn) SMC_NR((entity), (fn), 0, 1) ++ ++#define SMC_ENTITY_ARCH 0 /* ARM Architecture calls */ ++#define SMC_ENTITY_CPU 1 /* CPU Service calls */ ++#define SMC_ENTITY_SIP 2 /* SIP Service calls */ ++#define SMC_ENTITY_OEM 3 /* OEM Service calls */ ++#define SMC_ENTITY_STD 4 /* Standard Service calls */ ++#define SMC_ENTITY_RESERVED 5 /* Reserved for future use */ ++#define SMC_ENTITY_TRUSTED_APP 48 /* Trusted Application calls */ ++#define SMC_ENTITY_TRUSTED_OS 50 /* Trusted OS calls */ ++#define SMC_ENTITY_LOGGING 51 /* Used for secure -> nonsecure logging */ ++#define SMC_ENTITY_TEST 52 /* Used for secure -> nonsecure tests */ ++#define SMC_ENTITY_SECURE_MONITOR 60 /* Trusted OS calls internal to secure monitor */ ++ ++/* FC = Fast call, SC = Standard call */ ++#define SMC_SC_RESTART_LAST SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 0) ++#define SMC_SC_LOCKED_NOP SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 1) ++ ++/** ++ * SMC_SC_RESTART_FIQ - Re-enter trusty after it was interrupted by an fiq ++ * ++ * No arguments, no return value. ++ * ++ * Re-enter trusty after returning to ns to process an fiq. Must be called iff ++ * trusty returns SM_ERR_FIQ_INTERRUPTED. ++ * ++ * Enable by selecting api version TRUSTY_API_VERSION_RESTART_FIQ (1) or later. ++ */ ++#define SMC_SC_RESTART_FIQ SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 2) ++ ++/** ++ * SMC_SC_NOP - Enter trusty to run pending work. ++ * ++ * No arguments. ++ * ++ * Returns SM_ERR_NOP_INTERRUPTED or SM_ERR_NOP_DONE. ++ * If SM_ERR_NOP_INTERRUPTED is returned, the call must be repeated. ++ * ++ * Enable by selecting api version TRUSTY_API_VERSION_SMP (2) or later. ++ */ ++#define SMC_SC_NOP SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 3) ++ ++/* ++ * Return from secure os to non-secure os with return value in r1 ++ */ ++#define SMC_SC_NS_RETURN SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 0) ++ ++#define SMC_FC_RESERVED SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 0) ++#define SMC_FC_FIQ_EXIT SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 1) ++#define SMC_FC_REQUEST_FIQ SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 2) ++ ++#define TRUSTY_IRQ_TYPE_NORMAL (0) ++#define TRUSTY_IRQ_TYPE_PER_CPU (1) ++#define TRUSTY_IRQ_TYPE_DOORBELL (2) ++#define SMC_FC_GET_NEXT_IRQ SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 3) ++ ++#define SMC_FC_CPU_SUSPEND SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 7) ++#define SMC_FC_CPU_RESUME SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 8) ++ ++#define SMC_FC_AARCH_SWITCH SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 9) ++#define SMC_FC_GET_VERSION_STR SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 10) ++ ++/** ++ * SMC_FC_API_VERSION - Find and select supported API version. ++ * ++ * @r1: Version supported by client. ++ * ++ * Returns version supported by trusty. ++ * ++ * If multiple versions are supported, the client should start by calling ++ * SMC_FC_API_VERSION with the largest version it supports. Trusty will then ++ * return a version it supports. If the client does not support the version ++ * returned by trusty and the version returned is less than the version ++ * requested, repeat the call with the largest supported version less than the ++ * last returned version. ++ * ++ * This call must be made before any calls that are affected by the api version. ++ */ ++#define TRUSTY_API_VERSION_RESTART_FIQ (1) ++#define TRUSTY_API_VERSION_SMP (2) ++#define TRUSTY_API_VERSION_SMP_NOP (3) ++#define TRUSTY_API_VERSION_PHYS_MEM_OBJ (4) ++#define TRUSTY_API_VERSION_MEM_OBJ (5) ++#define TRUSTY_API_VERSION_CURRENT (5) ++#define SMC_FC_API_VERSION SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 11) ++ ++/* TRUSTED_OS entity calls */ ++#define SMC_SC_VIRTIO_GET_DESCR SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 20) ++#define SMC_SC_VIRTIO_START SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 21) ++#define SMC_SC_VIRTIO_STOP SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 22) ++ ++#define SMC_SC_VDEV_RESET SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 23) ++#define SMC_SC_VDEV_KICK_VQ SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 24) ++#define SMC_NC_VDEV_KICK_VQ SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 25) ++ ++#endif /* __LINUX_TRUSTY_SMCALL_H */ +diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h +new file mode 100644 +index 000000000000..efbb36999a8b +--- /dev/null ++++ b/include/linux/trusty/trusty.h +@@ -0,0 +1,131 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2013 Google, Inc. ++ */ ++#ifndef __LINUX_TRUSTY_TRUSTY_H ++#define __LINUX_TRUSTY_TRUSTY_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#if IS_ENABLED(CONFIG_TRUSTY) ++s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2); ++s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2); ++#ifdef CONFIG_64BIT ++s64 trusty_fast_call64(struct device *dev, u64 smcnr, u64 a0, u64 a1, u64 a2); ++#endif ++#else ++static inline s32 trusty_std_call32(struct device *dev, u32 smcnr, ++ u32 a0, u32 a1, u32 a2) ++{ ++ return SM_ERR_UNDEFINED_SMC; ++} ++static inline s32 trusty_fast_call32(struct device *dev, u32 smcnr, ++ u32 a0, u32 a1, u32 a2) ++{ ++ return SM_ERR_UNDEFINED_SMC; ++} ++#ifdef CONFIG_64BIT ++static inline s64 trusty_fast_call64(struct device *dev, ++ u64 smcnr, u64 a0, u64 a1, u64 a2) ++{ ++ return SM_ERR_UNDEFINED_SMC; ++} ++#endif ++#endif ++ ++struct notifier_block; ++enum { ++ TRUSTY_CALL_PREPARE, ++ TRUSTY_CALL_RETURNED, ++}; ++int trusty_call_notifier_register(struct device *dev, ++ struct notifier_block *n); ++int trusty_call_notifier_unregister(struct device *dev, ++ struct notifier_block *n); ++const char *trusty_version_str_get(struct device *dev); ++u32 trusty_get_api_version(struct device *dev); ++bool trusty_get_panic_status(struct device *dev); ++ ++struct ns_mem_page_info { ++ u64 paddr; ++ u8 ffa_mem_attr; ++ u8 ffa_mem_perm; ++ u64 compat_attr; ++}; ++ ++int trusty_encode_page_info(struct ns_mem_page_info *inf, ++ struct page *page, pgprot_t pgprot); ++ ++struct scatterlist; ++typedef u64 trusty_shared_mem_id_t; ++int trusty_share_memory(struct device *dev, trusty_shared_mem_id_t *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot); ++int trusty_share_memory_compat(struct device *dev, trusty_shared_mem_id_t *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot); ++int trusty_transfer_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag, bool lend); ++int trusty_reclaim_memory(struct device *dev, trusty_shared_mem_id_t id, ++ struct scatterlist *sglist, unsigned int nents); ++ ++struct dma_buf; ++#ifdef CONFIG_TRUSTY_DMA_BUF_FFA_TAG ++u64 trusty_dma_buf_get_ffa_tag(struct dma_buf *dma_buf); ++#else ++static inline u64 trusty_dma_buf_get_ffa_tag(struct dma_buf *dma_buf) ++{ ++ return 0; ++} ++#endif ++ ++/* Invalid handle value is defined by FF-A spec */ ++#ifdef CONFIG_TRUSTY_DMA_BUF_SHARED_MEM_ID ++/** ++ * trusty_dma_buf_get_shared_mem_id() - Get memory ID corresponding to a dma_buf ++ * @dma_buf: DMA buffer ++ * @id: Pointer to output trusty_shared_mem_id_t ++ * ++ * Sets @id to trusty_shared_mem_id_t corresponding to the given @dma_buf. ++ * @dma_buf "owns" the ID, i.e. is responsible for allocating/releasing it. ++ * @dma_buf with an allocated @id must be in secure memory and should only be ++ * sent to Trusty using TRUSTY_SEND_SECURE. ++ * ++ * Return: ++ * * 0 - success ++ * * -ENODATA - @dma_buf does not own a trusty_shared_mem_id_t ++ * * ... - @dma_buf should not be lent or shared ++ */ ++int trusty_dma_buf_get_shared_mem_id(struct dma_buf *dma_buf, ++ trusty_shared_mem_id_t *id); ++#else ++static inline int trusty_dma_buf_get_shared_mem_id(struct dma_buf *dma_buf, ++ trusty_shared_mem_id_t *id) ++{ ++ return -ENODATA; ++} ++#endif ++ ++struct trusty_nop { ++ struct list_head node; ++ u32 args[3]; ++}; ++ ++static inline void trusty_nop_init(struct trusty_nop *nop, ++ u32 arg0, u32 arg1, u32 arg2) { ++ INIT_LIST_HEAD(&nop->node); ++ nop->args[0] = arg0; ++ nop->args[1] = arg1; ++ nop->args[2] = arg2; ++} ++ ++void trusty_enqueue_nop(struct device *dev, struct trusty_nop *nop); ++void trusty_dequeue_nop(struct device *dev, struct trusty_nop *nop); ++ ++#endif +diff --git a/include/linux/trusty/trusty_ipc.h b/include/linux/trusty/trusty_ipc.h +new file mode 100644 +index 000000000000..9386392f3a64 +--- /dev/null ++++ b/include/linux/trusty/trusty_ipc.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2015 Google, Inc. ++ */ ++#ifndef __LINUX_TRUSTY_TRUSTY_IPC_H ++#define __LINUX_TRUSTY_TRUSTY_IPC_H ++ ++#include ++#include ++#include ++#include ++ ++struct tipc_chan; ++ ++struct tipc_msg_buf { ++ void *buf_va; ++ struct scatterlist sg; ++ trusty_shared_mem_id_t buf_id; ++ size_t buf_sz; ++ size_t wpos; ++ size_t rpos; ++ size_t shm_cnt; ++ struct list_head node; ++}; ++ ++enum tipc_chan_event { ++ TIPC_CHANNEL_CONNECTED = 1, ++ TIPC_CHANNEL_DISCONNECTED, ++ TIPC_CHANNEL_SHUTDOWN, ++}; ++ ++struct tipc_chan_ops { ++ void (*handle_event)(void *cb_arg, int event); ++ struct tipc_msg_buf *(*handle_msg)(void *cb_arg, ++ struct tipc_msg_buf *mb); ++ void (*handle_release)(void *cb_arg); ++}; ++ ++struct tipc_chan *tipc_create_channel(struct device *dev, ++ const struct tipc_chan_ops *ops, ++ void *cb_arg); ++ ++int tipc_chan_connect(struct tipc_chan *chan, const char *port); ++ ++int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb); ++ ++int tipc_chan_shutdown(struct tipc_chan *chan); ++ ++void tipc_chan_destroy(struct tipc_chan *chan); ++ ++struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan); ++ ++void tipc_chan_put_rxbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb); ++ ++struct tipc_msg_buf * ++tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, long timeout); ++ ++void tipc_chan_put_txbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb); ++ ++static inline size_t mb_avail_space(struct tipc_msg_buf *mb) ++{ ++ return mb->buf_sz - mb->wpos; ++} ++ ++static inline size_t mb_avail_data(struct tipc_msg_buf *mb) ++{ ++ return mb->wpos - mb->rpos; ++} ++ ++static inline void *mb_put_data(struct tipc_msg_buf *mb, size_t len) ++{ ++ void *pos = (u8 *)mb->buf_va + mb->wpos; ++ ++ BUG_ON(mb->wpos + len > mb->buf_sz); ++ mb->wpos += len; ++ return pos; ++} ++ ++static inline void *mb_get_data(struct tipc_msg_buf *mb, size_t len) ++{ ++ void *pos = (u8 *)mb->buf_va + mb->rpos; ++ ++ BUG_ON(mb->rpos + len > mb->wpos); ++ mb->rpos += len; ++ return pos; ++} ++ ++#endif /* __LINUX_TRUSTY_TRUSTY_IPC_H */ ++ +diff --git a/include/uapi/linux/trusty/ipc.h b/include/uapi/linux/trusty/ipc.h +new file mode 100644 +index 000000000000..af91035484f1 +--- /dev/null ++++ b/include/uapi/linux/trusty/ipc.h +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++ ++#ifndef _UAPI_LINUX_TRUSTY_IPC_H_ ++#define _UAPI_LINUX_TRUSTY_IPC_H_ ++ ++#include ++#include ++#include ++ ++/** ++ * enum transfer_kind - How to send an fd to Trusty ++ * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it ++ * will be mapped as nonsecure. Suitable for shared memory. ++ * The paired fd must be a "dma_buf". ++ * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will ++ * be transitioned to "Secure" memory if Trusty is in ++ * TrustZone. This transfer kind is suitable for donating ++ * video buffers or other similar resources. The paired fd ++ * may need to come from a platform-specific allocator for ++ * memory that may be transitioned to "Secure". ++ * @TRUSTY_SEND_SECURE: Send memory that is already "Secure". Memory will be ++ * accessible only to Trusty. The paired fd may need to ++ * come from a platform-specific allocator that returns ++ * "Secure" buffers. ++ * ++ * Describes how the user would like the resource in question to be sent to ++ * Trusty. Options may be valid only for certain kinds of fds. ++ */ ++enum transfer_kind { ++ TRUSTY_SHARE = 0, ++ TRUSTY_LEND = 1, ++ TRUSTY_SEND_SECURE = 2, ++}; ++ ++/** ++ * struct trusty_shm - Describes a transfer of memory to Trusty ++ * @fd: The fd to transfer ++ * @transfer: How to transfer it - see &enum transfer_kind ++ */ ++struct trusty_shm { ++ __s32 fd; ++ __u32 transfer; ++}; ++ ++/** ++ * struct tipc_send_msg_req - Request struct for @TIPC_IOC_SEND_MSG ++ * @iov: Pointer to an array of &struct iovec describing data to be sent ++ * @shm: Pointer to an array of &struct trusty_shm describing any file ++ * descriptors to be transferred. ++ * @iov_cnt: Number of elements in the @iov array ++ * @shm_cnt: Number of elements in the @shm array ++ */ ++struct tipc_send_msg_req { ++ __u64 iov; ++ __u64 shm; ++ __u64 iov_cnt; ++ __u64 shm_cnt; ++}; ++ ++#define TIPC_IOC_MAGIC 'r' ++#define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char *) ++#define TIPC_IOC_SEND_MSG _IOW(TIPC_IOC_MAGIC, 0x81, \ ++ struct tipc_send_msg_req) ++ ++#endif +diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h +index b052355ac7a3..cf6b95d9a1ec 100644 +--- a/include/uapi/linux/virtio_ids.h ++++ b/include/uapi/linux/virtio_ids.h +@@ -39,6 +39,7 @@ + #define VIRTIO_ID_9P 9 /* 9p virtio console */ + #define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */ + #define VIRTIO_ID_CAIF 12 /* Virtio caif */ ++#define VIRTIO_ID_TRUSTY_IPC 13 /* virtio trusty ipc */ + #define VIRTIO_ID_GPU 16 /* virtio GPU */ + #define VIRTIO_ID_INPUT 18 /* virtio input */ + #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ +-- +2.30.2 + From patchwork Wed May 4 16:58:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arunachalam Ganapathy X-Patchwork-Id: 7569 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0EB0DC433FE for ; Wed, 4 May 2022 16:58:47 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web08.600.1651683517498874931 for ; Wed, 04 May 2022 09:58:37 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: arunachalam.ganapathy@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 19CAD11FB; Wed, 4 May 2022 09:58:37 -0700 (PDT) Received: from ts710.cambridge.arm.com (ts710.cambridge.arm.com [10.1.197.68]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7C9543FA27; Wed, 4 May 2022 09:58:36 -0700 (PDT) From: Arunachalam Ganapathy To: meta-arm@lists.yoctoproject.org Cc: nd@arm.com, Arunachalam Ganapathy Subject: [PATCH 10/10] arm-bsp/linux: TC: Add Trusty FFA adoption patches Date: Wed, 4 May 2022 17:58:20 +0100 Message-Id: <20220504165820.882784-10-arunachalam.ganapathy@arm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> References: <20220504165820.882784-1-arunachalam.ganapathy@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Wed, 04 May 2022 16:58:47 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/3366 Signed-off-by: Arunachalam Ganapathy Change-Id: I5c152ca026dce2a7470d6ee7cfd84fa6b3f2e30a --- .../linux/linux-arm-platforms.inc | 9 + ...ty-Remove-FFA-specific-initilization.patch | 1076 +++++++++++++++++ ...ename-transfer-memory-function-to-le.patch | 191 +++ ...sty-Separate-out-SMC-based-transport.patch | 495 ++++++++ ...usty-Modify-device-compatible-string.patch | 56 + ...ROID-trusty-Add-transport-descriptor.patch | 209 ++++ ...ANDROID-trusty-Add-trusty-ffa-driver.patch | 312 +++++ ...fa-Add-support-for-FFA-memory-operat.patch | 151 +++ ...fa-Enable-FFA-transport-for-both-mem.patch | 142 +++ ...-Make-trusty-transports-configurable.patch | 146 +++ 10 files changed, 2787 insertions(+) create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0036-ANDROID-trusty-Remove-FFA-specific-initilization.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0037-ANDROID-trusty-Rename-transfer-memory-function-to-le.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0038-ANDROID-trusty-Separate-out-SMC-based-transport.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0039-ANDROID-trusty-Modify-device-compatible-string.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0040-ANDROID-trusty-Add-transport-descriptor.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0041-ANDROID-trusty-Add-trusty-ffa-driver.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0042-ANDROID-trusty-ffa-Add-support-for-FFA-memory-operat.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0043-ANDROID-trusty-ffa-Enable-FFA-transport-for-both-mem.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0044-ANDROID-trusty-Make-trusty-transports-configurable.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc index 4ebacd50..f05c5ffc 100644 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc @@ -171,6 +171,15 @@ SRC_URI:append:tc = " \ file://0033-firmware-arm_ffa-extern-ffa_bus_type.patch \ file://0034-firmware-arm_ffa-Fix-FFA_MEM_SHARE-and-FFA_MEM_FRAG_.patch \ file://0035-ANDROID-trusty-Backport-of-trusty-driver.patch \ + file://0036-ANDROID-trusty-Remove-FFA-specific-initilization.patch \ + file://0037-ANDROID-trusty-Rename-transfer-memory-function-to-le.patch \ + file://0038-ANDROID-trusty-Separate-out-SMC-based-transport.patch \ + file://0039-ANDROID-trusty-Modify-device-compatible-string.patch \ + file://0040-ANDROID-trusty-Add-transport-descriptor.patch \ + file://0041-ANDROID-trusty-Add-trusty-ffa-driver.patch \ + file://0042-ANDROID-trusty-ffa-Add-support-for-FFA-memory-operat.patch \ + file://0043-ANDROID-trusty-ffa-Enable-FFA-transport-for-both-mem.patch \ + file://0044-ANDROID-trusty-Make-trusty-transports-configurable.patch \ " KERNEL_FEATURES:append:tc = " bsp/arm-platforms/tc.scc" KERNEL_FEATURES:append:tc1 = " bsp/arm-platforms/tc-autofdo.scc" diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0036-ANDROID-trusty-Remove-FFA-specific-initilization.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0036-ANDROID-trusty-Remove-FFA-specific-initilization.patch new file mode 100644 index 00000000..6dd8af26 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0036-ANDROID-trusty-Remove-FFA-specific-initilization.patch @@ -0,0 +1,1076 @@ +From 8318af58a0f5d29352d3c84be6b20fe6d1ca352f Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 14 Jan 2022 13:41:26 +0000 +Subject: [PATCH 23/32] ANDROID: trusty: Remove FFA specific initilization + +Remove FFA specific initialization and its arm_ffa.h file from Trusty +driver. These changes are done so that Trusty can use ARM FFA driver +and its related header files. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Iaad473659de94930cdf78cd7201f016d59cee8d7 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/trusty-mem.c | 37 --- + drivers/trusty/trusty.c | 286 +--------------- + include/linux/trusty/arm_ffa.h | 590 --------------------------------- + include/linux/trusty/trusty.h | 3 - + 4 files changed, 3 insertions(+), 913 deletions(-) + delete mode 100644 include/linux/trusty/arm_ffa.h + +diff --git a/drivers/trusty/trusty-mem.c b/drivers/trusty/trusty-mem.c +index 8a360298e501..7775ff76c38c 100644 +--- a/drivers/trusty/trusty-mem.c ++++ b/drivers/trusty/trusty-mem.c +@@ -5,7 +5,6 @@ + + #include + #include +-#include + #include + #include + +@@ -75,8 +74,6 @@ int trusty_encode_page_info(struct ns_mem_page_info *inf, + { + int mem_attr; + u64 pte; +- u8 ffa_mem_attr; +- u8 ffa_mem_perm = 0; + + if (!inf || !page) + return -EINVAL; +@@ -89,30 +86,6 @@ int trusty_encode_page_info(struct ns_mem_page_info *inf, + if (mem_attr < 0) + return mem_attr; + +- switch (mem_attr) { +- case MEM_ATTR_STRONGLY_ORDERED: +- ffa_mem_attr = FFA_MEM_ATTR_DEVICE_NGNRNE; +- break; +- +- case MEM_ATTR_DEVICE: +- ffa_mem_attr = FFA_MEM_ATTR_DEVICE_NGNRE; +- break; +- +- case MEM_ATTR_NORMAL_NON_CACHEABLE: +- ffa_mem_attr = FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED; +- break; +- +- case MEM_ATTR_NORMAL_WRITE_BACK_READ_ALLOCATE: +- case MEM_ATTR_NORMAL_WRITE_BACK_WRITE_ALLOCATE: +- ffa_mem_attr = FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB; +- break; +- +- default: +- return -EINVAL; +- } +- +- inf->paddr = pte; +- + /* add other attributes */ + #if defined(CONFIG_ARM64) || defined(CONFIG_ARM_LPAE) + pte |= pgprot_val(pgprot); +@@ -123,16 +96,6 @@ int trusty_encode_page_info(struct ns_mem_page_info *inf, + pte |= ATTR_INNER_SHAREABLE; /* inner sharable */ + #endif + +- if (!(pte & ATTR_RDONLY)) +- ffa_mem_perm |= FFA_MEM_PERM_RW; +- else +- ffa_mem_perm |= FFA_MEM_PERM_RO; +- +- if ((pte & ATTR_INNER_SHAREABLE) == ATTR_INNER_SHAREABLE) +- ffa_mem_attr |= FFA_MEM_ATTR_INNER_SHAREABLE; +- +- inf->ffa_mem_attr = ffa_mem_attr; +- inf->ffa_mem_perm = ffa_mem_perm; + inf->compat_attr = (pte & 0x0000FFFFFFFFFFFFull) | + ((u64)mem_attr << 48); + return 0; +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 265eab52aea0..2dec75398f69 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -42,11 +41,6 @@ struct trusty_state { + struct list_head nop_queue; + spinlock_t nop_lock; /* protects nop_queue */ + struct device_dma_parameters dma_parms; +- void *ffa_tx; +- void *ffa_rx; +- u16 ffa_local_id; +- u16 ffa_remote_id; +- struct mutex share_memory_msg_lock; /* protects share_memory_msg */ + }; + + static inline unsigned long smc(unsigned long r0, unsigned long r1, +@@ -246,19 +240,6 @@ int trusty_transfer_memory(struct device *dev, u64 *id, + struct ns_mem_page_info pg_inf; + struct scatterlist *sg; + size_t count; +- size_t i; +- size_t len; +- u64 ffa_handle = 0; +- size_t total_len; +- size_t endpoint_count = 1; +- struct ffa_mtd *mtd = s->ffa_tx; +- size_t comp_mrd_offset = offsetof(struct ffa_mtd, emad[endpoint_count]); +- struct ffa_comp_mrd *comp_mrd = s->ffa_tx + comp_mrd_offset; +- struct ffa_cons_mrd *cons_mrd = comp_mrd->address_range_array; +- size_t cons_mrd_offset = (void *)cons_mrd - s->ffa_tx; +- struct smc_ret8 smc_ret; +- u32 cookie_low; +- u32 cookie_high; + + if (WARN_ON(dev->driver != &trusty_driver.driver)) + return -EINVAL; +@@ -284,126 +265,11 @@ int trusty_transfer_memory(struct device *dev, u64 *id, + if (ret) { + dev_err(s->dev, "%s: trusty_encode_page_info failed\n", + __func__); +- goto err_encode_page_info; +- } +- +- if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { +- *id = pg_inf.compat_attr; +- return 0; +- } +- +- len = 0; +- for_each_sg(sglist, sg, nents, i) +- len += sg_dma_len(sg); +- +- mutex_lock(&s->share_memory_msg_lock); +- +- mtd->sender_id = s->ffa_local_id; +- mtd->memory_region_attributes = pg_inf.ffa_mem_attr; +- mtd->reserved_3 = 0; +- mtd->flags = 0; +- mtd->handle = 0; +- mtd->tag = tag; +- mtd->reserved_24_27 = 0; +- mtd->emad_count = endpoint_count; +- for (i = 0; i < endpoint_count; i++) { +- struct ffa_emad *emad = &mtd->emad[i]; +- /* TODO: support stream ids */ +- emad->mapd.endpoint_id = s->ffa_remote_id; +- emad->mapd.memory_access_permissions = pg_inf.ffa_mem_perm; +- emad->mapd.flags = 0; +- emad->comp_mrd_offset = comp_mrd_offset; +- emad->reserved_8_15 = 0; +- } +- comp_mrd->total_page_count = len / PAGE_SIZE; +- comp_mrd->address_range_count = nents; +- comp_mrd->reserved_8_15 = 0; +- +- total_len = cons_mrd_offset + nents * sizeof(*cons_mrd); +- sg = sglist; +- while (count) { +- size_t lcount = +- min_t(size_t, count, (PAGE_SIZE - cons_mrd_offset) / +- sizeof(*cons_mrd)); +- size_t fragment_len = lcount * sizeof(*cons_mrd) + +- cons_mrd_offset; +- +- for (i = 0; i < lcount; i++) { +- cons_mrd[i].address = sg_dma_address(sg); +- cons_mrd[i].page_count = sg_dma_len(sg) / PAGE_SIZE; +- cons_mrd[i].reserved_12_15 = 0; +- sg = sg_next(sg); +- } +- count -= lcount; +- if (cons_mrd_offset) { +- u32 smc = lend ? SMC_FC_FFA_MEM_LEND : +- SMC_FC_FFA_MEM_SHARE; +- /* First fragment */ +- smc_ret = trusty_smc8(smc, total_len, +- fragment_len, 0, 0, 0, 0, 0); +- } else { +- smc_ret = trusty_smc8(SMC_FC_FFA_MEM_FRAG_TX, +- cookie_low, cookie_high, +- fragment_len, 0, 0, 0, 0); +- } +- if (smc_ret.r0 == SMC_FC_FFA_MEM_FRAG_RX) { +- cookie_low = smc_ret.r1; +- cookie_high = smc_ret.r2; +- dev_dbg(s->dev, "cookie %x %x", cookie_low, +- cookie_high); +- if (!count) { +- /* +- * We have sent all our descriptors. Expected +- * SMC_FC_FFA_SUCCESS, not a request to send +- * another fragment. +- */ +- dev_err(s->dev, "%s: fragment_len %zd/%zd, unexpected SMC_FC_FFA_MEM_FRAG_RX\n", +- __func__, fragment_len, total_len); +- ret = -EIO; +- break; +- } +- } else if (smc_ret.r0 == SMC_FC_FFA_SUCCESS) { +- ffa_handle = smc_ret.r2 | (u64)smc_ret.r3 << 32; +- dev_dbg(s->dev, "%s: fragment_len %zu/%zu, got handle 0x%llx\n", +- __func__, fragment_len, total_len, +- ffa_handle); +- if (count) { +- /* +- * We have not sent all our descriptors. +- * Expected SMC_FC_FFA_MEM_FRAG_RX not +- * SMC_FC_FFA_SUCCESS. +- */ +- dev_err(s->dev, "%s: fragment_len %zu/%zu, unexpected SMC_FC_FFA_SUCCESS, count %zu != 0\n", +- __func__, fragment_len, total_len, +- count); +- ret = -EIO; +- break; +- } +- } else { +- dev_err(s->dev, "%s: fragment_len %zu/%zu, SMC_FC_FFA_MEM_SHARE failed 0x%lx 0x%lx 0x%lx", +- __func__, fragment_len, total_len, +- smc_ret.r0, smc_ret.r1, smc_ret.r2); +- ret = -EIO; +- break; +- } +- +- cons_mrd = s->ffa_tx; +- cons_mrd_offset = 0; +- } +- +- mutex_unlock(&s->share_memory_msg_lock); +- +- if (!ret) { +- *id = ffa_handle; +- dev_dbg(s->dev, "%s: done\n", __func__); +- return 0; ++ return ret; + } + +- dev_err(s->dev, "%s: failed %d", __func__, ret); +- +-err_encode_page_info: +- dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); +- return ret; ++ *id = pg_inf.compat_attr; ++ return 0; + } + EXPORT_SYMBOL(trusty_transfer_memory); + +@@ -433,8 +299,6 @@ int trusty_reclaim_memory(struct device *dev, u64 id, + struct scatterlist *sglist, unsigned int nents) + { + struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); +- int ret = 0; +- struct smc_ret8 smc_ret; + + if (WARN_ON(dev->driver != &trusty_driver.driver)) + return -EINVAL; +@@ -454,28 +318,6 @@ int trusty_reclaim_memory(struct device *dev, u64 id, + return 0; + } + +- mutex_lock(&s->share_memory_msg_lock); +- +- smc_ret = trusty_smc8(SMC_FC_FFA_MEM_RECLAIM, (u32)id, id >> 32, 0, 0, +- 0, 0, 0); +- if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { +- dev_err(s->dev, "%s: SMC_FC_FFA_MEM_RECLAIM failed 0x%lx 0x%lx 0x%lx", +- __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); +- if (smc_ret.r0 == SMC_FC_FFA_ERROR && +- smc_ret.r2 == FFA_ERROR_DENIED) +- ret = -EBUSY; +- else +- ret = -EIO; +- } +- +- mutex_unlock(&s->share_memory_msg_lock); +- +- if (ret != 0) +- return ret; +- +- dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); +- +- dev_dbg(s->dev, "%s: done\n", __func__); + return 0; + } + EXPORT_SYMBOL(trusty_reclaim_memory); +@@ -527,118 +369,6 @@ const char *trusty_version_str_get(struct device *dev) + } + EXPORT_SYMBOL(trusty_version_str_get); + +-static int trusty_init_msg_buf(struct trusty_state *s, struct device *dev) +-{ +- phys_addr_t tx_paddr; +- phys_addr_t rx_paddr; +- int ret; +- struct smc_ret8 smc_ret; +- +- if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) +- return 0; +- +- /* Get supported FF-A version and check if it is compatible */ +- smc_ret = trusty_smc8(SMC_FC_FFA_VERSION, FFA_CURRENT_VERSION, 0, 0, +- 0, 0, 0, 0); +- if (FFA_VERSION_TO_MAJOR(smc_ret.r0) != FFA_CURRENT_VERSION_MAJOR) { +- dev_err(s->dev, +- "%s: Unsupported FF-A version 0x%lx, expected 0x%x\n", +- __func__, smc_ret.r0, FFA_CURRENT_VERSION); +- ret = -EIO; +- goto err_version; +- } +- +- /* Check that SMC_FC_FFA_MEM_SHARE is implemented */ +- smc_ret = trusty_smc8(SMC_FC_FFA_FEATURES, SMC_FC_FFA_MEM_SHARE, 0, 0, +- 0, 0, 0, 0); +- if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { +- dev_err(s->dev, +- "%s: SMC_FC_FFA_FEATURES(SMC_FC_FFA_MEM_SHARE) failed 0x%lx 0x%lx 0x%lx\n", +- __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); +- ret = -EIO; +- goto err_features; +- } +- +- /* +- * Set FF-A endpoint IDs. +- * +- * Hardcode 0x8000 for the secure os. +- * TODO: Use FF-A call or device tree to configure this dynamically +- */ +- smc_ret = trusty_smc8(SMC_FC_FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0); +- if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { +- dev_err(s->dev, +- "%s: SMC_FC_FFA_ID_GET failed 0x%lx 0x%lx 0x%lx\n", +- __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); +- ret = -EIO; +- goto err_id_get; +- } +- +- s->ffa_local_id = smc_ret.r2; +- s->ffa_remote_id = 0x8000; +- +- s->ffa_tx = kmalloc(PAGE_SIZE, GFP_KERNEL); +- if (!s->ffa_tx) { +- ret = -ENOMEM; +- goto err_alloc_tx; +- } +- tx_paddr = virt_to_phys(s->ffa_tx); +- if (WARN_ON(tx_paddr & (PAGE_SIZE - 1))) { +- ret = -EINVAL; +- goto err_unaligned_tx_buf; +- } +- +- s->ffa_rx = kmalloc(PAGE_SIZE, GFP_KERNEL); +- if (!s->ffa_rx) { +- ret = -ENOMEM; +- goto err_alloc_rx; +- } +- rx_paddr = virt_to_phys(s->ffa_rx); +- if (WARN_ON(rx_paddr & (PAGE_SIZE - 1))) { +- ret = -EINVAL; +- goto err_unaligned_rx_buf; +- } +- +- smc_ret = trusty_smc8(SMC_FCZ_FFA_RXTX_MAP, tx_paddr, rx_paddr, 1, 0, +- 0, 0, 0); +- if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { +- dev_err(s->dev, "%s: SMC_FCZ_FFA_RXTX_MAP failed 0x%lx 0x%lx 0x%lx\n", +- __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); +- ret = -EIO; +- goto err_rxtx_map; +- } +- +- return 0; +- +-err_rxtx_map: +-err_unaligned_rx_buf: +- kfree(s->ffa_rx); +- s->ffa_rx = NULL; +-err_alloc_rx: +-err_unaligned_tx_buf: +- kfree(s->ffa_tx); +- s->ffa_tx = NULL; +-err_alloc_tx: +-err_id_get: +-err_features: +-err_version: +- return ret; +-} +- +-static void trusty_free_msg_buf(struct trusty_state *s, struct device *dev) +-{ +- struct smc_ret8 smc_ret; +- +- smc_ret = trusty_smc8(SMC_FC_FFA_RXTX_UNMAP, 0, 0, 0, 0, 0, 0, 0); +- if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) { +- dev_err(s->dev, "%s: SMC_FC_FFA_RXTX_UNMAP failed 0x%lx 0x%lx 0x%lx\n", +- __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2); +- } else { +- kfree(s->ffa_rx); +- kfree(s->ffa_tx); +- } +-} +- + static void trusty_init_version(struct trusty_state *s, struct device *dev) + { + int ret; +@@ -842,7 +572,6 @@ static int trusty_probe(struct platform_device *pdev) + spin_lock_init(&s->nop_lock); + INIT_LIST_HEAD(&s->nop_queue); + mutex_init(&s->smc_lock); +- mutex_init(&s->share_memory_msg_lock); + ATOMIC_INIT_NOTIFIER_HEAD(&s->notifier); + init_completion(&s->cpu_idle_completion); + +@@ -862,10 +591,6 @@ static int trusty_probe(struct platform_device *pdev) + if (ret < 0) + goto err_api_version; + +- ret = trusty_init_msg_buf(s, &pdev->dev); +- if (ret < 0) +- goto err_init_msg_buf; +- + s->nop_wq = alloc_workqueue("trusty-nop-wq", WQ_CPU_INTENSIVE, 0); + if (!s->nop_wq) { + ret = -ENODEV; +@@ -910,13 +635,10 @@ static int trusty_probe(struct platform_device *pdev) + err_alloc_works: + destroy_workqueue(s->nop_wq); + err_create_nop_wq: +- trusty_free_msg_buf(s, &pdev->dev); +-err_init_msg_buf: + err_api_version: + s->dev->dma_parms = NULL; + kfree(s->version_str); + device_for_each_child(&pdev->dev, NULL, trusty_remove_child); +- mutex_destroy(&s->share_memory_msg_lock); + mutex_destroy(&s->smc_lock); + kfree(s); + err_allocate_state: +@@ -938,9 +660,7 @@ static int trusty_remove(struct platform_device *pdev) + free_percpu(s->nop_works); + destroy_workqueue(s->nop_wq); + +- mutex_destroy(&s->share_memory_msg_lock); + mutex_destroy(&s->smc_lock); +- trusty_free_msg_buf(s, &pdev->dev); + s->dev->dma_parms = NULL; + kfree(s->version_str); + kfree(s); +diff --git a/include/linux/trusty/arm_ffa.h b/include/linux/trusty/arm_ffa.h +deleted file mode 100644 +index ab7b2afb794c..000000000000 +--- a/include/linux/trusty/arm_ffa.h ++++ /dev/null +@@ -1,590 +0,0 @@ +-/* SPDX-License-Identifier: MIT */ +-/* +- * Copyright (C) 2020 Google, Inc. +- * +- * Trusty and TF-A also have a copy of this header. +- * Please keep the copies in sync. +- */ +-#ifndef __LINUX_TRUSTY_ARM_FFA_H +-#define __LINUX_TRUSTY_ARM_FFA_H +- +-/* +- * Subset of Arm PSA Firmware Framework for Arm v8-A 1.0 EAC 1_0 +- * (https://developer.arm.com/docs/den0077/a) needed for shared memory. +- */ +- +-#include "smcall.h" +- +-#ifndef STATIC_ASSERT +-#define STATIC_ASSERT(e) _Static_assert(e, #e) +-#endif +- +-#define FFA_CURRENT_VERSION_MAJOR (1U) +-#define FFA_CURRENT_VERSION_MINOR (0U) +- +-#define FFA_VERSION_TO_MAJOR(version) ((version) >> 16) +-#define FFA_VERSION_TO_MINOR(version) ((version) & (0xffff)) +-#define FFA_VERSION(major, minor) (((major) << 16) | (minor)) +-#define FFA_CURRENT_VERSION \ +- FFA_VERSION(FFA_CURRENT_VERSION_MAJOR, FFA_CURRENT_VERSION_MINOR) +- +-#define SMC_ENTITY_SHARED_MEMORY 4 +- +-#define SMC_FASTCALL_NR_SHARED_MEMORY(nr) \ +- SMC_FASTCALL_NR(SMC_ENTITY_SHARED_MEMORY, nr) +-#define SMC_FASTCALL64_NR_SHARED_MEMORY(nr) \ +- SMC_FASTCALL64_NR(SMC_ENTITY_SHARED_MEMORY, nr) +- +-/** +- * typedef ffa_endpoint_id16_t - Endpoint ID +- * +- * Current implementation only supports VMIDs. FFA spec also support stream +- * endpoint ids. +- */ +-typedef uint16_t ffa_endpoint_id16_t; +- +-/** +- * struct ffa_cons_mrd - Constituent memory region descriptor +- * @address: +- * Start address of contiguous memory region. Must be 4K page aligned. +- * @page_count: +- * Number of 4K pages in region. +- * @reserved_12_15: +- * Reserve bytes 12-15 to pad struct size to 16 bytes. +- */ +-struct ffa_cons_mrd { +- uint64_t address; +- uint32_t page_count; +- uint32_t reserved_12_15; +-}; +-STATIC_ASSERT(sizeof(struct ffa_cons_mrd) == 16); +- +-/** +- * struct ffa_comp_mrd - Composite memory region descriptor +- * @total_page_count: +- * Number of 4k pages in memory region. Must match sum of +- * @address_range_array[].page_count. +- * @address_range_count: +- * Number of entries in @address_range_array. +- * @reserved_8_15: +- * Reserve bytes 8-15 to pad struct size to 16 byte alignment and +- * make @address_range_array 16 byte aligned. +- * @address_range_array: +- * Array of &struct ffa_cons_mrd entries. +- */ +-struct ffa_comp_mrd { +- uint32_t total_page_count; +- uint32_t address_range_count; +- uint64_t reserved_8_15; +- struct ffa_cons_mrd address_range_array[]; +-}; +-STATIC_ASSERT(sizeof(struct ffa_comp_mrd) == 16); +- +-/** +- * typedef ffa_mem_attr8_t - Memory region attributes +- * +- * * @FFA_MEM_ATTR_DEVICE_NGNRNE: +- * Device-nGnRnE. +- * * @FFA_MEM_ATTR_DEVICE_NGNRE: +- * Device-nGnRE. +- * * @FFA_MEM_ATTR_DEVICE_NGRE: +- * Device-nGRE. +- * * @FFA_MEM_ATTR_DEVICE_GRE: +- * Device-GRE. +- * * @FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED +- * Normal memory. Non-cacheable. +- * * @FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB +- * Normal memory. Write-back cached. +- * * @FFA_MEM_ATTR_NON_SHAREABLE +- * Non-shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*. +- * * @FFA_MEM_ATTR_OUTER_SHAREABLE +- * Outer Shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*. +- * * @FFA_MEM_ATTR_INNER_SHAREABLE +- * Inner Shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*. +- */ +-typedef uint8_t ffa_mem_attr8_t; +-#define FFA_MEM_ATTR_DEVICE_NGNRNE ((1U << 4) | (0x0U << 2)) +-#define FFA_MEM_ATTR_DEVICE_NGNRE ((1U << 4) | (0x1U << 2)) +-#define FFA_MEM_ATTR_DEVICE_NGRE ((1U << 4) | (0x2U << 2)) +-#define FFA_MEM_ATTR_DEVICE_GRE ((1U << 4) | (0x3U << 2)) +-#define FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED ((2U << 4) | (0x1U << 2)) +-#define FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB ((2U << 4) | (0x3U << 2)) +-#define FFA_MEM_ATTR_NON_SHAREABLE (0x0U << 0) +-#define FFA_MEM_ATTR_OUTER_SHAREABLE (0x2U << 0) +-#define FFA_MEM_ATTR_INNER_SHAREABLE (0x3U << 0) +- +-/** +- * typedef ffa_mem_perm8_t - Memory access permissions +- * +- * * @FFA_MEM_ATTR_RO +- * Request or specify read-only mapping. +- * * @FFA_MEM_ATTR_RW +- * Request or allow read-write mapping. +- * * @FFA_MEM_PERM_NX +- * Deny executable mapping. +- * * @FFA_MEM_PERM_X +- * Request executable mapping. +- */ +-typedef uint8_t ffa_mem_perm8_t; +-#define FFA_MEM_PERM_RO (1U << 0) +-#define FFA_MEM_PERM_RW (1U << 1) +-#define FFA_MEM_PERM_NX (1U << 2) +-#define FFA_MEM_PERM_X (1U << 3) +- +-/** +- * typedef ffa_mem_flag8_t - Endpoint memory flags +- * +- * * @FFA_MEM_FLAG_OTHER +- * Other borrower. Memory region must not be or was not retrieved on behalf +- * of this endpoint. +- */ +-typedef uint8_t ffa_mem_flag8_t; +-#define FFA_MEM_FLAG_OTHER (1U << 0) +- +-/** +- * typedef ffa_mtd_flag32_t - Memory transaction descriptor flags +- * +- * * @FFA_MTD_FLAG_ZERO_MEMORY +- * Zero memory after unmapping from sender (must be 0 for share). +- * * @FFA_MTD_FLAG_TIME_SLICING +- * Not supported by this implementation. +- * * @FFA_MTD_FLAG_ZERO_MEMORY_AFTER_RELINQUISH +- * Zero memory after unmapping from borrowers (must be 0 for share). +- * * @FFA_MTD_FLAG_TYPE_MASK +- * Bit-mask to extract memory management transaction type from flags. +- * * @FFA_MTD_FLAG_TYPE_SHARE_MEMORY +- * Share memory transaction flag. +- * Used by @SMC_FC_FFA_MEM_RETRIEVE_RESP to indicate that memory came from +- * @SMC_FC_FFA_MEM_SHARE and by @SMC_FC_FFA_MEM_RETRIEVE_REQ to specify that +- * it must have. +- * * @FFA_MTD_FLAG_ADDRESS_RANGE_ALIGNMENT_HINT_MASK +- * Not supported by this implementation. +- */ +-typedef uint32_t ffa_mtd_flag32_t; +-#define FFA_MTD_FLAG_ZERO_MEMORY (1U << 0) +-#define FFA_MTD_FLAG_TIME_SLICING (1U << 1) +-#define FFA_MTD_FLAG_ZERO_MEMORY_AFTER_RELINQUISH (1U << 2) +-#define FFA_MTD_FLAG_TYPE_MASK (3U << 3) +-#define FFA_MTD_FLAG_TYPE_SHARE_MEMORY (1U << 3) +-#define FFA_MTD_FLAG_ADDRESS_RANGE_ALIGNMENT_HINT_MASK (0x1FU << 5) +- +-/** +- * struct ffa_mapd - Memory access permissions descriptor +- * @endpoint_id: +- * Endpoint id that @memory_access_permissions and @flags apply to. +- * (&typedef ffa_endpoint_id16_t). +- * @memory_access_permissions: +- * FFA_MEM_PERM_* values or'ed together (&typedef ffa_mem_perm8_t). +- * @flags: +- * FFA_MEM_FLAG_* values or'ed together (&typedef ffa_mem_flag8_t). +- */ +-struct ffa_mapd { +- ffa_endpoint_id16_t endpoint_id; +- ffa_mem_perm8_t memory_access_permissions; +- ffa_mem_flag8_t flags; +-}; +-STATIC_ASSERT(sizeof(struct ffa_mapd) == 4); +- +-/** +- * struct ffa_emad - Endpoint memory access descriptor. +- * @mapd: &struct ffa_mapd. +- * @comp_mrd_offset: +- * Offset of &struct ffa_comp_mrd form start of &struct ffa_mtd. +- * @reserved_8_15: +- * Reserved bytes 8-15. Must be 0. +- */ +-struct ffa_emad { +- struct ffa_mapd mapd; +- uint32_t comp_mrd_offset; +- uint64_t reserved_8_15; +-}; +-STATIC_ASSERT(sizeof(struct ffa_emad) == 16); +- +-/** +- * struct ffa_mtd - Memory transaction descriptor. +- * @sender_id: +- * Sender endpoint id. +- * @memory_region_attributes: +- * FFA_MEM_ATTR_* values or'ed together (&typedef ffa_mem_attr8_t). +- * @reserved_3: +- * Reserved bytes 3. Must be 0. +- * @flags: +- * FFA_MTD_FLAG_* values or'ed together (&typedef ffa_mtd_flag32_t). +- * @handle: +- * Id of shared memory object. Most be 0 for MEM_SHARE. +- * @tag: Client allocated tag. Must match original value. +- * @reserved_24_27: +- * Reserved bytes 24-27. Must be 0. +- * @emad_count: +- * Number of entries in @emad. Must be 1 in current implementation. +- * FFA spec allows more entries. +- * @emad: +- * Endpoint memory access descriptor array (see @struct ffa_emad). +- */ +-struct ffa_mtd { +- ffa_endpoint_id16_t sender_id; +- ffa_mem_attr8_t memory_region_attributes; +- uint8_t reserved_3; +- ffa_mtd_flag32_t flags; +- uint64_t handle; +- uint64_t tag; +- uint32_t reserved_24_27; +- uint32_t emad_count; +- struct ffa_emad emad[]; +-}; +-STATIC_ASSERT(sizeof(struct ffa_mtd) == 32); +- +-/** +- * struct ffa_mem_relinquish_descriptor - Relinquish request descriptor. +- * @handle: +- * Id of shared memory object to relinquish. +- * @flags: +- * If bit 0 is set clear memory after unmapping from borrower. Must be 0 +- * for share. Bit[1]: Time slicing. Not supported, must be 0. All other +- * bits are reserved 0. +- * @endpoint_count: +- * Number of entries in @endpoint_array. +- * @endpoint_array: +- * Array of endpoint ids. +- */ +-struct ffa_mem_relinquish_descriptor { +- uint64_t handle; +- uint32_t flags; +- uint32_t endpoint_count; +- ffa_endpoint_id16_t endpoint_array[]; +-}; +-STATIC_ASSERT(sizeof(struct ffa_mem_relinquish_descriptor) == 16); +- +-/** +- * enum ffa_error - FF-A error code +- * @FFA_ERROR_NOT_SUPPORTED: +- * Operation contained possibly valid parameters not supported by the +- * current implementation. Does not match FF-A 1.0 EAC 1_0 definition. +- * @FFA_ERROR_INVALID_PARAMETERS: +- * Invalid parameters. Conditions function specific. +- * @FFA_ERROR_NO_MEMORY: +- * Not enough memory. +- * @FFA_ERROR_DENIED: +- * Operation not allowed. Conditions function specific. +- * +- * FF-A 1.0 EAC 1_0 defines other error codes as well but the current +- * implementation does not use them. +- */ +-enum ffa_error { +- FFA_ERROR_NOT_SUPPORTED = -1, +- FFA_ERROR_INVALID_PARAMETERS = -2, +- FFA_ERROR_NO_MEMORY = -3, +- FFA_ERROR_DENIED = -6, +-}; +- +-/** +- * SMC_FC32_FFA_MIN - First 32 bit SMC opcode reserved for FFA +- */ +-#define SMC_FC32_FFA_MIN SMC_FASTCALL_NR_SHARED_MEMORY(0x60) +- +-/** +- * SMC_FC32_FFA_MAX - Last 32 bit SMC opcode reserved for FFA +- */ +-#define SMC_FC32_FFA_MAX SMC_FASTCALL_NR_SHARED_MEMORY(0x7F) +- +-/** +- * SMC_FC64_FFA_MIN - First 64 bit SMC opcode reserved for FFA +- */ +-#define SMC_FC64_FFA_MIN SMC_FASTCALL64_NR_SHARED_MEMORY(0x60) +- +-/** +- * SMC_FC64_FFA_MAX - Last 64 bit SMC opcode reserved for FFA +- */ +-#define SMC_FC64_FFA_MAX SMC_FASTCALL64_NR_SHARED_MEMORY(0x7F) +- +-/** +- * SMC_FC_FFA_ERROR - SMC error return opcode +- * +- * Register arguments: +- * +- * * w1: VMID in [31:16], vCPU in [15:0] +- * * w2: Error code (&enum ffa_error) +- */ +-#define SMC_FC_FFA_ERROR SMC_FASTCALL_NR_SHARED_MEMORY(0x60) +- +-/** +- * SMC_FC_FFA_SUCCESS - 32 bit SMC success return opcode +- * +- * Register arguments: +- * +- * * w1: VMID in [31:16], vCPU in [15:0] +- * * w2-w7: Function specific +- */ +-#define SMC_FC_FFA_SUCCESS SMC_FASTCALL_NR_SHARED_MEMORY(0x61) +- +-/** +- * SMC_FC64_FFA_SUCCESS - 64 bit SMC success return opcode +- * +- * Register arguments: +- * +- * * w1: VMID in [31:16], vCPU in [15:0] +- * * w2/x2-w7/x7: Function specific +- */ +-#define SMC_FC64_FFA_SUCCESS SMC_FASTCALL64_NR_SHARED_MEMORY(0x61) +- +-/** +- * SMC_FC_FFA_VERSION - SMC opcode to return supported FF-A version +- * +- * Register arguments: +- * +- * * w1: Major version bit[30:16] and minor version in bit[15:0] supported +- * by caller. Bit[31] must be 0. +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- * * w2: Major version bit[30:16], minor version in bit[15:0], bit[31] must +- * be 0. +- * +- * or +- * +- * * w0: SMC_FC_FFA_ERROR +- * * w2: FFA_ERROR_NOT_SUPPORTED if major version passed in is less than the +- * minimum major version supported. +- */ +-#define SMC_FC_FFA_VERSION SMC_FASTCALL_NR_SHARED_MEMORY(0x63) +- +-/** +- * SMC_FC_FFA_FEATURES - SMC opcode to check optional feature support +- * +- * Register arguments: +- * +- * * w1: FF-A function ID +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- * * w2: Bit[0]: Supports custom buffers for memory transactions. +- * Bit[1:0]: For RXTX_MAP min buffer size and alignment boundary. +- * Other bits must be 0. +- * * w3: For FFA_MEM_RETRIEVE_REQ, bit[7-0]: Number of times receiver can +- * retrieve each memory region before relinquishing it specified as +- * ((1U << (value + 1)) - 1 (or value = bits in reference count - 1). +- * For all other bits and commands: must be 0. +- * or +- * +- * * w0: SMC_FC_FFA_ERROR +- * * w2: FFA_ERROR_NOT_SUPPORTED if function is not implemented, or +- * FFA_ERROR_INVALID_PARAMETERS if function id is not valid. +- */ +-#define SMC_FC_FFA_FEATURES SMC_FASTCALL_NR_SHARED_MEMORY(0x64) +- +-/** +- * SMC_FC_FFA_RXTX_MAP - 32 bit SMC opcode to map message buffers +- * +- * Register arguments: +- * +- * * w1: TX address +- * * w2: RX address +- * * w3: RX/TX page count in bit[5:0] +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- */ +-#define SMC_FC_FFA_RXTX_MAP SMC_FASTCALL_NR_SHARED_MEMORY(0x66) +- +-/** +- * SMC_FC64_FFA_RXTX_MAP - 64 bit SMC opcode to map message buffers +- * +- * Register arguments: +- * +- * * x1: TX address +- * * x2: RX address +- * * x3: RX/TX page count in bit[5:0] +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- */ +-#define SMC_FC64_FFA_RXTX_MAP SMC_FASTCALL64_NR_SHARED_MEMORY(0x66) +-#ifdef CONFIG_64BIT +-#define SMC_FCZ_FFA_RXTX_MAP SMC_FC64_FFA_RXTX_MAP +-#else +-#define SMC_FCZ_FFA_RXTX_MAP SMC_FC_FFA_RXTX_MAP +-#endif +- +-/** +- * SMC_FC_FFA_RXTX_UNMAP - SMC opcode to unmap message buffers +- * +- * Register arguments: +- * +- * * w1: ID in [31:16] +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- */ +-#define SMC_FC_FFA_RXTX_UNMAP SMC_FASTCALL_NR_SHARED_MEMORY(0x67) +- +-/** +- * SMC_FC_FFA_ID_GET - SMC opcode to get endpoint id of caller +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- * * w2: ID in bit[15:0], bit[31:16] must be 0. +- */ +-#define SMC_FC_FFA_ID_GET SMC_FASTCALL_NR_SHARED_MEMORY(0x69) +- +-/** +- * SMC_FC_FFA_MEM_DONATE - 32 bit SMC opcode to donate memory +- * +- * Not supported. +- */ +-#define SMC_FC_FFA_MEM_DONATE SMC_FASTCALL_NR_SHARED_MEMORY(0x71) +- +-/** +- * SMC_FC_FFA_MEM_LEND - 32 bit SMC opcode to lend memory +- * +- * Not currently supported. +- */ +-#define SMC_FC_FFA_MEM_LEND SMC_FASTCALL_NR_SHARED_MEMORY(0x72) +- +-/** +- * SMC_FC_FFA_MEM_SHARE - 32 bit SMC opcode to share memory +- * +- * Register arguments: +- * +- * * w1: Total length +- * * w2: Fragment length +- * * w3: Address +- * * w4: Page count +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- * * w2/w3: Handle +- * +- * or +- * +- * * w0: &SMC_FC_FFA_MEM_FRAG_RX +- * * w1-: See &SMC_FC_FFA_MEM_FRAG_RX +- * +- * or +- * +- * * w0: SMC_FC_FFA_ERROR +- * * w2: Error code (&enum ffa_error) +- */ +-#define SMC_FC_FFA_MEM_SHARE SMC_FASTCALL_NR_SHARED_MEMORY(0x73) +- +-/** +- * SMC_FC64_FFA_MEM_SHARE - 64 bit SMC opcode to share memory +- * +- * Register arguments: +- * +- * * w1: Total length +- * * w2: Fragment length +- * * x3: Address +- * * w4: Page count +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- * * w2/w3: Handle +- * +- * or +- * +- * * w0: &SMC_FC_FFA_MEM_FRAG_RX +- * * w1-: See &SMC_FC_FFA_MEM_FRAG_RX +- * +- * or +- * +- * * w0: SMC_FC_FFA_ERROR +- * * w2: Error code (&enum ffa_error) +- */ +-#define SMC_FC64_FFA_MEM_SHARE SMC_FASTCALL64_NR_SHARED_MEMORY(0x73) +- +-/** +- * SMC_FC_FFA_MEM_RETRIEVE_REQ - 32 bit SMC opcode to retrieve shared memory +- * +- * Register arguments: +- * +- * * w1: Total length +- * * w2: Fragment length +- * * w3: Address +- * * w4: Page count +- * +- * Return: +- * * w0: &SMC_FC_FFA_MEM_RETRIEVE_RESP +- * * w1/x1-w5/x5: See &SMC_FC_FFA_MEM_RETRIEVE_RESP +- */ +-#define SMC_FC_FFA_MEM_RETRIEVE_REQ SMC_FASTCALL_NR_SHARED_MEMORY(0x74) +- +-/** +- * SMC_FC64_FFA_MEM_RETRIEVE_REQ - 64 bit SMC opcode to retrieve shared memory +- * +- * Register arguments: +- * +- * * w1: Total length +- * * w2: Fragment length +- * * x3: Address +- * * w4: Page count +- * +- * Return: +- * * w0: &SMC_FC_FFA_MEM_RETRIEVE_RESP +- * * w1/x1-w5/x5: See &SMC_FC_FFA_MEM_RETRIEVE_RESP +- */ +-#define SMC_FC64_FFA_MEM_RETRIEVE_REQ SMC_FASTCALL64_NR_SHARED_MEMORY(0x74) +- +-/** +- * SMC_FC_FFA_MEM_RETRIEVE_RESP - Retrieve 32 bit SMC return opcode +- * +- * Register arguments: +- * +- * * w1: Total length +- * * w2: Fragment length +- */ +-#define SMC_FC_FFA_MEM_RETRIEVE_RESP SMC_FASTCALL_NR_SHARED_MEMORY(0x75) +- +-/** +- * SMC_FC_FFA_MEM_RELINQUISH - SMC opcode to relinquish shared memory +- * +- * Input in &struct ffa_mem_relinquish_descriptor format in message buffer. +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- */ +-#define SMC_FC_FFA_MEM_RELINQUISH SMC_FASTCALL_NR_SHARED_MEMORY(0x76) +- +-/** +- * SMC_FC_FFA_MEM_RECLAIM - SMC opcode to reclaim shared memory +- * +- * Register arguments: +- * +- * * w1/w2: Handle +- * * w3: Flags +- * +- * Return: +- * * w0: &SMC_FC_FFA_SUCCESS +- */ +-#define SMC_FC_FFA_MEM_RECLAIM SMC_FASTCALL_NR_SHARED_MEMORY(0x77) +- +-/** +- * SMC_FC_FFA_MEM_FRAG_RX - SMC opcode to request next fragment. +- * +- * Register arguments: +- * +- * * w1/w2: Cookie +- * * w3: Fragment offset. +- * * w4: Endpoint id ID in [31:16], if client is hypervisor. +- * +- * Return: +- * * w0: &SMC_FC_FFA_MEM_FRAG_TX +- * * w1/x1-w5/x5: See &SMC_FC_FFA_MEM_FRAG_TX +- */ +-#define SMC_FC_FFA_MEM_FRAG_RX SMC_FASTCALL_NR_SHARED_MEMORY(0x7A) +- +-/** +- * SMC_FC_FFA_MEM_FRAG_TX - SMC opcode to transmit next fragment +- * +- * Register arguments: +- * +- * * w1/w2: Cookie +- * * w3: Fragment length. +- * * w4: Sender endpoint id ID in [31:16], if client is hypervisor. +- * +- * Return: +- * * w0: &SMC_FC_FFA_MEM_FRAG_RX or &SMC_FC_FFA_SUCCESS. +- * * w1/x1-w5/x5: See opcode in w0. +- */ +-#define SMC_FC_FFA_MEM_FRAG_TX SMC_FASTCALL_NR_SHARED_MEMORY(0x7B) +- +-#endif /* __LINUX_TRUSTY_ARM_FFA_H */ +diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h +index efbb36999a8b..272d96c1c696 100644 +--- a/include/linux/trusty/trusty.h ++++ b/include/linux/trusty/trusty.h +@@ -52,9 +52,6 @@ u32 trusty_get_api_version(struct device *dev); + bool trusty_get_panic_status(struct device *dev); + + struct ns_mem_page_info { +- u64 paddr; +- u8 ffa_mem_attr; +- u8 ffa_mem_perm; + u64 compat_attr; + }; + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0037-ANDROID-trusty-Rename-transfer-memory-function-to-le.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0037-ANDROID-trusty-Rename-transfer-memory-function-to-le.patch new file mode 100644 index 00000000..a7bc0600 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0037-ANDROID-trusty-Rename-transfer-memory-function-to-le.patch @@ -0,0 +1,191 @@ +From 804ef860d9757cbe31b606fd5ec68cc5454c88f8 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Tue, 18 Jan 2022 18:27:09 +0000 +Subject: [PATCH 24/32] ANDROID: trusty: Rename transfer memory function to + lend memory + +Renaming trusty_transfer_memory to trusty_lend_memory allows Trusty +to export memory operation like share, lend, reclaim and use common +code for memory share and lend operations. + +Define TRUSTY_DEFAULT_MEM_OBJ_TAG as 0 and use that in existing calls. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ie165a609cc4398bb916967595d0b748d54d75faf +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/trusty-ipc.c | 14 ++++++++---- + drivers/trusty/trusty-test.c | 3 ++- + drivers/trusty/trusty-virtio.c | 3 ++- + drivers/trusty/trusty.c | 41 ++++++++++++++++++++++------------ + include/linux/trusty/trusty.h | 11 ++++----- + 5 files changed, 47 insertions(+), 25 deletions(-) + +diff --git a/drivers/trusty/trusty-ipc.c b/drivers/trusty/trusty-ipc.c +index 82d6ddeb41f4..0a27af2063a7 100644 +--- a/drivers/trusty/trusty-ipc.c ++++ b/drivers/trusty/trusty-ipc.c +@@ -1233,10 +1233,16 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd, + goto cleanup_handle; + } + +- ret = trusty_transfer_memory(tipc_shared_handle_dev(shared_handle), +- &mem_id, shared_handle->sgt->sgl, +- shared_handle->sgt->orig_nents, prot, tag, +- lend); ++ if (lend) ++ ret = trusty_lend_memory(tipc_shared_handle_dev(shared_handle), ++ &mem_id, shared_handle->sgt->sgl, ++ shared_handle->sgt->orig_nents, prot, ++ tag); ++ else ++ ret = trusty_share_memory(tipc_shared_handle_dev(shared_handle), ++ &mem_id, shared_handle->sgt->sgl, ++ shared_handle->sgt->orig_nents, prot, ++ tag); + + if (ret < 0) { + dev_dbg(dev, "Transferring memory failed: %d\n", ret); +diff --git a/drivers/trusty/trusty-test.c b/drivers/trusty/trusty-test.c +index 844868981fa5..c25fc0f2fcf0 100644 +--- a/drivers/trusty/trusty-test.c ++++ b/drivers/trusty/trusty-test.c +@@ -138,7 +138,8 @@ static int trusty_test_share_objs(struct trusty_test_state *s, + t1 = ktime_get(); + tmpret = trusty_share_memory(s->trusty_dev, &obj->mem_id, + obj->sgt.sgl, obj->sgt.nents, +- PAGE_KERNEL); ++ PAGE_KERNEL, ++ TRUSTY_DEFAULT_MEM_OBJ_TAG); + t2 = ktime_get(); + if (tmpret) { + ret = tmpret; +diff --git a/drivers/trusty/trusty-virtio.c b/drivers/trusty/trusty-virtio.c +index fea59cd2e218..365e7c04bcf4 100644 +--- a/drivers/trusty/trusty-virtio.c ++++ b/drivers/trusty/trusty-virtio.c +@@ -626,7 +626,8 @@ static int trusty_virtio_add_devices(struct trusty_ctx *tctx) + + sg_init_one(&tctx->shared_sg, descr_va, descr_buf_sz); + ret = trusty_share_memory(tctx->dev->parent, &descr_id, +- &tctx->shared_sg, 1, PAGE_KERNEL); ++ &tctx->shared_sg, 1, PAGE_KERNEL, ++ TRUSTY_DEFAULT_MEM_OBJ_TAG); + if (ret) { + dev_err(tctx->dev, "trusty_share_memory failed: %d\n", ret); + goto err_share_memory; +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 2dec75398f69..6bd30bc1bbc9 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -222,18 +222,9 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2) + } + EXPORT_SYMBOL(trusty_std_call32); + +-int trusty_share_memory(struct device *dev, u64 *id, +- struct scatterlist *sglist, unsigned int nents, +- pgprot_t pgprot) +-{ +- return trusty_transfer_memory(dev, id, sglist, nents, pgprot, 0, +- false); +-} +-EXPORT_SYMBOL(trusty_share_memory); +- +-int trusty_transfer_memory(struct device *dev, u64 *id, +- struct scatterlist *sglist, unsigned int nents, +- pgprot_t pgprot, u64 tag, bool lend) ++static int __trusty_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag, bool mem_share) + { + struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); + int ret; +@@ -253,6 +244,12 @@ int trusty_transfer_memory(struct device *dev, u64 *id, + return -EOPNOTSUPP; + } + ++ if (mem_share == false && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { ++ dev_err(s->dev, "%s: old trusty version does not support lending memory objects\n", ++ __func__); ++ return -EOPNOTSUPP; ++ } ++ + count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); + if (count != nents) { + dev_err(s->dev, "failed to dma map sg_table\n"); +@@ -271,7 +268,22 @@ int trusty_transfer_memory(struct device *dev, u64 *id, + *id = pg_inf.compat_attr; + return 0; + } +-EXPORT_SYMBOL(trusty_transfer_memory); ++ ++int trusty_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag) ++{ ++ return __trusty_share_memory(dev, id, sglist, nents, pgprot, tag, true); ++} ++EXPORT_SYMBOL(trusty_share_memory); ++ ++int trusty_lend_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag) ++{ ++ return __trusty_share_memory(dev, id, sglist, nents, pgprot, tag, false); ++} ++EXPORT_SYMBOL(trusty_lend_memory); + + /* + * trusty_share_memory_compat - trusty_share_memory wrapper for old apis +@@ -287,7 +299,8 @@ int trusty_share_memory_compat(struct device *dev, u64 *id, + int ret; + struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); + +- ret = trusty_share_memory(dev, id, sglist, nents, pgprot); ++ ret = trusty_share_memory(dev, id, sglist, nents, pgprot, ++ TRUSTY_DEFAULT_MEM_OBJ_TAG); + if (!ret && s->api_version < TRUSTY_API_VERSION_PHYS_MEM_OBJ) + *id &= 0x0000FFFFFFFFF000ull; + +diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h +index 272d96c1c696..27f635f2d12d 100644 +--- a/include/linux/trusty/trusty.h ++++ b/include/linux/trusty/trusty.h +@@ -11,6 +11,7 @@ + #include + #include + ++#define TRUSTY_DEFAULT_MEM_OBJ_TAG (0) + + #if IS_ENABLED(CONFIG_TRUSTY) + s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2); +@@ -62,13 +63,13 @@ struct scatterlist; + typedef u64 trusty_shared_mem_id_t; + int trusty_share_memory(struct device *dev, trusty_shared_mem_id_t *id, + struct scatterlist *sglist, unsigned int nents, +- pgprot_t pgprot); ++ pgprot_t pgprot, u64 tag); + int trusty_share_memory_compat(struct device *dev, trusty_shared_mem_id_t *id, + struct scatterlist *sglist, unsigned int nents, + pgprot_t pgprot); +-int trusty_transfer_memory(struct device *dev, u64 *id, +- struct scatterlist *sglist, unsigned int nents, +- pgprot_t pgprot, u64 tag, bool lend); ++int trusty_lend_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag); + int trusty_reclaim_memory(struct device *dev, trusty_shared_mem_id_t id, + struct scatterlist *sglist, unsigned int nents); + +@@ -78,7 +79,7 @@ u64 trusty_dma_buf_get_ffa_tag(struct dma_buf *dma_buf); + #else + static inline u64 trusty_dma_buf_get_ffa_tag(struct dma_buf *dma_buf) + { +- return 0; ++ return TRUSTY_DEFAULT_MEM_OBJ_TAG; + } + #endif + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0038-ANDROID-trusty-Separate-out-SMC-based-transport.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0038-ANDROID-trusty-Separate-out-SMC-based-transport.patch new file mode 100644 index 00000000..c4ff31c0 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0038-ANDROID-trusty-Separate-out-SMC-based-transport.patch @@ -0,0 +1,495 @@ +From 844cdefb8b0f6b1f75cf4cbaa2d9260959a26e02 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 14 Jan 2022 14:02:39 +0000 +Subject: [PATCH 25/32] ANDROID: trusty: Separate out SMC based transport + +This commit refactors SMC based transport operation like +smc_fastcalls, smc memory operations in a separate file. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Iebee505b7172f6247186e3bf1e0b50740b2e4dfa +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/Makefile | 1 + + drivers/trusty/trusty-private.h | 61 ++++++++++++++ + drivers/trusty/trusty-smc.c | 136 ++++++++++++++++++++++++++++++ + drivers/trusty/trusty.c | 144 +++++++++----------------------- + 4 files changed, 237 insertions(+), 105 deletions(-) + create mode 100644 drivers/trusty/trusty-private.h + create mode 100644 drivers/trusty/trusty-smc.c + +diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile +index 2cf1cfccf97b..fbb53ee93003 100644 +--- a/drivers/trusty/Makefile ++++ b/drivers/trusty/Makefile +@@ -5,6 +5,7 @@ + + obj-$(CONFIG_TRUSTY) += trusty-core.o + trusty-core-objs += trusty.o trusty-mem.o ++trusty-core-objs += trusty-smc.o + trusty-core-$(CONFIG_ARM) += trusty-smc-arm.o + trusty-core-$(CONFIG_ARM64) += trusty-smc-arm64.o + obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o +diff --git a/drivers/trusty/trusty-private.h b/drivers/trusty/trusty-private.h +new file mode 100644 +index 000000000000..4d73c6ae35d4 +--- /dev/null ++++ b/drivers/trusty/trusty-private.h +@@ -0,0 +1,61 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2022 ARM Ltd. ++ */ ++ ++#ifndef _TRUSTY_PRIVATE_H ++#define _TRUSTY_PRIVATE_H ++ ++#include ++ ++struct trusty_work { ++ struct trusty_state *ts; ++ struct work_struct work; ++}; ++ ++struct trusty_msg_ops { ++ u32 (*send_direct_msg)(struct device *dev, unsigned long fid, ++ unsigned long a0, unsigned long a1, ++ unsigned long a2); ++}; ++ ++struct trusty_mem_ops { ++ int (*trusty_share_memory)(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, u64 tag); ++ int (*trusty_lend_memory)(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, u64 tag); ++ int (*trusty_reclaim_memory)(struct device *dev, u64 id, ++ struct scatterlist *sglist, ++ unsigned int nents); ++}; ++ ++struct trusty_state { ++ struct mutex smc_lock; ++ struct atomic_notifier_head notifier; ++ struct completion cpu_idle_completion; ++ char *version_str; ++ u32 api_version; ++ bool trusty_panicked; ++ struct device *dev; ++ struct workqueue_struct *nop_wq; ++ struct trusty_work __percpu *nop_works; ++ struct list_head nop_queue; ++ spinlock_t nop_lock; /* protects nop_queue */ ++ struct device_dma_parameters dma_parms; ++ const struct trusty_msg_ops *msg_ops; ++ const struct trusty_mem_ops *mem_ops; ++}; ++ ++int trusty_init_api_version(struct trusty_state *s, struct device *dev, ++ u32 (*send_direct_msg)(struct device *dev, ++ unsigned long fid, ++ unsigned long a0, ++ unsigned long a1, ++ unsigned long a2)); ++ ++int trusty_smc_transport_setup(struct device *dev); ++void trusty_smc_transport_cleanup(struct device *dev); ++ ++#endif /* _TRUSTY_PRIVATE_H */ +diff --git a/drivers/trusty/trusty-smc.c b/drivers/trusty/trusty-smc.c +new file mode 100644 +index 000000000000..8fa841e0e253 +--- /dev/null ++++ b/drivers/trusty/trusty-smc.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2013 Google, Inc. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "trusty-smc.h" ++#include "trusty-private.h" ++ ++static u32 trusty_smc_send_direct_msg(struct device *dev, unsigned long fid, ++ unsigned long a0, unsigned long a1, ++ unsigned long a2) ++{ ++ return trusty_smc8(fid, a0, a1, a2, 0, 0, 0, 0).r0; ++} ++ ++static int trusty_smc_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, u64 tag) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ int ret; ++ struct ns_mem_page_info pg_inf; ++ struct scatterlist *sg; ++ size_t count; ++ ++ if (WARN_ON(nents < 1)) ++ return -EINVAL; ++ ++ if (nents != 1) { ++ dev_err(s->dev, "%s: old trusty version does not support " ++ "non-contiguous memory objects\n", __func__); ++ return -EOPNOTSUPP; ++ } ++ ++ count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ if (count != nents) { ++ dev_err(s->dev, "failed to dma map sg_table\n"); ++ return -EINVAL; ++ } ++ ++ sg = sglist; ++ ret = trusty_encode_page_info(&pg_inf, phys_to_page(sg_dma_address(sg)), ++ pgprot); ++ if (ret) { ++ dev_err(s->dev, "%s: trusty_encode_page_info failed\n", ++ __func__); ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ return ret; ++ } ++ ++ *id = pg_inf.compat_attr; ++ return 0; ++} ++ ++static int trusty_smc_lend_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, u64 tag) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static int trusty_smc_reclaim_memory(struct device *dev, u64 id, ++ struct scatterlist *sglist, ++ unsigned int nents) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (WARN_ON(nents < 1)) ++ return -EINVAL; ++ ++ if (WARN_ON(s->api_version >= TRUSTY_API_VERSION_MEM_OBJ)) ++ return -EINVAL; ++ ++ if (nents != 1) { ++ dev_err(s->dev, "%s: not supported\n", __func__); ++ return -EOPNOTSUPP; ++ } ++ ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ ++ dev_dbg(s->dev, "%s: done\n", __func__); ++ return 0; ++} ++ ++static const struct trusty_msg_ops trusty_smc_msg_ops = { ++ .send_direct_msg = &trusty_smc_send_direct_msg, ++}; ++ ++static const struct trusty_mem_ops trusty_smc_mem_ops = { ++ .trusty_share_memory = &trusty_smc_share_memory, ++ .trusty_lend_memory = &trusty_smc_lend_memory, ++ .trusty_reclaim_memory = &trusty_smc_reclaim_memory, ++}; ++ ++int trusty_smc_transport_setup(struct device *dev) ++{ ++ int rc; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ rc = trusty_init_api_version(s, dev, &trusty_smc_send_direct_msg); ++ if (rc != 0) { ++ return rc; ++ } ++ ++ /* ++ * Initialize Trusty msg calls with Trusty SMC ABI ++ */ ++ s->msg_ops = &trusty_smc_msg_ops; ++ ++ /* ++ * Initialize Trusty memory operations with Trusty SMC ABI only when ++ * Trusty API version is below TRUSTY_API_VERSION_MEM_OBJ. ++ */ ++ if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) ++ s->mem_ops = &trusty_smc_mem_ops; ++ ++ return 0; ++} ++ ++void trusty_smc_transport_cleanup(struct device *dev) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (s->msg_ops == &trusty_smc_msg_ops) ++ s->msg_ops = NULL; ++ ++ if (s->mem_ops == &trusty_smc_mem_ops) ++ s->mem_ops = NULL; ++} +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 6bd30bc1bbc9..0486827a45ca 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -18,37 +18,10 @@ + #include + #include + +-#include "trusty-smc.h" ++#include "trusty-private.h" + +-struct trusty_state; + static struct platform_driver trusty_driver; + +-struct trusty_work { +- struct trusty_state *ts; +- struct work_struct work; +-}; +- +-struct trusty_state { +- struct mutex smc_lock; +- struct atomic_notifier_head notifier; +- struct completion cpu_idle_completion; +- char *version_str; +- u32 api_version; +- bool trusty_panicked; +- struct device *dev; +- struct workqueue_struct *nop_wq; +- struct trusty_work __percpu *nop_works; +- struct list_head nop_queue; +- spinlock_t nop_lock; /* protects nop_queue */ +- struct device_dma_parameters dma_parms; +-}; +- +-static inline unsigned long smc(unsigned long r0, unsigned long r1, +- unsigned long r2, unsigned long r3) +-{ +- return trusty_smc8(r0, r1, r2, r3, 0, 0, 0, 0).r0; +-} +- + s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2) + { + struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); +@@ -60,7 +33,7 @@ s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2) + if (WARN_ON(SMC_IS_SMC64(smcnr))) + return SM_ERR_INVALID_PARAMETERS; + +- return smc(smcnr, a0, a1, a2); ++ return s->msg_ops->send_direct_msg(dev, smcnr, a0, a1, a2); + } + EXPORT_SYMBOL(trusty_fast_call32); + +@@ -76,7 +49,7 @@ s64 trusty_fast_call64(struct device *dev, u64 smcnr, u64 a0, u64 a1, u64 a2) + if (WARN_ON(!SMC_IS_SMC64(smcnr))) + return SM_ERR_INVALID_PARAMETERS; + +- return smc(smcnr, a0, a1, a2); ++ return s->msg_ops->send_direct_msg(dev, smcnr, a0, a1, a2); + } + EXPORT_SYMBOL(trusty_fast_call64); + #endif +@@ -88,13 +61,16 @@ static unsigned long trusty_std_call_inner(struct device *dev, + { + unsigned long ret; + int retry = 5; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); + + dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx)\n", + __func__, smcnr, a0, a1, a2); + while (true) { +- ret = smc(smcnr, a0, a1, a2); ++ ret = s->msg_ops->send_direct_msg(dev, smcnr, a0, a1, a2); + while ((s32)ret == SM_ERR_FIQ_INTERRUPTED) +- ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0); ++ ret = s->msg_ops->send_direct_msg(dev, ++ SMC_SC_RESTART_FIQ, ++ 0, 0, 0); + if ((int)ret != SM_ERR_BUSY || !retry) + break; + +@@ -222,58 +198,17 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2) + } + EXPORT_SYMBOL(trusty_std_call32); + +-static int __trusty_share_memory(struct device *dev, u64 *id, +- struct scatterlist *sglist, unsigned int nents, +- pgprot_t pgprot, u64 tag, bool mem_share) ++int trusty_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, unsigned int nents, ++ pgprot_t pgprot, u64 tag) + { + struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); +- int ret; +- struct ns_mem_page_info pg_inf; +- struct scatterlist *sg; +- size_t count; + + if (WARN_ON(dev->driver != &trusty_driver.driver)) + return -EINVAL; + +- if (WARN_ON(nents < 1)) +- return -EINVAL; +- +- if (nents != 1 && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { +- dev_err(s->dev, "%s: old trusty version does not support non-contiguous memory objects\n", +- __func__); +- return -EOPNOTSUPP; +- } +- +- if (mem_share == false && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { +- dev_err(s->dev, "%s: old trusty version does not support lending memory objects\n", +- __func__); +- return -EOPNOTSUPP; +- } +- +- count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); +- if (count != nents) { +- dev_err(s->dev, "failed to dma map sg_table\n"); +- return -EINVAL; +- } +- +- sg = sglist; +- ret = trusty_encode_page_info(&pg_inf, phys_to_page(sg_dma_address(sg)), +- pgprot); +- if (ret) { +- dev_err(s->dev, "%s: trusty_encode_page_info failed\n", +- __func__); +- return ret; +- } +- +- *id = pg_inf.compat_attr; +- return 0; +-} +- +-int trusty_share_memory(struct device *dev, u64 *id, +- struct scatterlist *sglist, unsigned int nents, +- pgprot_t pgprot, u64 tag) +-{ +- return __trusty_share_memory(dev, id, sglist, nents, pgprot, tag, true); ++ return s->mem_ops->trusty_share_memory(dev, id, sglist, nents, pgprot, ++ tag); + } + EXPORT_SYMBOL(trusty_share_memory); + +@@ -281,7 +216,13 @@ int trusty_lend_memory(struct device *dev, u64 *id, + struct scatterlist *sglist, unsigned int nents, + pgprot_t pgprot, u64 tag) + { +- return __trusty_share_memory(dev, id, sglist, nents, pgprot, tag, false); ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ if (WARN_ON(dev->driver != &trusty_driver.driver)) ++ return -EINVAL; ++ ++ return s->mem_ops->trusty_lend_memory(dev, id, sglist, nents, pgprot, ++ tag); + } + EXPORT_SYMBOL(trusty_lend_memory); + +@@ -316,22 +257,7 @@ int trusty_reclaim_memory(struct device *dev, u64 id, + if (WARN_ON(dev->driver != &trusty_driver.driver)) + return -EINVAL; + +- if (WARN_ON(nents < 1)) +- return -EINVAL; +- +- if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { +- if (nents != 1) { +- dev_err(s->dev, "%s: not supported\n", __func__); +- return -EOPNOTSUPP; +- } +- +- dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); +- +- dev_dbg(s->dev, "%s: done\n", __func__); +- return 0; +- } +- +- return 0; ++ return s->mem_ops->trusty_reclaim_memory(dev, id, sglist, nents); + } + EXPORT_SYMBOL(trusty_reclaim_memory); + +@@ -382,7 +308,7 @@ const char *trusty_version_str_get(struct device *dev) + } + EXPORT_SYMBOL(trusty_version_str_get); + +-static void trusty_init_version(struct trusty_state *s, struct device *dev) ++static void trusty_init_version_str(struct trusty_state *s, struct device *dev) + { + int ret; + int i; +@@ -430,12 +356,17 @@ bool trusty_get_panic_status(struct device *dev) + } + EXPORT_SYMBOL(trusty_get_panic_status); + +-static int trusty_init_api_version(struct trusty_state *s, struct device *dev) ++int trusty_init_api_version(struct trusty_state *s, struct device *dev, ++ u32 (*send_direct_msg)(struct device *dev, ++ unsigned long fid, ++ unsigned long a0, ++ unsigned long a1, ++ unsigned long a2)) + { + u32 api_version; + +- api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION, +- TRUSTY_API_VERSION_CURRENT, 0, 0); ++ api_version = send_direct_msg(dev, SMC_FC_API_VERSION, ++ TRUSTY_API_VERSION_CURRENT, 0, 0); + if (api_version == SM_ERR_UNDEFINED_SMC) + api_version = 0; + +@@ -598,11 +529,12 @@ static int trusty_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, s); + +- trusty_init_version(s, &pdev->dev); ++ /* Initialize SMC transport */ ++ ret = trusty_smc_transport_setup(s->dev); ++ if (ret != 0 || s->msg_ops == NULL || s->mem_ops == NULL) ++ goto err_transport_setup; + +- ret = trusty_init_api_version(s, &pdev->dev); +- if (ret < 0) +- goto err_api_version; ++ trusty_init_version_str(s, &pdev->dev); + + s->nop_wq = alloc_workqueue("trusty-nop-wq", WQ_CPU_INTENSIVE, 0); + if (!s->nop_wq) { +@@ -648,9 +580,10 @@ static int trusty_probe(struct platform_device *pdev) + err_alloc_works: + destroy_workqueue(s->nop_wq); + err_create_nop_wq: +-err_api_version: +- s->dev->dma_parms = NULL; + kfree(s->version_str); ++ trusty_smc_transport_cleanup(s->dev); ++err_transport_setup: ++ s->dev->dma_parms = NULL; + device_for_each_child(&pdev->dev, NULL, trusty_remove_child); + mutex_destroy(&s->smc_lock); + kfree(s); +@@ -673,6 +606,7 @@ static int trusty_remove(struct platform_device *pdev) + free_percpu(s->nop_works); + destroy_workqueue(s->nop_wq); + ++ trusty_smc_transport_cleanup(s->dev); + mutex_destroy(&s->smc_lock); + s->dev->dma_parms = NULL; + kfree(s->version_str); +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0039-ANDROID-trusty-Modify-device-compatible-string.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0039-ANDROID-trusty-Modify-device-compatible-string.patch new file mode 100644 index 00000000..8fd1c7ce --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0039-ANDROID-trusty-Modify-device-compatible-string.patch @@ -0,0 +1,56 @@ +From 5566c2a41443e26068fe3a8e4a8e4b0c3a4e8ed6 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 14 Jan 2022 14:22:42 +0000 +Subject: [PATCH 26/32] ANDROID: trusty: Modify device compatible string + +Drop smc keyword from device tree node as Trusty can use SMC or FFA +based transport. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Id99b52f32a2122434a22f1991c0b4cd52b0676ed +Upstream-Status: Pending [Not submitted to upstream yet] +--- + Documentation/devicetree/bindings/trusty/trusty-irq.txt | 2 +- + Documentation/devicetree/bindings/trusty/trusty-smc.txt | 2 +- + drivers/trusty/trusty.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/trusty/trusty-irq.txt b/Documentation/devicetree/bindings/trusty/trusty-irq.txt +index cbb545ad452b..ae02030be4e7 100644 +--- a/Documentation/devicetree/bindings/trusty/trusty-irq.txt ++++ b/Documentation/devicetree/bindings/trusty/trusty-irq.txt +@@ -48,7 +48,7 @@ Example: + }; + ... + trusty { +- compatible = "android,trusty-smc-v1"; ++ compatible = "android,trusty-v1"; + ranges; + #address-cells = <2>; + #size-cells = <2>; +diff --git a/Documentation/devicetree/bindings/trusty/trusty-smc.txt b/Documentation/devicetree/bindings/trusty/trusty-smc.txt +index 1b39ad317c67..8d02a31ba814 100644 +--- a/Documentation/devicetree/bindings/trusty/trusty-smc.txt ++++ b/Documentation/devicetree/bindings/trusty/trusty-smc.txt +@@ -3,4 +3,4 @@ Trusty smc interface + Trusty is running in secure mode on the same (arm) cpu(s) as the current os. + + Required properties: +-- compatible: "android,trusty-smc-v1" ++- compatible: "android,trusty-v1" +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 0486827a45ca..757dd7b2c527 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -615,7 +615,7 @@ static int trusty_remove(struct platform_device *pdev) + } + + static const struct of_device_id trusty_of_match[] = { +- { .compatible = "android,trusty-smc-v1", }, ++ { .compatible = "android,trusty-v1", }, + {}, + }; + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0040-ANDROID-trusty-Add-transport-descriptor.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0040-ANDROID-trusty-Add-transport-descriptor.patch new file mode 100644 index 00000000..53c76be5 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0040-ANDROID-trusty-Add-transport-descriptor.patch @@ -0,0 +1,209 @@ +From 27248b5c8cb5c1a59b08e46eb3ab918867282c1c Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 14 Jan 2022 17:52:33 +0000 +Subject: [PATCH 27/32] ANDROID: trusty: Add transport descriptor + +Use transport descriptor to hold transport specific operations. This +helps to add new transport to Trusty core. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ibbde50de0302f6d259a7d572f0910067ce712b37 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/trusty-private.h | 20 +++++++++- + drivers/trusty/trusty-smc.c | 6 +++ + drivers/trusty/trusty.c | 71 ++++++++++++++++++++++++++++++--- + 3 files changed, 90 insertions(+), 7 deletions(-) + +diff --git a/drivers/trusty/trusty-private.h b/drivers/trusty/trusty-private.h +index 4d73c6ae35d4..74b88bb8f83b 100644 +--- a/drivers/trusty/trusty-private.h ++++ b/drivers/trusty/trusty-private.h +@@ -14,12 +14,14 @@ struct trusty_work { + }; + + struct trusty_msg_ops { ++ const struct trusty_transport_desc *desc; + u32 (*send_direct_msg)(struct device *dev, unsigned long fid, + unsigned long a0, unsigned long a1, + unsigned long a2); + }; + + struct trusty_mem_ops { ++ const struct trusty_transport_desc *desc; + int (*trusty_share_memory)(struct device *dev, u64 *id, + struct scatterlist *sglist, + unsigned int nents, pgprot_t pgprot, u64 tag); +@@ -46,6 +48,19 @@ struct trusty_state { + struct device_dma_parameters dma_parms; + const struct trusty_msg_ops *msg_ops; + const struct trusty_mem_ops *mem_ops; ++ struct trusty_ffa_state *ffa; ++}; ++ ++struct trusty_ffa_state { ++ struct device *dev; /* ffa device */ ++ const struct ffa_dev_ops *ops; ++ struct mutex share_memory_msg_lock; /* protects share_memory_msg */ ++}; ++ ++struct trusty_transport_desc { ++ const char *name; ++ int (*setup)(struct device *dev); ++ void (*cleanup)(struct device *dev); + }; + + int trusty_init_api_version(struct trusty_state *s, struct device *dev, +@@ -55,7 +70,8 @@ int trusty_init_api_version(struct trusty_state *s, struct device *dev, + unsigned long a1, + unsigned long a2)); + +-int trusty_smc_transport_setup(struct device *dev); +-void trusty_smc_transport_cleanup(struct device *dev); ++typedef const struct trusty_transport_desc *trusty_transports_t; ++ ++extern const struct trusty_transport_desc trusty_smc_transport; + + #endif /* _TRUSTY_PRIVATE_H */ +diff --git a/drivers/trusty/trusty-smc.c b/drivers/trusty/trusty-smc.c +index 8fa841e0e253..62d1d7060744 100644 +--- a/drivers/trusty/trusty-smc.c ++++ b/drivers/trusty/trusty-smc.c +@@ -134,3 +134,9 @@ void trusty_smc_transport_cleanup(struct device *dev) + if (s->mem_ops == &trusty_smc_mem_ops) + s->mem_ops = NULL; + } ++ ++const struct trusty_transport_desc trusty_smc_transport = { ++ .name = "smc", ++ .setup = trusty_smc_transport_setup, ++ .cleanup = trusty_smc_transport_cleanup, ++}; +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 757dd7b2c527..ec0fccfaa24c 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -493,6 +493,46 @@ void trusty_dequeue_nop(struct device *dev, struct trusty_nop *nop) + } + EXPORT_SYMBOL(trusty_dequeue_nop); + ++static int ++trusty_transports_setup(const trusty_transports_t *transports, ++ struct device *dev) ++{ ++ const struct trusty_transport_desc *transport; ++ int ret; ++ int transports_ret = -ENODEV; ++ ++ if (!transports) ++ return -EINVAL; ++ ++ for (; (transport = *transports); transports++) { ++ if (!transport->setup) ++ return -EINVAL; ++ ++ ret = transport->setup(dev); ++ transports_ret &= ret; ++ } ++ ++ /* One transport needs to complete setup without error. */ ++ if (transports_ret < 0) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++static void ++trusty_transports_cleanup(const trusty_transports_t *transports, ++ struct device *dev) ++{ ++ const struct trusty_transport_desc *transport; ++ ++ for (; (transport = *transports); transports++) { ++ if (!transport->cleanup) ++ continue; ++ ++ transport->cleanup(dev); ++ } ++} ++ + static int trusty_probe(struct platform_device *pdev) + { + int ret; +@@ -500,6 +540,7 @@ static int trusty_probe(struct platform_device *pdev) + work_func_t work_func; + struct trusty_state *s; + struct device_node *node = pdev->dev.of_node; ++ const trusty_transports_t *descs; + + if (!node) { + dev_err(&pdev->dev, "of_node required\n"); +@@ -529,8 +570,12 @@ static int trusty_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, s); + +- /* Initialize SMC transport */ +- ret = trusty_smc_transport_setup(s->dev); ++ /* ++ * Initialize Trusty transport. Trusty msg and mem ops has to be ++ * initialized as part of transport setup. ++ */ ++ descs = of_device_get_match_data(&pdev->dev); ++ ret = trusty_transports_setup(descs, s->dev); + if (ret != 0 || s->msg_ops == NULL || s->mem_ops == NULL) + goto err_transport_setup; + +@@ -581,7 +626,7 @@ static int trusty_probe(struct platform_device *pdev) + destroy_workqueue(s->nop_wq); + err_create_nop_wq: + kfree(s->version_str); +- trusty_smc_transport_cleanup(s->dev); ++ trusty_transports_cleanup(descs, s->dev); + err_transport_setup: + s->dev->dma_parms = NULL; + device_for_each_child(&pdev->dev, NULL, trusty_remove_child); +@@ -595,6 +640,7 @@ static int trusty_remove(struct platform_device *pdev) + { + unsigned int cpu; + struct trusty_state *s = platform_get_drvdata(pdev); ++ const trusty_transports_t *descs; + + device_for_each_child(&pdev->dev, NULL, trusty_remove_child); + +@@ -606,7 +652,10 @@ static int trusty_remove(struct platform_device *pdev) + free_percpu(s->nop_works); + destroy_workqueue(s->nop_wq); + +- trusty_smc_transport_cleanup(s->dev); ++ /* call transport cleanup */ ++ descs = of_device_get_match_data(&pdev->dev); ++ trusty_transports_cleanup(descs, s->dev); ++ + mutex_destroy(&s->smc_lock); + s->dev->dma_parms = NULL; + kfree(s->version_str); +@@ -614,8 +663,20 @@ static int trusty_remove(struct platform_device *pdev) + return 0; + } + ++/* ++ * Trusty probe will try all compiled in transports and will use the transport ++ * supported by the Trusty kernel. ++ * ++ * For Trusty API version < TRUSTY_API_VERSION_MEM_OBJ: ++ * trusty_smc_transport used for messaging. ++ */ ++static const trusty_transports_t trusty_transports[] = { ++ &trusty_smc_transport, ++ NULL, ++}; ++ + static const struct of_device_id trusty_of_match[] = { +- { .compatible = "android,trusty-v1", }, ++ { .compatible = "android,trusty-v1", .data = trusty_transports }, + {}, + }; + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0041-ANDROID-trusty-Add-trusty-ffa-driver.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0041-ANDROID-trusty-Add-trusty-ffa-driver.patch new file mode 100644 index 00000000..a61d2c88 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0041-ANDROID-trusty-Add-trusty-ffa-driver.patch @@ -0,0 +1,312 @@ +From 3104eb14f62df1c7c4b9038eb914514b0ff371dc Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Fri, 14 Jan 2022 18:47:08 +0000 +Subject: [PATCH 28/32] ANDROID: trusty: Add trusty-ffa driver + +Initial changes related to FFA transport support + - Adds FFA transport descriptor + - Defines Trusty UUID + - Initializes FFA transport does probe, sets ffa_ops + - Defers Trusty probe if ARM FF-A driver is not initialized or + Trusty SP not found. + - Link FF-A device as the supplier for Trusty platform device. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: I78f72b85c20e4bad4c24cf0826e96f27dcf2ee1d +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/Makefile | 1 + + drivers/trusty/trusty-ffa.c | 196 ++++++++++++++++++++++++++++++++ + drivers/trusty/trusty-ffa.h | 28 +++++ + drivers/trusty/trusty-private.h | 1 + + drivers/trusty/trusty.c | 6 + + 5 files changed, 232 insertions(+) + create mode 100644 drivers/trusty/trusty-ffa.c + create mode 100644 drivers/trusty/trusty-ffa.h + +diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile +index fbb53ee93003..797d61bf68ef 100644 +--- a/drivers/trusty/Makefile ++++ b/drivers/trusty/Makefile +@@ -6,6 +6,7 @@ + obj-$(CONFIG_TRUSTY) += trusty-core.o + trusty-core-objs += trusty.o trusty-mem.o + trusty-core-objs += trusty-smc.o ++trusty-core-objs += trusty-ffa.o + trusty-core-$(CONFIG_ARM) += trusty-smc-arm.o + trusty-core-$(CONFIG_ARM64) += trusty-smc-arm64.o + obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o +diff --git a/drivers/trusty/trusty-ffa.c b/drivers/trusty/trusty-ffa.c +new file mode 100644 +index 000000000000..c8c16a1fc700 +--- /dev/null ++++ b/drivers/trusty/trusty-ffa.c +@@ -0,0 +1,196 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2022 ARM Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "trusty-ffa.h" ++#include "trusty-private.h" ++ ++static const struct trusty_mem_ops trusty_ffa_mem_ops = { ++ .desc = &trusty_ffa_transport, ++}; ++ ++static const struct ffa_device_id trusty_ffa_device_id[] = { ++ /* ++ * Trusty UID: RFC-4122 compliant UUID version 4 ++ * 40ee25f0-a2bc-304c-8c4ca173c57d8af1 ++ */ ++ { UUID_INIT(0x40ee25f0, 0xa2bc, 0x304c, ++ 0x8c, 0x4c, 0xa1, 0x73, 0xc5, 0x7d, 0x8a, 0xf1) }, ++ {} ++}; ++ ++static int trusty_ffa_dev_match(struct device *dev, const void *uuid) ++{ ++ struct ffa_device *ffa_dev; ++ ++ ffa_dev = to_ffa_dev(dev); ++ if (uuid_equal(&ffa_dev->uuid, uuid)) ++ return 1; ++ ++ return 0; ++} ++ ++static struct ffa_device *trusty_ffa_dev_find(void) ++{ ++ const void *data; ++ struct device *dev; ++ ++ /* currently only one trusty instance is probed */ ++ data = &trusty_ffa_device_id[0].uuid; ++ ++ dev = bus_find_device(&ffa_bus_type, NULL, data, trusty_ffa_dev_match); ++ if (dev) { ++ /* drop reference count */ ++ put_device(dev); ++ return to_ffa_dev(dev); ++ } ++ ++ return NULL; ++} ++ ++static int trusty_ffa_link_supplier(struct device *c_dev, struct device *s_dev) ++{ ++ if (!c_dev || !s_dev) ++ return -EINVAL; ++ ++ if (!device_link_add(c_dev, s_dev, DL_FLAG_AUTOREMOVE_CONSUMER)) { ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++/* ++ * called from trusty probe ++ */ ++static int trusty_ffa_transport_setup(struct device *dev) ++{ ++ int rc; ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ struct trusty_ffa_state *ffa_state; ++ struct ffa_device *ffa_dev; ++ ++ /* ffa transport not required for lower api versions */ ++ if (s->api_version != 0 && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { ++ return -EINVAL; ++ } ++ ++ ffa_dev = trusty_ffa_dev_find(); ++ if (!ffa_dev) { ++ dev_dbg(dev, "FFA: Trusty device not found defer probe\n"); ++ return -EPROBE_DEFER; ++ } ++ ++ ffa_state = ffa_dev_get_drvdata(ffa_dev); ++ if (!ffa_state) ++ return -EINVAL; ++ ++ rc = trusty_ffa_link_supplier(dev, &ffa_dev->dev); ++ if (rc != 0) ++ return rc; ++ ++ /* FFA used only for memory sharing operations */ ++ if (s->api_version == TRUSTY_API_VERSION_MEM_OBJ) { ++ s->ffa = ffa_state; ++ s->mem_ops = &trusty_ffa_mem_ops; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static void trusty_ffa_transport_cleanup(struct device *dev) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ ++ /* ffa transport not setup for lower api versions */ ++ if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { ++ return; ++ } ++ ++ s->ffa = NULL; ++ s->mem_ops = NULL; ++} ++ ++static int trusty_ffa_probe(struct ffa_device *ffa_dev) ++{ ++ const struct ffa_dev_ops *ffa_ops; ++ struct trusty_ffa_state *s; ++ u32 ffa_drv_version; ++ ++ ffa_ops = ffa_dev_ops_get(ffa_dev); ++ if (!ffa_ops) { ++ dev_dbg(&ffa_dev->dev, "ffa_dev_ops_get: failed\n"); ++ return -ENOENT; ++ } ++ ++ /* check ffa driver version compatibility */ ++ ffa_drv_version = ffa_ops->api_version_get(); ++ if (TO_TRUSTY_FFA_MAJOR(ffa_drv_version) != TRUSTY_FFA_VERSION_MAJOR || ++ TO_TRUSTY_FFA_MINOR(ffa_drv_version) < TRUSTY_FFA_VERSION_MINOR) ++ return -EINVAL; ++ ++ s = kzalloc(sizeof(*s), GFP_KERNEL); ++ if (!s) ++ return -ENOMEM; ++ ++ s->dev = &ffa_dev->dev; ++ s->ops = ffa_ops; ++ mutex_init(&s->share_memory_msg_lock); ++ ffa_dev_set_drvdata(ffa_dev, s); ++ ++ ffa_ops->mode_32bit_set(ffa_dev); ++ ++ return 0; ++} ++ ++static void trusty_ffa_remove(struct ffa_device *ffa_dev) ++{ ++ struct trusty_ffa_state *s; ++ ++ s = ffa_dev_get_drvdata(ffa_dev); ++ ++ mutex_destroy(&s->share_memory_msg_lock); ++ memset(s, 0, sizeof(struct trusty_ffa_state)); ++ kfree(s); ++} ++ ++static struct ffa_driver trusty_ffa_driver = { ++ .name = "trusty-ffa", ++ .probe = trusty_ffa_probe, ++ .remove = trusty_ffa_remove, ++ .id_table = trusty_ffa_device_id, ++}; ++ ++static int __init trusty_ffa_transport_init(void) ++{ ++ if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT)) { ++ return ffa_register(&trusty_ffa_driver); ++ } else ++ return -ENODEV; ++} ++ ++static void __exit trusty_ffa_transport_exit(void) ++{ ++ if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT)) ++ ffa_unregister(&trusty_ffa_driver); ++} ++ ++const struct trusty_transport_desc trusty_ffa_transport = { ++ .name = "ffa", ++ .setup = trusty_ffa_transport_setup, ++ .cleanup = trusty_ffa_transport_cleanup, ++}; ++ ++module_init(trusty_ffa_transport_init); ++module_exit(trusty_ffa_transport_exit); +diff --git a/drivers/trusty/trusty-ffa.h b/drivers/trusty/trusty-ffa.h +new file mode 100644 +index 000000000000..267ca2c5db29 +--- /dev/null ++++ b/drivers/trusty/trusty-ffa.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2022 ARM Ltd. ++ */ ++ ++#ifndef __LINUX_TRUSTY_FFA_H ++#define __LINUX_TRUSTY_FFA_H ++ ++#include ++#include ++#include ++ ++#define TRUSTY_FFA_VERSION_MAJOR (1U) ++#define TRUSTY_FFA_VERSION_MINOR (0U) ++#define TRUSTY_FFA_VERSION_MAJOR_SHIFT (16U) ++#define TRUSTY_FFA_VERSION_MAJOR_MASK (0x7fffU) ++#define TRUSTY_FFA_VERSION_MINOR_SHIFT (0U) ++#define TRUSTY_FFA_VERSION_MINOR_MASK (0U) ++ ++#define TO_TRUSTY_FFA_MAJOR(v) \ ++ ((u16)((v >> TRUSTY_FFA_VERSION_MAJOR_SHIFT) & \ ++ TRUSTY_FFA_VERSION_MAJOR_MASK)) ++ ++#define TO_TRUSTY_FFA_MINOR(v) \ ++ ((u16)((v >> TRUSTY_FFA_VERSION_MINOR_SHIFT) & \ ++ TRUSTY_FFA_VERSION_MINOR_MASK)) ++ ++#endif /* __LINUX_TRUSTY_FFA_H */ +diff --git a/drivers/trusty/trusty-private.h b/drivers/trusty/trusty-private.h +index 74b88bb8f83b..2496f397e5d2 100644 +--- a/drivers/trusty/trusty-private.h ++++ b/drivers/trusty/trusty-private.h +@@ -73,5 +73,6 @@ int trusty_init_api_version(struct trusty_state *s, struct device *dev, + typedef const struct trusty_transport_desc *trusty_transports_t; + + extern const struct trusty_transport_desc trusty_smc_transport; ++extern const struct trusty_transport_desc trusty_ffa_transport; + + #endif /* _TRUSTY_PRIVATE_H */ +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index ec0fccfaa24c..4686b0d34f61 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -509,6 +509,11 @@ trusty_transports_setup(const trusty_transports_t *transports, + return -EINVAL; + + ret = transport->setup(dev); ++ if (ret == -EPROBE_DEFER) { ++ dev_notice(dev, "transport %s: defer probe\n", ++ transport->name); ++ return ret; ++ } + transports_ret &= ret; + } + +@@ -672,6 +677,7 @@ static int trusty_remove(struct platform_device *pdev) + */ + static const trusty_transports_t trusty_transports[] = { + &trusty_smc_transport, ++ &trusty_ffa_transport, + NULL, + }; + +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0042-ANDROID-trusty-ffa-Add-support-for-FFA-memory-operat.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0042-ANDROID-trusty-ffa-Add-support-for-FFA-memory-operat.patch new file mode 100644 index 00000000..2b150098 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0042-ANDROID-trusty-ffa-Add-support-for-FFA-memory-operat.patch @@ -0,0 +1,151 @@ +From c552f8ed6bbd68e838732598ca74055bb696dcb3 Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Tue, 18 Jan 2022 15:11:46 +0000 +Subject: [PATCH 29/32] ANDROID: trusty-ffa: Add support for FFA memory + operations + +Initializes Trusty mem_ops with FFA memory operations for share, +lend, reclaim. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Id3a1eb5ae8e4721cb983c624773d39bafe25a77d +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/trusty-ffa.c | 102 ++++++++++++++++++++++++++++++++++++ + drivers/trusty/trusty.c | 5 ++ + 2 files changed, 107 insertions(+) + +diff --git a/drivers/trusty/trusty-ffa.c b/drivers/trusty/trusty-ffa.c +index c8c16a1fc700..0655b3887b52 100644 +--- a/drivers/trusty/trusty-ffa.c ++++ b/drivers/trusty/trusty-ffa.c +@@ -15,8 +15,110 @@ + #include "trusty-ffa.h" + #include "trusty-private.h" + ++static int __trusty_ffa_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, ++ u64 tag, bool share) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ int ret; ++ struct scatterlist *sg; ++ size_t count; ++ struct ffa_device *ffa_dev = to_ffa_dev(s->ffa->dev); ++ const struct ffa_dev_ops *ffa_ops = s->ffa->ops; ++ struct ffa_mem_region_attributes ffa_mem_attr; ++ struct ffa_mem_ops_args ffa_mem_args; ++ ++ if (WARN_ON(nents < 1)) ++ return -EINVAL; ++ ++ count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ if (count != nents) { ++ dev_err(s->dev, "failed to dma map sg_table\n"); ++ return -EINVAL; ++ } ++ ++ sg = sglist; ++ ++ mutex_lock(&s->ffa->share_memory_msg_lock); ++ ++ ffa_mem_attr.receiver = ffa_dev->vm_id; ++ ffa_mem_attr.attrs = FFA_MEM_RW; ++ ++ ffa_mem_args.use_txbuf = 1; ++ ffa_mem_args.tag = tag; ++ ffa_mem_args.attrs = &ffa_mem_attr; ++ ffa_mem_args.nattrs = 1; ++ ffa_mem_args.sg = sg; ++ ffa_mem_args.flags = 0; ++ ++ if (share) { ++ ret = ffa_ops->memory_share(ffa_dev, &ffa_mem_args); ++ } else { ++ ret = ffa_ops->memory_lend(ffa_dev, &ffa_mem_args); ++ } ++ ++ mutex_unlock(&s->ffa->share_memory_msg_lock); ++ ++ if (!ret) { ++ *id = ffa_mem_args.g_handle; ++ dev_dbg(s->dev, "%s: done\n", __func__); ++ return 0; ++ } ++ ++ dev_err(s->dev, "%s: failed %d", __func__, ret); ++ ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ return ret; ++} ++ ++static int trusty_ffa_share_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, u64 tag) ++{ ++ return __trusty_ffa_share_memory(dev, id, sglist, nents, pgprot, tag, ++ true); ++} ++ ++static int trusty_ffa_lend_memory(struct device *dev, u64 *id, ++ struct scatterlist *sglist, ++ unsigned int nents, pgprot_t pgprot, u64 tag) ++{ ++ return __trusty_ffa_share_memory(dev, id, sglist, nents, pgprot, tag, ++ false); ++} ++ ++static int trusty_ffa_reclaim_memory(struct device *dev, u64 id, ++ struct scatterlist *sglist, ++ unsigned int nents) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ int ret = 0; ++ const struct ffa_dev_ops *ffa_ops = s->ffa->ops; ++ ++ if (WARN_ON(nents < 1)) ++ return -EINVAL; ++ ++ mutex_lock(&s->ffa->share_memory_msg_lock); ++ ++ ret = ffa_ops->memory_reclaim(id, 0); ++ ++ mutex_unlock(&s->ffa->share_memory_msg_lock); ++ ++ if (ret != 0) ++ return ret; ++ ++ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL); ++ ++ dev_dbg(s->dev, "%s: done\n", __func__); ++ return 0; ++} ++ + static const struct trusty_mem_ops trusty_ffa_mem_ops = { + .desc = &trusty_ffa_transport, ++ .trusty_share_memory = &trusty_ffa_share_memory, ++ .trusty_lend_memory = &trusty_ffa_lend_memory, ++ .trusty_reclaim_memory = &trusty_ffa_reclaim_memory, + }; + + static const struct ffa_device_id trusty_ffa_device_id[] = { +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 4686b0d34f61..f91c255c9897 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -674,6 +674,11 @@ static int trusty_remove(struct platform_device *pdev) + * + * For Trusty API version < TRUSTY_API_VERSION_MEM_OBJ: + * trusty_smc_transport used for messaging. ++ * ++ * For Trusty API version == TRUSTY_API_VERSION_MEM_OBJ: ++ * trusty_smc_transport used for messaging. ++ * trusty_ffa_transport used for memory sharing. ++ * + */ + static const trusty_transports_t trusty_transports[] = { + &trusty_smc_transport, +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0043-ANDROID-trusty-ffa-Enable-FFA-transport-for-both-mem.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0043-ANDROID-trusty-ffa-Enable-FFA-transport-for-both-mem.patch new file mode 100644 index 00000000..2c1623ac --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0043-ANDROID-trusty-ffa-Enable-FFA-transport-for-both-mem.patch @@ -0,0 +1,142 @@ +From e67cd78142984c7c4120f15ef14e1e026746af5a Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Thu, 3 Feb 2022 11:19:38 +0000 +Subject: [PATCH 30/32] ANDROID: trusty-ffa: Enable FFA transport for both + memory and message ops + +Adds new API version TRUSTY_API_VERSION_FFA and sets this as current +API version. + +If Trusty on the secure side supports receipt of FFA direct request, +then trusty core uses FFA calls for messages and memory operations. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: I4a8b060f906a96935a7df10713026fb543e2b9a7 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/trusty-ffa.c | 58 +++++++++++++++++++++++++++++++++++ + drivers/trusty/trusty.c | 3 ++ + include/linux/trusty/smcall.h | 3 +- + 3 files changed, 63 insertions(+), 1 deletion(-) + +diff --git a/drivers/trusty/trusty-ffa.c b/drivers/trusty/trusty-ffa.c +index 0655b3887b52..543f5a0d31cb 100644 +--- a/drivers/trusty/trusty-ffa.c ++++ b/drivers/trusty/trusty-ffa.c +@@ -15,6 +15,36 @@ + #include "trusty-ffa.h" + #include "trusty-private.h" + ++/* partition property: Supports receipt of direct requests */ ++#define FFA_PARTITION_DIRECT_REQ_RECV BIT(0) ++ ++/* string representation of trusty UUID used for partition info get call */ ++static const char *trusty_uuid = "40ee25f0-a2bc-304c-8c4c-a173c57d8af1"; ++ ++static u32 trusty_ffa_send_direct_msg(struct device *dev, unsigned long fid, ++ unsigned long a0, unsigned long a1, ++ unsigned long a2) ++{ ++ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); ++ struct ffa_send_direct_data ffa_msg; ++ struct ffa_device *ffa_dev; ++ int ret; ++ ++ ffa_dev = to_ffa_dev(s->ffa->dev); ++ ++ ffa_msg.data0 = fid; ++ ffa_msg.data1 = a0; ++ ffa_msg.data2 = a1; ++ ffa_msg.data3 = a2; ++ ffa_msg.data4 = 0; ++ ++ ret = s->ffa->ops->sync_send_receive(ffa_dev, &ffa_msg); ++ if (!ret) ++ return ffa_msg.data0; ++ ++ return ret; ++} ++ + static int __trusty_ffa_share_memory(struct device *dev, u64 *id, + struct scatterlist *sglist, + unsigned int nents, pgprot_t pgprot, +@@ -114,6 +144,11 @@ static int trusty_ffa_reclaim_memory(struct device *dev, u64 id, + return 0; + } + ++static const struct trusty_msg_ops trusty_ffa_msg_ops = { ++ .desc = &trusty_ffa_transport, ++ .send_direct_msg = &trusty_ffa_send_direct_msg, ++}; ++ + static const struct trusty_mem_ops trusty_ffa_mem_ops = { + .desc = &trusty_ffa_transport, + .trusty_share_memory = &trusty_ffa_share_memory, +@@ -181,6 +216,7 @@ static int trusty_ffa_transport_setup(struct device *dev) + struct trusty_state *s = platform_get_drvdata(to_platform_device(dev)); + struct trusty_ffa_state *ffa_state; + struct ffa_device *ffa_dev; ++ struct ffa_partition_info pinfo = { 0 }; + + /* ffa transport not required for lower api versions */ + if (s->api_version != 0 && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) { +@@ -208,6 +244,28 @@ static int trusty_ffa_transport_setup(struct device *dev) + return 0; + } + ++ /* check if Trusty partition can support receipt of direct requests. */ ++ rc = ffa_state->ops->partition_info_get(trusty_uuid, &pinfo); ++ if (rc || !(pinfo.properties & FFA_PARTITION_DIRECT_REQ_RECV)) { ++ dev_err(ffa_state->dev, "trusty_ffa_pinfo: ret: 0x%x, prop: 0x%x\n", ++ rc, pinfo.properties); ++ return -EINVAL; ++ } ++ ++ /* query and check Trusty API version */ ++ s->ffa = ffa_state; ++ rc = trusty_init_api_version(s, dev, trusty_ffa_send_direct_msg); ++ if (rc) { ++ s->ffa = NULL; ++ return -EINVAL; ++ } ++ ++ if (s->api_version == TRUSTY_API_VERSION_FFA) { ++ s->msg_ops = &trusty_ffa_msg_ops; ++ s->mem_ops = &trusty_ffa_mem_ops; ++ return 0; ++ } ++ + return -EINVAL; + } + +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index f91c255c9897..66273873f169 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -679,6 +679,9 @@ static int trusty_remove(struct platform_device *pdev) + * trusty_smc_transport used for messaging. + * trusty_ffa_transport used for memory sharing. + * ++ * For Trusty API version > TRUSTY_API_VERSION_MEM_OBJ: ++ * trusty_ffa_transport used for messaging and memory sharing operations. ++ * + */ + static const trusty_transports_t trusty_transports[] = { + &trusty_smc_transport, +diff --git a/include/linux/trusty/smcall.h b/include/linux/trusty/smcall.h +index aea3f6068593..17b3d1c2c4f6 100644 +--- a/include/linux/trusty/smcall.h ++++ b/include/linux/trusty/smcall.h +@@ -109,7 +109,8 @@ + #define TRUSTY_API_VERSION_SMP_NOP (3) + #define TRUSTY_API_VERSION_PHYS_MEM_OBJ (4) + #define TRUSTY_API_VERSION_MEM_OBJ (5) +-#define TRUSTY_API_VERSION_CURRENT (5) ++#define TRUSTY_API_VERSION_FFA (6) ++#define TRUSTY_API_VERSION_CURRENT (6) + #define SMC_FC_API_VERSION SMC_FASTCALL_NR(SMC_ENTITY_SECURE_MONITOR, 11) + + /* TRUSTED_OS entity calls */ +-- +2.30.2 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0044-ANDROID-trusty-Make-trusty-transports-configurable.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0044-ANDROID-trusty-Make-trusty-transports-configurable.patch new file mode 100644 index 00000000..3076eca7 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.10/tc/0044-ANDROID-trusty-Make-trusty-transports-configurable.patch @@ -0,0 +1,146 @@ +From 088162ab1852aa0f2034199e97a327b6240231db Mon Sep 17 00:00:00 2001 +From: Arunachalam Ganapathy +Date: Wed, 16 Mar 2022 11:14:09 +0000 +Subject: [PATCH 31/32] ANDROID: trusty: Make trusty transports configurable + +With TRUSTY_SMC_TRANSPORT set to 'y', SMC based message passing and +memory sharing support will be compiled in to trusty core. + +With TRUSTY_FFA_TRANSPORT set to 'y', FFA based message passing and +memory sharing support will be compiled in to trusty core. This +depends on ARM FF-A driver (ARM_FFA_TRANSPORT). + +Enabling any of the transport sets config TRUSTY_HAVE_TRANSPORT to 'y'. +Not enabling any of the transport causes the build to break. + +Signed-off-by: Arunachalam Ganapathy +Change-Id: Ib5bbf0d39202e6897700264d14371ae33101c1d1 +Upstream-Status: Pending [Not submitted to upstream yet] +--- + drivers/trusty/Kconfig | 30 ++++++++++++++++++++++++++++++ + drivers/trusty/Makefile | 26 +++++++++++++++----------- + drivers/trusty/trusty-private.h | 4 ++++ + drivers/trusty/trusty.c | 7 +++++++ + 4 files changed, 56 insertions(+), 11 deletions(-) + +diff --git a/drivers/trusty/Kconfig b/drivers/trusty/Kconfig +index fcde7f097acf..260022e4595b 100644 +--- a/drivers/trusty/Kconfig ++++ b/drivers/trusty/Kconfig +@@ -21,6 +21,36 @@ config TRUSTY + + if TRUSTY + ++config TRUSTY_HAVE_TRANSPORT ++ bool ++ help ++ If any of the Trusty transport is enabled then it sets this config ++ option. This variable is used to break the build when none of the ++ Trusty transports are enabled. ++ ++config TRUSTY_SMC_TRANSPORT ++ bool "Trusty transport based on SMC" ++ select TRUSTY_HAVE_TRANSPORT ++ default n ++ help ++ Enable SMC based transport for Trusty. This transport is required for ++ Trusty API version <= TRUSTY_API_VERSION_MEM_OBJ. ++ ++ If you want to use legacy SMC based transport for sending Trusty ++ messages to secure world, answer Y. ++ ++config TRUSTY_FFA_TRANSPORT ++ bool "Trusty transport based on FFA" ++ select TRUSTY_HAVE_TRANSPORT ++ depends on ARM_FFA_TRANSPORT ++ default y ++ help ++ Enable ARM FF-A based transport for Trusty. This transport is required ++ for Trusty API version >= TRUSTY_API_VERSION_MEM_OBJ. ++ ++ If you want to use ARM FF-A based transport for sending Trusty messages ++ to secure world, answer Y. ++ + config TRUSTY_IRQ + tristate "Trusty IRQ support" + default y +diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile +index 797d61bf68ef..104a4d0ed35c 100644 +--- a/drivers/trusty/Makefile ++++ b/drivers/trusty/Makefile +@@ -3,14 +3,18 @@ + # Makefile for trusty components + # + +-obj-$(CONFIG_TRUSTY) += trusty-core.o +-trusty-core-objs += trusty.o trusty-mem.o +-trusty-core-objs += trusty-smc.o +-trusty-core-objs += trusty-ffa.o +-trusty-core-$(CONFIG_ARM) += trusty-smc-arm.o +-trusty-core-$(CONFIG_ARM64) += trusty-smc-arm64.o +-obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o +-obj-$(CONFIG_TRUSTY_LOG) += trusty-log.o +-obj-$(CONFIG_TRUSTY_TEST) += trusty-test.o +-obj-$(CONFIG_TRUSTY_VIRTIO) += trusty-virtio.o +-obj-$(CONFIG_TRUSTY_VIRTIO_IPC) += trusty-ipc.o ++obj-$(CONFIG_TRUSTY) += trusty-core.o ++trusty-core-objs += trusty.o ++trusty-arm-smc-$(CONFIG_ARM) += trusty-smc-arm.o ++trusty-arm-smc64-$(CONFIG_ARM64) += trusty-smc-arm64.o ++trusty-transport-$(CONFIG_TRUSTY_SMC_TRANSPORT) += trusty-smc.o ++trusty-transport-$(CONFIG_TRUSTY_SMC_TRANSPORT) += trusty-mem.o ++trusty-transport-$(CONFIG_TRUSTY_SMC_TRANSPORT) += $(trusty-arm-smc-y) ++trusty-transport-$(CONFIG_TRUSTY_SMC_TRANSPORT) += $(trusty-arm-smc64-y) ++trusty-transport-$(CONFIG_TRUSTY_FFA_TRANSPORT) += trusty-ffa.o ++trusty-core-objs += $(trusty-transport-y) ++obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o ++obj-$(CONFIG_TRUSTY_LOG) += trusty-log.o ++obj-$(CONFIG_TRUSTY_TEST) += trusty-test.o ++obj-$(CONFIG_TRUSTY_VIRTIO) += trusty-virtio.o ++obj-$(CONFIG_TRUSTY_VIRTIO_IPC) += trusty-ipc.o +diff --git a/drivers/trusty/trusty-private.h b/drivers/trusty/trusty-private.h +index 2496f397e5d2..386ca9ae5af3 100644 +--- a/drivers/trusty/trusty-private.h ++++ b/drivers/trusty/trusty-private.h +@@ -72,7 +72,11 @@ int trusty_init_api_version(struct trusty_state *s, struct device *dev, + + typedef const struct trusty_transport_desc *trusty_transports_t; + ++#ifdef CONFIG_TRUSTY_SMC_TRANSPORT + extern const struct trusty_transport_desc trusty_smc_transport; ++#endif ++#ifdef CONFIG_TRUSTY_FFA_TRANSPORT + extern const struct trusty_transport_desc trusty_ffa_transport; ++#endif + + #endif /* _TRUSTY_PRIVATE_H */ +diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c +index 66273873f169..06698f3c67f9 100644 +--- a/drivers/trusty/trusty.c ++++ b/drivers/trusty/trusty.c +@@ -684,8 +684,12 @@ static int trusty_remove(struct platform_device *pdev) + * + */ + static const trusty_transports_t trusty_transports[] = { ++#ifdef CONFIG_TRUSTY_SMC_TRANSPORT + &trusty_smc_transport, ++#endif ++#ifdef CONFIG_TRUSTY_FFA_TRANSPORT + &trusty_ffa_transport, ++#endif + NULL, + }; + +@@ -708,6 +712,9 @@ static struct platform_driver trusty_driver = { + + static int __init trusty_driver_init(void) + { ++ BUILD_BUG_ON_MSG(!IS_ENABLED(CONFIG_TRUSTY_HAVE_TRANSPORT), ++ "Trusty transport not configured"); ++ + return platform_driver_register(&trusty_driver); + } + +-- +2.30.2 +