blob: 61ad8f1ae19a9581ff0a40cbb4d59bd3174f9662 [file] [log] [blame]
/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
*/
#include <debug.h>
#include <rpmb.h>
#include <rpmb_listener.h>
#include <qseecom_lk_api.h>
#include <stdlib.h>
#define RPMB_LSTNR_VERSION_2 0x2
typedef enum
{
TZ_CM_CMD_RPMB_INIT = 0x101, //257
TZ_CM_CMD_RPMB_READ, //258
TZ_CM_CMD_RPMB_WRITE, //259
TZ_CM_CMD_RPMB_PARTITION, //260
} tz_rpmb_cmd_type;
struct tz_device_init_req
{
uint32_t cmd_id;
uint32_t version;
}__PACKED;
/* RPMB Init response message */
struct tz_device_init_resp
{
uint32_t cmd_id; /* Command ID */
uint32_t version; /* Messaging version from RPMB listener */
uint32_t status; /* RPMB init status */
uint32_t num_sectors; /* Size of RPMB (in sectors) */
uint32_t rel_wr_count; /* Reliable write count for the RPMB */
uint32_t dev_type; /* Storage device type (like eMMC or UFS) */
uint32_t reserved1; /* Reserved 1 */
uint32_t reserved2; /* Reserved 2 */
uint32_t reserved3; /* Reserved 3 */
uint32_t reserved4; /* Reserved 4 */
}__PACKED;
struct tz_rpmb_rw_req
{
uint32_t cmd_id;
uint32_t num_sectors;
uint32_t req_buff_len;
uint32_t req_buff_offset;
uint32_t version;
uint32_t rel_wr_count;
}__PACKED;
struct tz_rpmb_rw_resp
{
uint32_t cmd_id;
int32_t status;
uint32_t res_buff_len;
uint32_t res_buff_offset;
uint32_t version;
}__PACKED;
typedef int (*ListenerCallback)(void*, uint32_t);
static void handle_init_request(void *buf, uint32_t sz)
{
struct tz_device_init_req *init_req_p = NULL;
struct tz_device_init_resp *init_resp = (struct tz_device_init_resp*) buf;
struct rpmb_init_info *rpmb_info = NULL;
init_req_p = (struct tz_device_init_req *) buf;
rpmb_info = rpmb_get_init_info();
if (rpmb_info)
init_resp->status = 0;
init_resp->cmd_id = init_req_p->cmd_id;
init_resp->version = RPMB_LSTNR_VERSION_2;
init_resp->num_sectors = rpmb_info->size;
init_resp->rel_wr_count = rpmb_info->rel_wr_count;
init_resp->dev_type = rpmb_info->dev_type;
}
static void handle_rw_request(void *buf, uint32_t sz)
{
struct tz_rpmb_rw_req *req_p = (struct tz_rpmb_rw_req *)buf;
struct tz_rpmb_rw_resp *resp_p = NULL;
uint32_t *req_buf = buf + req_p->req_buff_offset;
uint32_t *resp_buf = buf + sizeof(struct tz_rpmb_rw_resp);
resp_p = (struct tz_rpmb_rw_resp *) buf;
switch (req_p->cmd_id)
{
case TZ_CM_CMD_RPMB_READ:
#if DEBUG_RPMB
dprintf(INFO, "Read Request received\n");
dprintf(INFO, "READ: RPMB_REL_RW_COUNT 0x%x\n", req_p->rel_wr_count);
#endif
resp_p->status = rpmb_read(req_buf, req_p->num_sectors, resp_buf, &resp_p->res_buff_len);
break;
case TZ_CM_CMD_RPMB_WRITE:
#if DEBUG_RPMB
dprintf(INFO, "Write Request received\n");
dprintf(INFO, "WRITE: RPMB_REL_RW_COUNT 0x%x\n", req_p->rel_wr_count);
#endif
resp_p->status = rpmb_write(req_buf, req_p->num_sectors, req_p->rel_wr_count, resp_buf, &resp_p->res_buff_len);
break;
default:
dprintf(CRITICAL, "Unsupported request command request: %u\n", req_p->cmd_id);
ASSERT(0);
};
resp_p->res_buff_offset = sizeof(struct tz_rpmb_rw_resp);
resp_p->cmd_id = req_p->cmd_id;
}
int rpmb_cmd_handler(void *buf, uint32_t sz)
{
int ret = 0;
uint32_t cmd_id;
ASSERT(buf);
cmd_id = (uint32_t) *((uint32_t *)buf);
switch(cmd_id)
{
case TZ_CM_CMD_RPMB_READ:
case TZ_CM_CMD_RPMB_WRITE:
handle_rw_request(buf, sz);
break;
case TZ_CM_CMD_RPMB_INIT:
#if DEBUG_RPMB
dprintf(INFO, "RPMB init received\n");
#endif
handle_init_request(buf, sz);
break;
case TZ_CM_CMD_RPMB_PARTITION:
#if DEBUG_RPMB
dprintf(INFO, "Partition init received\n");
#endif
ret = -1;
break;
default:
/* Does qseecom need a response here? */
dprintf(CRITICAL, "Unsupported Request from qseecom: %d\n", cmd_id);
ASSERT(0);
};
return ret;
}
int rpmb_listener_start()
{
int ret;
struct qseecom_listener_services rpmb_listener;
rpmb_listener.service_name = "RPMB system services";
rpmb_listener.id = RPMB_LSTNR_ID;
rpmb_listener.sb_size = 25 * 1024;
rpmb_listener.service_cmd_handler = rpmb_cmd_handler;
ret = qseecom_register_listener(&rpmb_listener);
if (ret < 0)
dprintf(CRITICAL, "Failed to register rpmb listener\n");
return ret;
}
int rpmb_listener_stop(int id)
{
int ret;
ret = qseecom_deregister_listener(id);
if (ret < 0)
dprintf(CRITICAL, "Failed to unregister rpmb listener\n");
return ret;
}