diff mbox series

[v5,01/10] xen/arm: add generic TEE mediator framework

Message ID 20190521212530.12706-2-volodymyr_babchuk@epam.com (mailing list archive)
State Superseded
Headers show
Series TEE mediator (and OP-TEE) support in XEN | expand

Commit Message

Volodymyr Babchuk May 21, 2019, 9:25 p.m. UTC
This patch adds basic framework for TEE mediators. Guests can't talk
to TEE directly, we need some entity that will intercept request
and decide what to do with them. "TEE mediator" is a such entity.

This is how it works: user can build XEN with multiple TEE mediators
(see the next patches, where OP-TEE mediator is introduced).
TEE mediator register self with REGISTER_TEE_MEDIATOR() macro in the
same way, as device drivers use DT_DEVICE_START()/DT_DEVICE_END()
macros.

At run-time, during initialization, framework calls probe() function
for each available mediator driver to find which TEE is installed
on the platform. Then generic vSMC handler will call selected mediator
when it intercept SMC/HVC that belongs to TEE OS or TEE application.

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>

---

Changes from v4:
  - Added tee_get_type() function, which returns id of currently
    available TEE
  - Removed "dom0_tee_enabled" command line option. Dom0 now always
    uses currently available TEE.
  - Added TEE type sanity check in arch_sanitise_domain_config()
  - tee_domain_init() now internally checks if requested TEE type
    corresponds to available TEE
  - removed tee_domain_destroy() function because it is not used
    by anyone

Changes from v3:

  - tee_enable() renamed to tee_domain_init()
  - Added tee_relinquish_resources() function along with
    changes to domain_relinquish_resources()
  - Added command-line parameter dom0_tee_enabled, which controls
    if tee is enabled for Dom0. It is disabled by default
  - Instead of boolean tee state (enabled/disabled) I introduced
    enumeration with two values: none or native. It is possible
    to add other types of tee in the future

Changes from v2:
  - Removed empty tee/Kconfig file

 Changes from v1:
  - Removed tee_remove() function
  - CONFIG_TEE depends on EXPERT
  - tee_domain_created() converted to tee_enable()
  - tee_init() is called using initcall() mechanism
  - tee_handle_smc() renamed to tee_handle_call()

 Changes from "RFC" version:
  - renamed CONFIG_ARM_TEE to CONFIG_TEE
  - changed discovery mechanism: instead of UUID mathing, TEE-specific
     probing is used
---
 MAINTAINERS                   |   6 ++
 xen/arch/arm/Kconfig          |   7 +++
 xen/arch/arm/Makefile         |   1 +
 xen/arch/arm/domain.c         |  18 ++++++
 xen/arch/arm/setup.c          |   2 +
 xen/arch/arm/tee/Makefile     |   1 +
 xen/arch/arm/tee/tee.c        |  93 +++++++++++++++++++++++++++++
 xen/arch/arm/vsmc.c           |   5 ++
 xen/arch/arm/xen.lds.S        |   7 +++
 xen/include/asm-arm/domain.h  |   1 +
 xen/include/asm-arm/tee/tee.h | 109 ++++++++++++++++++++++++++++++++++
 xen/include/public/arch-arm.h |   3 +
 12 files changed, 253 insertions(+)
 create mode 100644 xen/arch/arm/tee/Makefile
 create mode 100644 xen/arch/arm/tee/tee.c
 create mode 100644 xen/include/asm-arm/tee/tee.h

Comments

Jan Beulich May 22, 2019, 8:45 a.m. UTC | #1
>>> On 21.05.19 at 23:25, <Volodymyr_Babchuk@epam.com> wrote:
>  MAINTAINERS                   |   6 ++
>  xen/arch/arm/Kconfig          |   7 +++
>  xen/arch/arm/Makefile         |   1 +
>  xen/arch/arm/domain.c         |  18 ++++++
>  xen/arch/arm/setup.c          |   2 +
>  xen/arch/arm/tee/Makefile     |   1 +
>  xen/arch/arm/tee/tee.c        |  93 +++++++++++++++++++++++++++++
>  xen/arch/arm/vsmc.c           |   5 ++
>  xen/arch/arm/xen.lds.S        |   7 +++
>  xen/include/asm-arm/domain.h  |   1 +
>  xen/include/asm-arm/tee/tee.h | 109 ++++++++++++++++++++++++++++++++++
>  xen/include/public/arch-arm.h |   3 +
>  12 files changed, 253 insertions(+)
>  create mode 100644 xen/arch/arm/tee/Makefile
>  create mode 100644 xen/arch/arm/tee/tee.c
>  create mode 100644 xen/include/asm-arm/tee/tee.h

I don't think I'm asking this for the first time: Why am I being Cc-ed
here? It's all Arm code that gets changed, and the MAINTAINERS
addition alone imo doesn't warrant widening the Cc list.

Jan
Julien Grall May 22, 2019, 9:27 a.m. UTC | #2
On 22/05/2019 09:45, Jan Beulich wrote:
>>>> On 21.05.19 at 23:25, <Volodymyr_Babchuk@epam.com> wrote:
>>   MAINTAINERS                   |   6 ++
>>   xen/arch/arm/Kconfig          |   7 +++
>>   xen/arch/arm/Makefile         |   1 +
>>   xen/arch/arm/domain.c         |  18 ++++++
>>   xen/arch/arm/setup.c          |   2 +
>>   xen/arch/arm/tee/Makefile     |   1 +
>>   xen/arch/arm/tee/tee.c        |  93 +++++++++++++++++++++++++++++
>>   xen/arch/arm/vsmc.c           |   5 ++
>>   xen/arch/arm/xen.lds.S        |   7 +++
>>   xen/include/asm-arm/domain.h  |   1 +
>>   xen/include/asm-arm/tee/tee.h | 109 ++++++++++++++++++++++++++++++++++
>>   xen/include/public/arch-arm.h |   3 +
>>   12 files changed, 253 insertions(+)
>>   create mode 100644 xen/arch/arm/tee/Makefile
>>   create mode 100644 xen/arch/arm/tee/tee.c
>>   create mode 100644 xen/include/asm-arm/tee/tee.h
> 
> I don't think I'm asking this for the first time: Why am I being Cc-ed
> here? It's all Arm code that gets changed, and the MAINTAINERS
> addition alone imo doesn't warrant widening the Cc list.

A lot of users uses the scripts/{add, get}_maintainers.pl to get the list of 
maintainers to CCed. Both of them output "THE REST" because of the file 
MAINTAINERS is modified.

I don't think it is sensible to expect users to know when to strip the list...

Cheers,
Jan Beulich May 22, 2019, 10:02 a.m. UTC | #3
>>> On 22.05.19 at 11:27, <julien.grall@arm.com> wrote:

> 
> On 22/05/2019 09:45, Jan Beulich wrote:
>>>>> On 21.05.19 at 23:25, <Volodymyr_Babchuk@epam.com> wrote:
>>>   MAINTAINERS                   |   6 ++
>>>   xen/arch/arm/Kconfig          |   7 +++
>>>   xen/arch/arm/Makefile         |   1 +
>>>   xen/arch/arm/domain.c         |  18 ++++++
>>>   xen/arch/arm/setup.c          |   2 +
>>>   xen/arch/arm/tee/Makefile     |   1 +
>>>   xen/arch/arm/tee/tee.c        |  93 +++++++++++++++++++++++++++++
>>>   xen/arch/arm/vsmc.c           |   5 ++
>>>   xen/arch/arm/xen.lds.S        |   7 +++
>>>   xen/include/asm-arm/domain.h  |   1 +
>>>   xen/include/asm-arm/tee/tee.h | 109 ++++++++++++++++++++++++++++++++++
>>>   xen/include/public/arch-arm.h |   3 +
>>>   12 files changed, 253 insertions(+)
>>>   create mode 100644 xen/arch/arm/tee/Makefile
>>>   create mode 100644 xen/arch/arm/tee/tee.c
>>>   create mode 100644 xen/include/asm-arm/tee/tee.h
>> 
>> I don't think I'm asking this for the first time: Why am I being Cc-ed
>> here? It's all Arm code that gets changed, and the MAINTAINERS
>> addition alone imo doesn't warrant widening the Cc list.
> 
> A lot of users uses the scripts/{add, get}_maintainers.pl to get the list of 
> 
> maintainers to CCed. Both of them output "THE REST" because of the file 
> MAINTAINERS is modified.
> 
> I don't think it is sensible to expect users to know when to strip the 
> list...

Hmm, well, I see your point, but I think applying some common sense
still can be expected. It's also not sensible for unrelated people to
get Cc-ed. I think anyone knowing enough to modify MAINTAINERS
can be expected to know whom to Cc.

Jan
Julien Grall May 22, 2019, 12:04 p.m. UTC | #4
Hi Jan,

On 22/05/2019 11:02, Jan Beulich wrote:
>>>> On 22.05.19 at 11:27, <julien.grall@arm.com> wrote:
> 
>>
>> On 22/05/2019 09:45, Jan Beulich wrote:
>>>>>> On 21.05.19 at 23:25, <Volodymyr_Babchuk@epam.com> wrote:
>>>>    MAINTAINERS                   |   6 ++
>>>>    xen/arch/arm/Kconfig          |   7 +++
>>>>    xen/arch/arm/Makefile         |   1 +
>>>>    xen/arch/arm/domain.c         |  18 ++++++
>>>>    xen/arch/arm/setup.c          |   2 +
>>>>    xen/arch/arm/tee/Makefile     |   1 +
>>>>    xen/arch/arm/tee/tee.c        |  93 +++++++++++++++++++++++++++++
>>>>    xen/arch/arm/vsmc.c           |   5 ++
>>>>    xen/arch/arm/xen.lds.S        |   7 +++
>>>>    xen/include/asm-arm/domain.h  |   1 +
>>>>    xen/include/asm-arm/tee/tee.h | 109 ++++++++++++++++++++++++++++++++++
>>>>    xen/include/public/arch-arm.h |   3 +
>>>>    12 files changed, 253 insertions(+)
>>>>    create mode 100644 xen/arch/arm/tee/Makefile
>>>>    create mode 100644 xen/arch/arm/tee/tee.c
>>>>    create mode 100644 xen/include/asm-arm/tee/tee.h
>>>
>>> I don't think I'm asking this for the first time: Why am I being Cc-ed
>>> here? It's all Arm code that gets changed, and the MAINTAINERS
>>> addition alone imo doesn't warrant widening the Cc list.
>>
>> A lot of users uses the scripts/{add, get}_maintainers.pl to get the list of
>>
>> maintainers to CCed. Both of them output "THE REST" because of the file
>> MAINTAINERS is modified.
>>
>> I don't think it is sensible to expect users to know when to strip the
>> list...
> 
> Hmm, well, I see your point, but I think applying some common sense
> still can be expected. It's also not sensible for unrelated people to
> get Cc-ed. I think anyone knowing enough to modify MAINTAINERS
> can be expected to know whom to Cc.

I disagree here, someone in "THE REST" may have an opinion in adding Volodymyr 
as a maintainer (this is only example).

This is a bit similar to when you send a patch to add a 3 lines timer helper in 
a common header but it is only used by x86. Even if I will not necessary answer 
on the patch because it does not impact Arm directly, I will still have a quick 
look to see if it makes sense.

Anyway, you can't expect the contributor to guess your will on MAINTAINERS. You 
should update the documentation/script if this is the expectation you have.

Cheers,
Julien Grall June 3, 2019, 11:46 a.m. UTC | #5
Hi Volodymyr,

On 21/05/2019 22:25, Volodymyr Babchuk wrote:
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index ccb0f181ea..1a240d208b 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -49,6 +49,7 @@
>   #include <asm/platform.h>
>   #include <asm/procinfo.h>
>   #include <asm/setup.h>
> +#include <asm/tee/tee.h>
>   #include <xsm/xsm.h>
>   #include <asm/acpi.h>
>   
> @@ -895,6 +896,7 @@ void __init start_xen(unsigned long boot_phys_offset,
>       dom0_cfg.arch.nr_spis = min(gic_number_lines(), (unsigned int) 992) - 32;
>       if ( gic_number_lines() > 992 )
>           printk(XENLOG_WARNING "Maximum number of vGIC IRQs exceeded.\n");
> +    dom0_cfg.arch.tee_type = tee_get_type();

I was expecting some code to generate/dropped the OP-TEE node in Dom0 DTB. For 
instance, we want to promote the use of "hvc" and not "smc".


>       dom0_cfg.max_vcpus = dom0_max_vcpus();
>   
>       dom0 = domain_create(0, &dom0_cfg, true);
> diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
> new file mode 100644
> index 0000000000..c54d4796ff
> --- /dev/null
> +++ b/xen/arch/arm/tee/Makefile
> @@ -0,0 +1 @@
> +obj-y += tee.o
> diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
> new file mode 100644
> index 0000000000..6bda846953
> --- /dev/null
> +++ b/xen/arch/arm/tee/tee.c
> @@ -0,0 +1,93 @@
> +/*
> + * xen/arch/arm/tee/tee.c
> + *
> + * Generic part of TEE mediator subsystem
> + *
> + * Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> + * Copyright (c) 2018-2019 EPAM Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/errno.h>
> +#include <xen/init.h>
> +#include <xen/types.h>
> +
> +#include <asm/tee/tee.h>
> +
> +extern const struct tee_mediator_desc _steemediator[], _eteemediator[];
> +static const struct tee_mediator_desc *cur_mediator;

NIT: You probably want a __read_mostly here.

Both changes can be done in follow-up:

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,
Julien Grall June 3, 2019, 11:48 a.m. UTC | #6
On 21/05/2019 22:25, Volodymyr Babchuk wrote:
> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
> index eb424e8286..5e938a91cc 100644
> --- a/xen/include/public/arch-arm.h
> +++ b/xen/include/public/arch-arm.h
> @@ -304,10 +304,13 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
>   #define XEN_DOMCTL_CONFIG_GIC_NATIVE    0
>   #define XEN_DOMCTL_CONFIG_GIC_V2        1
>   #define XEN_DOMCTL_CONFIG_GIC_V3        2

I forgot to mention the newline here. This would help to differentiate the two 
set of define.

I can add this one on commit.

Cheers,
Julien Grall June 6, 2019, 4:02 p.m. UTC | #7
Hi Volodymyr,

On 5/21/19 10:25 PM, Volodymyr Babchuk wrote:
> +static inline bool tee_handle_call(struct cpu_user_regs *regs)
> +{
> +    return false;
> +}
> +
> +static inline int tee_domain_init(struct domain *d, uint16_t tee_type)
> +{
> +    return -ENODEV;
> +}

I had a report that Xen fails to boot with this series and !CONFIG_TEE. 
This is because you return an error here in all the case some domain 
creation will always fail.

Instead this should check that tee_type is always NONE or else return an 
error.

Also, please at least check that your series does not break boot when 
CONFIG_TEE is not selected. It would also be ideal (but not mandatory) 
if you can check that it does not break on non-OPTEE platform when 
!CONFIG_TEE is selected.

Cheers,
Julien Grall June 7, 2019, 9:36 a.m. UTC | #8
On 06/06/2019 17:02, Julien Grall wrote:
> Hi Volodymyr,
> 
> On 5/21/19 10:25 PM, Volodymyr Babchuk wrote:
>> +static inline bool tee_handle_call(struct cpu_user_regs *regs)
>> +{
>> +    return false;
>> +}
>> +
>> +static inline int tee_domain_init(struct domain *d, uint16_t tee_type)
>> +{
>> +    return -ENODEV;
>> +}
> 
> I had a report that Xen fails to boot with this series and !CONFIG_TEE. This is 
> because you return an error here in all the case some domain creation will 
> always fail.
> 
> Instead this should check that tee_type is always NONE or else return an error.
> 
> Also, please at least check that your series does not break boot when CONFIG_TEE 
> is not selected. It would also be ideal (but not mandatory) if you can check 
> that it does not break on non-OPTEE platform when !CONFIG_TEE is selected.

I just realized this paragraph may not be clear. What I meant is we need to at 
least test there are no regression when booting when with CONFIG_TEE=n.

For CONFIG_TEE=y, it would be good to test that it still boots on platform not 
providing OP-TEE. This is not critical because the config cannot be selected 
without CONFIG_XEN_EXPERT=y.

Cheers,

> 
> Cheers,
>
Volodymyr Babchuk June 11, 2019, 6:18 p.m. UTC | #9
Hi Julien,

Julien Grall writes:

> On 06/06/2019 17:02, Julien Grall wrote:
>> Hi Volodymyr,
>>
>> On 5/21/19 10:25 PM, Volodymyr Babchuk wrote:
>>> +static inline bool tee_handle_call(struct cpu_user_regs *regs)
>>> +{
>>> + return false;
>>> +}
>>> +
>>> +static inline int tee_domain_init(struct domain *d, uint16_t tee_type)
>>> +{
>>> + return -ENODEV;
>>> +}
>>
>> I had a report that Xen fails to boot with this series and
>> !CONFIG_TEE. This is because you return an error here in all the
>> case some domain creation will always fail.
Thanks for reporting. I forgot to test that case :(

>> Instead this should check that tee_type is always NONE or else return an error.
>>
>> Also, please at least check that your series does not break boot
>> when CONFIG_TEE is not selected. It would also be ideal (but not
>> mandatory) if you can check that it does not break on non-OPTEE
>> platform when !CONFIG_TEE is selected.
>
> I just realized this paragraph may not be clear. What I meant is we
> need to at least test there are no regression when booting when with
> CONFIG_TEE=n.
>
> For CONFIG_TEE=y, it would be good to test that it still boots on
> platform not providing OP-TEE. This is not critical because the config
> cannot be selected without CONFIG_XEN_EXPERT=y.
I fixed CONFIG_TEE=n issue in the new version, which I'm going to send
later today.

Also I made optee_probe() (with CONFIG_OPTEE=y of course) to return
false to emulated platform without OP-TEE. System boots and works as
usual.

Also I addressed your other comments for this patch.

--
Best regards,Volodymyr Babchuk
Julien Grall June 11, 2019, 6:26 p.m. UTC | #10
On 11/06/2019 19:18, Volodymyr Babchuk wrote:
> 
> Hi Julien,

Hi,


> Julien Grall writes:
> 
>> On 06/06/2019 17:02, Julien Grall wrote:
>>> Hi Volodymyr,
>>>
>>> On 5/21/19 10:25 PM, Volodymyr Babchuk wrote:
>>>> +static inline bool tee_handle_call(struct cpu_user_regs *regs)
>>>> +{
>>>> + return false;
>>>> +}
>>>> +
>>>> +static inline int tee_domain_init(struct domain *d, uint16_t tee_type)
>>>> +{
>>>> + return -ENODEV;
>>>> +}
>>>
>>> I had a report that Xen fails to boot with this series and
>>> !CONFIG_TEE. This is because you return an error here in all the
>>> case some domain creation will always fail.
> Thanks for reporting. I forgot to test that case :(
> 
>>> Instead this should check that tee_type is always NONE or else return an error.
>>>
>>> Also, please at least check that your series does not break boot
>>> when CONFIG_TEE is not selected. It would also be ideal (but not
>>> mandatory) if you can check that it does not break on non-OPTEE
>>> platform when !CONFIG_TEE is selected.
>>
>> I just realized this paragraph may not be clear. What I meant is we
>> need to at least test there are no regression when booting when with
>> CONFIG_TEE=n.
>>
>> For CONFIG_TEE=y, it would be good to test that it still boots on
>> platform not providing OP-TEE. This is not critical because the config
>> cannot be selected without CONFIG_XEN_EXPERT=y.
> I fixed CONFIG_TEE=n issue in the new version, which I'm going to send
> later today.
> 
> Also I made optee_probe() (with CONFIG_OPTEE=y of course) to return
> false to emulated platform without OP-TEE. System boots and works as
> usual.
> 
> Also I addressed your other comments for this patch.

Thank you! I will have a look at the next version.

Cheers,
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index a208bbe304..17906b8321 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -385,6 +385,12 @@  F:	config/Stubdom.mk.in
 F:	m4/stubdom.m4
 F:	stubdom/
 
+TEE MEDIATORS
+M:	Volodymyr Babchuk <volodymyr_babchuk@epam.com>
+S:	Supported
+F:	xen/arch/arm/tee/
+F:	xen/include/asm-arm/tee
+
 TOOLSTACK
 M:	Ian Jackson <ian.jackson@eu.citrix.com>
 M:	Wei Liu <wei.liu2@citrix.com>
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 581de67b6b..e527b2f885 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -105,6 +105,13 @@  config HARDEN_BRANCH_PREDICTOR
 
 	  If unsure, say Y.
 
+config TEE
+	bool "Enable TEE mediators support" if EXPERT = "y"
+	default n
+	help
+	  This option enables generic TEE mediators support. It allows guests
+	  to access real TEE via one of TEE mediators implemented in XEN.
+
 endmenu
 
 menu "ARM errata workaround via the alternative framework"
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index cb902cb6fe..5c2aa34557 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -5,6 +5,7 @@  subdir-$(CONFIG_ACPI) += acpi
 ifneq ($(CONFIG_NO_PLAT),y)
 subdir-y += platforms
 endif
+subdir-$(CONFIG_TEE) += tee
 
 obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
 obj-y += bootfdt.init.o
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 6dc633ed50..0c8e50f48f 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -32,6 +32,7 @@ 
 #include <asm/platform.h>
 #include <asm/procinfo.h>
 #include <asm/regs.h>
+#include <asm/tee/tee.h>
 #include <asm/vfp.h>
 #include <asm/vgic.h>
 #include <asm/vtimer.h>
@@ -648,6 +649,12 @@  int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
+    if ( config->arch.tee_type != XEN_DOMCTL_CONFIG_TEE_NONE )
+    {
+        dprintk(XENLOG_INFO, "Unsupported TEE type\n");
+        return -EINVAL;
+    }
+
     return 0;
 }
 
@@ -705,6 +712,9 @@  int arch_domain_create(struct domain *d,
     if ( (rc = domain_vtimer_init(d, &config->arch)) != 0 )
         goto fail;
 
+    if ( (rc = tee_domain_init(d, config->arch.tee_type)) != 0 )
+        goto fail;
+
     update_domain_wallclock_time(d);
 
     /*
@@ -949,6 +959,14 @@  int domain_relinquish_resources(struct domain *d)
          */
         domain_vpl011_deinit(d);
 
+        d->arch.relmem = RELMEM_tee;
+        /* Fallthrough */
+
+    case RELMEM_tee:
+        ret = tee_relinquish_resources(d);
+        if (ret )
+            return ret;
+
         d->arch.relmem = RELMEM_xen;
         /* Fallthrough */
 
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index ccb0f181ea..1a240d208b 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -49,6 +49,7 @@ 
 #include <asm/platform.h>
 #include <asm/procinfo.h>
 #include <asm/setup.h>
+#include <asm/tee/tee.h>
 #include <xsm/xsm.h>
 #include <asm/acpi.h>
 
@@ -895,6 +896,7 @@  void __init start_xen(unsigned long boot_phys_offset,
     dom0_cfg.arch.nr_spis = min(gic_number_lines(), (unsigned int) 992) - 32;
     if ( gic_number_lines() > 992 )
         printk(XENLOG_WARNING "Maximum number of vGIC IRQs exceeded.\n");
+    dom0_cfg.arch.tee_type = tee_get_type();
     dom0_cfg.max_vcpus = dom0_max_vcpus();
 
     dom0 = domain_create(0, &dom0_cfg, true);
diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
new file mode 100644
index 0000000000..c54d4796ff
--- /dev/null
+++ b/xen/arch/arm/tee/Makefile
@@ -0,0 +1 @@ 
+obj-y += tee.o
diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
new file mode 100644
index 0000000000..6bda846953
--- /dev/null
+++ b/xen/arch/arm/tee/tee.c
@@ -0,0 +1,93 @@ 
+/*
+ * xen/arch/arm/tee/tee.c
+ *
+ * Generic part of TEE mediator subsystem
+ *
+ * Volodymyr Babchuk <volodymyr_babchuk@epam.com>
+ * Copyright (c) 2018-2019 EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/types.h>
+
+#include <asm/tee/tee.h>
+
+extern const struct tee_mediator_desc _steemediator[], _eteemediator[];
+static const struct tee_mediator_desc *cur_mediator;
+
+bool tee_handle_call(struct cpu_user_regs *regs)
+{
+    if ( unlikely(!cur_mediator) )
+        return false;
+
+    return cur_mediator->ops->handle_call(regs);
+}
+
+int tee_domain_init(struct domain *d, uint16_t tee_type)
+{
+    if ( tee_type == XEN_DOMCTL_CONFIG_TEE_NONE)
+        return 0;
+
+    if ( !cur_mediator )
+        return -ENODEV;
+
+    if ( cur_mediator->tee_type != tee_type )
+        return -EINVAL;
+
+    return cur_mediator->ops->domain_init(d);
+}
+
+int tee_relinquish_resources(struct domain *d)
+{
+    if ( !cur_mediator )
+        return 0;
+
+    return cur_mediator->ops->relinquish_resources(d);
+}
+
+uint16_t tee_get_type(void)
+{
+    if ( !cur_mediator )
+        return XEN_DOMCTL_CONFIG_TEE_NONE;
+
+    return cur_mediator->tee_type;
+}
+
+
+static int __init tee_init(void)
+{
+    const struct tee_mediator_desc *desc;
+
+    for ( desc = _steemediator; desc != _eteemediator; desc++ )
+    {
+        if ( desc->ops->probe() )
+        {
+            printk(XENLOG_INFO "Using TEE mediator for %s\n", desc->name);
+            cur_mediator = desc;
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+__initcall(tee_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vsmc.c b/xen/arch/arm/vsmc.c
index c72b9a04ff..f8e350311d 100644
--- a/xen/arch/arm/vsmc.c
+++ b/xen/arch/arm/vsmc.c
@@ -23,6 +23,7 @@ 
 #include <asm/monitor.h>
 #include <asm/regs.h>
 #include <asm/smccc.h>
+#include <asm/tee/tee.h>
 #include <asm/traps.h>
 #include <asm/vpsci.h>
 #include <asm/platform.h>
@@ -276,6 +277,10 @@  static bool vsmccc_handle_call(struct cpu_user_regs *regs)
         case ARM_SMCCC_OWNER_SIP:
             handled = platform_smc(regs);
             break;
+        case ARM_SMCCC_OWNER_TRUSTED_APP ... ARM_SMCCC_OWNER_TRUSTED_APP_END:
+        case ARM_SMCCC_OWNER_TRUSTED_OS ... ARM_SMCCC_OWNER_TRUSTED_OS_END:
+            handled = tee_handle_call(regs);
+            break;
         }
     }
 
diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
index 1e72906477..e664c4441a 100644
--- a/xen/arch/arm/xen.lds.S
+++ b/xen/arch/arm/xen.lds.S
@@ -137,6 +137,13 @@  SECTIONS
       _aedevice = .;
   } :text
 
+  . = ALIGN(8);
+  .teemediator.info : {
+      _steemediator = .;
+      *(.teemediator.info)
+      _eteemediator = .;
+  } :text
+
   . = ALIGN(PAGE_SIZE);             /* Init code and data */
   __init_begin = .;
   .init.text : {
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 312fec8932..0f15372098 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -58,6 +58,7 @@  struct arch_domain
     /* Continuable domain_relinquish_resources(). */
     enum {
         RELMEM_not_started,
+        RELMEM_tee,
         RELMEM_xen,
         RELMEM_page,
         RELMEM_mapping,
diff --git a/xen/include/asm-arm/tee/tee.h b/xen/include/asm-arm/tee/tee.h
new file mode 100644
index 0000000000..6eeefd4440
--- /dev/null
+++ b/xen/include/asm-arm/tee/tee.h
@@ -0,0 +1,109 @@ 
+/*
+ * xen/include/asm-arm/tee/tee.h
+ *
+ * Generic part of TEE mediator subsystem
+ *
+ * Volodymyr Babchuk <volodymyr_babchuk@epam.com>
+ * Copyright (c) 2018 EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_TEE_TEE_H__
+#define __ARCH_ARM_TEE_TEE_H__
+
+#include <xen/lib.h>
+#include <xen/types.h>
+
+#include <asm/regs.h>
+
+#ifdef CONFIG_TEE
+
+struct tee_mediator_ops {
+    /*
+     * Probe for TEE. Should return true if TEE found and
+     * mediator is initialized.
+     */
+    bool (*probe)(void);
+
+    /*
+     * Called during domain construction if toolstack requests to enable
+     * TEE support so mediator can inform TEE about new
+     * guest and create own structures for the new domain.
+     */
+    int (*domain_init)(struct domain *d);
+
+    /*
+     * Called during domain destruction to relinquish resources used
+     * by mediator itself. This function can return -ERESTART to indicate
+     * that it does not finished work and should be called again.
+     */
+    int (*relinquish_resources)(struct domain *d);
+
+    /* Handle SMCCC call for current domain. */
+    bool (*handle_call)(struct cpu_user_regs *regs);
+};
+
+struct tee_mediator_desc {
+    /* Printable name of the TEE. */
+    const char *name;
+
+    /* Mediator callbacks as described above. */
+    const struct tee_mediator_ops *ops;
+
+    /*
+     * ID of TEE. Corresponds to xen_arch_domainconfig.tee_type.
+     * Should be one of XEN_DOMCTL_CONFIG_TEE_xxx
+     */
+    uint16_t tee_type;
+};
+
+bool tee_handle_call(struct cpu_user_regs *regs);
+int tee_domain_init(struct domain *d, uint16_t tee_type);
+int tee_relinquish_resources(struct domain *d);
+uint16_t tee_get_type(void);
+
+#define REGISTER_TEE_MEDIATOR(_name, _namestr, _type, _ops)         \
+static const struct tee_mediator_desc __tee_desc_##_name __used     \
+__section(".teemediator.info") = {                                  \
+    .name = _namestr,                                               \
+    .ops = _ops,                                                    \
+    .tee_type = _type                                               \
+}
+
+#else
+
+static inline bool tee_handle_call(struct cpu_user_regs *regs)
+{
+    return false;
+}
+
+static inline int tee_domain_init(struct domain *d, uint16_t tee_type)
+{
+    return -ENODEV;
+}
+
+static inline int tee_relinquish_resources(struct domain *d)
+{
+    return 0;
+}
+
+static inline uint16_t tee_get_type(void)
+{
+    return XEN_DOMCTL_CONFIG_TEE_NONE;
+}
+
+#endif  /* CONFIG_TEE */
+
+#endif /* __ARCH_ARM_TEE_TEE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index eb424e8286..5e938a91cc 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -304,10 +304,13 @@  DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 #define XEN_DOMCTL_CONFIG_GIC_NATIVE    0
 #define XEN_DOMCTL_CONFIG_GIC_V2        1
 #define XEN_DOMCTL_CONFIG_GIC_V3        2
+#define XEN_DOMCTL_CONFIG_TEE_NONE      0
 struct xen_arch_domainconfig {
     /* IN/OUT */
     uint8_t gic_version;
     /* IN */
+    uint16_t tee_type;
+    /* IN */
     uint32_t nr_spis;
     /*
      * OUT