On Wed, 3 Mar 2021 at 14:55, Alex Bennée <alex.bennee@xxxxxxxxxx> 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/1478548394-8184-2-git-send-email-tomas.winkler@xxxxxxxxx/ > > 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: <87mtwashi4.fsf@xxxxxxxxxx>] > > Signed-off-by: Alex Bennée <alex.bennee@xxxxxxxxxx> > Cc: Tomas Winkler <tomas.winkler@xxxxxxxxx> > Cc: Ulf Hansson <ulf.hansson@xxxxxxxxxx> > Cc: Linus Walleij <linus.walleij@xxxxxxxxxx> > Cc: Arnd Bergmann <arnd.bergmann@xxxxxxxxxx> > Cc: Ilias Apalodimas <ilias.apalodimas@xxxxxxxxxx> 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: linux-kernel@xxxxxxxxxxxxxxx > +S: Supported > +F: drivers/char/rpmb/* > +F: include/linux/rpmb.h > + > RTL2830 MEDIA DRIVER > M: Antti Palosaari <crope@xxxxxx> > L: linux-media@xxxxxxxxxxxxxxx > 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 >