diff options
Diffstat (limited to 'target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch')
-rw-r--r-- | target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch b/target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch new file mode 100644 index 0000000000..8407b2f998 --- /dev/null +++ b/target/linux/sunxi/patches-3.12/170-sunxi-sid-initial.patch @@ -0,0 +1,290 @@ +From 1d4b3ab562fa87e2c7f05cf92af1ff4b6cd42581 Mon Sep 17 00:00:00 2001 +From: Oliver Schinagl <oliver@schinagl.nl> +Date: Tue, 3 Sep 2013 12:33:27 +0200 +Subject: [PATCH] ARM: sunxi: Initial support for Allwinner's Security ID fuses + +Allwinner has electric fuses (efuse) on their line of chips. This driver +reads those fuses, seeds the kernel entropy and exports them as a sysfs +node. + +These fuses are most likely to be programmed at the factory, encoding +things like Chip ID, some sort of serial number, etc. and appear to be +reasonably unique. +While in theory, these should be writeable by the user, it will probably +be inconvenient to do so. Allwinner recommends that a certain input pin, +labeled 'efuse_vddq', be connected to GND. To write these fuses however, +a 2.5 V programming voltage needs to be applied to this pin. + +Even so, they can still be used to generate a board-unique mac from, +board unique RSA key and seed the kernel RNG. + +On sun7i additional storage is available, this is initially used for an +UEFI BOOT key, Secure JTAG key, HDMI-HDCP key and vendor specific keys. + +Currently supported are the following known chips: +Allwinner sun4i (A10) +Allwinner sun5i (A10s, A13) +Allwinner sun7i (A20) + +Signed-off-by: Oliver Schinagl <oliver@schinagl.nl> +--- + Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 +++ + .../bindings/misc/allwinner,sunxi-sid.txt | 17 +++ + drivers/misc/eeprom/Kconfig | 13 ++ + drivers/misc/eeprom/Makefile | 1 + + drivers/misc/eeprom/sunxi_sid.c | 158 +++++++++++++++++++++ + 5 files changed, 211 insertions(+) + create mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid + create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt + create mode 100644 drivers/misc/eeprom/sunxi_sid.c + +diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid +new file mode 100644 +index 0000000..ffb9536 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-sunxi-sid +@@ -0,0 +1,22 @@ ++What: /sys/devices/*/<our-device>/eeprom ++Date: August 2013 ++Contact: Oliver Schinagl <oliver@schinagl.nl> ++Description: read-only access to the SID (Security-ID) on current ++ A-series SoC's from Allwinner. Currently supports A10, A10s, A13 ++ and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes, ++ whereas the newer A20 SoC exposes 512 bytes split into sections. ++ Besides the 16 bytes of SID, there's also an SJTAG area, ++ HDMI-HDCP key and some custom keys. Below a quick overview, for ++ details see the user manual: ++ 0x000 128 bit root-key (sun[457]i) ++ 0x010 128 bit boot-key (sun7i) ++ 0x020 64 bit security-jtag-key (sun7i) ++ 0x028 16 bit key configuration (sun7i) ++ 0x02b 16 bit custom-vendor-key (sun7i) ++ 0x02c 320 bit low general key (sun7i) ++ 0x040 32 bit read-control access (sun7i) ++ 0x064 224 bit low general key (sun7i) ++ 0x080 2304 bit HDCP-key (sun7i) ++ 0x1a0 768 bit high general key (sun7i) ++Users: any user space application which wants to read the SID on ++ Allwinner's A-series of CPU's. +diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt +new file mode 100644 +index 0000000..68ba372 +--- /dev/null ++++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt +@@ -0,0 +1,17 @@ ++Allwinner sunxi-sid ++ ++Required properties: ++- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-a20-sid". ++- reg: Should contain registers location and length ++ ++Example for sun4i: ++ sid@01c23800 { ++ compatible = "allwinner,sun4i-sid"; ++ reg = <0x01c23800 0x10> ++ }; ++ ++Example for sun7i: ++ sid@01c23800 { ++ compatible = "allwinner,sun7i-a20-sid"; ++ reg = <0x01c23800 0x200> ++ }; +diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig +index 04f2e1f..9536852f 100644 +--- a/drivers/misc/eeprom/Kconfig ++++ b/drivers/misc/eeprom/Kconfig +@@ -96,4 +96,17 @@ config EEPROM_DIGSY_MTC_CFG + + If unsure, say N. + ++config EEPROM_SUNXI_SID ++ tristate "Allwinner sunxi security ID support" ++ depends on ARCH_SUNXI && SYSFS ++ help ++ This is a driver for the 'security ID' available on various Allwinner ++ devices. ++ ++ Due to the potential risks involved with changing e-fuses, ++ this driver is read-only. ++ ++ This driver can also be built as a module. If so, the module ++ will be called sunxi_sid. ++ + endmenu +diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile +index fc1e81d..9507aec 100644 +--- a/drivers/misc/eeprom/Makefile ++++ b/drivers/misc/eeprom/Makefile +@@ -4,4 +4,5 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o + obj-$(CONFIG_EEPROM_MAX6875) += max6875.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o + obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o ++obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o + obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o +diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c +new file mode 100644 +index 0000000..9c34e57 +--- /dev/null ++++ b/drivers/misc/eeprom/sunxi_sid.c +@@ -0,0 +1,158 @@ ++/* ++ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl> ++ * http://www.linux-sunxi.org ++ * ++ * 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. ++ * ++ * This driver exposes the Allwinner security ID, efuses exported in byte- ++ * sized chunks. ++ */ ++ ++#include <linux/compiler.h> ++#include <linux/device.h> ++#include <linux/err.h> ++#include <linux/export.h> ++#include <linux/fs.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/kobject.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/random.h> ++#include <linux/slab.h> ++#include <linux/stat.h> ++#include <linux/sysfs.h> ++#include <linux/types.h> ++ ++#define DRV_NAME "sunxi-sid" ++ ++struct sunxi_sid_data { ++ void __iomem *reg_base; ++ unsigned int keysize; ++}; ++ ++/* We read the entire key, due to a 32 bit read alignment requirement. Since we ++ * want to return the requested byte, this results in somewhat slower code and ++ * uses 4 times more reads as needed but keeps code simpler. Since the SID is ++ * only very rarely probed, this is not really an issue. ++ */ ++static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data, ++ const unsigned int offset) ++{ ++ u32 sid_key; ++ ++ if (offset >= sid_data->keysize) ++ return 0; ++ ++ sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4)); ++ sid_key >>= (offset % 4) * 8; ++ ++ return sid_key; /* Only return the last byte */ ++} ++ ++static ssize_t sid_read(struct file *fd, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, ++ loff_t pos, size_t size) ++{ ++ struct platform_device *pdev; ++ struct sunxi_sid_data *sid_data; ++ int i; ++ ++ pdev = to_platform_device(kobj_to_dev(kobj)); ++ sid_data = platform_get_drvdata(pdev); ++ ++ if (pos < 0 || pos >= sid_data->keysize) ++ return 0; ++ if (size > sid_data->keysize - pos) ++ size = sid_data->keysize - pos; ++ ++ for (i = 0; i < size; i++) ++ buf[i] = sunxi_sid_read_byte(sid_data, pos + i); ++ ++ return i; ++} ++ ++static struct bin_attribute sid_bin_attr = { ++ .attr = { .name = "eeprom", .mode = S_IRUGO, }, ++ .read = sid_read, ++}; ++ ++static int sunxi_sid_remove(struct platform_device *pdev) ++{ ++ device_remove_bin_file(&pdev->dev, &sid_bin_attr); ++ dev_dbg(&pdev->dev, "driver unloaded\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id sunxi_sid_of_match[] = { ++ { .compatible = "allwinner,sun4i-sid", .data = (void *)16}, ++ { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512}, ++ {/* sentinel */}, ++}; ++MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); ++ ++static int sunxi_sid_probe(struct platform_device *pdev) ++{ ++ struct sunxi_sid_data *sid_data; ++ struct resource *res; ++ const struct of_device_id *of_dev_id; ++ u8 *entropy; ++ unsigned int i; ++ ++ sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data), ++ GFP_KERNEL); ++ if (!sid_data) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(sid_data->reg_base)) ++ return PTR_ERR(sid_data->reg_base); ++ ++ of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev); ++ if (!of_dev_id) ++ return -ENODEV; ++ sid_data->keysize = (int)of_dev_id->data; ++ ++ platform_set_drvdata(pdev, sid_data); ++ ++ sid_bin_attr.size = sid_data->keysize; ++ if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) ++ return -ENODEV; ++ ++ entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL); ++ for (i = 0; i < sid_data->keysize; i++) ++ entropy[i] = sunxi_sid_read_byte(sid_data, i); ++ add_device_randomness(entropy, sid_data->keysize); ++ kfree(entropy); ++ ++ dev_dbg(&pdev->dev, "loaded\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver sunxi_sid_driver = { ++ .probe = sunxi_sid_probe, ++ .remove = sunxi_sid_remove, ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = sunxi_sid_of_match, ++ }, ++}; ++module_platform_driver(sunxi_sid_driver); ++ ++MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>"); ++MODULE_DESCRIPTION("Allwinner sunxi security id driver"); ++MODULE_LICENSE("GPL"); +-- +1.8.4 + |