From: Zhongfu Luo Date: Thu, 17 May 2018 11:50:11 +0000 (+0800) Subject: defendkey: support secure upgrade check X-Git-Tag: khadas-vims-v0.9.6-release~2033 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e9b555745ad8dd4e7902c7e053ce33cf59e005aa;p=platform%2Fkernel%2Flinux-amlogic.git defendkey: support secure upgrade check PD#164929: G12A need to support defendkey Change-Id: I3c805c4dda03a39156fb91b53cc55ee8930f9e03 Signed-off-by: Zhongfu Luo --- diff --git a/MAINTAINERS b/MAINTAINERS index aade5105..bf67bb9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14451,3 +14451,6 @@ M: Jihong Sui F: drivers/amlogic/media/amldemod/* F: drivers/amlogic/media/dtv_demod/* +AMLOGIC DEFENDKEY DRIVER +M: Zhongfu Luo +F: drivers/amlogic/defendkey/* diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 8cdb8f9..1471ed4 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -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 diff --git a/drivers/amlogic/Kconfig b/drivers/amlogic/Kconfig index 1c66995..bbae04d 100644 --- a/drivers/amlogic/Kconfig +++ b/drivers/amlogic/Kconfig @@ -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 diff --git a/drivers/amlogic/Makefile b/drivers/amlogic/Makefile index fcc0523..fb12f96 100644 --- a/drivers/amlogic/Makefile +++ b/drivers/amlogic/Makefile @@ -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 index 0000000..6ae7eb4 --- /dev/null +++ b/drivers/amlogic/defendkey/Kconfig @@ -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 index 0000000..1c54c20 --- /dev/null +++ b/drivers/amlogic/defendkey/Makefile @@ -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 index 0000000..8bf3c46 --- /dev/null +++ b/drivers/amlogic/defendkey/defendkey.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 "); + + + diff --git a/drivers/amlogic/defendkey/securekey.c b/drivers/amlogic/defendkey/securekey.c new file mode 100644 index 0000000..1e9fbbb --- /dev/null +++ b/drivers/amlogic/defendkey/securekey.c @@ -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 +#include +/* #include */ +#include +#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 index 0000000..d55635b --- /dev/null +++ b/drivers/amlogic/defendkey/securekey.h @@ -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