summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJae Hyun Yoo <jae.hyun.yoo@intel.com>2020-03-28 00:42:05 +0300
committerJae Hyun Yoo <jae.hyun.yoo@intel.com>2021-07-14 20:10:33 +0300
commitafa31118717f755478cbdff0047a6b3bcfddba27 (patch)
treed8c4bc233c903f78ef7adb272e16d33493115f63
parent11e00eda4903f1939fdb978e6a6c76136502e187 (diff)
downloadlinux-afa31118717f755478cbdff0047a6b3bcfddba27.tar.xz
Add chip unique id reading interface
This commit adds an interface for reading chip unique id value. Optionally, the id can be encrypted using a dts-supplied hash data. Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com> Change-Id: Ifd98500ea87b3d40e1738e583e077a74851fae35
-rw-r--r--drivers/soc/aspeed/aspeed-bmc-misc.c119
1 files changed, 109 insertions, 10 deletions
diff --git a/drivers/soc/aspeed/aspeed-bmc-misc.c b/drivers/soc/aspeed/aspeed-bmc-misc.c
index 314007bad74f..4aad3129f793 100644
--- a/drivers/soc/aspeed/aspeed-bmc-misc.c
+++ b/drivers/soc/aspeed/aspeed-bmc-misc.c
@@ -7,14 +7,18 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
+#include <crypto/hash.h>
#define DEVICE_NAME "aspeed-bmc-misc"
struct aspeed_bmc_ctrl {
const char *name;
u32 offset;
- u32 mask;
+ u64 mask;
u32 shift;
+ bool read_only;
+ u32 reg_width;
+ const char *hash_data;
struct regmap *map;
struct kobj_attribute attr;
};
@@ -30,6 +34,7 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
struct aspeed_bmc_ctrl *ctrl)
{
int rc;
+ u32 mask;
/* Example child:
*
@@ -37,6 +42,7 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
* offset = <0x80>;
* bit-mask = <0x1>;
* bit-shift = <6>;
+ * reg-width = <64>;
* label = "foo";
* }
*/
@@ -47,15 +53,32 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
if (rc < 0)
return rc;
- rc = of_property_read_u32(child, "bit-mask", &ctrl->mask);
- if (rc < 0)
- return rc;
+ /* optional reg-width, default to 32 */
+ rc = of_property_read_u32(child, "reg-width", &ctrl->reg_width);
+ if (rc < 0 || ctrl->reg_width != 64)
+ ctrl->reg_width = 32;
+
+ if (ctrl->reg_width == 32) {
+ rc = of_property_read_u32(child, "bit-mask", &mask);
+ if (rc < 0)
+ return rc;
+ ctrl->mask = mask;
+ } else {
+ rc = of_property_read_u64(child, "bit-mask", &ctrl->mask);
+ if (rc < 0)
+ return rc;
+ }
rc = of_property_read_u32(child, "bit-shift", &ctrl->shift);
if (rc < 0)
return rc;
+ ctrl->read_only = of_property_read_bool(child, "read-only");
+
ctrl->mask <<= ctrl->shift;
+ /* optional hash_data for obfuscating reads */
+ if (of_property_read_string(child, "hash-data", &ctrl->hash_data))
+ ctrl->hash_data = NULL;
return 0;
}
@@ -85,22 +108,94 @@ static int aspeed_bmc_misc_parse_dt(struct aspeed_bmc_misc *bmc,
return 0;
}
+#define SHA256_DIGEST_LEN 32
+static int hmac_sha256(u8 *key, u8 ksize, const char *plaintext, u8 psize,
+ u8 *output)
+{
+ struct crypto_shash *tfm;
+ struct shash_desc *shash;
+ int ret;
+
+ if (!ksize)
+ return -EINVAL;
+
+ tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+ if (IS_ERR(tfm)) {
+ return -ENOMEM;
+ }
+
+ ret = crypto_shash_setkey(tfm, key, ksize);
+ if (ret)
+ goto failed;
+
+ shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!shash) {
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ shash->tfm = tfm;
+ ret = crypto_shash_digest(shash, plaintext, psize, output);
+
+ kfree(shash);
+
+failed:
+ crypto_free_shash(tfm);
+ return ret;
+}
+
static ssize_t aspeed_bmc_misc_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct aspeed_bmc_ctrl *ctrl;
- unsigned int val;
+ u32 val;
+ u64 val64;
int rc;
+ u8 *binbuf;
+ size_t buf_len;
+ u8 hashbuf[SHA256_DIGEST_LEN];
ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
+
+ if (ctrl->reg_width == 32) {
+ rc = regmap_read(ctrl->map, ctrl->offset, &val);
+ if (rc)
+ return rc;
+ val &= (u32)ctrl->mask;
+ val >>= ctrl->shift;
+
+ return sprintf(buf, "%u\n", val);
+ }
rc = regmap_read(ctrl->map, ctrl->offset, &val);
if (rc)
return rc;
+ val64 = val;
+ rc = regmap_read(ctrl->map, ctrl->offset + sizeof(u32), &val);
+ if (rc)
+ return rc;
+ /* aspeed puts 64-bit regs as L, H in address space */
+ val64 |= (u64)val << 32;
+ val64 &= ctrl->mask;
+ val64 >>= ctrl->shift;
+ buf_len = sizeof(val64);
+
+ if (ctrl->hash_data) {
+ rc = hmac_sha256((u8*)&val64, buf_len, ctrl->hash_data,
+ strlen(ctrl->hash_data), hashbuf);
+ if (rc)
+ return rc;
+ buf_len = SHA256_DIGEST_LEN;
+ binbuf = hashbuf;
+ } else {
+ binbuf = (u8*)&val64;
+ buf_len = sizeof(val64);
+ }
+ bin2hex(buf, binbuf, buf_len);
+ buf[buf_len * 2] = '\n';
+ rc = buf_len * 2 + 1;
- val &= ctrl->mask;
- val >>= ctrl->shift;
+ return rc;
- return sprintf(buf, "%u\n", val);
}
static ssize_t aspeed_bmc_misc_store(struct kobject *kobj,
@@ -111,13 +206,17 @@ static ssize_t aspeed_bmc_misc_store(struct kobject *kobj,
long val;
int rc;
+ ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
+
+ if (ctrl->read_only)
+ return -EROFS;
+
rc = kstrtol(buf, 0, &val);
if (rc)
return rc;
- ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
val <<= ctrl->shift;
- rc = regmap_update_bits(ctrl->map, ctrl->offset, ctrl->mask, val);
+ rc = regmap_write_bits(ctrl->map, ctrl->offset, ctrl->mask, val);
return rc < 0 ? rc : count;
}