diff mbox

[v6,5/9] char: rpmb: provide a user space interface

Message ID 1473772984-17562-6-git-send-email-tomas.winkler@intel.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Winkler, Tomas Sept. 13, 2016, 1:23 p.m. UTC
The user space API is achieved via two synchronous IOCTLs.
Simplified one, RPMB_IOC_REQ_CMD, were read result cycles is performed
by the framework on behalf the user and second, RPMB_IOC_SEQ_CMD where
the whole RPMB sequence including RESULT_READ is supplied by the caller.
The latter is intended for easier adjusting of the applications that
use MMC_IOC_MULTI_CMD ioctl.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: use memdup_user
V3: commit message fix
V4: resend
V5: 1. Add RPMB_IOC_SEQ_CMD API.
    2. Export uapi rpmb.h header
V6: 1. remove #include <linux/module.h>
    2. Add ioctl documentation

 Documentation/ioctl/ioctl-number.txt |   1 +
 MAINTAINERS                          |   1 +
 drivers/char/rpmb/Kconfig            |   7 +
 drivers/char/rpmb/Makefile           |   1 +
 drivers/char/rpmb/cdev.c             | 317 +++++++++++++++++++++++++++++++++++
 drivers/char/rpmb/core.c             |   9 +-
 drivers/char/rpmb/rpmb-cdev.h        |  25 +++
 include/linux/rpmb.h                 |  81 +--------
 include/uapi/linux/Kbuild            |   1 +
 include/uapi/linux/rpmb.h            | 152 +++++++++++++++++
 10 files changed, 521 insertions(+), 74 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 mbox

Patch

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 81c7f2bb7daf..f645543866c7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -321,6 +321,7 @@  Code  Seq#(hex)	Include File		Comments
 0xB1	00-1F	PPPoX			<mailto:mostrows@styx.uwaterloo.ca>
 0xB3	00	linux/mmc/ioctl.h
 0xB4	00-0F	linux/gpio.h		<mailto:linux-gpio@vger.kernel.org>
+0xB5	00-01	linux/uapi/linux/rpmb.h <mailto:linux-mei@linux.intel.com>
 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 d701a972c83a..3a092b90add3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9999,6 +9999,7 @@  M:	Tomas Winkler <tomas.winkler@intel.com>
 L:	linux-kernel@vger.kernel.org
 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..837c32e722ec
--- /dev/null
+++ b/drivers/char/rpmb/cdev.c
@@ -0,0 +1,317 @@ 
+/*
+ * 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/fs.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <linux/slab.h>
+#include <linux/capability.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) */
+/* from MMC_IOC_MAX_CMDS */
+#define RPMB_MAX_FRAMES 255
+
+/**
+ * rpmb_open - the open function
+ *
+ * @inode: pointer to inode structure
+ * @fp: pointer to file structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_open(struct inode *inode, struct file *fp)
+{
+	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);
+
+	fp->private_data = rdev;
+
+	mutex_unlock(&rdev->lock);
+
+	return nonseekable_open(inode, fp);
+}
+
+/**
+ * rpmb_open - the open function
+ *
+ * @inode: pointer to inode structure
+ * @fp: pointer to file structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_release(struct inode *inode, struct file *fp)
+{
+	struct rpmb_dev *rdev = fp->private_data;
+
+	clear_bit(RPMB_DEV_OPEN, &rdev->status);
+
+	return 0;
+}
+
+/**
+ * rpmb_cmd_copy_from_user -  copy rpmb command from the user space
+ *
+ * @cmd:  internal cmd structure
+ * @ucmd: user space cmd structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_cmd_copy_from_user(struct rpmb_cmd *cmd,
+				   struct rpmb_ioc_cmd __user *ucmd)
+{
+	size_t sz;
+	struct rpmb_frame *frames;
+
+	if (get_user(cmd->flags, &ucmd->flags))
+		return -EFAULT;
+
+	if (get_user(cmd->nframes, &ucmd->nframes))
+		return -EFAULT;
+
+	if (cmd->nframes > RPMB_MAX_FRAMES)
+		return -EINVAL;
+
+	sz = cmd->nframes * sizeof(struct rpmb_frame);
+	frames = memdup_user(u64_to_user_ptr(ucmd->frames_ptr), sz);
+	if (IS_ERR(frames))
+		return PTR_ERR(frames);
+
+	cmd->frames = frames;
+	return 0;
+}
+
+/**
+ * rpmb_cmd_copy_to_user -  copy rpmb command the the user space
+ *
+ * @ucmd: user space cmd structure
+ * @cmd:  internal cmd structure
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int rpmb_cmd_copy_to_user(struct rpmb_ioc_cmd __user *ucmd,
+				 struct rpmb_cmd *cmd)
+{
+	size_t sz;
+
+	sz = cmd->nframes * sizeof(struct rpmb_frame);
+	if (copy_to_user(u64_to_user_ptr(ucmd->frames_ptr), cmd->frames, sz))
+		return -EFAULT;
+
+	return 0;
+}
+
+/**
+ * rpmb_ioctl_seq_cmd: issue rpmb sequence
+ *
+ * @rdev: rpmb device
+ * @ptr:  rpmb cmd sequence
+ *
+ * RPMB_IOC_SEQ_CMD handler
+ *
+ * Return: 0 on success, <0 on error
+ */
+static long rpmb_ioctl_seq_cmd(struct rpmb_dev *rdev,
+			       struct rpmb_ioc_seq_cmd __user *ptr)
+{
+	__u64 ncmds;
+	struct rpmb_cmd *cmds;
+	struct rpmb_ioc_cmd __user *ucmds;
+
+	int i;
+	int ret;
+
+	/* The caller must have CAP_SYS_RAWIO, like mmc ioctl */
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* some archs have issues with 64bit get_user */
+	if (copy_from_user(&ncmds, &ptr->num_of_cmds, sizeof(ncmds)))
+		return -EFAULT;
+
+	if (ncmds > 3) {
+		dev_err(&rdev->dev, "supporting up to 3 packets (%llu)\n",
+			ncmds);
+		return -EINVAL;
+	}
+
+	cmds = kcalloc(ncmds, sizeof(*cmds), GFP_KERNEL);
+	if (!cmds)
+		return -ENOMEM;
+
+	ucmds = (struct rpmb_ioc_cmd __user *)ptr->cmds;
+	for (i = 0; i < ncmds; i++) {
+		ret = rpmb_cmd_copy_from_user(&cmds[i], &ucmds[i]);
+		if (ret)
+			goto out;
+	}
+
+	ret = rpmb_cmd_seq(rdev, cmds, ncmds);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < ncmds; i++) {
+		ret = rpmb_cmd_copy_to_user(&ucmds[i], &cmds[i]);
+		if (ret)
+			goto out;
+	}
+out:
+	for (i = 0; i < ncmds; i++)
+		kfree(cmds[i].frames);
+	kfree(cmds);
+	return ret;
+}
+
+/**
+ * rpmb_ioctl_req_cmd: issue rpmb request command
+ *
+ * @rdev: rpmb device
+ * @ptr: rpmb request command
+ *
+ * RPMB_IOC_REQ_CMD handler
+ *
+ * Return: 0 on success; < 0 on error
+ */
+static long rpmb_ioctl_req_cmd(struct rpmb_dev *rdev,
+			       struct rpmb_ioc_req_cmd __user *ptr)
+{
+	struct rpmb_data rpmbd;
+	u64 req_type;
+	int ret;
+
+	/* some archs have issues with 64bit get_user */
+	if (copy_from_user(&req_type, &ptr->req_type, sizeof(req_type)))
+		return -EFAULT;
+
+	if (req_type >= U16_MAX)
+		return -EINVAL;
+
+	memset(&rpmbd, 0, sizeof(rpmbd));
+
+	rpmbd.req_type = req_type & 0xFFFF;
+
+	ret = rpmb_cmd_copy_from_user(&rpmbd.icmd, &ptr->icmd);
+	if (ret)
+		goto out;
+
+	ret = rpmb_cmd_copy_from_user(&rpmbd.ocmd, &ptr->ocmd);
+	if (ret)
+		goto out;
+
+	ret = rpmb_cmd_req(rdev, &rpmbd);
+	if (ret)
+		goto out;
+
+	ret = rpmb_cmd_copy_to_user(&ptr->ocmd, &rpmbd.ocmd);
+
+out:
+	kfree(rpmbd.icmd.frames);
+	kfree(rpmbd.ocmd.frames);
+	return ret;
+}
+
+/**
+ * rpmb_ioctl - rpmb ioctl dispatcher
+ *
+ * @fp: a file pointer
+ * @cmd: ioctl command RPMB_IOC_REQ_CMD or RPMB_IOC_SEQ_CMD
+ * @arg: ioctl data: rpmb_ioc_req_cmd or rpmb_ioc_seq_cmd
+ *
+ * Return: 0 on success; < 0 on error
+ */
+static long rpmb_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct rpmb_dev *rdev = fp->private_data;
+	void __user *ptr = (void __user *)arg;
+
+	switch (cmd) {
+	case RPMB_IOC_REQ_CMD:
+		return rpmb_ioctl_req_cmd(rdev, ptr);
+	case RPMB_IOC_SEQ_CMD:
+		return rpmb_ioctl_seq_cmd(rdev, ptr);
+	default:
+		dev_err(&rdev->dev, "unsupported ioctl 0x%x.\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long rpmb_compat_ioctl(struct file *fp, unsigned int cmd,
+			      unsigned long arg)
+{
+	return rpmb_ioctl(fp, cmd, (unsigned long)compat_ptr(arg));
+}
+#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   = rpmb_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 f6b4cabb0982..7707ccb37b23 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);
 
@@ -429,6 +430,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);
 
@@ -479,10 +481,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;
@@ -499,11 +505,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..5fb41e586ba9
--- /dev/null
+++ b/drivers/char/rpmb/rpmb-cdev.h
@@ -0,0 +1,25 @@ 
+/*
+ * 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 ed4e372d5b13..1f3fa3fc5d67 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
@@ -106,9 +38,6 @@  enum rpmb_type {
 
 extern struct class rpmb_class;
 
-#define RPMB_F_WRITE     BIT(0)
-#define RPMB_F_REL_WRITE BIT(1)
-
 /**
  * struct rpmb_cmd: rpmb access command
  *
@@ -162,12 +91,18 @@  struct rpmb_ops {
  * @lock       : the device lock
  * @dev        : device
  * @id         : device id
+ * @cdev       : character dev
+ * @status     : device status
  * @ops        : operation exported by block layer
  */
 struct rpmb_dev {
 	struct mutex lock; /* device serialization 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/Kbuild b/include/uapi/linux/Kbuild
index 185f8ea2702f..8ea2ae1952dc 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -362,6 +362,7 @@  header-y += rio_mport_cdev.h
 header-y += romfs_fs.h
 header-y += rose.h
 header-y += route.h
+header-y += rpmb.h
 header-y += rtc.h
 header-y += rtnetlink.h
 header-y += scc.h
diff --git a/include/uapi/linux/rpmb.h b/include/uapi/linux/rpmb.h
new file mode 100644
index 000000000000..a6fa78e03c4f
--- /dev/null
+++ b/include/uapi/linux/rpmb.h
@@ -0,0 +1,152 @@ 
+/*
+ * 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
+};
+
+#define RPMB_F_WRITE     (1UL << 0)
+#define RPMB_F_REL_WRITE (1UL << 1)
+
+/**
+ * struct rpmb_cmd: rpmb access command
+ *
+ * @flags:   command flags
+ *      0 - read command
+ *      1 - write commnad RPMB_F_WRITE
+ *      2 -  reliable write RPMB_F_REL_WRITE
+ * @nframes: number of rpmb frames in the command
+ * @frames_ptr:  a pointer to the list of rpmb frames
+ */
+struct rpmb_ioc_cmd {
+	__u32 flags;
+	__u32 nframes;
+	__aligned_u64 frames_ptr;
+};
+
+#define rpmb_ioc_cmd_set_frames(_cmd, _ptr) \
+	(_cmd).frames_ptr = (__aligned_u64)(intptr_t)(_ptr)
+
+#define rpmb_ioc_cmd_set(_cmd, _flags, _ptr, _n) do {         \
+	(_cmd).flags = (_flags);                              \
+	(_cmd).nframes = (_n);                                \
+	(_cmd).frames_ptr = (__aligned_u64)(intptr_t)(_ptr);  \
+} while (0)
+
+/**
+ * struct rpmb_ioc_req_cmd - rpmb operation request command
+ *
+ * @req_type: request type:  must match the in frame req_resp
+ *            program key
+ *            get write counter
+ *            write data
+ *            read data
+ * @icmd: input command
+ * @ocmd: output/result command
+ */
+struct rpmb_ioc_req_cmd {
+	__u64 req_type;
+	struct rpmb_ioc_cmd icmd;
+	struct rpmb_ioc_cmd ocmd;
+};
+
+/**
+ * struct rpmb_ioc_seq_cmd - rpmb command sequence
+ *
+ * @num_of_cmds: number of commands
+ * @cmds: list of rpmb commands
+ */
+struct rpmb_ioc_seq_cmd {
+	__u64 num_of_cmds;
+	struct rpmb_ioc_cmd cmds[0];
+};
+
+#define RPMB_IOC_REQ_CMD _IOWR(0xB5, 0, struct rpmb_ioc_req_cmd)
+#define RPMB_IOC_SEQ_CMD _IOWR(0xB5, 1, struct rpmb_ioc_seq_cmd)
+
+#endif /* _UAPI_LINUX_RPMB_H_ */