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