trusty: Add trusty driver
Arve Hjønnevåg [Tue, 19 Nov 2013 04:46:48 +0000 (20:46 -0800)]
Bug 1818826

Change-Id: I35318be3d41f84b922397e9afdca6bf47d9645db
Signed-off-by: Arve Hjønnevåg <arve@android.com>
(cherry picked from commit 33dbf3395558ad97cf65770235d8dfe90b33345f from https://android.googlesource.com/kernel/common/+/android-trusty-3.10)
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-on: http://git-master/r/1255781
(cherry picked from commit 45bf2e74d512c0c6260094274be99f5635c3b57e in dev-kernel-3.10)
Reviewed-on: http://git-master/r/1256406
GVS: Gerrit_Virtual_Submit
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>

Documentation/devicetree/bindings/trusty/trusty-smc.txt [new file with mode: 0644]
drivers/Kconfig
drivers/Makefile
drivers/trusty/Kconfig [new file with mode: 0644]
drivers/trusty/Makefile [new file with mode: 0644]
drivers/trusty/trusty.c [new file with mode: 0644]
include/linux/trusty/sm_err.h [new file with mode: 0644]
include/linux/trusty/smcall.h [new file with mode: 0644]
include/linux/trusty/trusty.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/trusty/trusty-smc.txt b/Documentation/devicetree/bindings/trusty/trusty-smc.txt
new file mode 100644 (file)
index 0000000..1b39ad3
--- /dev/null
@@ -0,0 +1,6 @@
+Trusty smc interface
+
+Trusty is running in secure mode on the same (arm) cpu(s) as the current os.
+
+Required properties:
+- compatible: "android,trusty-smc-v1"
index cbde498..c7b32cf 100644 (file)
@@ -74,6 +74,8 @@ source "drivers/hwmon/Kconfig"
 
 source "drivers/thermal/Kconfig"
 
+source "drivers/trusty/Kconfig"
+
 source "drivers/watchdog/Kconfig"
 
 source "drivers/ssb/Kconfig"
index cb2a03c..ad25ff0 100644 (file)
@@ -107,6 +107,7 @@ obj-$(CONFIG_STAGING)               += staging/
 obj-$(CONFIG_POWER_SUPPLY)     += power/
 obj-$(CONFIG_HWMON)            += hwmon/
 obj-$(CONFIG_THERMAL)          += thermal/
+obj-$(CONFIG_TRUSTY)           += trusty/
 obj-$(CONFIG_WATCHDOG)         += watchdog/
 obj-$(CONFIG_MD)               += md/
 obj-$(CONFIG_BT)               += bluetooth/
diff --git a/drivers/trusty/Kconfig b/drivers/trusty/Kconfig
new file mode 100644 (file)
index 0000000..f577ae8
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Trusty
+#
+
+menu "Trusty"
+
+config TRUSTY
+       tristate "Trusty"
+       default n
+
+endmenu
diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile
new file mode 100644 (file)
index 0000000..1d77805
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for trusty components
+#
+
+obj-$(CONFIG_TRUSTY)           += trusty.o
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
new file mode 100644 (file)
index 0000000..9667fe8
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/trusty/smcall.h>
+#include <linux/trusty/sm_err.h>
+#include <linux/trusty/trusty.h>
+
+struct trusty_state {
+       struct mutex smc_lock;
+};
+
+static inline u32 smc(u32 r0, u32 r1, u32 r2, u32 r3)
+{
+       register u32 _r0 asm("r0") = r0;
+       register u32 _r1 asm("r1") = r1;
+       register u32 _r2 asm("r2") = r2;
+       register u32 _r3 asm("r3") = r3;
+
+       asm volatile(
+               __asmeq("%0", "r0")
+               __asmeq("%1", "r1")
+               __asmeq("%2", "r2")
+               __asmeq("%3", "r3")
+               __asmeq("%4", "r0")
+               __asmeq("%5", "r1")
+               __asmeq("%6", "r2")
+               __asmeq("%7", "r3")
+               ".arch_extension sec\n"
+               "smc    #0      @ switch to secure world\n"
+               : "=r" (_r0), "=r" (_r1), "=r" (_r2), "=r" (_r3)
+               : "r" (_r0), "r" (_r1), "r" (_r2), "r" (_r3)
+               : "ip");
+       return _r0;
+}
+
+s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
+{
+       struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+
+       BUG_ON(!s);
+       BUG_ON(!SMC_IS_FASTCALL(smcnr));
+
+       return smc(smcnr, a0, a1, a2);
+}
+EXPORT_SYMBOL(trusty_fast_call32);
+
+s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
+{
+       int ret;
+       struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+
+       BUG_ON(SMC_IS_FASTCALL(smcnr));
+
+       mutex_lock(&s->smc_lock);
+
+       dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) started\n",
+               __func__, smcnr, a0, a1, a2);
+       ret = smc(smcnr, a0, a1, a2);
+
+       while (ret == SM_ERR_INTERRUPTED) {
+               dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) interrupted\n",
+                       __func__, smcnr, a0, a1, a2);
+               ret = smc(SMC_SC_RESTART_LAST, 0, 0, 0);
+       }
+       dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n",
+               __func__, smcnr, a0, a1, a2, ret);
+
+       mutex_unlock(&s->smc_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(trusty_std_call32);
+
+static int trusty_remove_child(struct device *dev, void *data)
+{
+       platform_device_unregister(to_platform_device(dev));
+       return 0;
+}
+
+static int trusty_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct trusty_state *s;
+       struct device_node *node = pdev->dev.of_node;
+
+       if (!node) {
+               dev_err(&pdev->dev, "of_node required\n");
+               return -EINVAL;
+       }
+
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s) {
+               ret = -ENOMEM;
+               goto err_allocate_state;
+       }
+       mutex_init(&s->smc_lock);
+       platform_set_drvdata(pdev, s);
+
+       ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to add children: %d\n", ret);
+               goto err_add_children;
+       }
+
+       return 0;
+
+err_add_children:
+       device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
+       mutex_destroy(&s->smc_lock);
+       kfree(s);
+err_allocate_state:
+       return ret;
+}
+
+static int trusty_remove(struct platform_device *pdev)
+{
+       struct trusty_state *s = platform_get_drvdata(pdev);
+
+       device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
+       mutex_destroy(&s->smc_lock);
+       kfree(s);
+       return 0;
+}
+
+static const struct of_device_id trusty_of_match[] = {
+       { .compatible = "android,trusty-smc-v1", },
+       {},
+};
+
+static struct platform_driver trusty_driver = {
+       .probe = trusty_probe,
+       .remove = trusty_remove,
+       .driver = {
+               .name = "trusty",
+               .owner = THIS_MODULE,
+               .of_match_table = trusty_of_match,
+       },
+};
+
+module_platform_driver(trusty_driver);
diff --git a/include/linux/trusty/sm_err.h b/include/linux/trusty/sm_err.h
new file mode 100644 (file)
index 0000000..91e9748
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Google Inc. All rights reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LINUX_TRUSTY_SM_ERR_H
+#define __LINUX_TRUSTY_SM_ERR_H
+
+/* Errors from the secure monitor */
+#define SM_ERR_UNDEFINED_SMC           0xFFFFFFFF /* Unknown SMC (defined by ARM DEN 0028A(0.9.0) */
+#define SM_ERR_INVALID_PARAMETERS      -2
+#define SM_ERR_INTERRUPTED             -3      /* Got interrupted. Call back with restart SMC */
+#define SM_ERR_UNEXPECTED_RESTART      -4      /* Got an restart SMC when we didn't expect it */
+#define SM_ERR_BUSY                    -5      /* Temporarily busy. Call back with original args */
+#define SM_ERR_INTERLEAVED_SMC         -6      /* Got a trusted_service SMC when a restart SMC is required */
+#define SM_ERR_INTERNAL_FAILURE                -7      /* Unknown error */
+#define SM_ERR_NOT_SUPPORTED           -8
+#define SM_ERR_NOT_ALLOWED             -9      /* SMC call not allowed */
+#define SM_ERR_END_OF_INPUT            -10
+
+#endif
diff --git a/include/linux/trusty/smcall.h b/include/linux/trusty/smcall.h
new file mode 100644 (file)
index 0000000..5b15348
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Google Inc. All rights reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LINUX_TRUSTY_SMCALL_H
+#define __LINUX_TRUSTY_SMCALL_H
+
+#define SMC_NUM_ENTITIES       64
+#define SMC_NUM_ARGS           4
+#define SMC_NUM_PARAMS         (SMC_NUM_ARGS - 1)
+
+#define SMC_IS_FASTCALL(smc_nr)        ((smc_nr) & 0x80000000)
+#define SMC_ENTITY(smc_nr)     (((smc_nr) & 0x3F000000) >> 24)
+#define SMC_FUNCTION(smc_nr)   ((smc_nr) & 0x0000FFFF)
+
+#define SMC_NR(entity, fn, fastcall) ( (((fastcall) & 0x1) << 31) | \
+                                       (((entity) & 0x3F) << 24) | \
+                                       ((fn) & 0xFFFF) \
+                                    )
+
+#define SMC_FASTCALL_NR(entity, fn)    SMC_NR((entity), (fn), 1)
+#define SMC_STDCALL_NR(entity, fn)     SMC_NR((entity), (fn), 0)
+
+#define        SMC_ENTITY_ARCH                 0       /* ARM Architecture calls */
+#define        SMC_ENTITY_CPU                  1       /* CPU Service calls */
+#define        SMC_ENTITY_SIP                  2       /* SIP Service calls */
+#define        SMC_ENTITY_OEM                  3       /* OEM Service calls */
+#define        SMC_ENTITY_STD                  4       /* Standard Service calls */
+#define        SMC_ENTITY_RESERVED             5       /* Reserved for future use */
+#define        SMC_ENTITY_TRUSTED_APP          48      /* Trusted Application calls */
+#define        SMC_ENTITY_TRUSTED_OS           50      /* Trusted OS calls */
+#define        SMC_ENTITY_SECURE_MONITOR       60      /* Trusted OS calls internal to secure monitor */
+
+/* FC = Fast call, SC = Standard call */
+#define SMC_SC_RESTART_LAST    SMC_STDCALL_NR  (SMC_ENTITY_SECURE_MONITOR, 0)
+#define SMC_SC_NOP             SMC_STDCALL_NR  (SMC_ENTITY_SECURE_MONITOR, 1)
+
+#define SMC_FC_GO_NONSECURE    SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0)
+#define SMC_FC_FIQ_EXIT                SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1)
+#define SMC_FC_REQUEST_FIQ     SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2)
+#define SMC_FC_GET_NEXT_IRQ    SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3)
+
+#endif /* __LINUX_TRUSTY_SMCALL_H */
diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h
new file mode 100644 (file)
index 0000000..58b23c2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_TRUSTY_TRUSTY_H
+#define __LINUX_TRUSTY_TRUSTY_H
+
+#include <linux/kernel.h>
+
+s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2);
+s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2);
+
+#endif