/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2021 MediaTek Inc. */ #ifndef __RPMB_H__ #define __RPMB_H__ #include #include #include /** * struct rpmb_frame - rpmb frame as defined by specs * * @stuff : stuff bytes * @key_mac : The authentication key or the message authentication * code (MAC) depending on the request/response type. * The MAC will be delivered in the last (or the only) * block of data. * @data : Data to be written or read by signed access. * @nonce : Random number generated by the host for the requests * and copied to the response by the RPMB engine. * @write_counter: Counter value for the total amount of the successful * authenticated data write requests made by the host. * @addr : Address of the data to be programmed to or read * from the RPMB. Address is the serial number of * the accessed block (half sector 256B). * @block_count : Number of blocks (half sectors, 256B) requested to be * read/programmed. * @result : Includes information about the status of the write counter * (valid, expired) and result of the access made to the RPMB. * @req_resp : Defines the type of request and response to/from the memory. */ struct rpmb_frame { u8 stuff[196]; u8 key_mac[32]; u8 data[256]; u8 nonce[16]; __be32 write_counter; __be16 addr; __be16 block_count; __be16 result; __be16 req_resp; } __packed; #define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */ #define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */ #define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */ #define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */ #define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */ #define RPMB_REQ2RESP(_OP) ((_OP) << 8) #define RPMB_RESP2REQ(_OP) ((_OP) >> 8) /** * enum rpmb_op_result - rpmb operation results * * @RPMB_ERR_OK : operation successful * @RPMB_ERR_GENERAL : general failure * @RPMB_ERR_AUTH : mac doesn't match or ac calculation failure * @RPMB_ERR_COUNTER : counter doesn't match or counter increment failure * @RPMB_ERR_ADDRESS : address out of range or wrong address alignment * @RPMB_ERR_WRITE : data, counter, or result write failure * @RPMB_ERR_READ : data, counter, or result read failure * @RPMB_ERR_NO_KEY : authentication key not yet programmed * * @RPMB_ERR_COUNTER_EXPIRED: counter expired */ enum rpmb_op_result { RPMB_ERR_OK = 0x0000, RPMB_ERR_GENERAL = 0x0001, RPMB_ERR_AUTH = 0x0002, RPMB_ERR_COUNTER = 0x0003, RPMB_ERR_ADDRESS = 0x0004, RPMB_ERR_WRITE = 0x0005, RPMB_ERR_READ = 0x0006, RPMB_ERR_NO_KEY = 0x0007, RPMB_ERR_COUNTER_EXPIRED = 0x0080 }; /** * enum rpmb_type - type of underlaying storage technology * * @RPMB_TYPE_ANY : any type used for search only * @RPMB_TYPE_EMMC : emmc (JESD84-B50.1) * @RPMB_TYPE_UFS : UFS (JESD220) * @RPMB_TYPE_SIM : Simulation Device type * @RPMB_TYPE_MAX : upper sentinel */ enum rpmb_type { RPMB_TYPE_ANY = 0, RPMB_TYPE_EMMC, RPMB_TYPE_UFS, RPMB_TYPE_SIM, RPMB_TYPE_MAX = RPMB_TYPE_SIM }; extern struct class rpmb_class; #define RPMB_F_WRITE BIT(0) #define RPMB_F_REL_WRITE BIT(1) /** * 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 frames in the command * @frames: list of rpmb frames */ struct rpmb_cmd { u32 flags; u32 nframes; struct rpmb_frame *frames __aligned(8); }; /** * struct rpmb_data - rpmb data be transmitted in RPMB request * * @req_type: request type (program key, read, write, write counter) * @icmd: list of input frames * @ocmd: list of result frames */ struct rpmb_data { u16 req_type; struct rpmb_cmd icmd; struct rpmb_cmd ocmd; }; /** * struct rpmb_ops - RPMB ops to be implemented by underlaying block device * * @cmd_seq : send RPMB command sequence to the RPBM partition * backed by the disk * @type : block device type * @dev_id : unique device identifier * @dev_id_len : unique device identifier length * @reliable_wr_cnt: number of sectors that can be written in one access */ struct rpmb_ops { int (*cmd_seq)(struct device *dev, struct rpmb_cmd *cmds, u32 ncmds, u8 region); enum rpmb_type type; const u8 *dev_id; size_t dev_id_len; u16 reliable_wr_cnt; }; /** * struct rpmb_dev - device which can support RPMB partition * * @lock : the device lock * @dev : device * @id : device id * @ops : operation exported by block layer */ struct rpmb_dev { struct mutex lock; /* device serialization lock */ struct device dev; int id; const struct rpmb_ops *ops; }; #define to_rpmb_dev(x) container_of((x), struct rpmb_dev, dev) #if IS_ENABLED(CONFIG_RPMB) struct rpmb_dev *rpmb_dev_get(struct rpmb_dev *rdev); void rpmb_dev_put(struct rpmb_dev *rdev); struct rpmb_dev *rpmb_dev_find_by_device(struct device *parent); struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type); struct rpmb_dev *rpmb_dev_register(struct device *dev, const struct rpmb_ops *ops); struct rpmb_dev *rpmb_dev_find_device(void *data, int (*match)(struct device *dev, const void *data)); int rpmb_dev_unregister(struct device *dev); int rpmb_cmd_seq(struct rpmb_dev *rdev, struct rpmb_cmd *cmds, u32 ncmds, u8 region); int rpmb_cmd_req(struct rpmb_dev *rdev, struct rpmb_data *data, u8 region); #else static inline struct rpmb_dev *rpmb_dev_get(struct rpmb_dev *rdev) { return NULL; } static inline void rpmb_dev_put(struct rpmb_dev *rdev) { } static inline struct rpmb_dev *rpmb_dev_find_by_device(struct device *parent) { return NULL; } static inline struct rpmb_dev *rpmb_dev_get_by_type(enum rpmb_type type) { return NULL; } static inline struct rpmb_dev * rpmb_dev_register(struct device *dev, const struct rpmb_ops *ops) { return NULL; } static inline int rpmb_dev_unregister(struct device *dev) { return 0; } static inline int rpmb_cmd_seq(struct rpmb_dev *rdev, struct rpmb_cmd *cmds, u32 ncmds) { return 0; } static inline int rpmb_cmd_req(struct rpmb_dev *rdev, struct rpmb_data *data, u8 region) { return 0; } #endif /* CONFIG_RPMB */ #endif /* __RPMB_H__ */