From c32c62408c5e2dbd946e91bf2cf61c2db7d99fd9 Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Tue, 21 Feb 2017 14:58:52 +0800 Subject: [PATCH] securitykey: add securitykey. PD#138714: securitykey: add securitykey driver. Change-Id: Id897a9f5da3738d22613f2424aa06c8a5dc40801 Signed-off-by: Yan Wang --- MAINTAINERS | 7 + arch/arm64/boot/dts/amlogic/mesongxl.dtsi | 19 ++ arch/arm64/boot/dts/amlogic/mesongxm.dtsi | 19 ++ arch/arm64/configs/meson64_defconfig | 11 +- drivers/amlogic/Kconfig | 2 + drivers/amlogic/Makefile | 2 + drivers/amlogic/securitykey/Kconfig | 7 + drivers/amlogic/securitykey/Makefile | 4 + drivers/amlogic/securitykey/securitykey.c | 373 ++++++++++++++++++++++ include/linux/amlogic/security_key.h | 40 +++ 10 files changed, 479 insertions(+), 5 deletions(-) create mode 100644 drivers/amlogic/securitykey/Kconfig create mode 100644 drivers/amlogic/securitykey/Makefile create mode 100644 drivers/amlogic/securitykey/securitykey.c create mode 100644 include/linux/amlogic/security_key.h diff --git a/MAINTAINERS b/MAINTAINERS index efb3050edee0..e400308df2c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13632,3 +13632,10 @@ F: drivers/amlogic/smartcard/smartcard.h F: drivers/amlogic/smartcard/smc_reg.h F: include/linux/amlogic/amsmc.h F: Documentation/devicetree/bindings/amlogic/amlogic-smartcard.txt + +AMLOGIC securitykey +M: Yan Wang +F: drivers\amlogic\securitykey\Kconfig +F: drivers\amlogic\securitykey\Makefile +F: drivers\amlogic\securitykey\securitykey.c +F: include\linux\amlogic\security_key.h diff --git a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi index ce9f510533d3..db97b498b87a 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi @@ -162,6 +162,25 @@ out_base_func = <0x82000021>; }; + securitykey { + compatible = "aml, securitykey"; + storage_query = <0x82000060>; + storage_read = <0x82000061>; + storage_write = <0x82000062>; + storage_tell = <0x82000063>; + storage_verify = <0x82000064>; + storage_status = <0x82000065>; + storage_list = <0x82000067>; + storage_remove = <0x82000068>; + storage_in_func = <0x82000023>; + storage_out_func = <0x82000024>; + storage_block_func = <0x82000025>; + storage_size_func = <0x82000027>; + storage_set_enctype = <0x8200006A>; + storage_get_enctype = <0x8200006B>; + storage_version = <0x8200006C>; + }; + cpu_iomap{ compatible = "amlogic, iomap"; #address-cells=<2>; diff --git a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi index 22955e3cc1a1..2a0a6592b610 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi @@ -215,6 +215,25 @@ out_base_func = <0x82000021>; }; + securitykey { + compatible = "aml, securitykey"; + storage_query = <0x82000060>; + storage_read = <0x82000061>; + storage_write = <0x82000062>; + storage_tell = <0x82000063>; + storage_verify = <0x82000064>; + storage_status = <0x82000065>; + storage_list = <0x82000067>; + storage_remove = <0x82000068>; + storage_in_func = <0x82000023>; + storage_out_func = <0x82000024>; + storage_block_func = <0x82000025>; + storage_size_func = <0x82000027>; + storage_set_enctype = <0x8200006A>; + storage_get_enctype = <0x8200006B>; + storage_version = <0x8200006C>; + }; + cpu_iomap{ compatible = "amlogic, iomap"; #address-cells=<2>; diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index c4e796009d7d..52a6e70f7147 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -170,7 +170,6 @@ CONFIG_AMLOGIC_I2C_MASTER=y CONFIG_AMLOGIC_SEC=y CONFIG_AMLOGIC_CPU_VERSION=y CONFIG_AMLOGIC_MESON64_VERSION=y -CONFIG_AMLOGIC_MEDIA_DEINTERLACE=y CONFIG_AMLOGIC_CPU_INFO=y CONFIG_AMLOGIC_MHU_MBOX=y CONFIG_AMLOGIC_REG_ACCESS=y @@ -200,10 +199,6 @@ CONFIG_AMLOGIC_MEDIA_GE2D=y CONFIG_AMLOGIC_ION=y CONFIG_AMLOGIC_MEDIA_RDMA=y CONFIG_AMLOGIC_MEDIA_VFM=y -CONFIG_AMLOGIC_MEDIA_VIN=y -CONFIG_AMLOGIC_MEDIA_TVIN=y -CONFIG_AMLOGIC_MEDIA_VDIN=y -CONFIG_AMLOGIC_MEDIA_VIUIN=y CONFIG_AMLOGIC_VPU=y CONFIG_AMLOGIC_VOUT=y CONFIG_AMLOGIC_VOUT_SERVE=y @@ -215,9 +210,15 @@ CONFIG_AMLOGIC_MEDIA_FB=y CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA=y CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE=y CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR=y +CONFIG_AMLOGIC_MEDIA_DEINTERLACE=y +CONFIG_AMLOGIC_MEDIA_VIN=y +CONFIG_AMLOGIC_MEDIA_TVIN=y +CONFIG_AMLOGIC_MEDIA_VDIN=y +CONFIG_AMLOGIC_MEDIA_VIUIN=y CONFIG_AMLOGIC_MMC=y CONFIG_AMLOGIC_VRTC=y CONFIG_AMLOGIC_SMARTCARD=y +CONFIG_AMLOGIC_SECURITY_KEY=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 0219be6ea3d2..fe04b704b4c4 100644 --- a/drivers/amlogic/Kconfig +++ b/drivers/amlogic/Kconfig @@ -59,5 +59,7 @@ source "drivers/amlogic/smartcard/Kconfig" source "drivers/amlogic/cec/Kconfig" +source "drivers/amlogic/securitykey/Kconfig" + endmenu endif diff --git a/drivers/amlogic/Makefile b/drivers/amlogic/Makefile index 87103fb13414..ea4b612902c2 100644 --- a/drivers/amlogic/Makefile +++ b/drivers/amlogic/Makefile @@ -55,3 +55,5 @@ obj-$(CONFIG_AMLOGIC_SMARTCARD) += smartcard/ obj-$(CONFIG_AMLOGIC_AO_CEC) += cec/ +obj-$(CONFIG_AMLOGIC_SECURITY_KEY) += securitykey/ + diff --git a/drivers/amlogic/securitykey/Kconfig b/drivers/amlogic/securitykey/Kconfig new file mode 100644 index 000000000000..64783489b4c3 --- /dev/null +++ b/drivers/amlogic/securitykey/Kconfig @@ -0,0 +1,7 @@ +# Amlogic security key driver + + +config AMLOGIC_SECURITY_KEY + bool "Amlogic security key driver support" + help + This is the Amlogic security key driver diff --git a/drivers/amlogic/securitykey/Makefile b/drivers/amlogic/securitykey/Makefile new file mode 100644 index 000000000000..72f5fae93a74 --- /dev/null +++ b/drivers/amlogic/securitykey/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for Security key. +# +obj-$(CONFIG_AMLOGIC_SECURITY_KEY) += securitykey.o diff --git a/drivers/amlogic/securitykey/securitykey.c b/drivers/amlogic/securitykey/securitykey.c new file mode 100644 index 000000000000..7a897ea855ae --- /dev/null +++ b/drivers/amlogic/securitykey/securitykey.c @@ -0,0 +1,373 @@ +/* + * drivers/amlogic/securitykey/securitykey.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 +#undef pr_fmt +#define pr_fmt(fmt) "storage: " fmt + +#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" + +static void __iomem *storage_in_base; +static void __iomem *storage_out_base; +static void __iomem *storage_block_base; + +static long phy_storage_in_base; +static long phy_storage_out_base; +static long phy_storage_block_base; +static long storage_block_size; + +static unsigned long storage_read_func; +static unsigned long storage_write_func; +static unsigned long storage_query_func; +static unsigned long storage_tell_func; +static unsigned long storage_status_func; +static unsigned long storage_verify_func; +static unsigned long storage_list_func; +static unsigned long storage_remove_func; +static unsigned long storage_set_enctype_func; +static unsigned long storage_get_enctype_func; +static unsigned long storage_version_func; + +static DEFINE_SPINLOCK(storage_lock); +static unsigned long lockflags; + +static uint64_t storage_smc_ops(uint64_t func) +{ + register unsigned long x0 asm("x0") = func; + asm volatile( + __asmeq("%0", "x0") + "smc #0\n" + : "+r" (x0)); + + return x0; +} +static uint64_t storage_smc_ops2(uint64_t func, uint64_t arg1) +{ + register unsigned long x0 asm("x0") = func; + register unsigned long x1 asm("x1") = arg1; + asm volatile( + __asmeq("%0", "x0") + __asmeq("%1", "x1") + "smc #0\n" + : "+r" (x0) + : "r"(x1)); + + return x0; +} + +static inline int32_t smc_to_linux_errno(uint64_t errno) +{ + int32_t ret = (int32_t)(errno & 0xffffffff); + return ret; +} + +void *secure_storage_getbuffer(uint32_t *size) +{ + *size = storage_block_size; + return (void *)storage_block_base; +} + +int32_t secure_storage_write(uint8_t *keyname, uint8_t *keybuf, + uint32_t keylen, uint32_t keyattr) +{ + uint32_t *input; + uint32_t namelen; + uint8_t *keydata, *name; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + input = (uint32_t *)storage_in_base; + *input++ = namelen; + *input++ = keylen; + *input++ = keyattr; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + keydata = name + namelen; + memcpy(keydata, keybuf, keylen); + ret = storage_smc_ops(storage_write_func); + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_read(uint8_t *keyname, uint8_t *keybuf, + uint32_t keylen, uint32_t *readlen) +{ + uint32_t *input = (uint32_t *)storage_in_base; + uint32_t *output = (uint32_t *)storage_out_base; + uint32_t namelen; + uint8_t *name, *buf; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + *input++ = namelen; + *input++ = keylen; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + ret = storage_smc_ops(storage_read_func); + if (ret == RET_OK) { + *readlen = *output; + buf = (uint8_t *)(output + 1); + memcpy(keybuf, buf, *readlen); + } + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_verify(uint8_t *keyname, uint8_t *hashbuf) +{ + uint32_t *input = (uint32_t *)storage_in_base; + uint32_t *output = (uint32_t *)storage_out_base; + uint32_t namelen; + uint8_t *name; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + *input++ = namelen; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + ret = storage_smc_ops(storage_verify_func); + if (ret == RET_OK) + memcpy(hashbuf, (uint8_t *)output, 32); + spin_unlock_irqrestore(&storage_lock, lockflags); + + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_query(uint8_t *keyname, uint32_t *retval) +{ + uint32_t *input = (uint32_t *)storage_in_base; + uint32_t *output = (uint32_t *)storage_out_base; + uint32_t namelen; + uint8_t *name; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + *input++ = namelen; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + ret = storage_smc_ops(storage_query_func); + if (ret == RET_OK) + *retval = *output; + spin_unlock_irqrestore(&storage_lock, lockflags); + + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_tell(uint8_t *keyname, uint32_t *retval) +{ + uint32_t *input = (uint32_t *)storage_in_base; + uint32_t *output = (uint32_t *)storage_out_base; + uint32_t namelen; + uint8_t *name; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + *input++ = namelen; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + ret = storage_smc_ops(storage_tell_func); + if (ret == RET_OK) + *retval = *output; + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_status(uint8_t *keyname, uint32_t *retval) +{ + uint32_t *input = (uint32_t *)storage_in_base; + uint32_t *output = (uint32_t *)storage_out_base; + uint32_t namelen; + uint8_t *name; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + *input++ = namelen; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + ret = storage_smc_ops(storage_status_func); + if (ret == RET_OK) + *retval = *output; + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_list(uint8_t *listbuf, + uint32_t buflen, uint32_t *readlen) +{ + uint32_t *output = (uint32_t *)storage_out_base; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + ret = storage_smc_ops(storage_list_func); + if (ret == RET_OK) { + if (*output > buflen) + *readlen = buflen; + else + *readlen = *output; + memcpy(listbuf, (uint8_t *)(output+1), *readlen); + } + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_remove(uint8_t *keyname) +{ + uint32_t *input = (uint32_t *)storage_in_base; + uint32_t namelen; + uint8_t *name; + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + namelen = strlen((const char *)keyname); + *input++ = namelen; + name = (uint8_t *)input; + memcpy(name, keyname, namelen); + ret = storage_smc_ops(storage_remove_func); + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +int32_t secure_storage_set_enctype(uint32_t type) +{ + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + ret = storage_smc_ops2(storage_set_enctype_func, type); + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} +int32_t secure_storage_get_enctype(void) +{ + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + ret = storage_smc_ops(storage_get_enctype_func); + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} +int32_t secure_storage_version(void) +{ + uint64_t ret; + + spin_lock_irqsave(&storage_lock, lockflags); + ret = storage_smc_ops(storage_version_func); + spin_unlock_irqrestore(&storage_lock, lockflags); + return smc_to_linux_errno(ret); +} + +static int storage_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + unsigned int id; + int ret; + + phy_storage_in_base = 0; + phy_storage_out_base = 0; + phy_storage_block_base = 0; + storage_block_size = 0; + + if (!of_property_read_u32(np, "storage_in_func", &id)) + phy_storage_in_base = storage_smc_ops(id); + if (!of_property_read_u32(np, "storage_out_func", &id)) + phy_storage_out_base = storage_smc_ops(id); + if (!of_property_read_u32(np, "storage_block_func", &id)) + phy_storage_block_base = storage_smc_ops(id); + if (!of_property_read_u32(np, "storage_size_func", &id)) + storage_block_size = storage_smc_ops(id); + + if (!of_property_read_u32(np, "storage_read", &id)) + storage_read_func = id; + if (!of_property_read_u32(np, "storage_write", &id)) + storage_write_func = id; + if (!of_property_read_u32(np, "storage_query", &id)) + storage_query_func = id; + if (!of_property_read_u32(np, "storage_tell", &id)) + storage_tell_func = id; + if (!of_property_read_u32(np, "storage_status", &id)) + storage_status_func = id; + if (!of_property_read_u32(np, "storage_verify", &id)) + storage_verify_func = id; + if (!of_property_read_u32(np, "storage_list", &id)) + storage_list_func = id; + if (!of_property_read_u32(np, "storage_remove", &id)) + storage_remove_func = id; + if (!of_property_read_u32(np, "storage_set_enctype", &id)) + storage_set_enctype_func = id; + if (!of_property_read_u32(np, "storage_get_enctype", &id)) + storage_get_enctype_func = id; + if (!of_property_read_u32(np, "storage_version", &id)) + storage_version_func = id; + + if (!phy_storage_in_base || !phy_storage_out_base + || !phy_storage_block_base || !storage_block_size) { + pr_info("probe fail!\n"); + return -1; + } + + storage_in_base = ioremap_cache(phy_storage_in_base, + storage_block_size); + storage_out_base = ioremap_cache(phy_storage_out_base, + storage_block_size); + storage_block_base = ioremap_cache(phy_storage_block_base, + storage_block_size); + pr_info("storage in base: 0x%lx\n", (long)storage_in_base); + pr_info("storage out base: 0x%lx\n", (long)storage_out_base); + pr_info("storage block base: 0x%lx\n", (long)storage_block_base); + + ret = 0; + if (!storage_in_base || !storage_out_base || !storage_block_base) + ret = -1; + pr_info("probe done!\n"); + return ret; +} + +static const struct of_device_id securitykey_dt_match[] = { + { .compatible = "aml, securitykey" }, + { /* sentinel */ }, +}; + +static struct platform_driver securitykey_platform_driver = { + .probe = storage_probe, + .driver = { + .owner = THIS_MODULE, + .name = "securitykey", + .of_match_table = securitykey_dt_match, + }, +}; + +static int __init meson_securitykey_init(void) +{ + return platform_driver_register(&securitykey_platform_driver); +} +module_init(meson_securitykey_init); diff --git a/include/linux/amlogic/security_key.h b/include/linux/amlogic/security_key.h new file mode 100644 index 000000000000..992e89372d37 --- /dev/null +++ b/include/linux/amlogic/security_key.h @@ -0,0 +1,40 @@ +/* + * include/linux/amlogic/security_key.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. + * + */ + +#ifndef _AML_SECURITY_KEY_H_ +#define _AML_SECURITY_KEY_H_ + +/* internal return value*/ +#define RET_OK 0 +#define RET_EFAIL 1 /*not found*/ +#define RET_EINVAL 2 /*name length*/ +#define RET_EMEM 3 /*no enough memory*/ + +/* keyattr: 0: normal, 1: secure*/ +int32_t secure_storage_write(uint8_t *keyname, uint8_t *keybuf, + uint32_t keylen, uint32_t keyattr); +int32_t secure_storage_read(uint8_t *keyname, uint8_t *keybuf, + uint32_t keylen, uint32_t *readlen); +int32_t secure_storage_verify(uint8_t *keyname, uint8_t *hashbuf); +int32_t secure_storage_query(uint8_t *keyname, uint32_t *retval); +int32_t secure_storage_tell(uint8_t *keyname, uint32_t *retval); +int32_t secure_storage_status(uint8_t *keyname, uint32_t *retval); +void *secure_storage_getbuffer(uint32_t *size); +int32_t secure_storage_set_enctype(uint32_t type); +int32_t secure_storage_get_enctype(void); +int32_t secure_storage_version(void); +#endif