clear-pkgs-linux-iot-lts2018/0020-char-rpmb-provide-a-us...

822 lines
24 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tomas Winkler <tomas.winkler@intel.com>
Date: Thu, 16 Jul 2015 12:29:50 +0300
Subject: [PATCH] char: rpmb: provide a user space interface
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.
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.
V7: 1. copy_from_user the value of the frame pointer.
2. Fix possible macro side-effect due to macro argument reuse.
V8: 1. Fix kdoc errors
2. Move IOCTL to a different range due to conflict
3. Change license to dual BSD/GPL
V9: 1. Add version and capability ioctls and drop the request ioctl
2. Use zero based frame count: 0 means only meted are in a frame.
2. Add SPDX identifiers.
3. Fix comment typo in uapi/linux/rpmb.h
V10:
1. Rebase on 4.18
V11:
1. Rebase on 4.19
Change-Id: I00f2b5d5c92982fa2a3814a8bc56a3fecd19456f
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Tested-by: Avri Altman <avri.altman@sandisk.com>
---
Documentation/ioctl/ioctl-number.txt | 1 +
MAINTAINERS | 1 +
drivers/char/rpmb/Kconfig | 7 +
drivers/char/rpmb/Makefile | 1 +
drivers/char/rpmb/cdev.c | 296 +++++++++++++++++++++++++++
drivers/char/rpmb/core.c | 9 +-
drivers/char/rpmb/rpmb-cdev.h | 17 ++
include/linux/rpmb.h | 107 +---------
include/uapi/linux/rpmb.h | 192 +++++++++++++++++
9 files changed, 532 insertions(+), 99 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 13a7c999c04a..ae2f081324f4 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -324,6 +324,7 @@ Code Seq#(hex) Include File Comments
0xB3 00 linux/mmc/ioctl.h
0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org>
0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org>
+0xB5 80-8F linux/uapi/linux/rpmb.h <mailto:linux-mei@linux.intel.com>
0xB6 all linux/fpga-dfl.h
0xC0 00-0F linux/usb/iowarrior.h
0xCA 00-0F uapi/misc/cxl.h
diff --git a/MAINTAINERS b/MAINTAINERS
index c48553a07ce6..a3a9873e4307 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12547,6 +12547,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 b5cd02de91bb..cfecb1fccfc0 100644
--- a/drivers/char/rpmb/Kconfig
+++ b/drivers/char/rpmb/Kconfig
@@ -7,3 +7,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 badc1cd9428b..c171a5cfaed3 100644
--- a/drivers/char/rpmb/Makefile
+++ b/drivers/char/rpmb/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
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..bdac3894b111
--- /dev/null
+++ b/drivers/char/rpmb/cdev.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/*
+ * Copyright(c) 2015 - 2018 Intel Corporation. All rights reserved.
+ */
+#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_release - the cdev release function
+ *
+ * @inode: pointer to inode structure
+ * @fp: pointer to file structure
+ *
+ * Return: 0 always.
+ */
+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)
+{
+ struct rpmb_frame *frames;
+ u64 frames_ptr;
+
+ 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 -EOVERFLOW;
+
+ /* some archs have issues with 64bit get_user */
+ if (copy_from_user(&frames_ptr, &ucmd->frames_ptr, sizeof(frames_ptr)))
+ return -EFAULT;
+
+ frames = memdup_user(u64_to_user_ptr(frames_ptr),
+ rpmb_ioc_frames_len_jdec(cmd->nframes));
+ if (IS_ERR(frames))
+ return PTR_ERR(frames);
+
+ cmd->frames = frames;
+ return 0;
+}
+
+/**
+ * rpmb_cmd_copy_to_user - copy rpmb command to 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)
+{
+ u64 frames_ptr;
+
+ if (copy_from_user(&frames_ptr, &ucmd->frames_ptr, sizeof(frames_ptr)))
+ return -EFAULT;
+
+ /* some archs have issues with 64bit get_user */
+ if (copy_to_user(u64_to_user_ptr(frames_ptr), cmd->frames,
+ rpmb_ioc_frames_len_jdec(cmd->nframes)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
+ * rpmb_ioctl_seq_cmd - issue an rpmb command 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;
+}
+
+static long rpmb_ioctl_ver_cmd(struct rpmb_dev *rdev,
+ struct rpmb_ioc_ver_cmd __user *ptr)
+{
+ struct rpmb_ioc_ver_cmd ver = {
+ .api_version = RPMB_API_VERSION,
+ };
+
+ return copy_to_user(ptr, &ver, sizeof(ver)) ? -EFAULT : 0;
+}
+
+static long rpmb_ioctl_cap_cmd(struct rpmb_dev *rdev,
+ struct rpmb_ioc_cap_cmd __user *ptr)
+{
+ struct rpmb_ioc_cap_cmd cap;
+
+ cap.device_type = rdev->ops->type;
+ cap.target = rdev->target;
+ cap.block_size = rdev->ops->block_size;
+ cap.wr_cnt_max = rdev->ops->wr_cnt_max;
+ cap.rd_cnt_max = rdev->ops->rd_cnt_max;
+ cap.auth_method = rdev->ops->auth_method;
+ cap.capacity = rpmb_get_capacity(rdev);
+ cap.reserved = 0;
+
+ return copy_to_user(ptr, &cap, sizeof(cap)) ? -EFAULT : 0;
+}
+
+/**
+ * rpmb_ioctl - rpmb ioctl dispatcher
+ *
+ * @fp: a file pointer
+ * @cmd: ioctl command RPMB_IOC_SEQ_CMD RPMB_IOC_VER_CMD RPMB_IOC_CAP_CMD
+ * @arg: ioctl data: rpmb_ioc_ver_cmd rpmb_ioc_cap_cmd pmb_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_VER_CMD:
+ return rpmb_ioctl_ver_cmd(rdev, ptr);
+ case RPMB_IOC_CAP_CMD:
+ return rpmb_ioctl_cap_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)
+{
+ unregister_chrdev_region(rpmb_devt, RPMB_MAX_DEVS);
+}
diff --git a/drivers/char/rpmb/core.c b/drivers/char/rpmb/core.c
index 41a249c0c58f..e02c12b8046c 100644
--- a/drivers/char/rpmb/core.c
+++ b/drivers/char/rpmb/core.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/rpmb.h>
+#include "rpmb-cdev.h"
static DEFINE_IDA(rpmb_ida);
@@ -307,6 +308,7 @@ int rpmb_dev_unregister(struct rpmb_dev *rdev)
return -EINVAL;
mutex_lock(&rdev->lock);
+ rpmb_cdev_del(rdev);
device_del(&rdev->dev);
mutex_unlock(&rdev->lock);
@@ -413,10 +415,14 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev, u8 target,
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 device\n");
return rdev;
@@ -433,11 +439,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..e59ff0c05e9d
--- /dev/null
+++ b/drivers/char/rpmb/rpmb-cdev.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/*
+ * Copyright (C) 2015-2018 Intel Corp. All rights reserved
+ */
+#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 6acd9b1e70f6..fb535336d50f 100644
--- a/include/linux/rpmb.h
+++ b/include/linux/rpmb.h
@@ -7,105 +7,14 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/cdev.h>
+#include <uapi/linux/rpmb.h>
#include <linux/kref.h>
-/**
- * struct rpmb_frame_jdec - rpmb frame as defined by JDEC 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_jdec {
- 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 0x0001 /* Program RPMB Authentication Key */
-#define RPMB_GET_WRITE_COUNTER 0x0002 /* Read RPMB write counter */
-#define RPMB_WRITE_DATA 0x0003 /* Write data to RPMB partition */
-#define RPMB_READ_DATA 0x0004 /* Read data from RPMB partition */
-#define RPMB_RESULT_READ 0x0005 /* 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 underlying 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_NVME : NVM Express Revision 1.3a
- * @RPMB_TYPE_SIM : Simulation device.
- * @RPMB_TYPE_MAX : upper sentinel
- */
-enum rpmb_type {
- RPMB_TYPE_ANY = 0,
- RPMB_TYPE_EMMC,
- RPMB_TYPE_UFS,
- RPMB_TYPE_NVME,
-
- RPMB_TYPE_SIM = 0x0100,
- RPMB_TYPE_MAX = RPMB_TYPE_SIM | RPMB_TYPE_NVME,
-};
-
-#define RPMB_TYPE_HW(_type) ((_type) & 0xFF)
+#define RPMB_API_VERSION 0x80000001
extern struct class rpmb_class;
-#define RPMB_F_WRITE BIT(0)
-#define RPMB_F_REL_WRITE BIT(1)
-
/**
* struct rpmb_cmd: rpmb access command
*
@@ -122,10 +31,6 @@ struct rpmb_cmd {
void *frames;
};
-enum rpmb_auth_method {
- RPMB_HMAC_ALGO_SHA_256 = 0,
-};
-
/**
* struct rpmb_ops - RPMB ops to be implemented by underlying block device
*
@@ -163,6 +68,8 @@ struct rpmb_ops {
* @dev : device
* @id : device id
* @target : RPMB target/region within the physical device
+ * @cdev : character dev
+ * @status : device status
* @ops : operation exported by block layer
*/
struct rpmb_dev {
@@ -170,6 +77,10 @@ struct rpmb_dev {
struct device dev;
int id;
u8 target;
+#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..d304701cd258
--- /dev/null
+++ b/include/uapi/linux/rpmb.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/*
+ * Copyright (C) 2015-2018 Intel Corp. All rights reserved
+ */
+#ifndef _UAPI_LINUX_RPMB_H_
+#define _UAPI_LINUX_RPMB_H_
+
+#include <linux/types.h>
+
+/**
+ * enum rpmb_type - type of underlying 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_NVME : NVM Express Revision 1.3a
+ * @RPMB_TYPE_SIM : Simulation device.
+ * @RPMB_TYPE_MAX : upper sentinel
+ */
+enum rpmb_type {
+ RPMB_TYPE_ANY = 0,
+ RPMB_TYPE_EMMC,
+ RPMB_TYPE_UFS,
+ RPMB_TYPE_NVME,
+
+ RPMB_TYPE_SIM = 0x0100,
+ RPMB_TYPE_MAX = RPMB_TYPE_SIM | RPMB_TYPE_NVME,
+};
+
+#define RPMB_TYPE_HW(_type) ((_type) & 0xFF)
+
+/**
+ * struct rpmb_frame_jdec - rpmb frame as defined by JDEC 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_jdec {
+ __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));
+
+/* length of the part of the frame used for HMAC computation */
+#define rpmb_jdec_hmac_data_len \
+ (sizeof(struct rpmb_frame_jdec) - \
+ offsetof(struct rpmb_frame_jdec, data))
+
+#define RPMB_PROGRAM_KEY 0x0001 /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 0x0002 /* Read RPMB write counter */
+#define RPMB_WRITE_DATA 0x0003 /* Write data to RPMB partition */
+#define RPMB_READ_DATA 0x0004 /* Read data from RPMB partition */
+#define RPMB_RESULT_READ 0x0005 /* 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
+};
+
+#define RPMB_F_READ 0UL
+#define RPMB_F_WRITE (1UL << 0)
+#define RPMB_F_REL_WRITE (1UL << 1)
+
+enum rpmb_auth_method {
+ RPMB_HMAC_ALGO_SHA_256 = 0,
+};
+
+/**
+ * struct rpmb_cmd - rpmb access command
+ *
+ * @flags: command flags
+ * 0 - read command
+ * 1 - write command RPMB_F_WRITE
+ * 2 - reliable write RPMB_F_REL_WRITE
+ * @nframes: number of rpmb data frames in the command.
+ * 0 means 1 frame with meta data only.
+ * @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 { \
+ struct rpmb_ioc_cmd *icmd = &(_cmd); \
+ icmd->flags = (_flags); \
+ icmd->nframes = (_n); \
+ icmd->frames_ptr = (__aligned_u64)(intptr_t)(_ptr); \
+} while (0)
+
+#define rpmb_ioc_frames_len_jdec(_n) \
+ (((_n) ?: 1) * sizeof(struct rpmb_frame_jdec))
+
+/**
+ * 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];
+} __attribute__((packed));
+
+/**
+ * struct rpmb_ioc_ver_cmd - rpmb api version
+ *
+ * @api_version: rpmb API version.
+ */
+struct rpmb_ioc_ver_cmd {
+ __u32 api_version;
+} __attribute__((packed));
+
+/**
+ * struct rpmb_ioc_ver_cmd - rpmb api version
+ *
+ * @device_type: underlying storage device type
+ * @target: rpmb target/region within RPMB partition.
+ * @capacity: storage capacity
+ * @block_size: storage data block size
+ * @wr_cnt_max: maximal number of block that can be written in a single request.
+ * @rd_cnt_max: maximal number of block that can be read in a single request.
+ * @auth_method: authentication method: currently always HMAC_SHA_256
+ * @reserved: reserved to align to 4 bytes.
+ */
+struct rpmb_ioc_cap_cmd {
+ __u16 device_type;
+ __u16 target;
+ __u16 capacity;
+ __u16 block_size;
+ __u16 wr_cnt_max;
+ __u16 rd_cnt_max;
+ __u16 auth_method;
+ __u16 reserved;
+} __attribute__((packed));
+
+#define RPMB_IOC_VER_CMD _IOR(0xB5, 80, struct rpmb_ioc_ver_cmd)
+#define RPMB_IOC_CAP_CMD _IOR(0xB5, 81, struct rpmb_ioc_cap_cmd)
+#define RPMB_IOC_SEQ_CMD _IOWR(0xB5, 82, struct rpmb_ioc_seq_cmd)
+
+#endif /* _UAPI_LINUX_RPMB_H_ */
--
https://clearlinux.org