From 766f7e504cc2a0508c887c7625332c88f93c5729 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 27 Mar 2020 14:42:05 -0700 Subject: [PATCH] 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 Signed-off-by: Vernon Mauery Signed-off-by: Arun P. Mohanan --- drivers/soc/aspeed/aspeed-bmc-misc.c | 118 ++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 13 deletions(-) diff --git a/drivers/soc/aspeed/aspeed-bmc-misc.c b/drivers/soc/aspeed/aspeed-bmc-misc.c index 04d97ab17274..4aad3129f793 100644 --- a/drivers/soc/aspeed/aspeed-bmc-misc.c +++ b/drivers/soc/aspeed/aspeed-bmc-misc.c @@ -7,15 +7,18 @@ #include #include #include +#include #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; }; @@ -31,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: * @@ -38,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"; * } */ @@ -48,9 +53,21 @@ 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) @@ -59,6 +76,9 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child, 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; } @@ -88,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, @@ -114,17 +206,17 @@ static ssize_t aspeed_bmc_misc_store(struct kobject *kobj, long val; int rc; - rc = kstrtol(buf, 0, &val); - if (rc) - return 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; + 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; } -- 2.17.1