defendkey: support secure upgrade check
authorZhongfu Luo <zhongfu.luo@amlogic.com>
Thu, 17 May 2018 11:50:11 +0000 (19:50 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Fri, 18 May 2018 10:11:36 +0000 (03:11 -0700)
PD#164929: G12A need to support defendkey

Change-Id: I3c805c4dda03a39156fb91b53cc55ee8930f9e03
Signed-off-by: Zhongfu Luo <zhongfu.luo@amlogic.com>
MAINTAINERS
arch/arm64/configs/meson64_defconfig
drivers/amlogic/Kconfig
drivers/amlogic/Makefile
drivers/amlogic/defendkey/Kconfig [new file with mode: 0644]
drivers/amlogic/defendkey/Makefile [new file with mode: 0644]
drivers/amlogic/defendkey/defendkey.c [new file with mode: 0644]
drivers/amlogic/defendkey/securekey.c [new file with mode: 0644]
drivers/amlogic/defendkey/securekey.h [new file with mode: 0644]

index aade510..bf67bb9 100644 (file)
@@ -14451,3 +14451,6 @@ M:      Jihong Sui <jihong.sui@amlogic.com>
 F:      drivers/amlogic/media/amldemod/*
 F:      drivers/amlogic/media/dtv_demod/*
 
+AMLOGIC DEFENDKEY DRIVER
+M:     Zhongfu Luo <zhongfu.luo@amlogic.com>
+F:     drivers/amlogic/defendkey/*
index 8cdb8f9..1471ed4 100644 (file)
@@ -348,6 +348,7 @@ CONFIG_AMLOGIC_GPIO_IRQ=y
 CONFIG_AMLOGIC_ATV_DEMOD=y
 CONFIG_AMLOGIC_DEBUG=y
 CONFIG_AMLOGIC_DEBUG_LOCKUP=y
+CONFIG_AMLOGIC_DEFENDKEY=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
index 1c66995..bbae04d 100644 (file)
@@ -129,5 +129,8 @@ source "drivers/amlogic/irqchip/Kconfig"
 source "drivers/amlogic/atv_demod/Kconfig"
 
 source "drivers/amlogic/debug/Kconfig"
+
+source "drivers/amlogic/defendkey/Kconfig"
+
 endmenu
 endif
index fcc0523..fb12f96 100644 (file)
@@ -120,3 +120,5 @@ obj-$(CONFIG_AMLOGIC_GPIO_IRQ) += irqchip/
 obj-$(CONFIG_AMLOGIC_ATV_DEMOD) += atv_demod/
 
 obj-$(CONFIG_AMLOGIC_DEBUG) += debug/
+
+obj-$(CONFIG_AMLOGIC_DEFENDKEY) += defendkey/
diff --git a/drivers/amlogic/defendkey/Kconfig b/drivers/amlogic/defendkey/Kconfig
new file mode 100644 (file)
index 0000000..6ae7eb4
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# amlogic encrypt img judge
+#
+
+menu "Amlogic defend img file update support"
+
+config AMLOGIC_DEFENDKEY
+       bool "defend img update"
+       default n
+       help
+               defend update system for board, when system is encrypted, the system img
+               must be encrypted with same key in board
+
+endmenu
diff --git a/drivers/amlogic/defendkey/Makefile b/drivers/amlogic/defendkey/Makefile
new file mode 100644 (file)
index 0000000..1c54c20
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+#EXTRA_CFLAGS += -fno-common -w
+#ccflags-y += -I$(srctree)/drivers/amlogic/defendkey/include
+
+obj-$(CONFIG_AMLOGIC_DEFENDKEY) += defendkey.o securekey.o
+#obj-$(CONFIG_AMLOGIC_DEFENDKEY) += crypto/
+
+
+
diff --git a/drivers/amlogic/defendkey/defendkey.c b/drivers/amlogic/defendkey/defendkey.c
new file mode 100644 (file)
index 0000000..8bf3c46
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * drivers/amlogic/defendkey/defendkey.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/cdev.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/ioctl.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/dma-contiguous.h>
+#include <linux/dma-mapping.h>
+#include <linux/cma.h>
+#include <linux/io-mapping.h>
+#include <linux/sysfs.h>
+#include <asm/cacheflush.h>
+#include "securekey.h"
+
+#define DEFENDKEY_DEVICE_NAME  "defendkey"
+#define DEFENDKEY_CLASS_NAME "defendkey"
+void __iomem *mem_base_virt;
+unsigned long mem_size;
+unsigned long random_virt;
+
+enum e_defendkey_type {
+       e_upgrade_check = 0,
+       e_decrypt_dtb = 1,
+       e_decrypt_dtb_success = 2,
+};
+
+enum ret_defendkey {
+       ret_fail = 0,
+       ret_success = 1,
+       ret_error = -1,
+};
+
+struct defendkey_dev_t {
+       struct cdev cdev;
+       dev_t  devno;
+};
+
+static struct defendkey_dev_t *defendkey_devp;
+static enum e_defendkey_type decrypt_dtb;
+
+static int defendkey_open(struct inode *inode, struct file *file)
+{
+       struct defendkey_dev_t *devp;
+
+       devp = container_of(inode->i_cdev, struct defendkey_dev_t, cdev);
+       file->private_data = devp;
+       return 0;
+}
+static int defendkey_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static loff_t defendkey_llseek(struct file *filp, loff_t off, int whence)
+{
+       return 0;
+}
+
+static long defendkey_unlocked_ioctl(struct file *file,
+       unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long defendkey_compat_ioctl(struct file *filp,
+                             unsigned int cmd, unsigned long args)
+{
+       unsigned long ret;
+
+       args = (unsigned long)compat_ptr(args);
+       ret = defendkey_unlocked_ioctl(filp, cmd, args);
+
+       return ret;
+}
+#endif
+
+
+static ssize_t defendkey_read(struct file *file,
+       char __user *buf, size_t count, loff_t *ppos)
+{
+       int i, ret;
+       unsigned long copy_base, copy_size;
+
+       switch (decrypt_dtb) {
+       case e_upgrade_check:
+       case e_decrypt_dtb:
+               return ret_error;
+       case e_decrypt_dtb_success:
+       {
+               for (i = 0; i <= count/mem_size; i++) {
+                       copy_size = mem_size;
+                       copy_base = (unsigned long)buf+i*mem_size;
+                       if ((i+1)*mem_size > count)
+                               copy_size = count - mem_size*i;
+                       ret = copy_to_user((void __user *)copy_base,
+                               (const void *)mem_base_virt, copy_size);
+                       if (ret) {
+                               pr_err("%s:copy_to_user fail! ret:%d\n",
+                                       __func__, ret);
+                               return ret_fail;
+                       }
+               __dma_flush_area((const void *)mem_base_virt, copy_size);
+               }
+               if (!ret) {
+                       pr_info("%s: copy data to user successfully!\n",
+                               __func__);
+                       return ret_success;
+               }
+       }
+       default:
+               return ret_error;
+       }
+}
+
+static ssize_t defendkey_write(struct file *file,
+       const char __user *buf, size_t count, loff_t *ppos)
+{
+       ssize_t ret_value = ret_error;
+       int ret = -EINVAL;
+
+       unsigned long mem_base_phy, copy_base, copy_size, random;
+       unsigned long option = 0;
+       int i;
+
+       mem_base_phy = get_sharemem_info(GET_SHARE_MEM_INPUT_BASE);
+       mem_base_virt = phys_to_virt(mem_base_phy);
+
+       if (!mem_base_phy || !mem_size) {
+               pr_err("bad secure check memory!\nmem_base_phy:%lx,size:%lx\n",
+                       mem_base_phy, mem_size);
+               ret =  -EFAULT;
+               goto exit;
+       }
+       pr_info("defendkey: mem_base_phy:%lx mem_size:%lx mem_base_virt:%p\n",
+               mem_base_phy, mem_size, mem_base_virt);
+
+       random = readl((void *)random_virt);
+
+       for (i = 0; i <= count/mem_size; i++) {
+               copy_size = mem_size;
+               copy_base = (unsigned long)buf+i*mem_size;
+               if ((i+1)*mem_size > count)
+                       copy_size = count - mem_size*i;
+               ret = copy_from_user(mem_base_virt,
+                       (const void __user *)copy_base, copy_size);
+               if (ret) {
+                       pr_err("defendkey:copy_from_user fail! ret:%d\n", ret);
+                       ret =  -EFAULT;
+                       goto exit;
+               }
+               __dma_flush_area((const void *)mem_base_virt, copy_size);
+
+               if (i == 0) {
+                       option = 1;
+                       if (count <= mem_size) {
+                               /*just transfer data to BL31 one time*/
+                               option = 1|2|4;
+                       }
+                       option |= (random<<32);
+               } else if ((i > 0) && (i < (count/mem_size))) {
+                       option = 2|(random<<32);
+                       if ((count%mem_size == 0) &&
+                               (i == (count/mem_size - 1)))
+                               option = 4|(random<<32);
+               } else if (i == (count/mem_size)) {
+                       if (count%mem_size != 0)
+                               option = 4|(random<<32);
+                       else
+                               break;
+               }
+               pr_info("defendkey:%d: copy_size:0x%lx, option:0x%lx\n",
+                       __LINE__, copy_size, option);
+               pr_info("decrypt_dtb: %d\n", decrypt_dtb);
+               if (e_decrypt_dtb == decrypt_dtb)
+                       ret = aml_sec_boot_check(AML_D_P_IMG_DECRYPT,
+                               mem_base_phy, copy_size, 0); /*option: 0: dtb*/
+               else if (e_upgrade_check == decrypt_dtb)
+                       ret = aml_sec_boot_check(AML_D_P_UPGRADE_CHECK,
+                               mem_base_phy, copy_size, option);
+               else {
+                       ret = -1;
+                       pr_err("%s: decrypt_dtb: %d,", __func__, decrypt_dtb);
+                       pr_err("not for upgrade check and decrypt_dtb\n");
+               }
+               if (ret) {
+                       ret_value = ret_fail;
+                       pr_err("defendkey: aml_sec_boot_check error,");
+                       pr_err(" %s:%d: ret %d %s\n", __func__, __LINE__,
+                               ret, decrypt_dtb ? ": for decrypt dtb":"\n");
+                       goto exit;
+               }
+       }
+
+       if (!ret) {
+               if (decrypt_dtb) {
+                       decrypt_dtb = e_decrypt_dtb_success;
+                       pr_info("defendkey: aml_sec_boot_check decrypt dtb ok!\n");
+               } else {
+                       pr_info("defendkey: aml_sec_boot_check ok!\n");
+               }
+               ret_value = ret_success;
+       }
+exit:
+       return ret_value;
+}
+
+static ssize_t version_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+
+       return sprintf(buf, "version:2.00\n");
+}
+
+static ssize_t secure_check_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       ssize_t n = 0;
+       int ret;
+
+       ret = aml_is_secure_set();
+       if (ret < 0)
+               n = sprintf(buf, "fail");
+       else if (ret == 0)
+               n = sprintf(buf, "raw");
+       else if (ret > 0)
+               n = sprintf(buf, "encrypt");
+
+       return n;
+}
+
+static ssize_t secure_verify_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       return 0;
+}
+
+static ssize_t decrypt_dtb_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       /* show lock state. */
+       return sprintf(buf, "%d\n", decrypt_dtb);
+}
+
+static ssize_t decrypt_dtb_store(struct class *cla,
+       struct class_attribute *attr, const char *buf, size_t count)
+{
+       unsigned int len;
+       /* check '\n' and del */
+       if (buf[count - 1] == '\n')
+               len = count - 1;
+       else
+               len = count;
+
+       if (!strncmp(buf, "1", len)) {
+               //decrypt_dtb = 1;
+               pr_info("current BL31 share memory size not support decrypt_dtb\n");
+       } else if (!strncmp(buf, "0", len))
+               decrypt_dtb = 0;
+       else {
+               pr_info("set defendkey decrypt_dtb fail,invalid value\n");
+       }
+
+       return count;
+}
+
+static const struct file_operations defendkey_fops = {
+       .owner      = THIS_MODULE,
+       .llseek     = defendkey_llseek,
+       .open       = defendkey_open,
+       .release    = defendkey_release,
+       .read       = defendkey_read,
+       .write      = defendkey_write,
+       .unlocked_ioctl      = defendkey_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = defendkey_compat_ioctl,
+#endif
+};
+
+static struct class_attribute defendkey_class_attrs[] = {
+       __ATTR_RO(version),
+       __ATTR_RO(secure_check),
+       __ATTR_RO(secure_verify),
+       __ATTR(decrypt_dtb, (0700), decrypt_dtb_show, decrypt_dtb_store),
+       __ATTR_NULL
+};
+static struct class defendkey_class = {
+       .name = DEFENDKEY_CLASS_NAME,
+       .class_attrs = defendkey_class_attrs,
+};
+
+static int aml_defendkey_probe(struct platform_device *pdev)
+{
+       int ret =  -1;
+       u64 val64;
+       struct resource *res;
+
+       struct device *devp;
+
+       defendkey_devp = devm_kzalloc(&(pdev->dev),
+               sizeof(struct defendkey_dev_t), GFP_KERNEL);
+       if (!defendkey_devp) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "defendkey: failed to allocate memory\n ");
+               goto out;
+       }
+
+       ret = of_property_read_u64(pdev->dev.of_node, "mem_size", &val64);
+       if (ret) {
+               dev_err(&pdev->dev, "please config mem_size in dts\n");
+               goto error1;
+       }
+       mem_size = val64;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (IS_ERR(res)) {
+               dev_err(&pdev->dev, "reg: cannot obtain I/O memory region");
+               ret = PTR_ERR(res);
+               goto error1;
+       }
+
+       random_virt = (unsigned long)devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR((void *)random_virt)) {
+               ret = PTR_ERR((void *)random_virt);
+               goto error1;
+       }
+
+       ret = alloc_chrdev_region(&defendkey_devp->devno, 0, 1,
+               DEFENDKEY_DEVICE_NAME);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "defendkey: failed to allocate major number\n ");
+               ret = -ENODEV;
+               goto error1;
+       }
+       dev_info(&pdev->dev, "defendkey_devno:%x\n", defendkey_devp->devno);
+       ret = class_register(&defendkey_class);
+       if (ret) {
+               dev_err(&pdev->dev, "defendkey: failed to register class\n ");
+               goto error2;
+       }
+
+       /* connect the file operations with cdev */
+       cdev_init(&defendkey_devp->cdev, &defendkey_fops);
+       defendkey_devp->cdev.owner = THIS_MODULE;
+       /* connect the major/minor number to the cdev */
+       ret = cdev_add(&defendkey_devp->cdev, defendkey_devp->devno, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "defendkey: failed to add device\n");
+               goto error3;
+       }
+       devp = device_create(&defendkey_class, NULL, defendkey_devp->devno,
+               NULL, DEFENDKEY_DEVICE_NAME);
+       if (IS_ERR(devp)) {
+               dev_err(&pdev->dev, "defendkey: failed to create device node\n");
+               ret = PTR_ERR(devp);
+               goto error4;
+       }
+
+
+       dev_info(&pdev->dev, "defendkey: device %s created ok\n",
+                       DEFENDKEY_DEVICE_NAME);
+       return 0;
+
+error4:
+       cdev_del(&defendkey_devp->cdev);
+error3:
+       class_unregister(&defendkey_class);
+error2:
+       unregister_chrdev_region(defendkey_devp->devno, 1);
+error1:
+       devm_kfree(&(pdev->dev), defendkey_devp);
+out:
+       return ret;
+}
+
+static int aml_defendkey_remove(struct platform_device *pdev)
+{
+       unregister_chrdev_region(defendkey_devp->devno, 1);
+       device_destroy(&defendkey_class, defendkey_devp->devno);
+       cdev_del(&defendkey_devp->cdev);
+       class_unregister(&defendkey_class);
+       return 0;
+}
+
+static const struct of_device_id meson_defendkey_dt_match[] = {
+       {       .compatible = "amlogic, defendkey",
+       },
+       {},
+};
+
+static struct platform_driver aml_defendkey_driver = {
+       .probe = aml_defendkey_probe,
+       .remove = aml_defendkey_remove,
+       .driver = {
+               .name = DEFENDKEY_DEVICE_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = meson_defendkey_dt_match,
+       },
+};
+
+module_platform_driver(aml_defendkey_driver);
+
+
+MODULE_DESCRIPTION("AMLOGIC defendkey driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("benlong zhou <benlong.zhou@amlogic.com>");
+
+
+
diff --git a/drivers/amlogic/defendkey/securekey.c b/drivers/amlogic/defendkey/securekey.c
new file mode 100644 (file)
index 0000000..1e9fbbb
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * drivers/amlogic/defendkey/securekey.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/types.h>
+#include <linux/slab.h>
+/* #include <asm/compiler.h> */
+#include <linux/amlogic/iomap.h>
+#include "securekey.h"
+
+#ifdef CONFIG_ARM64
+#define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
+
+int aml_is_secure_set(void)
+{
+       int ret;
+
+       /*AO_SEC_SD_CFG10: bit4 secure boot enable*/
+       ret = (aml_read_aobus(0x228)>>4)&0x1;
+
+       return ret;
+}
+
+long get_sharemem_info(unsigned long function_id)
+{
+       asm volatile(
+               __asmeq("%0", "x0")
+               "smc    #0\n"
+               : "+r" (function_id));
+
+       return function_id;
+}
+
+unsigned long aml_sec_boot_check(unsigned long nType,
+       unsigned long pBuffer,
+       unsigned long nLength,
+       unsigned long nOption)
+{
+       uint64_t ret = 1;
+
+       register uint64_t x0 asm("x0");
+       register uint64_t x1 asm("x1");
+       register uint64_t x2 asm("x2");
+       register uint64_t x3 asm("x3");
+       register uint64_t x4 asm("x4");
+
+       asm __volatile__("" : : : "memory");
+
+       x0 = AML_DATA_PROCESS;
+       x1 = nType;
+       x2 = pBuffer;
+       x3 = nLength;
+       x4 = nOption;
+
+       do {
+               asm volatile(
+                       __asmeq("%0", "x0")
+                       __asmeq("%1", "x0")
+                       __asmeq("%2", "x1")
+                       __asmeq("%3", "x2")
+                       __asmeq("%4", "x3")
+                       __asmeq("%5", "x4")
+                   "smc #0\n"
+                   : "=r"(x0)
+                   : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4));
+       } while (0);
+
+       ret = x0;
+
+       return ret;
+
+}
+#endif
diff --git a/drivers/amlogic/defendkey/securekey.h b/drivers/amlogic/defendkey/securekey.h
new file mode 100644 (file)
index 0000000..d55635b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * drivers/amlogic/defendkey/securekey.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifdef CONFIG_ARM64
+#define AML_D_P_UPGRADE_CHECK   (0x80)
+#define AML_D_P_IMG_DECRYPT     (0x40)
+#define AML_DATA_PROCESS               (0x820000FF)
+#define GET_SHARE_MEM_INPUT_BASE       0x82000020
+
+long get_sharemem_info(unsigned long function_id);
+
+int aml_is_secure_set(void);
+unsigned long aml_sec_boot_check(unsigned long nType,
+       unsigned long pBuffer,
+       unsigned long nLength,
+       unsigned long nOption);
+#endif