* [PATCH 02/10] arm/trusted-firmware-a: Add support for spmd build option
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
@ 2021-01-12 15:20 ` arunachalam.ganapathy
2021-01-12 15:20 ` [PATCH 03/10] arm-bsp/tc0: Add hafnium support Arunachalam Ganapathy
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: arunachalam.ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
This patch adds generic dispatcher 'spmd' option for SPD along with
SPMD_SPM_AT_SEL2 build option.
Config: SPD=spmd and SPMD_SPM_AT_SEL2=1. Indicates the SPMC component
runs at the S-EL2
- Add hafnium dependency
- Set CTX_INCLUDE_EL2_REGS=1 and ARM_ARCH_MINOR=4
- Set BL32 to hafnium image
- Set SP_LAYOUT_FILE and ARM_SPMC_MANIFEST build parameters
Config: SPD=spmd and SPMD_SPM_AT_SEL2=0. Indicates the SPMC component
runs at the S-EL1 execution state.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Icd3970e5132e75de67ef7f41dbfc8f9e1cdde7f3
---
.../trusted-firmware-a/trusted-firmware-a.inc | 26 ++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/meta-arm/recipes-bsp/trusted-firmware-a/trusted-firmware-a.inc b/meta-arm/recipes-bsp/trusted-firmware-a/trusted-firmware-a.inc
index 48f5129..69d5ca8 100644
--- a/meta-arm/recipes-bsp/trusted-firmware-a/trusted-firmware-a.inc
+++ b/meta-arm/recipes-bsp/trusted-firmware-a/trusted-firmware-a.inc
@@ -22,11 +22,20 @@ TFA_PLATFORM_aarch64_qemuall ?= "qemu"
TFA_BOARD ?= ""
# Some platforms use SPD (Secure Payload Dispatcher) services
-# Few options are "opteed", "tlkd", "trusty", "tspd"...
+# Few options are "opteed", "tlkd", "trusty", "tspd", "spmd"...
# Leave empty to not use SPD
TFA_SPD ?= ""
TFA_SPD_aarch64_qemuall ?= "opteed"
+# Variable used when TFA_SPD=spmd
+TFA_SPMD_SPM_AT_SEL2 ?= "1"
+
+# SP layout file location. Used when TFA_SPD=spmd and TFA_SPMD_SPM_AT_SEL2=1
+TFA_SP_LAYOUT_FILE ?= ""
+
+# SPMC manifest file location. Used when TFA_SPD=spmd and TFA_SPMD_SPM_AT_SEL2=1
+TFA_ARM_SPMC_MANIFEST_DTS ?= ""
+
# Build for debug (set TFA_DEBUG to 1 to activate)
TFA_DEBUG ?= "0"
@@ -114,6 +123,9 @@ EXTRA_OEMAKE += "${@'TARGET_BOARD=${TFA_BOARD}' if d.getVar('TFA_BOARD') else ''
# Handle TFA_SPD parameter
EXTRA_OEMAKE += "${@'SPD=${TFA_SPD}' if d.getVar('TFA_SPD') else ''}"
+# If TFA_SPD is spmd, set SPMD_SPM_AT_SEL2
+EXTRA_OEMAKE += "${@'SPMD_SPM_AT_SEL2=${TFA_SPMD_SPM_AT_SEL2}' if d.getVar('TFA_SPD', True) == 'spmd' else ''}"
+
# Handle TFA_DEBUG parameter
EXTRA_OEMAKE += "${@bb.utils.contains('TFA_DEBUG', '1', 'DEBUG=${TFA_DEBUG}', '', d)}"
@@ -125,6 +137,18 @@ DEPENDS += " ${@bb.utils.contains('TFA_UBOOT', '1', 'u-boot', '', d)}"
do_compile[depends] += " ${@bb.utils.contains('TFA_UBOOT', '1', 'u-boot:do_deploy', '', d)}"
EXTRA_OEMAKE += "${@bb.utils.contains('TFA_UBOOT', '1', 'BL33=${DEPLOY_DIR_IMAGE}/u-boot.bin', '',d)}"
+# Hafnium support
+SEL2_SPMC = "${@'${TFA_SPMD_SPM_AT_SEL2}' if d.getVar('TFA_SPD', True) == 'spmd' else ''}"
+
+DEPENDS += " ${@bb.utils.contains('SEL2_SPMC', '1', 'hafnium', '', d)}"
+
+EXTRA_OEMAKE += "${@bb.utils.contains('SEL2_SPMC', '1', 'CTX_INCLUDE_EL2_REGS=1 ARM_ARCH_MINOR=4 BL32=${RECIPE_SYSROOT}/firmware/hafnium.bin', '', d)}"
+
+# Add SP layout file and spmc manifest for hafnium
+EXTRA_OEMAKE += "${@bb.utils.contains('SEL2_SPMC', '1', 'SP_LAYOUT_FILE=${TFA_SP_LAYOUT_FILE}' if d.getVar('TFA_SP_LAYOUT_FILE') else '', '', d)}"
+
+EXTRA_OEMAKE += "${@bb.utils.contains('SEL2_SPMC', '1', 'ARM_SPMC_MANIFEST_DTS=${TFA_ARM_SPMC_MANIFEST_DTS}' if d.getVar('TFA_ARM_SPMC_MANIFEST_DTS') else '', '', d)}"
+
# Tell the tools where the native OpenSSL is located
EXTRA_OEMAKE += "OPENSSL_DIR=${STAGING_DIR_NATIVE}/${prefix_native}"
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 03/10] arm-bsp/tc0: Add hafnium support
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
2021-01-12 15:20 ` [PATCH 02/10] arm/trusted-firmware-a: Add support for spmd build option arunachalam.ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 04/10] arm-bsp/tc0: Add support for optee Arunachalam Ganapathy
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
Enables hafnium support for tc0.
Adds pending patches for SEL1 SP support.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: If5c12b7e7b7a301ae9a48a88223be3e51f38d3aa
---
...condary-core-entry-point-at-SPMC-ini.patch | 324 ++++++++++++++++++
...A-Cold-boot-and-wake-up-from-suspend.patch | 65 ++++
...-A-Respond-to-PSCI_CPU_OFF-from-SPMD.patch | 87 +++++
.../recipes-bsp/hafnium/hafnium-tc0.inc | 19 +
.../recipes-bsp/hafnium/hafnium_2.4.bbappend | 6 +
5 files changed, 501 insertions(+)
create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0001-FF-A-Register-secondary-core-entry-point-at-SPMC-ini.patch
create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0002-FF-A-Cold-boot-and-wake-up-from-suspend.patch
create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0003-FF-A-Respond-to-PSCI_CPU_OFF-from-SPMD.patch
create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc0.inc
create mode 100644 meta-arm-bsp/recipes-bsp/hafnium/hafnium_2.4.bbappend
diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0001-FF-A-Register-secondary-core-entry-point-at-SPMC-ini.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0001-FF-A-Register-secondary-core-entry-point-at-SPMC-ini.patch
new file mode 100644
index 0000000..5828750
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0001-FF-A-Register-secondary-core-entry-point-at-SPMC-ini.patch
@@ -0,0 +1,324 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From cb329ce33874abd8b69988c3dc63fd323a3413be Mon Sep 17 00:00:00 2001
+From: Max Shvetsov <maksims.svecovs@arm.com>
+Date: Thu, 27 Aug 2020 12:37:57 +0100
+Subject: [PATCH 1/4] FF-A: Register secondary core entry point at SPMC init.
+
+When the primary physical core boots the SPMC registers its secondary physical
+core entry points to the SPMD. All Secure Partition are then initialized on
+their primary Execution Contexts. A Secure Partition calls PSCI_CPU_ON from its
+first EC (trapped to the SPMC) passing entry point addresses of secondary ECs.
+ECs are turned "on" in their SPMC internal states, although they do not run yet
+(the service call does not reach the EL3 PSCI layer). Later, when the NWd
+(Hypervisor or OS Kernel) boots, it calls PSCI_CPU_ON for waking up physical
+cores down to EL3. The PSCI layer calls into SPMD PM hooks, then the SPMD calls
+into the SPMC by an exception return to the registered secondary entry point.
+The target secondary core then reaches Hafnium vcpu_main.
+
+Change-Id: I2bd42ea54e1a7feebff20e878345ec196ff352e9
+Signed-off-by: Max Shvetsov <maksims.svecovs@arm.com>
+Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
+---
+ inc/hf/arch/init.h | 7 ++
+ src/arch/aarch64/hypervisor/psci_handler.c | 131 +++++++++++++++++---
+ src/arch/aarch64/inc/hf/arch/spmd_helpers.h | 15 +++
+ src/cpu.c | 7 ++
+ src/init.c | 2 +
+ 5 files changed, 143 insertions(+), 19 deletions(-)
+ create mode 100644 src/arch/aarch64/inc/hf/arch/spmd_helpers.h
+
+diff --git a/inc/hf/arch/init.h b/inc/hf/arch/init.h
+index 5205e4e..ef0e48f 100644
+--- a/inc/hf/arch/init.h
++++ b/inc/hf/arch/init.h
+@@ -8,6 +8,8 @@
+
+ #pragma once
+
++#include "hf/boot_params.h"
++
+ /**
+ * Performs arch specific boot time initialization.
+ *
+@@ -15,3 +17,8 @@
+ * possible.
+ */
+ void arch_one_time_init(void);
++
++/**
++ * Sets up secondary cores.
++ */
++void arch_psci_secondary_core_init(const struct boot_params *params);
+diff --git a/src/arch/aarch64/hypervisor/psci_handler.c b/src/arch/aarch64/hypervisor/psci_handler.c
+index f89a00b..bdcc1d3 100644
+--- a/src/arch/aarch64/hypervisor/psci_handler.c
++++ b/src/arch/aarch64/hypervisor/psci_handler.c
+@@ -11,9 +11,11 @@
+ #include <stdint.h>
+
+ #include "hf/arch/plat/psci.h"
++#include "hf/arch/spmd_helpers.h"
+ #include "hf/arch/types.h"
+
+ #include "hf/api.h"
++#include "hf/boot_params.h"
+ #include "hf/cpu.h"
+ #include "hf/dlog.h"
+ #include "hf/ffa.h"
+@@ -24,9 +26,32 @@
+ #include "smc.h"
+
+ static uint32_t el3_psci_version;
++static ffa_vm_id_t physical_ffa_id;
+
+ void cpu_entry(struct cpu *c);
+
++#if SECURE_WORLD == 1
++
++static void set_ffa_id(void)
++{
++ struct ffa_value res =
++ smc_ffa_call((struct ffa_value){.func = FFA_ID_GET_32});
++
++ if (res.func != FFA_SUCCESS_32) {
++ dlog_error("%s Failed to get it's own FF-A ID.\n", __func__);
++ physical_ffa_id = HF_INVALID_VM_ID;
++ return;
++ }
++ physical_ffa_id = res.arg2 & 0xFFFF;
++}
++
++#endif
++
++ffa_vm_id_t get_ffa_id(void)
++{
++ return physical_ffa_id;
++}
++
+ /* Performs arch specific boot time initialisation. */
+ void arch_one_time_init(void)
+ {
+@@ -53,9 +78,79 @@ void arch_one_time_init(void)
+ }
+ #else
+ el3_psci_version = PSCI_VERSION_1_1;
++
++ set_ffa_id();
+ #endif
+ }
+
++/**
++ * Register secondary physical core entry points to the SPMD.
++ */
++void arch_psci_secondary_core_init(const struct boot_params *params)
++{
++#if SECURE_WORLD == 1
++ struct ffa_value res;
++
++ for (uint32_t count = 0; count < params->cpu_count; count++) {
++ uint32_t id = params->cpu_ids[count];
++ struct cpu *cpu = cpu_find(id);
++ const ffa_vm_id_t ffa_id = get_ffa_id();
++
++ res = smc_ffa_call((struct ffa_value){
++ .func = FFA_MSG_SEND_DIRECT_REQ_32,
++ .arg1 = (ffa_id << 16) | SPMD_ID,
++ .arg3 = SPMD_DIRECT_MSG_SET_ENTRY_POINT,
++ .arg4 = params->cpu_ids[count],
++ .arg5 = (uintreg_t)&cpu_entry,
++ .arg6 = (uintreg_t)cpu});
++
++ if (res.func != FFA_SUCCESS_32) {
++ dlog_warning(
++ "%s Failed to initialize secondary core ID: "
++ "%u\n",
++ __func__, id);
++ }
++
++ dlog_verbose("SPMD EP register returned %#x\n", res.func);
++ }
++#endif
++}
++
++/**
++ * Convert a PSCI CPU / affinity ID for a secondary VM to the corresponding vCPU
++ * index.
++ */
++ffa_vcpu_index_t vcpu_id_to_index(cpu_id_t vcpu_id)
++{
++ /* For now we use indices as IDs for the purposes of PSCI. */
++ return vcpu_id;
++}
++
++#if SECURE_WORLD == 1
++/**
++ * Use vcpu_on only as a way to initialize entry point without
++ * an intent to power up vcpu.
++ */
++static uintreg_t ffa_register_entrypoint(cpu_id_t id, struct vm *vm,
++ uintreg_t entrypoint, uintreg_t param)
++{
++ ffa_vcpu_index_t target_vcpu_index = vcpu_id_to_index(id);
++
++ if (target_vcpu_index >= vm->vcpu_count) {
++ return PSCI_ERROR_INVALID_PARAMETERS;
++ }
++
++ struct vcpu *target_vcpu = vm_get_vcpu(vm, target_vcpu_index);
++ struct vcpu_locked locked_target_vcpu = vcpu_lock(target_vcpu);
++
++ vcpu_on(locked_target_vcpu, ipa_init(entrypoint), param);
++
++ vcpu_unlock(&locked_target_vcpu);
++
++ return PSCI_RETURN_SUCCESS;
++}
++#endif
++
+ /**
+ * Handles PSCI requests received via HVC or SMC instructions from the primary
+ * VM.
+@@ -180,7 +275,8 @@ bool psci_primary_vm_handler(struct vcpu *vcpu, uint32_t func, uintreg_t arg0,
+ panic("CPU off failed");
+ break;
+
+- case PSCI_CPU_ON:
++ case PSCI_CPU_ON: {
++#if SECURE_WORLD == 0
+ c = cpu_find(arg0);
+ if (!c) {
+ *ret = PSCI_ERROR_INVALID_PARAMETERS;
+@@ -208,7 +304,12 @@ bool psci_primary_vm_handler(struct vcpu *vcpu, uint32_t func, uintreg_t arg0,
+ if (*ret != PSCI_RETURN_SUCCESS) {
+ cpu_off(c);
+ }
++#else
++ *ret = ffa_register_entrypoint((cpu_id_t)arg0, vcpu->vm, arg1,
++ arg2);
++#endif
+ break;
++ }
+
+ case PSCI_MIGRATE:
+ case PSCI_MIGRATE_INFO_TYPE:
+@@ -234,16 +335,6 @@ bool psci_primary_vm_handler(struct vcpu *vcpu, uint32_t func, uintreg_t arg0,
+ return true;
+ }
+
+-/**
+- * Convert a PSCI CPU / affinity ID for a secondary VM to the corresponding vCPU
+- * index.
+- */
+-ffa_vcpu_index_t vcpu_id_to_index(cpu_id_t vcpu_id)
+-{
+- /* For now we use indices as IDs for the purposes of PSCI. */
+- return vcpu_id;
+-}
+-
+ /**
+ * Handles PSCI requests received via HVC or SMC instructions from a secondary
+ * VM.
+@@ -337,22 +428,23 @@ bool psci_secondary_vm_handler(struct vcpu *vcpu, uint32_t func, uintreg_t arg0,
+ case PSCI_CPU_ON: {
+ /* Parameter names as per PSCI specification. */
+ cpu_id_t target_cpu = arg0;
+- ipaddr_t entry_point_address = ipa_init(arg1);
+ uint64_t context_id = arg2;
+- ffa_vcpu_index_t target_vcpu_index =
+- vcpu_id_to_index(target_cpu);
+ struct vm *vm = vcpu->vm;
+- struct vcpu *target_vcpu;
+
++#if SECURE_WORLD == 1
++ *ret = ffa_register_entrypoint((cpu_id_t)target_cpu, vm, arg1,
++ context_id);
++#else
++ ffa_vcpu_index_t target_vcpu_index =
++ vcpu_id_to_index(target_cpu);
+ if (target_vcpu_index >= vm->vcpu_count) {
+ *ret = PSCI_ERROR_INVALID_PARAMETERS;
+ break;
+ }
++ struct vcpu *target_vcpu = vm_get_vcpu(vm, target_vcpu_index);
+
+- target_vcpu = vm_get_vcpu(vm, target_vcpu_index);
+-
+- if (vcpu_secondary_reset_and_start(
+- target_vcpu, entry_point_address, context_id)) {
++ if (vcpu_secondary_reset_and_start(target_vcpu, ipa_init(arg1),
++ context_id)) {
+ /*
+ * Tell the scheduler that it can start running the new
+ * vCPU now.
+@@ -362,6 +454,7 @@ bool psci_secondary_vm_handler(struct vcpu *vcpu, uint32_t func, uintreg_t arg0,
+ } else {
+ *ret = PSCI_ERROR_ALREADY_ON;
+ }
++#endif
+
+ break;
+ }
+diff --git a/src/arch/aarch64/inc/hf/arch/spmd_helpers.h b/src/arch/aarch64/inc/hf/arch/spmd_helpers.h
+new file mode 100644
+index 0000000..6e11c36
+--- /dev/null
++++ b/src/arch/aarch64/inc/hf/arch/spmd_helpers.h
+@@ -0,0 +1,15 @@
++/*
++ * Copyright 2020 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.
++ */
++
++#define SPMD_ID 0xFFFF
++#define SPMD_DIRECT_MSG_SET_ENTRY_POINT 1
++
++/**
++ * Get SPMC ID stored in the manifest.
++ */
++ffa_vm_id_t get_ffa_id(void);
+diff --git a/src/cpu.c b/src/cpu.c
+index 0a3fc6f..42a17fa 100644
+--- a/src/cpu.c
++++ b/src/cpu.c
+@@ -138,6 +138,8 @@ bool cpu_on(struct cpu *c, ipaddr_t entry, uintreg_t arg)
+ c->is_on = true;
+ sl_unlock(&c->lock);
+
++#if SECURE_WORLD == 0
++
+ if (!prev) {
+ struct vm *vm = vm_find(HF_PRIMARY_VM_ID);
+ struct vcpu *vcpu = vm_get_vcpu(vm, cpu_index(c));
+@@ -148,6 +150,11 @@ bool cpu_on(struct cpu *c, ipaddr_t entry, uintreg_t arg)
+ vcpu_unlock(&vcpu_locked);
+ }
+
++#else
++ (void)entry;
++ (void)arg;
++#endif
++
+ return prev;
+ }
+
+diff --git a/src/init.c b/src/init.c
+index a5b48ab..0121213 100644
+--- a/src/init.c
++++ b/src/init.c
+@@ -146,6 +146,8 @@ void one_time_init(void)
+
+ cpu_module_init(params.cpu_ids, params.cpu_count);
+
++ arch_psci_secondary_core_init(¶ms);
++
+ /* Load all VMs. */
+ update.reserved_ranges_count = 0;
+ if (!load_vms(mm_stage1_locked, &manifest, &cpio, ¶ms, &update,
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0002-FF-A-Cold-boot-and-wake-up-from-suspend.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0002-FF-A-Cold-boot-and-wake-up-from-suspend.patch
new file mode 100644
index 0000000..0b58637
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0002-FF-A-Cold-boot-and-wake-up-from-suspend.patch
@@ -0,0 +1,65 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 8422e2a5d6b2094f9f451a2d818a593cba29af84 Mon Sep 17 00:00:00 2001
+From: Max Shvetsov <maksims.svecovs@arm.com>
+Date: Thu, 27 Aug 2020 12:39:50 +0100
+Subject: [PATCH 2/4] FF-A: Cold boot and wake up from suspend.
+
+WIP: Currently there is zero entry-point passed with no arguments, This
+will be reworked once a proper way to pass this information will be
+defined.
+
+Change-Id: Ic6050af16d4081ca31729744995fbb999b170e11
+Signed-off-by: Max Shvetsov <maksims.svecovs@arm.com>
+---
+ src/main.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/src/main.c b/src/main.c
+index 5f30aac..7b7264f 100644
+--- a/src/main.c
++++ b/src/main.c
+@@ -7,6 +7,7 @@
+ */
+
+ #include "hf/cpu.h"
++#include "hf/dlog.h"
+ #include "hf/vm.h"
+
+ /**
+@@ -16,9 +17,31 @@
+ struct vcpu *cpu_main(struct cpu *c)
+ {
+ struct vcpu *vcpu;
++
+ #if SECURE_WORLD == 1
+ struct vm *first_boot = vm_get_first_boot();
+
++ if (c->is_on == false) {
++ /*
++ * This is the PSCI warm reset path (svc_cpu_on_finish
++ * handler relayed by SPMD). Notice currenty the "first_boot"
++ * VM is resumed on any CPU on event.
++ */
++ (void)cpu_on(c, ipa_init(0UL), 0UL);
++ dlog_verbose("%s: cpu mpidr 0x%x on\n", __func__, c->id);
++ }
++
++ /*
++ * If `vm_get_first_boot` returns a valid vm, the first partition to
++ * execute is in accordance to the boot-order field of the partition's
++ * manifest.
++ * Else, no partition has been configured with the "boot-order" field
++ * in its manifest, and primary vm should be booted.
++ */
++ if (!first_boot) {
++ first_boot = vm_find(HF_PRIMARY_VM_ID);
++ }
++
+ vcpu = vm_get_vcpu(first_boot, cpu_index(c));
+ #else
+ vcpu = vm_get_vcpu(vm_find(HF_PRIMARY_VM_ID), cpu_index(c));
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0003-FF-A-Respond-to-PSCI_CPU_OFF-from-SPMD.patch b/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0003-FF-A-Respond-to-PSCI_CPU_OFF-from-SPMD.patch
new file mode 100644
index 0000000..83aeca3
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/hafnium/files/tc0/0003-FF-A-Respond-to-PSCI_CPU_OFF-from-SPMD.patch
@@ -0,0 +1,87 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 66d7628fea54dd7a25d25a13eb4f732c0a3428d0 Mon Sep 17 00:00:00 2001
+From: Max Shvetsov <maksims.svecovs@arm.com>
+Date: Fri, 18 Sep 2020 13:52:20 +0100
+Subject: [PATCH 3/4] FF-A: Respond to PSCI_CPU_OFF from SPMD.
+
+At run-time when a PSCI call is made from NWd, the corresponding SPMD PM
+hooks gets called and is eventually routed to the SPMC. This change
+implements a generic "SPMD handler" processing PM events that may be
+conveyed from SPMD to SPMC such as core suspend, core off.
+
+Change-Id: Id288e26d9fbb8328acc71f5cf68c39e095a0e3da
+Signed-off-by: Max Shvetsov <maksims.svecovs@arm.com>
+---
+ src/arch/aarch64/hypervisor/handler.c | 40 ++++++++++++++++++++++++++-
+ 1 file changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
+index c10f77e..95d6a18 100644
+--- a/src/arch/aarch64/hypervisor/handler.c
++++ b/src/arch/aarch64/hypervisor/handler.c
+@@ -13,6 +13,7 @@
+ #include "hf/arch/mmu.h"
+ #include "hf/arch/other_world.h"
+ #include "hf/arch/plat/smc.h"
++#include "hf/arch/spmd_helpers.h"
+
+ #include "hf/api.h"
+ #include "hf/check.h"
+@@ -478,6 +479,41 @@ static bool ffa_handler(struct ffa_value *args, struct vcpu *current,
+
+ #if SECURE_WORLD == 1
+
++/**
++ * Returns true if the message is sent directly from SPMD to SPMC.
++ */
++static bool is_spmd_message(const uint64_t arg)
++{
++ return (((arg & 0xFFFF) == get_ffa_id()) &&
++ (((arg >> 16) & 0xFFFF) == SPMD_ID));
++}
++
++/**
++ * Handle special direct messages from SPMD to SPMC. For now related to power
++ * management only.
++ */
++static bool spmd_handler(struct ffa_value *ret)
++{
++ if (!is_spmd_message(ret->arg1)) {
++ return false;
++ }
++
++ dlog_verbose("%s Handling direct PSCI calls from SPMD\n", __func__);
++
++ switch (ret->arg3) {
++ case PSCI_CPU_OFF:
++ ret->func = FFA_MSG_SEND_DIRECT_RESP_32;
++ ret->arg1 = (get_ffa_id() << 16) | SPMD_ID;
++ ret->arg2 = 0U;
++ break;
++ default:
++ dlog_verbose("Following message not handled %#x\n", ret->arg3);
++ return false;
++ }
++
++ return true;
++}
++
+ /**
+ * Called to switch to the other world and handle FF-A calls from it. Returns
+ * when it is ready to run a secure partition again.
+@@ -510,7 +546,9 @@ static void other_world_switch_loop(struct vcpu *other_world_vcpu,
+ * the result of the call back to EL3 unless the API handler
+ * sets *next to something different.
+ */
+- if (!ffa_handler(&other_world_args, other_world_vcpu, next)) {
++
++ if (!spmd_handler(&other_world_args) &&
++ !ffa_handler(&other_world_args, other_world_vcpu, next)) {
+ other_world_args.func = SMCCC_ERROR_UNKNOWN;
+ }
+ }
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc0.inc b/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc0.inc
new file mode 100644
index 0000000..51747ce
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/hafnium/hafnium-tc0.inc
@@ -0,0 +1,19 @@
+# TC0 specific configuration
+
+# Intermediate SHA with 2.4 baseline version
+SRCREV = "ee68c5494dea5c5a59aa02af46b35ab3d949672e"
+PV = "2.4+git${SRCPV}"
+
+FILESEXTRAPATHS_prepend_tc0 := "${THISDIR}/files/tc0:"
+
+SRC_URI_append = " \
+ file://0001-FF-A-Register-secondary-core-entry-point-at-SPMC-ini.patch \
+ file://0002-FF-A-Cold-boot-and-wake-up-from-suspend.patch \
+ file://0003-FF-A-Respond-to-PSCI_CPU_OFF-from-SPMD.patch \
+ "
+
+COMPATIBLE_MACHINE = "tc0"
+
+HAFNIUM_PROJECT = "reference"
+HAFNIUM_PLATFORM = "secure_tc0"
+HAFNIUM_INSTALL_TARGET = "hafnium"
diff --git a/meta-arm-bsp/recipes-bsp/hafnium/hafnium_2.4.bbappend b/meta-arm-bsp/recipes-bsp/hafnium/hafnium_2.4.bbappend
new file mode 100644
index 0000000..a6e6874
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/hafnium/hafnium_2.4.bbappend
@@ -0,0 +1,6 @@
+# Machine specific configurations
+
+MACHINE_HAFNIUM_REQUIRE ?= ""
+MACHINE_HAFNIUM_REQUIRE_tc0 = "hafnium-tc0.inc"
+
+require ${MACHINE_HAFNIUM_REQUIRE}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 04/10] arm-bsp/tc0: Add support for optee
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
2021-01-12 15:20 ` [PATCH 02/10] arm/trusted-firmware-a: Add support for spmd build option arunachalam.ganapathy
2021-01-12 15:20 ` [PATCH 03/10] arm-bsp/tc0: Add hafnium support Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 05/10] arm-bsp/tc0: Add tc0 platform support patches " Arunachalam Ganapathy
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
This patch adds optee-os, optee-client, optee-test support in tc0 bsp.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I65f795b7ec2b4def4778b286b2f744b06b177157
---
.../recipes-security/optee/optee-client-tc0.inc | 5 +++++
.../optee/optee-client_3.11.0.bbappend | 6 ++++++
.../recipes-security/optee/optee-os-tc0.inc | 16 ++++++++++++++++
.../optee/optee-os_3.11.0.bbappend | 6 ++++++
.../recipes-security/optee/optee-test-tc0.inc | 14 ++++++++++++++
.../optee/optee-test_3.11.0.bbappend | 6 ++++++
6 files changed, 53 insertions(+)
create mode 100644 meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc
create mode 100644 meta-arm-bsp/recipes-security/optee/optee-client_3.11.0.bbappend
create mode 100644 meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
create mode 100644 meta-arm-bsp/recipes-security/optee/optee-os_3.11.0.bbappend
create mode 100644 meta-arm-bsp/recipes-security/optee/optee-test-tc0.inc
create mode 100644 meta-arm-bsp/recipes-security/optee/optee-test_3.11.0.bbappend
diff --git a/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc b/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc
new file mode 100644
index 0000000..8b13386
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc
@@ -0,0 +1,5 @@
+# TC0 specific configuration
+
+# Intermediate SHA with 3.11 baseline version
+SRCREV = "3f44b870299514ad8c6b7dee776eb2994d9c1cd4"
+PV = "3.11.0+git${SRCPV}"
diff --git a/meta-arm-bsp/recipes-security/optee/optee-client_3.11.0.bbappend b/meta-arm-bsp/recipes-security/optee/optee-client_3.11.0.bbappend
new file mode 100644
index 0000000..fa4fd69
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-client_3.11.0.bbappend
@@ -0,0 +1,6 @@
+# Machine specific configurations
+
+MACHINE_OPTEE_CLIENT_REQUIRE ?= ""
+MACHINE_OPTEE_CLIENT_REQUIRE_tc0 = "optee-client-tc0.inc"
+
+require ${MACHINE_OPTEE_CLIENT_REQUIRE}
diff --git a/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc b/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
new file mode 100644
index 0000000..a700daf
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
@@ -0,0 +1,16 @@
+# TC0 specific configuration
+
+# Intermediate SHA with 3.11 baseline version
+SRCREV = "3284d935bc7e7bf7abfb5b19394a387d975d6dd4"
+PV = "3.11.0+git${SRCPV}"
+
+# This is incorporated into the SRCREV above
+SRC_URI_remove = " \
+ file://0001-libutils-provide-empty-__getauxval-implementation.patch \
+ file://0002-link.mk-implement-support-for-libnames-after-libgcc-.patch \
+ file://0003-ta_dev_kit.mk-make-sure-that-libutils-is-linked-seco.patch \
+"
+
+COMPATIBLE_MACHINE = "tc0"
+
+OPTEEMACHINE = "totalcompute-tc0"
diff --git a/meta-arm-bsp/recipes-security/optee/optee-os_3.11.0.bbappend b/meta-arm-bsp/recipes-security/optee/optee-os_3.11.0.bbappend
new file mode 100644
index 0000000..7b96a4d
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-os_3.11.0.bbappend
@@ -0,0 +1,6 @@
+# Machine specific configurations
+
+MACHINE_OPTEE_OS_REQUIRE ?= ""
+MACHINE_OPTEE_OS_REQUIRE_tc0 = "optee-os-tc0.inc"
+
+require ${MACHINE_OPTEE_OS_REQUIRE}
diff --git a/meta-arm-bsp/recipes-security/optee/optee-test-tc0.inc b/meta-arm-bsp/recipes-security/optee/optee-test-tc0.inc
new file mode 100644
index 0000000..cca5076
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-test-tc0.inc
@@ -0,0 +1,14 @@
+# TC0 specific configuration
+
+# Intermediate SHA with 3.11 baseline version
+SRCREV = "b35df64954ef96e09c0d5573014f4d1432dbc92f"
+PV = "3.11.0+git${SRCPV}"
+
+# This is incorporated into the SRCREV above
+SRC_URI_remove = " \
+ file://0001-host-xtest-Adjust-order-of-including-compiler.h.patch \
+ file://0002-make-remove-Wno-unsafe-loop-for-clang.patch \
+ file://0003-make-remove-Wmissing-noreturn-for-clang.patch \
+"
+
+COMPATIBLE_MACHINE = "tc0"
diff --git a/meta-arm-bsp/recipes-security/optee/optee-test_3.11.0.bbappend b/meta-arm-bsp/recipes-security/optee/optee-test_3.11.0.bbappend
new file mode 100644
index 0000000..4fd1cde
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-test_3.11.0.bbappend
@@ -0,0 +1,6 @@
+# Machine specific configurations
+
+MACHINE_OPTEE_TEST_REQUIRE ?= ""
+MACHINE_OPTEE_TEST_REQUIRE_tc0 = "optee-test-tc0.inc"
+
+require ${MACHINE_OPTEE_TEST_REQUIRE}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 05/10] arm-bsp/tc0: Add tc0 platform support patches for optee
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (2 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 04/10] arm-bsp/tc0: Add support for optee Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 06/10] arm-bsp/tc0: Enable optee core with SPMC at SEL2 Arunachalam Ganapathy
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
These patches in optee-os adds support for
- tc0 platform
- SEL2 SPMC support in optee core
- support for tc0 SEL2 SPMC config
The patch in optee-client adds support for
- allocating page aligned shmem buffers
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I1cfe134bdcedc45adf446f46af0d2881815b98f6
---
...void-memcpy-when-using-TEEC_TempMemo.patch | 52 ++
...e-page-aligned-shared-memory-buffers.patch | 95 +++
...ore-SPMC-update-for-FF-A-version-1.0.patch | 50 ++
.../tc0/0002-core-add-thread_smccc.patch | 89 +++
...e-enable-SPCI-with-SPM-Core-at-S-EL2.patch | 623 ++++++++++++++++++
...fixes-to-align-with-upstream-hafnium.patch | 188 ++++++
...e-arm-Total-Compute-platform-support.patch | 187 ++++++
...alcompute-Add-support-for-S-EL2-SPMC.patch | 108 +++
...e-add-optee-manifest-file-and-sp-lay.patch | 73 ++
...e-define-tzdram-start-address-for-S-.patch | 36 +
.../optee/optee-client-tc0.inc | 7 +
.../recipes-security/optee/optee-os-tc0.inc | 15 +-
12 files changed, 1522 insertions(+), 1 deletion(-)
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0001-Revert-libteec-Avoid-memcpy-when-using-TEEC_TempMemo.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0002-Allocate-page-aligned-shared-memory-buffers.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0001-core-SPMC-update-for-FF-A-version-1.0.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0002-core-add-thread_smccc.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0003-core-enable-SPCI-with-SPM-Core-at-S-EL2.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0004-core-fixes-to-align-with-upstream-hafnium.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0005-core-arm-Total-Compute-platform-support.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0006-plat-totalcompute-Add-support-for-S-EL2-SPMC.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0007-plat-totalcompute-add-optee-manifest-file-and-sp-lay.patch
create mode 100644 meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0008-plat-totalcompute-define-tzdram-start-address-for-S-.patch
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0001-Revert-libteec-Avoid-memcpy-when-using-TEEC_TempMemo.patch b/meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0001-Revert-libteec-Avoid-memcpy-when-using-TEEC_TempMemo.patch
new file mode 100644
index 0000000..4515c1d
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0001-Revert-libteec-Avoid-memcpy-when-using-TEEC_TempMemo.patch
@@ -0,0 +1,52 @@
+Upstream-Status: Pending [https://github.com/jenswi-linaro/optee_client/commit/7e569bdf770f635c5de1f4e659d41039a6199a0b]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 7e569bdf770f635c5de1f4e659d41039a6199a0b Mon Sep 17 00:00:00 2001
+From: Jens Wiklander <jens.wiklander@linaro.org>
+Date: Wed, 11 Nov 2020 10:09:38 +0100
+Subject: [PATCH 1/2] Revert "libteec: Avoid memcpy() when using
+ TEEC_TempMemoryReference"
+
+This reverts commit dcb13e2f457fa98e9ba49dd2a364542680671e95.
+---
+ libteec/src/tee_client_api.c | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/libteec/src/tee_client_api.c b/libteec/src/tee_client_api.c
+index 6b81e09..b8ccdfa 100644
+--- a/libteec/src/tee_client_api.c
++++ b/libteec/src/tee_client_api.c
+@@ -217,15 +217,11 @@ static TEEC_Result teec_pre_process_tmpref(TEEC_Context *ctx,
+ MEMREF_SHM_ID(param) = shm->id;
+ }
+ } else {
+- shm->buffer = tmpref->buffer;
+- res = TEEC_RegisterSharedMemory(ctx, shm);
++ res = TEEC_AllocateSharedMemory(ctx, shm);
+ if (res != TEEC_SUCCESS)
+ return res;
+
+- if (shm->shadow_buffer)
+- memcpy(shm->shadow_buffer, tmpref->buffer,
+- tmpref->size);
+-
++ memcpy(shm->buffer, tmpref->buffer, tmpref->size);
+ MEMREF_SHM_ID(param) = shm->id;
+ }
+
+@@ -388,10 +384,8 @@ static void teec_post_process_tmpref(uint32_t param_type,
+ TEEC_SharedMemory *shm)
+ {
+ if (param_type != TEEC_MEMREF_TEMP_INPUT) {
+- if (MEMREF_SIZE(param) <= tmpref->size && tmpref->buffer &&
+- shm->shadow_buffer)
+- memcpy(tmpref->buffer, shm->shadow_buffer,
+- MEMREF_SIZE(param));
++ if (MEMREF_SIZE(param) <= tmpref->size && tmpref->buffer)
++ memcpy(tmpref->buffer, shm->buffer, MEMREF_SIZE(param));
+
+ tmpref->size = MEMREF_SIZE(param);
+ }
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0002-Allocate-page-aligned-shared-memory-buffers.patch b/meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0002-Allocate-page-aligned-shared-memory-buffers.patch
new file mode 100644
index 0000000..5928bfd
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-client/tc0/0002-Allocate-page-aligned-shared-memory-buffers.patch
@@ -0,0 +1,95 @@
+Upstream-Status: Pending [https://github.com/jenswi-linaro/optee_client/commit/7a67f8b7681ecf3abb5b09e5e320857d16f4a7e6]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 7a67f8b7681ecf3abb5b09e5e320857d16f4a7e6 Mon Sep 17 00:00:00 2001
+From: Jens Wiklander <jens.wiklander@linaro.org>
+Date: Mon, 16 Nov 2020 17:34:07 +0100
+Subject: [PATCH 2/2] Allocate page aligned shared memory buffers
+
+Allocate page aligned shared memory buffer guarantee that each shared
+memory buffer doesn't accidentally share a page of memory or they may
+become aliased when mapped in secure world. This is normally not a big
+problem but may make it a bit harder to track down buffer overruns in
+shared memory buffers.
+
+In a post Arm v8.4 architecture with FF-A [1] there's trouble since it's
+not permitted to share the same physical page twice.
+
+Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
+---
+ libteec/src/tee_client_api.c | 14 ++++++++++++--
+ tee-supplicant/src/tee_supplicant.c | 12 +++++++++++-
+ 2 files changed, 23 insertions(+), 3 deletions(-)
+
+diff --git a/libteec/src/tee_client_api.c b/libteec/src/tee_client_api.c
+index b8ccdfa..676d373 100644
+--- a/libteec/src/tee_client_api.c
++++ b/libteec/src/tee_client_api.c
+@@ -74,6 +74,16 @@ static void teec_mutex_unlock(pthread_mutex_t *mu)
+ pthread_mutex_unlock(mu);
+ }
+
++static void *teec_paged_aligned_alloc(size_t sz)
++{
++ void *p = NULL;
++
++ if (!posix_memalign(&p, sysconf(_SC_PAGESIZE), sz))
++ return p;
++
++ return NULL;
++}
++
+ static int teec_open_dev(const char *devname, const char *capabilities,
+ uint32_t *gen_caps)
+ {
+@@ -790,7 +800,7 @@ TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
+ * we're not making matters worse by trying to allocate and
+ * register a shadow buffer before giving up.
+ */
+- shm->shadow_buffer = malloc(s);
++ shm->shadow_buffer = teec_paged_aligned_alloc(s);
+ if (!shm->shadow_buffer)
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ fd = teec_shm_register(ctx->fd, shm->shadow_buffer, s,
+@@ -873,7 +883,7 @@ TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
+ s = 8;
+
+ if (ctx->reg_mem) {
+- shm->buffer = malloc(s);
++ shm->buffer = teec_paged_aligned_alloc(s);
+ if (!shm->buffer)
+ return TEEC_ERROR_OUT_OF_MEMORY;
+
+diff --git a/tee-supplicant/src/tee_supplicant.c b/tee-supplicant/src/tee_supplicant.c
+index 94cf382..d590c2b 100644
+--- a/tee-supplicant/src/tee_supplicant.c
++++ b/tee-supplicant/src/tee_supplicant.c
+@@ -127,6 +127,16 @@ static size_t num_waiters_dec(struct thread_arg *arg)
+ return ret;
+ }
+
++static void *paged_aligned_alloc(size_t sz)
++{
++ void *p = NULL;
++
++ if (!posix_memalign(&p, sysconf(_SC_PAGESIZE), sz))
++ return p;
++
++ return NULL;
++}
++
+ static int get_value(size_t num_params, struct tee_ioctl_param *params,
+ const uint32_t idx, struct param_value **value)
+ {
+@@ -336,7 +346,7 @@ static struct tee_shm *register_local_shm(int fd, size_t size)
+
+ memset(&data, 0, sizeof(data));
+
+- buf = malloc(size);
++ buf = paged_aligned_alloc(size);
+ if (!buf)
+ return NULL;
+
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0001-core-SPMC-update-for-FF-A-version-1.0.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0001-core-SPMC-update-for-FF-A-version-1.0.patch
new file mode 100644
index 0000000..d3b2319
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0001-core-SPMC-update-for-FF-A-version-1.0.patch
@@ -0,0 +1,50 @@
+Upstream-Status: Pending [https://github.com/jenswi-linaro/optee_os/commit/7c3b052b871420618a08402f626923fe85a139db]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 7c3b052b871420618a08402f626923fe85a139db Mon Sep 17 00:00:00 2001
+From: Marc Bonnici <marc.bonnici@arm.com>
+Date: Wed, 23 Sep 2020 13:55:22 +0100
+Subject: [PATCH 1/3] core: SPMC: update for FF-A version 1.0
+
+Update expected memory attributes. As per the FF-A spec (5.11.3) a
+lender of a memory region should not specify the instruction access
+permission, therefore update the expected memory attribute.
+
+Updates the version number to 1.0 replacing the previous version number
+0.9.
+---
+ core/arch/arm/include/optee_ffa.h | 4 ++--
+ core/arch/arm/kernel/thread_spmc.c | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/core/arch/arm/include/optee_ffa.h b/core/arch/arm/include/optee_ffa.h
+index 8498fbab..9daca732 100644
+--- a/core/arch/arm/include/optee_ffa.h
++++ b/core/arch/arm/include/optee_ffa.h
+@@ -27,8 +27,8 @@
+ * w3-w7: Implementation defined, free to be used below
+ */
+
+-#define OPTEE_FFA_VERSION_MAJOR UINT32_C(0)
+-#define OPTEE_FFA_VERSION_MINOR UINT32_C(9)
++#define OPTEE_FFA_VERSION_MAJOR UINT32_C(1)
++#define OPTEE_FFA_VERSION_MINOR UINT32_C(0)
+
+ #define OPTEE_FFA_BLOCKING_CALL(id) UINT32_C(id)
+ #define OPTEE_FFA_YIELDING_CALL_BIT 31
+diff --git a/core/arch/arm/kernel/thread_spmc.c b/core/arch/arm/kernel/thread_spmc.c
+index 81edf03a..16f3bbe1 100644
+--- a/core/arch/arm/kernel/thread_spmc.c
++++ b/core/arch/arm/kernel/thread_spmc.c
+@@ -433,7 +433,7 @@ static int mem_share_init(void *buf, size_t blen, unsigned int *page_count,
+ {
+ struct mem_region_descr *region_descr = NULL;
+ struct mem_transaction_descr *descr = NULL;
+- const uint8_t exp_mem_acc_perm = 0x6; /* Not executable, Read-write */
++ const uint8_t exp_mem_acc_perm = 0x2; /* Read-write */
+ /* Normal memory, Write-Back cacheable, Inner shareable */
+ const uint8_t exp_mem_reg_attr = 0x2f;
+ unsigned int num_mem_accs = 0;
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0002-core-add-thread_smccc.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0002-core-add-thread_smccc.patch
new file mode 100644
index 0000000..32a420e
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0002-core-add-thread_smccc.patch
@@ -0,0 +1,89 @@
+Upstream-Status: Pending [https://github.com/jenswi-linaro/optee_os/commit/269e226eea2b2f26a6f844b7d25bc2b2a9b26315]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 269e226eea2b2f26a6f844b7d25bc2b2a9b26315 Mon Sep 17 00:00:00 2001
+From: Jens Wiklander <jens.wiklander@linaro.org>
+Date: Tue, 4 Feb 2020 17:30:55 +0100
+Subject: [PATCH 2/3] core: add thread_smccc()
+
+Adds the assembly function thread_smccc() which loads the first 8
+registers with the argument and executes an SMC or HVC instruction as
+appropriate. The result in the first 8 registers is then saved in the
+argument struct.
+
+Change-Id: Ie14154fb38de5ced3cfdebdb0bf19e48caaf2279
+Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
+---
+ core/arch/arm/include/kernel/thread.h | 1 +
+ core/arch/arm/kernel/thread_a32.S | 16 ++++++++++++++++
+ core/arch/arm/kernel/thread_a64.S | 15 +++++++++++++++
+ 3 files changed, 32 insertions(+)
+
+diff --git a/core/arch/arm/include/kernel/thread.h b/core/arch/arm/include/kernel/thread.h
+index b9c0ba4b..4f0520e9 100644
+--- a/core/arch/arm/include/kernel/thread.h
++++ b/core/arch/arm/include/kernel/thread.h
+@@ -704,6 +704,7 @@ uint32_t thread_rpc_cmd(uint32_t cmd, size_t num_params,
+
+ unsigned long thread_smc(unsigned long func_id, unsigned long a1,
+ unsigned long a2, unsigned long a3);
++void thread_smccc(struct thread_smc_args *arg_res);
+
+ /**
+ * Allocate data for payload buffers.
+diff --git a/core/arch/arm/kernel/thread_a32.S b/core/arch/arm/kernel/thread_a32.S
+index 199e90a9..75d85c32 100644
+--- a/core/arch/arm/kernel/thread_a32.S
++++ b/core/arch/arm/kernel/thread_a32.S
+@@ -210,6 +210,22 @@ FUNC thread_smc , :
+ bx lr
+ END_FUNC thread_smc
+
++/* void thread_smccc(struct thread_smc_args *arg_res) */
++FUNC thread_smccc , :
++ push {r4-r7}
++ push {r0, lr}
++ ldm r0, {r0-r7}
++#ifdef CFG_CORE_SEL2_SPMC
++ hvc #0
++#else
++ smc #0
++#endif
++ pop {r12, lr}
++ stm r12, {r0-r7}
++ pop {r4-r7}
++ bx lr
++END_FUNC thread_smccc
++
+ FUNC thread_init_vbar , :
+ /* Set vector (VBAR) */
+ write_vbar r0
+diff --git a/core/arch/arm/kernel/thread_a64.S b/core/arch/arm/kernel/thread_a64.S
+index 9ce31eb2..3e0f5115 100644
+--- a/core/arch/arm/kernel/thread_a64.S
++++ b/core/arch/arm/kernel/thread_a64.S
+@@ -65,6 +65,21 @@ FUNC thread_smc , :
+ ret
+ END_FUNC thread_smc
+
++/* void thread_smccc(struct thread_smc_args *arg_res) */
++FUNC thread_smccc , :
++ push x0, xzr
++ mov x8, x0
++ load_xregs x8, 0, 0, 7
++#ifdef CFG_CORE_SEL2_SPMC
++ hvc #0
++#else
++ smc #0
++#endif
++ pop x8, xzr
++ store_xregs x8, 0, 0, 7
++ ret
++END_FUNC thread_smccc
++
+ FUNC thread_init_vbar , :
+ msr vbar_el1, x0
+ ret
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0003-core-enable-SPCI-with-SPM-Core-at-S-EL2.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0003-core-enable-SPCI-with-SPM-Core-at-S-EL2.patch
new file mode 100644
index 0000000..c3967dc
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0003-core-enable-SPCI-with-SPM-Core-at-S-EL2.patch
@@ -0,0 +1,623 @@
+Upstream-Status: Pending [https://github.com/jenswi-linaro/optee_os/commit/80f0ec4ba2af33584e99e917fa165b77028a511f]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 80f0ec4ba2af33584e99e917fa165b77028a511f Mon Sep 17 00:00:00 2001
+From: Marc Bonnici <marc.bonnici@arm.com>
+Date: Fri, 5 Jun 2020 13:47:40 +0100
+Subject: [PATCH 3/3] core: enable SPCI with SPM Core at S-EL2
+
+This is a port of a pre-exisiting patch to support the case where
+the SPM Core is implementation at S-EL2, that is, in a secure hypervisor.
+This configuration is also know as "S-EL2 SPMC" in the FFA specification.
+
+Compile with CFG_CORE_SEL2_SPMC=y
+
+Note that this is an experimental feature, ABIs etc may have
+incompatible changes.
+
+Sqaushed in:
+ core: Update cookie to uint64 in S-EL2 code
+
+ As part of the update to FF-A 1.0 the globally
+ unique handle to identify a shared memory object is now 64
+ bits wide instead of 32. This commit updates the
+ remaining usage of 32 bit values.
+
+ core: Remove page count from S-EL2 code
+
+ The page count field has been dropped from upstream OP-TEE to
+ accommodate using a 64 bit handle in the same size message param struct,
+ therefore update our implementation to support this.
+
+ core: Update remaining FF-A structures to EAC
+
+ Update relinquish data structures and ABI invocations to the FFA
+ EAC spec
+---
+ core/arch/arm/arm.mk | 7 ++
+ core/arch/arm/include/kernel/thread.h | 6 +
+ core/arch/arm/include/mm/mobj.h | 6 +
+ core/arch/arm/kernel/thread_spmc.c | 164 ++++++++++++++++++++++++-
+ core/arch/arm/kernel/thread_spmc_a64.S | 3 +-
+ core/arch/arm/mm/mobj_ffa.c | 104 +++++++++++-----
+ core/arch/arm/plat-vexpress/conf.mk | 5 +
+ 7 files changed, 260 insertions(+), 35 deletions(-)
+
+diff --git a/core/arch/arm/arm.mk b/core/arch/arm/arm.mk
+index f495f3c9..7c5e8fb0 100644
+--- a/core/arch/arm/arm.mk
++++ b/core/arch/arm/arm.mk
+@@ -97,6 +97,13 @@ endif
+ # changes
+ ifeq ($(CFG_CORE_SEL1_SPMC),y)
+ $(call force,CFG_CORE_FFA,y)
++$(call force,CFG_CORE_SEL2_SPMC,n)
++endif
++# SPMC configuration "S-EL2 SPMC" where SPM Core is implemented at S-EL2,
++# that is, the hypervisor sandboxing OP-TEE
++ifeq ($(CFG_CORE_SEL2_SPMC),y)
++$(call force,CFG_CORE_FFA,y)
++$(call force,CFG_CORE_SEL1_SPMC,n)
+ endif
+
+ # Unmaps all kernel mode code except the code needed to take exceptions
+diff --git a/core/arch/arm/include/kernel/thread.h b/core/arch/arm/include/kernel/thread.h
+index 4f0520e9..95f48589 100644
+--- a/core/arch/arm/include/kernel/thread.h
++++ b/core/arch/arm/include/kernel/thread.h
+@@ -759,6 +759,12 @@ enum thread_shm_cache_user {
+ void *thread_rpc_shm_cache_alloc(enum thread_shm_cache_user user,
+ enum thread_shm_type shm_type,
+ size_t size, struct mobj **mobj);
++
++#if defined(CFG_CORE_SEL2_SPMC)
++struct mobj_ffa *thread_spmc_populate_mobj_from_rx(uint64_t cookie);
++void thread_spmc_relinquish(uint64_t memory_region_handle);
++#endif
++
+ #endif /*__ASSEMBLER__*/
+
+ #endif /*KERNEL_THREAD_H*/
+diff --git a/core/arch/arm/include/mm/mobj.h b/core/arch/arm/include/mm/mobj.h
+index 2b9bd90c..3f820666 100644
+--- a/core/arch/arm/include/mm/mobj.h
++++ b/core/arch/arm/include/mm/mobj.h
+@@ -216,6 +216,12 @@ struct mobj_ffa *mobj_ffa_sel1_spmc_new(unsigned int num_pages);
+ void mobj_ffa_sel1_spmc_delete(struct mobj_ffa *mobj);
+ TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie);
+ #endif
++#ifdef CFG_CORE_SEL2_SPMC
++struct mobj_ffa *mobj_ffa_sel2_spmc_new(uint64_t cookie,
++ unsigned int num_pages);
++void mobj_ffa_sel2_spmc_delete(struct mobj_ffa *mobj);
++#endif
++
+ uint64_t mobj_ffa_get_cookie(struct mobj_ffa *mobj);
+ TEE_Result mobj_ffa_add_pages_at(struct mobj_ffa *mobj, unsigned int *idx,
+ paddr_t pa, unsigned int num_pages);
+diff --git a/core/arch/arm/kernel/thread_spmc.c b/core/arch/arm/kernel/thread_spmc.c
+index 16f3bbe1..3d7dc035 100644
+--- a/core/arch/arm/kernel/thread_spmc.c
++++ b/core/arch/arm/kernel/thread_spmc.c
+@@ -7,6 +7,7 @@
+ #include <assert.h>
+ #include <ffa.h>
+ #include <io.h>
++#include <initcall.h>
+ #include <kernel/interrupt.h>
+ #include <kernel/panic.h>
+ #include <kernel/spinlock.h>
+@@ -88,6 +89,18 @@ struct mem_frag_state {
+
+ static uint16_t my_sp_id = 0x8001;
+
++
++/* Table 149: FFA_MEM_RELINQUISH. */
++struct ffa_relinquish_descriptor {
++ uint64_t handle;
++ uint32_t flags;
++ uint32_t endpoint_count;
++ uint16_t endpoint_id_array[];
++};
++
++/* Our VM ID is 0x8001, non-secure VM ID 0x0001 */
++const uint32_t thread_spmc_target_info = 0x80010001;
++
+ /*
+ * If @rxtx_size is 0 RX/TX buffers are not mapped or initialized.
+ *
+@@ -101,8 +114,16 @@ static uint16_t my_sp_id = 0x8001;
+ * these buffers so we must always be careful when reading. while we hold
+ * the lock.
+ */
++
++#ifdef CFG_CORE_SEL2_SPMC
++static uint8_t rx_buf[SMALL_PAGE_SIZE] __aligned(SMALL_PAGE_SIZE);
++static uint8_t tx_buf[SMALL_PAGE_SIZE] __aligned(SMALL_PAGE_SIZE);
++#else
+ static void *rx_buf;
+ static void *tx_buf;
++#endif
++
++
+ static unsigned int rxtx_size;
+ static unsigned int rxtx_spinlock;
+ static bool tx_buf_is_mine;
+@@ -127,6 +148,28 @@ static void set_args(struct thread_smc_args *args, uint32_t fid,
+ .a5 = w5, };
+ }
+
++static int __maybe_unused
++set_pages(struct constituent_address_range *regions, unsigned int num_regions,
++ unsigned int num_pages, struct mobj_ffa *mf)
++{
++ unsigned int n = 0;
++ unsigned int idx = 0;
++
++ for (n = 0; n < num_regions; n++) {
++ unsigned int page_count = READ_ONCE(regions[n].page_count);
++ uint64_t addr = READ_ONCE(regions[n].address);
++
++ if (mobj_ffa_add_pages_at(mf, &idx, addr, page_count))
++ return FFA_INVALID_PARAMETERS;
++ }
++
++ if (idx != num_pages)
++ return FFA_INVALID_PARAMETERS;
++
++ return 0;
++}
++
++
+ static void handle_version(struct thread_smc_args *args)
+ {
+ /*
+@@ -188,6 +231,7 @@ static void handle_features(struct thread_smc_args *args)
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ);
+ }
+
++#ifdef CFG_CORE_SEL1_SPMC
+ static int map_buf(paddr_t pa, unsigned int sz, void **va_ret)
+ {
+ tee_mm_entry_t *mm = NULL;
+@@ -293,6 +337,7 @@ out:
+ set_args(args, ret_fid, FFA_PARAM_MBZ, rc,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ);
+ }
++#endif
+
+ static void handle_rx_release(struct thread_smc_args *args)
+ {
+@@ -408,6 +453,7 @@ static void handle_blocking_call(struct thread_smc_args *args)
+ }
+ }
+
++#if CFG_CORE_SEL1_SPMC
+ static int get_acc_perms(struct mem_accsess_descr *mem_acc,
+ unsigned int num_mem_accs, uint8_t *acc_perms,
+ unsigned int *region_offs)
+@@ -531,7 +577,11 @@ static int add_mem_share_frag(struct mem_frag_state *s, void *buf, size_t flen)
+
+ SLIST_REMOVE(&frag_state_head, s, mem_frag_state, link);
+ if (rc < 0)
++#ifdef CFG_CORE_SEL2_SPMC
++ mobj_ffa_sel2_spmc_delete(s->share.mf);
++#else
+ mobj_ffa_sel1_spmc_delete(s->share.mf);
++#endif
+ else
+ mobj_ffa_push_to_inactive(s->share.mf);
+ free(s);
+@@ -559,8 +609,8 @@ static int add_mem_share(tee_mm_entry_t *mm, void *buf, size_t blen,
+ sizeof(struct constituent_address_range), &n) ||
+ ADD_OVERFLOW(n, addr_range_offs, &n) || n > blen)
+ return FFA_INVALID_PARAMETERS;
+-
+ share.mf = mobj_ffa_sel1_spmc_new(share.page_count);
++
+ if (!share.mf)
+ return FFA_NO_MEMORY;
+
+@@ -601,6 +651,7 @@ static int add_mem_share(tee_mm_entry_t *mm, void *buf, size_t blen,
+ return 0;
+ err:
+ mobj_ffa_sel1_spmc_delete(share.mf);
++
+ return rc;
+ }
+
+@@ -809,6 +860,7 @@ static void handle_mem_reclaim(struct thread_smc_args *args)
+ out:
+ set_args(args, ret_fid, ret_val, 0, 0, 0, 0);
+ }
++#endif
+
+ /* Only called from assembly */
+ void thread_spmc_msg_recv(struct thread_smc_args *args);
+@@ -822,6 +874,7 @@ void thread_spmc_msg_recv(struct thread_smc_args *args)
+ case FFA_FEATURES:
+ handle_features(args);
+ break;
++#if CFG_CORE_SEL1_SPMC
+ #ifdef ARM64
+ case FFA_RXTX_MAP_64:
+ #endif
+@@ -831,6 +884,7 @@ void thread_spmc_msg_recv(struct thread_smc_args *args)
+ case FFA_RXTX_UNMAP:
+ handle_rxtx_unmap(args);
+ break;
++#endif
+ case FFA_RX_RELEASE:
+ handle_rx_release(args);
+ break;
+@@ -847,6 +901,7 @@ void thread_spmc_msg_recv(struct thread_smc_args *args)
+ else
+ handle_blocking_call(args);
+ break;
++#if CFG_CORE_SEL1_SPMC
+ #ifdef ARM64
+ case FFA_MEM_SHARE_64:
+ #endif
+@@ -859,6 +914,7 @@ void thread_spmc_msg_recv(struct thread_smc_args *args)
+ case FFA_MEM_FRAG_TX:
+ handle_mem_frag_tx(args);
+ break;
++#endif
+ default:
+ EMSG("Unhandled FFA function ID %#"PRIx32, (uint32_t)args->a0);
+ set_args(args, FFA_ERROR, FFA_PARAM_MBZ, FFA_NOT_SUPPORTED,
+@@ -1185,3 +1241,109 @@ void thread_rpc_free_global_payload(struct mobj *mobj __unused)
+
+ assert(!cant_happen);
+ }
++
++#ifdef CFG_CORE_SEL2_SPMC
++static void spmc_rxtx_map(void)
++{
++ struct thread_smc_args args = {
++ .a0 = FFA_RXTX_MAP_64,
++ .a1 = (vaddr_t)tx_buf,
++ .a2 = (vaddr_t)rx_buf,
++ .a3 = 1,
++ };
++
++ thread_smccc(&args);
++ if (args.a0 == FFA_ERROR) {
++ EMSG("ERROR rxtx map failed with error %ld\n", args.a2);
++ panic();
++ }
++}
++
++static struct mem_transaction_descr *spmc_retrieve_req(uint64_t cookie)
++{
++ struct mem_transaction_descr *retrieve_region = (void *)tx_buf;
++
++ struct thread_smc_args args = {
++ .a0 = FFA_MEM_RETRIEVE_REQ_64,
++ .a1 = sizeof(*retrieve_region), // Total Length
++ .a2 = sizeof(*retrieve_region), // Frag Length == Total length
++ .a3 = 0, // Address, Using TX -> MBZ
++ .a4 = 0 // Using TX -> MBZ
++ };
++
++ /* TODO pass all the information required by the spec */
++ memset(retrieve_region, 0, sizeof(*retrieve_region));
++ retrieve_region->global_handle = cookie;
++
++ thread_smccc(&args);
++ if (args.a0 == FFA_ERROR /*TODO != FFA_MEM_RETRIEVE_RESP_64 */) {
++ EMSG("Failed to fetch cookie %#"PRIx64, cookie);
++ return NULL;
++ }
++
++ return (void *)rx_buf;
++}
++
++void thread_spmc_relinquish(uint64_t cookie)
++{
++ struct ffa_relinquish_descriptor *relinquish_desc = (void *)tx_buf;
++
++ struct thread_smc_args args = {
++ .a0 = FFA_MEM_RELINQUISH,
++ };
++
++ memset(relinquish_desc, 0, sizeof(*relinquish_desc));
++ relinquish_desc->handle = cookie;
++ relinquish_desc->flags = 0;
++ /* TODO: Add endpoint details. */
++ thread_smccc(&args);
++ if (args.a0 != FFA_SUCCESS_32)
++ EMSG("Failed to relinquish cookie %#"PRIx64, cookie);
++}
++
++struct mobj_ffa *thread_spmc_populate_mobj_from_rx(uint64_t cookie)
++{
++ struct mem_transaction_descr *retrieve_desc;
++ struct mem_region_descr *descr;
++ struct mobj_ffa *mf;
++ uint32_t num_pages;
++
++
++ /* XXX Support single mem_region. */
++ retrieve_desc = spmc_retrieve_req(cookie);
++
++ if (!retrieve_desc) {
++ EMSG("Failed to retrieve cookie from rx buffer %#"PRIx64, cookie);
++ return NULL;
++ }
++
++ descr = (struct mem_region_descr *)
++ ((uint8_t *)retrieve_desc +
++ retrieve_desc->mem_accsess_descr_array[0].mem_region_offs);
++
++ num_pages = descr->total_page_count;
++ mf = mobj_ffa_sel2_spmc_new(cookie, num_pages);
++
++ if (!mf)
++ return NULL;
++
++ if (set_pages(descr->address_range_array,
++ descr->address_range_count,
++ num_pages, mf)) {
++ mobj_ffa_sel2_spmc_delete(mf);
++ return NULL;
++
++ }
++
++ return mf;
++}
++
++static TEE_Result spmc_init(void)
++{
++ spmc_rxtx_map();
++
++ return TEE_SUCCESS;
++}
++service_init(spmc_init);
++
++#endif /*CFG_CORE_SEL2_SPMC*/
+diff --git a/core/arch/arm/kernel/thread_spmc_a64.S b/core/arch/arm/kernel/thread_spmc_a64.S
+index 3d57da4d..66f9d0b4 100644
+--- a/core/arch/arm/kernel/thread_spmc_a64.S
++++ b/core/arch/arm/kernel/thread_spmc_a64.S
+@@ -17,7 +17,8 @@
+
+ FUNC thread_ffa_msg_wait , :
+ mov_imm x0, FFA_MSG_WAIT /* FID */
+- mov x1, #FFA_TARGET_INFO_MBZ /* Target info MBZ */
++ adr x1, thread_spmc_target_info
++ ldr w1, [x1]
+ mov x2, #FFA_PARAM_MBZ /* Param MBZ */
+ mov x3, #FFA_PARAM_MBZ /* Param MBZ */
+ mov x4, #FFA_PARAM_MBZ /* Param MBZ */
+diff --git a/core/arch/arm/mm/mobj_ffa.c b/core/arch/arm/mm/mobj_ffa.c
+index fd5e66ea..e2c585a2 100644
+--- a/core/arch/arm/mm/mobj_ffa.c
++++ b/core/arch/arm/mm/mobj_ffa.c
+@@ -19,8 +19,10 @@ struct mobj_ffa {
+ tee_mm_entry_t *mm;
+ struct refcount mapcount;
+ uint16_t page_offset;
++#ifdef CFG_CORE_SEL1_SPMC
+ bool registered_by_cookie;
+ bool unregistered_by_cookie;
++#endif
+ paddr_t pages[];
+ };
+
+@@ -186,6 +188,24 @@ void mobj_ffa_sel1_spmc_delete(struct mobj_ffa *mf)
+ }
+ #endif /*CFG_CORE_SEL1_SPMC*/
+
++#ifdef CFG_CORE_SEL2_SPMC
++struct mobj_ffa *mobj_ffa_sel2_spmc_new(uint64_t cookie,
++ unsigned int num_pages)
++{
++ struct mobj_ffa *mf = NULL;
++
++ mf = ffa_new(num_pages);
++ if (mf)
++ mf->cookie = cookie;
++ return mf;
++}
++
++void mobj_ffa_sel2_spmc_delete(struct mobj_ffa *mf)
++{
++ free(mf);
++}
++#endif /*CFG_CORE_SEL2_SPMC*/
++
+ TEE_Result mobj_ffa_add_pages_at(struct mobj_ffa *mf, unsigned int *idx,
+ paddr_t pa, unsigned int num_pages)
+ {
+@@ -234,7 +254,9 @@ static void unmap_helper(struct mobj_ffa *mf)
+ }
+ }
+
+-TEE_Result mobj_ffa_unregister_by_cookie(uint64_t cookie)
++
++#ifdef CFG_CORE_SEL1_SPMC
++TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie)
+ {
+ TEE_Result res = TEE_SUCCESS;
+ struct mobj_ffa *mf = NULL;
+@@ -244,7 +266,7 @@ TEE_Result mobj_ffa_unregister_by_cookie(uint64_t cookie)
+ mf = find_in_list(&shm_head, cmp_cookie, cookie);
+ /*
+ * If the mobj is found here it's still active and cannot be
+- * unregistered.
++ * reclaimed.
+ */
+ if (mf) {
+ DMSG("cookie %#"PRIx64" busy refc %u",
+@@ -252,24 +274,34 @@ TEE_Result mobj_ffa_unregister_by_cookie(uint64_t cookie)
+ res = TEE_ERROR_BUSY;
+ goto out;
+ }
++
+ mf = find_in_list(&shm_inactive_head, cmp_cookie, cookie);
++ if (!mf) {
++ res = TEE_ERROR_ITEM_NOT_FOUND;
++ goto out;
++ }
+ /*
+- * If the mobj isn't found or if it already has been unregistered.
++ * If the mobj has been registered via mobj_ffa_get_by_cookie()
++ * but not unregistered yet with mobj_ffa_unregister_by_cookie().
+ */
+- if (!mf || mf->unregistered_by_cookie) {
+- res = TEE_ERROR_ITEM_NOT_FOUND;
++ if (mf->registered_by_cookie && !mf->unregistered_by_cookie) {
++ DMSG("cookie %#"PRIx64" busy", cookie);
++ res = TEE_ERROR_BUSY;
+ goto out;
+ }
+- mf->unregistered_by_cookie = true;
+- res = TEE_SUCCESS;
+
++ if (!pop_from_list(&shm_inactive_head, cmp_ptr, (vaddr_t)mf))
++ panic();
++ res = TEE_SUCCESS;
+ out:
+ cpu_spin_unlock_xrestore(&shm_lock, exceptions);
++ if (!res)
++ mobj_ffa_sel1_spmc_delete(mf);
+ return res;
+ }
++#endif /*CFG_CORE_SEL1_SPMC*/
+
+-#ifdef CFG_CORE_SEL1_SPMC
+-TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie)
++TEE_Result mobj_ffa_unregister_by_cookie(uint64_t cookie)
+ {
+ TEE_Result res = TEE_SUCCESS;
+ struct mobj_ffa *mf = NULL;
+@@ -279,7 +311,7 @@ TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie)
+ mf = find_in_list(&shm_head, cmp_cookie, cookie);
+ /*
+ * If the mobj is found here it's still active and cannot be
+- * reclaimed.
++ * unregistered.
+ */
+ if (mf) {
+ DMSG("cookie %#"PRIx64" busy refc %u",
+@@ -287,43 +319,42 @@ TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie)
+ res = TEE_ERROR_BUSY;
+ goto out;
+ }
+-
+ mf = find_in_list(&shm_inactive_head, cmp_cookie, cookie);
+- if (!mf) {
+- res = TEE_ERROR_ITEM_NOT_FOUND;
+- goto out;
+- }
+ /*
+- * If the mobj has been registered via mobj_ffa_get_by_cookie()
+- * but not unregistered yet with mobj_ffa_unregister_by_cookie().
++ * If the mobj isn't found or if it already has been unregistered.
+ */
+- if (mf->registered_by_cookie && !mf->unregistered_by_cookie) {
+- DMSG("cookie %#"PRIx64" busy", cookie);
+- res = TEE_ERROR_BUSY;
++#ifdef CFG_CORE_SEL2_SPMC
++ if (!mf) {
++#else
++ if (!mf || mf->unregistered_by_cookie) {
++#endif
++ res = TEE_ERROR_ITEM_NOT_FOUND;
+ goto out;
+ }
+
+- if (!pop_from_list(&shm_inactive_head, cmp_ptr, (vaddr_t)mf))
+- panic();
++
++#ifdef CFG_CORE_SEL2_SPMC
++ mf = pop_from_list(&shm_inactive_head, cmp_cookie, cookie);
++ mobj_ffa_sel2_spmc_delete(mf);
++ thread_spmc_relinquish(cookie);
++#else
++ mf->unregistered_by_cookie = true;
++#endif
+ res = TEE_SUCCESS;
++
+ out:
+ cpu_spin_unlock_xrestore(&shm_lock, exceptions);
+- if (!res)
+- mobj_ffa_sel1_spmc_delete(mf);
+ return res;
+ }
+-#endif /*CFG_CORE_SEL1_SPMC*/
+
+-struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie, unsigned int internal_offs)
++struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie,
++ unsigned int internal_offs)
+ {
+ struct mobj_ffa *mf = NULL;
+ uint32_t exceptions = 0;
+-
+ if (internal_offs >= SMALL_PAGE_SIZE)
+ return NULL;
+-
+ exceptions = cpu_spin_lock_xsave(&shm_lock);
+-
+ mf = find_in_list(&shm_head, cmp_cookie, cookie);
+ if (mf) {
+ if (mf->page_offset == internal_offs) {
+@@ -345,9 +376,19 @@ struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie, unsigned int internal_offs)
+ }
+ } else {
+ mf = pop_from_list(&shm_inactive_head, cmp_cookie, cookie);
++#if defined(CFG_CORE_SEL2_SPMC)
++ /* Try to retrieve it from the SPM at S-EL2 */
++ if (mf)
++ DMSG("cookie %#"PRIx64" resurrecting", cookie);
++ if (!mf)
++ EMSG("Populating mobj from rx buffer\n");
++ mf = thread_spmc_populate_mobj_from_rx(cookie);
++#endif
+ if (mf) {
++#if defined(CFG_CORE_SEL1_SPMC)
+ mf->unregistered_by_cookie = false;
+ mf->registered_by_cookie = true;
++#endif
+ assert(refcount_val(&mf->mobj.refc) == 0);
+ refcount_set(&mf->mobj.refc, 1);
+ refcount_set(&mf->mapcount, 0);
+@@ -358,15 +399,12 @@ struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie, unsigned int internal_offs)
+ SLIST_INSERT_HEAD(&shm_head, mf, link);
+ }
+ }
+-
+ cpu_spin_unlock_xrestore(&shm_lock, exceptions);
+-
+ if (!mf) {
+ EMSG("Failed to get cookie %#"PRIx64" internal_offs %#x",
+- cookie, internal_offs);
++ cookie, internal_offs);
+ return NULL;
+ }
+-
+ return &mf->mobj;
+ }
+
+diff --git a/core/arch/arm/plat-vexpress/conf.mk b/core/arch/arm/plat-vexpress/conf.mk
+index 26b9f51e..dd6530a6 100644
+--- a/core/arch/arm/plat-vexpress/conf.mk
++++ b/core/arch/arm/plat-vexpress/conf.mk
+@@ -58,8 +58,13 @@ CFG_WITH_STATS ?= y
+
+ ifeq ($(PLATFORM_FLAVOR),fvp)
+ CFG_TEE_CORE_NB_CORE = 8
++ifeq ($(CFG_CORE_SEL2_SPMC),y)
++CFG_TZDRAM_START ?= 0x06280000
++CFG_TZDRAM_SIZE ?= 0x01D80000
++else
+ CFG_TZDRAM_START ?= 0x06000000
+ CFG_TZDRAM_SIZE ?= 0x02000000
++endif
+ CFG_SHMEM_START ?= 0x83000000
+ CFG_SHMEM_SIZE ?= 0x00200000
+ # DRAM1 is defined above 4G
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0004-core-fixes-to-align-with-upstream-hafnium.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0004-core-fixes-to-align-with-upstream-hafnium.patch
new file mode 100644
index 0000000..a36a510
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0004-core-fixes-to-align-with-upstream-hafnium.patch
@@ -0,0 +1,188 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 5ca96d9ff7fa5481282fb8f59a54d3cc91a1ae36 Mon Sep 17 00:00:00 2001
+From: Olivier Deprez <olivier.deprez@arm.com>
+Date: Thu, 1 Oct 2020 07:59:54 +0200
+Subject: [PATCH 1/5] core: fixes to align with upstream hafnium
+
+FF-A: fix call to thread_spmc_populate_mobj_from_rx
+
+FF-A: fix typos in thread_spmc.c
+
+FF-A: fix mem retrieve request
+
+FF-A. fix mem relinquish
+
+FF-A: call rx release from thread_spmc_populate_mobj_from_rx
+
+Change-Id: I38794b34bf17428d62218e30bdd0180f75498ed4
+Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ core/arch/arm/kernel/thread_spmc.c | 52 +++++++++++++++++++++---------
+ core/arch/arm/mm/mobj_ffa.c | 3 +-
+ 2 files changed, 39 insertions(+), 16 deletions(-)
+
+diff --git a/core/arch/arm/kernel/thread_spmc.c b/core/arch/arm/kernel/thread_spmc.c
+index 3d7dc035..872221d6 100644
+--- a/core/arch/arm/kernel/thread_spmc.c
++++ b/core/arch/arm/kernel/thread_spmc.c
+@@ -48,7 +48,7 @@ struct mem_access_perm_descr {
+ };
+
+ /* Table 41: Endpoint memory access descriptor */
+-struct mem_accsess_descr {
++struct mem_access_descr {
+ struct mem_access_perm_descr mem_access_perm_descr;
+ uint32_t mem_region_offs;
+ uint64_t reserved;
+@@ -64,7 +64,7 @@ struct mem_transaction_descr {
+ uint64_t tag;
+ uint32_t reserved1;
+ uint32_t mem_access_descr_count;
+- struct mem_accsess_descr mem_accsess_descr_array[];
++ struct mem_access_descr mem_access_descr_array[];
+ };
+
+ struct ffa_partition_info {
+@@ -453,8 +453,8 @@ static void handle_blocking_call(struct thread_smc_args *args)
+ }
+ }
+
+-#if CFG_CORE_SEL1_SPMC
+-static int get_acc_perms(struct mem_accsess_descr *mem_acc,
++#ifdef CFG_CORE_SEL1_SPMC
++static int get_acc_perms(struct mem_access_descr *mem_acc,
+ unsigned int num_mem_accs, uint8_t *acc_perms,
+ unsigned int *region_offs)
+ {
+@@ -495,7 +495,7 @@ static int mem_share_init(void *buf, size_t blen, unsigned int *page_count,
+
+ /* Check that the endpoint memory access descriptor array fits */
+ num_mem_accs = READ_ONCE(descr->mem_access_descr_count);
+- if (MUL_OVERFLOW(sizeof(struct mem_accsess_descr), num_mem_accs, &n) ||
++ if (MUL_OVERFLOW(sizeof(struct mem_access_descr), num_mem_accs, &n) ||
+ ADD_OVERFLOW(sizeof(*descr), n, &n) || n > blen)
+ return FFA_INVALID_PARAMETERS;
+
+@@ -503,7 +503,7 @@ static int mem_share_init(void *buf, size_t blen, unsigned int *page_count,
+ return FFA_INVALID_PARAMETERS;
+
+ /* Check that the access permissions matches what's expected */
+- if (get_acc_perms(descr->mem_accsess_descr_array,
++ if (get_acc_perms(descr->mem_access_descr_array,
+ num_mem_accs, &mem_acc_perm, ®ion_descr_offs) ||
+ mem_acc_perm != exp_mem_acc_perm)
+ return FFA_INVALID_PARAMETERS;
+@@ -1263,17 +1263,29 @@ static struct mem_transaction_descr *spmc_retrieve_req(uint64_t cookie)
+ {
+ struct mem_transaction_descr *retrieve_region = (void *)tx_buf;
+
++ uint64_t size = sizeof(*retrieve_region) +
++ 1 * sizeof(struct mem_access_descr);
+ struct thread_smc_args args = {
+ .a0 = FFA_MEM_RETRIEVE_REQ_64,
+- .a1 = sizeof(*retrieve_region), // Total Length
+- .a2 = sizeof(*retrieve_region), // Frag Length == Total length
++ .a1 = size, // Total Length
++ .a2 = size, // Frag Length == Total length
+ .a3 = 0, // Address, Using TX -> MBZ
+ .a4 = 0 // Using TX -> MBZ
+ };
+
+ /* TODO pass all the information required by the spec */
+- memset(retrieve_region, 0, sizeof(*retrieve_region));
++ memset(retrieve_region, 0, size);
+ retrieve_region->global_handle = cookie;
++ retrieve_region->flags = 1;
++ retrieve_region->mem_access_descr_count = 1;
++ retrieve_region->mem_access_descr_array[0].mem_region_offs = 0;
++ retrieve_region->mem_access_descr_array[0].reserved = 0;
++ retrieve_region->mem_access_descr_array[0].mem_access_perm_descr =
++ (struct mem_access_perm_descr) {
++ .endpoint_id = my_sp_id,
++ .access_perm = 0,
++ .flags = 0
++ };
+
+ thread_smccc(&args);
+ if (args.a0 == FFA_ERROR /*TODO != FFA_MEM_RETRIEVE_RESP_64 */) {
+@@ -1296,6 +1308,8 @@ void thread_spmc_relinquish(uint64_t cookie)
+ relinquish_desc->handle = cookie;
+ relinquish_desc->flags = 0;
+ /* TODO: Add endpoint details. */
++ relinquish_desc->endpoint_count = 1;
++ relinquish_desc->endpoint_id_array[0] = my_sp_id;
+ thread_smccc(&args);
+ if (args.a0 != FFA_SUCCESS_32)
+ EMSG("Failed to relinquish cookie %#"PRIx64, cookie);
+@@ -1303,11 +1317,14 @@ void thread_spmc_relinquish(uint64_t cookie)
+
+ struct mobj_ffa *thread_spmc_populate_mobj_from_rx(uint64_t cookie)
+ {
++ struct mobj_ffa *ret = NULL;
+ struct mem_transaction_descr *retrieve_desc;
+ struct mem_region_descr *descr;
+ struct mobj_ffa *mf;
+ uint32_t num_pages;
+-
++ struct thread_smc_args ffa_rx_release_args = {
++ .a0 = FFA_RX_RELEASE
++ };
+
+ /* XXX Support single mem_region. */
+ retrieve_desc = spmc_retrieve_req(cookie);
+@@ -1319,23 +1336,28 @@ struct mobj_ffa *thread_spmc_populate_mobj_from_rx(uint64_t cookie)
+
+ descr = (struct mem_region_descr *)
+ ((uint8_t *)retrieve_desc +
+- retrieve_desc->mem_accsess_descr_array[0].mem_region_offs);
++ retrieve_desc->mem_access_descr_array[0].mem_region_offs);
+
+ num_pages = descr->total_page_count;
+ mf = mobj_ffa_sel2_spmc_new(cookie, num_pages);
+
+ if (!mf)
+- return NULL;
++ goto out;
+
+ if (set_pages(descr->address_range_array,
+ descr->address_range_count,
+ num_pages, mf)) {
+ mobj_ffa_sel2_spmc_delete(mf);
+- return NULL;
+-
++ goto out;
+ }
+
+- return mf;
++ ret = mf;
++
++out:
++ /* Release RX buffer after the mem retrieve request. */
++ thread_smccc(&ffa_rx_release_args);
++
++ return ret;
+ }
+
+ static TEE_Result spmc_init(void)
+diff --git a/core/arch/arm/mm/mobj_ffa.c b/core/arch/arm/mm/mobj_ffa.c
+index e2c585a2..8e334f04 100644
+--- a/core/arch/arm/mm/mobj_ffa.c
++++ b/core/arch/arm/mm/mobj_ffa.c
+@@ -380,9 +380,10 @@ struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie,
+ /* Try to retrieve it from the SPM at S-EL2 */
+ if (mf)
+ DMSG("cookie %#"PRIx64" resurrecting", cookie);
+- if (!mf)
++ if (!mf) {
+ EMSG("Populating mobj from rx buffer\n");
+ mf = thread_spmc_populate_mobj_from_rx(cookie);
++ }
+ #endif
+ if (mf) {
+ #if defined(CFG_CORE_SEL1_SPMC)
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0005-core-arm-Total-Compute-platform-support.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0005-core-arm-Total-Compute-platform-support.patch
new file mode 100644
index 0000000..52270ec
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0005-core-arm-Total-Compute-platform-support.patch
@@ -0,0 +1,187 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 0c427d7f164a46862f6267b616d4ade28865b57a Mon Sep 17 00:00:00 2001
+From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Date: Wed, 15 Jul 2020 12:51:04 +0100
+Subject: [PATCH 2/5] core: arm: Total Compute platform support
+
+Initial support for Total Compute platform[1]
+ - defines tc0 platform configuration
+ - enables CFG_ARM64_core by default
+ - defines TZCDRAM_BASE
+
+Link: [1] https://community.arm.com/developer/tools-software/oss-platforms/w/docs/606/total-compute
+
+Change-Id: Icddafbdfac40bb6ff3c367910acf632688343721
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ core/arch/arm/plat-totalcompute/conf.mk | 32 +++++++++++
+ core/arch/arm/plat-totalcompute/main.c | 55 +++++++++++++++++++
+ .../arm/plat-totalcompute/platform_config.h | 43 +++++++++++++++
+ core/arch/arm/plat-totalcompute/sub.mk | 2 +
+ 4 files changed, 132 insertions(+)
+ create mode 100644 core/arch/arm/plat-totalcompute/conf.mk
+ create mode 100644 core/arch/arm/plat-totalcompute/main.c
+ create mode 100644 core/arch/arm/plat-totalcompute/platform_config.h
+ create mode 100644 core/arch/arm/plat-totalcompute/sub.mk
+
+diff --git a/core/arch/arm/plat-totalcompute/conf.mk b/core/arch/arm/plat-totalcompute/conf.mk
+new file mode 100644
+index 00000000..4fe894c7
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/conf.mk
+@@ -0,0 +1,32 @@
++PLATFORM_FLAVOR ?= tc0
++
++ifeq ($(PLATFORM_FLAVOR),tc0)
++include core/arch/arm/cpu/cortex-armv8-0.mk
++platform-debugger-arm := 1
++endif
++
++$(call force,CFG_WITH_ARM_TRUSTED_FW,y)
++$(call force,CFG_GENERIC_BOOT,y)
++$(call force,CFG_GIC,y)
++$(call force,CFG_ARM_GICV3,y)
++$(call force,CFG_PL011,y)
++$(call force,CFG_PM_STUBS,y)
++$(call force,CFG_SECURE_TIME_SOURCE_CNTPCT,y)
++$(call force,CFG_ARM64_core,y)
++$(call force,CFG_WITH_LPAE,y)
++
++ifeq ($(platform-debugger-arm),1)
++# ARM debugger needs this
++platform-cflags-debug-info = -gdwarf-2
++platform-aflags-debug-info = -gdwarf-2
++endif
++
++ifeq ($(PLATFORM_FLAVOR),tc0)
++CFG_TEE_CORE_NB_CORE = 4
++
++CFG_TZDRAM_START ?= 0xff000000
++CFG_TZDRAM_SIZE ?= 0x01000000
++
++CFG_SHMEM_START ?= 0xfce00000
++CFG_SHMEM_SIZE ?= 0x00200000
++endif
+diff --git a/core/arch/arm/plat-totalcompute/main.c b/core/arch/arm/plat-totalcompute/main.c
+new file mode 100644
+index 00000000..e775abfc
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/main.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (c) 2020, Arm Limited. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <arm.h>
++#include <console.h>
++#include <drivers/gic.h>
++#include <drivers/pl011.h>
++#include <initcall.h>
++#include <kernel/boot.h>
++#include <kernel/interrupt.h>
++#include <kernel/misc.h>
++#include <kernel/panic.h>
++
++#include <mm/core_mmu.h>
++#include <platform_config.h>
++
++static struct gic_data gic_data __nex_bss;
++static struct pl011_data console_data __nex_bss;
++
++register_phys_mem_pgdir(MEM_AREA_IO_SEC, CONSOLE_UART_BASE, PL011_REG_SIZE);
++register_phys_mem_pgdir(MEM_AREA_IO_SEC, GICD_BASE, GIC_DIST_REG_SIZE);
++
++register_ddr(DRAM0_BASE, DRAM0_SIZE);
++
++void main_init_gic(void)
++{
++ vaddr_t gicc_base;
++
++ gicc_base = (vaddr_t)phys_to_virt(GIC_BASE + GICC_OFFSET,
++ MEM_AREA_IO_SEC);
++ if (!gicc_base)
++ panic();
++
++ /*
++ * On ARMv8, GIC configuration is initialized in ARM-TF
++ * gicd base address is same as gicc_base.
++ */
++ gic_init_base_addr(&gic_data, gicc_base, gicc_base);
++ itr_init(&gic_data.chip);
++}
++
++void itr_core_handler(void)
++{
++ gic_it_handle(&gic_data);
++}
++
++void console_init(void)
++{
++ pl011_init(&console_data, CONSOLE_UART_BASE, CONSOLE_UART_CLK_IN_HZ,
++ CONSOLE_UART_BAUDRATE);
++ register_serial_console(&console_data.chip);
++}
+diff --git a/core/arch/arm/plat-totalcompute/platform_config.h b/core/arch/arm/plat-totalcompute/platform_config.h
+new file mode 100644
+index 00000000..dfc58857
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/platform_config.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (c) 2020, Arm Limited. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef PLATFORM_CONFIG_H
++#define PLATFORM_CONFIG_H
++
++#include <mm/generic_ram_layout.h>
++
++/* Make stacks aligned to data cache line length */
++#define STACK_ALIGNMENT 64
++
++#if defined(PLATFORM_FLAVOR_tc0)
++#define GIC_BASE 0x30000000
++#define GICD_OFFSET 0x0
++#define GICC_OFFSET 0x0
++
++#define UART0_BASE 0x7FF70000
++#define UART1_BASE 0x7FF80000
++
++#define CONSOLE_UART_BASE UART0_BASE
++
++#define DRAM0_BASE 0x80000000
++#define DRAM0_SIZE 0x7d000000
++
++#define TZCDRAM_BASE 0xff000000
++#define TZCDRAM_SIZE 0x01000000
++
++#else
++#error "Unknown platform flavor"
++#endif
++
++#ifdef GIC_BASE
++#define GICD_BASE (GIC_BASE + GICD_OFFSET)
++#define GICC_BASE (GIC_BASE + GICC_OFFSET)
++#endif
++
++#define CONSOLE_UART_BAUDRATE 115200
++#define CONSOLE_UART_CLK_IN_HZ 7372800
++
++#endif /* PLATFORM_CONFIG_H */
+diff --git a/core/arch/arm/plat-totalcompute/sub.mk b/core/arch/arm/plat-totalcompute/sub.mk
+new file mode 100644
+index 00000000..8ddc2fd4
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/sub.mk
+@@ -0,0 +1,2 @@
++global-incdirs-y += .
++srcs-y += main.c
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0006-plat-totalcompute-Add-support-for-S-EL2-SPMC.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0006-plat-totalcompute-Add-support-for-S-EL2-SPMC.patch
new file mode 100644
index 0000000..3070d5f
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0006-plat-totalcompute-Add-support-for-S-EL2-SPMC.patch
@@ -0,0 +1,108 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 8c21a8c7ac92839f36f83ebff9a208f24302c780 Mon Sep 17 00:00:00 2001
+From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Date: Mon, 16 Nov 2020 17:29:09 +0000
+Subject: [PATCH 3/5] plat-totalcompute: Add support for S-EL2 SPMC
+
+This patch adds CFG_CORE_SEL2_SPMC support. Defines CFG_TZDRAM_START
+address with memory region reserved for SPMC. Adds secondary cpu boot
+request handler.
+
+Change-Id: I3f274c7bb6b7df2706ea81aee0f2a8f8f39c1d80
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ core/arch/arm/plat-totalcompute/conf.mk | 5 ++
+ core/arch/arm/plat-totalcompute/sub.mk | 3 ++
+ core/arch/arm/plat-totalcompute/tc0_spmc_pm.c | 50 +++++++++++++++++++
+ 3 files changed, 58 insertions(+)
+ create mode 100644 core/arch/arm/plat-totalcompute/tc0_spmc_pm.c
+
+diff --git a/core/arch/arm/plat-totalcompute/conf.mk b/core/arch/arm/plat-totalcompute/conf.mk
+index 4fe894c7..34095acf 100644
+--- a/core/arch/arm/plat-totalcompute/conf.mk
++++ b/core/arch/arm/plat-totalcompute/conf.mk
+@@ -24,8 +24,13 @@ endif
+ ifeq ($(PLATFORM_FLAVOR),tc0)
+ CFG_TEE_CORE_NB_CORE = 4
+
++ifeq ($(CFG_CORE_SEL2_SPMC),y)
++CFG_TZDRAM_START ?= 0xfd281000
++CFG_TZDRAM_SIZE ?= 0x01d7f000
++else
+ CFG_TZDRAM_START ?= 0xff000000
+ CFG_TZDRAM_SIZE ?= 0x01000000
++endif
+
+ CFG_SHMEM_START ?= 0xfce00000
+ CFG_SHMEM_SIZE ?= 0x00200000
+diff --git a/core/arch/arm/plat-totalcompute/sub.mk b/core/arch/arm/plat-totalcompute/sub.mk
+index 8ddc2fd4..ffd76ee9 100644
+--- a/core/arch/arm/plat-totalcompute/sub.mk
++++ b/core/arch/arm/plat-totalcompute/sub.mk
+@@ -1,2 +1,5 @@
+ global-incdirs-y += .
+ srcs-y += main.c
++ifeq ($(CFG_CORE_FFA),y)
++srcs-y += tc0_spmc_pm.c
++endif
+diff --git a/core/arch/arm/plat-totalcompute/tc0_spmc_pm.c b/core/arch/arm/plat-totalcompute/tc0_spmc_pm.c
+new file mode 100644
+index 00000000..8e59a8cc
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/tc0_spmc_pm.c
+@@ -0,0 +1,50 @@
++// SPDX-License-Identifier: BSD-2-Clause
++/*
++ * Copyright (c) 2020, Arm Limited
++ */
++
++#include <arm.h>
++#include <kernel/boot.h>
++#include <ffa.h>
++#include <sm/psci.h>
++
++/*
++ * Lookup table of core and cluster affinities on the TC0. In the absence of a
++ * DT that provides the same information, this table is used to initialise
++ * OP-TEE on secondary cores.
++ */
++static const uint64_t core_clus_aff_array[] = {
++ 0x0000, /* Cluster 0 Cpu 0 */
++ 0x0001, /* Cluster 0 Cpu 1 */
++ 0x0002, /* Cluster 0 Cpu 2 */
++ 0x0003 /* Cluster 0 Cpu 3 */
++};
++
++void ffa_secondary_cpu_boot_req(vaddr_t secondary_ep, uint64_t cookie)
++{
++ unsigned long mpidr = read_mpidr();
++ unsigned int aff_shift = 0;
++ unsigned long a1 = 0;
++ unsigned int cnt = 0;
++ int32_t ret = 0;
++
++ if (mpidr & MPIDR_MT_MASK)
++ aff_shift = MPIDR_CLUSTER_SHIFT;
++
++ for (cnt = 0; cnt < ARRAY_SIZE(core_clus_aff_array); cnt++) {
++ /* Clear out the affinity fields until level 2 */
++ a1 = mpidr & ~(unsigned long)MPIDR_AARCH32_AFF_MASK;
++
++ /* Create an mpidr from core_clus_aff_array */
++ a1 |= core_clus_aff_array[cnt] << aff_shift;
++
++ /* Invoke the PSCI_CPU_ON_SMC64 function */
++ ret = thread_smc(PSCI_CPU_ON_SMC64, a1, secondary_ep, cookie);
++
++ if (ret != PSCI_RET_SUCCESS)
++ EMSG("PSCI_CPU_ON op on mpidr 0x%lx failed %"PRId32,
++ a1, ret);
++ else
++ DMSG("PSCI_CPU_ON op on mpidr 0x%lx done", a1);
++ }
++}
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0007-plat-totalcompute-add-optee-manifest-file-and-sp-lay.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0007-plat-totalcompute-add-optee-manifest-file-and-sp-lay.patch
new file mode 100644
index 0000000..6535496
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0007-plat-totalcompute-add-optee-manifest-file-and-sp-lay.patch
@@ -0,0 +1,73 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 582bf63102ec37dadff2147dcebcb62783dcf377 Mon Sep 17 00:00:00 2001
+From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Date: Mon, 16 Nov 2020 18:03:21 +0000
+Subject: [PATCH 4/5] plat-totalcompute: add optee manifest file and sp layout
+
+For S-EL2 SPMC, add optee manifest file and sp layout file
+
+Change-Id: Ic3179987decf4e017cd4a0ad91b3beeea2bd6ca1
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ .../arm/plat-totalcompute/optee_manifest.dts | 33 +++++++++++++++++++
+ .../arch/arm/plat-totalcompute/sp_layout.json | 6 ++++
+ 2 files changed, 39 insertions(+)
+ create mode 100644 core/arch/arm/plat-totalcompute/optee_manifest.dts
+ create mode 100644 core/arch/arm/plat-totalcompute/sp_layout.json
+
+diff --git a/core/arch/arm/plat-totalcompute/optee_manifest.dts b/core/arch/arm/plat-totalcompute/optee_manifest.dts
+new file mode 100644
+index 00000000..4e60cbe1
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/optee_manifest.dts
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (c) 2020, Arm Limited. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ *
++ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
++ * that has additional optional properties defined.
++ *
++ */
++
++/dts-v1/;
++
++/ {
++ compatible = "arm,ffa-manifest-1.0";
++
++ /* Properties */
++ description = "op-tee";
++ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
++ uuid = <0x486178e0 0xe7f811e3 0xbc5e0002 0xa5d5c51b>;
++ id = <1>;
++ execution-ctx-count = <4>;
++ exception-level = <2>; /* S-EL1 */
++ execution-state = <0>; /* AARCH64 */
++ load-address = <0xfd280000>;
++ entrypoint-offset = <0x1000>;
++ xlat-granule = <0>; /* 4KiB */
++ boot-order = <0>;
++ messaging-method = <0>; /* Direct messaging only */
++ run-time-model = <1>; /* Run to completion */
++
++ /* Boot protocol */
++ gp-register-num = <0x0>;
++};
+diff --git a/core/arch/arm/plat-totalcompute/sp_layout.json b/core/arch/arm/plat-totalcompute/sp_layout.json
+new file mode 100644
+index 00000000..05bc7851
+--- /dev/null
++++ b/core/arch/arm/plat-totalcompute/sp_layout.json
+@@ -0,0 +1,6 @@
++{
++ "op-tee" : {
++ "image": "tee-pager_v2.bin",
++ "pm": "optee_manifest.dts"
++ }
++}
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0008-plat-totalcompute-define-tzdram-start-address-for-S-.patch b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0008-plat-totalcompute-define-tzdram-start-address-for-S-.patch
new file mode 100644
index 0000000..015bdc9
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/files/optee-os/tc0/0008-plat-totalcompute-define-tzdram-start-address-for-S-.patch
@@ -0,0 +1,36 @@
+Upstream-Status: Pending [Not submitted to upstream yet]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 1827607c6381339d051a36a84d749c3a50e3463d Mon Sep 17 00:00:00 2001
+From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Date: Mon, 16 Nov 2020 17:38:07 +0000
+Subject: [PATCH 5/5] plat-totalcompute: define tzdram start address for S-EL1
+ SPMC config
+
+Define TZDRAM_START for CFG_CORE_SEL1_SPMC config
+
+Change-Id: I71aaa92a0ecdb791802336ca31ab52e97ee52955
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ core/arch/arm/plat-totalcompute/conf.mk | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/core/arch/arm/plat-totalcompute/conf.mk b/core/arch/arm/plat-totalcompute/conf.mk
+index 34095acf..d330eb92 100644
+--- a/core/arch/arm/plat-totalcompute/conf.mk
++++ b/core/arch/arm/plat-totalcompute/conf.mk
+@@ -24,7 +24,10 @@ endif
+ ifeq ($(PLATFORM_FLAVOR),tc0)
+ CFG_TEE_CORE_NB_CORE = 4
+
+-ifeq ($(CFG_CORE_SEL2_SPMC),y)
++ifeq ($(CFG_CORE_SEL1_SPMC),y)
++CFG_TZDRAM_START ?= 0xfd000000
++CFG_TZDRAM_SIZE ?= 0x02000000
++else ifeq ($(CFG_CORE_SEL2_SPMC),y)
+ CFG_TZDRAM_START ?= 0xfd281000
+ CFG_TZDRAM_SIZE ?= 0x01d7f000
+ else
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc b/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc
index 8b13386..ad9c475 100644
--- a/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc
+++ b/meta-arm-bsp/recipes-security/optee/optee-client-tc0.inc
@@ -3,3 +3,10 @@
# Intermediate SHA with 3.11 baseline version
SRCREV = "3f44b870299514ad8c6b7dee776eb2994d9c1cd4"
PV = "3.11.0+git${SRCPV}"
+
+FILESEXTRAPATHS_prepend_tc0 := "${THISDIR}/files/optee-client/tc0:"
+
+SRC_URI_append = " \
+ file://0001-Revert-libteec-Avoid-memcpy-when-using-TEEC_TempMemo.patch \
+ file://0002-Allocate-page-aligned-shared-memory-buffers.patch \
+ "
diff --git a/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc b/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
index a700daf..fc89a9f 100644
--- a/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
+++ b/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
@@ -9,7 +9,20 @@ SRC_URI_remove = " \
file://0001-libutils-provide-empty-__getauxval-implementation.patch \
file://0002-link.mk-implement-support-for-libnames-after-libgcc-.patch \
file://0003-ta_dev_kit.mk-make-sure-that-libutils-is-linked-seco.patch \
-"
+ "
+
+FILESEXTRAPATHS_prepend_tc0 := "${THISDIR}/files/optee-os/tc0:"
+
+SRC_URI_append = " \
+ file://0001-core-SPMC-update-for-FF-A-version-1.0.patch \
+ file://0002-core-add-thread_smccc.patch \
+ file://0003-core-enable-SPCI-with-SPM-Core-at-S-EL2.patch \
+ file://0004-core-fixes-to-align-with-upstream-hafnium.patch \
+ file://0005-core-arm-Total-Compute-platform-support.patch \
+ file://0006-plat-totalcompute-Add-support-for-S-EL2-SPMC.patch \
+ file://0007-plat-totalcompute-add-optee-manifest-file-and-sp-lay.patch \
+ file://0008-plat-totalcompute-define-tzdram-start-address-for-S-.patch \
+ "
COMPATIBLE_MACHINE = "tc0"
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 06/10] arm-bsp/tc0: Enable optee core with SPMC at SEL2
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (3 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 05/10] arm-bsp/tc0: Add tc0 platform support patches " Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 07/10] arm-bsp/linux: add ffa driver to TC0 Arunachalam Ganapathy
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
Sets config flag CFG_CORE_SEL2_SPMC. Copies optee manifest file and
sp_layout files to deploy directory.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: If2104e2d588cbc9fbd9db3d8c4ba9fb74732901b
---
.../recipes-security/optee/optee-os-tc0.inc | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc b/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
index fc89a9f..fff6381 100644
--- a/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
+++ b/meta-arm-bsp/recipes-security/optee/optee-os-tc0.inc
@@ -27,3 +27,25 @@ SRC_URI_append = " \
COMPATIBLE_MACHINE = "tc0"
OPTEEMACHINE = "totalcompute-tc0"
+
+# Enable optee memory layout and boot logs
+EXTRA_OEMAKE += " CFG_TEE_CORE_LOG_LEVEL=3"
+
+# default disable latency benchmarks (over all OP-TEE layers)
+EXTRA_OEMAKE += " CFG_TEE_BENCHMARK=n"
+
+# Enable stats
+EXTRA_OEMAKE += " CFG_WITH_STATS=y"
+
+EXTRA_OEMAKE += " CFG_CORE_SEL2_SPMC=y"
+
+# Copy optee manifest file and sp_layout
+# This function will be modified or removed once upstream optee-os adds support
+# for SEL2 SPMC config
+do_install_append() {
+ install -d ${D}${nonarch_base_libdir}/firmware/
+ install -m 644 ${S}/core/arch/arm/plat-totalcompute/sp_layout.json \
+ ${D}${nonarch_base_libdir}/firmware/
+ install -m 644 ${S}/core/arch/arm/plat-totalcompute/optee_manifest.dts \
+ ${D}${nonarch_base_libdir}/firmware/
+}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 07/10] arm-bsp/linux: add ffa driver to TC0
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (4 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 06/10] arm-bsp/tc0: Enable optee core with SPMC at SEL2 Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 08/10] arm-bsp/linux: enable ffa driver for TC0 Arunachalam Ganapathy
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
This patch contains initial version of ffa driver adopted for
android11-5.4-lts kernel.
This is based on prototype ffa driver released by Arm.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Idb198cc77368a95257f1b5bff37b17bd13144109
---
.../linux/linux-arm-platforms.inc | 1 +
...Initial-version-of-ffa-driver-based-.patch | 1461 +++++++++++++++++
2 files changed, 1462 insertions(+)
create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0009-driver-firmware-Initial-version-of-ffa-driver-based-.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 1c9fdc1..873f120 100644
--- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
@@ -76,6 +76,7 @@ SRC_URI_append_tc0 = " \
file://0006-mailbox-arm_mhuv2-add-multi-word-transport-protocol-.patch \
file://0007-firmware-arm_scmi-Add-fast_switch_possible-api.patch \
file://0008-cpufreq-arm_scmi-Set-fast_switch_possible-conditiona.patch \
+ file://0009-driver-firmware-Initial-version-of-ffa-driver-based-.patch \
"
#
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0009-driver-firmware-Initial-version-of-ffa-driver-based-.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0009-driver-firmware-Initial-version-of-ffa-driver-based-.patch
new file mode 100644
index 0000000..e5e1ff6
--- /dev/null
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0009-driver-firmware-Initial-version-of-ffa-driver-based-.patch
@@ -0,0 +1,1461 @@
+Upstream-Status: Pending [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=ffa_rel_proto&id=74aeede25bd737f4930e1322f5780ec1c61b9fd5]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 411f4ed69a06f213fb2abb7dbef0be5ce31ff55e Mon Sep 17 00:00:00 2001
+From: Jose Marinho <jose.marinho@arm.com>
+Date: Tue, 29 Oct 2019 09:28:55 +0000
+Subject: [PATCH] driver: firmware: Initial version of ffa driver based on
+ ffa_rel_proto
+
+Initial version of ffa driver based on ffa_rel_proto [1].
+
+[1]: https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/log/?h=ffa_rel_proto
+
+Squashed in:
+ firmware: arm64/spci: Add initial SPCI driver
+
+ Add initial SPCI driver
+
+ firmware: spci: add conduit selection from DT
+
+ The driver can use smc or hvc conduits depending on what is
+ specified in the spci node in the DT.
+
+ arm64: spci/smccc: Create smc call returning on x0 to x7
+
+ The new smc call is SMCCCv1.2 compliant.
+
+ arm_spci: Register Rx/Tx buffers.
+
+ Registers the Rx/Tx buffers with the SPCI implementation at a higher EL.
+ The buffers are restricted to 4KB in this implementation.
+
+ arm_spci: Add SPCI memory sharing mechanisms.
+
+ Add mem_share and mem_reclaim to the SPCI driver interface.
+ These two methods allow for the basic memory sharing use-case where
+ normal world shares a set of pages with secure world.
+ The memory region description is in this implementation restricted to
+ 4KB (i.e. it must fit in the Tx buffer of the normal world VM).
+
+ spci_driver/mem_share: Add lock around TX Buffer
+
+ Ensure we aquire a lock around the TX buffer when sending information to
+ prevent race conditions.
+
+ arm_spci: Expose SPCI_PARTITION_INFO_GET
+
+ Expose the SPCI_PARTITION_INFO_GET ABI to allow querying the system for
+ information about a set of partitions identified by a specified UUID.
+
+ The function expects the 128bit UUID to be discovered passed via 4 32bit
+ words in the format: UUID_0-UUID_1-UUID_2-UUID3 and a pointer to an
+ array of `spci_partition_info` structs that will allocated and populated
+ with the discovered partitions information by the SPCI driver. The
+ caller is responsible for freeing this memory allocated by the SPCI
+ driver.
+
+ The function returns the number of the partitions found (and therefore
+ the number of elements in the array) or a negative value indicating the
+ error code if unsuccessful.
+
+ This implementation currently disallows use of the NULL UUID.
+
+ arm_spci: Implement rx_release
+
+ SPCI: Move driver to directory
+
+ The SPCI driver has a specific directory at drivers/firmware/spci.
+
+ SPCI: multi-fragment memory share support
+
+ arm_spci: use scatterlist in mem_share interface
+
+ Previously an array of page* was passed in the mem_share interface.
+ This commit introduces a scatterlist as partameter to mem_share function.
+
+ arm_spci: Add RX_RELEASE return to spci_rx_release
+
+ A Hypervisor can return SPCI_RX_RELEASE when the PVM calls
+ SPCI_RX_RELEASE to signal that other VMs need to be scheduled.
+
+ arm_spci: Change spci_memory_reclaim declaration
+
+ Function takes an enum mem_clear_t flag to denote if memory should be
+ cleared upon reclaim.
+
+ arm_spci: Allow nil UUID in spci_parition_info_get
+
+ Previously the nil UUID was disallowed.
+
+ arm_spci: Add support for non-Tx buffer mem_share
+
+ This commit introduces the buffer*, buffer_size parameters to the
+ mem_share function. The buffer can be used alternatively to the Tx
+ buffer. The mem_share function will populate the IPA-contiguous memory
+ pointed to by buffer using the information in sg.
+
+ The buffer* must be NULL is mem_share should use the Tx buffer.
+ The buffer*, if non-NULL, must point to a IPA-contiguous memory region
+ of size multiple of 4kiB.
+
+ arm_spci: Support pause/resume in mem_share handle
+
+ The Hypervisor is allowed to return SPCI_MEM_OPS_PAUSE if a mem_share
+ operation is taking too long. The PVM must reply with
+ SPCI_MEM_OPS_RESUME.
+
+ arm_spci: Ammend debug print.
+
+ arm_spci: add missing fields in mem descriptor
+
+ The sender_id, vm_id fields were not properly filled in the mem_share
+ function.
+
+ arm_spci: mem_share selection of Tx or alloc buf
+
+ This commit allows the mem_share invokation to select the tx buffer or a
+ dynamically allocated buffer to be used for the transfer of the memory
+ region description.
+
+ if use_tx == true: the tx_lock is held until the memory region is fully
+ transmitted.
+
+ if use_tx == false: the tx_lock is very briefly held in the preamble
+ and postamble of the mem_share procedure.
+
+ arm_spci: Allow compilation for arm arch [smcccv1_2 bits]
+
+ arm_spci: Allow compilation for arm arch [arm_spci bits]
+
+ Implement SPCI features
+
+ Currently only SPCI_Direct_Req is checked during SPCI driver
+ initialisation.
+
+ arm_spci: add err print when features does not report direct_req support
+
+ arm_spci: refactor mem_share implementation for EAC [arm_spci bits]
+
+ arm_spci: introduce support for SPCI_INTERRUPT
+
+ A SP while executing in the context of a SPCI_MSG_SEND_DIRECT_REQ
+ may be interrupted. In which case the scheduler must be instructed and
+ be provided with the necessary information to resume the interrupted SP.
+
+ arm_ffa: optee: Swap spci/SPCI for ffa/FFA. [arm_ffa bits]
+
+ arm_ffa: Implement ffa_version discovery.
+
+ arm_ffa: corrections to EAC support.
+
+ arm_ffa: cast status return to signed for compare
+
+ arm_ffa: rename 1st member of arm_smcccv1_2_return [arm-smcccv1_2.h bits]
+
+ The smcccv1_2_return.func is renamed to arg0.
+
+ arm_ffa: rename 1st member of arm_smcccv1_2_return [arm_ffa bits]
+
+ The smcccv1_2_return.func is renamed to arg0.
+
+ arm_ffa: set the default shareability to inner.
+
+ Pages are shared with inner shareability attribute set in S2.
+
+ arm_ffa: remove some panic calls
+
+ Some panics were swaped by pr_warns and an error code return when the
+ error condition being signaled is predicted by the FFA spec. The panics
+ issued when an unexpected status is returned from EL2 or
+ EL3 (behaviour deviating from the FFA spec) are left in the driver.
+
+ arm_ffa: fix warnings and remove debug print
+
+ Fixed few warnings related to unused variable and in pr_warn prints
+
+ arm_ffa: correct checkpatch warnings
+
+ arm_ffa.h: Split memory access permissions
+
+ Split the FF-A instruction and data access permissions.
+ This allows for specifying one attribute but not the other. This is
+ required for lenders of memory for which must not specify the
+ instruction access permission.
+
+Signed-off-by: Jose Marinho <jose.marinho@arm.com>
+Signed-off-by: Marc Bonnici <marc.bonnici@arm.com>
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Change-Id: I7bd8cf453e99498ab4df1f01092137a67116d15d
+---
+ arch/arm/kernel/Makefile | 1 +
+ arch/arm/kernel/smcccv1_2-call.S | 58 +++
+ arch/arm64/kernel/Makefile | 2 +-
+ arch/arm64/kernel/smccc_v1_2-call.S | 24 +
+ drivers/firmware/Kconfig | 11 +
+ drivers/firmware/Makefile | 1 +
+ drivers/firmware/ffa/Makefile | 6 +
+ drivers/firmware/ffa/arm_ffa.c | 782 ++++++++++++++++++++++++++++
+ include/linux/arm-smcccv1_2.h | 51 ++
+ include/linux/arm_ffa.h | 235 +++++++++
+ 10 files changed, 1170 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/kernel/smcccv1_2-call.S
+ create mode 100644 arch/arm64/kernel/smccc_v1_2-call.S
+ create mode 100644 drivers/firmware/ffa/Makefile
+ create mode 100644 drivers/firmware/ffa/arm_ffa.c
+ create mode 100644 include/linux/arm-smcccv1_2.h
+ create mode 100644 include/linux/arm_ffa.h
+
+diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
+index 8cad59465af3..5be97585d130 100644
+--- a/arch/arm/kernel/Makefile
++++ b/arch/arm/kernel/Makefile
+@@ -101,5 +101,6 @@ obj-$(CONFIG_SMP) += psci_smp.o
+ endif
+
+ obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o
++obj-$(CONFIG_HAVE_ARM_SMCCC) += smcccv1_2-call.o
+
+ extra-y := $(head-y) vmlinux.lds
+diff --git a/arch/arm/kernel/smcccv1_2-call.S b/arch/arm/kernel/smcccv1_2-call.S
+new file mode 100644
+index 000000000000..9a577c4045a7
+--- /dev/null
++++ b/arch/arm/kernel/smcccv1_2-call.S
+@@ -0,0 +1,58 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (c) 2020, Linaro Limited
++ */
++#include <linux/linkage.h>
++
++#include <asm-generic/export.h>
++#include <asm/opcodes-sec.h>
++#include <asm/opcodes-virt.h>
++#include <asm/unwind.h>
++
++ /*
++ * Wrap c macros in asm macros to delay expansion until after the
++ * SMCCC asm macro is expanded.
++ */
++ .macro SMCCC_SMC
++ __SMC(0)
++ .endm
++
++ .macro SMCCC_HVC
++ __HVC(0)
++ .endm
++
++ .macro SMCCC instr
++UNWIND( .fnstart)
++ mov r12, sp
++ push {r4-r7}
++UNWIND( .save {r4-r7})
++ ldm r12, {r4-r7}
++ \instr
++ ldr r12, [sp, #(4 * 8)]
++ stm r12, {r0-r7}
++ pop {r4-r7}
++ bx lr
++UNWIND( .fnend)
++ .endm
++
++/*
++ * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
++ * unsigned long a3, unsigned long a4, unsigned long a5,
++ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
++ * struct arm_smccc_quirk *quirk)
++ */
++ENTRY(__arm_smcccv1_2_smc)
++ SMCCC SMCCC_SMC
++ENDPROC(__arm_smcccv1_2_smc)
++EXPORT_SYMBOL(__arm_smcccv1_2_smc)
++
++/*
++ * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
++ * unsigned long a3, unsigned long a4, unsigned long a5,
++ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
++ * struct arm_smccc_quirk *quirk)
++ */
++ENTRY(__arm_smcccv1_2_hvc)
++ SMCCC SMCCC_HVC
++ENDPROC(__arm_smcccv1_2_hvc)
++EXPORT_SYMBOL(__arm_smcccv1_2_hvc)
+diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
+index b3995329d9e5..4327ef6f4f8d 100644
+--- a/arch/arm64/kernel/Makefile
++++ b/arch/arm64/kernel/Makefile
+@@ -19,7 +19,7 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
+ return_address.o cpuinfo.o cpu_errata.o \
+ cpufeature.o alternative.o cacheinfo.o \
+ smp.o smp_spin_table.o topology.o smccc-call.o \
+- syscall.o
++ syscall.o smccc_v1_2-call.o
+
+ extra-$(CONFIG_EFI) := efi-entry.o
+
+diff --git a/arch/arm64/kernel/smccc_v1_2-call.S b/arch/arm64/kernel/smccc_v1_2-call.S
+new file mode 100644
+index 000000000000..518e849409ed
+--- /dev/null
++++ b/arch/arm64/kernel/smccc_v1_2-call.S
+@@ -0,0 +1,24 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2019 Arm Ltd.
++ */
++
++#include <linux/linkage.h>
++
++.macro SMC_CALL conduit
++ \conduit #0
++ ldr x8, [sp]
++ stp x0, x1, [x8]
++ stp x2, x3, [x8, #16]
++ stp x4, x5, [x8, #32]
++ stp x6, x7, [x8, #48]
++ ret
++.endm
++
++ENTRY(__arm_smcccv1_2_hvc)
++ SMC_CALL hvc
++ENDPROC(__arm_smcccv1_2_hvc)
++
++ENTRY(__arm_smcccv1_2_smc)
++ SMC_CALL smc
++ENDPROC(__arm_smcccv1_2_smc)
+diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
+index 1bc0e965f2e9..3bcf3d4514e4 100644
+--- a/drivers/firmware/Kconfig
++++ b/drivers/firmware/Kconfig
+@@ -77,6 +77,17 @@ config ARM_SDE_INTERFACE
+ standard for registering callbacks from the platform firmware
+ into the OS. This is typically used to implement RAS notifications.
+
++config ARM_FFA_TRANSPORT
++ bool "ARM Secure Partition Client Interface (FFA)"
++ depends on ARM64 || ARM
++ help
++ The Secure Partition Client Interface (FFA) is an Arm standard for
++ communication and memory sharing between entities managed by SMCCC
++ compliant firmware.
++
++ This driver provides interface for all the client drivers making
++ use of the features offered by FFA.
++
+ config EDD
+ tristate "BIOS Enhanced Disk Drive calls determine boot disk"
+ depends on X86
+diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
+index 64f5391e5749..10041c5f4d07 100644
+--- a/drivers/firmware/Makefile
++++ b/drivers/firmware/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
+
+ obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/
+ obj-y += psci/
++obj-y += ffa/
+ obj-y += broadcom/
+ obj-y += meson/
+ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
+diff --git a/drivers/firmware/ffa/Makefile b/drivers/firmware/ffa/Makefile
+new file mode 100644
+index 000000000000..37f4ccae197b
+--- /dev/null
++++ b/drivers/firmware/ffa/Makefile
+@@ -0,0 +1,6 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# Makefile for the linux kernel.
++#
++obj-$(CONFIG_ARM_FFA_TRANSPORT) += arm_ffa.o
++ccflags-y += -Og
+diff --git a/drivers/firmware/ffa/arm_ffa.c b/drivers/firmware/ffa/arm_ffa.c
+new file mode 100644
+index 000000000000..21838f8c4632
+--- /dev/null
++++ b/drivers/firmware/ffa/arm_ffa.c
+@@ -0,0 +1,782 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Secure Partitions Communication Interface (FFA) Protocol driver
++ *
++ * FFA is a system message passing and memory sharing protocol allowing for
++ * execution contexts to exchange information with other execution contexts
++ * residing on other Secure Partitions or Virtual Machines managed by any FFA
++ * compliant firmware framework.
++ *
++ * Copyright (C) 2019, 2020 Arm Ltd.
++ */
++#define DEBUG
++
++#include <linux/platform_device.h>
++#include <linux/arm_ffa.h>
++#include <linux/arm-smcccv1_2.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/scatterlist.h>
++
++
++static DEFINE_MUTEX(rx_lock);
++static DEFINE_MUTEX(tx_lock);
++
++static ffa_sp_id_t vm_id;
++
++static struct page *rx_buffer;
++static struct page *tx_buffer;
++
++static struct arm_smcccv1_2_return
++(*arm_ffa_smccc)(u32 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4,
++ u64 arg5, u64 arg6, u64 arg7);
++
++#define FFA_DEFINE_CALL(conduit) \
++static struct arm_smcccv1_2_return \
++arm_ffa_##conduit(u32 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, \
++ u64 arg5, u64 arg6, u64 arg7) \
++{ \
++ struct arm_smcccv1_2_return smccc_ret; \
++ \
++ __arm_smcccv1_2_##conduit(func, arg1, arg2, arg3, arg4, arg5, \
++ arg6, arg7, &smccc_ret); \
++ \
++ return smccc_ret; \
++}
++
++FFA_DEFINE_CALL(smc)
++FFA_DEFINE_CALL(hvc)
++
++static u32 sender_receiver_pack(u32 src_id, u32 dst_id)
++{
++ return (((src_id << 16) & 0xffff0000) | (dst_id & 0xffff));
++}
++
++int ffa_msg_send(ffa_sp_id_t dst_id, u32 len, u32 attributes)
++{
++ struct arm_smcccv1_2_return msg_send_return;
++
++ /* w1[32:16] Sender endpoint ID, w1[15:0] destination endpoint id. */
++ u32 sender_receiver = sender_receiver_pack(vm_id, dst_id);
++
++ msg_send_return = arm_ffa_smccc(FFA_MSG_SEND_32, sender_receiver,
++ 0, len, attributes, 0, 0, 0);
++
++ if (msg_send_return.arg0 == FFA_ERROR_32) {
++ switch ((int)msg_send_return.arg2) {
++ case FFA_INVALID_PARAMETERS:
++ return -ENXIO;
++ case FFA_DENIED:
++ case FFA_BUSY:
++ return -EAGAIN;
++ default:
++ panic("%s: Unhandled return code (%lld)\n", __func__,
++ msg_send_return.arg2);
++ }
++ }
++ return 0;
++}
++
++struct arm_smcccv1_2_return
++ffa_msg_send_direct_req(ffa_sp_id_t dst_id, u64 w3, u64 w4, u64 w5,
++ u64 w6, u64 w7)
++{
++ struct arm_smcccv1_2_return ret;
++
++ /* w1[32:16] Sender endpoint ID, w1[15:0] destination endpoint id. */
++ u32 sender_receiver = sender_receiver_pack(vm_id, dst_id);
++
++ ret = arm_ffa_smccc(FFA_MSG_SEND_DIRECT_REQ_32, sender_receiver, 0,
++ w3, w4, w5, w6, w7);
++
++ while (ret.arg0 != FFA_MSG_SEND_DIRECT_RESP_32 &&
++ ret.arg0 != FFA_SUCCESS_32) {
++ if (ret.arg0 == FFA_ERROR_32) {
++ pr_err("%s: Error sending message %llu\n", __func__,
++ ret.arg0);
++ switch ((int)ret.arg1) {
++ case FFA_INVALID_PARAMETERS:
++ ret.arg0 = -ENXIO;
++ goto out;
++
++ case FFA_DENIED:
++ case FFA_NOT_SUPPORTED:
++ ret.arg0 = -EIO;
++ goto out;
++
++ case FFA_BUSY:
++ ret.arg0 = -EAGAIN;
++ goto out;
++ }
++ } else if (ret.arg0 == FFA_INTERRUPT_32) {
++ ret = arm_ffa_smccc(FFA_RUN_32, ret.arg1,
++ 0, 0, 0, 0, 0, 0);
++ }
++
++ }
++
++ ret.arg0 = 0;
++
++out:
++ return ret;
++}
++
++static int ffa_share_next_frag(u64 handle, u32 frag_len, u32 *tx_offset)
++{
++
++ struct arm_smcccv1_2_return smccc_return;
++ u32 handle_high = (handle >> 32) & 0xffffffff;
++ u32 handle_low = handle & 0xffffffff;
++
++ smccc_return =
++ arm_ffa_smccc(FFA_MEM_FRAG_TX_32, handle_low,
++ handle_high, frag_len, 0, 0, 0, 0);
++
++ while (smccc_return.arg0 != FFA_MEM_FRAG_RX_32) {
++
++ if (smccc_return.arg0 == FFA_ERROR_32) {
++ switch ((int)smccc_return.arg2) {
++ case FFA_INVALID_PARAMETERS:
++ return -ENXIO;
++ case FFA_NOT_SUPPORTED:
++ return -ENODEV;
++ default:
++ pr_warn("%s: Unknown Error code %llx\n",
++ __func__, smccc_return.arg2);
++ return -EIO;
++ }
++ }
++
++ if (smccc_return.arg0 == FFA_MEM_OP_PAUSE_32) {
++
++ smccc_return = arm_ffa_smccc(FFA_MEM_OP_RESUME_32,
++ smccc_return.arg1, smccc_return.arg2, 0, 0, 0,
++ 0, 0);
++ }
++ }
++
++ *tx_offset = smccc_return.arg3;
++
++ return 0;
++}
++
++static int ffa_share_init_frag(phys_addr_t buffer, u32 buffer_size,
++ u32 fragment_len, u32 total_len, u64 *handle)
++{
++
++ struct arm_smcccv1_2_return smccc_return;
++
++ smccc_return =
++ arm_ffa_smccc(FFA_MEM_SHARE_64, total_len, fragment_len, buffer,
++ buffer_size, 0, 0, 0);
++
++ while (smccc_return.arg0 != FFA_SUCCESS_32) {
++
++ if (smccc_return.arg0 == FFA_ERROR_32) {
++ switch ((int)smccc_return.arg2) {
++ case FFA_INVALID_PARAMETERS:
++ return -ENXIO;
++ case FFA_DENIED:
++ return -EIO;
++ case FFA_NO_MEMORY:
++ return -ENOMEM;
++ case FFA_ABORTED:
++ return -EAGAIN;
++ default:
++ pr_warn("%s: Unknown Error code %llx\n",
++ __func__, smccc_return.arg2);
++ return -EIO;
++ }
++ }
++
++ if (smccc_return.arg0 == FFA_MEM_OP_PAUSE_32) {
++
++ smccc_return = arm_ffa_smccc(FFA_MEM_OP_RESUME_32,
++ smccc_return.arg1, smccc_return.arg2, 0, 0, 0,
++ 0, 0);
++ }
++ }
++
++ *handle = (smccc_return.arg3 << 32) | smccc_return.arg2;
++
++ return 0;
++}
++
++static inline u32 compute_composite_offset(u32 num_attributes)
++{
++ u32 composite_offset = offsetof(struct ffa_mem_region,
++ endpoints[num_attributes]);
++
++ /* ensure composite are 8 byte aligned. */
++ if (composite_offset & 0x7)
++ return (composite_offset & (~(u32)0x7)) + 0x8;
++
++ return composite_offset;
++}
++
++static inline u32 compute_constituent_offset(u32 num_attributes)
++{
++ u32 constituent_offset = offsetof(struct ffa_mem_region,
++ endpoints[num_attributes]) +
++ offsetof(struct ffa_composite_memory_region, constituents[0]);
++
++ /* ensure constituents are 8 byte aligned. */
++ if (constituent_offset & 0x7)
++ return (constituent_offset & (~(u32)0x7)) + 0x8;
++
++ return constituent_offset;
++}
++
++static inline u32 compute_region_length(u32 num_constituents,
++ u32 num_attributes)
++{
++ /* This assumes that there is a single ffa_composite_memory_region. */
++ return compute_constituent_offset(num_attributes) +
++ sizeof(struct ffa_mem_region_constituent)*num_constituents;
++}
++
++static int ffa_rx_release(void)
++{
++ struct arm_smcccv1_2_return rx_release_return;
++
++ rx_release_return = arm_ffa_smccc(FFA_RX_RELEASE_32,
++ 0, 0, 0, 0, 0, 0, 0);
++
++ if (rx_release_return.arg0 == FFA_ERROR_32) {
++ switch ((int)rx_release_return.arg2) {
++ case FFA_DENIED:
++ return -EAGAIN;
++ default:
++ panic("%s: Unhandled return code (%lld)\n", __func__,
++ rx_release_return.arg2);
++ }
++ }
++
++ if (rx_release_return.arg0 == FFA_RX_RELEASE_32) {
++ /*
++ * FFA implementation returned FFA_RX_RELEASE which signals
++ * the PVM that other VMs need to be scheduled.
++ */
++ return 1;
++ }
++
++ return 0;
++}
++
++static uint32_t ffa_get_num_pages_sg(struct scatterlist *sg)
++{
++ uint32_t num_pages = 0;
++
++ do {
++ num_pages += sg->length/PAGE_SIZE;
++ } while ((sg = sg_next(sg)));
++
++ return num_pages;
++}
++
++static inline struct ffa_memory_region_attribute ffa_set_region_normal(
++ enum ffa_mem_cacheability cacheability,
++ enum ffa_mem_shareability shareability)
++{
++ struct ffa_memory_region_attribute attr = {0};
++
++ attr.attribute = (FFA_MEM_NORMAL << FFA_MEMTYPE_OFFSET) |
++ (cacheability << FFA_CACHEABILITY_OFFSET) | shareability;
++
++ return attr;
++}
++
++static inline struct ffa_memory_region_attribute ffa_set_region_device(
++ enum ffa_mem_device_type device_type)
++{
++ struct ffa_memory_region_attribute attr = {0};
++
++ attr.attribute = (FFA_MEM_DEVICE << FFA_MEMTYPE_OFFSET) |
++ (device_type << FFA_DEVICE_OFFSET);
++
++ return attr;
++}
++
++static inline int ffa_transmit_fragment(u32 *tx_offset, phys_addr_t buffer,
++ u32 buffer_size, u32 frag_len, u32 total_len, u64 *handle)
++{
++ int rc;
++
++ if (*tx_offset == 0) {
++ rc = ffa_share_init_frag(buffer, buffer_size,
++ frag_len, total_len, handle);
++
++ *tx_offset = frag_len;
++ } else
++ rc = ffa_share_next_frag(*handle, frag_len, tx_offset);
++
++
++ return rc;
++}
++
++/*
++ * Share a set of pages with a list of destination endpoints.
++ * Returns a system-wide unique handle
++ */
++static int _ffa_share_memory(u32 tag, enum mem_clear_t flags,
++ struct ffa_mem_region_attributes *attrs,
++ u32 num_attrs, struct scatterlist *sg, u32 nents,
++ ffa_mem_handle_t *handle, phys_addr_t buffer, uint32_t buffer_size)
++{
++ struct ffa_mem_region *mem_region;
++ u32 index;
++ u32 num_constituents;
++ struct ffa_mem_region_constituent *constituents;
++ u32 total_len;
++ u32 fragment_len = sizeof(struct ffa_mem_region);
++ u32 max_fragment_size;
++ int rc = 0;
++ u32 tx_offset = 0;
++ struct ffa_composite_memory_region *composite = NULL;
++
++ if (buffer) {
++
++ BUG_ON(!buffer_size);
++ max_fragment_size = buffer_size * FFA_BASE_GRANULE_SIZE;
++ mem_region = phys_to_virt(buffer);
++
++ } else {
++
++ BUG_ON(buffer_size);
++ mem_region = (struct ffa_mem_region *)page_address(tx_buffer);
++ max_fragment_size = FFA_BASE_GRANULE_SIZE;
++
++ }
++
++ mem_region->flags = flags;
++ mem_region->tag = tag;
++ mem_region->sender_id = vm_id;
++ mem_region->region_attr = ffa_set_region_normal(FFA_WRITE_BACK,
++ FFA_INNER_SHAREABLE);
++ composite = ffa_get_composite(mem_region, num_attrs);
++ composite->total_page_count = ffa_get_num_pages_sg(sg);
++
++ fragment_len = compute_constituent_offset(num_attrs);
++
++ /* Ensure attribute description fits within the Tx buffer. */
++ if (fragment_len > max_fragment_size)
++ return -ENXIO;
++
++ constituents = (struct ffa_mem_region_constituent *)
++ (((void *)mem_region) + fragment_len);
++
++ composite->constituent_count = nents;
++ total_len = compute_region_length(nents, num_attrs);
++
++ for (index = 0; index < num_attrs; index++) {
++ mem_region->endpoints[index].receiver = attrs[index].receiver;
++ mem_region->endpoints[index].attrs =
++ attrs[index].attrs;
++
++ mem_region->endpoints[index].composite_off =
++ compute_composite_offset(num_attrs);
++ }
++ mem_region->endpoint_count = num_attrs;
++
++ num_constituents = 0;
++
++ do {
++ phys_addr_t address;
++
++ /*
++ * If current fragment size equal Tx size trigger fragment
++ * transfer.
++ */
++ if (fragment_len == max_fragment_size) {
++
++ /* Transmit fragment. */
++ rc = ffa_transmit_fragment(&tx_offset, buffer,
++ buffer_size, fragment_len, total_len, handle);
++
++ if (rc < 0)
++ return -ENXIO;
++
++
++ constituents =
++ (struct ffa_mem_region_constituent *)mem_region;
++
++ num_constituents = 0;
++ fragment_len = 0;
++ }
++
++ address = sg_phys(sg);
++
++ /*
++ * Detect if any part of the constituent region surpasses the Tx
++ * region.
++ */
++ if (((void *) &constituents[num_constituents])
++ - (void *)mem_region > max_fragment_size) {
++ pr_err("%s: memory region fragment greater that the Tx buffer",
++ __func__);
++ return -EFAULT;
++ }
++#if 0
++ pr_devel("arm_ffa mem_share pa=%#lX\n", address);
++#endif
++ constituents[num_constituents].address = address;
++ constituents[num_constituents].page_count =
++ sg->length/PAGE_SIZE;
++ num_constituents++;
++ fragment_len += sizeof(struct ffa_mem_region_constituent);
++
++
++ } while ((sg = sg_next(sg)));
++
++ rc = ffa_transmit_fragment(&tx_offset, buffer, buffer_size,
++ fragment_len, total_len, handle);
++
++ return rc;
++}
++
++/*
++ * Share a set of pages with a list of destination endpoints.
++ *
++ * Returns a system-wide unique handle
++ */
++static int ffa_share_memory(u32 tag, enum mem_clear_t flags,
++ struct ffa_mem_region_attributes *attrs,
++ u32 num_attrs, struct scatterlist *sg, u32 nents,
++ ffa_mem_handle_t *global_handle, bool use_tx)
++{
++ u32 buffer_size = 0;
++ phys_addr_t buffer_pa = 0;
++ int ret;
++ struct page *buffer_page = NULL;
++
++ if (!use_tx) {
++ /* Allocate buffer for this mem_share operation. */
++ buffer_page = alloc_page(GFP_KERNEL);
++ if (IS_ERR_OR_NULL(buffer_page)) {
++ /* print error. Return as tx lock is not held. */
++ pr_err("%s: unable to allocate buffer", __func__);
++ return -ENOMEM;
++ }
++
++ buffer_pa = page_to_phys(buffer_page);
++
++ buffer_size = 1;
++ }
++
++ if (use_tx)
++ mutex_lock(&tx_lock);
++
++ ret = _ffa_share_memory(tag, flags, attrs, num_attrs, sg, nents,
++ global_handle, buffer_pa, buffer_size);
++
++ if (use_tx)
++ mutex_unlock(&tx_lock);
++
++ return ret;
++}
++
++static int ffa_memory_reclaim(ffa_mem_handle_t global_handle,
++ enum mem_clear_t flags)
++{
++
++ struct arm_smcccv1_2_return smccc_return;
++ u32 handle_high = (global_handle >> 32) & 0xffffffff;
++ u32 handle_low = global_handle & 0xffffffff;
++
++ smccc_return = arm_ffa_smccc(FFA_MEM_RECLAIM_32, handle_low,
++ handle_high, flags, 0, 0, 0, 0);
++
++ if (smccc_return.arg0 == FFA_ERROR_32) {
++ pr_err("%s: Error sending message %llu\n", __func__,
++ smccc_return.arg0);
++ switch ((int)smccc_return.arg2) {
++ case FFA_INVALID_PARAMETERS:
++ return -ENXIO;
++ case FFA_DENIED:
++ case FFA_NOT_SUPPORTED:
++ return -EIO;
++ case FFA_BUSY:
++ return -EAGAIN;
++ default:
++ pr_warn("%s: Unknown Error code %llx\n", __func__,
++ smccc_return.arg2);
++ return -EIO;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * Returns a negative value if function not supported. Otherwise returns w2,
++ * supplying optional feature parameter else 0.
++ */
++
++static int ffa_features(uint32_t function_id)
++{
++ struct arm_smcccv1_2_return features_return =
++ arm_ffa_smccc(FFA_FEATURES_32, function_id, 0, 0, 0, 0, 0, 0);
++
++ if (features_return.arg0 == FFA_ERROR_32) {
++ switch ((int)features_return.arg2) {
++ case FFA_NOT_SUPPORTED:
++ return -ENODEV;
++ default:
++ panic("%s: Unhandled return code (%lld)\n", __func__,
++ features_return.arg2);
++ }
++ } else {
++ return features_return.arg2;
++ }
++}
++
++static ffa_sp_id_t ffa_id_get(ffa_sp_id_t *vm_id_p)
++{
++ struct arm_smcccv1_2_return id_get_return =
++ arm_ffa_smccc(FFA_ID_GET_32, 0, 0, 0, 0, 0, 0, 0);
++
++ if (id_get_return.arg0 == FFA_ERROR_32) {
++ pr_warn("%s: failed to obtain vm id\n", __func__);
++ return -EIO;
++ }
++
++ *vm_id_p = id_get_return.arg2 & 0xffff;
++
++ return 0;
++}
++
++static int ffa_partition_info_get(uint32_t uuid0, uint32_t uuid1,
++ uint32_t uuid2, uint32_t uuid3,
++ struct ffa_partition_info **buffer)
++{
++ int rc = 0;
++ uint32_t count;
++ struct ffa_partition_info *info =
++ (struct ffa_partition_info *) page_address(rx_buffer);
++ struct arm_smcccv1_2_return partition_info_get_return;
++
++ mutex_lock(&rx_lock);
++ partition_info_get_return = arm_ffa_smccc(FFA_PARTITION_INFO_GET_32,
++ uuid0, uuid1, uuid2, uuid3,
++ 0, 0, 0);
++
++ if (partition_info_get_return.arg0 == FFA_ERROR_32) {
++ switch ((int)partition_info_get_return.arg2) {
++ case FFA_INVALID_PARAMETERS:
++ rc = -ENXIO;
++ goto err;
++ case FFA_NO_MEMORY:
++ rc = -ENOMEM;
++ goto err;
++ case FFA_NOT_SUPPORTED:
++ rc = -ENODEV;
++ goto err;
++ default:
++ panic("%s: Unhandled return code (%lld)\n", __func__,
++ partition_info_get_return.arg2);
++ }
++ }
++
++ count = partition_info_get_return.arg2;
++
++ /* Allocate and copy the info structs.
++ * Client is responsible for freeing.
++ */
++ *buffer = kzalloc(sizeof(struct ffa_partition_info) * count,
++ GFP_KERNEL);
++ if (*buffer == NULL) {
++ rc = -ENOMEM;
++ goto err;
++ }
++ memcpy(*buffer, info, sizeof(struct ffa_partition_info) * count);
++
++ ffa_rx_release();
++
++ rc = count;
++err:
++ mutex_unlock(&rx_lock);
++
++ return rc;
++}
++
++static struct ffa_ops ffa_ops = {
++ .async_msg_send = ffa_msg_send,
++ .sync_msg_send = ffa_msg_send_direct_req,
++ .mem_share = ffa_share_memory,
++ .mem_reclaim = ffa_memory_reclaim,
++ .partition_info_get = ffa_partition_info_get,
++};
++
++struct ffa_ops *get_ffa_ops(void)
++{
++ return &ffa_ops;
++}
++EXPORT_SYMBOL_GPL(get_ffa_ops);
++
++static int ffa_dt_init(struct device_node *np)
++{
++ const char *conduit;
++
++ pr_info("FFA: obtaining conduit from DT.\n");
++
++ if (of_property_read_string(np, "conduit", &conduit)) {
++ pr_warn("FFA: cannot find conduit in DT\n");
++ return -ENXIO;
++ }
++
++ if (!strcmp("smc", conduit))
++ arm_ffa_smccc = arm_ffa_smc;
++ else if (!strcmp("hvc", conduit))
++ arm_ffa_smccc = arm_ffa_hvc;
++ else {
++ pr_warn("%s: unrecognized FFA conduit\n", __func__);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static const struct of_device_id ffa_of_match[] = {
++ {.compatible = "arm,ffa"},
++ {},
++};
++
++static int ffa_rxtx_map(uintptr_t tx_page, uintptr_t rx_page)
++{
++ struct arm_smcccv1_2_return map_return;
++
++ map_return = arm_ffa_smccc(FFA_RXTX_MAP_32, tx_page,
++ rx_page, 1, 0, 0, 0, 0);
++
++ if (map_return.arg0 == FFA_ERROR_32) {
++ switch ((int)map_return.arg2) {
++ case FFA_INVALID_PARAMETERS:
++ return -ENXIO;
++ case FFA_DENIED:
++ return -EAGAIN;
++ case FFA_NO_MEMORY:
++ return -ENOMEM;
++ case FFA_NOT_SUPPORTED:
++ return -ENODEV;
++
++ default:
++ panic("%s: Unhandled return code (%lld)\n", __func__,
++ map_return.arg2);
++ }
++ }
++
++ return 0;
++}
++
++static int ffa_version_check(void)
++{
++ struct arm_smcccv1_2_return version_return;
++ u16 major = 1;
++ u16 minor = 0;
++ u32 hv_version;
++
++ version_return = arm_ffa_smccc(FFA_VERSION_32, ((u32)major<<16)|minor,
++ 0, 0, 0, 0, 0, 0);
++
++ if ((int)version_return.arg0 == FFA_NOT_SUPPORTED) {
++ pr_err("%s: FFA ABI is not supported at higher exception levels\n",
++ __func__);
++ return -ENODEV;
++ }
++
++ hv_version = version_return.arg0;
++
++ if ((hv_version>>16) == major)
++ if ((hv_version & 0xffff) >= minor)
++ return 0;
++
++ pr_err("%s: incompatible FFA ABI at higher exception level (%x)\n",
++ __func__, hv_version);
++ return -ENODEV;
++}
++
++static int ffa_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ ret = ffa_dt_init(pdev->dev.of_node);
++ if (ret) {
++ pr_warn("%s: FFA driver initialization failed\n", __func__);
++ return ret;
++ }
++
++ ret = ffa_version_check();
++ if (ret)
++ return ret;
++
++ /* Initialize VM ID. */
++ ret = ffa_id_get(&vm_id);
++ if (ret) {
++ pr_warn("%s: failed to obtain own FFA endpoint ID\n", __func__);
++ return ret;
++ }
++
++ if (ffa_features(FFA_MSG_SEND_DIRECT_REQ_32)) {
++ pr_err("%s: FFA implementation at EL2 does not support FFA_MSG_SEND_DIRECT_REQ_32\n",
++ __func__);
++ return -ENXIO;
++ }
++
++ /* Allocate Rx buffer. */
++ rx_buffer = alloc_page(GFP_KERNEL);
++
++ /*
++ * Ensure buffer was correctly allocated and that the refcout was
++ * incremented.
++ */
++ if (!rx_buffer || !try_get_page(rx_buffer)) {
++ pr_err("%s: failed to allocate FFA Rx buffer\n", __func__);
++ return -ENOMEM;
++ }
++
++ /* Allocate Tx buffer. */
++ tx_buffer = alloc_page(GFP_KERNEL);
++
++ /*
++ * Ensure buffer was correctly allocated and that the refcout was
++ * incremented.
++ */
++ if (!tx_buffer || !try_get_page(rx_buffer)) {
++ put_page(rx_buffer);
++ __free_page(rx_buffer);
++
++ pr_err("%s: failed to allocate FFA Tx buffer\n", __func__);
++ return -ENOMEM;
++ }
++
++ /* Register the RxTx buffers with the FFA supervisor implementation. */
++ ret = ffa_rxtx_map(page_to_phys(tx_buffer), page_to_phys(rx_buffer));
++ if (ret) {
++ put_page(rx_buffer);
++ put_page(tx_buffer);
++ __free_page(rx_buffer);
++ __free_page(tx_buffer);
++
++ pr_err("%s: failed to register FFA RxTx buffers\n", __func__);
++ return ret;
++ }
++
++ return 0;
++}
++
++static struct platform_driver ffa_driver = {
++ .driver = {
++ .name = "ffa_protocol",
++ .of_match_table = ffa_of_match,
++ },
++ .probe = ffa_probe,
++};
++module_platform_driver(ffa_driver);
++
++MODULE_AUTHOR("Arm");
++MODULE_DESCRIPTION("Arm FFA transport driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/arm-smcccv1_2.h b/include/linux/arm-smcccv1_2.h
+new file mode 100644
+index 000000000000..a622cc352ae1
+--- /dev/null
++++ b/include/linux/arm-smcccv1_2.h
+@@ -0,0 +1,51 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2019 Arm Ltd.
++ */
++
++//#if defined(ARM64)
++#if CONFIG_ARM64
++struct arm_smcccv1_2_return {
++ u64 arg0;
++ u64 arg1;
++ u64 arg2;
++ u64 arg3;
++ u64 arg4;
++ u64 arg5;
++ u64 arg6;
++ u64 arg7;
++};
++#elif CONFIG_ARM
++struct arm_smcccv1_2_return {
++ u32 arg0;
++ u32 arg1;
++ u32 arg2;
++ u32 arg3;
++ u32 arg4;
++ u32 arg5;
++ u32 arg6;
++ u32 arg7;
++};
++#endif
++
++/**
++ * __arm_smcccv1_2_hvc() - make HVC calls
++ * @a0-a7: arguments passed in registers 0 to 7
++ * @res: result values from registers 0 to 7
++ */
++asmlinkage
++void __arm_smcccv1_2_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
++ unsigned long a3, unsigned long a4, unsigned long a5,
++ unsigned long a6, unsigned long a7,
++ struct arm_smcccv1_2_return *res);
++
++/**
++ * __arm_smcccv1_2_smc() - make SMC calls
++ * @a0-a7: arguments passed in registers 0 to 7
++ * @res: result values from registers 0 to 7
++ */
++asmlinkage
++void __arm_smcccv1_2_smc(unsigned long a0, unsigned long a1, unsigned long a2,
++ unsigned long a3, unsigned long a4, unsigned long a5,
++ unsigned long a6, unsigned long a7,
++ struct arm_smcccv1_2_return *res);
+diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
+new file mode 100644
+index 000000000000..d3c80b7f9e07
+--- /dev/null
++++ b/include/linux/arm_ffa.h
+@@ -0,0 +1,235 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2019, 2020 Arm Ltd.
++ */
++
++#ifndef __LINUX_ARM_FFA_H
++#define __LINUX_ARM_FFA_H
++
++#define FFA_ERROR_32 0x84000060
++#define FFA_SUCCESS_32 0x84000061
++#define FFA_INTERRUPT_32 0x84000062
++#define FFA_VERSION_32 0x84000063
++#define FFA_FEATURES_32 0x84000064
++#define FFA_RX_RELEASE_32 0x84000065
++#define FFA_RXTX_MAP_32 0x84000066
++
++#define FFA_PARTITION_INFO_GET_32 0x84000068
++#define FFA_ID_GET_32 0x84000069
++
++#define FFA_RUN_32 0x8400006D
++#define FFA_MSG_SEND_32 0x8400006E
++#define FFA_MSG_SEND_DIRECT_REQ_32 0x8400006F
++#define FFA_MSG_SEND_DIRECT_RESP_32 0x84000070
++#define FFA_MEM_RECLAIM_32 0x84000077
++#define FFA_MEM_OP_PAUSE_32 0x84000078
++#define FFA_MEM_OP_RESUME_32 0x84000079
++
++#define FFA_MEM_SHARE_64 0xC4000073
++
++#define FFA_MEM_FRAG_RX_32 0x8400007A
++#define FFA_MEM_FRAG_TX_32 0x8400007B
++
++/* FFA error codes. */
++#define FFA_SUCCESS (0)
++#define FFA_NOT_SUPPORTED (-1)
++#define FFA_INVALID_PARAMETERS (-2)
++#define FFA_NO_MEMORY (-3)
++#define FFA_BUSY (-4)
++#define FFA_INTERRUPTED (-5)
++#define FFA_DENIED (-6)
++#define FFA_RETRY (-7)
++#define FFA_ABORTED (-8)
++
++#define FFA_BASE_GRANULE_SIZE 4096
++
++struct scatterlist;
++
++enum ffa_mem_permission {
++ FFA_MEM_R = 0x1,
++ FFA_MEM_RW = 0x2,
++ FFA_MEM_XN = 0x4,
++ FFA_MEM_X = 0x8,
++};
++
++#define FFA_MEMTYPE_OFFSET 4
++enum ffa_mem_type {
++ FFA_MEM_DEVICE = 0x1,
++ FFA_MEM_NORMAL = 0x2,
++};
++
++
++#define FFA_CACHEABILITY_OFFSET 2
++enum ffa_mem_cacheability {
++ FFA_NON_CACHEABLE = 0x1,
++ FFA_WRITE_BACK = 0x3,
++};
++
++enum ffa_mem_shareability {
++ FFA_NON_SHAREABLE,
++ FFA_OUTER_SHAREABLE = 0x2,
++ FFA_INNER_SHAREABLE = 0x3,
++};
++
++#define FFA_DEVICE_OFFSET 2
++enum ffa_mem_device_type {
++ FFA_NGNRNE,
++ FFA_NGNRE,
++ FFA_NGRE,
++ FFA_GRE,
++};
++
++enum mem_clear_t {
++ FFA_KEEP_MEMORY,
++ FFA_CLEAR_MEMORY,
++};
++
++typedef u64 ffa_mem_handle_t;
++
++/* The type of an FFA endpoint ID */
++typedef u16 ffa_sp_id_t;
++
++struct ffa_mem_region_constituent {
++ u64 address;
++ u32 page_count;
++ u32 reserved_12_15;
++};
++
++struct ffa_composite_memory_region {
++
++ uint32_t total_page_count;
++ uint32_t constituent_count;
++
++ uint64_t reserved_0;
++
++ struct ffa_mem_region_constituent constituents[];
++};
++
++struct ffa_mem_region_attributes {
++ ffa_sp_id_t receiver;
++ u8 attrs;
++ u32 composite_off;
++ u64 reserved_8_15;
++};
++
++/* Table 43 */
++struct ffa_memory_region_attribute {
++ uint8_t attribute;
++};
++
++struct ffa_mem_region {
++ u16 sender_id;
++ struct ffa_memory_region_attribute region_attr;
++ u8 reserved_0;
++ u32 flags;
++ u64 handle;
++ u64 tag;
++ u32 reserved_1;
++ u32 endpoint_count;
++ struct ffa_mem_region_attributes endpoints[];
++};
++
++static inline struct ffa_composite_memory_region *
++ffa_get_composite(struct ffa_mem_region *mem_region, u32 num_endpoints)
++{
++ struct ffa_composite_memory_region *composite;
++
++ composite = (struct ffa_composite_memory_region *)
++ (&mem_region->endpoints[num_endpoints]);
++ return composite;
++}
++
++
++struct ffa_partition_info {
++ /** The ID of the VM the information is about. */
++ ffa_sp_id_t id;
++ /**
++ * The number of execution contexts implemented by the
++ * partition.
++ */
++ uint16_t execution_context;
++ /**
++ * The Partition's properties, e.g. supported messaging
++ * methods
++ */
++ uint32_t partition_properties;
++};
++
++
++/**
++ * struct ffa_ops - represents the various FFA protocol operations
++ * available for an SCPI endpoint.
++ */
++struct ffa_ops {
++ int (*async_msg_send)(ffa_sp_id_t dst_id, u32 len, u32 attributes);
++ struct arm_smcccv1_2_return
++ (*sync_msg_send)(ffa_sp_id_t dst_id, u64 w3, u64 w4, u64 w5,
++ u64 w6, u64 w7);
++
++ /**
++ * Registers a memory region with the FFA implementation.
++ *
++ * Params:
++ * - tag: Implementation defined value.
++ * - flags:
++ * - FFA_KEEP_MEMORY: DO not clear the memory region;
++ * - FFA_CLEAR_MEMORY: Clear the memory region.
++ * - attrs[]: Array of destination VMs and permissions with which the
++ * Stage-2 mappings are set.
++ * - num_attrs: Count of elements pointed to by attrs.
++ * - sg: scatter list holding the pages to be shared.
++ * - global_handle: A system-wide unique handle referring to the shared
++ * set of physical pages being shared.
++ * - use_tx: select if memorry region description is transmitted in tx
++ * or in a dynamically allocated buffer. When using the tx buffer a
++ * global lock on the tx buffer will be held.
++ *
++ * Return: 0 in case of success, otherwise a negative value
++ * (error code).
++ */
++ int (*mem_share)(u32 tag, enum mem_clear_t flags,
++ struct ffa_mem_region_attributes attrs[],
++ u32 num_attrs, struct scatterlist *sg, u32 nents,
++ ffa_mem_handle_t *global_handle, bool use_tx);
++
++ /**
++ * Reclaims a memory region previously registered with the FFA
++ * implementation.
++ * Params:
++ * - global_handle: The global identifier of the memory region being
++ * reclaimed.
++ * - clear_memory: Set if the memory is meant to be cleared before
++ * being mapped in the owner's Stage-2.
++ *
++ * Return: 0 in case of success, otherwise a negative value
++ * (error code).
++ */
++ int (*mem_reclaim)(ffa_mem_handle_t global_handle,
++ enum mem_clear_t flags);
++ /**
++ * Returns information on a sub-set of partitions within a system
++ * identified by a UUID.
++ * Params:
++ * - uuid0-3: The 128 bit UUID of the desired partition(s) represented
++ * as 4 32 bit uints in form: uuid0-uuid1-uuid2-uuid3.
++ * - ffa_partition_info**: A pointer to an array of
++ * `ffa_parition_info` structs that will be
++ * allocated and populated with the
++ * discovered partitions information. The
++ * caller is responsible for freeing the
++ * memory allocated by the FFA driver.
++ * Return: The number of discovered partitions in the system and the
++ * length of the array of ffa_partition_info structs,
++ * otherwise a negative value (error code).
++ */
++ int (*partition_info_get)(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
++ struct ffa_partition_info **buffer);
++};
++
++#if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT)
++struct ffa_ops *get_ffa_ops(void);
++#else
++static inline struct ffa_ops *get_ffa_ops(void) { return NULL; }
++#endif
++
++#endif /*__LINUX_ARM_FFA_H*/
+--
+2.26.2
+
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 08/10] arm-bsp/linux: enable ffa driver for TC0
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (5 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 07/10] arm-bsp/linux: add ffa driver to TC0 Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 09/10] arm-bsp/linux: add ffa transport in optee " Arunachalam Ganapathy
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
Enables ffa driver. Sets CONFIG_ARM_FFA_TRANSPORT=y
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I71ffeb6b3bc5b28c34bfab09cdcc66227203c74c
---
.../recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig
index f858f51..0f44a94 100644
--- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig
@@ -102,6 +102,7 @@ CONFIG_ARM_SCMI_CPUFREQ=y
CONFIG_ARM_TEGRA186_CPUFREQ=y
CONFIG_ARM_SCMI_PROTOCOL=y
CONFIG_ARM_SCPI_PROTOCOL=y
+CONFIG_ARM_FFA_TRANSPORT=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_INTEL_STRATIX10_SERVICE=y
CONFIG_INTEL_STRATIX10_RSU=m
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 09/10] arm-bsp/linux: add ffa transport in optee driver for TC0
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (6 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 08/10] arm-bsp/linux: enable ffa driver for TC0 Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-12 15:20 ` [PATCH 10/10] arm-bsp/tc0: Enable spmd and SEL2 SPMC with optee as SEL1 SP Arunachalam Ganapathy
2021-01-14 19:23 ` [meta-arm] [PATCH 01/10] arm: Add hafnium support Jon Mason
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
This patch adds FF-A transport driver for optee driver. This is based
on prototype version released by Arm and its port for android11-5.4-lts
kernel.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I991895881c069767854ae8a0722cdc282b221dd9
---
.../linux/linux-arm-platforms.inc | 4 +
...for-session-s-client-UUID-generation.patch | 252 ++
...pport-for-session-login-client-UUID-.patch | 43 +
...iver-optee-Support-for-ffa-transport.patch | 3150 +++++++++++++++++
...m-handle-removal-in-ffa_shm_unregist.patch | 51 +
5 files changed, 3500 insertions(+)
create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0010-tee-add-support-for-session-s-client-UUID-generation.patch
create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0011-tee-optee-Add-support-for-session-login-client-UUID-.patch
create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0012-driver-optee-Support-for-ffa-transport.patch
create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.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 873f120..839fe68 100644
--- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
@@ -77,6 +77,10 @@ SRC_URI_append_tc0 = " \
file://0007-firmware-arm_scmi-Add-fast_switch_possible-api.patch \
file://0008-cpufreq-arm_scmi-Set-fast_switch_possible-conditiona.patch \
file://0009-driver-firmware-Initial-version-of-ffa-driver-based-.patch \
+ file://0010-tee-add-support-for-session-s-client-UUID-generation.patch \
+ file://0011-tee-optee-Add-support-for-session-login-client-UUID-.patch \
+ file://0012-driver-optee-Support-for-ffa-transport.patch \
+ file://0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch \
"
#
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0010-tee-add-support-for-session-s-client-UUID-generation.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0010-tee-add-support-for-session-s-client-UUID-generation.patch
new file mode 100644
index 0000000..269940e
--- /dev/null
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0010-tee-add-support-for-session-s-client-UUID-generation.patch
@@ -0,0 +1,252 @@
+Upstream-Status: Backport [https://github.com/linaro-swg/linux/commit/e33bcbab16d1c0dd85d72bec275308369ad901f5#diff-317c0445401e56bde9d2ee0e0bb2758b0362a4099dca8e535dd20f1f649ecfc8]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 69a50f4234d8fb143d499e92e3f0f67009bae586 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?=
+ <vesa.jaaskelainen@vaisala.com>
+Date: Wed, 22 Apr 2020 15:28:07 +0300
+Subject: [PATCH] tee: add support for session's client UUID generation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+TEE Client API defines that from user space only information needed for
+specified login operations is group identifier for group based logins.
+
+REE kernel is expected to formulate trustworthy client UUID and pass that
+to TEE environment. REE kernel is required to verify that provided group
+identifier for group based logins matches calling processes group
+memberships.
+
+TEE specification only defines that the information passed from REE
+environment to TEE environment is encoded into on UUID.
+
+In order to guarantee trustworthiness of client UUID user space is not
+allowed to freely pass client UUID.
+
+UUIDv5 form is used encode variable amount of information needed for
+different login types.
+
+Signed-off-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
+Change-Id: I414f68d7485f95277d292fcb2646cc41bd57e62a
+---
+ drivers/tee/Kconfig | 1 +
+ drivers/tee/tee_core.c | 143 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/tee_drv.h | 16 +++++
+ 3 files changed, 160 insertions(+)
+
+diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
+index 676ffcb64985..5a56317f3f4e 100644
+--- a/drivers/tee/Kconfig
++++ b/drivers/tee/Kconfig
+@@ -3,6 +3,7 @@
+ config TEE
+ tristate "Trusted Execution Environment support"
+ depends on HAVE_ARM_SMCCC || COMPILE_TEST
++ select CRYPTO_SHA1
+ select DMA_SHARED_BUFFER
+ select GENERIC_ALLOCATOR
+ help
+diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
+index 0f16d9ffd8d1..3d32a2ca48c3 100644
+--- a/drivers/tee/tee_core.c
++++ b/drivers/tee/tee_core.c
+@@ -6,18 +6,33 @@
+ #define pr_fmt(fmt) "%s: " fmt, __func__
+
+ #include <linux/cdev.h>
++#include <linux/cred.h>
+ #include <linux/fs.h>
+ #include <linux/idr.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/tee_drv.h>
+ #include <linux/uaccess.h>
++#include <crypto/hash.h>
++#include <crypto/sha.h>
+ #include "tee_private.h"
+
+ #define TEE_NUM_DEVICES 32
+
+ #define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
+
++#define TEE_UUID_NS_NAME_SIZE 128
++
++/*
++ * TEE Client UUID name space identifier (UUIDv4)
++ *
++ * Value here is random UUID that is allocated as name space identifier for
++ * forming Client UUID's for TEE environment using UUIDv5 scheme.
++ */
++static const uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683,
++ 0xa1, 0xb8, 0xec, 0x4b,
++ 0xc0, 0x8e, 0x01, 0xb6);
++
+ /*
+ * Unprivileged devices in the lower half range and privileged devices in
+ * the upper half range.
+@@ -111,6 +126,134 @@ static int tee_release(struct inode *inode, struct file *filp)
+ return 0;
+ }
+
++/**
++ * uuid_v5() - Calculate UUIDv5
++ * @uuid: Resulting UUID
++ * @ns: Name space ID for UUIDv5 function
++ * @name: Name for UUIDv5 function
++ * @size: Size of name
++ *
++ * UUIDv5 is specific in RFC 4122.
++ *
++ * This implements section (for SHA-1):
++ * 4.3. Algorithm for Creating a Name-Based UUID
++ */
++static int uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name,
++ size_t size)
++{
++ unsigned char hash[SHA1_DIGEST_SIZE];
++ struct crypto_shash *shash = NULL;
++ struct shash_desc *desc = NULL;
++ int rc;
++
++ shash = crypto_alloc_shash("sha1", 0, 0);
++ if (IS_ERR(shash)) {
++ rc = PTR_ERR(shash);
++ pr_err("shash(sha1) allocation failed\n");
++ return rc;
++ }
++
++ desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),
++ GFP_KERNEL);
++ if (IS_ERR(desc)) {
++ rc = PTR_ERR(desc);
++ goto out;
++ }
++
++ desc->tfm = shash;
++
++ rc = crypto_shash_init(desc);
++ if (rc < 0)
++ goto out2;
++
++ rc = crypto_shash_update(desc, (const u8 *)ns, sizeof(*ns));
++ if (rc < 0)
++ goto out2;
++
++ rc = crypto_shash_update(desc, (const u8 *)name, size);
++ if (rc < 0)
++ goto out2;
++
++ rc = crypto_shash_final(desc, hash);
++ if (rc < 0)
++ goto out2;
++
++ memcpy(uuid->b, hash, UUID_SIZE);
++
++ /* Tag for version 5 */
++ uuid->b[6] = (hash[6] & 0x0F) | 0x50;
++ uuid->b[8] = (hash[8] & 0x3F) | 0x80;
++
++out2:
++ kfree(desc);
++
++out:
++ crypto_free_shash(shash);
++ return rc;
++}
++
++int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
++ const u8 connection_data[TEE_IOCTL_UUID_LEN])
++{
++ const char *application_id = NULL;
++ gid_t ns_grp = (gid_t)-1;
++ kgid_t grp = INVALID_GID;
++ char *name = NULL;
++ int rc;
++
++ if (connection_method == TEE_IOCTL_LOGIN_PUBLIC) {
++ /* Nil UUID to be passed to TEE environment */
++ uuid_copy(uuid, &uuid_null);
++ return 0;
++ }
++
++ /*
++ * In Linux environment client UUID is based on UUIDv5.
++ *
++ * Determine client UUID with following semantics for 'name':
++ *
++ * For TEEC_LOGIN_USER:
++ * uid=<uid>
++ *
++ * For TEEC_LOGIN_GROUP:
++ * gid=<gid>
++ *
++ */
++
++ name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL);
++ if (!name)
++ return -ENOMEM;
++
++ switch (connection_method) {
++ case TEE_IOCTL_LOGIN_USER:
++ scnprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x",
++ current_euid().val);
++ break;
++
++ case TEE_IOCTL_LOGIN_GROUP:
++ memcpy(&ns_grp, connection_data, sizeof(gid_t));
++ grp = make_kgid(current_user_ns(), ns_grp);
++ if (!gid_valid(grp) || !in_egroup_p(grp)) {
++ rc = -EPERM;
++ goto out;
++ }
++
++ scnprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x", grp.val);
++ break;
++
++ default:
++ rc = -EINVAL;
++ goto out;
++ }
++
++ rc = uuid_v5(uuid, &tee_client_uuid_ns, name, strlen(name));
++out:
++ kfree(name);
++
++ return rc;
++}
++EXPORT_SYMBOL_GPL(tee_session_calc_client_uuid);
++
+ static int tee_ioctl_version(struct tee_context *ctx,
+ struct tee_ioctl_version_data __user *uvers)
+ {
+diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
+index 7a03f68fb982..545a57f61a5e 100644
+--- a/include/linux/tee_drv.h
++++ b/include/linux/tee_drv.h
+@@ -166,6 +166,22 @@ int tee_device_register(struct tee_device *teedev);
+ */
+ void tee_device_unregister(struct tee_device *teedev);
+
++/**
++ * tee_session_calc_client_uuid() - Calculates client UUID for session
++ * @uuid: Resulting UUID
++ * @connection_method: Connection method for session (TEE_IOCTL_LOGIN_*)
++ * @connectuon_data: Connection data for opening session
++ *
++ * Based on connection method calculates UUIDv5 based client UUID.
++ *
++ * For group based logins verifies that calling process has specified
++ * credentials.
++ *
++ * @return < 0 on failure
++ */
++int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
++ const u8 connection_data[TEE_IOCTL_UUID_LEN]);
++
+ /**
+ * struct tee_shm - shared memory object
+ * @teedev: device used to allocate the object
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0011-tee-optee-Add-support-for-session-login-client-UUID-.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0011-tee-optee-Add-support-for-session-login-client-UUID-.patch
new file mode 100644
index 0000000..65d4311
--- /dev/null
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0011-tee-optee-Add-support-for-session-login-client-UUID-.patch
@@ -0,0 +1,43 @@
+Upstream-Status: Backport [https://github.com/linaro-swg/linux/commit/c5b4312bea5d5e5e3d4f0af640e2ef8a1c1bb167#diff-2d83bca4adf0468bdb51b155a5df495e0226f7971f4150cfffbf043fe3b5a279]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From c6c4046d8fcd34a4b8da9d844ce592951780ba8c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?=
+ <vesa.jaaskelainen@vaisala.com>
+Date: Wed, 22 Apr 2020 15:30:39 +0300
+Subject: [PATCH] tee: optee: Add support for session login client UUID
+ generation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds support for client UUID generation for OP-TEE. For group based session
+logins membership is verified.
+
+Signed-off-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
+---
+ drivers/tee/optee/call.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
+index cf2367ba08d6..dbed3f480dc0 100644
+--- a/drivers/tee/optee/call.c
++++ b/drivers/tee/optee/call.c
+@@ -233,9 +233,13 @@ int optee_open_session(struct tee_context *ctx,
+ msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
+ OPTEE_MSG_ATTR_META;
+ memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid));
+- memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid));
+ msg_arg->params[1].u.value.c = arg->clnt_login;
+
++ rc = tee_session_calc_client_uuid((uuid_t *)&msg_arg->params[1].u.value,
++ arg->clnt_login, arg->clnt_uuid);
++ if (rc)
++ goto out;
++
+ rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param);
+ if (rc)
+ goto out;
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0012-driver-optee-Support-for-ffa-transport.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0012-driver-optee-Support-for-ffa-transport.patch
new file mode 100644
index 0000000..40d4ffe
--- /dev/null
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0012-driver-optee-Support-for-ffa-transport.patch
@@ -0,0 +1,3150 @@
+Upstream-Status: Pending [https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/commit/?h=ffa_rel_proto&id=8a0acded67268b7110c69ed5425c56d881716d78]
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+
+From 2e12bf893c180cb1444ca20148983d1c45431c71 Mon Sep 17 00:00:00 2001
+From: Jens Wiklander <jens.wiklander@linaro.org>
+Date: Tue, 30 Oct 2018 21:12:11 +0100
+Subject: [PATCH] driver: optee: Support for ffa transport
+
+FF-A transport support for optee driver. Based on ffa_rel_proto at
+https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git/log/?h=ffa_rel_proto
+
+Squashed in:
+ tee: remove linked list of struct tee_shm
+
+ Removes list_shm from struct tee_context since the linked list isn't used
+ any longer.
+
+ tee: remove unused tee_shm_priv_alloc()
+
+ tee_shm_priv_alloc() isn't useful in the current state and it's also not
+ not used so remove it.
+
+ tee: don't assign shm id for private shms
+
+ Private shared memory object must not be referenced from user space. To
+ guarantee that don't assign an id to keep the shared memory driver
+ private.
+
+ tee: remove redundant teedev in struct tee_shm
+
+ Since the ctx element in struct tee_shm always is valid has the teedev
+ element become redundant so remove it.
+
+ tee: add sec_world_id to struct tee_shm
+
+ Adds sec_world_id to struct tee_shm which describes a shared memory
+ object. sec_world_id can be used by a driver to store an id assigned by
+ secure world.
+
+ tee: tee_shm_op_mmap(): use TEE_SHM_USER_MAPPED
+
+ tee_shm_op_mmap() uses the TEE_SHM_USER_MAPPED flag instead of the
+ TEE_SHM_REGISTER flag to tell if a shared memory object is originating
+ from registered user space memory.
+
+ Set -Og flags for the OPTEE driver compilation.
+
+ optee: simplify optee_release()
+
+ Simplifies optee_release() with a new helper function,
+ optee_close_session_helper() which has been factored out from
+ optee_close_session().
+
+ A separate optee_release_supp() is added for the supplicant device.
+
+ tee: optee: sync optee_msg.h and optee_rpc_cmd.h
+
+ Updates to latest optee_msg.h and optee_rpc_cmd.h. There's no changes in
+ the ABI. Only some clarifications and a complete specification of RPC
+ requests where the latter is now in a separate file, optee_rpc_cmd.h.
+
+ Most of the RPC requests are not served by the OP-TEE driver instead
+ they are forwarded as opaque requests to tee-supplicant.
+
+ tee: export tee_shm_alloc()
+
+ Export tee_shm_alloc() using EXPORT_SYMBOL_GPL(). Needed by
+ optee_rng_init() and other drivers complied as a module and using OP-TEE
+ as a service.
+
+ optee: add spci support
+
+ Adds support for using SPCI as transport to the OP-TEE driver.
+
+ tee: optee: introduce SPCI specific OPTEE_MSG memref
+
+ Introduces struct optee_msg_param_smem which carries all information
+ needed when OP-TEE is calling SPCI_MEM_RETRIEVE_REQ to get the shared
+ memory reference mapped by the hypervisor in S-EL2. Register usage is
+ also updated to include the information needed.
+
+ This isn't strictly needed without a hypervisor in S-EL2 and OP-TEE
+ itself has the SPMC part. However, this is a configuration which
+ shouldn't concern normal world.
+
+ tee: optee: Use PARTITION_INFO_GET to get SP ID.
+
+ Instead of using a hardcoded partition ID for OPTEE, use the
+ SPCI_PARTITION_INFO_GET ABI to find the partition ID corresponding to
+ the OPTEE UUID.
+
+ tee: optee: Update OPTEE for mem_share SPCI
+
+ Update OPTEE to pass a scatterlist in the mem_share interface.
+
+ tee: Adapt OPTEE to new SPCI mem_share interface
+
+ optee: test_spci: Update optee, spci test driver [optee bits]
+
+ Enable optee and spci test drivesr to pass a scatterlist* and a nents
+ parameter in mem_share.
+
+ arm_spci: refactor mem_share implementation for EAC [optee bits]
+
+ arm_ffa: optee: Swap spci/SPCI for ffa/FFA. [optee bits]
+
+ arm_ffa: rename 1st member of arm_smcccv1_2_return [optee bits]
+
+ The smcccv1_2_return.func is renamed to arg0.
+
+ tee: add sec_world_id to struct tee_shm
+
+ Change the type of sec_world_id member of struct tee_shm to u64 to be
+ able to store the 64-bit Global Handle defined in FF-A.
+
+ optee: updated for FF-A 1.0
+
+ With FF-A 1.0 the ABI to secure world has changed compared to SPCI
+ beta1.
+
+ The globally unique handle to identify a shared memory object is now 64
+ bits wide instead of previous 32. The IDR in struct optee_ffa is
+ replaced with a struct rhashtable instead in order to support 64-bit
+ keys.
+
+ Register usage in the FF-A function has changed compared to SPCI beta1
+ so the OP-TEE ABI is updated accordingly. The global handle, aka cookie,
+ is now requires 2 registers.
+
+ struct optee_msg_param_smem is updated to be able to carry a 64-bit
+ global handle while maintaining the same size of the struct. Due to this
+ the "page_count" field is dropped.
+
+ optee: Update SMCC field name
+
+ optee: Update FFA_VERSION from 0.9 to 1.0
+
+ optee/call.c: Update SPCI reference to FFA
+
+Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
+Signed-off-by: Marc Bonnici <marc.bonnici@arm.com>
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+---
+ drivers/tee/Makefile | 1 +
+ drivers/tee/optee/Makefile | 1 +
+ drivers/tee/optee/call.c | 318 ++++++++++---
+ drivers/tee/optee/core.c | 735 +++++++++++++++++++++++++-----
+ drivers/tee/optee/optee_ffa.h | 201 ++++++++
+ drivers/tee/optee/optee_msg.h | 167 ++-----
+ drivers/tee/optee/optee_private.h | 61 ++-
+ drivers/tee/optee/optee_rpc_cmd.h | 333 ++++++++++++++
+ drivers/tee/optee/rpc.c | 147 +++++-
+ drivers/tee/optee/shm_pool.c | 50 ++
+ drivers/tee/optee/shm_pool.h | 1 +
+ drivers/tee/tee_core.c | 1 -
+ drivers/tee/tee_shm.c | 85 +---
+ include/linux/tee_drv.h | 26 +-
+ 14 files changed, 1710 insertions(+), 417 deletions(-)
+ create mode 100644 drivers/tee/optee/optee_ffa.h
+ create mode 100644 drivers/tee/optee/optee_rpc_cmd.h
+
+diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
+index 21f51fd88b07..c4fe9f0d3bf8 100644
+--- a/drivers/tee/Makefile
++++ b/drivers/tee/Makefile
+@@ -4,3 +4,4 @@ tee-objs += tee_core.o
+ tee-objs += tee_shm.o
+ tee-objs += tee_shm_pool.o
+ obj-$(CONFIG_OPTEE) += optee/
++ccflags-y += -Og
+diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
+index 56263ae3b1d7..57371dc91bba 100644
+--- a/drivers/tee/optee/Makefile
++++ b/drivers/tee/optee/Makefile
+@@ -6,3 +6,4 @@ optee-objs += rpc.o
+ optee-objs += supp.o
+ optee-objs += shm_pool.o
+ optee-objs += device.o
++ccflags-y += -Og
+diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
+index dbed3f480dc0..ac89ab42a43f 100644
+--- a/drivers/tee/optee/call.c
++++ b/drivers/tee/optee/call.c
+@@ -3,16 +3,20 @@
+ * Copyright (c) 2015, Linaro Limited
+ */
+ #include <linux/arm-smccc.h>
++#include <linux/arm-smcccv1_2.h>
++#include <linux/arm_ffa.h>
+ #include <linux/device.h>
+ #include <linux/err.h>
+ #include <linux/errno.h>
+ #include <linux/mm.h>
++#include <linux/scatterlist.h>
+ #include <linux/slab.h>
+ #include <linux/tee_drv.h>
+ #include <linux/types.h>
+ #include <linux/uaccess.h>
+ #include "optee_private.h"
+ #include "optee_smc.h"
++#include "optee_ffa.h"
+
+ struct optee_call_waiter {
+ struct list_head list_node;
+@@ -122,13 +126,18 @@ static struct optee_session *find_session(struct optee_context_data *ctxdata,
+ *
+ * Returns return code from secure world, 0 is OK
+ */
+-u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
++int optee_do_call_with_arg(struct tee_context *ctx, struct tee_shm *arg)
+ {
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+- struct optee_call_waiter w;
++ struct optee_call_waiter w = { };
+ struct optee_rpc_param param = { };
+ struct optee_call_ctx call_ctx = { };
+- u32 ret;
++ phys_addr_t parg = 0;
++ int rc = 0;
++
++ rc = tee_shm_get_pa(arg, 0, &parg);
++ if (rc)
++ return rc;
+
+ param.a0 = OPTEE_SMC_CALL_WITH_ARG;
+ reg_pair_from_64(¶m.a1, ¶m.a2, parg);
+@@ -155,7 +164,7 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
+ param.a3 = res.a3;
+ optee_handle_rpc(ctx, ¶m, &call_ctx);
+ } else {
+- ret = res.a0;
++ rc = res.a0;
+ break;
+ }
+ }
+@@ -167,16 +176,15 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
+ */
+ optee_cq_wait_final(&optee->call_queue, &w);
+
+- return ret;
++ return rc;
+ }
+
+ static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params,
+- struct optee_msg_arg **msg_arg,
+- phys_addr_t *msg_parg)
++ struct optee_msg_arg **msg_arg)
+ {
+- int rc;
+- struct tee_shm *shm;
+- struct optee_msg_arg *ma;
++ int rc = 0;
++ struct tee_shm *shm = NULL;
++ struct optee_msg_arg *ma = NULL;
+
+ shm = tee_shm_alloc(ctx, OPTEE_MSG_GET_ARG_SIZE(num_params),
+ TEE_SHM_MAPPED);
+@@ -189,10 +197,6 @@ static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params,
+ goto out;
+ }
+
+- rc = tee_shm_get_pa(shm, 0, msg_parg);
+- if (rc)
+- goto out;
+-
+ memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+ ma->num_params = num_params;
+ *msg_arg = ma;
+@@ -209,15 +213,15 @@ int optee_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param)
+ {
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_context_data *ctxdata = ctx->data;
+- int rc;
+- struct tee_shm *shm;
+- struct optee_msg_arg *msg_arg;
+- phys_addr_t msg_parg;
++ struct optee_msg_arg *msg_arg = NULL;
+ struct optee_session *sess = NULL;
++ struct tee_shm *shm = NULL;
++ int rc = 0;
+
+ /* +2 for the meta parameters added below */
+- shm = get_msg_arg(ctx, arg->num_params + 2, &msg_arg, &msg_parg);
++ shm = get_msg_arg(ctx, arg->num_params + 2, &msg_arg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+@@ -240,7 +244,8 @@ int optee_open_session(struct tee_context *ctx,
+ if (rc)
+ goto out;
+
+- rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param);
++ rc = optee->ops->to_msg_param(optee, msg_arg->params + 2,
++ arg->num_params, param);
+ if (rc)
+ goto out;
+
+@@ -250,7 +255,7 @@ int optee_open_session(struct tee_context *ctx,
+ goto out;
+ }
+
+- if (optee_do_call_with_arg(ctx, msg_parg)) {
++ if (optee->ops->do_call_with_arg(ctx, shm)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+@@ -265,7 +270,8 @@ int optee_open_session(struct tee_context *ctx,
+ kfree(sess);
+ }
+
+- if (optee_from_msg_param(param, arg->num_params, msg_arg->params + 2)) {
++ if (optee->ops->from_msg_param(optee, param, arg->num_params,
++ msg_arg->params + 2)) {
+ arg->ret = TEEC_ERROR_COMMUNICATION;
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+ /* Close session again to avoid leakage */
+@@ -281,12 +287,28 @@ int optee_open_session(struct tee_context *ctx,
+ return rc;
+ }
+
+-int optee_close_session(struct tee_context *ctx, u32 session)
++int optee_close_session_helper(struct tee_context *ctx, u32 session)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ struct optee_msg_arg *msg_arg = NULL;
++ struct tee_shm *shm = NULL;
++
++ shm = get_msg_arg(ctx, 0, &msg_arg);
++ if (IS_ERR(shm))
++ return PTR_ERR(shm);
++
++ msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
++ msg_arg->session = session;
++ optee->ops->do_call_with_arg(ctx, shm);
++
++ tee_shm_free(shm);
++
++ return 0;
++}
++
++static int remove_session(struct tee_context *ctx, u32 session)
+ {
+ struct optee_context_data *ctxdata = ctx->data;
+- struct tee_shm *shm;
+- struct optee_msg_arg *msg_arg;
+- phys_addr_t msg_parg;
+ struct optee_session *sess;
+
+ /* Check that the session is valid and remove it from the list */
+@@ -299,27 +321,28 @@ int optee_close_session(struct tee_context *ctx, u32 session)
+ return -EINVAL;
+ kfree(sess);
+
+- shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg);
+- if (IS_ERR(shm))
+- return PTR_ERR(shm);
++ return 0;
++}
+
+- msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
+- msg_arg->session = session;
+- optee_do_call_with_arg(ctx, msg_parg);
++int optee_close_session(struct tee_context *ctx, u32 session)
++{
++ int rc = remove_session(ctx, session);
+
+- tee_shm_free(shm);
+- return 0;
++ if (rc)
++ return rc;
++
++ return optee_close_session_helper(ctx, session);
+ }
+
+ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param)
+ {
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_context_data *ctxdata = ctx->data;
+- struct tee_shm *shm;
+- struct optee_msg_arg *msg_arg;
+- phys_addr_t msg_parg;
+- struct optee_session *sess;
+- int rc;
++ struct optee_msg_arg *msg_arg = NULL;
++ struct optee_session *sess = NULL;
++ struct tee_shm *shm = NULL;
++ int rc = 0;
+
+ /* Check that the session is valid */
+ mutex_lock(&ctxdata->mutex);
+@@ -328,7 +351,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ if (!sess)
+ return -EINVAL;
+
+- shm = get_msg_arg(ctx, arg->num_params, &msg_arg, &msg_parg);
++ shm = get_msg_arg(ctx, arg->num_params, &msg_arg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+ msg_arg->cmd = OPTEE_MSG_CMD_INVOKE_COMMAND;
+@@ -336,16 +359,18 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ msg_arg->session = arg->session;
+ msg_arg->cancel_id = arg->cancel_id;
+
+- rc = optee_to_msg_param(msg_arg->params, arg->num_params, param);
++ rc = optee->ops->to_msg_param(optee, msg_arg->params, arg->num_params,
++ param);
+ if (rc)
+ goto out;
+
+- if (optee_do_call_with_arg(ctx, msg_parg)) {
++ if (optee->ops->do_call_with_arg(ctx, shm)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+- if (optee_from_msg_param(param, arg->num_params, msg_arg->params)) {
++ if (optee->ops->from_msg_param(optee, param, arg->num_params,
++ msg_arg->params)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+@@ -359,11 +384,11 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+
+ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
+ {
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_context_data *ctxdata = ctx->data;
+- struct tee_shm *shm;
+- struct optee_msg_arg *msg_arg;
+- phys_addr_t msg_parg;
+- struct optee_session *sess;
++ struct optee_msg_arg *msg_arg = NULL;
++ struct optee_session *sess = NULL;
++ struct tee_shm *shm = NULL;
+
+ /* Check that the session is valid */
+ mutex_lock(&ctxdata->mutex);
+@@ -372,14 +397,14 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
+ if (!sess)
+ return -EINVAL;
+
+- shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg);
++ shm = get_msg_arg(ctx, 0, &msg_arg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_CANCEL;
+ msg_arg->session = session;
+ msg_arg->cancel_id = cancel_id;
+- optee_do_call_with_arg(ctx, msg_parg);
++ optee->ops->do_call_with_arg(ctx, shm);
+
+ tee_shm_free(shm);
+ return 0;
+@@ -442,6 +467,16 @@ void optee_disable_shm_cache(struct optee *optee)
+ optee_cq_wait_final(&optee->call_queue, &w);
+ }
+
++/**
++ * optee_ffa_disable_shm_cache() - Disables caching of some shared memory
++ * allocation in OP-TEE
++ * @optee: main service struct
++ */
++void optee_ffa_disable_shm_cache(struct optee *optee)
++{
++ BUG();
++}
++
+ #define PAGELIST_ENTRIES_PER_PAGE \
+ ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
+
+@@ -577,11 +612,11 @@ int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+ struct page **pages, size_t num_pages,
+ unsigned long start)
+ {
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ struct optee_msg_arg *msg_arg = NULL;
+ struct tee_shm *shm_arg = NULL;
+- struct optee_msg_arg *msg_arg;
+- u64 *pages_list;
+- phys_addr_t msg_parg;
+- int rc;
++ u64 *pages_list = NULL;
++ int rc = 0;
+
+ if (!num_pages)
+ return -EINVAL;
+@@ -594,7 +629,7 @@ int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+ if (!pages_list)
+ return -ENOMEM;
+
+- shm_arg = get_msg_arg(ctx, 1, &msg_arg, &msg_parg);
++ shm_arg = get_msg_arg(ctx, 1, &msg_arg);
+ if (IS_ERR(shm_arg)) {
+ rc = PTR_ERR(shm_arg);
+ goto out;
+@@ -615,7 +650,7 @@ int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+ msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) |
+ (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
+
+- if (optee_do_call_with_arg(ctx, msg_parg) ||
++ if (optee->ops->do_call_with_arg(ctx, shm) ||
+ msg_arg->ret != TEEC_SUCCESS)
+ rc = -EINVAL;
+
+@@ -627,12 +662,12 @@ int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+
+ int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
+ {
+- struct tee_shm *shm_arg;
+- struct optee_msg_arg *msg_arg;
+- phys_addr_t msg_parg;
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ struct optee_msg_arg *msg_arg = NULL;
++ struct tee_shm *shm_arg = NULL;
+ int rc = 0;
+
+- shm_arg = get_msg_arg(ctx, 1, &msg_arg, &msg_parg);
++ shm_arg = get_msg_arg(ctx, 1, &msg_arg);
+ if (IS_ERR(shm_arg))
+ return PTR_ERR(shm_arg);
+
+@@ -641,7 +676,7 @@ int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
+ msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
+ msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm;
+
+- if (optee_do_call_with_arg(ctx, msg_parg) ||
++ if (optee->ops->do_call_with_arg(ctx, shm) ||
+ msg_arg->ret != TEEC_SUCCESS)
+ rc = -EINVAL;
+ tee_shm_free(shm_arg);
+@@ -663,3 +698,166 @@ int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm)
+ {
+ return 0;
+ }
++
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++static int optee_ffa_yielding_call(struct tee_context *ctx, u32 w3, u32 w4,
++ u32 w5)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ struct arm_smcccv1_2_return ret = { };
++ const u32 dst = optee->ffa.dst;
++ struct optee_call_waiter w;
++ u32 w6 = 0;
++ u32 w7 = 0;
++ int rc = 0;
++
++ /* Initialize waiter */
++ optee_cq_wait_init(&optee->call_queue, &w);
++ while (true) {
++ ret = optee->ffa.ops->sync_msg_send(dst, w3, w4, w5, w6, w7);
++
++ if (ret.arg0) {
++ pr_err("ret.arg0 %d\n", (int)ret.arg0);
++ rc = -EIO;
++ goto done;
++ }
++
++ switch ((int)ret.arg3) {
++ case FFA_SUCCESS:
++ break;
++ case FFA_BUSY:
++ if (w3 == OPTEE_FFA_YIELDING_CALL_RESUME) {
++ pr_err("err OPTEE_FFA_YIELDING_CALL_RESUME\n");
++ rc = -EIO;
++ goto done;
++ }
++
++ /*
++ * Out of threads in secure world, wait for a thread
++ * become available.
++ */
++ optee_cq_wait_for_completion(&optee->call_queue, &w);
++ continue;
++ default:
++ pr_err("ret.arg3 0x%llx\n", (u64)ret.arg3);
++ rc = -EIO;
++ goto done;
++ }
++
++ if (ret.arg4 == OPTEE_FFA_YIELDING_CALL_RETURN_DONE)
++ goto done;
++
++ might_sleep();
++ w4 = ret.arg4;
++ w5 = ret.arg5;
++ w6 = ret.arg6;
++ optee_handle_ffa_rpc(ctx, &w4, &w5, &w6);
++ w3 = OPTEE_FFA_YIELDING_CALL_RESUME;
++ w7 = ret.arg7;
++ }
++done:
++
++ /*
++ * We're done with our thread in secure world, if there's any
++ * thread waiters wake up one.
++ */
++ optee_cq_wait_final(&optee->call_queue, &w);
++
++ return rc;
++}
++
++int optee_ffa_do_call_with_arg(struct tee_context *ctx, struct tee_shm *shm)
++{
++ if (shm->offset)
++ return -EINVAL;
++ return optee_ffa_yielding_call(ctx, OPTEE_FFA_YIELDING_CALL_WITH_ARG,
++ shm->sec_world_id,
++ shm->sec_world_id >> 32);
++}
++
++int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
++ struct page **pages, size_t num_pages,
++ unsigned long start)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ u64 global_handle = 0;
++ u32 rc = 0;
++ struct sg_table sgt;
++ struct ffa_mem_region_attributes mem_attr = {
++ .receiver = optee->ffa.dst,
++ .attrs = FFA_MEM_RW,
++ };
++
++ rc = check_mem_type(start, num_pages);
++ if (rc)
++ return rc;
++
++ sg_alloc_table_from_pages(&sgt, pages,
++ num_pages, 0,
++ num_pages * 4096, GFP_KERNEL);
++
++ rc = optee->ffa.ops->mem_share(0, 0, &mem_attr, 1, sgt.sgl, sgt.nents,
++ &global_handle, true);
++ if (rc) {
++ if (rc == FFA_NO_MEMORY)
++ return -ENOMEM;
++ return -EINVAL;
++ }
++
++ rc = optee_shm_add_ffa_handle(optee, shm, global_handle);
++ if (rc) {
++ optee->ffa.ops->mem_reclaim(global_handle, 0);
++ return rc;
++ }
++
++ shm->sec_world_id = global_handle;
++
++ return 0;
++}
++
++int optee_ffa_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ u64 global_handle = shm->sec_world_id;
++ int rc = 0;
++
++ optee_shm_rem_ffa_handle(optee, global_handle);
++ shm->sec_world_id = 0;
++
++ rc = optee_ffa_yielding_call(ctx,
++ OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM,
++ global_handle, global_handle >> 32);
++ if (rc)
++ pr_err("OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM id 0x%llx rc %d\n",
++ global_handle, rc);
++
++ rc = optee->ffa.ops->mem_reclaim(global_handle, 0);
++ if (rc)
++ pr_err("mem_reclain: %d", rc);
++
++ return rc;
++}
++
++int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
++ struct tee_shm *shm)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ int rc = 0;
++
++ /*
++ * We're skipping the OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM call
++ * since this is OP-TEE freeing via RPC so it has already retired
++ * this ID.
++ */
++
++ rc = optee->ffa.ops->mem_reclaim(shm->sec_world_id, 0);
++ if (rc)
++ pr_err("mem_reclain: %d", rc);
++
++ optee_shm_rem_ffa_handle(optee, shm->sec_world_id);
++
++ shm->sec_world_id = 0;
++
++ return rc;
++}
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
+diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
+index b830e0a87fba..4178ae7f914a 100644
+--- a/drivers/tee/optee/core.c
++++ b/drivers/tee/optee/core.c
+@@ -6,6 +6,8 @@
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+ #include <linux/arm-smccc.h>
++#include <linux/arm-smcccv1_2.h>
++#include <linux/arm_ffa.h>
+ #include <linux/errno.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
+@@ -19,12 +21,157 @@
+ #include <linux/uaccess.h>
+ #include "optee_private.h"
+ #include "optee_smc.h"
++#include "optee_ffa.h"
+ #include "shm_pool.h"
+
+ #define DRIVER_NAME "optee"
++#define SUPPORTED_OPTEE_PARTITIONS 1
+
+ #define OPTEE_SHM_NUM_PRIV_PAGES CONFIG_OPTEE_SHM_NUM_PRIV_PAGES
+
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++struct shm_rhash {
++ struct tee_shm *shm;
++ u64 global_id;
++ struct rhash_head linkage;
++};
++
++static void rh_free_fn(void *ptr, void *arg)
++{
++ kfree(ptr);
++}
++
++static const struct rhashtable_params shm_rhash_params = {
++ .head_offset = offsetof(struct shm_rhash, linkage),
++ .key_len = sizeof(u64),
++ .key_offset = offsetof(struct shm_rhash, global_id),
++ .automatic_shrinking = true,
++};
++
++struct tee_shm *optee_shm_from_ffa_handle(struct optee *optee, u64 global_id)
++{
++ struct shm_rhash *r = NULL;
++ struct tee_shm *shm = NULL;
++
++ mutex_lock(&optee->ffa.mutex);
++ r = rhashtable_lookup_fast(&optee->ffa.global_ids, &global_id,
++ shm_rhash_params);
++ if (r)
++ shm = r->shm;
++ mutex_unlock(&optee->ffa.mutex);
++
++ return shm;
++}
++
++int optee_shm_add_ffa_handle(struct optee *optee, struct tee_shm *shm,
++ u64 global_id)
++{
++ struct shm_rhash *r = NULL;
++ int rc = 0;
++
++ r = kmalloc(sizeof(*r), GFP_KERNEL);
++ if (!r)
++ return -ENOMEM;
++ r->shm = shm;
++ r->global_id = global_id;
++
++ mutex_lock(&optee->ffa.mutex);
++ rc = rhashtable_lookup_insert_fast(&optee->ffa.global_ids, &r->linkage,
++ shm_rhash_params);
++ mutex_unlock(&optee->ffa.mutex);
++
++ if (rc)
++ kfree(r);
++
++ return rc;
++}
++
++int optee_shm_rem_ffa_handle(struct optee *optee, u64 global_id)
++{
++ struct shm_rhash *r = NULL;
++ int rc = -ENOENT;
++
++ mutex_lock(&optee->ffa.mutex);
++ r = rhashtable_lookup_fast(&optee->ffa.global_ids, &global_id,
++ shm_rhash_params);
++ if (r) {
++ rc = rhashtable_remove_fast(&optee->ffa.global_ids,
++ &r->linkage, shm_rhash_params);
++ if (!rc)
++ kfree(r);
++ }
++ mutex_unlock(&optee->ffa.mutex);
++
++ return rc;
++}
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
++
++static void from_msg_param_value(struct tee_param *p, u32 attr,
++ const struct optee_msg_param *mp)
++{
++ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT +
++ attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
++ p->u.value.a = mp->u.value.a;
++ p->u.value.b = mp->u.value.b;
++ p->u.value.c = mp->u.value.c;
++}
++
++static int from_msg_param_tmp_mem(struct tee_param *p, u32 attr,
++ const struct optee_msg_param *mp)
++{
++ struct tee_shm *shm = NULL;
++ phys_addr_t pa = 0;
++ int rc = 0;
++
++ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
++ attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
++ p->u.memref.size = mp->u.tmem.size;
++ shm = (struct tee_shm *)(unsigned long)mp->u.tmem.shm_ref;
++ if (!shm) {
++ p->u.memref.shm_offs = 0;
++ p->u.memref.shm = NULL;
++ return 0;
++ }
++
++ rc = tee_shm_get_pa(shm, 0, &pa);
++ if (rc)
++ return rc;
++
++ p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
++ p->u.memref.shm = shm;
++
++ /* Check that the memref is covered by the shm object */
++ if (p->u.memref.size) {
++ size_t o = p->u.memref.shm_offs +
++ p->u.memref.size - 1;
++
++ rc = tee_shm_get_pa(shm, o, NULL);
++ if (rc)
++ return rc;
++ }
++
++ return 0;
++}
++
++static void from_msg_param_reg_mem(struct tee_param *p, u32 attr,
++ const struct optee_msg_param *mp)
++{
++ struct tee_shm *shm = NULL;
++
++ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
++ attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
++ p->u.memref.size = mp->u.rmem.size;
++ shm = (struct tee_shm *)(unsigned long) mp->u.rmem.shm_ref;
++
++ if (shm) {
++ p->u.memref.shm_offs = mp->u.rmem.offs;
++ p->u.memref.shm = shm;
++ } else {
++ p->u.memref.shm_offs = 0;
++ p->u.memref.shm = NULL;
++ }
++}
++
+ /**
+ * optee_from_msg_param() - convert from OPTEE_MSG parameters to
+ * struct tee_param
+@@ -33,13 +180,12 @@
+ * @msg_params: OPTEE_MSG parameters
+ * Returns 0 on success or <0 on failure
+ */
+-int optee_from_msg_param(struct tee_param *params, size_t num_params,
+- const struct optee_msg_param *msg_params)
++static int optee_from_msg_param(struct optee *optee, struct tee_param *params,
++ size_t num_params,
++ const struct optee_msg_param *msg_params)
+ {
+- int rc;
+- size_t n;
+- struct tee_shm *shm;
+- phys_addr_t pa;
++ size_t n = 0;
++ int rc = 0;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_param *p = params + n;
+@@ -54,58 +200,19 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params,
+ case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
+- p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT +
+- attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
+- p->u.value.a = mp->u.value.a;
+- p->u.value.b = mp->u.value.b;
+- p->u.value.c = mp->u.value.c;
++ from_msg_param_value(p, attr, mp);
+ break;
+ case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
+- p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
+- attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
+- p->u.memref.size = mp->u.tmem.size;
+- shm = (struct tee_shm *)(unsigned long)
+- mp->u.tmem.shm_ref;
+- if (!shm) {
+- p->u.memref.shm_offs = 0;
+- p->u.memref.shm = NULL;
+- break;
+- }
+- rc = tee_shm_get_pa(shm, 0, &pa);
++ rc = from_msg_param_tmp_mem(p, attr, mp);
+ if (rc)
+ return rc;
+- p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
+- p->u.memref.shm = shm;
+-
+- /* Check that the memref is covered by the shm object */
+- if (p->u.memref.size) {
+- size_t o = p->u.memref.shm_offs +
+- p->u.memref.size - 1;
+-
+- rc = tee_shm_get_pa(shm, o, NULL);
+- if (rc)
+- return rc;
+- }
+ break;
+ case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
+- p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
+- attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
+- p->u.memref.size = mp->u.rmem.size;
+- shm = (struct tee_shm *)(unsigned long)
+- mp->u.rmem.shm_ref;
+-
+- if (!shm) {
+- p->u.memref.shm_offs = 0;
+- p->u.memref.shm = NULL;
+- break;
+- }
+- p->u.memref.shm_offs = mp->u.rmem.offs;
+- p->u.memref.shm = shm;
+-
++ from_msg_param_reg_mem(p, attr, mp);
+ break;
+
+ default:
+@@ -115,11 +222,21 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params,
+ return 0;
+ }
+
++static void to_msg_param_value(struct optee_msg_param *mp,
++ const struct tee_param *p)
++{
++ mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
++ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
++ mp->u.value.a = p->u.value.a;
++ mp->u.value.b = p->u.value.b;
++ mp->u.value.c = p->u.value.c;
++}
++
+ static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
+ const struct tee_param *p)
+ {
+- int rc;
+- phys_addr_t pa;
++ phys_addr_t pa = 0;
++ int rc = 0;
+
+ mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+@@ -162,11 +279,12 @@ static int to_msg_param_reg_mem(struct optee_msg_param *mp,
+ * @params: subsystem itnernal parameter representation
+ * Returns 0 on success or <0 on failure
+ */
+-int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+- const struct tee_param *params)
++static int optee_to_msg_param(struct optee *optee,
++ struct optee_msg_param *msg_params,
++ size_t num_params, const struct tee_param *params)
+ {
+- int rc;
+- size_t n;
++ size_t n = 0;
++ int rc = 0;
+
+ for (n = 0; n < num_params; n++) {
+ const struct tee_param *p = params + n;
+@@ -180,11 +298,7 @@ int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+- mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
+- TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+- mp->u.value.a = p->u.value.a;
+- mp->u.value.b = p->u.value.b;
+- mp->u.value.c = p->u.value.c;
++ to_msg_param_value(mp, p);
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+@@ -203,6 +317,137 @@ int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+ return 0;
+ }
+
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++static void from_msg_param_ffa_mem(struct optee *optee, struct tee_param *p,
++ u32 attr, const struct optee_msg_param *mp)
++{
++ struct tee_shm *shm = NULL;
++ u64 offs_high = 0;
++ u64 offs_low = 0;
++
++ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
++ attr - OPTEE_MSG_ATTR_TYPE_SMEM_INPUT;
++ p->u.memref.size = mp->u.smem.size;
++ shm = optee_shm_from_ffa_handle(optee, mp->u.smem.global_id);
++ p->u.memref.shm = shm;
++ if (shm) {
++ offs_low = mp->u.smem.offs_low;
++ offs_high = mp->u.smem.offs_high;
++ }
++ p->u.memref.shm_offs = offs_low | offs_high << 32;
++}
++
++/**
++ * optee_ffa_from_msg_param() - convert from OPTEE_MSG parameters to
++ * struct tee_param
++ * @params: subsystem internal parameter representation
++ * @num_params: number of elements in the parameter arrays
++ * @msg_params: OPTEE_MSG parameters
++ * Returns 0 on success or <0 on failure
++ */
++static int optee_ffa_from_msg_param(struct optee *optee,
++ struct tee_param *params,
++ size_t num_params,
++ const struct optee_msg_param *msg_params)
++{
++ size_t n = 0;
++
++ for (n = 0; n < num_params; n++) {
++ struct tee_param *p = params + n;
++ const struct optee_msg_param *mp = msg_params + n;
++ u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
++
++ switch (attr) {
++ case OPTEE_MSG_ATTR_TYPE_NONE:
++ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
++ memset(&p->u, 0, sizeof(p->u));
++ break;
++ case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
++ case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
++ case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
++ from_msg_param_value(p, attr, mp);
++ break;
++ case OPTEE_MSG_ATTR_TYPE_SMEM_INPUT:
++ case OPTEE_MSG_ATTR_TYPE_SMEM_OUTPUT:
++ case OPTEE_MSG_ATTR_TYPE_SMEM_INOUT:
++ from_msg_param_ffa_mem(optee, p, attr, mp);
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++ return 0;
++}
++
++static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
++ const struct tee_param *p)
++{
++ struct tee_shm *shm = p->u.memref.shm;
++
++ mp->attr = OPTEE_MSG_ATTR_TYPE_SMEM_INPUT + p->attr -
++ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
++
++ if (shm) {
++ u64 shm_offs = p->u.memref.shm_offs;
++
++ mp->u.smem.internal_offs = shm->offset;
++
++ mp->u.smem.offs_low = shm_offs;
++ mp->u.smem.offs_high = shm_offs >> 32;
++ /* Check that the entire offset could be stored. */
++ if (mp->u.smem.offs_high != shm_offs >> 32)
++ return -EINVAL;
++
++ mp->u.smem.global_id = shm->sec_world_id;
++ } else {
++ memset(&mp->u, 0, sizeof(mp->u));
++ }
++ mp->u.smem.size = p->u.memref.size;
++ return 0;
++}
++
++/**
++ * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
++ * @msg_params: OPTEE_MSG parameters
++ * @num_params: number of elements in the parameter arrays
++ * @params: subsystem itnernal parameter representation
++ * Returns 0 on success or <0 on failure
++ */
++static int optee_ffa_to_msg_param(struct optee *optee,
++ struct optee_msg_param *msg_params,
++ size_t num_params,
++ const struct tee_param *params)
++{
++ size_t n;
++
++ for (n = 0; n < num_params; n++) {
++ const struct tee_param *p = params + n;
++ struct optee_msg_param *mp = msg_params + n;
++
++ switch (p->attr) {
++ case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
++ mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
++ memset(&mp->u, 0, sizeof(mp->u));
++ break;
++ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
++ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
++ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
++ to_msg_param_value(mp, p);
++ break;
++ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
++ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
++ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
++ if (to_msg_param_ffa_mem(mp, p))
++ return -EINVAL;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++ return 0;
++}
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
++
+ static void optee_get_version(struct tee_device *teedev,
+ struct tee_ioctl_version_data *vers)
+ {
+@@ -218,6 +463,17 @@ static void optee_get_version(struct tee_device *teedev,
+ *vers = v;
+ }
+
++static void optee_ffa_get_version(struct tee_device *teedev,
++ struct tee_ioctl_version_data *vers)
++{
++ struct tee_ioctl_version_data v = {
++ .impl_id = TEE_IMPL_ID_OPTEE,
++ .impl_caps = TEE_OPTEE_CAP_TZ,
++ .gen_caps = TEE_GEN_CAP_GP | TEE_GEN_CAP_REG_MEM,
++ };
++ *vers = v;
++}
++
+ static int optee_open(struct tee_context *ctx)
+ {
+ struct optee_context_data *ctxdata;
+@@ -250,57 +506,41 @@ static int optee_open(struct tee_context *ctx)
+ return 0;
+ }
+
+-static void optee_release(struct tee_context *ctx)
++static void optee_release_helper(struct tee_context *ctx,
++ int (*close_session)(struct tee_context *ctx,
++ u32 session))
+ {
+ struct optee_context_data *ctxdata = ctx->data;
+- struct tee_device *teedev = ctx->teedev;
+- struct optee *optee = tee_get_drvdata(teedev);
+- struct tee_shm *shm;
+- struct optee_msg_arg *arg = NULL;
+- phys_addr_t parg;
+ struct optee_session *sess;
+ struct optee_session *sess_tmp;
+
+ if (!ctxdata)
+ return;
+
+- shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED);
+- if (!IS_ERR(shm)) {
+- arg = tee_shm_get_va(shm, 0);
+- /*
+- * If va2pa fails for some reason, we can't call into
+- * secure world, only free the memory. Secure OS will leak
+- * sessions and finally refuse more sessions, but we will
+- * at least let normal world reclaim its memory.
+- */
+- if (!IS_ERR(arg))
+- if (tee_shm_va2pa(shm, arg, &parg))
+- arg = NULL; /* prevent usage of parg below */
+- }
+-
+ list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
+ list_node) {
+ list_del(&sess->list_node);
+- if (!IS_ERR_OR_NULL(arg)) {
+- memset(arg, 0, sizeof(*arg));
+- arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
+- arg->session = sess->session_id;
+- optee_do_call_with_arg(ctx, parg);
+- }
++ close_session(ctx, sess->session_id);
+ kfree(sess);
+ }
+ kfree(ctxdata);
++ ctx->data = NULL;
++}
+
+- if (!IS_ERR(shm))
+- tee_shm_free(shm);
++static void optee_release(struct tee_context *ctx)
++{
++ optee_release_helper(ctx, optee_close_session_helper);
++}
+
+- ctx->data = NULL;
++static void optee_release_supp(struct tee_context *ctx)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
+
+- if (teedev == optee->supp_teedev)
+- optee_supp_release(&optee->supp);
++ optee_release_helper(ctx, optee_close_session_helper);
++ optee_supp_release(&optee->supp);
+ }
+
+-static const struct tee_driver_ops optee_ops = {
++static const struct tee_driver_ops optee_legacy_clnt_ops = {
+ .get_version = optee_get_version,
+ .open = optee_open,
+ .release = optee_release,
+@@ -312,29 +552,36 @@ static const struct tee_driver_ops optee_ops = {
+ .shm_unregister = optee_shm_unregister,
+ };
+
+-static const struct tee_desc optee_desc = {
+- .name = DRIVER_NAME "-clnt",
+- .ops = &optee_ops,
++static const struct tee_desc optee_legacy_clnt_desc = {
++ .name = DRIVER_NAME "legacy-clnt",
++ .ops = &optee_legacy_clnt_ops,
+ .owner = THIS_MODULE,
+ };
+
+-static const struct tee_driver_ops optee_supp_ops = {
++static const struct tee_driver_ops optee_legacy_supp_ops = {
+ .get_version = optee_get_version,
+ .open = optee_open,
+- .release = optee_release,
++ .release = optee_release_supp,
+ .supp_recv = optee_supp_recv,
+ .supp_send = optee_supp_send,
+ .shm_register = optee_shm_register_supp,
+ .shm_unregister = optee_shm_unregister_supp,
+ };
+
+-static const struct tee_desc optee_supp_desc = {
+- .name = DRIVER_NAME "-supp",
+- .ops = &optee_supp_ops,
++static const struct tee_desc optee_legacy_supp_desc = {
++ .name = DRIVER_NAME "legacy-supp",
++ .ops = &optee_legacy_supp_ops,
+ .owner = THIS_MODULE,
+ .flags = TEE_DESC_PRIVILEGED,
+ };
+
++static const struct optee_ops optee_legacy_ops = {
++ .do_call_with_arg = optee_do_call_with_arg,
++ .to_msg_param = optee_to_msg_param,
++ .from_msg_param = optee_from_msg_param,
++};
++
++
+ static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
+ {
+ struct arm_smccc_res res;
+@@ -534,16 +781,9 @@ static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
+ arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+ }
+
+-static optee_invoke_fn *get_invoke_func(struct device_node *np)
++static optee_invoke_fn *get_invoke_func(const char *method)
+ {
+- const char *method;
+
+- pr_info("probing for conduit method from DT.\n");
+-
+- if (of_property_read_string(np, "method", &method)) {
+- pr_warn("missing \"method\" property\n");
+- return ERR_PTR(-ENXIO);
+- }
+
+ if (!strcmp("hvc", method))
+ return optee_smccc_hvc;
+@@ -554,7 +794,7 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np)
+ return ERR_PTR(-EINVAL);
+ }
+
+-static struct optee *optee_probe(struct device_node *np)
++static struct optee *optee_probe_legacy(const char *method)
+ {
+ optee_invoke_fn *invoke_fn;
+ struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
+@@ -564,7 +804,7 @@ static struct optee *optee_probe(struct device_node *np)
+ u32 sec_caps;
+ int rc;
+
+- invoke_fn = get_invoke_func(np);
++ invoke_fn = get_invoke_func(method);
+ if (IS_ERR(invoke_fn))
+ return (void *)invoke_fn;
+
+@@ -606,17 +846,18 @@ static struct optee *optee_probe(struct device_node *np)
+ goto err;
+ }
+
++ optee->ops = &optee_legacy_ops;
+ optee->invoke_fn = invoke_fn;
+ optee->sec_caps = sec_caps;
+
+- teedev = tee_device_alloc(&optee_desc, NULL, pool, optee);
++ teedev = tee_device_alloc(&optee_legacy_clnt_desc, NULL, pool, optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+ goto err;
+ }
+ optee->teedev = teedev;
+
+- teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
++ teedev = tee_device_alloc(&optee_legacy_supp_desc, NULL, pool, optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+ goto err;
+@@ -662,6 +903,266 @@ static struct optee *optee_probe(struct device_node *np)
+ return ERR_PTR(rc);
+ }
+
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++static bool optee_ffa_api_is_compatbile(struct ffa_ops *ffa_ops, u32 dst)
++{
++ struct arm_smcccv1_2_return ret = { };
++
++ ret = ffa_ops->sync_msg_send(dst, OPTEE_FFA_GET_API_VERSION,
++ 0, 0, 0, 0);
++ if (ret.arg0 != FFA_SUCCESS) {
++ pr_err("Unexpected return fid 0x%llx", ret.arg0);
++ return false;
++ }
++ if (ret.arg3 != OPTEE_FFA_VERSION_MAJOR ||
++ ret.arg4 < OPTEE_FFA_VERSION_MINOR) {
++ pr_err("Incompatible OP-TEE API version %llu.%llu",
++ ret.arg3, ret.arg4);
++ return false;
++ }
++
++ ret = ffa_ops->sync_msg_send(dst, OPTEE_FFA_GET_OS_VERSION,
++ 0, 0, 0, 0);
++ if (ret.arg0) {
++ pr_err("Unexpected error 0x%llx", ret.arg0);
++ return false;
++ }
++ if (ret.arg5)
++ pr_info("revision %llu.%llu (%08llx)",
++ ret.arg3, ret.arg4, ret.arg5);
++ else
++ pr_info("revision %llu.%llu", ret.arg3, ret.arg4);
++
++ return true;
++}
++
++static bool optee_ffa_exchange_caps(struct ffa_ops *ffa_ops, u32 dst,
++ u32 *sec_caps)
++{
++ struct arm_smcccv1_2_return ret = { };
++
++ ret = ffa_ops->sync_msg_send(dst, OPTEE_FFA_EXCHANGE_CAPABILITIES,
++ 0, 0, 0, 0);
++ if (ret.arg0) {
++ pr_err("Unexpected error 0x%llx", ret.arg0);
++ return false;
++ }
++
++ *sec_caps = 0;
++
++ return true;
++}
++
++static struct tee_shm_pool *optee_ffa_config_dyn_shm(void)
++{
++ struct tee_shm_pool_mgr *priv_mgr;
++ struct tee_shm_pool_mgr *dmabuf_mgr;
++ void *rc;
++
++ rc = optee_ffa_shm_pool_alloc_pages();
++ if (IS_ERR(rc))
++ return rc;
++ priv_mgr = rc;
++
++ rc = optee_ffa_shm_pool_alloc_pages();
++ if (IS_ERR(rc)) {
++ tee_shm_pool_mgr_destroy(priv_mgr);
++ return rc;
++ }
++ dmabuf_mgr = rc;
++
++ rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
++ if (IS_ERR(rc)) {
++ tee_shm_pool_mgr_destroy(priv_mgr);
++ tee_shm_pool_mgr_destroy(dmabuf_mgr);
++ }
++
++ return rc;
++}
++
++static const struct tee_driver_ops optee_ffa_clnt_ops = {
++ .get_version = optee_ffa_get_version,
++ .open = optee_open,
++ .release = optee_release,
++ .open_session = optee_open_session,
++ .close_session = optee_close_session,
++ .invoke_func = optee_invoke_func,
++ .cancel_req = optee_cancel_req,
++ .shm_register = optee_ffa_shm_register,
++ .shm_unregister = optee_ffa_shm_unregister,
++};
++
++static const struct tee_desc optee_ffa_clnt_desc = {
++ .name = DRIVER_NAME "ffa-clnt",
++ .ops = &optee_ffa_clnt_ops,
++ .owner = THIS_MODULE,
++};
++
++static const struct tee_driver_ops optee_ffa_supp_ops = {
++ .get_version = optee_ffa_get_version,
++ .open = optee_open,
++ .release = optee_release_supp,
++ .supp_recv = optee_supp_recv,
++ .supp_send = optee_supp_send,
++ .shm_register = optee_ffa_shm_register, /* same as for clnt ops */
++ .shm_unregister = optee_ffa_shm_unregister_supp,
++};
++
++static const struct tee_desc optee_ffa_supp_desc = {
++ .name = DRIVER_NAME "ffa-supp",
++ .ops = &optee_ffa_supp_ops,
++ .owner = THIS_MODULE,
++ .flags = TEE_DESC_PRIVILEGED,
++};
++
++static const struct optee_ops optee_ffa_ops = {
++ .do_call_with_arg = optee_ffa_do_call_with_arg,
++ .to_msg_param = optee_ffa_to_msg_param,
++ .from_msg_param = optee_ffa_from_msg_param,
++};
++
++static struct optee *optee_probe_ffa(void)
++{
++ struct tee_device *teedev = NULL;
++ struct ffa_ops *ffa_ops = NULL;
++ struct optee *optee = NULL;
++ struct ffa_partition_info *partition_info = NULL;
++ u32 ffa_dst = 0;
++ u32 sec_caps = 0;
++ int count = 0;
++ int rc = 0;
++
++ ffa_ops = get_ffa_ops();
++ if (!ffa_ops) {
++ pr_warn("failed \"method\" init: ffa\n");
++ return ERR_PTR(-ENOENT);
++ }
++ /* Use OPTEE UUID to retrieve partition ID. */
++ count = ffa_ops->partition_info_get(OPTEE_MSG_OS_OPTEE_UUID_0,
++ OPTEE_MSG_OS_OPTEE_UUID_1,
++ OPTEE_MSG_OS_OPTEE_UUID_2,
++ OPTEE_MSG_OS_OPTEE_UUID_3,
++ &partition_info);
++
++ /* If count is negative propergate the error code. */
++ if (count < 0) {
++ return ERR_PTR(count);
++ }
++ /*
++ * If the function returned sucessfully we must ensure to free the
++ * allocated memory before exiting.
++ */
++
++ /* Check only a single patition is found.*/
++ /* TODO: Add support for dealing with multiple partitions. */
++ if (count > SUPPORTED_OPTEE_PARTITIONS) {
++ kfree(partition_info);
++ return ERR_PTR(-EINVAL);
++ }
++ ffa_dst = partition_info[0].id;
++ kfree(partition_info);
++
++ if (!optee_ffa_api_is_compatbile(ffa_ops, ffa_dst))
++ return ERR_PTR(-EINVAL);
++
++ if (!optee_ffa_exchange_caps(ffa_ops, ffa_dst, &sec_caps))
++ return ERR_PTR(-EINVAL);
++
++ optee = kzalloc(sizeof(*optee), GFP_KERNEL);
++ if (!optee) {
++ rc = -ENOMEM;
++ goto err;
++ }
++ optee->pool = optee_ffa_config_dyn_shm();
++ if (IS_ERR(optee->pool)) {
++ rc = PTR_ERR(optee->pool);
++ optee->pool = NULL;
++ goto err;
++ }
++
++ optee->ops = &optee_ffa_ops;
++ optee->ffa.ops = ffa_ops;
++ optee->ffa.dst = ffa_dst;
++ optee->sec_caps = sec_caps;
++
++ teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool,
++ optee);
++ if (IS_ERR(teedev)) {
++ rc = PTR_ERR(teedev);
++ goto err;
++ }
++ optee->teedev = teedev;
++
++ teedev = tee_device_alloc(&optee_ffa_supp_desc, NULL, optee->pool,
++ optee);
++ if (IS_ERR(teedev)) {
++ rc = PTR_ERR(teedev);
++ goto err;
++ }
++ optee->supp_teedev = teedev;
++
++ rc = tee_device_register(optee->teedev);
++ if (rc)
++ goto err;
++
++ rc = tee_device_register(optee->supp_teedev);
++ if (rc)
++ goto err;
++
++ rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params);
++ if (rc)
++ goto err;
++ mutex_init(&optee->ffa.mutex);
++ mutex_init(&optee->call_queue.mutex);
++ INIT_LIST_HEAD(&optee->call_queue.waiters);
++ optee_wait_queue_init(&optee->wait_queue);
++ optee_supp_init(&optee->supp);
++
++ return optee;
++err:
++ /*
++ * tee_device_unregister() is safe to call even if the
++ * devices hasn't been registered with
++ * tee_device_register() yet.
++ */
++ tee_device_unregister(optee->supp_teedev);
++ tee_device_unregister(optee->teedev);
++ if (optee->pool)
++ tee_shm_pool_free(optee->pool);
++ kfree(optee);
++ return ERR_PTR(rc);
++}
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
++
++static const char *get_conduit_method(struct device_node *np)
++{
++ const char *method = NULL;
++
++ pr_info("probing for conduit method from DT.\n");
++
++ if (of_property_read_string(np, "method", &method)) {
++ pr_warn("missing \"method\" property\n");
++ return NULL;
++ }
++
++ return method;
++}
++
++static struct optee *optee_probe(struct device_node *np)
++{
++ const char *method = get_conduit_method(np);
++
++ if (!method)
++ return ERR_PTR(-ENXIO);
++
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++ if (!strcmp(method, "ffa"))
++ return optee_probe_ffa();
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
++
++ return optee_probe_legacy(method);
++}
++
+ static void optee_remove(struct optee *optee)
+ {
+ /*
+@@ -669,7 +1170,10 @@ static void optee_remove(struct optee *optee)
+ * reference counters and also avoid wild pointers in secure world
+ * into the old shared memory range.
+ */
+- optee_disable_shm_cache(optee);
++ if (optee->invoke_fn)
++ optee_disable_shm_cache(optee);
++ else
++ optee_ffa_disable_shm_cache(optee);
+
+ /*
+ * The two devices has to be unregistered before we can free the
+@@ -684,6 +1188,13 @@ static void optee_remove(struct optee *optee)
+ optee_wait_queue_exit(&optee->wait_queue);
+ optee_supp_uninit(&optee->supp);
+ mutex_destroy(&optee->call_queue.mutex);
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++ if (optee->ffa.ops) {
++ mutex_destroy(&optee->ffa.mutex);
++ rhashtable_free_and_destroy(&optee->ffa.global_ids,
++ rh_free_fn, NULL);
++ }
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
+
+ kfree(optee);
+ }
+diff --git a/drivers/tee/optee/optee_ffa.h b/drivers/tee/optee/optee_ffa.h
+new file mode 100644
+index 000000000000..768e056ab491
+--- /dev/null
++++ b/drivers/tee/optee/optee_ffa.h
+@@ -0,0 +1,201 @@
++/* SPDX-License-Identifier: BSD-2-Clause */
++/*
++ * Copyright (c) 2019, Linaro Limited
++ */
++
++/*
++ * This file is exported by OP-TEE and is in kept in sync between secure
++ * world and normal world kernel driver. We're using ARM FF-A 1.0 EAC
++ * specification.
++ */
++
++#ifndef __OPTEE_FFA_H
++#define __OPTEE_FFA_H
++
++#include <linux/arm_ffa.h>
++
++/*
++ * Normal world sends requests with FFA_MSG_SEND_DIRECT_REQ and
++ * responses are returned with FFA_MSG_SEND_DIRECT_RESP for normal
++ * messages.
++ *
++ * All requests with FFA_MSG_SEND_DIRECT_REQ and FFA_MSG_SEND_DIRECT_RESP
++ * are using the AArch32 SMC calling convention with register usage as
++ * defined in FF-A specification:
++ * w0: Function ID (0x8400006F or 0x84000070)
++ * w1: Source/Destination IDs
++ * w2: Reserved (MBZ)
++ * w3-w7: Implementation defined, free to be used below
++ */
++
++#define OPTEE_FFA_VERSION_MAJOR 1
++#define OPTEE_FFA_VERSION_MINOR 0
++
++#define OPTEE_FFA_BLOCKING_CALL(id) (id)
++#define OPTEE_FFA_YIELDING_CALL_BIT 31
++#define OPTEE_FFA_YIELDING_CALL(id) ((id) | BIT(OPTEE_FFA_YIELDING_CALL_BIT))
++
++/*
++ * Returns the API version implemented, currently follows the FF-A version.
++ * Call register usage:
++ * w3: Service ID, OPTEE_FFA_GET_API_VERSION
++ * w4-w7: Not used (MBZ)
++ *
++ * Return register usage:
++ * w3: OPTEE_FFA_VERSION_MAJOR
++ * w4: OPTEE_FFA_VERSION_MINOR
++ * w5-w7: Not used (MBZ)
++ */
++#define OPTEE_FFA_GET_API_VERSION OPTEE_FFA_BLOCKING_CALL(0)
++
++/*
++ * Returns the revision of OP-TEE.
++ *
++ * Used by non-secure world to figure out which version of the Trusted OS
++ * is installed. Note that the returned revision is the revision of the
++ * Trusted OS, not of the API.
++ *
++ * Call register usage:
++ * w3: Service ID, OPTEE_FFA_GET_OS_VERSION
++ * w4-w7: Unused (MBZ)
++ *
++ * Return register usage:
++ * w3: CFG_OPTEE_REVISION_MAJOR
++ * w4: CFG_OPTEE_REVISION_MINOR
++ * w5: TEE_IMPL_GIT_SHA1 (or zero if not supported)
++ */
++#define OPTEE_FFA_GET_OS_VERSION OPTEE_FFA_BLOCKING_CALL(1)
++
++/*
++ * Exchange capabilities between normal world and secure world.
++ *
++ * Currently there are no defined capabilities. When features are added new
++ * capabilities may be added.
++ *
++ * Call register usage:
++ * w3: Service ID, OPTEE_FFA_EXCHANGE_CAPABILITIES
++ * w4-w7: Note used (MBZ)
++ *
++ * Return register usage:
++ * w3: Error code, 0 on success
++ * w4: Bit[1:0]: Number of pages of shared memory to register with
++ * OPTEE_FFA_REGISTER_RPC_SHM to support RPC
++ * Bit[31:2]: Reserved (MBZ)
++ * w5-w7: Note used (MBZ)
++ */
++#define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2)
++
++/*
++ * Call with struct optee_msg_arg as argument in the supplied shared memory
++ * with a zero internal offset and normal cached memory attributes.
++ * Register usage:
++ * w3: Service ID, OPTEE_FFA_YIELDING_CALL_WITH_ARG
++ * w4: Shared memory handle, lower bits
++ * w5: Shared memory handle, higher bits
++ * w6: Offset into shared memory pointing to a struct optee_msg_arg
++ * w7: Not used (MBZ)
++ *
++ * Call to register shared memory memory. The data is supplied in shared
++ * memory with a zero internal offset and normal cached memory attributes.
++ * The data is formatted as described in FFA 1.0 Beta1 Table 137 "
++ * Descriptor to retrieve a donated, lent or shared memory region".
++ * Register usage:
++ * w3: Service ID, OPTEE_FFA_YIELDING_CALL_REGISTER_SHM
++ * w4: Shared memory handle, lower bits
++ * w5: Shared memory handle, higher bits
++ * w6-w7: Not used (MBZ)
++ *
++ * Call unregister shared memory register usage:
++ * w3: Service ID, OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM
++ * w4: Shared memory handle, lower bits
++ * w5: Shared memory handle, higher bits
++ * w6-w7: Not used (MBZ)
++ *
++ * Resume from RPC register usage:
++ * w3: Service ID, OPTEE_FFA_YIELDING_CALL_RESUME
++ * If returning from OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_SHM:
++ * w4: Shared memory handle, lower bits
++ * w5: Shared memory handle, higher bits
++ * If the allocation failed both w4 and w5 are 0
++ * w6: Offset into shared memory pointing the table If internal
++ * offset > 0 then one more page than requested has been allocated.
++ * else if resuming from another RPC:
++ * w4-w6: Not used (MBZ)
++ * w7: Resume info
++ *
++ * Normal return (yielding call is completed) register usage:
++ * w3: Error code, 0 on success
++ * w4: OPTEE_FFA_YIELDING_CALL_RETURN_DONE
++ * w5-w7: Not used (MBZ)
++ *
++ * Alloc SHM return (RPC from secure world) register usage:
++ * w3: Error code == 0
++ * w4: OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_KERN_SHM or
++ * OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_SUPPL_SHM
++ * allocate kernel private or supplicant memory respectively.
++ * w5: Number of pages of shared memory
++ * w6: Not used (MBZ)
++ * w7: Resume info
++ *
++ * Free SHM return (RPC from secure world) register usage:
++ * w3: Error code == 0
++ * w4: OPTEE_FFA_YIELDING_CALL_RETURN_FREE_KERN_SHM or
++ * OPTEE_FFA_YIELDING_CALL_RETURN_FREE_SUPPL_SHM
++ * free kernel private or supplicant memory respectively.
++ * w5 Shared memory handle to free, lower bits
++ * w6 Shared memory handle to free, higher bits
++ * The handle previously allocated with
++ * OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_KERN_SHM or
++ * OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_SUPPL_SHM.
++ * w7: Resume info
++ *
++ * RPC cmd return (RPC from secure world) register usage:
++ * w3: Error code == 0
++ * w4: OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD
++ * w5: Shared memory handle, lower bits
++ * w6: Shared memory handle, higher bits
++ * The handle contains aed the RPC.
++ * w7: Resume info
++ *
++ * RPC interrupt return (RPC from secure world) register usage:
++ * w3: Error code == 0
++ * w4: OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT
++ * w5-w6: Not used (MBZ)
++ * w7: Resume info
++ *
++ * Possible error codes in register w3:
++ * 0: Success
++ * FFA_DENIED: w4 isn't one of OPTEE_FFA_YIELDING_CALL_START
++ * OPTEE_FFA_YIELDING_CALL_REGISTER_SHM,
++ * OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM or
++ * OPTEE_FFA_YIELDING_CALL_RESUME
++ *
++ * Possible error codes for OPTEE_FFA_YIELDING_CALL_START,
++ * OPTEE_FFA_YIELDING_CALL_REGISTER_SHM and
++ * OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM
++ * FFA_BUSY: Number of OP-TEE OS threads exceeded,
++ * try again later
++ * FFA_DENIED: RPC shared memory object not found
++ * FFA_INVALID_PARAMETER: Bad shared memory handle or offset into the memory
++ *
++ * Possible error codes for OPTEE_FFA_YIELDING_CALL_RESUME
++ * FFA_INVALID_PARAMETER: Bad resume info
++ *
++ */
++#define OPTEE_FFA_YIELDING_CALL_WITH_ARG OPTEE_FFA_YIELDING_CALL(0)
++#define OPTEE_FFA_YIELDING_CALL_REGISTER_SHM OPTEE_FFA_YIELDING_CALL(1)
++#define OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM OPTEE_FFA_YIELDING_CALL(2)
++#define OPTEE_FFA_YIELDING_CALL_RESUME OPTEE_FFA_YIELDING_CALL(3)
++
++#define OPTEE_FFA_YIELDING_CALL_RETURN_DONE 0
++#define OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_KERN_SHM 1
++#define OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_SUPPL_SHM 2
++#define OPTEE_FFA_YIELDING_CALL_RETURN_RESERVED0 3
++#define OPTEE_FFA_YIELDING_CALL_RETURN_FREE_KERN_SHM 4
++#define OPTEE_FFA_YIELDING_CALL_RETURN_FREE_SUPPL_SHM 5
++#define OPTEE_FFA_YIELDING_CALL_RETURN_RESERVED1 6
++#define OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD 7
++#define OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT 8
++
++#endif /*__OPTEE_FFA_H*/
++
+diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
+index 795bc19ae17a..95ee82c11733 100644
+--- a/drivers/tee/optee/optee_msg.h
++++ b/drivers/tee/optee/optee_msg.h
+@@ -1,6 +1,5 @@
+-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
+ /*
+- * Copyright (c) 2015-2019, Linaro Limited
++ * Copyright (c) 2015-2020, Linaro Limited
+ */
+ #ifndef _OPTEE_MSG_H
+ #define _OPTEE_MSG_H
+@@ -11,12 +10,6 @@
+ /*
+ * This file defines the OP-TEE message protocol used to communicate
+ * with an instance of OP-TEE running in secure world.
+- *
+- * This file is divided into three sections.
+- * 1. Formatting of messages.
+- * 2. Requests from normal world
+- * 3. Requests from secure world, Remote Procedure Call (RPC), handled by
+- * tee-supplicant.
+ */
+
+ /*****************************************************************************
+@@ -30,6 +23,9 @@
+ #define OPTEE_MSG_ATTR_TYPE_RMEM_INPUT 0x5
+ #define OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT 0x6
+ #define OPTEE_MSG_ATTR_TYPE_RMEM_INOUT 0x7
++#define OPTEE_MSG_ATTR_TYPE_SMEM_INPUT OPTEE_MSG_ATTR_TYPE_RMEM_INPUT
++#define OPTEE_MSG_ATTR_TYPE_SMEM_OUTPUT OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT
++#define OPTEE_MSG_ATTR_TYPE_SMEM_INOUT OPTEE_MSG_ATTR_TYPE_RMEM_INOUT
+ #define OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 0x9
+ #define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa
+ #define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb
+@@ -54,14 +50,14 @@
+ * Every entry in buffer should point to a 4k page beginning (12 least
+ * significant bits must be equal to zero).
+ *
+- * 12 least significant bints of optee_msg_param.u.tmem.buf_ptr should hold page
+- * offset of the user buffer.
++ * 12 least significant bits of optee_msg_param.u.tmem.buf_ptr should hold
++ * page offset of user buffer.
+ *
+ * So, entries should be placed like members of this structure:
+ *
+ * struct page_data {
+- * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
+- * uint64_t next_page_data;
++ * u64 pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(u64) - 1];
++ * u64 next_page_data;
+ * };
+ *
+ * Structure is designed to exactly fit into the page size
+@@ -129,6 +125,23 @@ struct optee_msg_param_rmem {
+ u64 shm_ref;
+ };
+
++/**
++ * struct optee_msg_param_smem - ffa memory reference parameter
++ * @offs_lower: Lower bits of offset into shared memory reference
++ * @offs_upper: Upper bits of offset into shared memory reference
++ * @internal_offs: Internal offset into the first page of shared memory
++ * reference
++ * @size: Size of the buffer
++ * @global_id: Global identifier of Shared memory
++ */
++struct optee_msg_param_smem {
++ u32 offs_low;
++ u16 offs_high;
++ u16 internal_offs;
++ u64 size;
++ u64 global_id;
++};
++
+ /**
+ * struct optee_msg_param_value - opaque value parameter
+ *
+@@ -145,12 +158,14 @@ struct optee_msg_param_value {
+ * @attr: attributes
+ * @tmem: parameter by temporary memory reference
+ * @rmem: parameter by registered memory reference
++ * @smem: parameter by ffa registered memory reference
+ * @value: parameter by opaque value
+ *
+ * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in
+ * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value,
+ * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates @tmem and
+- * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates @rmem,
++ * OPTEE_MSG_ATTR_TYPE_RMEM_* or the alias PTEE_MSG_ATTR_TYPE_SMEM_* indicates
++ * @rmem or @smem depending on the conduit.
+ * OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used.
+ */
+ struct optee_msg_param {
+@@ -158,6 +173,7 @@ struct optee_msg_param {
+ union {
+ struct optee_msg_param_tmem tmem;
+ struct optee_msg_param_rmem rmem;
++ struct optee_msg_param_smem smem;
+ struct optee_msg_param_value value;
+ } u;
+ };
+@@ -176,17 +192,9 @@ struct optee_msg_param {
+ * @params: the parameters supplied to the OS Command
+ *
+ * All normal calls to Trusted OS uses this struct. If cmd requires further
+- * information than what these field holds it can be passed as a parameter
++ * information than what these fields hold it can be passed as a parameter
+ * tagged as meta (setting the OPTEE_MSG_ATTR_META bit in corresponding
+- * attrs field). All parameters tagged as meta has to come first.
+- *
+- * Temp memref parameters can be fragmented if supported by the Trusted OS
+- * (when optee_smc.h is bearer of this protocol this is indicated with
+- * OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM). If a logical memref parameter is
+- * fragmented then has all but the last fragment the
+- * OPTEE_MSG_ATTR_FRAGMENT bit set in attrs. Even if a memref is fragmented
+- * it will still be presented as a single logical memref to the Trusted
+- * Application.
++ * attrs field). All parameters tagged as meta have to come first.
+ */
+ struct optee_msg_arg {
+ u32 cmd;
+@@ -199,7 +207,7 @@ struct optee_msg_arg {
+ u32 num_params;
+
+ /* num_params tells the actual number of element in params */
+- struct optee_msg_param params[0];
++ struct optee_msg_param params[];
+ };
+
+ /**
+@@ -290,13 +298,10 @@ struct optee_msg_arg {
+ * OPTEE_MSG_CMD_REGISTER_SHM registers a shared memory reference. The
+ * information is passed as:
+ * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_TMEM_INPUT
+- * [| OPTEE_MSG_ATTR_FRAGMENT]
++ * [| OPTEE_MSG_ATTR_NONCONTIG]
+ * [in] param[0].u.tmem.buf_ptr physical address (of first fragment)
+ * [in] param[0].u.tmem.size size (of first fragment)
+ * [in] param[0].u.tmem.shm_ref holds shared memory reference
+- * ...
+- * The shared memory can optionally be fragmented, temp memrefs can follow
+- * each other with all but the last with the OPTEE_MSG_ATTR_FRAGMENT bit set.
+ *
+ * OPTEE_MSG_CMD_UNREGISTER_SHM unregisteres a previously registered shared
+ * memory reference. The information is passed as:
+@@ -313,110 +318,4 @@ struct optee_msg_arg {
+ #define OPTEE_MSG_CMD_UNREGISTER_SHM 5
+ #define OPTEE_MSG_FUNCID_CALL_WITH_ARG 0x0004
+
+-/*****************************************************************************
+- * Part 3 - Requests from secure world, RPC
+- *****************************************************************************/
+-
+-/*
+- * All RPC is done with a struct optee_msg_arg as bearer of information,
+- * struct optee_msg_arg::arg holds values defined by OPTEE_MSG_RPC_CMD_* below
+- *
+- * RPC communication with tee-supplicant is reversed compared to normal
+- * client communication desribed above. The supplicant receives requests
+- * and sends responses.
+- */
+-
+-/*
+- * Load a TA into memory, defined in tee-supplicant
+- */
+-#define OPTEE_MSG_RPC_CMD_LOAD_TA 0
+-
+-/*
+- * Reserved
+- */
+-#define OPTEE_MSG_RPC_CMD_RPMB 1
+-
+-/*
+- * File system access, defined in tee-supplicant
+- */
+-#define OPTEE_MSG_RPC_CMD_FS 2
+-
+-/*
+- * Get time
+- *
+- * Returns number of seconds and nano seconds since the Epoch,
+- * 1970-01-01 00:00:00 +0000 (UTC).
+- *
+- * [out] param[0].u.value.a Number of seconds
+- * [out] param[0].u.value.b Number of nano seconds.
+- */
+-#define OPTEE_MSG_RPC_CMD_GET_TIME 3
+-
+-/*
+- * Wait queue primitive, helper for secure world to implement a wait queue.
+- *
+- * If secure world need to wait for a secure world mutex it issues a sleep
+- * request instead of spinning in secure world. Conversely is a wakeup
+- * request issued when a secure world mutex with a thread waiting thread is
+- * unlocked.
+- *
+- * Waiting on a key
+- * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP
+- * [in] param[0].u.value.b wait key
+- *
+- * Waking up a key
+- * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP
+- * [in] param[0].u.value.b wakeup key
+- */
+-#define OPTEE_MSG_RPC_CMD_WAIT_QUEUE 4
+-#define OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP 0
+-#define OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP 1
+-
+-/*
+- * Suspend execution
+- *
+- * [in] param[0].value .a number of milliseconds to suspend
+- */
+-#define OPTEE_MSG_RPC_CMD_SUSPEND 5
+-
+-/*
+- * Allocate a piece of shared memory
+- *
+- * Shared memory can optionally be fragmented, to support that additional
+- * spare param entries are allocated to make room for eventual fragments.
+- * The spare param entries has .attr = OPTEE_MSG_ATTR_TYPE_NONE when
+- * unused. All returned temp memrefs except the last should have the
+- * OPTEE_MSG_ATTR_FRAGMENT bit set in the attr field.
+- *
+- * [in] param[0].u.value.a type of memory one of
+- * OPTEE_MSG_RPC_SHM_TYPE_* below
+- * [in] param[0].u.value.b requested size
+- * [in] param[0].u.value.c required alignment
+- *
+- * [out] param[0].u.tmem.buf_ptr physical address (of first fragment)
+- * [out] param[0].u.tmem.size size (of first fragment)
+- * [out] param[0].u.tmem.shm_ref shared memory reference
+- * ...
+- * [out] param[n].u.tmem.buf_ptr physical address
+- * [out] param[n].u.tmem.size size
+- * [out] param[n].u.tmem.shm_ref shared memory reference (same value
+- * as in param[n-1].u.tmem.shm_ref)
+- */
+-#define OPTEE_MSG_RPC_CMD_SHM_ALLOC 6
+-/* Memory that can be shared with a non-secure user space application */
+-#define OPTEE_MSG_RPC_SHM_TYPE_APPL 0
+-/* Memory only shared with non-secure kernel */
+-#define OPTEE_MSG_RPC_SHM_TYPE_KERNEL 1
+-
+-/*
+- * Free shared memory previously allocated with OPTEE_MSG_RPC_CMD_SHM_ALLOC
+- *
+- * [in] param[0].u.value.a type of memory one of
+- * OPTEE_MSG_RPC_SHM_TYPE_* above
+- * [in] param[0].u.value.b value of shared memory reference
+- * returned in param[0].u.tmem.shm_ref
+- * above
+- */
+-#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+-
+ #endif /* _OPTEE_MSG_H */
+diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
+index d9c5037b4e03..d12d9b9f6d33 100644
+--- a/drivers/tee/optee/optee_private.h
++++ b/drivers/tee/optee/optee_private.h
+@@ -7,6 +7,7 @@
+ #define OPTEE_PRIVATE_H
+
+ #include <linux/arm-smccc.h>
++#include <linux/rhashtable.h>
+ #include <linux/semaphore.h>
+ #include <linux/tee_drv.h>
+ #include <linux/types.h>
+@@ -17,6 +18,7 @@
+ /* Some Global Platform error codes used in this driver */
+ #define TEEC_SUCCESS 0x00000000
+ #define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
++#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A
+ #define TEEC_ERROR_COMMUNICATION 0xFFFF000E
+ #define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
+ #define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
+@@ -65,6 +67,32 @@ struct optee_supp {
+ struct completion reqs_c;
+ };
+
++/**
++ * struct optee_ffa_data - FFA communication struct
++ * @dst FFA destination id, the id of OP-TEE in secure world
++ * @ops FFA operations
++ * @mutex Serializes access to @global_ids
++ * @global_ids FF-A shared memory global handle translation
++ */
++struct optee_ffa {
++ u32 dst;
++ struct ffa_ops *ops;
++ struct mutex mutex;
++ struct rhashtable global_ids;
++};
++
++struct optee;
++struct optee_ops {
++ int (*do_call_with_arg)(struct tee_context *ctx,
++ struct tee_shm *shm_arg);
++ int (*to_msg_param)(struct optee *optee,
++ struct optee_msg_param *msg_params,
++ size_t num_params, const struct tee_param *params);
++ int (*from_msg_param)(struct optee *optee, struct tee_param *params,
++ size_t num_params,
++ const struct optee_msg_param *msg_params);
++};
++
+ /**
+ * struct optee - main service struct
+ * @supp_teedev: supplicant device
+@@ -82,7 +110,11 @@ struct optee_supp {
+ struct optee {
+ struct tee_device *supp_teedev;
+ struct tee_device *teedev;
++ const struct optee_ops *ops;
+ optee_invoke_fn *invoke_fn;
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++ struct optee_ffa ffa;
++#endif
+ struct optee_call_queue call_queue;
+ struct optee_wait_queue wait_queue;
+ struct optee_supp supp;
+@@ -141,10 +173,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
+ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param);
+
+-u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg);
++int optee_do_call_with_arg(struct tee_context *ctx, struct tee_shm *arg);
+ int optee_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param);
++int optee_close_session_helper(struct tee_context *ctx, u32 session);
+ int optee_close_session(struct tee_context *ctx, u32 session);
+ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param);
+@@ -163,11 +196,6 @@ int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
+ unsigned long start);
+ int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm);
+
+-int optee_from_msg_param(struct tee_param *params, size_t num_params,
+- const struct optee_msg_param *msg_params);
+-int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+- const struct tee_param *params);
+-
+ u64 *optee_allocate_pages_list(size_t num_entries);
+ void optee_free_pages_list(void *array, size_t num_entries);
+ void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
+@@ -175,6 +203,27 @@ void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
+
+ int optee_enumerate_devices(void);
+
++int optee_shm_add_ffa_handle(struct optee *optee, struct tee_shm *shm,
++ u64 global_id);
++int optee_shm_rem_ffa_handle(struct optee *optee, u64 global_id);
++
++struct tee_shm *optee_shm_from_ffa_handle(struct optee *optee, u64 global_id);
++void optee_ffa_disable_shm_cache(struct optee *optee);
++
++int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
++ struct page **pages, size_t num_pages,
++ unsigned long start);
++int optee_ffa_shm_unregister(struct tee_context *ctx, struct tee_shm *shm);
++int optee_ffa_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
++ struct page **pages, size_t num_pages,
++ unsigned long start);
++int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
++ struct tee_shm *shm);
++
++int optee_ffa_do_call_with_arg(struct tee_context *ctx, struct tee_shm *arg);
++int optee_ffa_rpc_shm_register(struct tee_context *ctx, struct tee_shm *shm);
++void optee_handle_ffa_rpc(struct tee_context *ctx, u32 *w4, u32 *w5, u32 *w6);
++
+ /*
+ * Small helpers
+ */
+diff --git a/drivers/tee/optee/optee_rpc_cmd.h b/drivers/tee/optee/optee_rpc_cmd.h
+new file mode 100644
+index 000000000000..712aa32513d7
+--- /dev/null
++++ b/drivers/tee/optee/optee_rpc_cmd.h
+@@ -0,0 +1,333 @@
++/* SPDX-License-Identifier: BSD-2-Clause */
++/*
++ * Copyright (c) 2016-2018, Linaro Limited
++ */
++
++#ifndef __OPTEE_RPC_CMD_H
++#define __OPTEE_RPC_CMD_H
++
++/*
++ * All RPC is done with a struct optee_msg_arg as bearer of information,
++ * struct optee_msg_arg::arg holds values defined by OPTEE_RPC_CMD_* below.
++ * Only the commands handled by the kernel driver are defined here.
++ *
++ * RPC communication with tee-supplicant is reversed compared to normal
++ * client communication described above. The supplicant receives requests
++ * and sends responses.
++ */
++
++/*
++ * Load a TA into memory
++ *
++ * Since the size of the TA isn't known in advance the size of the TA is
++ * can be queried with a NULL buffer.
++ *
++ * [in] value[0].a-b UUID
++ * [out] memref[1] Buffer with TA
++ */
++#define OPTEE_RPC_CMD_LOAD_TA 0
++
++/*
++ * Replay Protected Memory Block access
++ *
++ * [in] memref[0] Frames to device
++ * [out] memref[1] Frames from device
++ */
++#define OPTEE_RPC_CMD_RPMB 1
++
++/*
++ * File system access, see definition of protocol below
++ */
++#define OPTEE_RPC_CMD_FS 2
++
++/*
++ * Get time
++ *
++ * Returns number of seconds and nano seconds since the Epoch,
++ * 1970-01-01 00:00:00 +0000 (UTC).
++ *
++ * [out] value[0].a Number of seconds
++ * [out] value[0].b Number of nano seconds.
++ */
++#define OPTEE_RPC_CMD_GET_TIME 3
++
++/*
++ * Wait queue primitive, helper for secure world to implement a wait queue.
++ *
++ * If secure world needs to wait for a secure world mutex it issues a sleep
++ * request instead of spinning in secure world. Conversely is a wakeup
++ * request issued when a secure world mutex with a thread waiting thread is
++ * unlocked.
++ *
++ * Waiting on a key
++ * [in] value[0].a OPTEE_RPC_WAIT_QUEUE_SLEEP
++ * [in] value[0].b Wait key
++ *
++ * Waking up a key
++ * [in] value[0].a OPTEE_RPC_WAIT_QUEUE_WAKEUP
++ * [in] value[0].b Wakeup key
++ */
++#define OPTEE_RPC_CMD_WAIT_QUEUE 4
++#define OPTEE_RPC_WAIT_QUEUE_SLEEP 0
++#define OPTEE_RPC_WAIT_QUEUE_WAKEUP 1
++
++/*
++ * Suspend execution
++ *
++ * [in] value[0].a Number of milliseconds to suspend
++ */
++#define OPTEE_RPC_CMD_SUSPEND 5
++
++/*
++ * Allocate a piece of shared memory
++ *
++ * [in] value[0].a Type of memory one of
++ * OPTEE_RPC_SHM_TYPE_* below
++ * [in] value[0].b Requested size
++ * [in] value[0].c Required alignment
++ * [out] memref[0] Buffer
++ */
++#define OPTEE_RPC_CMD_SHM_ALLOC 6
++/* Memory that can be shared with a non-secure user space application */
++#define OPTEE_RPC_SHM_TYPE_APPL 0
++/* Memory only shared with non-secure kernel */
++#define OPTEE_RPC_SHM_TYPE_KERNEL 1
++/*
++ * Memory shared with non-secure kernel and exported to a non-secure user
++ * space application
++ */
++#define OPTEE_RPC_SHM_TYPE_GLOBAL 2
++
++/*
++ * Free shared memory previously allocated with OPTEE_RPC_CMD_SHM_ALLOC
++ *
++ * [in] value[0].a Type of memory one of
++ * OPTEE_RPC_SHM_TYPE_* above
++ * [in] value[0].b Value of shared memory reference or cookie
++ */
++#define OPTEE_RPC_CMD_SHM_FREE 7
++
++/* Was OPTEE_RPC_CMD_SQL_FS, which isn't supported any longer */
++#define OPTEE_RPC_CMD_SQL_FS_RESERVED 8
++
++/*
++ * Send TA profiling information to normal world
++ *
++ * [in/out] value[0].a File identifier. Must be set to 0 on
++ * first call. A value >= 1 will be
++ * returned on success. Re-use this value
++ * to append data to the same file.
++ * [in] memref[1] TA UUID
++ * [in] memref[2] Profile data
++ */
++#define OPTEE_RPC_CMD_GPROF 9
++
++/*
++ * Socket command, see definition of protocol below
++ */
++#define OPTEE_RPC_CMD_SOCKET 10
++
++/*
++ * Send TA function graph data to normal world
++ *
++ * [in/out] value[0].a File identifier. Must be set to 0 on
++ * first call. A value >= 1 will be
++ * returned on success. Re-use this value
++ * to append data to the same file.
++ * [in] memref[1] TA UUID
++ * [in] memref[2] function graph data
++ */
++#define OPTEE_RPC_CMD_FTRACE 11
++
++/*
++ * Register timestamp buffer in the linux kernel optee driver
++ *
++ * [in] value[0].a Subcommand (register buffer, unregister buffer)
++ * OPTEE_RPC_CMD_BENCH_REG_* below
++ * [in] value[0].b Physical address of timestamp buffer
++ * [in] value[0].c Size of buffer
++ */
++#define OPTEE_RPC_CMD_BENCH_REG_NEW 0
++#define OPTEE_RPC_CMD_BENCH_REG_DEL 1
++#define OPTEE_RPC_CMD_BENCH_REG 20
++
++/*
++ * Definition of protocol for command OPTEE_RPC_CMD_FS
++ */
++
++/*
++ * Open a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_OPEN
++ * [in] memref[1] A string holding the file name
++ * [out] value[2].a File descriptor of open file
++ */
++#define OPTEE_RPC_FS_OPEN 0
++
++/*
++ * Create a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_CREATE
++ * [in] memref[1] A string holding the file name
++ * [out] value[2].a File descriptor of open file
++ */
++#define OPTEE_RPC_FS_CREATE 1
++
++/*
++ * Close a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_CLOSE
++ * [in] value[0].b File descriptor of open file.
++ */
++#define OPTEE_RPC_FS_CLOSE 2
++
++/*
++ * Read from a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_READ
++ * [in] value[0].b File descriptor of open file
++ * [in] value[0].c Offset into file
++ * [out] memref[1] Buffer to hold returned data
++ */
++#define OPTEE_RPC_FS_READ 3
++
++/*
++ * Write to a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_WRITE
++ * [in] value[0].b File descriptor of open file
++ * [in] value[0].c Offset into file
++ * [in] memref[1] Buffer holding data to be written
++ */
++#define OPTEE_RPC_FS_WRITE 4
++
++/*
++ * Truncate a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_TRUNCATE
++ * [in] value[0].b File descriptor of open file
++ * [in] value[0].c Length of file.
++ */
++#define OPTEE_RPC_FS_TRUNCATE 5
++
++/*
++ * Remove a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_REMOVE
++ * [in] memref[1] A string holding the file name
++ */
++#define OPTEE_RPC_FS_REMOVE 6
++
++/*
++ * Rename a file
++ *
++ * [in] value[0].a OPTEE_RPC_FS_RENAME
++ * [in] value[0].b True if existing target should be removed
++ * [in] memref[1] A string holding the old file name
++ * [in] memref[2] A string holding the new file name
++ */
++#define OPTEE_RPC_FS_RENAME 7
++
++/*
++ * Opens a directory for file listing
++ *
++ * [in] value[0].a OPTEE_RPC_FS_OPENDIR
++ * [in] memref[1] A string holding the name of the directory
++ * [out] value[2].a Handle to open directory
++ */
++#define OPTEE_RPC_FS_OPENDIR 8
++
++/*
++ * Closes a directory handle
++ *
++ * [in] value[0].a OPTEE_RPC_FS_CLOSEDIR
++ * [in] value[0].b Handle to open directory
++ */
++#define OPTEE_RPC_FS_CLOSEDIR 9
++
++/*
++ * Read next file name of directory
++ *
++ *
++ * [in] value[0].a OPTEE_RPC_FS_READDIR
++ * [in] value[0].b Handle to open directory
++ * [out] memref[1] A string holding the file name
++ */
++#define OPTEE_RPC_FS_READDIR 10
++
++/* End of definition of protocol for command OPTEE_RPC_CMD_FS */
++
++/*
++ * Definition of protocol for command OPTEE_RPC_CMD_SOCKET
++ */
++
++#define OPTEE_RPC_SOCKET_TIMEOUT_NONBLOCKING 0
++#define OPTEE_RPC_SOCKET_TIMEOUT_BLOCKING 0xffffffff
++
++/*
++ * Open socket
++ *
++ * [in] value[0].a OPTEE_RPC_SOCKET_OPEN
++ * [in] value[0].b TA instance id
++ * [in] value[1].a Server port number
++ * [in] value[1].b Protocol, TEE_ISOCKET_PROTOCOLID_*
++ * [in] value[1].c Ip version TEE_IP_VERSION_* from tee_ipsocket.h
++ * [in] memref[2] Server address
++ * [out] value[3].a Socket handle (32-bit)
++ */
++#define OPTEE_RPC_SOCKET_OPEN 0
++
++/*
++ * Close socket
++ *
++ * [in] value[0].a OPTEE_RPC_SOCKET_CLOSE
++ * [in] value[0].b TA instance id
++ * [in] value[0].c Socket handle
++ */
++#define OPTEE_RPC_SOCKET_CLOSE 1
++
++/*
++ * Close all sockets
++ *
++ * [in] value[0].a OPTEE_RPC_SOCKET_CLOSE_ALL
++ * [in] value[0].b TA instance id
++ */
++#define OPTEE_RPC_SOCKET_CLOSE_ALL 2
++
++/*
++ * Send data on socket
++ *
++ * [in] value[0].a OPTEE_RPC_SOCKET_SEND
++ * [in] value[0].b TA instance id
++ * [in] value[0].c Socket handle
++ * [in] memref[1] Buffer to transmit
++ * [in] value[2].a Timeout ms or OPTEE_RPC_SOCKET_TIMEOUT_*
++ * [out] value[2].b Number of transmitted bytes
++ */
++#define OPTEE_RPC_SOCKET_SEND 3
++
++/*
++ * Receive data on socket
++ *
++ * [in] value[0].a OPTEE_RPC_SOCKET_RECV
++ * [in] value[0].b TA instance id
++ * [in] value[0].c Socket handle
++ * [out] memref[1] Buffer to receive
++ * [in] value[2].a Timeout ms or OPTEE_RPC_SOCKET_TIMEOUT_*
++ */
++#define OPTEE_RPC_SOCKET_RECV 4
++
++/*
++ * Perform IOCTL on socket
++ *
++ * [in] value[0].a OPTEE_RPC_SOCKET_IOCTL
++ * [in] value[0].b TA instance id
++ * [in] value[0].c Socket handle
++ * [in/out] memref[1] Buffer
++ * [in] value[2].a Ioctl command
++ */
++#define OPTEE_RPC_SOCKET_IOCTL 5
++
++/* End of definition of protocol for command OPTEE_RPC_CMD_SOCKET */
++
++#endif /*__OPTEE_RPC_CMD_H*/
+diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
+index b4ade54d1f28..ca5d5d01b58f 100644
+--- a/drivers/tee/optee/rpc.c
++++ b/drivers/tee/optee/rpc.c
+@@ -9,8 +9,11 @@
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/tee_drv.h>
++#include "optee_msg.h"
+ #include "optee_private.h"
++#include "optee_rpc_cmd.h"
+ #include "optee_smc.h"
++#include "optee_ffa.h"
+
+ struct wq_entry {
+ struct list_head link;
+@@ -102,10 +105,10 @@ static void handle_rpc_func_cmd_wq(struct optee *optee,
+ goto bad;
+
+ switch (arg->params[0].u.value.a) {
+- case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP:
++ case OPTEE_RPC_WAIT_QUEUE_SLEEP:
+ wq_sleep(&optee->wait_queue, arg->params[0].u.value.b);
+ break;
+- case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP:
++ case OPTEE_RPC_WAIT_QUEUE_WAKEUP:
+ wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b);
+ break;
+ default:
+@@ -140,10 +143,10 @@ static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ }
+
+-static void handle_rpc_supp_cmd(struct tee_context *ctx,
++static void handle_rpc_supp_cmd(struct tee_context *ctx, struct optee *optee,
+ struct optee_msg_arg *arg)
+ {
+- struct tee_param *params;
++ struct tee_param *params = NULL;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+@@ -154,32 +157,36 @@ static void handle_rpc_supp_cmd(struct tee_context *ctx,
+ return;
+ }
+
+- if (optee_from_msg_param(params, arg->num_params, arg->params)) {
++ if (optee->ops->from_msg_param(optee, params, arg->num_params,
++ arg->params)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);
+
+- if (optee_to_msg_param(arg->params, arg->num_params, params))
++ if (optee->ops->to_msg_param(optee, arg->params, arg->num_params,
++ params))
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ out:
+ kfree(params);
+ }
+
++
++
+ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
+ {
+- u32 ret;
+- struct tee_param param;
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+- struct tee_shm *shm;
++ struct tee_param param = { };
++ struct tee_shm *shm = NULL;
++ u32 ret = 0;
+
+ param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+- param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
++ param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL;
+ param.u.value.b = sz;
+ param.u.value.c = 0;
+
+- ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, ¶m);
++ ret = optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_ALLOC, 1, ¶m);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
+
+@@ -216,10 +223,10 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+
+ sz = arg->params[0].u.value.b;
+ switch (arg->params[0].u.value.a) {
+- case OPTEE_MSG_RPC_SHM_TYPE_APPL:
++ case OPTEE_RPC_SHM_TYPE_APPL:
+ shm = cmd_alloc_suppl(ctx, sz);
+ break;
+- case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
++ case OPTEE_RPC_SHM_TYPE_KERNEL:
+ shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED);
+ break;
+ default:
+@@ -291,7 +298,7 @@ static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
+ struct tee_param param;
+
+ param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+- param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
++ param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL;
+ param.u.value.b = tee_shm_get_id(shm);
+ param.u.value.c = 0;
+
+@@ -308,7 +315,7 @@ static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
+ */
+ tee_shm_put(shm);
+
+- optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, ¶m);
++ optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_FREE, 1, ¶m);
+ }
+
+ static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
+@@ -326,10 +333,10 @@ static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
+
+ shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
+ switch (arg->params[0].u.value.a) {
+- case OPTEE_MSG_RPC_SHM_TYPE_APPL:
++ case OPTEE_RPC_SHM_TYPE_APPL:
+ cmd_free_suppl(ctx, shm);
+ break;
+- case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
++ case OPTEE_RPC_SHM_TYPE_KERNEL:
+ tee_shm_free(shm);
+ break;
+ default:
+@@ -357,7 +364,7 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
+ struct tee_shm *shm,
+ struct optee_call_ctx *call_ctx)
+ {
+- struct optee_msg_arg *arg;
++ struct optee_msg_arg *arg = NULL;
+
+ arg = tee_shm_get_va(shm, 0);
+ if (IS_ERR(arg)) {
+@@ -366,24 +373,24 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
+ }
+
+ switch (arg->cmd) {
+- case OPTEE_MSG_RPC_CMD_GET_TIME:
++ case OPTEE_RPC_CMD_GET_TIME:
+ handle_rpc_func_cmd_get_time(arg);
+ break;
+- case OPTEE_MSG_RPC_CMD_WAIT_QUEUE:
++ case OPTEE_RPC_CMD_WAIT_QUEUE:
+ handle_rpc_func_cmd_wq(optee, arg);
+ break;
+- case OPTEE_MSG_RPC_CMD_SUSPEND:
++ case OPTEE_RPC_CMD_SUSPEND:
+ handle_rpc_func_cmd_wait(arg);
+ break;
+- case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
++ case OPTEE_RPC_CMD_SHM_ALLOC:
+ free_pages_list(call_ctx);
+ handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
+ break;
+- case OPTEE_MSG_RPC_CMD_SHM_FREE:
++ case OPTEE_RPC_CMD_SHM_FREE:
+ handle_rpc_func_cmd_shm_free(ctx, arg);
+ break;
+ default:
+- handle_rpc_supp_cmd(ctx, arg);
++ handle_rpc_supp_cmd(ctx, optee, arg);
+ }
+ }
+
+@@ -441,3 +448,95 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
+
+ param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
+ }
++
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
++ struct optee *optee,
++ struct optee_msg_arg *arg)
++{
++ switch (arg->cmd) {
++ case OPTEE_RPC_CMD_GET_TIME:
++ handle_rpc_func_cmd_get_time(arg);
++ break;
++ case OPTEE_RPC_CMD_WAIT_QUEUE:
++ handle_rpc_func_cmd_wq(optee, arg);
++ break;
++ case OPTEE_RPC_CMD_SUSPEND:
++ handle_rpc_func_cmd_wait(arg);
++ break;
++ case OPTEE_RPC_CMD_SHM_ALLOC:
++ case OPTEE_RPC_CMD_SHM_FREE:
++ pr_err("%s: RPC cmd 0x%x: not supported\n", __func__,
++ arg->cmd);
++ arg->ret = TEEC_ERROR_NOT_SUPPORTED;
++ break;
++ default:
++ handle_rpc_supp_cmd(ctx, optee, arg);
++ }
++}
++
++void optee_handle_ffa_rpc(struct tee_context *ctx, u32 *w4, u32 *w5, u32 *w6)
++{
++ struct optee *optee = tee_get_drvdata(ctx->teedev);
++ struct tee_shm *shm = NULL;
++ struct optee_msg_arg *rpc_arg = NULL;
++ u64 global_handle = 0;
++ u32 cmd = *w4;
++
++ switch (cmd) {
++ case OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_KERN_SHM:
++ case OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_SUPPL_SHM:
++ if (cmd == OPTEE_FFA_YIELDING_CALL_RETURN_ALLOC_KERN_SHM)
++ shm = tee_shm_alloc(ctx, *w5 * PAGE_SIZE,
++ TEE_SHM_MAPPED);
++ else
++ shm = cmd_alloc_suppl(ctx, *w5 * PAGE_SIZE);
++
++ if (IS_ERR_OR_NULL(shm))
++ break;
++
++ *w4 = shm->sec_world_id;
++ *w5 = shm->sec_world_id >> 32;
++ *w6 = shm->offset;
++ return;
++ case OPTEE_FFA_YIELDING_CALL_RETURN_FREE_KERN_SHM:
++ case OPTEE_FFA_YIELDING_CALL_RETURN_FREE_SUPPL_SHM:
++ global_handle = *w5 | ((u64)*w6 << 32);
++ shm = optee_shm_from_ffa_handle(optee, global_handle);
++ if (!shm) {
++ pr_err("Invalid global handle 0x%llx\n", global_handle);
++ break;
++ }
++ if (cmd == OPTEE_FFA_YIELDING_CALL_RETURN_FREE_KERN_SHM)
++ tee_shm_free(shm);
++ else
++ cmd_free_suppl(ctx, shm);
++ break;
++ case OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD:
++ global_handle = *w5 | ((u64)*w6 << 32);
++ shm = optee_shm_from_ffa_handle(optee, global_handle);
++ if (!shm) {
++ pr_err("Invalid global handle 0x%llx\n", global_handle);
++ break;
++ }
++ rpc_arg = tee_shm_get_va(shm, 0);
++ if (IS_ERR(rpc_arg)) {
++ pr_err("Invalid offset 0 for global handle 0x%llx\n",
++ global_handle);
++ break;
++ }
++ handle_ffa_rpc_func_cmd(ctx, optee, rpc_arg);
++ break;
++ case OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT:
++ /* Interrupt delivered by now */
++ break;
++ default:
++ pr_warn("Unknown RPC func 0x%x\n", cmd);
++ break;
++ }
++
++ *w4 = 0;
++ *w5 = 0;
++ *w6 = 0;
++}
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
+diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c
+index d767eebf30bd..ffc6821f6ce3 100644
+--- a/drivers/tee/optee/shm_pool.c
++++ b/drivers/tee/optee/shm_pool.c
+@@ -87,3 +87,53 @@ struct tee_shm_pool_mgr *optee_shm_pool_alloc_pages(void)
+
+ return mgr;
+ }
++
++#ifdef CONFIG_ARM_FFA_TRANSPORT
++static int pool_ffa_op_alloc(struct tee_shm_pool_mgr *poolm,
++ struct tee_shm *shm, size_t size)
++{
++ unsigned int order = get_order(size);
++ struct page *page;
++ int rc = 0;
++
++ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
++ if (!page)
++ return -ENOMEM;
++
++ shm->kaddr = page_address(page);
++ shm->paddr = page_to_phys(page);
++ shm->size = PAGE_SIZE << order;
++
++ shm->flags |= TEE_SHM_REGISTER;
++ rc = optee_ffa_shm_register(shm->ctx, shm, &page, 1 << order,
++ (unsigned long)shm->kaddr);
++
++ return rc;
++}
++
++static void pool_ffa_op_free(struct tee_shm_pool_mgr *poolm,
++ struct tee_shm *shm)
++{
++ optee_ffa_shm_unregister(shm->ctx, shm);
++ free_pages((unsigned long)shm->kaddr, get_order(shm->size));
++ shm->kaddr = NULL;
++}
++
++static const struct tee_shm_pool_mgr_ops pool_ffa_ops = {
++ .alloc = pool_ffa_op_alloc,
++ .free = pool_ffa_op_free,
++ .destroy_poolmgr = pool_op_destroy_poolmgr,
++};
++
++struct tee_shm_pool_mgr *optee_ffa_shm_pool_alloc_pages(void)
++{
++ struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
++
++ if (!mgr)
++ return ERR_PTR(-ENOMEM);
++
++ mgr->ops = &pool_ffa_ops;
++
++ return mgr;
++}
++#endif /*CONFIG_ARM_FFA_TRANSPORT*/
+diff --git a/drivers/tee/optee/shm_pool.h b/drivers/tee/optee/shm_pool.h
+index 28109d991c4b..34c5fd74a3ff 100644
+--- a/drivers/tee/optee/shm_pool.h
++++ b/drivers/tee/optee/shm_pool.h
+@@ -10,5 +10,6 @@
+ #include <linux/tee_drv.h>
+
+ struct tee_shm_pool_mgr *optee_shm_pool_alloc_pages(void);
++struct tee_shm_pool_mgr *optee_ffa_shm_pool_alloc_pages(void);
+
+ #endif
+diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
+index 3d32a2ca48c3..974fe7081225 100644
+--- a/drivers/tee/tee_core.c
++++ b/drivers/tee/tee_core.c
+@@ -59,7 +59,6 @@ static struct tee_context *teedev_open(struct tee_device *teedev)
+
+ kref_init(&ctx->refcount);
+ ctx->teedev = teedev;
+- INIT_LIST_HEAD(&ctx->list_shm);
+ rc = teedev->desc->ops->open(ctx);
+ if (rc)
+ goto err;
+diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
+index 09ddcd06c715..deb22f877881 100644
+--- a/drivers/tee/tee_shm.c
++++ b/drivers/tee/tee_shm.c
+@@ -13,13 +13,13 @@
+
+ static void tee_shm_release(struct tee_shm *shm)
+ {
+- struct tee_device *teedev = shm->teedev;
++ struct tee_device *teedev = shm->ctx->teedev;
+
+- mutex_lock(&teedev->mutex);
+- idr_remove(&teedev->idr, shm->id);
+- if (shm->ctx)
+- list_del(&shm->link);
+- mutex_unlock(&teedev->mutex);
++ if (shm->flags & TEE_SHM_DMA_BUF) {
++ mutex_lock(&teedev->mutex);
++ idr_remove(&teedev->idr, shm->id);
++ mutex_unlock(&teedev->mutex);
++ }
+
+ if (shm->flags & TEE_SHM_POOL) {
+ struct tee_shm_pool_mgr *poolm;
+@@ -44,8 +44,7 @@ static void tee_shm_release(struct tee_shm *shm)
+ kfree(shm->pages);
+ }
+
+- if (shm->ctx)
+- teedev_ctx_put(shm->ctx);
++ teedev_ctx_put(shm->ctx);
+
+ kfree(shm);
+
+@@ -82,7 +81,7 @@ static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+ size_t size = vma->vm_end - vma->vm_start;
+
+ /* Refuse sharing shared memory provided by application */
+- if (shm->flags & TEE_SHM_REGISTER)
++ if (shm->flags & TEE_SHM_USER_MAPPED)
+ return -EINVAL;
+
+ return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
+@@ -97,20 +96,14 @@ static const struct dma_buf_ops tee_shm_dma_buf_ops = {
+ .mmap = tee_shm_op_mmap,
+ };
+
+-static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+- struct tee_device *teedev,
+- size_t size, u32 flags)
++struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+ {
++ struct tee_device *teedev = ctx->teedev;
+ struct tee_shm_pool_mgr *poolm = NULL;
+ struct tee_shm *shm;
+ void *ret;
+ int rc;
+
+- if (ctx && ctx->teedev != teedev) {
+- dev_err(teedev->dev.parent, "ctx and teedev mismatch\n");
+- return ERR_PTR(-EINVAL);
+- }
+-
+ if (!(flags & TEE_SHM_MAPPED)) {
+ dev_err(teedev->dev.parent,
+ "only mapped allocations supported\n");
+@@ -138,7 +131,6 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+ }
+
+ shm->flags = flags | TEE_SHM_POOL;
+- shm->teedev = teedev;
+ shm->ctx = ctx;
+ if (flags & TEE_SHM_DMA_BUF)
+ poolm = teedev->pool->dma_buf_mgr;
+@@ -151,17 +143,18 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+ goto err_kfree;
+ }
+
+- mutex_lock(&teedev->mutex);
+- shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+- mutex_unlock(&teedev->mutex);
+- if (shm->id < 0) {
+- ret = ERR_PTR(shm->id);
+- goto err_pool_free;
+- }
+
+ if (flags & TEE_SHM_DMA_BUF) {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
++ mutex_lock(&teedev->mutex);
++ shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
++ mutex_unlock(&teedev->mutex);
++ if (shm->id < 0) {
++ ret = ERR_PTR(shm->id);
++ goto err_pool_free;
++ }
++
+ exp_info.ops = &tee_shm_dma_buf_ops;
+ exp_info.size = shm->size;
+ exp_info.flags = O_RDWR;
+@@ -174,18 +167,16 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+ }
+ }
+
+- if (ctx) {
++ if (ctx)
+ teedev_ctx_get(ctx);
+- mutex_lock(&teedev->mutex);
+- list_add_tail(&shm->link, &ctx->list_shm);
+- mutex_unlock(&teedev->mutex);
+- }
+
+ return shm;
+ err_rem:
+- mutex_lock(&teedev->mutex);
+- idr_remove(&teedev->idr, shm->id);
+- mutex_unlock(&teedev->mutex);
++ if (flags & TEE_SHM_DMA_BUF) {
++ mutex_lock(&teedev->mutex);
++ idr_remove(&teedev->idr, shm->id);
++ mutex_unlock(&teedev->mutex);
++ }
+ err_pool_free:
+ poolm->ops->free(poolm, shm);
+ err_kfree:
+@@ -194,31 +185,8 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+ tee_device_put(teedev);
+ return ret;
+ }
+-
+-/**
+- * tee_shm_alloc() - Allocate shared memory
+- * @ctx: Context that allocates the shared memory
+- * @size: Requested size of shared memory
+- * @flags: Flags setting properties for the requested shared memory.
+- *
+- * Memory allocated as global shared memory is automatically freed when the
+- * TEE file pointer is closed. The @flags field uses the bits defined by
+- * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
+- * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
+- * associated with a dma-buf handle, else driver private memory.
+- */
+-struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+-{
+- return __tee_shm_alloc(ctx, ctx->teedev, size, flags);
+-}
+ EXPORT_SYMBOL_GPL(tee_shm_alloc);
+
+-struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size)
+-{
+- return __tee_shm_alloc(NULL, teedev, size, TEE_SHM_MAPPED);
+-}
+-EXPORT_SYMBOL_GPL(tee_shm_priv_alloc);
+-
+ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+ size_t length, u32 flags)
+ {
+@@ -251,7 +219,6 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+ }
+
+ shm->flags = flags | TEE_SHM_REGISTER;
+- shm->teedev = teedev;
+ shm->ctx = ctx;
+ shm->id = -1;
+ addr = untagged_addr(addr);
+@@ -307,10 +274,6 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+ }
+ }
+
+- mutex_lock(&teedev->mutex);
+- list_add_tail(&shm->link, &ctx->list_shm);
+- mutex_unlock(&teedev->mutex);
+-
+ return shm;
+ err:
+ if (shm) {
+diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
+index 545a57f61a5e..407c27c11b2b 100644
+--- a/include/linux/tee_drv.h
++++ b/include/linux/tee_drv.h
+@@ -49,7 +49,6 @@ struct tee_shm_pool;
+ */
+ struct tee_context {
+ struct tee_device *teedev;
+- struct list_head list_shm;
+ void *data;
+ struct kref refcount;
+ bool releasing;
+@@ -184,9 +183,7 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
+
+ /**
+ * struct tee_shm - shared memory object
+- * @teedev: device used to allocate the object
+- * @ctx: context using the object, if NULL the context is gone
+- * @link link element
++ * @ctx: context using the object
+ * @paddr: physical address of the shared memory
+ * @kaddr: virtual address of the shared memory
+ * @size: size of shared memory
+@@ -195,15 +192,17 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
+ * @num_pages: number of locked pages
+ * @dmabuf: dmabuf used to for exporting to user space
+ * @flags: defined by TEE_SHM_* in tee_drv.h
+- * @id: unique id of a shared memory object on this device
++ * @id: unique id of a shared memory object on this device, shared
++ * with user space
++ * @sec_world_id:
++ * secure world assigned id of this shared memory object, not
++ * used by all drivers
+ *
+ * This pool is only supposed to be accessed directly from the TEE
+ * subsystem and from drivers that implements their own shm pool manager.
+ */
+ struct tee_shm {
+- struct tee_device *teedev;
+ struct tee_context *ctx;
+- struct list_head link;
+ phys_addr_t paddr;
+ void *kaddr;
+ size_t size;
+@@ -213,6 +212,7 @@ struct tee_shm {
+ struct dma_buf *dmabuf;
+ u32 flags;
+ int id;
++ u64 sec_world_id;
+ };
+
+ /**
+@@ -334,18 +334,6 @@ void *tee_get_drvdata(struct tee_device *teedev);
+ */
+ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags);
+
+-/**
+- * tee_shm_priv_alloc() - Allocate shared memory privately
+- * @dev: Device that allocates the shared memory
+- * @size: Requested size of shared memory
+- *
+- * Allocates shared memory buffer that is not associated with any client
+- * context. Such buffers are owned by TEE driver and used for internal calls.
+- *
+- * @returns a pointer to 'struct tee_shm'
+- */
+-struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size);
+-
+ /**
+ * tee_shm_register() - Register shared memory buffer
+ * @ctx: Context that registers the shared memory
+--
+2.26.2
+
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch
new file mode 100644
index 0000000..ad2c945
--- /dev/null
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch
@@ -0,0 +1,51 @@
+From 957e0145899813017a6a2b7f863a4a2b4e4b75aa Mon Sep 17 00:00:00 2001
+From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Date: Tue, 5 Jan 2021 09:27:41 +0000
+Subject: [PATCH] tee: optee: fix mem handle removal in ffa_shm_unregister
+
+Remove ffa memory handle before calling mem_reclaim. This enables the
+handle to be re-used by another thread once mem_claim for that handle
+is completed.
+
+Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
+Change-Id: I7294bd71f2bbc28514eaa09ae757dd216bc7df45
+
+Upstream-Status: Pending [Not submitted to upstream yet]
+---
+ drivers/tee/optee/call.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
+index ac89ab42a43f..9c9480add0b5 100644
+--- a/drivers/tee/optee/call.c
++++ b/drivers/tee/optee/call.c
+@@ -843,6 +843,10 @@ int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
+ {
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ int rc = 0;
++ u64 handle = shm->sec_world_id;
++
++ optee_shm_rem_ffa_handle(optee, handle);
++ shm->sec_world_id = 0;
+
+ /*
+ * We're skipping the OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM call
+@@ -850,14 +854,10 @@ int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
+ * this ID.
+ */
+
+- rc = optee->ffa.ops->mem_reclaim(shm->sec_world_id, 0);
++ rc = optee->ffa.ops->mem_reclaim(handle, 0);
+ if (rc)
+ pr_err("mem_reclain: %d", rc);
+
+- optee_shm_rem_ffa_handle(optee, shm->sec_world_id);
+-
+- shm->sec_world_id = 0;
+-
+ return rc;
+ }
+ #endif /*CONFIG_ARM_FFA_TRANSPORT*/
+--
+2.26.2
+
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 10/10] arm-bsp/tc0: Enable spmd and SEL2 SPMC with optee as SEL1 SP
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (7 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 09/10] arm-bsp/linux: add ffa transport in optee " Arunachalam Ganapathy
@ 2021-01-12 15:20 ` Arunachalam Ganapathy
2021-01-14 19:23 ` [meta-arm] [PATCH 01/10] arm: Add hafnium support Jon Mason
9 siblings, 0 replies; 11+ messages in thread
From: Arunachalam Ganapathy @ 2021-01-12 15:20 UTC (permalink / raw)
To: meta-arm; +Cc: nd, Arunachalam Ganapathy
- Set SPD to spmd with SEL2 SPMC. Set optee as SP
- Assign SP layout and spmc manifest file that corresponds to optee
- Move TF-A version from 2.3 to 2.4
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I3da3bf7f95ba42716b731f92e2cdfb928b1ab77f
---
meta-arm-bsp/conf/machine/tc0.conf | 3 +--
.../trusted-firmware-a-tc0.inc | 19 +++++++++++++------
.../trusted-firmware-a_2.3.bbappend | 1 -
.../trusted-firmware-a_2.4.bbappend | 1 +
4 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/meta-arm-bsp/conf/machine/tc0.conf b/meta-arm-bsp/conf/machine/tc0.conf
index 6c366da..eda3324 100644
--- a/meta-arm-bsp/conf/machine/tc0.conf
+++ b/meta-arm-bsp/conf/machine/tc0.conf
@@ -26,9 +26,8 @@ UBOOT_SIGN_KEYNAME = "dev_key"
UBOOT_SIGN_KEYDIR = "${DEPLOY_DIR_IMAGE}/keys"
FIT_GENERATE_KEYS = "1"
-# Trusted firmware A v2.3
PREFERRED_PROVIDER_virtual/trusted-firmware-a ?= "trusted-firmware-a"
-PREFERRED_VERSION_trusted-firmware-a ?= "2.3%"
+PREFERRED_VERSION_trusted-firmware-a ?= "2.4%"
PREFERRED_PROVIDER_virtual/kernel ?= "linux-arm64-ack"
PREFERRED_VERSION_linux-arm64-ack ?= "5.4"
diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc0.inc b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc0.inc
index 8d98937..bb12ba4 100644
--- a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc0.inc
+++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-tc0.inc
@@ -1,10 +1,8 @@
-# TCO specific TFA configuration
+# TC0 specific TFA configuration
-# Intermediate SHA with 2.3 baseline version
-SRCREV_tfa = "16796a25fefc4ecf780211bf554d3b8dc5436fa4"
-
-# This is incorporated into the SRCREV above
-SRC_URI_remove = "file://0001-fdts-a5ds-Fix-for-the-system-timer-issue.patch"
+# Intermediate SHA with 2.4 baseline version, required for OP-TEE SP
+SRCREV_tfa = "b153ce0391012e9228b807815a65fa0dc514cf77"
+PV = "2.4+git${SRCPV}"
DEPENDS += "scp-firmware"
@@ -17,6 +15,15 @@ TFA_INSTALL_TARGET = "bl1 fip"
TFA_MBEDTLS = "1"
TFA_DEBUG = "1"
+TFA_SPD = "spmd"
+TFA_SPMD_SPM_AT_SEL2 = "1"
+
+# Set optee as SP. Set spmc manifest and sp layout file to optee
+DEPENDS += "optee-os"
+
+TFA_SP_LAYOUT_FILE = "${RECIPE_SYSROOT}/lib/firmware/sp_layout.json"
+TFA_ARM_SPMC_MANIFEST_DTS = "plat/arm/board/tc0/fdts/tc0_spmc_optee_sp_manifest.dts"
+
EXTRA_OEMAKE += "SCP_BL2=${RECIPE_SYSROOT}/firmware/scp_ramfw.bin"
EXTRA_OEMAKE += "TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 ARM_ROTPK_LOCATION=devel_rsa \
ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem"
diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.3.bbappend b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.3.bbappend
index f1908f8..0535278 100644
--- a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.3.bbappend
+++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.3.bbappend
@@ -1,7 +1,6 @@
# Machine specific TFAs
MACHINE_TFA_REQUIRE ?= ""
-MACHINE_TFA_REQUIRE_tc0 = "trusted-firmware-a-tc0.inc"
MACHINE_TFA_REQUIRE_corstone500 = "trusted-firmware-a-corstone500.inc"
MACHINE_TFA_REQUIRE_juno = "trusted-firmware-a-juno.inc"
MACHINE_TFA_REQUIRE_corstone700 = "trusted-firmware-a-corstone700.inc"
diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.4.bbappend b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.4.bbappend
index 944dd7a..8087f39 100644
--- a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.4.bbappend
+++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_2.4.bbappend
@@ -4,5 +4,6 @@ MACHINE_TFA_REQUIRE ?= ""
MACHINE_TFA_REQUIRE_fvp-base = "trusted-firmware-a-fvp.inc"
MACHINE_TFA_REQUIRE_fvp-base-arm32 = "trusted-firmware-a-fvp-arm32.inc"
MACHINE_TFA_REQUIRE_n1sdp = "trusted-firmware-a-n1sdp.inc"
+MACHINE_TFA_REQUIRE_tc0 = "trusted-firmware-a-tc0.inc"
require ${MACHINE_TFA_REQUIRE}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [meta-arm] [PATCH 01/10] arm: Add hafnium support
2021-01-12 15:20 [PATCH 01/10] arm: Add hafnium support arunachalam.ganapathy
` (8 preceding siblings ...)
2021-01-12 15:20 ` [PATCH 10/10] arm-bsp/tc0: Enable spmd and SEL2 SPMC with optee as SEL1 SP Arunachalam Ganapathy
@ 2021-01-14 19:23 ` Jon Mason
9 siblings, 0 replies; 11+ messages in thread
From: Jon Mason @ 2021-01-14 19:23 UTC (permalink / raw)
To: Arunachalam Ganapathy; +Cc: meta-arm, nd
On Tue, Jan 12, 2021 at 03:20:40PM +0000, Arunachalam Ganapathy wrote:
> Initial recipe for hafnium[1]. This enables build for reference Secure
> Partition Manager (SPM) for systems that implement the Armv8.4-A
> Secure-EL2 extension.
>
> Link: [1] https://www.trustedfirmware.org/projects/hafnium/
>
> Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
> Change-Id: Ib256d8ca03c94131e308d962d786d5d6a656c256
> ---
Series pulled into master.
Thanks,
Jon
> meta-arm/recipes-bsp/hafnium/hafnium_2.4.bb | 74 +++++++++++++++++++++
> 1 file changed, 74 insertions(+)
> create mode 100644 meta-arm/recipes-bsp/hafnium/hafnium_2.4.bb
>
> diff --git a/meta-arm/recipes-bsp/hafnium/hafnium_2.4.bb b/meta-arm/recipes-bsp/hafnium/hafnium_2.4.bb
> new file mode 100644
> index 0000000..3a52599
> --- /dev/null
> +++ b/meta-arm/recipes-bsp/hafnium/hafnium_2.4.bb
> @@ -0,0 +1,74 @@
> +SUMMARY = "Hafnium"
> +DESCRIPTION = "A reference Secure Partition Manager (SPM) for systems that implement the Armv8.4-A Secure-EL2 extension"
> +LICENSE = "BSD-3-Clause & GPLv2"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=782b40c14bad5294672c500501edc103"
> +
> +PACKAGE_ARCH = "${MACHINE_ARCH}"
> +
> +inherit deploy python3native
> +
> +SRC_URI = "gitsm://git.trustedfirmware.org/hafnium/hafnium.git;protocol=https"
> +SRCREV = "410a3acaf669c12d41fb4c57fcaf3ecee6fdba61"
> +S = "${WORKDIR}/git"
> +
> +COMPATIBLE_MACHINE ?= "invalid"
> +
> +# Default build 'reference'
> +HAFNIUM_PROJECT ?= "reference"
> +
> +# Platform must be set for each machine
> +HAFNIUM_PLATFORM ?= "invalid"
> +
> +# hafnium build directory
> +# Append _clang as the build rule in hafnium adds this to the platform name.
> +HAFNIUM_BUILD_DIR_PLAT = "out/${HAFNIUM_PROJECT}/${HAFNIUM_PLATFORM}_clang"
> +
> +# do_deploy will install everything listed in this variable. It is set by
> +# default to hafnium
> +HAFNIUM_INSTALL_TARGET ?= "hafnium"
> +
> +DEPENDS = "bison-native bc-native"
> +
> +# set project to build
> +EXTRA_OEMAKE += "PROJECT=${HAFNIUM_PROJECT}"
> +
> +do_compile_prepend() {
> + # Hafnium expects 'python'. Create symlink python to python3
> + real=$(which ${PYTHON})
> + ln -snf $real $(dirname $real)/python
> +}
> +
> +do_install() {
> + install -d -m 755 ${D}/firmware
> + for bldfile in ${HAFNIUM_INSTALL_TARGET}; do
> + processed="0"
> + if [ -f ${S}/${HAFNIUM_BUILD_DIR_PLAT}/$bldfile.bin ]; then
> + echo "Install $bldfile.bin"
> + install -m 0755 ${S}/${HAFNIUM_BUILD_DIR_PLAT}/$bldfile.bin \
> + ${D}/firmware/$bldfile-${HAFNIUM_PLATFORM}.bin
> + ln -sf $bldfile-${HAFNIUM_PLATFORM}.bin ${D}/firmware/$bldfile.bin
> + processed="1"
> + fi
> + if [ -f ${S}/${HAFNIUM_BUILD_DIR_PLAT}/$bldfile.elf ]; then
> + echo "Install $bldfile.elf"
> + install -m 0755 ${S}/${HAFNIUM_BUILD_DIR_PLAT}/$bldfile.elf \
> + ${D}/firmware/$bldfile-${HAFNIUM_PLATFORM}.elf
> + ln -sf $bldfile-${HAFNIUM_PLATFORM}.elf ${D}/firmware/$bldfile.elf
> + processed="1"
> + fi
> + if [ "$processed" = "0" ]; then
> + bberror "Unsupported HAFNIUM_INSTALL_TARGET target $bldfile"
> + exit 1
> + fi
> + done
> +}
> +
> +FILES_${PN} = "/firmware"
> +SYSROOT_DIRS += "/firmware"
> +# skip QA tests: {'ldflags'}
> +INSANE_SKIP_${PN} = "ldflags"
> +
> +do_deploy() {
> + cp -rf ${D}/firmware/* ${DEPLOYDIR}/
> +}
> +addtask deploy after do_install
> --
> 2.29.2
>
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread