/*
 * Copyright (C) 2018-2022 Intel Corporation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer
 *    in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Contact Information: weideng <wei.a.deng@intel.com>
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
#ifndef __RPMB_H__
#define __RPMB_H__

#include <linux/types.h>


#define RPMB_PHY_MODE       0
#define RPMB_SIM_MODE       1
#define RPMB_BLOCK_SIZE     256
#define RPMB_FRAME_SIZE     512
#define RPMB_PHY_PATH_NAME  "/dev/rpmbmux"
#define RPMB_SIM_PATH_NAME  "/data/rpmbfile"
#define SEQ_CMD_MAX         3	/*support up to 3 cmds*/

#define RPMB_F_WRITE        (1UL << 0)
#define RPMB_F_REL_WRITE    (1UL << 1)

enum rpmb_request {
    RPMB_REQ_PROGRAM_KEY                = 0x0001,
    RPMB_REQ_GET_COUNTER                = 0x0002,
    RPMB_REQ_DATA_WRITE                 = 0x0003,
    RPMB_REQ_DATA_READ                  = 0x0004,
    RPMB_REQ_RESULT_READ                = 0x0005,
};

enum rpmb_response {
    RPMB_RESP_PROGRAM_KEY               = 0x0100,
    RPMB_RESP_GET_COUNTER               = 0x0200,
    RPMB_RESP_DATA_WRITE                = 0x0300,
    RPMB_RESP_DATA_READ                 = 0x0400,
};

enum rpmb_result {
    RPMB_RES_OK                         = 0x0000,
    RPMB_RES_GENERAL_FAILURE            = 0x0001,
    RPMB_RES_AUTH_FAILURE               = 0x0002,
    RPMB_RES_COUNT_FAILURE              = 0x0003,
    RPMB_RES_ADDR_FAILURE               = 0x0004,
    RPMB_RES_WRITE_FAILURE              = 0x0005,
    RPMB_RES_READ_FAILURE               = 0x0006,
    RPMB_RES_NO_AUTH_KEY                = 0x0007,

    RPMB_RES_WRITE_COUNTER_EXPIRED      = 0x0080,
};

/**
 * 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;
};

/**
 * 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_frame - rpmb frame as defined by specs
 *
 * @stuff        : stuff bytes
 * @key_mac      : The authentication key or the message authentication
 *                 code (MAC) depending on the request/response type.
 *                 The MAC will be delivered in the last (or the only)
 *                 block of data.
 * @data         : Data to be written or read by signed access.
 * @nonce        : Random number generated by the host for the requests
 *                 and copied to the response by the RPMB engine.
 * @write_counter: Counter value for the total amount of the successful
 *                 authenticated data write requests made by the host.
 * @addr         : Address of the data to be programmed to or read
 *                 from the RPMB. Address is the serial number of
 *                 the accessed block (half sector 256B).
 * @block_count  : Number of blocks (half sectors, 256B) requested to be
 *                 read/programmed.
 * @result       : Includes information about the status of the write counter
 *                 (valid, expired) and result of the access made to the RPMB.
 * @req_resp     : Defines the type of request and response to/from the memory.
 */
struct rpmb_frame {
	__u8   stuff[196];
	__u8   key_mac[32];
	__u8   data[256];
	__u8   nonce[16];
	__be32 write_counter;
	__be16 addr;
	__be16 block_count;
	__be16 result;
	__be16 req_resp;
} __attribute__((packed));

/**
 * struct rpmb_cmd - rpmb access command
 *
 * @flags: command flags
 *      0 - read command
 *      1 - write commnad RPMB_F_WRITE
 *      2 - reliable write RPMB_F_REL_WRITE
 * @nframes: number of rpmb frames in the command
 * @frames_ptr:  a pointer to the list of rpmb frames
 */
struct rpmb_ioc_cmd {
	__u32 flags;
	__u32 nframes;
	__aligned_u64 frames_ptr;
};

/**
 * struct rpmb_ioc_req_cmd - rpmb operation request command
 *
 * @req_type: request type:  must match the in frame req_resp
 *            program key
 *            get write counter
 *            write data
 *            read data
 * @icmd: input command
 * @ocmd: output/result command
 */
struct rpmb_ioc_req_cmd {
	__u64 req_type;
	struct rpmb_ioc_cmd icmd;
	struct rpmb_ioc_cmd ocmd;
};

/**
 * struct rpmb_ioc_seq_cmd - rpmb command sequence
 *
 * @num_of_cmds: number of commands
 * @cmds: list of rpmb commands
 */
struct rpmb_ioc_seq_cmd {
	__u64 num_of_cmds;
	struct rpmb_ioc_cmd cmds[0];
};

struct rpmb_ioc_seq_data {
	struct rpmb_ioc_seq_cmd h;
	struct rpmb_ioc_cmd cmd[SEQ_CMD_MAX + 1];
};

int
rpmb_get_counter(__u8 mode, __u8 *key, __u32 *counter, __u16 *result);

#define RPMB_IOC_REQ_CMD _IOWR(0xB5, 80, struct rpmb_ioc_req_cmd)
#define RPMB_IOC_SEQ_CMD _IOWR(0xB5, 82, struct rpmb_ioc_seq_cmd)

__u16 rpmb_get_blocks(void);

#endif /* __RPMB_H__ */
