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
