Few storage technology such is EMMC, UFS, and NVMe support RPMB
hardware partition with common protocol and frame layout.
The RPMB partition cannot be accessed via standard block layer, but
by a set of specific commands: WRITE, READ, GET_WRITE_COUNTER, and
PROGRAM_KEY.
Such a partition provides authenticated and replay protected access,
hence suitable as a secure storage.
A storage device registers its RPMB hardware (emmc) partition or
RPMB W-LUN (ufs) with the RPMB layer providing an implementation for
send_rpmb_req() handler.
Tere is as well simulation platform device. This is handy as an RPMB
key can be programmed only once at storage device lifetime.
ThePMB layer aims to provide in-kernel API for Trusted Execution
Environment (TEE) devices that are capable to securely compute block
frame signature. In case a TEE device wish to store a replay protected
data, it creates an RPMB frame with requested data and computes HMAC of
the frame, then it requests the storage device via RPMB layer to store
the data.
A TEE driver can claim rpmb interface, for example,
via class_interface_register ().
A parallel user space API is provided via /dev/rpmbX character
device with a single IOCTL command similar to the one provided by
mmc/ioctl. h
There is a sample tool under tools/rpmb/ directory that exercises
this interface.
Tomas Winkler (8):
rpmb: add Replay Protected Memory Block (RPMB) subsystem
char: rpmb: add sysfs-class ABI documentation
char: rpmb: add device attributes
char: rpmb: provide user space interface
char: rpmb: add RPMB simulation device
tools rpmb: add RPBM access tool
mmc: block: register rpmb partition with the RPMB subsystem
scsi: ufs: connect to RPMB subsystem
Documentation/ABI/testing/sysfs-class-rpmb | 39 ++
Documentation/ioctl/ioctl-number.txt | 1 +
MAINTAINERS | 10 +
drivers/char/Kconfig | 2 +
drivers/char/Makefile | 1 +
drivers/char/rpmb/Kconfig | 25 +
drivers/char/rpmb/Makefile | 6 +
drivers/char/rpmb/cdev.c | 209 ++++++++
drivers/char/rpmb/core.c | 408 +++++++++++++++
drivers/char/rpmb/rpmb-cdev.h | 31 ++
drivers/char/rpmb/rpmb_sim.c | 584 +++++++++++++++++++++
drivers/mmc/card/block.c | 289 +++++++++++
drivers/scsi/ufs/ufshcd.c | 219 ++++++++
drivers/scsi/ufs/ufshcd.h | 2 +
include/linux/rpmb.h | 138 +++++
include/uapi/linux/rpmb.h | 120 +++++
tools/Makefile | 16 +-
tools/rpmb/.gitignore | 2 +
tools/rpmb/Makefile | 32 ++
tools/rpmb/rpmb.c | 807 +++++++++++++++++++++++++++++
20 files changed, 2936 insertions(+), 5 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-class-rpmb
create mode 100644 drivers/char/rpmb/Kconfig
create mode 100644 drivers/char/rpmb/Makefile
create mode 100644 drivers/char/rpmb/cdev.c
create mode 100644 drivers/char/rpmb/core.c
create mode 100644 drivers/char/rpmb/rpmb-cdev.h
create mode 100644 drivers/char/rpmb/rpmb_sim.c
create mode 100644 include/linux/rpmb.h
create mode 100644 include/uapi/linux/rpmb.h
create mode 100644 tools/rpmb/.gitignore
create mode 100644 tools/rpmb/Makefile
create mode 100644 tools/rpmb/rpmb.c
--
2.4.3
Few storage technology such is EMMC, UFS, and NVMe support RPMB hardware
partition with common protocol and frame layout.
The RPMB partition cannot be accessed via standard block layer, but by a
set of specific commands: WRITE, READ, GET_WRITE_COUNTER, and PROGRAM_KEY.
Such a partition provides authenticated and replay protected access,
hence suitable as a secure storage.
The RPMB layer aims to provide in-kernel API for Trusted Execution
Environment (TEE) devices that are capable to securely compute block
frame signature. In case a TEE device wish to store a replay protected
data, it creates an RPMB frame with requested data and computes HMAC of
the frame, then it requests the storage device via RPMB layer to store
the data.
A TEE driver can claim rpmb interface, for example,
via class_interface_register ().
A storage device registers its RPMB hardware (emmc) partition or
RPMB W-LUN (ufs) with the RPMB layer providing an implementation
for send_rpmb_req() handler.
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Alexander Usyskin <[email protected]>
---
V2: added short workflow description in the commit message
MAINTAINERS | 7 +
drivers/char/Kconfig | 2 +
drivers/char/Makefile | 1 +
drivers/char/rpmb/Kconfig | 8 ++
drivers/char/rpmb/Makefile | 4 +
drivers/char/rpmb/core.c | 337 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/rpmb.h | 200 +++++++++++++++++++++++++++
7 files changed, 559 insertions(+)
create mode 100644 drivers/char/rpmb/Kconfig
create mode 100644 drivers/char/rpmb/Makefile
create mode 100644 drivers/char/rpmb/core.c
create mode 100644 include/linux/rpmb.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 03e00c7c88eb..98dcd40ab900 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9417,6 +9417,13 @@ F: include/net/rose.h
F: include/uapi/linux/rose.h
F: net/rose/
+RPMB SUBSYSTEM
+M: Tomas Winkler <[email protected]>
+L: [email protected]
+S: Supported
+F: drivers/char/rpmb/*
+F: include/linux/rpmb.h
+
RTL2830 MEDIA DRIVER
M: Antti Palosaari <[email protected]>
L: [email protected]
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 3ec0766ed5e9..b5970f965fa7 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -604,5 +604,7 @@ config TILE_SROM
source "drivers/char/xillybus/Kconfig"
+source "drivers/char/rpmb/Kconfig"
+
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index d8a7579300d2..1a5e43c1a9a6 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -60,3 +60,4 @@ js-rtc-y = rtc.o
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_XILLYBUS) += xillybus/
+obj-$(CONFIG_RPMB) += rpmb/
diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
new file mode 100644
index 000000000000..c5e6e909efce
--- /dev/null
+++ b/drivers/char/rpmb/Kconfig
@@ -0,0 +1,8 @@
+config RPMB
+ tristate "RPMB partition interface"
+ help
+ Unified RPMB partition interface for eMMC and UFS.
+ Provides interface for in kernel security controllers to
+ access RPMB partition.
+
+ If unsure, select N.
diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile
new file mode 100644
index 000000000000..812b3ed264c0
--- /dev/null
+++ b/drivers/char/rpmb/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_RPMB) += rpmb.o
+rpmb-objs += core.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/char/rpmb/core.c b/drivers/char/rpmb/core.c
new file mode 100644
index 000000000000..c9ea30aca6be
--- /dev/null
+++ b/drivers/char/rpmb/core.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2015-2016 Intel Corp. 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; version 2 of the License.
+ *
+ * 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include <linux/rpmb.h>
+
+static DEFINE_IDA(rpmb_ida);
+
+/**
+ * rpmb_dev_get - increase rpmb device ref counter
+ *
+ * @rdev: rpmb device
+ */
+struct rpmb_dev *rpmb_dev_get(struct rpmb_dev *rdev)
+{
+ return get_device(&rdev->dev) ? rdev : NULL;
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_get);
+
+/**
+ * rpmb_dev_put - decrease rpmb device ref counter
+ *
+ * @rdev: rpmb device
+ */
+void rpmb_dev_put(struct rpmb_dev *rdev)
+{
+ put_device(&rdev->dev);
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_put);
+
+static int rpmb_request_verify(struct rpmb_dev *rdev, struct rpmb_data *rpmbd)
+{
+ u16 req_type, block_count;
+
+ if (rpmbd->in_frames == NULL || rpmbd->out_frames == NULL ||
+ rpmbd->in_frames_cnt == 0 || rpmbd->out_frames_cnt == 0)
+ return -EINVAL;
+
+ req_type = be16_to_cpu(rpmbd->in_frames[0].req_resp);
+ block_count = be16_to_cpu(rpmbd->in_frames[0].block_count);
+
+ if (rpmbd->req_type != req_type) {
+ dev_err(&rdev->dev, "rpmb req type doesn't match 0x%04X = 0x%04X\n",
+ req_type, rpmbd->req_type);
+ return -EINVAL;
+ }
+
+ switch (req_type) {
+ case RPMB_PROGRAM_KEY:
+ dev_dbg(&rdev->dev, "rpmb program key = 0x%1x blk = %d\n",
+ req_type, block_count);
+ break;
+ case RPMB_GET_WRITE_COUNTER:
+ dev_dbg(&rdev->dev, "rpmb get write counter = 0x%1x blk = %d\n",
+ req_type, block_count);
+
+ break;
+ case RPMB_WRITE_DATA:
+ dev_dbg(&rdev->dev, "rpmb write data = 0x%1x blk = %d\n",
+ req_type, block_count);
+
+ if (rdev->ops->reliable_wr_cnt &&
+ block_count > rdev->ops->reliable_wr_cnt) {
+ dev_err(&rdev->dev, "rpmb write data: block count %u > reliable wr count %u\n",
+ block_count, rdev->ops->reliable_wr_cnt);
+ return -EINVAL;
+ }
+
+ if (block_count > rpmbd->in_frames_cnt) {
+ dev_err(&rdev->dev, "rpmb write data: block count %u > in frame count %u\n",
+ block_count, rpmbd->in_frames_cnt);
+ return -EINVAL;
+ }
+ break;
+ case RPMB_READ_DATA:
+ dev_dbg(&rdev->dev, "rpmb read data = 0x%1x blk = %d\n",
+ req_type, block_count);
+
+ if (block_count > rpmbd->out_frames_cnt) {
+ dev_err(&rdev->dev, "rpmb read data: block count %u > out frame count %u\n",
+ block_count, rpmbd->in_frames_cnt);
+ return -EINVAL;
+ }
+ break;
+ case RPMB_RESULT_READ:
+ /* Internal command not supported */
+ dev_err(&rdev->dev, "NOTSUPPORTED rpmb resut read = 0x%1x blk = %d\n",
+ req_type, block_count);
+ return -EOPNOTSUPP;
+
+ default:
+ dev_err(&rdev->dev, "Error rpmb invalid command = 0x%1x blk = %d\n",
+ req_type, block_count);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * rpmb_send_req - send rpmb request
+ *
+ * @rdev: rpmb device
+ * @data: rpmb request data
+ *
+ * Return: 0 on success
+ * -EINVAL on wrong parameters
+ * -EOPNOTSUPP if device doesn't support the requested operation
+ * < 0 if the operation fails
+ */
+int rpmb_send_req(struct rpmb_dev *rdev, struct rpmb_data *data)
+{
+ int err;
+
+ if (!rdev || !data)
+ return -EINVAL;
+
+ err = rpmb_request_verify(rdev, data);
+ if (err)
+ return err;
+
+ mutex_lock(&rdev->lock);
+ if (rdev->ops && rdev->ops->send_rpmb_req)
+ err = rdev->ops->send_rpmb_req(rdev->dev.parent, data);
+ else
+ err = -EOPNOTSUPP;
+ mutex_unlock(&rdev->lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(rpmb_send_req);
+
+static void rpmb_dev_release(struct device *dev)
+{
+ struct rpmb_dev *rdev = to_rpmb_dev(dev);
+
+ ida_simple_remove(&rpmb_ida, rdev->id);
+ kfree(rdev);
+}
+
+struct class rpmb_class = {
+ .name = "rpmb",
+ .owner = THIS_MODULE,
+ .dev_release = rpmb_dev_release,
+};
+EXPORT_SYMBOL(rpmb_class);
+
+/**
+ * rpmb_dev_find_device - return first matching rpmb device
+ *
+ * @data: data for the match function
+ * @match: the matching function
+ *
+ * Return: matching rpmb device or NULL on failure
+ */
+struct rpmb_dev *rpmb_dev_find_device(void *data,
+ int (*match)(struct device *dev, const void *data))
+{
+ struct device *dev;
+
+ dev = class_find_device(&rpmb_class, NULL, data, match);
+
+ return dev ? to_rpmb_dev(dev) : NULL;
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_find_device);
+
+static int match_by_type(struct device *dev, const void *data)
+{
+ struct rpmb_dev *rdev = to_rpmb_dev(dev);
+ enum rpmb_type *type = (enum rpmb_type *)data;
+
+ return (*type == RPMB_TYPE_ANY || rdev->ops->type == *type);
+}
+
+/**
+ * rpmb_dev_get_by_type - return first registered rpmb device
+ * with matching type.
+ * If run with RPMB_TYPE_ANY the first an probably only
+ * device is returned
+ *
+ * @type: rpbm underlying device type
+ *
+ * Return: matching rpmb device or NULL/ERR_PTR on failure
+ */
+struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type)
+{
+ if (type > RPMB_TYPE_MAX)
+ return ERR_PTR(-EINVAL);
+
+ return rpmb_dev_find_device(&type, match_by_type);
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_get_by_type);
+
+static int match_by_parent(struct device *dev, const void *data)
+{
+ const struct device *parent = data;
+
+ return (parent && dev->parent == parent);
+}
+
+/**
+ * rpmb_dev_find_by_device - retrieve rpmb device from the parent device
+ *
+ * @parent: parent device of the rpmb device
+ *
+ * Return: NULL if there is no rpmb device associated with the parent device
+ */
+struct rpmb_dev *rpmb_dev_find_by_device(struct device *parent)
+{
+ if (!parent)
+ return NULL;
+
+ return rpmb_dev_find_device(parent, match_by_parent);
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_find_by_device);
+
+/**
+ * rpmb_dev_unregister - unregister RPMB partition from the RPMB subsystem
+ *
+ * @dev: parent device of the rpmb device
+ */
+int rpmb_dev_unregister(struct device *dev)
+{
+ struct rpmb_dev *rdev;
+
+ if (!dev)
+ return -EINVAL;
+
+ rdev = rpmb_dev_find_by_device(dev);
+ if (!rdev) {
+ dev_warn(dev, "no disk found %s\n", dev_name(dev->parent));
+ return -ENODEV;
+ }
+
+ rpmb_dev_put(rdev);
+
+ mutex_lock(&rdev->lock);
+ device_del(&rdev->dev);
+ mutex_unlock(&rdev->lock);
+
+ rpmb_dev_put(rdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_unregister);
+
+
+/**
+ * rpmb_dev_register - register RPMB partition with the RPMB subsystem
+ *
+ * @dev: storage device of the rpmb device
+ * @ops: device specific operations
+ */
+struct rpmb_dev *rpmb_dev_register(struct device *dev,
+ const struct rpmb_ops *ops)
+{
+ struct rpmb_dev *rdev;
+ int id;
+ int ret;
+
+ if (!dev || !ops)
+ return ERR_PTR(-EINVAL);
+
+ if (!ops->send_rpmb_req)
+ return ERR_PTR(-EINVAL);
+
+ if (ops->type == RPMB_TYPE_ANY || ops->type > RPMB_TYPE_MAX)
+ return ERR_PTR(-EINVAL);
+
+ rdev = kzalloc(sizeof(struct rpmb_dev), GFP_KERNEL);
+ if (!rdev)
+ return ERR_PTR(-ENOMEM);
+
+ id = ida_simple_get(&rpmb_ida, 0, 0, GFP_KERNEL);
+ if (id < 0) {
+ ret = id;
+ goto exit;
+ }
+
+ mutex_init(&rdev->lock);
+ rdev->ops = ops;
+ rdev->id = id;
+
+ dev_set_name(&rdev->dev, "rpmb%d", id);
+ rdev->dev.class = &rpmb_class;
+ rdev->dev.parent = dev;
+ ret = device_register(&rdev->dev);
+ if (ret)
+ goto exit;
+
+ dev_dbg(&rdev->dev, "registered disk\n");
+
+ return rdev;
+
+exit:
+ if (id >= 0)
+ ida_simple_remove(&rpmb_ida, id);
+ kfree(rdev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(rpmb_dev_register);
+
+static int __init rpmb_init(void)
+{
+ ida_init(&rpmb_ida);
+ class_register(&rpmb_class);
+ return 0;
+}
+
+static void __exit rpmb_exit(void)
+{
+ class_unregister(&rpmb_class);
+ ida_destroy(&rpmb_ida);
+}
+
+subsys_initcall(rpmb_init);
+module_exit(rpmb_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("RPMB class");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h
new file mode 100644
index 000000000000..2c1e259f1a04
--- /dev/null
+++ b/include/linux/rpmb.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2015-2016 Intel Corp. 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; version 2 of the License.
+ *
+ * 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 __RPMB_H__
+#define __RPMB_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+
+/**
+ * struct rpmb_frame - rpmb frame as defined by specs
+ *
+ * @stuff : stuff bytes
+ * @key_mac : The authentication key or the message authentication
+ * code (MAC) depending on the request/response type.
+ * The MAC will be delivered in the last (or the only)
+ * block of data.
+ * @data : Data to be written or read by signed access.
+ * @nonce : Random number generated by the host for the requests
+ * and copied to the response by the RPMB engine.
+ * @write_counter: Counter value for the total amount of the successful
+ * authenticated data write requests made by the host.
+ * @addr : Address of the data to be programmed to or read
+ * from the RPMB. Address is the serial number of
+ * the accessed block (half sector 256B).
+ * @block_count : Number of blocks (half sectors, 256B) requested to be
+ * read/programmed.
+ * @result : Includes information about the status of the write counter
+ * (valid, expired) and result of the access made to the RPMB.
+ * @req_resp : Defines the type of request and response to/from the memory.
+ */
+struct rpmb_frame {
+ u8 stuff[196];
+ u8 key_mac[32];
+ u8 data[256];
+ u8 nonce[16];
+ __be32 write_counter;
+ __be16 addr;
+ __be16 block_count;
+ __be16 result;
+ __be16 req_resp;
+} __packed;
+
+#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */
+#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */
+#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */
+#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */
+
+#define RPMB_REQ2RESP(_OP) ((_OP) << 8)
+#define RPMB_RESP2REQ(_OP) ((_OP) >> 8)
+
+/**
+ * enum rpmb_op_result - rpmb operation results
+ *
+ * @RPMB_ERR_OK : operation successful
+ * @RPMB_ERR_GENERAL : general failure
+ * @RPMB_ERR_AUTH : mac doesn't match or ac calculation failure
+ * @RPMB_ERR_COUNTER : counter doesn't match or counter increment failure
+ * @RPMB_ERR_ADDRESS : address out of range or wrong address alignment
+ * @RPMB_ERR_WRITE : data, counter, or result write failure
+ * @RPMB_ERR_READ : data, counter, or result read failure
+ * @RPMB_ERR_NO_KEY : authentication key not yet programmed
+ *
+ * @RPMB_ERR_COUNTER_EXPIRED: counter expired
+ */
+enum rpmb_op_result {
+ RPMB_ERR_OK = 0x0000,
+ RPMB_ERR_GENERAL = 0x0001,
+ RPMB_ERR_AUTH = 0x0002,
+ RPMB_ERR_COUNTER = 0x0003,
+ RPMB_ERR_ADDRESS = 0x0004,
+ RPMB_ERR_WRITE = 0x0005,
+ RPMB_ERR_READ = 0x0006,
+ RPMB_ERR_NO_KEY = 0x0007,
+
+ RPMB_ERR_COUNTER_EXPIRED = 0x0080
+};
+
+/**
+ * enum rpmb_type - type of underlaying storage technology
+ *
+ * @RPMB_TYPE_ANY : any type used for search only
+ * @RPMB_TYPE_EMMC : emmc (JESD84-B50.1)
+ * @RPMB_TYPE_UFS : UFS (JESD220)
+ * @RPMB_TYPE_MAX : upper sentinel
+ */
+enum rpmb_type {
+ RPMB_TYPE_ANY = 0,
+ RPMB_TYPE_EMMC,
+ RPMB_TYPE_UFS,
+ RPMB_TYPE_MAX = RPMB_TYPE_UFS
+};
+
+extern struct class rpmb_class;
+
+/**
+ * struct rpmb_data - rpmb data be transmitted in RPMB request
+ *
+ * @in_frames : list of input frames
+ * @out_frames : list of result frames
+ * @in_frames_cnt : count of the input frames
+ * @out_frames_cnt: count of the output frames
+ * @req_type : request type (program key, read, write, write counter)
+ */
+struct rpmb_data {
+ struct rpmb_frame *in_frames;
+ struct rpmb_frame *out_frames;
+ u32 in_frames_cnt;
+ u32 out_frames_cnt;
+ u16 req_type;
+};
+
+/**
+ * struct rpmb_ops - RPMB ops to be implemented by underlaying block device
+ *
+ * @send_rpmb_req : send RPMB request to RPBM partition backed by the disk
+ * @type : block device type
+ * @dev_id : unique device identifier
+ * @dev_id_len : unique device identifier length
+ * @reliable_wr_cnt: number of sectors that can be written in one access
+ */
+struct rpmb_ops {
+ int (*send_rpmb_req)(struct device *dev, struct rpmb_data *req);
+ enum rpmb_type type;
+ const u8 *dev_id;
+ size_t dev_id_len;
+ u16 reliable_wr_cnt;
+};
+
+/**
+ * struct rpmb_dev - device which can support RPMB partition
+ *
+ * @lock : lock
+ * @dev : device
+ * @id : device id
+ * @ops : operation exported by block layer
+ */
+struct rpmb_dev {
+ struct mutex lock;
+ struct device dev;
+ int id;
+ const struct rpmb_ops *ops;
+};
+
+#define to_rpmb_dev(x) container_of((x), struct rpmb_dev, dev)
+
+#if IS_ENABLED(CONFIG_RPMB)
+struct rpmb_dev *rpmb_dev_get(struct rpmb_dev *rdev);
+void rpmb_dev_put(struct rpmb_dev *rdev);
+struct rpmb_dev *rpmb_dev_find_by_device(struct device *parent);
+struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type);
+struct rpmb_dev *rpmb_dev_register(struct device *dev,
+ const struct rpmb_ops *ops);
+struct rpmb_dev *rpmb_dev_find_device(void *data,
+ int (*match)(struct device *dev, const void *data));
+int rpmb_dev_unregister(struct device *dev);
+int rpmb_send_req(struct rpmb_dev *rdev, struct rpmb_data *data);
+
+#else
+static inline struct rpmb_dev *rpmb_dev_get(struct rpmb_dev *rdev)
+{
+ return NULL;
+}
+static inline void rpmb_dev_put(struct rpmb_dev *rdev) { }
+static inline struct rpmb_dev *rpmb_dev_find_by_device(struct device *parent)
+{
+ return NULL;
+}
+static inline
+struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type)
+{
+ return NULL;
+}
+static inline struct rpmb_dev *
+rpmb_dev_register(struct device *dev, const struct rpmb_ops *ops)
+{
+ return NULL;
+}
+static inline int rpmb_dev_unregister(struct device *dev)
+{
+ return 0;
+}
+static inline int rpmb_send_req(struct rpmb_dev *rdev, struct rpmb_data *data)
+{
+ return 0;
+}
+#endif /* CONFIG_RPMB */
+
+#endif /* __RPMB_H__ */
--
2.4.3
Signed-off-by: Tomas Winkler <[email protected]>
---
V2: resend
Documentation/ABI/testing/sysfs-class-rpmb | 15 +++++++++++++++
MAINTAINERS | 1 +
2 files changed, 16 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-rpmb
diff --git a/Documentation/ABI/testing/sysfs-class-rpmb b/Documentation/ABI/testing/sysfs-class-rpmb
new file mode 100644
index 000000000000..62d1959bf19e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-rpmb
@@ -0,0 +1,15 @@
+What: /sys/class/rpmb/
+Date: Mar 2016
+KernelVersion: TBD
+Contact: Tomas Winkler <[email protected]>
+Description:
+ The rpmb/ class sub-directory belongs to RPMB device class
+
+
+What: /sys/class/rpmb/rpmbN/
+Date: Mar 2016
+KernelVersion: TBD
+Contact: Tomas Winkler <[email protected]>
+Description:
+ The /sys/class/rpmb/rpmbN directory is created for
+ each RPMB registered device
diff --git a/MAINTAINERS b/MAINTAINERS
index 98dcd40ab900..62b9edb8881c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9423,6 +9423,7 @@ L: [email protected]
S: Supported
F: drivers/char/rpmb/*
F: include/linux/rpmb.h
+F: Documentation/ABI/testing/sysfs-class-rpmb
RTL2830 MEDIA DRIVER
M: Antti Palosaari <[email protected]>
--
2.4.3
The user space API is achieved via single synchronous IOCTL.
The request is submitted in_frames_ptr pointer and received
in out_frames_ptr.
Signed-off-by: Tomas Winkler <[email protected]>
---
V2: use memdup_user
Documentation/ioctl/ioctl-number.txt | 1 +
MAINTAINERS | 1 +
drivers/char/rpmb/Kconfig | 7 ++
drivers/char/rpmb/Makefile | 1 +
drivers/char/rpmb/cdev.c | 207 +++++++++++++++++++++++++++++++++++
drivers/char/rpmb/core.c | 9 +-
drivers/char/rpmb/rpmb-cdev.h | 31 ++++++
include/linux/rpmb.h | 78 ++-----------
include/uapi/linux/rpmb.h | 120 ++++++++++++++++++++
9 files changed, 384 insertions(+), 71 deletions(-)
create mode 100644 drivers/char/rpmb/cdev.c
create mode 100644 drivers/char/rpmb/rpmb-cdev.h
create mode 100644 include/uapi/linux/rpmb.h
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 9369d3b0f09a..51a514befa48 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -320,6 +320,7 @@ Code Seq#(hex) Include File Comments
0xB1 00-1F PPPoX <mailto:[email protected]>
0xB3 00 linux/mmc/ioctl.h
0xB4 00-0F linux/gpio.h <mailto:[email protected]>
+0xB5 00 linux/uapi/linux/rpmb.h <mailto:[email protected]>
0xC0 00-0F linux/usb/iowarrior.h
0xCA 00-0F uapi/misc/cxl.h
0xCA 80-8F uapi/scsi/cxlflash_ioctl.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 62b9edb8881c..07bd6f380460 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9422,6 +9422,7 @@ M: Tomas Winkler <[email protected]>
L: [email protected]
S: Supported
F: drivers/char/rpmb/*
+F: include/uapi/linux/rpmb.h
F: include/linux/rpmb.h
F: Documentation/ABI/testing/sysfs-class-rpmb
diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
index c5e6e909efce..6794be9fcc5e 100644
--- a/drivers/char/rpmb/Kconfig
+++ b/drivers/char/rpmb/Kconfig
@@ -6,3 +6,10 @@ config RPMB
access RPMB partition.
If unsure, select N.
+
+config RPMB_INTF_DEV
+ bool "RPMB character device interface /dev/rpmbN"
+ depends on RPMB
+ help
+ Say yes here if you want to access RPMB from user space
+ via character device interface /dev/rpmb%d
diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile
index 812b3ed264c0..b5dc087b1299 100644
--- a/drivers/char/rpmb/Makefile
+++ b/drivers/char/rpmb/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_RPMB) += rpmb.o
rpmb-objs += core.o
+rpmb-$(CONFIG_RPMB_INTF_DEV) += cdev.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/char/rpmb/cdev.c b/drivers/char/rpmb/cdev.c
new file mode 100644
index 000000000000..67e94943d3e3
--- /dev/null
+++ b/drivers/char/rpmb/cdev.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2015-2016 Intel Corp. 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <linux/slab.h>
+#include <linux/rpmb.h>
+
+#include "rpmb-cdev.h"
+
+static dev_t rpmb_devt;
+#define RPMB_MAX_DEVS MINORMASK
+
+#define RPMB_DEV_OPEN 0 /** single open bit (position) */
+
+/**
+ * rpmb_open - the open function
+ *
+ * @inode: pointer to inode structure
+ * @file: pointer to file structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_open(struct inode *inode, struct file *file)
+{
+ struct rpmb_dev *rdev;
+
+ rdev = container_of(inode->i_cdev, struct rpmb_dev, cdev);
+ if (!rdev)
+ return -ENODEV;
+
+ /* the rpmb is single open! */
+ if (test_and_set_bit(RPMB_DEV_OPEN, &rdev->status))
+ return -EBUSY;
+
+ mutex_lock(&rdev->lock);
+
+ file->private_data = rdev;
+
+ mutex_unlock(&rdev->lock);
+
+ return nonseekable_open(inode, file);
+}
+
+static int rpmb_release(struct inode *inode, struct file *file)
+{
+ struct rpmb_dev *rdev = file->private_data;
+
+ clear_bit(RPMB_DEV_OPEN, &rdev->status);
+
+ return 0;
+}
+
+/*
+ * FIMXE: will be exported by the kernel in future version
+ * helper to convert user pointers passed inside __aligned_u64 fields
+ */
+static void __user *u64_to_ptr(__u64 val)
+{
+ return (void __user *) (unsigned long) val;
+}
+
+static int rpmb_ioctl_cmd(struct rpmb_dev *rdev,
+ struct rpmb_ioc_cmd __user *ptr)
+{
+ struct rpmb_ioc_cmd cmd;
+ struct rpmb_data rpmbd;
+ struct rpmb_frame *in_frames = NULL;
+ struct rpmb_frame *out_frames = NULL;
+ size_t in_sz, out_sz;
+ int ret;
+
+ if (copy_from_user(&cmd, ptr, sizeof(cmd)))
+ return -EFAULT;
+
+ if (cmd.in_frames_count == 0 || cmd.out_frames_count == 0)
+ return -EINVAL;
+
+ in_sz = sizeof(struct rpmb_frame) * cmd.in_frames_count;
+ in_frames = memdup_user(u64_to_ptr(cmd.in_frames_ptr), in_sz);
+ if (IS_ERR(in_frames)) {
+ ret = PTR_ERR(in_frames);
+ in_frames = NULL;
+ goto out;
+ }
+
+ out_sz = sizeof(struct rpmb_frame) * cmd.out_frames_count;
+ out_frames = kmalloc(out_sz, GFP_KERNEL);
+ if (!out_frames) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rpmbd.req_type = cmd.req;
+ rpmbd.in_frames = in_frames;
+ rpmbd.out_frames = out_frames;
+ rpmbd.in_frames_cnt = cmd.in_frames_count;
+ rpmbd.out_frames_cnt = cmd.out_frames_count;
+
+ ret = rpmb_send_req(rdev, &rpmbd);
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to process request = %d.\n", ret);
+ goto out;
+ }
+
+ if (copy_to_user(u64_to_ptr(cmd.out_frames_ptr), out_frames, out_sz)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (copy_to_user(ptr, &cmd, sizeof(cmd))) {
+ ret = -EFAULT;
+ goto out;
+ }
+out:
+ kfree(in_frames);
+ kfree(out_frames);
+ return ret;
+}
+
+static long rpmb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct rpmb_dev *rdev = file->private_data;
+ struct rpmb_ioc_cmd __user *req = (void __user *)arg;
+
+ if (cmd != RPMB_IOC_REQ) {
+ dev_err(&rdev->dev, "unsupported ioctl 0x%x.\n", cmd);
+ return -ENOIOCTLCMD;
+ }
+
+ return rpmb_ioctl_cmd(rdev, req);
+}
+
+#ifdef CONFIG_COMPAT
+static long compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct rpmb_dev *rdev = file->private_data;
+ struct rpmb_ioc_cmd __user *req = (void __user *)compat_ptr(arg);
+
+ if (cmd != RPMB_IOC_REQ) {
+ dev_err(&rdev->dev, "unsupported ioctl 0x%x.\n", cmd);
+ return -ENOIOCTLCMD;
+ }
+
+ return rpmb_ioctl_cmd(rdev, req);
+}
+#endif /* CONFIG_COMPAT */
+
+static const struct file_operations rpmb_fops = {
+ .open = rpmb_open,
+ .release = rpmb_release,
+ .unlocked_ioctl = rpmb_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_ioctl,
+#endif
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+};
+
+void rpmb_cdev_prepare(struct rpmb_dev *rdev)
+{
+ rdev->dev.devt = MKDEV(MAJOR(rpmb_devt), rdev->id);
+ rdev->cdev.owner = THIS_MODULE;
+ cdev_init(&rdev->cdev, &rpmb_fops);
+}
+
+void rpmb_cdev_add(struct rpmb_dev *rdev)
+{
+ cdev_add(&rdev->cdev, rdev->dev.devt, 1);
+}
+
+void rpmb_cdev_del(struct rpmb_dev *rdev)
+{
+ if (rdev->dev.devt)
+ cdev_del(&rdev->cdev);
+}
+
+int __init rpmb_cdev_init(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&rpmb_devt, 0, RPMB_MAX_DEVS, "rpmb");
+ if (ret < 0)
+ pr_err("unable to allocate char dev region\n");
+
+ return ret;
+}
+
+void __exit rpmb_cdev_exit(void)
+{
+ if (rpmb_devt)
+ unregister_chrdev_region(rpmb_devt, RPMB_MAX_DEVS);
+}
diff --git a/drivers/char/rpmb/core.c b/drivers/char/rpmb/core.c
index fb401331d345..ce875d773ee4 100644
--- a/drivers/char/rpmb/core.c
+++ b/drivers/char/rpmb/core.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/rpmb.h>
+#include "rpmb-cdev.h"
static DEFINE_IDA(rpmb_ida);
@@ -313,6 +314,7 @@ int rpmb_dev_unregister(struct device *dev)
rpmb_dev_put(rdev);
mutex_lock(&rdev->lock);
+ rpmb_cdev_del(rdev);
device_del(&rdev->dev);
mutex_unlock(&rdev->lock);
@@ -364,10 +366,14 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev,
rdev->dev.parent = dev;
rdev->dev.groups = rpmb_attr_groups;
+ rpmb_cdev_prepare(rdev);
+
ret = device_register(&rdev->dev);
if (ret)
goto exit;
+ rpmb_cdev_add(rdev);
+
dev_dbg(&rdev->dev, "registered disk\n");
return rdev;
@@ -384,11 +390,12 @@ static int __init rpmb_init(void)
{
ida_init(&rpmb_ida);
class_register(&rpmb_class);
- return 0;
+ return rpmb_cdev_init();
}
static void __exit rpmb_exit(void)
{
+ rpmb_cdev_exit();
class_unregister(&rpmb_class);
ida_destroy(&rpmb_ida);
}
diff --git a/drivers/char/rpmb/rpmb-cdev.h b/drivers/char/rpmb/rpmb-cdev.h
new file mode 100644
index 000000000000..d20e0f16f1a1
--- /dev/null
+++ b/drivers/char/rpmb/rpmb-cdev.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015-2016 Intel Corp. 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; version 2 of the License.
+ *
+ * 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_RPMB_INTF_DEV
+int __init rpmb_cdev_init(void);
+void __exit rpmb_cdev_exit(void);
+void rpmb_cdev_prepare(struct rpmb_dev *rdev);
+void rpmb_cdev_add(struct rpmb_dev *rdev);
+void rpmb_cdev_del(struct rpmb_dev *rdev);
+
+#else
+static inline int __init rpmb_cdev_init(void)
+{
+ return 0;
+}
+static inline void __exit rpmb_cdev_exit(void) {}
+static inline void rpmb_cdev_prepare(struct rpmb_dev *rdev) {}
+static inline void rpmb_cdev_add(struct rpmb_dev *rdev) {}
+static inline void rpmb_cdev_del(struct rpmb_dev *rdev) {}
+#endif /* CONFIG_RPMB_INTF_DEV */
diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h
index 2c1e259f1a04..446c6639d275 100644
--- a/include/linux/rpmb.h
+++ b/include/linux/rpmb.h
@@ -15,79 +15,11 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/cdev.h>
+#include <uapi/linux/rpmb.h>
#include <linux/kref.h>
/**
- * struct rpmb_frame - rpmb frame as defined by specs
- *
- * @stuff : stuff bytes
- * @key_mac : The authentication key or the message authentication
- * code (MAC) depending on the request/response type.
- * The MAC will be delivered in the last (or the only)
- * block of data.
- * @data : Data to be written or read by signed access.
- * @nonce : Random number generated by the host for the requests
- * and copied to the response by the RPMB engine.
- * @write_counter: Counter value for the total amount of the successful
- * authenticated data write requests made by the host.
- * @addr : Address of the data to be programmed to or read
- * from the RPMB. Address is the serial number of
- * the accessed block (half sector 256B).
- * @block_count : Number of blocks (half sectors, 256B) requested to be
- * read/programmed.
- * @result : Includes information about the status of the write counter
- * (valid, expired) and result of the access made to the RPMB.
- * @req_resp : Defines the type of request and response to/from the memory.
- */
-struct rpmb_frame {
- u8 stuff[196];
- u8 key_mac[32];
- u8 data[256];
- u8 nonce[16];
- __be32 write_counter;
- __be16 addr;
- __be16 block_count;
- __be16 result;
- __be16 req_resp;
-} __packed;
-
-#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */
-#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */
-#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */
-#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */
-#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */
-
-#define RPMB_REQ2RESP(_OP) ((_OP) << 8)
-#define RPMB_RESP2REQ(_OP) ((_OP) >> 8)
-
-/**
- * enum rpmb_op_result - rpmb operation results
- *
- * @RPMB_ERR_OK : operation successful
- * @RPMB_ERR_GENERAL : general failure
- * @RPMB_ERR_AUTH : mac doesn't match or ac calculation failure
- * @RPMB_ERR_COUNTER : counter doesn't match or counter increment failure
- * @RPMB_ERR_ADDRESS : address out of range or wrong address alignment
- * @RPMB_ERR_WRITE : data, counter, or result write failure
- * @RPMB_ERR_READ : data, counter, or result read failure
- * @RPMB_ERR_NO_KEY : authentication key not yet programmed
- *
- * @RPMB_ERR_COUNTER_EXPIRED: counter expired
- */
-enum rpmb_op_result {
- RPMB_ERR_OK = 0x0000,
- RPMB_ERR_GENERAL = 0x0001,
- RPMB_ERR_AUTH = 0x0002,
- RPMB_ERR_COUNTER = 0x0003,
- RPMB_ERR_ADDRESS = 0x0004,
- RPMB_ERR_WRITE = 0x0005,
- RPMB_ERR_READ = 0x0006,
- RPMB_ERR_NO_KEY = 0x0007,
-
- RPMB_ERR_COUNTER_EXPIRED = 0x0080
-};
-
-/**
* enum rpmb_type - type of underlaying storage technology
*
* @RPMB_TYPE_ANY : any type used for search only
@@ -144,12 +76,18 @@ struct rpmb_ops {
* @lock : lock
* @dev : device
* @id : device id
+ * @cdev : character dev
+ * @status : device status
* @ops : operation exported by block layer
*/
struct rpmb_dev {
struct mutex lock;
struct device dev;
int id;
+#ifdef CONFIG_RPMB_INTF_DEV
+ struct cdev cdev;
+ unsigned long status;
+#endif /* CONFIG_RPMB_INTF_DEV */
const struct rpmb_ops *ops;
};
diff --git a/include/uapi/linux/rpmb.h b/include/uapi/linux/rpmb.h
new file mode 100644
index 000000000000..55aa92e11280
--- /dev/null
+++ b/include/uapi/linux/rpmb.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015-2016, Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation;
+ *
+ * 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 _UAPI_LINUX_RPMB_H_
+#define _UAPI_LINUX_RPMB_H_
+
+#include <linux/types.h>
+
+/**
+ * struct rpmb_frame - rpmb frame as defined by specs
+ *
+ * @stuff : stuff bytes
+ * @key_mac : The authentication key or the message authentication
+ * code (MAC) depending on the request/response type.
+ * The MAC will be delivered in the last (or the only)
+ * block of data.
+ * @data : Data to be written or read by signed access.
+ * @nonce : Random number generated by the host for the requests
+ * and copied to the response by the RPMB engine.
+ * @write_counter: Counter value for the total amount of the successful
+ * authenticated data write requests made by the host.
+ * @addr : Address of the data to be programmed to or read
+ * from the RPMB. Address is the serial number of
+ * the accessed block (half sector 256B).
+ * @block_count : Number of blocks (half sectors, 256B) requested to be
+ * read/programmed.
+ * @result : Includes information about the status of the write counter
+ * (valid, expired) and result of the access made to the RPMB.
+ * @req_resp : Defines the type of request and response to/from the memory.
+ */
+struct rpmb_frame {
+ __u8 stuff[196];
+ __u8 key_mac[32];
+ __u8 data[256];
+ __u8 nonce[16];
+ __be32 write_counter;
+ __be16 addr;
+ __be16 block_count;
+ __be16 result;
+ __be16 req_resp;
+} __attribute__((packed));
+
+#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */
+#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */
+#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */
+#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */
+
+#define RPMB_REQ2RESP(_OP) ((_OP) << 8)
+#define RPMB_RESP2REQ(_OP) ((_OP) >> 8)
+
+/* length of the part of the frame used for HMAC computation */
+#define hmac_data_len \
+ (sizeof(struct rpmb_frame) - offsetof(struct rpmb_frame, data))
+
+/**
+ * enum rpmb_op_result - rpmb operation results
+ *
+ * @RPMB_ERR_OK: operation successful
+ * @RPMB_ERR_GENERAL: general failure
+ * @RPMB_ERR_AUTH: mac doesn't match or ac calculation failure
+ * @RPMB_ERR_COUNTER: counter doesn't match or counter increment failure
+ * @RPMB_ERR_ADDRESS: address out of range or wrong address alignment
+ * @RPMB_ERR_WRITE: data, counter, or result write failure
+ * @RPMB_ERR_READ: data, counter, or result read failure
+ * @RPMB_ERR_NO_KEY: authentication key not yet programmed
+ *
+ * @RPMB_ERR_COUNTER_EXPIRED: counter expired
+ */
+enum rpmb_op_result {
+ RPMB_ERR_OK = 0x0000,
+ RPMB_ERR_GENERAL = 0x0001,
+ RPMB_ERR_AUTH = 0x0002,
+ RPMB_ERR_COUNTER = 0x0003,
+ RPMB_ERR_ADDRESS = 0x0004,
+ RPMB_ERR_WRITE = 0x0005,
+ RPMB_ERR_READ = 0x0006,
+ RPMB_ERR_NO_KEY = 0x0007,
+
+ RPMB_ERR_COUNTER_EXPIRED = 0x0080
+};
+
+/**
+ * struct rpmb_ioc_cmd - rpmb operation request command
+ *
+ * @req: request type: must match the in frame req_resp
+ * program key
+ * get write counter
+ * write/read data
+ * @in_frames_count: number of in frames
+ * @out_frames_count: number of out frames
+ * @in_frames_ptr: a pointer to the input frames buffer
+ * @out_frames_ptr: a pointer to output frames buffer
+ */
+struct rpmb_ioc_cmd {
+ __u32 req;
+ __u32 in_frames_count;
+ __u32 out_frames_count;
+ __aligned_u64 in_frames_ptr;
+ __aligned_u64 out_frames_ptr;
+};
+
+#define rpmb_ioc_cmd_set_in_frames(_ic, _ptr) \
+ (_ic).in_frames_ptr = (__aligned_u64)(intptr_t)(_ptr)
+#define rpmb_ioc_cmd_set_out_frames(_ic, _ptr) \
+ (_ic).out_frames_ptr = (__aligned_u64)(intptr_t)(_ptr)
+
+#define RPMB_IOC_REQ _IOWR(0xB5, 1, struct rpmb_ioc_cmd)
+
+#endif /* _UAPI_LINUX_RPMB_H_ */
--
2.4.3
Add simple RPMB host testing tool. It can be used
to program key, write and read data block, and retrieve
write counter.
Signed-off-by: Tomas Winkler <[email protected]>
---
V2: resend
MAINTAINERS | 1 +
tools/Makefile | 16 +-
tools/rpmb/.gitignore | 2 +
tools/rpmb/Makefile | 32 ++
tools/rpmb/rpmb.c | 807 ++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 853 insertions(+), 5 deletions(-)
create mode 100644 tools/rpmb/.gitignore
create mode 100644 tools/rpmb/Makefile
create mode 100644 tools/rpmb/rpmb.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 07bd6f380460..b7966b95c265 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9425,6 +9425,7 @@ F: drivers/char/rpmb/*
F: include/uapi/linux/rpmb.h
F: include/linux/rpmb.h
F: Documentation/ABI/testing/sysfs-class-rpmb
+F: tools/rpmb/
RTL2830 MEDIA DRIVER
M: Antti Palosaari <[email protected]>
diff --git a/tools/Makefile b/tools/Makefile
index 60c7e6c8ff17..5b37ccd95cab 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -19,6 +19,7 @@ help:
@echo ' lguest - a minimal 32-bit x86 hypervisor'
@echo ' net - misc networking tools'
@echo ' perf - Linux performance measurement and analysis tool'
+ @echo ' rpmb - Replay protected memory block access tool'
@echo ' selftests - various kernel selftests'
@echo ' spi - spi tools'
@echo ' objtool - an ELF object analysis tool'
@@ -55,7 +56,8 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)
-cgroup firewire hv guest spi usb virtio vm net iio gpio objtool: FORCE
+cgroup firewire hv guest rpmb spi usb virtio vm net iio gpio objtool: FORCE
+cgroup firewire hv guest rpmb spi usb virtio vm net iio: FORCE
$(call descend,$@)
liblockdep: FORCE
@@ -85,7 +87,7 @@ freefall: FORCE
$(call descend,laptop/$@)
all: acpi cgroup cpupower hv firewire lguest \
- perf selftests turbostat usb \
+ perf rpmb selftests turbostat usb \
virtio vm net x86_energy_perf_policy \
tmon freefall objtool
@@ -95,7 +97,8 @@ acpi_install:
cpupower_install:
$(call descend,power/$(@:_install=),install)
-cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install:
+cgroup_install firewire_install hv_install lguest_install perf_install rpmb_install usb_install virtio_install vm_install net_install objtool_install:
+cgroup_install firewire_install hv_install lguest_install perf_install rpmb_install usb_install virtio_install vm_install net_install:
$(call descend,$(@:_install=),install)
selftests_install:
@@ -111,7 +114,7 @@ freefall_install:
$(call descend,laptop/$(@:_install=),install)
install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
- perf_install selftests_install turbostat_install usb_install \
+ perf_install rpmb_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \
tmon_install freefall_install objtool_install
@@ -139,6 +142,9 @@ libsubcmd_clean:
perf_clean:
$(call descend,$(@:_clean=),clean)
+rpmb_clean:
+ $(call descend,$(@:_clean=),clean)
+
selftests_clean:
$(call descend,testing/$(@:_clean=),clean)
@@ -155,7 +161,7 @@ build_clean:
$(call descend,build,clean)
clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
- perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
+ perf_clean rpmb_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
gpio_clean objtool_clean
diff --git a/tools/rpmb/.gitignore b/tools/rpmb/.gitignore
new file mode 100644
index 000000000000..218f680548e6
--- /dev/null
+++ b/tools/rpmb/.gitignore
@@ -0,0 +1,2 @@
+*.o
+rpmb
diff --git a/tools/rpmb/Makefile b/tools/rpmb/Makefile
new file mode 100644
index 000000000000..e0e51f306dac
--- /dev/null
+++ b/tools/rpmb/Makefile
@@ -0,0 +1,32 @@
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+PKG_CONFIG = $(CROSS_COMPILE)pkg-config
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
+INSTALL = install
+prefix ?= /usr/local
+bindir = $(prefix)/bin
+
+
+CFLAGS += -D__EXPORTED_HEADERS__
+CFLAGS += -I$(srctree)/include/uapi -I$(srctree)/include
+LDLIBS += $(shell $(PKG_CONFIG) --libs libcrypto)
+
+prog := rpmb
+
+all : $(prog)
+
+$(prog): rpmb.o
+
+clean :
+ $(RM) $(prog) *.o
+
+install: $(prog)
+ $(INSTALL) -m755 -d $(DESTDIR)$(bindir)
+ $(INSTALL) $(prog) $(DESTDIR)$(bindir)
+
diff --git a/tools/rpmb/rpmb.c b/tools/rpmb/rpmb.c
new file mode 100644
index 000000000000..e55f4d4e7ef7
--- /dev/null
+++ b/tools/rpmb/rpmb.c
@@ -0,0 +1,807 @@
+/******************************************************************************
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation.
+ * [email protected]
+ * http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <openssl/engine.h>
+#include <openssl/hmac.h>
+
+#include "linux/rpmb.h"
+
+#define RPMB_KEY_SIZE 32
+#define RPMB_MAC_SIZE 32
+#define RPMB_NONCE_SIZE 16
+
+#define rpmb_msg(fmt, ARGS...) \
+ fprintf(stderr, "rpmb: " fmt, ##ARGS)
+
+#define rpmb_err(fmt, ARGS...) \
+ fprintf(stderr, "rpmb: error: " fmt, ##ARGS)
+
+static const char *rpmb_op_str(uint16_t op)
+{
+#define RPMB_OP(_op) case RPMB_##_op: return #_op
+
+ switch (op) {
+ RPMB_OP(PROGRAM_KEY);
+ RPMB_OP(GET_WRITE_COUNTER);
+ RPMB_OP(WRITE_DATA);
+ RPMB_OP(READ_DATA);
+ RPMB_OP(RESULT_READ);
+ break;
+ default:
+ return "unknown";
+ }
+}
+
+static const char *rpmb_result_str(enum rpmb_op_result result)
+{
+#define str(x) #x
+#define RPMB_ERR(_res) case RPMB_ERR_##_res: \
+ { if (result & RPMB_ERR_COUNTER_EXPIRED) \
+ return "COUNTER_EXPIRE:" str(_res); \
+ else \
+ return #_res; \
+ }
+
+ switch (result & 0x000F) {
+ RPMB_ERR(OK);
+ RPMB_ERR(GENERAL);
+ RPMB_ERR(AUTH);
+ RPMB_ERR(COUNTER);
+ RPMB_ERR(ADDRESS);
+ RPMB_ERR(WRITE);
+ RPMB_ERR(READ);
+ RPMB_ERR(NO_KEY);
+ break;
+ default:
+ return "unknown";
+ }
+#undef RPMB_ERR
+};
+
+static inline void __dump_buffer(const char *buf)
+{
+ fprintf(stderr, "%s\n", buf);
+}
+static void rpmb_dump_hex_buffer(const unsigned char *buf, size_t len)
+{
+ const size_t pbufsz = 16 * 3;
+ char pbuf[pbufsz];
+ int j = 0;
+
+ while (len-- > 0) {
+ snprintf(&pbuf[j], pbufsz - j, "%02X ", *buf++);
+ j += 3;
+ if (j == 16 * 3) {
+ __dump_buffer(pbuf);
+ j = 0;
+ }
+ }
+ if (j)
+ __dump_buffer(pbuf);
+}
+
+static int open_dev_file(const char *devfile)
+{
+ int fd;
+
+ fd = open(devfile, O_RDWR);
+ if (fd < 0)
+ rpmb_err("Cannot open: %s: %s\n", devfile, strerror(errno));
+ return fd;
+}
+
+static int open_rd_file(const char *datafile, const char *type)
+{
+ int fd;
+
+ if (!strcmp(datafile, "-"))
+ fd = STDIN_FILENO;
+ else
+ fd = open(datafile, O_RDONLY);
+
+ if (fd < 0)
+ rpmb_err("Cannot open %s: %s: %s\n",
+ type, datafile, strerror(errno));
+
+ return fd;
+}
+
+static int open_wr_file(const char *datafile, const char *type)
+{
+ int fd;
+
+ if (!strcmp(datafile, "-"))
+ fd = STDOUT_FILENO;
+ else
+ fd = open(datafile, O_WRONLY | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ rpmb_err("Cannot open %s: %s: %s\n",
+ type, datafile, strerror(errno));
+ return fd;
+}
+
+static void close_fd(int fd)
+{
+ if (fd > 0 && fd != STDIN_FILENO && fd != STDOUT_FILENO)
+ close(fd);
+}
+
+/* blocking rw wrapper */
+#define rw(func, fd, buf, size) \
+({ \
+ ssize_t nread = 0, n; \
+ char *_buf = (char *)buf; \
+ do { \
+ n = func(fd, _buf + nread, size - nread); \
+ if (n == -1 && errno != EINTR) { \
+ nread = -1; \
+ break; \
+ } else if (n > 0) { \
+ nread += n; \
+ } \
+ } while (n != 0 && (size_t)nread != size); \
+ nread; \
+})
+
+
+static ssize_t read_file(int fd, unsigned char *data, size_t size)
+{
+ ssize_t ret;
+
+ ret = rw(read, fd, data, size);
+ if (ret < 0) {
+ rpmb_err("cannot read file: %s\n", strerror(errno));
+ } else if (ret != size) {
+ rpmb_err("read %zd but must be %zu bytes length\n",
+ ret, size);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t write_file(int fd, unsigned char *data, size_t size)
+{
+ ssize_t ret;
+
+ ret = rw(write, fd, data, size);
+ if (ret < 0) {
+ rpmb_err("cannot read file: %s\n", strerror(errno));
+ } else if (ret != size) {
+ rpmb_err("data is %zd but must be %zu bytes length\n",
+ ret, size);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int rpmb_calc_hmac_sha256(struct rpmb_frame *frames, size_t blocks_cnt,
+ const unsigned char key[],
+ unsigned int key_size,
+ unsigned char mac[],
+ unsigned int mac_size)
+{
+ HMAC_CTX ctx;
+ int ret;
+ int i;
+
+ /* SSL returns 1 on success 0 on failure */
+
+ HMAC_CTX_init(&ctx);
+ ret = HMAC_Init_ex(&ctx, key, key_size, EVP_sha256(), NULL);
+ if (ret == 0)
+ goto out;
+ for (i = 0; i < blocks_cnt; i++)
+ HMAC_Update(&ctx, frames[i].data, hmac_data_len);
+
+ ret = HMAC_Final(&ctx, mac, &mac_size);
+ if (ret == 0)
+ goto out;
+ if (mac_size != RPMB_MAC_SIZE)
+ ret = 0;
+
+ ret = 1;
+out:
+ HMAC_CTX_cleanup(&ctx);
+ return ret == 1 ? 0 : -1;
+}
+
+static int rpmb_ioctl(int fd, uint16_t req,
+ const struct rpmb_frame *frames_in,
+ unsigned int in_cnt,
+ struct rpmb_frame *frames_out,
+ unsigned int out_cnt)
+{
+ int ret;
+ struct rpmb_ioc_cmd icmd;
+
+ icmd.req = req;
+ icmd.in_frames_count = in_cnt;
+ rpmb_ioc_cmd_set_in_frames(icmd, frames_in);
+ rpmb_ioc_cmd_set_out_frames(icmd, frames_out);
+ icmd.out_frames_count = out_cnt;
+
+ ret = ioctl(fd, RPMB_IOC_REQ, &icmd);
+ if (ret < 0)
+ rpmb_err("ioctl failure %d: %s\n", ret, strerror(errno));
+
+ return ret;
+}
+
+
+static int op_rpmb_program_key(int nargs, char *argv[])
+{
+ int ret;
+ int dev_fd = -1, key_fd = -1;
+ uint16_t req = RPMB_PROGRAM_KEY;
+ struct rpmb_frame frame_in, frame_out;
+
+ ret = -EINVAL;
+ if (nargs != 2)
+ return ret;
+
+ dev_fd = open_dev_file(argv[0]);
+ if (dev_fd < 0)
+ goto out;
+ argv++;
+
+ key_fd = open_rd_file(argv[0], "key file");
+ if (key_fd < 0)
+ goto out;
+ argv++;
+
+ memset(&frame_in, 0, sizeof(frame_in));
+ frame_in.req_resp = htobe16(req);
+
+ read_file(key_fd, frame_in.key_mac, RPMB_KEY_SIZE);
+
+ ret = rpmb_ioctl(dev_fd, req, &frame_in, 1, &frame_out, 1);
+ if (ret)
+ goto out;
+
+ ret = be16toh(frame_out.result);
+ if (ret)
+ rpmb_err("RPMB operation %s failed, %s[0x%04x]\n",
+ rpmb_op_str(req), rpmb_result_str(ret), ret);
+
+out:
+ close_fd(dev_fd);
+ close_fd(key_fd);
+
+ return ret;
+}
+
+static int rpmb_get_write_counter(int dev_fd, unsigned int *cnt,
+ const unsigned char *key)
+{
+ int ret;
+ uint16_t req = RPMB_GET_WRITE_COUNTER;
+ unsigned char mac[RPMB_MAC_SIZE];
+ struct rpmb_frame frame_in;
+ struct rpmb_frame frame_out;
+
+ memset(&frame_in, 0, sizeof(frame_in));
+ frame_in.req_resp = htobe16(req);
+ RAND_bytes(frame_in.nonce, RPMB_NONCE_SIZE);
+
+ ret = rpmb_ioctl(dev_fd, req, &frame_in, 1, &frame_out, 1);
+ if (ret != 0)
+ return ret;
+
+ ret = be16toh(frame_out.result);
+ if (ret)
+ goto out;
+
+ if (key) {
+ rpmb_calc_hmac_sha256(&frame_out, 1,
+ key, RPMB_KEY_SIZE,
+ mac, RPMB_MAC_SIZE);
+ if (memcmp(mac, frame_out.key_mac, RPMB_MAC_SIZE)) {
+ rpmb_err("RPMB hmac mismatch\n");
+ rpmb_dump_hex_buffer(frame_out.key_mac, RPMB_MAC_SIZE);
+ rpmb_dump_hex_buffer(mac, RPMB_MAC_SIZE);
+ ret = RPMB_ERR_AUTH;
+ goto out;
+ }
+ }
+
+ *cnt = be32toh(frame_out.write_counter);
+
+out:
+ if (ret) {
+ rpmb_err("RPMB operation %s failed, %s[0x%04x]\n",
+ rpmb_op_str(req), rpmb_result_str(ret), ret);
+ }
+ return ret;
+}
+
+static int op_rpmb_get_write_counter(int nargs, char **argv)
+{
+ int ret;
+ int dev_fd = -1, key_fd = -1;
+ bool has_key;
+ unsigned char key[RPMB_KEY_SIZE];
+ unsigned int cnt;
+
+ if (nargs == 2)
+ has_key = true;
+ else if (nargs == 1)
+ has_key = false;
+ else
+ return -EINVAL;
+
+ ret = -EINVAL;
+ dev_fd = open_dev_file(argv[0]);
+ if (dev_fd < 0)
+ return ret;
+ argv++;
+
+ if (has_key) {
+ key_fd = open_rd_file(argv[0], "key file");
+ if (key_fd < 0)
+ goto out;
+ argv++;
+
+ ret = read_file(key_fd, key, RPMB_KEY_SIZE);
+ if (ret < 0)
+ goto out;
+
+ ret = rpmb_get_write_counter(dev_fd, &cnt, key);
+ } else {
+ ret = rpmb_get_write_counter(dev_fd, &cnt, NULL);
+ }
+
+ if (!ret)
+ printf("Counter value: 0x%08x\n", cnt);
+
+out:
+ close_fd(dev_fd);
+ close_fd(key_fd);
+ return ret;
+}
+
+static int op_rpmb_read_blocks(int nargs, char **argv)
+{
+ int i, ret;
+ int dev_fd = -1, data_fd = -1, key_fd = -1;
+ uint16_t req = RPMB_READ_DATA;
+ uint16_t addr, blocks_cnt;
+ unsigned char key[RPMB_KEY_SIZE];
+ unsigned char mac[RPMB_MAC_SIZE];
+ unsigned long numarg;
+ bool has_key;
+ struct rpmb_frame frame_in;
+ struct rpmb_frame *frames_out = NULL;
+ struct rpmb_frame *frame_out;
+
+ ret = -EINVAL;
+ if (nargs == 4)
+ has_key = false;
+ else if (nargs == 5)
+ has_key = true;
+ else
+ return ret;
+
+ dev_fd = open_dev_file(argv[0]);
+ if (dev_fd < 0)
+ goto out;
+ argv++;
+
+ errno = 0;
+ numarg = strtoul(argv[0], NULL, 0);
+ if (errno || numarg > USHRT_MAX) {
+ rpmb_err("wrong block address\n");
+ goto out;
+ }
+ addr = (uint16_t)numarg;
+ argv++;
+
+ errno = 0;
+ numarg = strtoul(argv[0], NULL, 0);
+ if (errno || numarg > USHRT_MAX) {
+ rpmb_err("wrong blocks count\n");
+ goto out;
+ }
+ blocks_cnt = (uint16_t)numarg;
+ argv++;
+
+ if (blocks_cnt == 0) {
+ rpmb_err("wrong blocks count\n");
+ goto out;
+ }
+
+ data_fd = open_wr_file(argv[0], "output data");
+ if (data_fd < 0)
+ goto out;
+ argv++;
+
+ if (has_key) {
+ key_fd = open_rd_file(argv[0], "key file");
+ if (key_fd < 0)
+ goto out;
+ argv++;
+
+ ret = read_file(key_fd, key, RPMB_KEY_SIZE);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = 0;
+ memset(&frame_in, 0, sizeof(frame_in));
+ frame_in.req_resp = htobe16(req);
+ frame_in.addr = htobe16(addr);
+ frame_in.block_count = htobe16(blocks_cnt);
+ if (has_key)
+ RAND_bytes(frame_in.nonce, RPMB_NONCE_SIZE);
+
+ frames_out = calloc(blocks_cnt, sizeof(struct rpmb_frame));
+ if (!frames_out) {
+ rpmb_err("Cannot allocate %d RPMB frames\n", blocks_cnt);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = rpmb_ioctl(dev_fd, req, &frame_in, 1, frames_out, blocks_cnt);
+ if (ret)
+ goto out;
+
+ frame_out = &frames_out[blocks_cnt - 1];
+ ret = be16toh(frame_out->result);
+ if (ret) {
+ rpmb_err("RPMB operation %s failed, %s[0x%04x]\n",
+ rpmb_op_str(req), rpmb_result_str(ret), ret);
+ goto out;
+ }
+
+ if (has_key) {
+ rpmb_calc_hmac_sha256(frames_out, blocks_cnt,
+ key, RPMB_KEY_SIZE,
+ mac, RPMB_MAC_SIZE);
+ if (memcmp(mac, frame_out->key_mac, RPMB_MAC_SIZE)) {
+ rpmb_err("RPMB hmac mismatch\n");
+ rpmb_dump_hex_buffer(frame_out->key_mac, RPMB_MAC_SIZE);
+ rpmb_dump_hex_buffer(mac, RPMB_MAC_SIZE);
+ ret = RPMB_ERR_AUTH;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < blocks_cnt; i++) {
+ ret = write_file(data_fd,
+ frames_out[i].data, sizeof(frames_out[i].data));
+ if (ret < 0)
+ goto out;
+ }
+
+out:
+ free(frames_out);
+ close_fd(dev_fd);
+ close_fd(data_fd);
+ close_fd(key_fd);
+
+ return ret;
+}
+
+static int op_rpmb_write_blocks(int nargs, char **argv)
+{
+ int ret;
+ int dev_fd = -1, key_fd = -1, data_fd = -1;
+ int i;
+ uint16_t req = RPMB_WRITE_DATA;
+ unsigned char key[RPMB_KEY_SIZE];
+ unsigned char mac[RPMB_MAC_SIZE];
+ unsigned long numarg;
+ uint16_t addr, blocks_cnt;
+ unsigned int cnt;
+ struct rpmb_frame *frames_in;
+ struct rpmb_frame frame_out;
+
+ ret = -EINVAL;
+ if (nargs != 5)
+ goto out;
+
+ dev_fd = open_dev_file(argv[0]);
+ if (dev_fd < 0)
+ goto out;
+ argv++;
+
+ errno = 0;
+ numarg = strtoul(argv[0], NULL, 0);
+ if (errno || numarg > USHRT_MAX) {
+ rpmb_err("wrong block address %s\n", argv[0]);
+ goto out;
+ }
+ addr = (uint16_t)numarg;
+ argv++;
+
+ errno = 0;
+ numarg = strtoul(argv[0], NULL, 0);
+ if (errno || numarg > USHRT_MAX) {
+ rpmb_err("wrong blocks count\n");
+ goto out;
+ }
+ blocks_cnt = (uint16_t)numarg;
+ argv++;
+
+ if (blocks_cnt == 0) {
+ rpmb_err("wrong blocks count\n");
+ goto out;
+ }
+
+ data_fd = open_rd_file(argv[0], "data file");
+ if (data_fd < 0)
+ goto out;
+ argv++;
+
+ key_fd = open_rd_file(argv[0], "key file");
+ if (key_fd < 0)
+ goto out;
+ argv++;
+
+ ret = read_file(key_fd, key, RPMB_KEY_SIZE);
+ if (ret < 0)
+ goto out;
+
+ frames_in = calloc(blocks_cnt, sizeof(struct rpmb_frame));
+ if (!frames_in) {
+ rpmb_err("can't allocate memory for RPMB outer frames\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = rpmb_get_write_counter(dev_fd, &cnt, key);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < blocks_cnt; i++) {
+ frames_in[i].req_resp = htobe16(req);
+ frames_in[i].block_count = htobe16(blocks_cnt);
+ frames_in[i].addr = htobe16(addr);
+ frames_in[i].write_counter = htobe32(cnt);
+ }
+
+ for (i = 0; i < blocks_cnt; i++) {
+ ret = read_file(data_fd, frames_in[i].data,
+ sizeof(frames_in[0].data));
+ if (ret < 0)
+ goto out;
+ }
+
+ rpmb_calc_hmac_sha256(frames_in, blocks_cnt,
+ key, RPMB_KEY_SIZE,
+ mac, RPMB_MAC_SIZE);
+ memcpy(frames_in[blocks_cnt - 1].key_mac, mac, RPMB_MAC_SIZE);
+ ret = rpmb_ioctl(dev_fd, req, frames_in, blocks_cnt, &frame_out, 1);
+ if (ret != 0)
+ goto out;
+
+ ret = be16toh(frame_out.result);
+ if (ret) {
+ rpmb_err("RPMB operation %s failed, %s[0x%04x]\n",
+ rpmb_op_str(req), rpmb_result_str(ret), ret);
+ }
+out:
+ close_fd(dev_fd);
+ close_fd(data_fd);
+ close_fd(key_fd);
+ return ret;
+}
+
+typedef int (*rpmb_op)(int argc, char *argv[]);
+
+struct rpmb_cmd {
+ const char *op_name;
+ rpmb_op op;
+ const char *usage; /* usage title */
+ const char *help; /* help */
+};
+
+
+static const struct rpmb_cmd cmds[] = {
+ {
+ "program-key",
+ op_rpmb_program_key,
+ "<RPMB_DEVICE> <KEY_FILE>",
+ " Program authentication key of 32 bytes length from the KEY_FILE\n"
+ " when KEY_FILE is -, read standard input.\n"
+ " NOTE: This is a one-time programmable irreversible change.\n",
+ },
+ {
+ "write-counter",
+ op_rpmb_get_write_counter,
+ "<RPMB_DEVICE> [KEY_FILE]",
+ " Rertrive write counter value from the <RPMB_DEVICE> to stdout.\n"
+ " When KEY_FILE is present data is verified via HMAC\n"
+ " when KEY_FILE is -, read standard input.\n"
+ },
+ {
+ "write-blocks",
+ op_rpmb_write_blocks,
+ "<RPMB_DEVICE> <address> <block_count> <DATA_FILE> <KEY_FILE>",
+ " <block count> of 256 bytes will be written from the DATA_FILE\n"
+ " to the <RPMB_DEVICE> at block offset <address>.\n"
+ " When DATA_FILE is -, read from standard input.\n",
+ },
+ {
+ "read-blocks",
+ op_rpmb_read_blocks,
+ "<RPMB_DEVICE> <address> <blocks count> <OUTPUT_FILE> [KEY_FILE]",
+ " <block count> of 256 bytes will be read from <RPMB_DEVICE>\n"
+ " to the OUTPUT_FILE\n"
+ " When KEY_FILE is present data is verified via HMAC\n"
+ " When OUTPUT/KEY_FILE is -, read from standard input.\n"
+ " When OUTPUT_FILE is -, write to standard output\n",
+ },
+
+ { NULL, NULL, NULL, NULL }
+};
+
+static void help(const char *prog, const struct rpmb_cmd *cmd)
+{
+ printf("%s %s %s\n", prog, cmd->op_name, cmd->usage);
+ printf("%s\n", cmd->help);
+}
+
+static void usage(const char *prog)
+{
+ int i;
+
+ printf("\n");
+ printf("Usage: %s <command> <args>\n\n", prog);
+ for (i = 0; cmds[i].op_name; i++)
+ printf(" %s %s %s\n",
+ prog, cmds[i].op_name, cmds[i].usage);
+
+ printf("\n");
+ printf(" %s help : shows this help\n", prog);
+ printf(" %s help <command>: shows detailed help\n", prog);
+}
+
+static bool call_for_help(const char *arg)
+{
+ return !strcmp(arg, "help") ||
+ !strcmp(arg, "-h") ||
+ !strcmp(arg, "--help");
+}
+
+static const
+struct rpmb_cmd *parse_args(const char *prog, int *_argc, char **_argv[])
+{
+
+ int i;
+ int argc = *_argc;
+ char **argv = *_argv;
+ const struct rpmb_cmd *cmd = NULL;
+ bool need_help = false;
+
+ argc--; argv++;
+
+ if (argc == 0)
+ goto out;
+
+ if (call_for_help(argv[0])) {
+ argc--; argv++;
+ if (argc == 0)
+ goto out;
+ else
+ need_help = true;
+ }
+
+ for (i = 0; cmds[i].op_name; i++) {
+ if (!strncmp(argv[0], cmds[i].op_name,
+ strlen(cmds[i].op_name))) {
+ cmd = &cmds[i];
+ argc--; argv++;
+ break;
+ }
+ }
+
+ if (!cmd)
+ goto out;
+
+ if (need_help || (argc > 0 && call_for_help(argv[0]))) {
+ help(prog, cmd);
+ argc--; argv++;
+ return NULL;
+ }
+
+out:
+ *_argc = argc;
+ *_argv = argv;
+
+ if (!cmd)
+ usage(prog);
+
+ return cmd;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *prog = basename(argv[0]);
+ const struct rpmb_cmd *cmd;
+ int ret;
+
+ cmd = parse_args(prog, &argc, &argv);
+ if (!cmd)
+ exit(EXIT_SUCCESS);
+
+ ret = cmd->op(argc, argv);
+ if (ret == -EINVAL)
+ help(prog, cmd);
+
+ if (ret)
+ exit(EXIT_FAILURE);
+
+ exit(EXIT_SUCCESS);
+}
--
2.4.3
This is simple platform device for used for testing
rpmb subystem.
The module currently suppot two configuration options
1.max_wr_blks: for specifying max blocks that can be written
in a single command and.
2. daunits: used to set storage capacity in 128K units.
Signed-off-by: Tomas Winkler <[email protected]>
---
V2: remove .owner setting, it is set automatically
drivers/char/rpmb/Kconfig | 10 +
drivers/char/rpmb/Makefile | 1 +
drivers/char/rpmb/rpmb_sim.c | 583 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 594 insertions(+)
create mode 100644 drivers/char/rpmb/rpmb_sim.c
diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
index 6794be9fcc5e..09225080c7fc 100644
--- a/drivers/char/rpmb/Kconfig
+++ b/drivers/char/rpmb/Kconfig
@@ -13,3 +13,13 @@ config RPMB_INTF_DEV
help
Say yes here if you want to access RPMB from user space
via character device interface /dev/rpmb%d
+
+
+config RPMB_SIM
+ tristate "RPMB partition device simulator"
+ default n
+ depends on RPMB
+ select CRYPTO_SHA256
+ select CRYPTO_HMAC
+ help
+ RPMB partition simulator used for testing the RPMB subsystem
diff --git a/drivers/char/rpmb/Makefile b/drivers/char/rpmb/Makefile
index b5dc087b1299..81f924fd9a87 100644
--- a/drivers/char/rpmb/Makefile
+++ b/drivers/char/rpmb/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_RPMB) += rpmb.o
rpmb-objs += core.o
rpmb-$(CONFIG_RPMB_INTF_DEV) += cdev.o
+obj-$(CONFIG_RPMB_SIM) += rpmb_sim.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/char/rpmb/rpmb_sim.c b/drivers/char/rpmb/rpmb_sim.c
new file mode 100644
index 000000000000..d2caa80eefb0
--- /dev/null
+++ b/drivers/char/rpmb/rpmb_sim.c
@@ -0,0 +1,583 @@
+/******************************************************************************
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Corporation.
+ * [email protected]
+ * http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <crypto/hash.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+
+#include <linux/rpmb.h>
+
+static const char id[] = "RPMB:SIM";
+#define CAPACITY_UNIT SZ_128K
+#define CAPACITY_MIN SZ_128K
+#define CAPACITY_MAX SZ_16M
+#define BLK_UNIT SZ_256
+
+static unsigned int max_wr_blks = 1;
+module_param(max_wr_blks, uint, 0644);
+MODULE_PARM_DESC(max_wr_blks,
+ "max blocks that can be written in a single command (default: 1)");
+
+static unsigned int daunits = 1;
+module_param(daunits, uint, 0644);
+MODULE_PARM_DESC(daunits,
+ "number of data area units of 128K (default: 1)");
+
+struct blk {
+ u8 data[BLK_UNIT];
+};
+
+/**
+ * struct rpmb_sim_dev
+ *
+ * @dev: back pointer to the platform device
+ * @rdev: rpmb device
+ * @auth_key: Authentication key register which is used to authenticate
+ * accesses when MAC is calculated;
+ * @auth_key_set: true if auth key was set
+ * @write_counter: Counter value for the total amount of successful
+ * authenticated data write requests made by the host.
+ * The initial value of this register after production is 00000000h.
+ * The value will be incremented by one along with each successful
+ * programming access. The value cannot be reset. After the counter
+ * has reached the maximum value of FFFFFFFFh,
+ * it will not be incremented anymore (overflow prevention)
+ * @hash_tfm: hmac(sha256) tfm
+ *
+ * @capacity: size of the partition in bytes multiple of 128K
+ * @blkcnt: block count
+ * @da: data area in blocks
+ */
+struct rpmb_sim_dev {
+ struct device *dev;
+ struct rpmb_dev *rdev;
+ u8 auth_key[32];
+ bool auth_key_set;
+ u32 write_counter;
+ struct crypto_shash *hash_tfm;
+
+ size_t capacity;
+ size_t blkcnt;
+ struct blk *da;
+};
+
+static __be16 op_result(struct rpmb_sim_dev *rsdev, u16 result)
+{
+ if (!rsdev->auth_key_set)
+ return cpu_to_be16(RPMB_ERR_NO_KEY);
+
+ if (rsdev->write_counter == 0xFFFFFFFF)
+ result |= RPMB_ERR_COUNTER_EXPIRED;
+
+ return cpu_to_be16(result);
+}
+
+static __be16 req_to_resp(u16 req)
+{
+ return cpu_to_be16(RPMB_REQ2RESP(req));
+}
+
+static int rpmb_sim_calc_hmac(struct rpmb_sim_dev *rsdev,
+ struct rpmb_frame *frames,
+ unsigned int blks, u8 *mac)
+{
+ SHASH_DESC_ON_STACK(desc, rsdev->hash_tfm);
+ int i;
+ int ret;
+
+ desc->tfm = rsdev->hash_tfm;
+ desc->flags = 0;
+
+ ret = crypto_shash_init(desc);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < blks; i++) {
+ ret = crypto_shash_update(desc, frames[i].data, hmac_data_len);
+ if (ret)
+ goto out;
+ }
+ ret = crypto_shash_final(desc, mac);
+out:
+ if (ret)
+ dev_err(rsdev->dev, "digest error = %d", ret);
+
+ return ret;
+}
+
+static int rpmb_op_not_programmed(struct rpmb_sim_dev *rsdev,
+ struct rpmb_data *rpmbd)
+{
+ struct rpmb_frame *in_frame, *out_frame;
+ u16 req;
+
+ in_frame = &rpmbd->in_frames[0];
+ req = be16_to_cpu(in_frame->req_resp);
+
+ out_frame = &rpmbd->out_frames[0];
+
+ out_frame->req_resp = req_to_resp(req);
+ out_frame->result = op_result(rsdev, RPMB_ERR_NO_KEY);
+
+ dev_err(rsdev->dev, "not programmed\n");
+
+ return 0;
+}
+
+static int rpmb_op_program_key(struct rpmb_sim_dev *rsdev,
+ struct rpmb_data *rpmbd)
+{
+ struct rpmb_frame *in_frame, *out_frame;
+ u16 req;
+ int ret;
+ u16 err = RPMB_ERR_OK;
+
+ in_frame = rpmbd->in_frames;
+ req = be16_to_cpu(in_frame[0].req_resp);
+
+ if (req != RPMB_PROGRAM_KEY)
+ return -EINVAL;
+
+ if (rsdev->auth_key_set) {
+ dev_err(rsdev->dev, "key allread set\n");
+ err = RPMB_ERR_WRITE;
+ goto out;
+ }
+
+ ret = crypto_shash_setkey(rsdev->hash_tfm, in_frame[0].key_mac, 32);
+ if (ret) {
+ dev_err(rsdev->dev, "set key failed = %d\n", ret);
+ err = RPMB_ERR_GENERAL;
+ goto out;
+ }
+
+ dev_dbg(rsdev->dev, "digest size %u",
+ crypto_shash_digestsize(rsdev->hash_tfm));
+
+ memcpy(rsdev->auth_key, in_frame[0].key_mac, 32);
+ rsdev->auth_key_set = true;
+out:
+ out_frame = rpmbd->out_frames;
+ memset(out_frame, 0, sizeof(struct rpmb_frame));
+
+ out_frame[0].req_resp = req_to_resp(req);
+ out_frame[0].result = op_result(rsdev, err);
+
+ return 0;
+}
+
+
+static int rpmb_op_get_wr_conter(struct rpmb_sim_dev *rsdev,
+ struct rpmb_data *rpmbd)
+{
+ struct rpmb_frame *in_frame, *out_frame;
+ u16 req;
+ u16 err;
+
+ in_frame = rpmbd->in_frames;
+ req = be16_to_cpu(in_frame[0].req_resp);
+
+ if (req != RPMB_GET_WRITE_COUNTER)
+ return -EINVAL;
+
+ out_frame = rpmbd->out_frames;
+ memset(out_frame, 0, sizeof(struct rpmb_frame));
+
+ out_frame[0].req_resp = req_to_resp(req);
+ out_frame[0].write_counter = cpu_to_be32(rsdev->write_counter);
+ memcpy(out_frame[0].nonce, in_frame[0].nonce, 16);
+
+ err = RPMB_ERR_OK;
+ out_frame[0].result = op_result(rsdev, err);
+
+ if (rpmb_sim_calc_hmac(rsdev, out_frame, 1, out_frame->key_mac))
+ err = RPMB_ERR_READ;
+
+ out_frame[0].result = op_result(rsdev, err);
+
+ return 0;
+}
+
+static int rpmb_op_write_data(struct rpmb_sim_dev *rsdev,
+ struct rpmb_data *rpmbd)
+{
+ struct rpmb_frame *in_frame, *out_frame;
+ u8 mac[32];
+ u16 req, err, addr, blks;
+ unsigned int i;
+ int ret = 0;
+
+ in_frame = rpmbd->in_frames;
+ req = be16_to_cpu(in_frame[0].req_resp);
+
+ if (req != RPMB_WRITE_DATA)
+ return -EINVAL;
+
+
+ if (rsdev->write_counter == 0xFFFFFFFF) {
+ err = RPMB_ERR_WRITE;
+ goto out;
+ }
+
+ blks = be16_to_cpu(in_frame[0].block_count);
+ if (blks == 0 || blks > rpmbd->in_frames_cnt) {
+ ret = -EINVAL;
+ err = RPMB_ERR_GENERAL;
+ goto out;
+ }
+
+ if (blks > max_wr_blks) {
+ err = RPMB_ERR_WRITE;
+ goto out;
+ }
+
+
+ addr = be16_to_cpu(in_frame[0].addr);
+ if (addr >= rsdev->blkcnt) {
+ err = RPMB_ERR_ADDRESS;
+ goto out;
+ }
+
+ if (rpmb_sim_calc_hmac(rsdev, in_frame, blks, mac)) {
+ err = RPMB_ERR_AUTH;
+ goto out;
+ }
+
+ /* mac is in the last frame */
+ if (memcmp(mac, in_frame[blks - 1].key_mac, sizeof(mac)) != 0) {
+ err = RPMB_ERR_AUTH;
+ goto out;
+ }
+
+ if (be32_to_cpu(in_frame[0].write_counter) != rsdev->write_counter) {
+ err = RPMB_ERR_COUNTER;
+ goto out;
+ }
+
+ if (addr + blks > rsdev->blkcnt) {
+ err = RPMB_ERR_WRITE;
+ goto out;
+ }
+
+ err = RPMB_ERR_OK;
+ for (i = 0; i < blks; i++)
+ memcpy(rsdev->da[addr + i].data, in_frame[i].data, BLK_UNIT);
+
+ rsdev->write_counter++;
+
+out:
+ out_frame = &rpmbd->out_frames[0];
+ memset(out_frame, 0, sizeof(struct rpmb_frame));
+
+ if (err == RPMB_ERR_OK) {
+ out_frame[0].write_counter = cpu_to_be32(rsdev->write_counter);
+ memcpy(out_frame[0].key_mac, mac, sizeof(mac));
+ }
+ out_frame[0].req_resp = req_to_resp(req);
+ out_frame[0].result = op_result(rsdev, err);
+
+ return ret;
+}
+
+static int rpmb_op_read_data(struct rpmb_sim_dev *rsdev,
+ struct rpmb_data *rpmbd)
+{
+ struct rpmb_frame *in_frame, *out_frame;
+ u8 mac[32];
+ u16 req, err, addr, blks;
+ unsigned int i;
+ int ret;
+
+ in_frame = rpmbd->in_frames;
+ req = be16_to_cpu(in_frame[0].req_resp);
+ if (req != RPMB_READ_DATA)
+ return -EINVAL;
+
+
+ out_frame = rpmbd->out_frames;
+
+ blks = be16_to_cpu(in_frame[0].block_count);
+ if (blks == 0 || blks > rpmbd->out_frames_cnt) {
+ ret = -EINVAL;
+ memset(out_frame, 0, sizeof(struct rpmb_frame));
+ err = RPMB_ERR_READ;
+ goto out;
+ }
+
+ ret = 0;
+ memset(out_frame, 0, sizeof(struct rpmb_frame) * blks);
+
+ addr = be16_to_cpu(in_frame[0].addr);
+ if (addr >= rsdev->blkcnt) {
+ err = RPMB_ERR_ADDRESS;
+ goto out;
+ }
+
+ if (addr + blks > rsdev->blkcnt) {
+ err = RPMB_ERR_READ;
+ goto out;
+ }
+
+ for (i = 0; i < blks; i++) {
+ memcpy(out_frame[i].data, rsdev->da[addr + i].data, BLK_UNIT);
+ memcpy(out_frame[i].nonce, in_frame[0].nonce, 16);
+ out_frame[i].req_resp = req_to_resp(req);
+ out_frame[i].addr = in_frame[0].addr;
+ out_frame[i].block_count = cpu_to_be16(blks);
+ }
+
+ if (rpmb_sim_calc_hmac(rsdev, out_frame, blks, mac)) {
+ err = RPMB_ERR_AUTH;
+ goto out;
+ }
+
+ memcpy(out_frame[blks - 1].key_mac, mac, sizeof(mac));
+
+ err = RPMB_ERR_OK;
+out:
+
+ /* FIXME: not sure if this has to be updated in each frame */
+ out_frame[0].result = op_result(rsdev, err);
+
+
+ return ret;
+}
+
+static int rpmb_sim_sequence(struct rpmb_sim_dev *rsdev,
+ struct rpmb_data *rpmbd)
+{
+ u16 type;
+ int ret;
+
+ type = rpmbd->req_type;
+
+ if (rpmbd->out_frames == NULL || rpmbd->in_frames == NULL ||
+ rpmbd->out_frames_cnt == 0 || rpmbd->in_frames_cnt == 0)
+ return -EINVAL;
+
+ if (rsdev->auth_key_set == false && type != RPMB_PROGRAM_KEY)
+ return rpmb_op_not_programmed(rsdev, rpmbd);
+
+ switch (type) {
+ case RPMB_PROGRAM_KEY:
+ ret = rpmb_op_program_key(rsdev, rpmbd);
+ break;
+ case RPMB_WRITE_DATA:
+ ret = rpmb_op_write_data(rsdev, rpmbd);
+ break;
+ case RPMB_GET_WRITE_COUNTER:
+ ret = rpmb_op_get_wr_conter(rsdev, rpmbd);
+ break;
+ case RPMB_READ_DATA:
+ ret = rpmb_op_read_data(rsdev, rpmbd);
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static int rpmb_sim_send_rpmb_req(struct device *dev, struct rpmb_data *rpmbd)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rpmb_sim_dev *rsdev = platform_get_drvdata(pdev);
+
+ if (!rsdev)
+ return -EINVAL;
+
+ if (!rpmbd)
+ return -EINVAL;
+
+ return rpmb_sim_sequence(rsdev, rpmbd);
+}
+
+static struct rpmb_ops rpmb_sim_ops = {
+ .send_rpmb_req = rpmb_sim_send_rpmb_req,
+ .type = RPMB_TYPE_EMMC,
+};
+
+static int rpmb_sim_hmac_256_alloc(struct rpmb_sim_dev *rsdev)
+{
+ struct crypto_shash *hash_tfm;
+
+ hash_tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+ if (IS_ERR(hash_tfm))
+ return PTR_ERR(hash_tfm);
+
+ rsdev->hash_tfm = hash_tfm;
+
+ dev_dbg(rsdev->dev, "hamac(sha256) registered\n");
+ return 0;
+}
+
+static void rpmb_sim_hmac_256_free(struct rpmb_sim_dev *rsdev)
+{
+ if (rsdev->hash_tfm)
+ crypto_free_shash(rsdev->hash_tfm);
+
+ rsdev->hash_tfm = NULL;
+}
+
+static int rpmb_sim_probe(struct platform_device *pdev)
+{
+ struct rpmb_sim_dev *rsdev;
+ int ret;
+
+ rsdev = kzalloc(sizeof(struct rpmb_sim_dev), GFP_KERNEL);
+ if (!rsdev)
+ return -ENOMEM;
+
+ rsdev->dev = &pdev->dev;
+
+ ret = rpmb_sim_hmac_256_alloc(rsdev);
+ if (ret)
+ goto err;
+
+ rsdev->capacity = CAPACITY_UNIT * daunits;
+ rsdev->blkcnt = rsdev->capacity / BLK_UNIT;
+ rsdev->da = kzalloc(rsdev->capacity, GFP_KERNEL);
+ if (!rsdev->da) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ rpmb_sim_ops.dev_id_len = strlen(id);
+ rpmb_sim_ops.dev_id = id;
+ rpmb_sim_ops.reliable_wr_cnt = max_wr_blks;
+
+ rsdev->rdev = rpmb_dev_register(rsdev->dev, &rpmb_sim_ops);
+ if (IS_ERR(rsdev->rdev)) {
+ ret = PTR_ERR(rsdev->rdev);
+ goto err;
+ }
+
+ dev_info(&pdev->dev, "registered RPMB capacity = %zu of %zu blocks\n",
+ rsdev->capacity, rsdev->blkcnt);
+
+ platform_set_drvdata(pdev, rsdev);
+
+ return 0;
+err:
+ rpmb_sim_hmac_256_free(rsdev);
+ if (rsdev)
+ kfree(rsdev->da);
+ kfree(rsdev);
+ return ret;
+}
+
+static int rpmb_sim_remove(struct platform_device *pdev)
+{
+ struct rpmb_sim_dev *rsdev;
+
+ rsdev = platform_get_drvdata(pdev);
+
+ rpmb_dev_unregister(rsdev->dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ rpmb_sim_hmac_256_free(rsdev);
+
+ kfree(rsdev->da);
+ kfree(rsdev);
+ return 0;
+}
+
+static struct platform_driver rpmb_sim_driver = {
+ .driver = {
+ .name = "rpmb_sim",
+ },
+ .probe = rpmb_sim_probe,
+ .remove = rpmb_sim_remove,
+};
+
+static struct platform_device *rpmb_sim_pdev;
+
+static int __init rpmb_sim_init(void)
+{
+ int ret;
+
+ rpmb_sim_pdev = platform_device_register_simple("rpmb_sim", -1,
+ NULL, 0);
+
+ if (IS_ERR(rpmb_sim_pdev))
+ return PTR_ERR(rpmb_sim_pdev);
+
+ ret = platform_driver_register(&rpmb_sim_driver);
+ if (ret)
+ platform_device_unregister(rpmb_sim_pdev);
+
+ return ret;
+}
+
+static void __exit rpmb_sim_exit(void)
+{
+ platform_device_unregister(rpmb_sim_pdev);
+ platform_driver_unregister(&rpmb_sim_driver);
+}
+
+module_init(rpmb_sim_init);
+module_exit(rpmb_sim_exit);
+
+MODULE_AUTHOR("Tomas Winkler <[email protected]");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:rpmb_sim");
--
2.4.3
Register UFS RPMB LUN with the RPMB subsystem and provide
implementation for the RPMB access operations. RPMB partition is
accessed via a sequence of security protocol in and security protocol
out commands with UFS specific parameters. This multi step process is
abstracted into 4 basic RPMB commands.
Signed-off-by: Alexander Usyskin <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
V2: resend
drivers/scsi/ufs/ufshcd.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd.h | 2 +
2 files changed, 221 insertions(+)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f8fa72c31a9d..c087e9713db3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -37,10 +37,13 @@
* license terms, and distributes only under these terms.
*/
+#include <asm/unaligned.h>
#include <linux/async.h>
#include <linux/devfreq.h>
#include <linux/nls.h>
#include <linux/of.h>
+#include <linux/rpmb.h>
+
#include "ufshcd.h"
#include "ufs_quirks.h"
#include "unipro.h"
@@ -4744,6 +4747,214 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
}
+#define SEC_PROTOCOL_UFS 0xEC
+#define SEC_SPECIFIC_UFS_RPMB 0x0001
+
+#define SEC_PROTOCOL_CMD_SIZE 12
+#define SEC_PROTOCOL_RETRIES 3
+#define SEC_PROTOCOL_RETRIES_ON_RESET 10
+#define SEC_PROTOCOL_TIMEOUT msecs_to_jiffies(1000)
+
+static int
+ufshcd_rpmb_security_out(struct scsi_device *sdev,
+ struct rpmb_frame *frames, u32 cnt)
+{
+ struct scsi_sense_hdr sshdr;
+ u32 trans_len = cnt * sizeof(struct rpmb_frame);
+ int reset_retries = SEC_PROTOCOL_RETRIES_ON_RESET;
+ int ret;
+ u8 cmd[SEC_PROTOCOL_CMD_SIZE];
+
+retry:
+ memset(cmd, 0, SEC_PROTOCOL_CMD_SIZE);
+ cmd[0] = SECURITY_PROTOCOL_OUT;
+ cmd[1] = SEC_PROTOCOL_UFS;
+ put_unaligned_be16(SEC_SPECIFIC_UFS_RPMB, cmd + 2);
+ cmd[4] = 0; /* inc_512 bit 7 set to 0 */
+ put_unaligned_be32(trans_len, cmd + 6); /* transfer length */
+
+ ret = scsi_execute_req_flags(sdev, cmd, DMA_TO_DEVICE,
+ frames, trans_len, &sshdr,
+ SEC_PROTOCOL_TIMEOUT, SEC_PROTOCOL_RETRIES,
+ NULL, 0);
+ if (ret && scsi_sense_valid(&sshdr) &&
+ sshdr.sense_key == UNIT_ATTENTION &&
+ sshdr.asc == 0x29 && sshdr.ascq == 0x00)
+ /* Device reset might occur several times,
+ * give it one more chance
+ */
+ if (--reset_retries > 0)
+ goto retry;
+
+ if (ret)
+ pr_err("%s: failed with err %0x\n", __func__, ret);
+
+ if (driver_byte(ret) & DRIVER_SENSE)
+ scsi_print_sense_hdr(sdev, "rpmb: security out", &sshdr);
+
+ return ret;
+}
+
+static int
+ufshcd_rpmb_security_in(struct scsi_device *sdev,
+ struct rpmb_frame *frames, u32 cnt)
+{
+ struct scsi_sense_hdr sshdr;
+ u32 alloc_len = cnt * sizeof(struct rpmb_frame);
+ int reset_retries = SEC_PROTOCOL_RETRIES_ON_RESET;
+ int ret;
+ u8 cmd[SEC_PROTOCOL_CMD_SIZE];
+
+retry:
+ memset(cmd, 0, SEC_PROTOCOL_CMD_SIZE);
+ cmd[0] = SECURITY_PROTOCOL_IN;
+ cmd[1] = SEC_PROTOCOL_UFS;
+ put_unaligned_be16(SEC_SPECIFIC_UFS_RPMB, cmd + 2);
+ cmd[4] = 0; /* inc_512 bit 7 set to 0 */
+ put_unaligned_be32(alloc_len, cmd + 6); /* allocation length */
+
+ ret = scsi_execute_req_flags(sdev, cmd, DMA_FROM_DEVICE,
+ frames, alloc_len, &sshdr,
+ SEC_PROTOCOL_TIMEOUT, SEC_PROTOCOL_RETRIES,
+ NULL, 0);
+ if (ret && scsi_sense_valid(&sshdr) &&
+ sshdr.sense_key == UNIT_ATTENTION &&
+ sshdr.asc == 0x29 && sshdr.ascq == 0x00)
+ /* Device reset might occur several times,
+ * give it one more chance
+ */
+ if (--reset_retries > 0)
+ goto retry;
+
+ if (ret)
+ pr_err("%s: failed with err %0x\n", __func__, ret);
+
+ if (driver_byte(ret) & DRIVER_SENSE)
+ scsi_print_sense_hdr(sdev, "rpmb: security in", &sshdr);
+
+ return ret;
+}
+
+
+static int ufshcd_rpmb_send_req(struct device *dev, struct rpmb_data *rpmbd)
+{
+ unsigned long flags;
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct scsi_device *sdev;
+ struct rpmb_frame *in_frames, *out_frames;
+ u16 blks;
+ u16 type;
+ int ret;
+
+ in_frames = rpmbd->in_frames;
+ out_frames = rpmbd->out_frames;
+
+ type = rpmbd->req_type;
+ blks = be16_to_cpu(in_frames[0].block_count);
+
+ dev_dbg(hba->dev, "RPMB : type = %d, blocks = %d\n", type, blks);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ sdev = hba->sdev_ufs_rpmb;
+ if (sdev) {
+ ret = scsi_device_get(sdev);
+ if (!ret && !scsi_device_online(sdev)) {
+ ret = -ENODEV;
+ scsi_device_put(sdev);
+ }
+ } else {
+ ret = -ENODEV;
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (ret)
+ return ret;
+
+ switch (type) {
+ case RPMB_PROGRAM_KEY:
+ blks = 1;
+ /* fall through */
+ case RPMB_WRITE_DATA:
+ /* STEP 1: send request to RPMB partition */
+ ret = ufshcd_rpmb_security_out(sdev, in_frames, blks);
+ if (ret)
+ break;
+
+ /* STEP 2: check write result (reuse out_frames) */
+ memset(out_frames, 0, 512);
+ out_frames[0].req_resp = cpu_to_be16(RPMB_RESULT_READ);
+ ret = ufshcd_rpmb_security_out(sdev, out_frames, 1);
+ if (ret)
+ break;
+
+ /* STEP 3: get response from RPMB partition */
+ ret = ufshcd_rpmb_security_in(sdev, out_frames, 1);
+ if (ret)
+ break;
+
+ break;
+ case RPMB_GET_WRITE_COUNTER:
+ blks = 1;
+ /* fall through */
+ case RPMB_READ_DATA:
+ /* STEP 1: send request to RPMB partition */
+ ret = ufshcd_rpmb_security_out(sdev, in_frames, 1);
+ if (ret)
+ break;
+ /* STEP 2: get response from RPMB partition */
+ ret = ufshcd_rpmb_security_in(sdev, out_frames, blks);
+ if (ret)
+ break;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ scsi_device_put(sdev);
+ return ret;
+}
+
+static struct rpmb_ops ufshcd_rpmb_dev_ops = {
+ .send_rpmb_req = ufshcd_rpmb_send_req,
+ .type = RPMB_TYPE_UFS,
+};
+
+static inline void ufshcd_rpmb_add(struct ufs_hba *hba)
+{
+ struct rpmb_dev *rdev;
+
+ scsi_device_get(hba->sdev_ufs_rpmb);
+ rdev = rpmb_dev_register(hba->dev, &ufshcd_rpmb_dev_ops);
+ if (IS_ERR(rdev)) {
+ dev_warn(hba->dev, "%s: cannot register to rpmb %ld\n",
+ dev_name(hba->dev), PTR_ERR(rdev));
+ goto out_put_dev;
+ }
+
+ return;
+
+out_put_dev:
+ scsi_device_put(hba->sdev_ufs_rpmb);
+ hba->sdev_ufs_rpmb = NULL;
+}
+
+static inline void ufshcd_rpmb_remove(struct ufs_hba *hba)
+{
+ unsigned long flags;
+
+ if (!hba->sdev_ufs_rpmb)
+ return;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ rpmb_dev_unregister(hba->dev);
+ scsi_device_put(hba->sdev_ufs_rpmb);
+ hba->sdev_ufs_rpmb = NULL;
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+
+
/**
* ufshcd_scsi_add_wlus - Adds required W-LUs
* @hba: per-adapter instance
@@ -4799,7 +5010,11 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
ret = PTR_ERR(sdev_rpmb);
goto remove_sdev_boot;
}
+ hba->sdev_ufs_rpmb = sdev_rpmb;
+
+ ufshcd_rpmb_add(hba);
scsi_device_put(sdev_rpmb);
+
goto out;
remove_sdev_boot:
@@ -6168,6 +6383,8 @@ int ufshcd_shutdown(struct ufs_hba *hba)
goto out;
}
+ ufshcd_rpmb_remove(hba);
+
ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM);
out:
if (ret)
@@ -6184,6 +6401,8 @@ EXPORT_SYMBOL(ufshcd_shutdown);
*/
void ufshcd_remove(struct ufs_hba *hba)
{
+ ufshcd_rpmb_remove(hba);
+
scsi_remove_host(hba->host);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 4bb65669f052..92bfddf80ae8 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -346,6 +346,7 @@ struct ufs_init_prefetch {
* @utmrdl_dma_addr: UTMRDL DMA address
* @host: Scsi_Host instance of the driver
* @dev: device handle
+ * @sdev_ufs_rpmb: reference to RPMB device W-LU
* @lrb: local reference block
* @lrb_in_use: lrb in use
* @outstanding_tasks: Bits representing outstanding task requests
@@ -408,6 +409,7 @@ struct ufs_hba {
* "UFS device" W-LU.
*/
struct scsi_device *sdev_ufs_device;
+ struct scsi_device *sdev_ufs_rpmb;
enum ufs_dev_pwr_mode curr_dev_pwr_mode;
enum uic_link_state uic_link_state;
--
2.4.3
Register eMMC rpmb partition with the rpmb subsystem and provide
implementation for the RPMB access operations abstracting
actual multi step process.
Signed-off-by: Tomas Winkler <[email protected]>
Signed-off-by: Alexander Usyskin <[email protected]>
---
V2: resend
drivers/mmc/card/block.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 289 insertions(+)
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 3bdbe50a363f..441754a7d4cf 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -41,6 +41,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
+#include <linux/rpmb.h>
#include <asm/uaccess.h>
@@ -111,6 +112,7 @@ struct mmc_blk_data {
#define MMC_BLK_WRITE BIT(1)
#define MMC_BLK_DISCARD BIT(2)
#define MMC_BLK_SECDISCARD BIT(3)
+#define MMC_BLK_RPMB BIT(4)
/*
* Only set in main mmc_blk_data associated
@@ -1138,6 +1140,289 @@ int mmc_access_rpmb(struct mmc_queue *mq)
return false;
}
+static int mmc_rpmb_send_cmd(struct mmc_card *card,
+ u16 rpmb_type, int data_type,
+ u8 *buf, u16 blks)
+{
+ struct mmc_command sbc = {
+ .opcode = MMC_SET_BLOCK_COUNT,
+ .flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC,
+ };
+
+ struct mmc_command cmd = {
+ .flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
+ };
+
+ struct mmc_data data = {
+ .blksz = 512,
+ };
+ struct mmc_request mrq = {
+ .sbc = &sbc,
+ .cmd = &cmd,
+ .data = &data,
+ .stop = NULL,
+ };
+ struct scatterlist sg;
+ bool do_rel_wr;
+
+ /* set CMD23 */
+ sbc.arg = blks & 0x0000FFFF;
+ do_rel_wr = (rpmb_type == RPMB_WRITE_DATA ||
+ rpmb_type == RPMB_PROGRAM_KEY);
+
+ if (do_rel_wr)
+ sbc.arg |= MMC_CMD23_ARG_REL_WR;
+
+ /* set CMD25/18 */
+ cmd.opcode = (data_type == MMC_DATA_WRITE) ?
+ MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
+
+ sg_init_one(&sg, buf, 512 * blks);
+
+ data.blocks = blks;
+ data.sg = &sg;
+ data.sg_len = 1;
+ data.flags = data_type;
+ mmc_set_data_timeout(&data, card);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error) {
+ pr_err("%s: %s cmd error (%d)\n",
+ mmc_hostname(card->host), __func__, cmd.error);
+ return cmd.error;
+ }
+ if (data.error) {
+ pr_err("%s: %s data error (%d)\n",
+ mmc_hostname(card->host), __func__, data.error);
+ return data.error;
+ }
+ return 0;
+}
+
+static int mmc_blk_rpmb_sequence(struct mmc_card *card,
+ struct rpmb_data *rpmbd)
+{
+ struct rpmb_frame *in_frames, *out_frames;
+ u8 *in_buf, *out_buf;
+ u16 blks;
+ u16 type;
+ int err;
+
+ in_frames = rpmbd->in_frames;
+ out_frames = rpmbd->out_frames;
+ in_buf = (u8 *)in_frames;
+ out_buf = (u8 *)out_frames;
+
+ type = rpmbd->req_type;
+ blks = be16_to_cpu(in_frames[0].block_count);
+
+ switch (type) {
+ case RPMB_PROGRAM_KEY:
+ blks = 1;
+ /* fall through */
+ case RPMB_WRITE_DATA:
+ /* STEP 1: send request to RPMB partition */
+ err = mmc_rpmb_send_cmd(card, type, MMC_DATA_WRITE,
+ in_buf, blks);
+ if (err) {
+ pr_err("%s: mmc_rpmb_send_cmd failed(%d)\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* STEP 2: check write result (reuse out_frames) */
+ memset(out_frames, 0, 512);
+ out_frames[0].req_resp = cpu_to_be16(RPMB_RESULT_READ);
+ err = mmc_rpmb_send_cmd(card,
+ RPMB_RESULT_READ, MMC_DATA_WRITE, out_buf, 1);
+ if (err) {
+ pr_err("%s: mmc_rpmb_send_cmd failed(%d)\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* STEP 3: get response from RPMB partition */
+ err = mmc_rpmb_send_cmd(card,
+ RPMB_READ_DATA, MMC_DATA_READ, out_buf, 1);
+
+ if (err) {
+ pr_err("%s: mmc_rpmb_send_cmd failed(%d)\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+ break;
+
+ case RPMB_GET_WRITE_COUNTER:
+ blks = 1;
+ /* fall through */
+ case RPMB_READ_DATA:
+ /* STEP 1: send request to RPMB partition */
+ err = mmc_rpmb_send_cmd(card, type, MMC_DATA_WRITE, in_buf, 1);
+ if (err) {
+ pr_err("%s: mmc_rpmb_send_cmd failed(%d)\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* STEP 3: get response from RPMB partition */
+ err = mmc_rpmb_send_cmd(card, type, MMC_DATA_READ,
+ out_buf, blks);
+ if (err) {
+ pr_err("%s: mmc_rpmb_send_cmd failed(%d)\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+ break;
+
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+out:
+ return err;
+}
+
+static int mmc_blk_rpmb_req_process(struct mmc_blk_data *md,
+ struct rpmb_data *rpmbd)
+{
+ struct mmc_card *card;
+ int ret;
+
+ if (WARN_ON(!md || !rpmbd))
+ return -EINVAL;
+
+ if (!(md->flags & MMC_BLK_CMD23) ||
+ (md->part_type != EXT_CSD_PART_CONFIG_ACC_RPMB))
+ return -EOPNOTSUPP;
+
+ card = md->queue.card;
+ if (!card || !mmc_card_mmc(card))
+ return -ENODEV;
+
+
+ pr_debug("%s rpmb request type = 0x%1x\n",
+ md->disk->disk_name, rpmbd->req_type);
+
+ mmc_get_card(card);
+
+ /* switch to RPMB partition */
+ ret = mmc_blk_part_switch(card, md);
+ if (ret) {
+ pr_err("%s: Invalid RPMB partition switch (%d)!\n",
+ mmc_hostname(card->host), ret);
+ /*
+ * In case partition is not in user data area, make
+ * a force partition switch.
+ * we need reset eMMC card at here
+ */
+ ret = mmc_blk_reset(md, card->host, MMC_BLK_RPMB);
+ if (!ret)
+ mmc_blk_reset_success(md, MMC_BLK_RPMB);
+ else
+ pr_err("%s: eMMC card reset failed (%d)\n",
+ mmc_hostname(card->host), ret);
+ goto out;
+ }
+
+ ret = mmc_blk_rpmb_sequence(card, rpmbd);
+ if (ret)
+ pr_err("%s: failed (%d) to handle RPMB request type %d!\n",
+ mmc_hostname(card->host), ret, rpmbd->req_type);
+out:
+ mmc_put_card(card);
+ return ret;
+}
+
+static int mmc_blk_rpmb_send_req(struct device *dev, struct rpmb_data *req)
+{
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ int ret;
+
+ if (!md)
+ return -ENODEV;
+
+ ret = mmc_blk_rpmb_req_process(md, req);
+
+ mmc_blk_put(md);
+
+ return ret;
+}
+
+static struct rpmb_ops mmc_rpmb_dev_ops = {
+ .send_rpmb_req = mmc_blk_rpmb_send_req,
+ .type = RPMB_TYPE_EMMC,
+};
+
+static struct mmc_blk_data *mmc_blk_rpmb_part_get(struct mmc_blk_data *md)
+{
+ struct mmc_blk_data *part_md;
+
+ if (!md)
+ return NULL;
+
+ list_for_each_entry(part_md, &md->part, part) {
+ if (part_md->area_type == MMC_BLK_DATA_AREA_RPMB)
+ return part_md;
+ }
+
+ return NULL;
+}
+
+static void mmc_blk_rpmb_unset_dev_id(struct rpmb_ops *ops)
+{
+ kfree(ops->dev_id);
+ ops->dev_id = NULL;
+}
+
+static int mmc_blk_rpmb_set_dev_id(struct rpmb_ops *ops, struct mmc_card *card)
+{
+ char *id;
+
+ id = kmalloc(sizeof(card->raw_cid), GFP_KERNEL);
+ if (!id)
+ return -ENOMEM;
+
+ memcpy(id, card->raw_cid, sizeof(card->raw_cid));
+ ops->dev_id = id;
+ ops->dev_id_len = sizeof(card->raw_cid);
+
+ return 0;
+}
+
+static void mmc_blk_rpmb_add(struct mmc_card *card)
+{
+ struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ struct mmc_blk_data *part_md = mmc_blk_rpmb_part_get(md);
+ struct rpmb_dev *rdev;
+
+ if (!part_md)
+ return;
+
+ mmc_blk_rpmb_set_dev_id(&mmc_rpmb_dev_ops, card);
+
+ /* RPMB blocks are written in half sectors hence '* 2' */
+ mmc_rpmb_dev_ops.reliable_wr_cnt = card->ext_csd.rel_sectors * 2;
+
+ rdev = rpmb_dev_register(disk_to_dev(part_md->disk),
+ &mmc_rpmb_dev_ops);
+ if (IS_ERR(rdev)) {
+ pr_warn("%s: cannot register to rpmb %ld\n",
+ part_md->disk->disk_name, PTR_ERR(rdev));
+ }
+}
+
+static void mmc_blk_rpmb_remove(struct mmc_card *card)
+{
+ struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ struct mmc_blk_data *part_md = mmc_blk_rpmb_part_get(md);
+
+ if (part_md)
+ rpmb_dev_unregister(disk_to_dev(part_md->disk));
+
+ mmc_blk_rpmb_unset_dev_id(&mmc_rpmb_dev_ops);
+}
+
static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
@@ -2586,6 +2871,8 @@ static int mmc_blk_probe(struct mmc_card *card)
goto out;
}
+ mmc_blk_rpmb_add(card);
+
pm_runtime_set_autosuspend_delay(&card->dev, 3000);
pm_runtime_use_autosuspend(&card->dev);
@@ -2610,6 +2897,7 @@ static void mmc_blk_remove(struct mmc_card *card)
{
struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ mmc_blk_rpmb_remove(card);
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
@@ -2638,6 +2926,7 @@ static int _mmc_blk_suspend(struct mmc_card *card)
static void mmc_blk_shutdown(struct mmc_card *card)
{
+ mmc_blk_rpmb_remove(card);
_mmc_blk_suspend(card);
}
--
2.4.3
Add attribute type that displays underlay storage type technology
EMMC, UFS, and attribute id, that displays underlay storage device id.
For EMMC this would be content of CID and for UFS serial number from
the device descriptor
Signed-off-by: Tomas Winkler <[email protected]>
---
V2: resend
Documentation/ABI/testing/sysfs-class-rpmb | 24 +++++++++++
drivers/char/rpmb/core.c | 64 ++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-class-rpmb b/Documentation/ABI/testing/sysfs-class-rpmb
index 62d1959bf19e..9b2bf65dae95 100644
--- a/Documentation/ABI/testing/sysfs-class-rpmb
+++ b/Documentation/ABI/testing/sysfs-class-rpmb
@@ -13,3 +13,27 @@ Contact: Tomas Winkler <[email protected]>
Description:
The /sys/class/rpmb/rpmbN directory is created for
each RPMB registered device
+
+What: /sys/class/rpmb/rpmbN/id
+Date: Mar 2016
+KernelVersion: TBD
+Contact: Tomas Winkler <[email protected]>
+Description:
+ The /sys/class/rpmb/rpmbN/id file contains device id
+ in a binary form
+
+What: /sys/class/rpmb/rpmbN/type
+Date: Mar 2016
+KernelVersion: TBD
+Contact: Tomas Winkler <[email protected]>
+Description:
+ The /sys/class/rpmb/rpmbN/type file contains device
+ underlay storage type technology: EMMC, UFS
+
+What: /sys/class/rpmb/rpmbN/reliable_wr_cnt
+Date: Mar 2016
+KernelVersion: TBD
+Contact: Tomas Winkler <[email protected]>
+Description:
+ The /sys/class/rpmb/rpmbN/reliable_wr_cnt file contains
+ number of blocks that can be written in a single request
diff --git a/drivers/char/rpmb/core.c b/drivers/char/rpmb/core.c
index c9ea30aca6be..fb401331d345 100644
--- a/drivers/char/rpmb/core.c
+++ b/drivers/char/rpmb/core.c
@@ -230,6 +230,68 @@ struct rpmb_dev *rpmb_dev_find_by_device(struct device *parent)
}
EXPORT_SYMBOL_GPL(rpmb_dev_find_by_device);
+static ssize_t type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpmb_dev *rdev = to_rpmb_dev(dev);
+ ssize_t ret;
+
+ switch (rdev->ops->type) {
+ case RPMB_TYPE_EMMC:
+ ret = scnprintf(buf, PAGE_SIZE, "EMMC\n");
+ break;
+ case RPMB_TYPE_UFS:
+ ret = scnprintf(buf, PAGE_SIZE, "UFS\n");
+ break;
+ default:
+ ret = scnprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+ break;
+ }
+
+ return ret;
+}
+static DEVICE_ATTR_RO(type);
+
+static ssize_t id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpmb_dev *rdev = to_rpmb_dev(dev);
+ size_t sz = min_t(size_t, rdev->ops->dev_id_len, PAGE_SIZE);
+
+ if (!rdev->ops->dev_id)
+ return 0;
+
+ memcpy(buf, rdev->ops->dev_id, sz);
+ return sz;
+}
+static DEVICE_ATTR_RO(id);
+
+static ssize_t reliable_wr_cnt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpmb_dev *rdev = to_rpmb_dev(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", rdev->ops->reliable_wr_cnt);
+}
+static DEVICE_ATTR_RO(reliable_wr_cnt);
+
+
+static struct attribute *rpmb_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_id.attr,
+ &dev_attr_reliable_wr_cnt.attr,
+ NULL,
+};
+
+static struct attribute_group rpmb_attr_group = {
+ .attrs = rpmb_attrs,
+};
+
+static const struct attribute_group *rpmb_attr_groups[] = {
+ &rpmb_attr_group,
+ NULL
+};
+
/**
* rpmb_dev_unregister - unregister RPMB partition from the RPMB subsystem
*
@@ -300,6 +362,8 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev,
dev_set_name(&rdev->dev, "rpmb%d", id);
rdev->dev.class = &rpmb_class;
rdev->dev.parent = dev;
+ rdev->dev.groups = rpmb_attr_groups;
+
ret = device_register(&rdev->dev);
if (ret)
goto exit;
--
2.4.3
Hi Tomas,
[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on v4.6-rc2 next-20160405]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Tomas-Winkler/Replay-Protected-Memory-Block-RPMB-subsystem/20160404-192243
config: x86_64-randconfig-s3-04051858 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
make[3]: *** No rule to make target 'kernel/gcov/base.o', needed by 'kernel/gcov/built-in.o'.
make[3]: *** No rule to make target 'kernel/gcov/fs.o', needed by 'kernel/gcov/built-in.o'.
>> make[3]: *** No rule to make target 'kernel/gcov/gcc_3_4.o', needed by 'kernel/gcov/built-in.o'.
make[3]: Target '__build' not remade because of errors.
--
>> make[3]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/mfd/88pm800.o'.
make[3]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/firmware/google/memconsole.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/iio/dac/ad5624r_spi.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/iio/trigger/iio-trig-interrupt.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/input/joystick/gf2k.o'.
make[4]: *** [drivers/input/joystick/iforce] Error 2
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/misc/eeprom/max6875.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/mmc/card/mmc_test.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/mmc/host/sdhci.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/pinctrl/intel/pinctrl-intel.o'.
make[4]: Target '__build' not remade because of errors.
--
>> make[4]: *** No rule to make target 'tools/objtool/objtool', needed by 'drivers/platform/chrome/chromeos_laptop.o'.
make[4]: Target '__build' not remade because of errors.
..
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Tomas,
[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on v4.6-rc2 next-20160405]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Tomas-Winkler/Replay-Protected-Memory-Block-RPMB-subsystem/20160404-192243
config: x86_64-randconfig-s5-04051858 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
make[3]: *** No rule to make target 'arch/x86/kernel/process_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/signal.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/signal_compat.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/traps.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/irq.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/irq_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/dumpstack_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/time.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/ioport.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/dumpstack.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/nmi.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/setup.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/x86_init.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/i8259.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/irqinit.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/jump_label.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/irq_work.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/probe_roms.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/sys_x86_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/x8664_ksyms_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/mcount_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/ksysfs.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/bootflag.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/e820.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/pci-dma.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/quirks.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/topology.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/kdebugfs.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/alternative.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/i8253.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/pci-nommu.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/hw_breakpoint.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/tsc.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/tsc_msr.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/io_delay.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/rtc.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/pci-iommu_table.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/resource.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/process.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/ptrace.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/tls.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/step.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/stacktrace.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/reboot.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/msr.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/cpuid.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/early-quirks.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/smp.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/smpboot.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/tsc_sync.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/setup_percpu.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/mpparse.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/ftrace.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/trace_clock.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/machine_kexec_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/relocate_kernel_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/crash.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/kexec-bzimage64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/doublefault.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/hpet.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/amd_nb.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/test_rodata.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/nmi_selftest.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/kvm.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/kvmclock.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/paravirt.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/paravirt_patch_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/pvclock.o', needed by 'arch/x86/kernel/built-in.o'.
>> make[3]: *** No rule to make target 'arch/x86/kernel/pmem.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/pcspeaker.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/pci-swiotlb.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/uprobes.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/sysfb.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/sysfb_simplefb.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/perf_regs.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/tracepoint.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/vsmp_64.o', needed by 'arch/x86/kernel/built-in.o'.
make[3]: *** No rule to make target 'arch/x86/kernel/head_64.o', needed by '__build'.
make[3]: *** No rule to make target 'arch/x86/kernel/head64.o', needed by '__build'.
make[3]: *** No rule to make target 'arch/x86/kernel/head.o', needed by '__build'.
make[3]: *** [arch/x86/kernel/acpi] Error 2
make[3]: *** [arch/x86/kernel/fpu] Error 2
make[3]: *** [arch/x86/kernel/apic] Error 2
make[3]: *** [arch/x86/kernel/cpu] Error 2
make[3]: Target '__build' not remade because of errors.
--
make[3]: *** No rule to make target 'fs/squashfs/block.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/cache.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/dir.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/export.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/file.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/fragment.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/id.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/inode.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/namei.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/super.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/symlink.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/decompressor.o', needed by 'fs/squashfs/squashfs.o'.
>> make[3]: *** No rule to make target 'fs/squashfs/file_direct.o', needed by 'fs/squashfs/squashfs.o'.
>> make[3]: *** No rule to make target 'fs/squashfs/page_actor.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/decompressor_single.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/xattr.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/xattr_id.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/lzo_wrapper.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: *** No rule to make target 'fs/squashfs/xz_wrapper.o', needed by 'fs/squashfs/squashfs.o'.
make[3]: Target '__build' not remade because of errors.
--
make[3]: *** No rule to make target 'drivers/scsi/scsi.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/hosts.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_ioctl.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsicam.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_error.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_lib.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_common.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_lib_dma.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_scan.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_sysfs.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_devinfo.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_sysctl.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_proc.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_trace.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_logging.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_pm.o', needed by 'drivers/scsi/scsi_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/raid_class.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_transport_spi.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_transport_sas.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/scsi_transport_srp.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/iscsi_boot_sysfs.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/dpt_i2o.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/ips.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/fdomain.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/dmx3191d.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/hpsa.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/dc395x.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/esp_scsi.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/am53c974.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/megaraid.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/a100u2w.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/3w-xxxx.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/3w-9xxx.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/ppa.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/stex.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/virtio_scsi.o', needed by 'drivers/scsi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/vmw_pvscsi.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/st.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/sd.o', needed by 'drivers/scsi/sd_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/sd_dif.o', needed by 'drivers/scsi/sd_mod.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/sr.o', needed by 'drivers/scsi/sr_mod.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/sr_ioctl.o', needed by 'drivers/scsi/sr_mod.o'.
>> make[3]: *** No rule to make target 'drivers/scsi/sr_vendor.o', needed by 'drivers/scsi/sr_mod.o'.
make[3]: *** No rule to make target 'drivers/scsi/sg.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/ch.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** No rule to make target 'drivers/scsi/ses.o', needed by 'drivers/scsi/built-in.o'.
make[3]: *** [drivers/scsi/megaraid] Error 2
make[3]: *** [drivers/scsi/arcmsr] Error 2
make[3]: *** [drivers/scsi/esas2r] Error 2
make[3]: *** [drivers/scsi/pm8001] Error 2
make[3]: *** [drivers/scsi/mvsas] Error 2
make[3]: *** [drivers/scsi/mpt3sas] Error 2
make[3]: *** [drivers/scsi/aic94xx] Error 2
make[3]: *** [drivers/scsi/aacraid] Error 2
make[3]: *** [drivers/scsi/libsas] Error 2
make[3]: *** [drivers/scsi/aic7xxx] Error 2
make[3]: *** [drivers/scsi/snic] Error 2
make[3]: Target '__build' not remade because of errors.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Tomas,
[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on v4.6-rc2 next-20160405]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Tomas-Winkler/Replay-Protected-Memory-Block-RPMB-subsystem/20160404-192243
config: x86_64-randconfig-s2-04051858 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
make[2]: *** No rule to make target 'lib/usercopy.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/lockref.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/bcd.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/div64.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/sort.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/parser.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/halfmd4.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/debug_locks.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/random32.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/bust_spinlocks.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/kasprintf.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/bitmap.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/scatterlist.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/gcd.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/lcm.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/list_sort.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/uuid.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/flex_array.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/iov_iter.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/clz_ctz.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/bsearch.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/find_bit.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/llist.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/memweight.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/kfifo.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/percpu-refcount.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/percpu_ida.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/rhashtable.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/reciprocal_div.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/once.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/string_helpers.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/test-string_helpers.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/hexdump.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/test_hexdump.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/kstrtox.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/test_firmware.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/test-kstrtox.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/test_rhashtable.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/test_printf.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/iomap.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/pci_iomap.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/iomap_copy.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/devres.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/check_signature.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/locking-selftest.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/hweight.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/assoc_array.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/bitrev.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/rational.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/crc-ccitt.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/crc16.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/crc-t10dif.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/crc-itu-t.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/crc7.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/libcrc32c.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/crc8.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/genalloc.o', needed by 'lib/built-in.o'.
make[2]: *** [lib/reed_solomon] Error 2
make[2]: *** [lib/842] Error 2
make[2]: *** [lib/xz] Error 2
make[2]: *** No rule to make target 'lib/bch.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/swiotlb.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/iommu-helper.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/iommu-common.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/fault-inject.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/notifier-error-inject.o', needed by 'lib/built-in.o'.
>> make[2]: *** No rule to make target 'lib/netdev-notifier-error-inject.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/syscall.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/nlattr.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/cordic.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/dynamic_queue_limits.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/strncpy_from_user.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/strnlen_user.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/net_utils.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/irq_poll.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/rbtree_test.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/asn1_decoder.o', needed by 'lib/built-in.o'.
make[2]: *** [lib/lz4] Error 2
make[2]: *** No rule to make target 'lib/ubsan.o', needed by 'lib/built-in.o'.
make[2]: *** No rule to make target 'lib/argv_split.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/bug.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/clz_tab.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/cmdline.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/ctype.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/dec_and_lock.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress_bunzip2.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress_inflate.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress_unlz4.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress_unlzma.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress_unlzo.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/decompress_unxz.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/dma-noop.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/dump_stack.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/earlycpio.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/extable.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/flex_proportions.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/idr.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/int_sqrt.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/ioremap.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/irq_regs.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/is_single_threaded.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/klist.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/kobject.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/kobject_uevent.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/md5.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/nmi_backtrace.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/plist.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/proportions.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/radix-tree.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/ratelimit.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/rbtree.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/seq_buf.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/sha1.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/show_mem.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/string.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/timerqueue.o', needed by 'lib/lib.a'.
make[2]: *** No rule to make target 'lib/vsprintf.o', needed by 'lib/lib.a'.
make[2]: *** [lib/lzo] Error 2
make[2]: *** [lib/zlib_deflate] Error 2
make[2]: *** [lib/zlib_inflate] Error 2
make[2]: *** [lib/mpi] Error 2
make[2]: Target '__build' not remade because of errors.
--
make[3]: *** No rule to make target 'drivers/spi/spi.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spidev.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-altera.o', needed by 'drivers/spi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/spi/spi-axi-spi-engine.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-bitbang.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-cadence.o', needed by 'drivers/spi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/spi/spi-dln2.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-dw.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-fsl-lib.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-fsl-spi.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-sc18is602.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-tle62x0.o', needed by 'drivers/spi/built-in.o'.
>> make[3]: *** No rule to make target 'drivers/spi/spi-xcomm.o', needed by 'drivers/spi/built-in.o'.
make[3]: *** No rule to make target 'drivers/spi/spi-zynqmp-gqspi.o', needed by 'drivers/spi/built-in.o'.
make[3]: Target '__build' not remade because of errors.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi!
On 4/4/2016 12:11 PM, Tomas Winkler wrote:
> Register UFS RPMB LUN with the RPMB subsystem and provide
> implementation for the RPMB access operations. RPMB partition is
> accessed via a sequence of security protocol in and security protocol
> out commands with UFS specific parameters. This multi step process is
> abstracted into 4 basic RPMB commands.
[snip]
> * "UFS device" W-LU.
> */
> struct scsi_device *sdev_ufs_device;
> + struct scsi_device *sdev_ufs_rpmb;
>
> enum ufs_dev_pwr_mode curr_dev_pwr_mode;
> enum uic_link_state uic_link_state;
>
I have a UFS device emulator that has the RPMB capability. What are the expected
good results for me to validate?
Thanks.
On Wed, 2016-04-06 at 09:51 +0100, Joao Pinto wrote:
> Hi!
>
> On 4/4/2016 12:11 PM, Tomas Winkler wrote:
> > Register UFS RPMB LUN with the RPMB subsystem and provide
> > implementation for the RPMB access operations. RPMB partition is
> > accessed via a sequence of security protocol in and security
> > protocol
> > out commands with UFS specific parameters. This multi step process
> > is
> > abstracted into 4 basic RPMB commands.
>
> [snip]
>
> > * "UFS device" W-LU.
> > */
> > struct scsi_device *sdev_ufs_device;
> > + struct scsi_device *sdev_ufs_rpmb;
> >
> > enum ufs_dev_pwr_mode curr_dev_pwr_mode;
> > enum uic_link_state uic_link_state;
> >
>
> I have a UFS device emulator that has the RPMB capability. What are
> the expected
> good results for me to validate?
Hi Joao, thanks for that. I'm attaching an archive with few basic
samples via user space interface.
You should run the program key first (program-key.sh), just don't do it
on a real device it's one in life time operation.
Thanks
Tomas
Hi!
On 4/7/2016 10:15 PM, Winkler, Tomas wrote:
> On Wed, 2016-04-06 at 09:51 +0100, Joao Pinto wrote:
>> Hi!
>>
>> On 4/4/2016 12:11 PM, Tomas Winkler wrote:
>>> Register UFS RPMB LUN with the RPMB subsystem and provide
>>> implementation for the RPMB access operations. RPMB partition is
>>> accessed via a sequence of security protocol in and security
>>> protocol
>>> out commands with UFS specific parameters. This multi step process
>>> is
>>> abstracted into 4 basic RPMB commands.
>>
>> [snip]
>>
>>> * "UFS device" W-LU.
>>> */
>>> struct scsi_device *sdev_ufs_device;
>>> + struct scsi_device *sdev_ufs_rpmb;
>>>
>>> enum ufs_dev_pwr_mode curr_dev_pwr_mode;
>>> enum uic_link_state uic_link_state;
>>>
>>
>> I have a UFS device emulator that has the RPMB capability. What are
>> the expected
>> good results for me to validate?
>
> Hi Joao, thanks for that. I'm attaching an archive with few basic
> samples via user space interface.
> You should run the program key first (program-key.sh), just don't do it
> on a real device it's one in life time operation.
No attachment received.
>
> Thanks
> Tomas
>
Thanks,
Joao
Hi,
On 4/7/2016 10:15 PM, Winkler, Tomas wrote:
> On Wed, 2016-04-06 at 09:51 +0100, Joao Pinto wrote:
>> Hi!
>>
>> On 4/4/2016 12:11 PM, Tomas Winkler wrote:
>>> Register UFS RPMB LUN with the RPMB subsystem and provide
>>> implementation for the RPMB access operations. RPMB partition is
>>> accessed via a sequence of security protocol in and security
>>> protocol
>>> out commands with UFS specific parameters. This multi step process
>>> is
>>> abstracted into 4 basic RPMB commands.
>>
>> [snip]
>>
>>> * "UFS device" W-LU.
>>> */
>>> struct scsi_device *sdev_ufs_device;
>>> + struct scsi_device *sdev_ufs_rpmb;
>>>
>>> enum ufs_dev_pwr_mode curr_dev_pwr_mode;
>>> enum uic_link_state uic_link_state;
>>>
>>
>> I have a UFS device emulator that has the RPMB capability. What are
>> the expected
>> good results for me to validate?
>
> Hi Joao, thanks for that. I'm attaching an archive with few basic
> samples via user space interface.
> You should run the program key first (program-key.sh), just don't do it
> on a real device it's one in life time operation.
>
> Thanks
> Tomas
>
I have tested your patch set the following way:
Patches applied:
- Got 4.7-queue from the SCSI repo
- Applied the patch set for DW UFS support
- Applied your patch set for RPMB support
Platform (UFS IP Prototyping Kit):
- CPU: ARC CPU 32-bit
- UFS 2.0 Core running in FPGA
Results:
Kernel Build without RPMB configured: OK
Kernel Build with RPMB configured: OK
UFS Device partitions shown in UFS Host without RPMB configured: Yes
UFS Device partitions shown in UFS Host with RPMB configured: Yes
I would like to run more verifications regarding RPMB. Could you tell me what is
the procedure you suggest?
Thanks,
Joao
On 4/7/2016 10:15 PM, Winkler, Tomas wrote:
> On Wed, 2016-04-06 at 09:51 +0100, Joao Pinto wrote:
>> Hi!
>>
>> On 4/4/2016 12:11 PM, Tomas Winkler wrote:
>>> Register UFS RPMB LUN with the RPMB subsystem and provide
>>> implementation for the RPMB access operations. RPMB partition is
>>> accessed via a sequence of security protocol in and security
>>> protocol
>>> out commands with UFS specific parameters. This multi step process
>>> is
>>> abstracted into 4 basic RPMB commands.
>>
>> [snip]
>>
>>> * "UFS device" W-LU.
>>> */
>>> struct scsi_device *sdev_ufs_device;
>>> + struct scsi_device *sdev_ufs_rpmb;
>>>
>>> enum ufs_dev_pwr_mode curr_dev_pwr_mode;
>>> enum uic_link_state uic_link_state;
>>>
>>
>> I have a UFS device emulator that has the RPMB capability. What are
>> the expected
>> good results for me to validate?
>
> Hi Joao, thanks for that. I'm attaching an archive with few basic
> samples via user space interface.
> You should run the program key first (program-key.sh), just don't do it
> on a real device it's one in life time operation.
Sorry, I have received the attachment. Going to explore it now.
>
> Thanks
> Tomas
>
Joao
Hi,
On 4/7/2016 10:15 PM, Winkler, Tomas wrote:
> On Wed, 2016-04-06 at 09:51 +0100, Joao Pinto wrote:
>> Hi!
>>
>> On 4/4/2016 12:11 PM, Tomas Winkler wrote:
>>> Register UFS RPMB LUN with the RPMB subsystem and provide
>>> implementation for the RPMB access operations. RPMB partition is
>>> accessed via a sequence of security protocol in and security
>>> protocol
>>> out commands with UFS specific parameters. This multi step process
>>> is
>>> abstracted into 4 basic RPMB commands.
>>
>> [snip]
>>
>>> * "UFS device" W-LU.
>>> */
>>> struct scsi_device *sdev_ufs_device;
>>> + struct scsi_device *sdev_ufs_rpmb;
>>>
>>> enum ufs_dev_pwr_mode curr_dev_pwr_mode;
>>> enum uic_link_state uic_link_state;
>>>
>>
>> I have a UFS device emulator that has the RPMB capability. What are
>> the expected
>> good results for me to validate?
>
> Hi Joao, thanks for that. I'm attaching an archive with few basic
> samples via user space interface.
> You should run the program key first (program-key.sh), just don't do it
> on a real device it's one in life time operation.
>
Managed to cross-compile to ARC and execute your test app in my platform. I made
it in Buildroot, so I have the patches to enable the tool cross-compilation if
necessary in the future.
The tool execution gives no errors, but also no info. I suggest you had success
info and maybe some statistic (e.g. bytes read or written).
> Thanks
> Tomas
>
Thanks,
Joao
>
> On 4/7/2016 10:15 PM, Winkler, Tomas wrote:
> > On Wed, 2016-04-06 at 09:51 +0100, Joao Pinto wrote:
> >> Hi!
> >>
> >> On 4/4/2016 12:11 PM, Tomas Winkler wrote:
> >>> Register UFS RPMB LUN with the RPMB subsystem and provide
> >>> implementation for the RPMB access operations. RPMB partition is
> >>> accessed via a sequence of security protocol in and security
> >>> protocol out commands with UFS specific parameters. This multi step
> >>> process is abstracted into 4 basic RPMB commands.
> >>
> >> [snip]
> >>
> >>> * "UFS device" W-LU.
> >>> */
> >>> struct scsi_device *sdev_ufs_device;
> >>> + struct scsi_device *sdev_ufs_rpmb;
> >>>
> >>> enum ufs_dev_pwr_mode curr_dev_pwr_mode;
> >>> enum uic_link_state uic_link_state;
> >>>
> >>
> >> I have a UFS device emulator that has the RPMB capability. What are
> >> the expected good results for me to validate?
> >
> > Hi Joao, thanks for that. I'm attaching an archive with few basic
> > samples via user space interface.
> > You should run the program key first (program-key.sh), just don't do
> > it on a real device it's one in life time operation.
> >
>
> Managed to cross-compile to ARC and execute your test app in my platform.
> I made it in Buildroot, so I have the patches to enable the tool cross-
> compilation if necessary in the future.
>
Sounds like fun :)
I've just tried to follow the standard under tools, though this it's not something really generic which was surpising to me as this is in the kernel tree.
> The tool execution gives no errors, but also no info. I suggest you had success
> info and maybe some statistic (e.g. bytes read or written).
It did have some verbose print outs on both ends, but I've cleaned it out. It was meant to be an example rather than unit testing tool, but we can repurpose it.
Thanks
Toma
Thanks
Tomas
On Tue, 2016-04-05 at 20:16 +0800, kbuild test robot wrote:
> Hi Tomas,
>
> [auto build test ERROR on char-misc/char-misc-testing]
> [also build test ERROR on v4.6-rc2 next-20160405]
> [if your patch is applied to the wrong git tree, please drop us a
> note to help improving the system]
>
> url: https://github.com/0day-ci/linux/commits/Tomas-Winkler/Replay
> -Protected-Memory-Block-RPMB-subsystem/20160404-192243
> config: x86_64-randconfig-s3-04051858 (attached as .config)
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=x86_64
>
> All errors (new ones prefixed by >>):
>
> make[3]: *** No rule to make target 'kernel/gcov/base.o', needed
> by 'kernel/gcov/built-in.o'.
> make[3]: *** No rule to make target 'kernel/gcov/fs.o', needed by
> 'kernel/gcov/built-in.o'.
> >
> > >
> > > make[3]: *** No rule to make target 'kernel/gcov/gcc_3_4.o',
> > > needed by 'kernel/gcov/built-in.o'.
> make[3]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[3]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/mfd/88pm800.o'.
> make[3]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/firmware/google/memconsole.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/iio/dac/ad5624r_spi.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/iio/trigger/iio-trig-interrupt.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/input/joystick/gf2k.o'.
> make[4]: *** [drivers/input/joystick/iforce] Error 2
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/misc/eeprom/max6875.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/mmc/card/mmc_test.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/mmc/host/sdhci.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/pinctrl/intel/pinctrl-intel.o'.
> make[4]: Target '__build' not remade because of errors.
> --
> >
> > >
> > > make[4]: *** No rule to make target 'tools/objtool/objtool',
> > > needed by 'drivers/platform/chrome/chromeos_laptop.o'.
> make[4]: Target '__build' not remade because of errors.
> ..
Just to put that straight, those are issues in the testing environment
not in the patches.
Thanks
Tomas
Hi Tomas,
On Mon, Apr 04, 2016 at 02:11:22PM +0300, Tomas Winkler wrote:
> Add simple RPMB host testing tool. It can be used
> to program key, write and read data block, and retrieve
> write counter.
>
> Signed-off-by: Tomas Winkler <[email protected]>
> ---
> V2: resend
> MAINTAINERS | 1 +
> tools/Makefile | 16 +-
> tools/rpmb/.gitignore | 2 +
> tools/rpmb/Makefile | 32 ++
> tools/rpmb/rpmb.c | 807 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 853 insertions(+), 5 deletions(-)
> create mode 100644 tools/rpmb/.gitignore
> create mode 100644 tools/rpmb/Makefile
> create mode 100644 tools/rpmb/rpmb.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 07bd6f380460..b7966b95c265 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9425,6 +9425,7 @@ F: drivers/char/rpmb/*
> F: include/uapi/linux/rpmb.h
> F: include/linux/rpmb.h
> F: Documentation/ABI/testing/sysfs-class-rpmb
> +F: tools/rpmb/
>
> RTL2830 MEDIA DRIVER
> M: Antti Palosaari <[email protected]>
> diff --git a/tools/Makefile b/tools/Makefile
> index 60c7e6c8ff17..5b37ccd95cab 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -19,6 +19,7 @@ help:
> @echo ' lguest - a minimal 32-bit x86 hypervisor'
> @echo ' net - misc networking tools'
> @echo ' perf - Linux performance measurement and analysis tool'
> + @echo ' rpmb - Replay protected memory block access tool'
> @echo ' selftests - various kernel selftests'
> @echo ' spi - spi tools'
> @echo ' objtool - an ELF object analysis tool'
> @@ -55,7 +56,8 @@ acpi: FORCE
> cpupower: FORCE
> $(call descend,power/$@)
>
> -cgroup firewire hv guest spi usb virtio vm net iio gpio objtool: FORCE
> +cgroup firewire hv guest rpmb spi usb virtio vm net iio gpio objtool: FORCE
> +cgroup firewire hv guest rpmb spi usb virtio vm net iio: FORCE
This looks like an artifact from a bad merge resolution. The second
line needs to be deleted. This probably explains the kbuild robot build
errors, since CONFIG_STACK_VALIDATION requires objtool to be built.
> $(call descend,$@)
>
> liblockdep: FORCE
> @@ -85,7 +87,7 @@ freefall: FORCE
> $(call descend,laptop/$@)
>
> all: acpi cgroup cpupower hv firewire lguest \
> - perf selftests turbostat usb \
> + perf rpmb selftests turbostat usb \
> virtio vm net x86_energy_perf_policy \
> tmon freefall objtool
>
> @@ -95,7 +97,8 @@ acpi_install:
> cpupower_install:
> $(call descend,power/$(@:_install=),install)
>
> -cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install:
> +cgroup_install firewire_install hv_install lguest_install perf_install rpmb_install usb_install virtio_install vm_install net_install objtool_install:
> +cgroup_install firewire_install hv_install lguest_install perf_install rpmb_install usb_install virtio_install vm_install net_install:
Same here.
--
Josh