On Wed, 3 Mar 2021 at 14:55, Alex Bennée <[email protected]> wrote:
>
> A number of storage technologies support a specialised hardware
> partition designed to be resistant to replay attacks. The underlying
> HW protocols differ but the operations are common. 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 wishes to store a replay
> protected data, requests the storage device via RPMB layer to store
> the data.
>
> A TEE device driver can claim the RPMB interface, for example, via
> class_interface_register(). The RPMB layer provides a series of
> operations for interacting with the device.
>
> * program_key - a one time operation for setting up a new device
> * get_capacity - introspect the device capacity
> * get_write_count - check the write counter
> * write_blocks - write a series of blocks to the RPMB device
> * read_blocks - read a series of blocks from the RPMB device
>
> The detailed operation of implementing the access is left to the TEE
> device driver itself.
>
> [This is based-on Thomas Winkler's proposed API from:
>
> https://lore.kernel.org/linux-mmc/[email protected]/
>
> The principle difference is the framing details and HW specific
> bits (JDEC vs NVME frames) are left to the lower level TEE driver to
> worry about. The eventual userspace ioctl interface will aim to be
> similarly generic. This is an RFC to follow up on:
>
> Subject: RPMB user space ABI
> Date: Thu, 11 Feb 2021 14:07:00 +0000
> Message-ID: <[email protected]>]
>
> Signed-off-by: Alex Bennée <[email protected]>
> Cc: Tomas Winkler <[email protected]>
> Cc: Ulf Hansson <[email protected]>
> Cc: Linus Walleij <[email protected]>
> Cc: Arnd Bergmann <[email protected]>
> Cc: Ilias Apalodimas <[email protected]>
Alex, I promise to have a closer look at this and provide my opinions.
However, it looks like you have posted patch 1 and patch2, but the
remainder 3, 4, 5 I can't find. Was this perhaps intentional?
Moreover, I think these kinds of changes deserve a proper
cover-letter, describing the overall goal with the series. Can you
perhaps re-submit, so clarify things.
Kind regards
Uffe
> ---
> MAINTAINERS | 7 +
> drivers/char/Kconfig | 2 +
> drivers/char/Makefile | 1 +
> drivers/char/rpmb/Kconfig | 11 +
> drivers/char/rpmb/Makefile | 7 +
> drivers/char/rpmb/core.c | 429 +++++++++++++++++++++++++++++++++++++
> include/linux/rpmb.h | 163 ++++++++++++++
> 7 files changed, 620 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 bfc1b86e3e73..076f3983526c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -15369,6 +15369,13 @@ T: git git://linuxtv.org/media_tree.git
> F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
> F: drivers/media/platform/sunxi/sun8i-rotate/
>
> +RPMB SUBSYSTEM
> +M: ?
> +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 d229a2d0c017..a7834cc3e0ea 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -471,6 +471,8 @@ config ADI
> and SSM (Silicon Secured Memory). Intended consumers of this
> driver include crash and makedumpfile.
>
> +source "drivers/char/rpmb/Kconfig"
> +
> endmenu
>
> config RANDOM_TRUST_CPU
> diff --git a/drivers/char/Makefile b/drivers/char/Makefile
> index ffce287ef415..0eed6e21a7a7 100644
> --- a/drivers/char/Makefile
> +++ b/drivers/char/Makefile
> @@ -47,3 +47,4 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
> obj-$(CONFIG_XILLYBUS) += xillybus/
> obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
> obj-$(CONFIG_ADI) += adi.o
> +obj-$(CONFIG_RPMB) += rpmb/
> diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
> new file mode 100644
> index 000000000000..431c2823cf70
> --- /dev/null
> +++ b/drivers/char/rpmb/Kconfig
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2015-2019, Intel Corporation.
> +
> +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..24d4752a9a53
> --- /dev/null
> +++ b/drivers/char/rpmb/Makefile
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2015-2019, Intel Corporation.
> +
> +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..a2e21c14986a
> --- /dev/null
> +++ b/drivers/char/rpmb/core.c
> @@ -0,0 +1,429 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright(c) 2015 - 2019 Intel Corporation. All rights reserved.
> + * Copyright(c) 2021 - Linaro Ltd.
> + */
> +#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);
> +
> +/**
> + * rpmb_program_key() - program the RPMB access key
> + * @rdev: rpmb device
> + * @key: key data
> + * @keylen: length of key data
> + *
> + * A successful programming of the key implies it has been set by the
> + * driver and can be used.
> + *
> + * Return:
> + * * 0 on success
> + * * -EINVAL on wrong parameters
> + * * -EPERM key already programmed
> + * * -EOPNOTSUPP if device doesn't support the requested operation
> + * * < 0 if the operation fails
> + */
> +int rpmb_program_key(struct rpmb_dev *rdev, key_serial_t keyid)
> +{
> + int err;
> +
> + if (!rdev || !keyid)
> + return -EINVAL;
> +
> + mutex_lock(&rdev->lock);
> + err = -EOPNOTSUPP;
> + if (rdev->ops && rdev->ops->program_key) {
> + err = rdev->ops->program_key(rdev->dev.parent, rdev->target,
> + keyid);
> + }
> + mutex_unlock(&rdev->lock);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(rpmb_program_key);
> +
> +/**
> + * rpmb_get_capacity() - returns the capacity of the rpmb device
> + * @rdev: rpmb device
> + *
> + * Return:
> + * * capacity of the device in units of 128K, on success
> + * * -EINVAL on wrong parameters
> + * * -EOPNOTSUPP if device doesn't support the requested operation
> + * * < 0 if the operation fails
> + */
> +int rpmb_get_capacity(struct rpmb_dev *rdev)
> +{
> + int err;
> +
> + if (!rdev)
> + return -EINVAL;
> +
> + mutex_lock(&rdev->lock);
> + err = -EOPNOTSUPP;
> + if (rdev->ops && rdev->ops->get_capacity)
> + err = rdev->ops->get_capacity(rdev->dev.parent, rdev->target);
> + mutex_unlock(&rdev->lock);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(rpmb_get_capacity);
> +
> +/**
> + * rpmb_get_write_count() - returns the write counter of the rpmb device
> + * @rdev: rpmb device
> + *
> + * Return:
> + * * counter
> + * * -EINVAL on wrong parameters
> + * * -EOPNOTSUPP if device doesn't support the requested operation
> + * * < 0 if the operation fails
> + */
> +int rpmb_get_write_count(struct rpmb_dev *rdev)
> +{
> + int err;
> +
> + if (!rdev)
> + return -EINVAL;
> +
> + mutex_lock(&rdev->lock);
> + err = -EOPNOTSUPP;
> + if (rdev->ops && rdev->ops->get_write_count)
> + err = rdev->ops->get_write_count(rdev->dev.parent, rdev->target);
> + mutex_unlock(&rdev->lock);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(rpmb_get_write_count);
> +
> +/**
> + * rpmb_write_blocks() - write data to RPMB device
> + * @rdev: rpmb device
> + * @addr: block address (index of first block - 256B blocks)
> + * @count: number of 256B blosks
> + * @data: pointer to data to program
> + *
> + * Write a series of blocks to the RPMB device.
> + *
> + * Return:
> + * * 0 on success
> + * * -EINVAL on wrong parameters
> + * * -EACCESS no key set
> + * * -EOPNOTSUPP if device doesn't support the requested operation
> + * * < 0 if the operation fails
> + */
> +int rpmb_write_blocks(struct rpmb_dev *rdev, key_serial_t keyid, int addr,
> + int count, u8 *data)
> +{
> + int err;
> +
> + if (!rdev || !count || !data)
> + return -EINVAL;
> +
> + mutex_lock(&rdev->lock);
> + err = -EOPNOTSUPP;
> + if (rdev->ops && rdev->ops->write_blocks) {
> + err = rdev->ops->write_blocks(rdev->dev.parent, rdev->target, keyid,
> + addr, count, data);
> + }
> + mutex_unlock(&rdev->lock);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(rpmb_write_blocks);
> +
> +/**
> + * rpmb_read_blocks() - read data from RPMB device
> + * @rdev: rpmb device
> + * @addr: block address (index of first block - 256B blocks)
> + * @count: number of 256B blocks
> + * @data: pointer to data to read
> + *
> + * Read a series of one or more blocks from the RPMB device.
> + *
> + * Return:
> + * * 0 on success
> + * * -EINVAL on wrong parameters
> + * * -EACCESS no key set
> + * * -EOPNOTSUPP if device doesn't support the requested operation
> + * * < 0 if the operation fails
> + */
> +int rpmb_read_blocks(struct rpmb_dev *rdev, int addr, int count, u8 *data)
> +{
> + int err;
> +
> + if (!rdev || !count || !data)
> + return -EINVAL;
> +
> + mutex_lock(&rdev->lock);
> + err = -EOPNOTSUPP;
> + if (rdev->ops && rdev->ops->read_blocks) {
> + err = rdev->ops->read_blocks(rdev->dev.parent, rdev->target,
> + addr, count, data);
> + }
> + mutex_unlock(&rdev->lock);
> +
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(rpmb_read_blocks);
> +
> +
> +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
> + */
> +static
> +struct rpmb_dev *rpmb_dev_find_device(const 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;
> +}
> +
> +struct device_with_target {
> + const struct device *dev;
> + u8 target;
> +};
> +
> +static int match_by_parent(struct device *dev, const void *data)
> +{
> + const struct device_with_target *d = data;
> + struct rpmb_dev *rdev = to_rpmb_dev(dev);
> +
> + return (d->dev && dev->parent == d->dev && rdev->target == d->target);
> +}
> +
> +/**
> + * rpmb_dev_find_by_device() - retrieve rpmb device from the parent device
> + * @parent: parent device of the rpmb device
> + * @target: RPMB target/region within the physical 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, u8 target)
> +{
> + struct device_with_target t;
> +
> + if (!parent)
> + return NULL;
> +
> + t.dev = parent;
> + t.target = target;
> +
> + return rpmb_dev_find_device(&t, match_by_parent);
> +}
> +EXPORT_SYMBOL_GPL(rpmb_dev_find_by_device);
> +
> +/**
> + * rpmb_dev_unregister() - unregister RPMB partition from the RPMB subsystem
> + * @rdev: the rpmb device to unregister
> + * Return:
> + * * 0 on success
> + * * -EINVAL on wrong parameters
> + */
> +int rpmb_dev_unregister(struct rpmb_dev *rdev)
> +{
> + if (!rdev)
> + return -EINVAL;
> +
> + 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_unregister_by_device() - unregister RPMB partition
> + * from the RPMB subsystem
> + * @dev: the parent device of the rpmb device
> + * @target: RPMB target/region within the physical device
> + * Return:
> + * * 0 on success
> + * * -EINVAL on wrong parameters
> + * * -ENODEV if a device cannot be find.
> + */
> +int rpmb_dev_unregister_by_device(struct device *dev, u8 target)
> +{
> + struct rpmb_dev *rdev;
> +
> + if (!dev)
> + return -EINVAL;
> +
> + rdev = rpmb_dev_find_by_device(dev, target);
> + if (!rdev) {
> + dev_warn(dev, "no disk found %s\n", dev_name(dev->parent));
> + return -ENODEV;
> + }
> +
> + rpmb_dev_put(rdev);
> +
> + return rpmb_dev_unregister(rdev);
> +}
> +EXPORT_SYMBOL_GPL(rpmb_dev_unregister_by_device);
> +
> +/**
> + * rpmb_dev_get_drvdata() - driver data getter
> + * @rdev: rpmb device
> + *
> + * Return: driver private data
> + */
> +void *rpmb_dev_get_drvdata(const struct rpmb_dev *rdev)
> +{
> + return dev_get_drvdata(&rdev->dev);
> +}
> +EXPORT_SYMBOL_GPL(rpmb_dev_get_drvdata);
> +
> +/**
> + * rpmb_dev_set_drvdata() - driver data setter
> + * @rdev: rpmb device
> + * @data: data to store
> + */
> +void rpmb_dev_set_drvdata(struct rpmb_dev *rdev, void *data)
> +{
> + dev_set_drvdata(&rdev->dev, data);
> +}
> +EXPORT_SYMBOL_GPL(rpmb_dev_set_drvdata);
> +
> +/**
> + * rpmb_dev_register - register RPMB partition with the RPMB subsystem
> + * @dev: storage device of the rpmb device
> + * @target: RPMB target/region within the physical device
> + * @ops: device specific operations
> + *
> + * Return: a pointer to rpmb device
> + */
> +struct rpmb_dev *rpmb_dev_register(struct device *dev, u8 target,
> + const struct rpmb_ops *ops)
> +{
> + struct rpmb_dev *rdev;
> + int id;
> + int ret;
> +
> + if (!dev || !ops)
> + return ERR_PTR(-EINVAL);
> +
> + if (!ops->program_key)
> + return ERR_PTR(-EINVAL);
> +
> + if (!ops->get_capacity)
> + return ERR_PTR(-EINVAL);
> +
> + if (!ops->get_write_count)
> + return ERR_PTR(-EINVAL);
> +
> + if (!ops->write_blocks)
> + return ERR_PTR(-EINVAL);
> +
> + if (!ops->read_blocks)
> + return ERR_PTR(-EINVAL);
> +
> + if (ops->type == RPMB_TYPE_ANY || ops->type > RPMB_TYPE_MAX)
> + return ERR_PTR(-EINVAL);
> +
> + rdev = kzalloc(sizeof(*rdev), 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;
> + rdev->target = target;
> +
> + 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 device\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 v2");
> diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h
> new file mode 100644
> index 000000000000..718ba7c91ecd
> --- /dev/null
> +++ b/include/linux/rpmb.h
> @@ -0,0 +1,163 @@
> +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
> +/*
> + * Copyright (C) 2015-2019 Intel Corp. All rights reserved
> + * Copyright (C) 2021 Linaro Ltd
> + */
> +#ifndef __RPMB_H__
> +#define __RPMB_H__
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/key.h>
> +
> +/**
> + * struct rpmb_ops - RPMB ops to be implemented by underlying block device
> + *
> + * @program_key : program device key (once only op).
> + * @get_capacity : rpmb size in 128K units in for region/target.
> + * @get_write_count: return the device write counter
> + * @write_blocks : write blocks to RPMB device
> + * @read_blocks : read blocks from RPMB device
> + * @block_size : block size in half sectors (1 == 256B)
> + * @wr_cnt_max : maximal number of blocks that can be
> + * written in one access.
> + * @rd_cnt_max : maximal number of blocks that can be
> + * read in one access.
> + * @auth_method : rpmb_auth_method
> + * @dev_id : unique device identifier
> + * @dev_id_len : unique device identifier length
> + */
> +struct rpmb_ops {
> + int (*program_key)(struct device *dev, u8 target, key_serial_t keyid);
> + int (*get_capacity)(struct device *dev, u8 target);
> + int (*get_write_count)(struct device *dev, u8 target);
> + int (*write_blocks)(struct device *dev, u8 target, key_serial_t keyid,
> + int addr, int count, u8 *data);
> + int (*read_blocks)(struct device *dev, u8 target,
> + int addr, int count, u8 *data);
> + u16 block_size;
> + u16 wr_cnt_max;
> + u16 rd_cnt_max;
> + u16 auth_method;
> + const u8 *dev_id;
> + size_t dev_id_len;
> +};
> +
> +/**
> + * struct rpmb_dev - device which can support RPMB partition
> + *
> + * @lock : the device lock
> + * @dev : device
> + * @id : device id
> + * @target : RPMB target/region within the physical device
> + * @ops : operation exported by block layer
> + */
> +struct rpmb_dev {
> + struct mutex lock; /* device serialization lock */
> + struct device dev;
> + int id;
> + u8 target;
> + 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, u8 target);
> +struct rpmb_dev *rpmb_dev_get_by_type(u32 type);
> +struct rpmb_dev *rpmb_dev_register(struct device *dev, u8 target,
> + const struct rpmb_ops *ops);
> +void *rpmb_dev_get_drvdata(const struct rpmb_dev *rdev);
> +void rpmb_dev_set_drvdata(struct rpmb_dev *rdev, void *data);
> +int rpmb_dev_unregister(struct rpmb_dev *rdev);
> +int rpmb_dev_unregister_by_device(struct device *dev, u8 target);
> +int rpmb_program_key(struct rpmb_dev *rdev, key_serial_t keyid);
> +int rpmb_get_capacity(struct rpmb_dev *rdev);
> +int rpmb_get_write_count(struct rpmb_dev *rdev);
> +int rpmb_write_blocks(struct rpmb_dev *rdev, key_serial_t keyid,
> + int addr, int count, u8 *data);
> +int rpmb_read_blocks(struct rpmb_dev *rdev, int addr, int count, u8 *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,
> + u8 target)
> +{
> + return NULL;
> +}
> +
> +static inline
> +struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type)
> +{
> + return NULL;
> +}
> +
> +static inline void *rpmb_dev_get_drvdata(const struct rpmb_dev *rdev)
> +{
> + return NULL;
> +}
> +
> +static inline void rpmb_dev_set_drvdata(struct rpmb_dev *rdev, void *data)
> +{
> +}
> +
> +static inline struct rpmb_dev *
> +rpmb_dev_register(struct device *dev, u8 target, const struct rpmb_ops *ops)
> +{
> + return NULL;
> +}
> +
> +static inline int rpmb_dev_unregister(struct rpmb_dev *dev)
> +{
> + return 0;
> +}
> +
> +static inline int rpmb_dev_unregister_by_device(struct device *dev, u8 target)
> +{
> + return 0;
> +}
> +
> +static inline int rpmb_program_key(struct rpmb_dev *rdev, key_serial_t keyid)
> +{
> + return 0;
> +}
> +
> +static inline rpmb_set_key(struct rpmb_dev *rdev, u8 *key, int keylen);
> +{
> + return 0;
> +}
> +
> +static inline int rpmb_get_capacity(struct rpmb_dev *rdev)
> +{
> + return 0;
> +}
> +
> +static inline int rpmb_get_write_count(struct rpmb_dev *rdev)
> +{
> + return 0;
> +}
> +
> +static inline int rpmb_write_blocks(struct rpmb_dev *rdev, int addr, int count,
> + u8 *data)
> +{
> + return 0;
> +}
> +
> +static inline int rpmb_read_blocks(struct rpmb_dev *rdev, int addr, int count,
> + u8 *data)
> +{
> + return 0;
> +}
> +
> +#endif /* CONFIG_RPMB */
> +
> +#endif /* __RPMB_H__ */
> --
> 2.20.1
>
Foolishly I'd missed you out of the series Cc so you only got those
two patches. You should find the rest @
Subject: [RFC PATCH 0/5] RPMB internal and user-space API + WIP
virtio-rpmb frontend
Date: Wed, 3 Mar 2021 13:54:55 +0000
Message-Id: <[email protected]>
assuming you are subscribed to one of the Cc'd lists.
On Wed, 3 Mar 2021 at 15:29, Ulf Hansson <[email protected]> wrote:
>
> On Wed, 3 Mar 2021 at 14:55, Alex Bennée <[email protected]> wrote:
> >
> > A number of storage technologies support a specialised hardware
> > partition designed to be resistant to replay attacks. The underlying
> > HW protocols differ but the operations are common. 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 wishes to store a replay
> > protected data, requests the storage device via RPMB layer to store
> > the data.
> >
> > A TEE device driver can claim the RPMB interface, for example, via
> > class_interface_register(). The RPMB layer provides a series of
> > operations for interacting with the device.
> >
> > * program_key - a one time operation for setting up a new device
> > * get_capacity - introspect the device capacity
> > * get_write_count - check the write counter
> > * write_blocks - write a series of blocks to the RPMB device
> > * read_blocks - read a series of blocks from the RPMB device
> >
> > The detailed operation of implementing the access is left to the TEE
> > device driver itself.
> >
> > [This is based-on Thomas Winkler's proposed API from:
> >
> > https://lore.kernel.org/linux-mmc/[email protected]/
> >
> > The principle difference is the framing details and HW specific
> > bits (JDEC vs NVME frames) are left to the lower level TEE driver to
> > worry about. The eventual userspace ioctl interface will aim to be
> > similarly generic. This is an RFC to follow up on:
> >
> > Subject: RPMB user space ABI
> > Date: Thu, 11 Feb 2021 14:07:00 +0000
> > Message-ID: <[email protected]>]
> >
> > Signed-off-by: Alex Bennée <[email protected]>
> > Cc: Tomas Winkler <[email protected]>
> > Cc: Ulf Hansson <[email protected]>
> > Cc: Linus Walleij <[email protected]>
> > Cc: Arnd Bergmann <[email protected]>
> > Cc: Ilias Apalodimas <[email protected]>
>
> Alex, I promise to have a closer look at this and provide my opinions.
>
> However, it looks like you have posted patch 1 and patch2, but the
> remainder 3, 4, 5 I can't find. Was this perhaps intentional?
>
> Moreover, I think these kinds of changes deserve a proper
> cover-letter, describing the overall goal with the series. Can you
> perhaps re-submit, so clarify things.
>
> Kind regards
> Uffe
>
> > ---
> > MAINTAINERS | 7 +
> > drivers/char/Kconfig | 2 +
> > drivers/char/Makefile | 1 +
> > drivers/char/rpmb/Kconfig | 11 +
> > drivers/char/rpmb/Makefile | 7 +
> > drivers/char/rpmb/core.c | 429 +++++++++++++++++++++++++++++++++++++
> > include/linux/rpmb.h | 163 ++++++++++++++
> > 7 files changed, 620 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 bfc1b86e3e73..076f3983526c 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -15369,6 +15369,13 @@ T: git git://linuxtv.org/media_tree.git
> > F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
> > F: drivers/media/platform/sunxi/sun8i-rotate/
> >
> > +RPMB SUBSYSTEM
> > +M: ?
> > +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 d229a2d0c017..a7834cc3e0ea 100644
> > --- a/drivers/char/Kconfig
> > +++ b/drivers/char/Kconfig
> > @@ -471,6 +471,8 @@ config ADI
> > and SSM (Silicon Secured Memory). Intended consumers of this
> > driver include crash and makedumpfile.
> >
> > +source "drivers/char/rpmb/Kconfig"
> > +
> > endmenu
> >
> > config RANDOM_TRUST_CPU
> > diff --git a/drivers/char/Makefile b/drivers/char/Makefile
> > index ffce287ef415..0eed6e21a7a7 100644
> > --- a/drivers/char/Makefile
> > +++ b/drivers/char/Makefile
> > @@ -47,3 +47,4 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
> > obj-$(CONFIG_XILLYBUS) += xillybus/
> > obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
> > obj-$(CONFIG_ADI) += adi.o
> > +obj-$(CONFIG_RPMB) += rpmb/
> > diff --git a/drivers/char/rpmb/Kconfig b/drivers/char/rpmb/Kconfig
> > new file mode 100644
> > index 000000000000..431c2823cf70
> > --- /dev/null
> > +++ b/drivers/char/rpmb/Kconfig
> > @@ -0,0 +1,11 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2015-2019, Intel Corporation.
> > +
> > +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..24d4752a9a53
> > --- /dev/null
> > +++ b/drivers/char/rpmb/Makefile
> > @@ -0,0 +1,7 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2015-2019, Intel Corporation.
> > +
> > +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..a2e21c14986a
> > --- /dev/null
> > +++ b/drivers/char/rpmb/core.c
> > @@ -0,0 +1,429 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright(c) 2015 - 2019 Intel Corporation. All rights reserved.
> > + * Copyright(c) 2021 - Linaro Ltd.
> > + */
> > +#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);
> > +
> > +/**
> > + * rpmb_program_key() - program the RPMB access key
> > + * @rdev: rpmb device
> > + * @key: key data
> > + * @keylen: length of key data
> > + *
> > + * A successful programming of the key implies it has been set by the
> > + * driver and can be used.
> > + *
> > + * Return:
> > + * * 0 on success
> > + * * -EINVAL on wrong parameters
> > + * * -EPERM key already programmed
> > + * * -EOPNOTSUPP if device doesn't support the requested operation
> > + * * < 0 if the operation fails
> > + */
> > +int rpmb_program_key(struct rpmb_dev *rdev, key_serial_t keyid)
> > +{
> > + int err;
> > +
> > + if (!rdev || !keyid)
> > + return -EINVAL;
> > +
> > + mutex_lock(&rdev->lock);
> > + err = -EOPNOTSUPP;
> > + if (rdev->ops && rdev->ops->program_key) {
> > + err = rdev->ops->program_key(rdev->dev.parent, rdev->target,
> > + keyid);
> > + }
> > + mutex_unlock(&rdev->lock);
> > +
> > + return err;
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_program_key);
> > +
> > +/**
> > + * rpmb_get_capacity() - returns the capacity of the rpmb device
> > + * @rdev: rpmb device
> > + *
> > + * Return:
> > + * * capacity of the device in units of 128K, on success
> > + * * -EINVAL on wrong parameters
> > + * * -EOPNOTSUPP if device doesn't support the requested operation
> > + * * < 0 if the operation fails
> > + */
> > +int rpmb_get_capacity(struct rpmb_dev *rdev)
> > +{
> > + int err;
> > +
> > + if (!rdev)
> > + return -EINVAL;
> > +
> > + mutex_lock(&rdev->lock);
> > + err = -EOPNOTSUPP;
> > + if (rdev->ops && rdev->ops->get_capacity)
> > + err = rdev->ops->get_capacity(rdev->dev.parent, rdev->target);
> > + mutex_unlock(&rdev->lock);
> > +
> > + return err;
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_get_capacity);
> > +
> > +/**
> > + * rpmb_get_write_count() - returns the write counter of the rpmb device
> > + * @rdev: rpmb device
> > + *
> > + * Return:
> > + * * counter
> > + * * -EINVAL on wrong parameters
> > + * * -EOPNOTSUPP if device doesn't support the requested operation
> > + * * < 0 if the operation fails
> > + */
> > +int rpmb_get_write_count(struct rpmb_dev *rdev)
> > +{
> > + int err;
> > +
> > + if (!rdev)
> > + return -EINVAL;
> > +
> > + mutex_lock(&rdev->lock);
> > + err = -EOPNOTSUPP;
> > + if (rdev->ops && rdev->ops->get_write_count)
> > + err = rdev->ops->get_write_count(rdev->dev.parent, rdev->target);
> > + mutex_unlock(&rdev->lock);
> > +
> > + return err;
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_get_write_count);
> > +
> > +/**
> > + * rpmb_write_blocks() - write data to RPMB device
> > + * @rdev: rpmb device
> > + * @addr: block address (index of first block - 256B blocks)
> > + * @count: number of 256B blosks
> > + * @data: pointer to data to program
> > + *
> > + * Write a series of blocks to the RPMB device.
> > + *
> > + * Return:
> > + * * 0 on success
> > + * * -EINVAL on wrong parameters
> > + * * -EACCESS no key set
> > + * * -EOPNOTSUPP if device doesn't support the requested operation
> > + * * < 0 if the operation fails
> > + */
> > +int rpmb_write_blocks(struct rpmb_dev *rdev, key_serial_t keyid, int addr,
> > + int count, u8 *data)
> > +{
> > + int err;
> > +
> > + if (!rdev || !count || !data)
> > + return -EINVAL;
> > +
> > + mutex_lock(&rdev->lock);
> > + err = -EOPNOTSUPP;
> > + if (rdev->ops && rdev->ops->write_blocks) {
> > + err = rdev->ops->write_blocks(rdev->dev.parent, rdev->target, keyid,
> > + addr, count, data);
> > + }
> > + mutex_unlock(&rdev->lock);
> > +
> > + return err;
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_write_blocks);
> > +
> > +/**
> > + * rpmb_read_blocks() - read data from RPMB device
> > + * @rdev: rpmb device
> > + * @addr: block address (index of first block - 256B blocks)
> > + * @count: number of 256B blocks
> > + * @data: pointer to data to read
> > + *
> > + * Read a series of one or more blocks from the RPMB device.
> > + *
> > + * Return:
> > + * * 0 on success
> > + * * -EINVAL on wrong parameters
> > + * * -EACCESS no key set
> > + * * -EOPNOTSUPP if device doesn't support the requested operation
> > + * * < 0 if the operation fails
> > + */
> > +int rpmb_read_blocks(struct rpmb_dev *rdev, int addr, int count, u8 *data)
> > +{
> > + int err;
> > +
> > + if (!rdev || !count || !data)
> > + return -EINVAL;
> > +
> > + mutex_lock(&rdev->lock);
> > + err = -EOPNOTSUPP;
> > + if (rdev->ops && rdev->ops->read_blocks) {
> > + err = rdev->ops->read_blocks(rdev->dev.parent, rdev->target,
> > + addr, count, data);
> > + }
> > + mutex_unlock(&rdev->lock);
> > +
> > + return err;
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_read_blocks);
> > +
> > +
> > +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
> > + */
> > +static
> > +struct rpmb_dev *rpmb_dev_find_device(const 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;
> > +}
> > +
> > +struct device_with_target {
> > + const struct device *dev;
> > + u8 target;
> > +};
> > +
> > +static int match_by_parent(struct device *dev, const void *data)
> > +{
> > + const struct device_with_target *d = data;
> > + struct rpmb_dev *rdev = to_rpmb_dev(dev);
> > +
> > + return (d->dev && dev->parent == d->dev && rdev->target == d->target);
> > +}
> > +
> > +/**
> > + * rpmb_dev_find_by_device() - retrieve rpmb device from the parent device
> > + * @parent: parent device of the rpmb device
> > + * @target: RPMB target/region within the physical 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, u8 target)
> > +{
> > + struct device_with_target t;
> > +
> > + if (!parent)
> > + return NULL;
> > +
> > + t.dev = parent;
> > + t.target = target;
> > +
> > + return rpmb_dev_find_device(&t, match_by_parent);
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_dev_find_by_device);
> > +
> > +/**
> > + * rpmb_dev_unregister() - unregister RPMB partition from the RPMB subsystem
> > + * @rdev: the rpmb device to unregister
> > + * Return:
> > + * * 0 on success
> > + * * -EINVAL on wrong parameters
> > + */
> > +int rpmb_dev_unregister(struct rpmb_dev *rdev)
> > +{
> > + if (!rdev)
> > + return -EINVAL;
> > +
> > + 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_unregister_by_device() - unregister RPMB partition
> > + * from the RPMB subsystem
> > + * @dev: the parent device of the rpmb device
> > + * @target: RPMB target/region within the physical device
> > + * Return:
> > + * * 0 on success
> > + * * -EINVAL on wrong parameters
> > + * * -ENODEV if a device cannot be find.
> > + */
> > +int rpmb_dev_unregister_by_device(struct device *dev, u8 target)
> > +{
> > + struct rpmb_dev *rdev;
> > +
> > + if (!dev)
> > + return -EINVAL;
> > +
> > + rdev = rpmb_dev_find_by_device(dev, target);
> > + if (!rdev) {
> > + dev_warn(dev, "no disk found %s\n", dev_name(dev->parent));
> > + return -ENODEV;
> > + }
> > +
> > + rpmb_dev_put(rdev);
> > +
> > + return rpmb_dev_unregister(rdev);
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_dev_unregister_by_device);
> > +
> > +/**
> > + * rpmb_dev_get_drvdata() - driver data getter
> > + * @rdev: rpmb device
> > + *
> > + * Return: driver private data
> > + */
> > +void *rpmb_dev_get_drvdata(const struct rpmb_dev *rdev)
> > +{
> > + return dev_get_drvdata(&rdev->dev);
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_dev_get_drvdata);
> > +
> > +/**
> > + * rpmb_dev_set_drvdata() - driver data setter
> > + * @rdev: rpmb device
> > + * @data: data to store
> > + */
> > +void rpmb_dev_set_drvdata(struct rpmb_dev *rdev, void *data)
> > +{
> > + dev_set_drvdata(&rdev->dev, data);
> > +}
> > +EXPORT_SYMBOL_GPL(rpmb_dev_set_drvdata);
> > +
> > +/**
> > + * rpmb_dev_register - register RPMB partition with the RPMB subsystem
> > + * @dev: storage device of the rpmb device
> > + * @target: RPMB target/region within the physical device
> > + * @ops: device specific operations
> > + *
> > + * Return: a pointer to rpmb device
> > + */
> > +struct rpmb_dev *rpmb_dev_register(struct device *dev, u8 target,
> > + const struct rpmb_ops *ops)
> > +{
> > + struct rpmb_dev *rdev;
> > + int id;
> > + int ret;
> > +
> > + if (!dev || !ops)
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!ops->program_key)
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!ops->get_capacity)
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!ops->get_write_count)
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!ops->write_blocks)
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (!ops->read_blocks)
> > + return ERR_PTR(-EINVAL);
> > +
> > + if (ops->type == RPMB_TYPE_ANY || ops->type > RPMB_TYPE_MAX)
> > + return ERR_PTR(-EINVAL);
> > +
> > + rdev = kzalloc(sizeof(*rdev), 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;
> > + rdev->target = target;
> > +
> > + 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 device\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 v2");
> > diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h
> > new file mode 100644
> > index 000000000000..718ba7c91ecd
> > --- /dev/null
> > +++ b/include/linux/rpmb.h
> > @@ -0,0 +1,163 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
> > +/*
> > + * Copyright (C) 2015-2019 Intel Corp. All rights reserved
> > + * Copyright (C) 2021 Linaro Ltd
> > + */
> > +#ifndef __RPMB_H__
> > +#define __RPMB_H__
> > +
> > +#include <linux/types.h>
> > +#include <linux/device.h>
> > +#include <linux/kref.h>
> > +#include <linux/key.h>
> > +
> > +/**
> > + * struct rpmb_ops - RPMB ops to be implemented by underlying block device
> > + *
> > + * @program_key : program device key (once only op).
> > + * @get_capacity : rpmb size in 128K units in for region/target.
> > + * @get_write_count: return the device write counter
> > + * @write_blocks : write blocks to RPMB device
> > + * @read_blocks : read blocks from RPMB device
> > + * @block_size : block size in half sectors (1 == 256B)
> > + * @wr_cnt_max : maximal number of blocks that can be
> > + * written in one access.
> > + * @rd_cnt_max : maximal number of blocks that can be
> > + * read in one access.
> > + * @auth_method : rpmb_auth_method
> > + * @dev_id : unique device identifier
> > + * @dev_id_len : unique device identifier length
> > + */
> > +struct rpmb_ops {
> > + int (*program_key)(struct device *dev, u8 target, key_serial_t keyid);
> > + int (*get_capacity)(struct device *dev, u8 target);
> > + int (*get_write_count)(struct device *dev, u8 target);
> > + int (*write_blocks)(struct device *dev, u8 target, key_serial_t keyid,
> > + int addr, int count, u8 *data);
> > + int (*read_blocks)(struct device *dev, u8 target,
> > + int addr, int count, u8 *data);
> > + u16 block_size;
> > + u16 wr_cnt_max;
> > + u16 rd_cnt_max;
> > + u16 auth_method;
> > + const u8 *dev_id;
> > + size_t dev_id_len;
> > +};
> > +
> > +/**
> > + * struct rpmb_dev - device which can support RPMB partition
> > + *
> > + * @lock : the device lock
> > + * @dev : device
> > + * @id : device id
> > + * @target : RPMB target/region within the physical device
> > + * @ops : operation exported by block layer
> > + */
> > +struct rpmb_dev {
> > + struct mutex lock; /* device serialization lock */
> > + struct device dev;
> > + int id;
> > + u8 target;
> > + 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, u8 target);
> > +struct rpmb_dev *rpmb_dev_get_by_type(u32 type);
> > +struct rpmb_dev *rpmb_dev_register(struct device *dev, u8 target,
> > + const struct rpmb_ops *ops);
> > +void *rpmb_dev_get_drvdata(const struct rpmb_dev *rdev);
> > +void rpmb_dev_set_drvdata(struct rpmb_dev *rdev, void *data);
> > +int rpmb_dev_unregister(struct rpmb_dev *rdev);
> > +int rpmb_dev_unregister_by_device(struct device *dev, u8 target);
> > +int rpmb_program_key(struct rpmb_dev *rdev, key_serial_t keyid);
> > +int rpmb_get_capacity(struct rpmb_dev *rdev);
> > +int rpmb_get_write_count(struct rpmb_dev *rdev);
> > +int rpmb_write_blocks(struct rpmb_dev *rdev, key_serial_t keyid,
> > + int addr, int count, u8 *data);
> > +int rpmb_read_blocks(struct rpmb_dev *rdev, int addr, int count, u8 *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,
> > + u8 target)
> > +{
> > + return NULL;
> > +}
> > +
> > +static inline
> > +struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type)
> > +{
> > + return NULL;
> > +}
> > +
> > +static inline void *rpmb_dev_get_drvdata(const struct rpmb_dev *rdev)
> > +{
> > + return NULL;
> > +}
> > +
> > +static inline void rpmb_dev_set_drvdata(struct rpmb_dev *rdev, void *data)
> > +{
> > +}
> > +
> > +static inline struct rpmb_dev *
> > +rpmb_dev_register(struct device *dev, u8 target, const struct rpmb_ops *ops)
> > +{
> > + return NULL;
> > +}
> > +
> > +static inline int rpmb_dev_unregister(struct rpmb_dev *dev)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline int rpmb_dev_unregister_by_device(struct device *dev, u8 target)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline int rpmb_program_key(struct rpmb_dev *rdev, key_serial_t keyid)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline rpmb_set_key(struct rpmb_dev *rdev, u8 *key, int keylen);
> > +{
> > + return 0;
> > +}
> > +
> > +static inline int rpmb_get_capacity(struct rpmb_dev *rdev)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline int rpmb_get_write_count(struct rpmb_dev *rdev)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline int rpmb_write_blocks(struct rpmb_dev *rdev, int addr, int count,
> > + u8 *data)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline int rpmb_read_blocks(struct rpmb_dev *rdev, int addr, int count,
> > + u8 *data)
> > +{
> > + return 0;
> > +}
> > +
> > +#endif /* CONFIG_RPMB */
> > +
> > +#endif /* __RPMB_H__ */
> > --
> > 2.20.1
> >
--
Alex Bennée
KVM/QEMU Hacker for Linaro