platform: msm_shared: Add support for rpmb
Add support for rpmb listener, rpmb driver for emmc & ufs.
Change-Id: Iacfb2bd34d6ddc309f2c7f5422576fa253322f82
diff --git a/platform/msm_shared/include/rpmb.h b/platform/msm_shared/include/rpmb.h
index 8bbd985..6cd7ecd 100644
--- a/platform/msm_shared/include/rpmb.h
+++ b/platform/msm_shared/include/rpmb.h
@@ -26,6 +26,49 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef _RPMB_H_
+#define _RPMB_H_
+
+#include <qseecom_lk_api.h>
+#include <mmc_sdhci.h>
+#include <ufs.h>
+#include <debug.h>
+
+#define RPMB_SECTOR_SIZE 256
+#define RPMB_LSTNR_ID 0x2000
+#define RPMB_BLK_SIZE 512
+#define RPMB_FRAME_SIZE 512
+#define RPMB_MIN_BLK_CNT 1
+#define RPMB_MIN_BLK_SZ 512
+
+enum app_commands
+{
+ CLIENT_CMD_READ_LK_DEVICE_STATE = 0,
+ CLIENT_CMD_LK_END_MILESTONE,
+ CLIENT_CMD_GET_VERSION,
+ CLIENT_CMD_WRITE_LK_DEVICE_STATE,
+};
+
+struct send_cmd_req
+{
+ uint32_t cmd_id;
+ uint32_t data;
+ uint32_t len;
+}__PACKED;
+
+struct send_cmd_rsp
+{
+ uint32_t cmd_id;
+ uint32_t data;
+ int32_t status;
+}__PACKED;
+
+enum device_type
+{
+ EMMC_RPMB = 3,
+ UFS_RPMB = 9,
+};
+
/* RPMB request and response types */
enum rpmb_rr_type {
KEY_PROVISION = 0x1,
@@ -62,9 +105,61 @@
uint8_t keyMAC[32];
uint8_t data[256];
uint8_t nonce[16];
- uint32_t writecounter;
- uint16_t address;
- uint16_t blockcount;
+ uint8_t writecounter[4];
+ uint8_t address[2];
+ uint8_t blockcount[2];
uint8_t result[2];
- uint16_t requestresponse;
+ uint8_t requestresponse[2];
};
+
+struct rpmb_init_info
+{
+ uint32_t size;
+ uint32_t rel_wr_count;
+ uint32_t dev_type;
+};
+
+/* dump a given RPMB frame */
+static inline void dump_rpmb_frame(uint8_t *frame, const char *frame_type)
+{
+ int i;
+ char buf[512] = {0};
+ char *p = buf;
+
+ printf("Printing %s frame (in hex)\n", frame_type);
+ printf("________0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F__0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F\n");
+ for (i = 0; i < 512; i++) {
+ if (!(i % 32)) {
+ snprintf(p, 8, "| %2d | ", (i + 1) / 32);
+ p += 7;
+ }
+ snprintf(p, 4, "%.2x ", frame[i]);
+ p += 3;
+ if (((i + 1) % 32) == 0) {
+ printf("%s\n", buf);
+ p = buf;
+ }
+ }
+ printf("________F__E__D__C__B__A__9__8__7__6__5__4__3__2__1__0__F__E__D__C__B__A__9__8__7__6__5__4__3__2__1__0\n");
+}
+
+int read_device_info_rpmb(void *info, uint32_t sz);
+int write_device_info_rpmb(void *info, uint32_t sz);
+
+/* Function Prototypes */
+int rpmb_write_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_read_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_read_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+
+/* APIs exposed to applications */
+int rpmb_init();
+int rpmb_uninit();
+int rpmb_write(uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_read(uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+struct rpmb_init_info *rpmb_get_init_info();
+int rpmb_get_app_handle();
+bool is_sec_app_loaded();
+int load_sec_app();
+int unload_sec_app();
+#endif
diff --git a/platform/msm_shared/include/rpmb_listener.h b/platform/msm_shared/include/rpmb_listener.h
new file mode 100644
index 0000000..a3bb3e5
--- /dev/null
+++ b/platform/msm_shared/include/rpmb_listener.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2015, 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 <qseecom_lk_api.h>
+#include <mmc_sdhci.h>
+#include <ufs.h>
+
+#define RPMB_LSTNR_ID 0x2000
+
+int rpmb_listener_start();
+int rpmb_listener_stop();
diff --git a/platform/msm_shared/rpmb/rpmb.c b/platform/msm_shared/rpmb/rpmb.c
new file mode 100644
index 0000000..de67c46
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2013-2015, 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 <platform.h>
+#include <rpmb.h>
+#include <rpmb_listener.h>
+#include <mmc_sdhci.h>
+#include <boot_device.h>
+#include <debug.h>
+#include <target.h>
+
+static bool lksec_app_loaded;
+
+static void *dev;
+static int app_handle;
+struct rpmb_init_info info;
+
+int rpmb_init()
+{
+ int ret = 0;
+
+ dev = target_mmc_device();
+
+ /* 1. Initialize storage specific data */
+ if (platform_boot_dev_isemmc())
+ {
+ struct mmc_device *mmc_dev = (struct mmc_device *) dev;
+ info.size = mmc_dev->card.rpmb_size / RPMB_MIN_BLK_SZ;
+ info.rel_wr_count = mmc_dev->card.rel_wr_count;
+ info.dev_type = EMMC_RPMB;
+ }
+ else
+ {
+ struct ufs_dev *ufs_dev = (struct ufs_dev *) dev;
+ ufs_rpmb_init(ufs_dev);
+ info.size = ufs_dev->rpmb_num_blocks;
+ info.rel_wr_count = ufs_dev->rpmb_rw_size;
+ info.dev_type = UFS_RPMB;
+ }
+
+ /* Initialize Qseecom */
+ ret = qseecom_init();
+
+ if (ret < 0)
+ {
+ dprintf(CRITICAL, "Failed to initialize qseecom, error: %d\n", ret);
+ goto err;
+ }
+
+ /* Register & start the listener */
+ ret = rpmb_listener_start();
+ if (ret < 0)
+ {
+ dprintf(CRITICAL, "Error registering the handler\n");
+ goto err;
+ }
+
+ /* Start Qseecom */
+ ret = qseecom_tz_init();
+
+ if (ret < 0)
+ {
+ dprintf(CRITICAL, "Failed to start qseecom, error: %d\n", ret);
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+struct rpmb_init_info *rpmb_get_init_info()
+{
+ return &info;
+}
+
+int rpmb_read(uint32_t *req, uint32_t req_len, uint32_t *resp, uint32_t *resp_len)
+{
+ if (platform_boot_dev_isemmc())
+ return rpmb_read_emmc(dev, req, req_len, resp, resp_len);
+ else
+ return rpmb_read_ufs(dev, req, req_len, resp, resp_len);
+}
+
+int rpmb_write(uint32_t *req, uint32_t req_len, uint32_t *resp, uint32_t *resp_len)
+{
+ if (platform_boot_dev_isemmc())
+ return rpmb_write_emmc(dev, req, req_len, resp, resp_len);
+ else
+ return rpmb_write_ufs(dev, req, req_len, resp, resp_len);
+}
+
+/* This API calls into TZ app to read device_info */
+int read_device_info_rpmb(void *info, uint32_t sz)
+{
+ int ret = 0;
+ struct send_cmd_req read_req = {0};
+ struct send_cmd_rsp read_rsp = {0};
+
+ /*
+ * Load the sec app for first time
+ */
+ if (!lksec_app_loaded)
+ {
+ if (load_sec_app() < 0)
+ {
+ dprintf(CRITICAL, "Failed to load App for rpmb\n");
+ ASSERT(0);
+ }
+ lksec_app_loaded = true;
+ }
+
+ read_req.cmd_id = CLIENT_CMD_READ_LK_DEVICE_STATE;
+ read_req.data = (uint32_t) info;
+ read_req.len = sz;
+
+ read_rsp.cmd_id = CLIENT_CMD_READ_LK_DEVICE_STATE;
+
+ /* Read the device info */
+ ret = qseecom_send_command(app_handle, (void*) &read_req, sizeof(read_req), (void*) &read_rsp, sizeof(read_rsp));
+
+ if (ret < 0 || read_rsp.status < 0)
+ {
+ dprintf(CRITICAL, "Reading device info failed: Error: %d\n", read_rsp.status);
+ return read_rsp.status;
+ }
+
+ return 0;
+}
+
+int write_device_info_rpmb(void *info, uint32_t sz)
+{
+ int ret = 0;
+
+ struct send_cmd_req write_req = {0};
+ struct send_cmd_rsp write_rsp = {0};
+
+ write_req.cmd_id = CLIENT_CMD_WRITE_LK_DEVICE_STATE;
+ write_req.data = (uint32_t) info;
+ write_req.len = sz;
+
+ write_rsp.cmd_id = CLIENT_CMD_WRITE_LK_DEVICE_STATE;
+
+ /* Write the device info */
+ ret = qseecom_send_command(app_handle, (void *)&write_req, sizeof(write_req), (void *)&write_rsp, sizeof(write_rsp));
+
+ if (ret < 0 || write_rsp.status < 0)
+ {
+ dprintf(CRITICAL, "Writing device info failed: Error: %d\n", write_rsp.status);
+ return ret;
+ }
+
+ return 0;
+}
+
+int rpmb_get_app_handle()
+{
+ return app_handle;
+}
+
+int rpmb_uninit()
+{
+ int ret = 0;
+
+ ret = rpmb_listener_stop(RPMB_LSTNR_ID);
+ if (ret < 0)
+ {
+ dprintf(CRITICAL, "Failed to stop Qseecom Listener\n");
+ return ret;
+ }
+ ret = qseecom_exit();
+
+ if (ret < 0)
+ {
+ dprintf(CRITICAL, "Failed to exit qseecom \n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int load_sec_app()
+{
+ /* start TZ app */
+ app_handle = qseecom_start_app("lksecapp");
+
+ if (app_handle < 0)
+ {
+ dprintf(CRITICAL, "Failure to load TZ app: lksecapp, error: %d\n", app_handle);
+ return app_handle;
+ }
+
+ return 0;
+}
+
+int unload_sec_app()
+{
+ int ret = 0;
+
+ struct send_cmd_req req = {0};
+ struct send_cmd_rsp rsp = {0};
+
+ req.cmd_id = CLIENT_CMD_LK_END_MILESTONE;
+ rsp.cmd_id = CLIENT_CMD_LK_END_MILESTONE;
+
+ /* Milestone end command */
+ ret = qseecom_send_command(app_handle, (void *)&req, sizeof(req), (void *)&rsp, sizeof(rsp));
+
+ if (ret < 0 || rsp.status < 0)
+ {
+ dprintf(CRITICAL, "Failed to send milestone end command: Error: %x\n", rsp.status);
+ return ret;
+ }
+
+ if (qseecom_shutdown_app(app_handle) < 0)
+ {
+ dprintf(CRITICAL, "Failed to Shutdown sec app\n");
+ ASSERT(0);
+ }
+
+
+ return 0;
+}
+
+bool is_sec_app_loaded()
+{
+ return lksec_app_loaded;
+}
diff --git a/platform/msm_shared/rpmb/rpmb_emmc.c b/platform/msm_shared/rpmb/rpmb_emmc.c
new file mode 100644
index 0000000..2bfa545
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb_emmc.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 2015, 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 <rpmb.h>
+#include <mmc_sdhci.h>
+#include <debug.h>
+
+static const char *str_err[] =
+{
+ "Operation Ok",
+ "General failure",
+ "Authentication error (MAC comparison not matching, MAC calculation failure)",
+ "Counter failure (counters not matching in comparison, counter incrementing failure)",
+ "Address failure (address out of range, wrong address alignment)",
+ "Write failure (data/counter/result write failure)",
+ "Read failure (data/counter/result read failure)",
+ "Authentication Key not yet programmed",
+};
+
+static struct rpmb_frame read_result_reg =
+{
+ .requestresponse[1] = READ_RESULT_FLAG,
+};
+
+int rpmb_write_emmc(struct mmc_device *dev,uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+ uint32_t i;
+ int ret = 0;
+ struct mmc_command cmd[3] = {{0},{0},{0}};
+ struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
+
+ for (i = 0; i < blk_cnt; i++)
+ {
+#if DEBUG_RPMB
+ dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+ /* CMD25 program data packet */
+ cmd[0].write_flag = true;
+ cmd[0].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+ cmd[0].argument = 0;
+ cmd[0].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd[0].resp_type = SDHCI_CMD_RESP_R1;
+ cmd[0].trans_mode = SDHCI_MMC_WRITE;
+ cmd[0].data_present = 0x1;
+ cmd[0].data.data_ptr = (void *)req_buf;
+ cmd[0].data.num_blocks = RPMB_MIN_BLK_CNT;
+
+ /* CMD25 Result Register Read Request Packet */
+ cmd[1].write_flag = false;
+ cmd[1].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+ cmd[1].argument = 0;
+ cmd[1].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd[1].resp_type = SDHCI_CMD_RESP_R1;
+ cmd[1].trans_mode = SDHCI_MMC_WRITE;
+ cmd[1].data_present = 0x1;
+ cmd[1].data.data_ptr = (void *)&read_result_reg;
+ cmd[1].data.num_blocks = RPMB_MIN_BLK_CNT;
+
+ /* Read actual result with read request */
+ cmd[2].write_flag = false;
+ cmd[2].cmd_index = CMD18_READ_MULTIPLE_BLOCK;
+ cmd[2].argument = 0;
+ cmd[2].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd[2].resp_type = SDHCI_CMD_RESP_R1;
+ cmd[2].trans_mode = SDHCI_MMC_READ;
+ cmd[2].data_present = 0x1;
+ cmd[2].data.data_ptr = (void *)resp_buf;
+ cmd[2].data.num_blocks = RPMB_MIN_BLK_CNT;
+
+ ret = mmc_sdhci_rpmb_send(dev, cmd);
+
+ if (ret)
+ {
+ dprintf(CRITICAL, "Failed to Send the RPMB write sequnce of commands\n");
+ break;
+ }
+
+ if (result->result[0] == 0x80)
+ {
+ dprintf(CRITICAL, "Max write counter reached: \n");
+ break;
+ }
+
+ if (result->result[1])
+ {
+ dprintf(CRITICAL, "%s\n", str_err[result->result[1]]);
+ break;
+ }
+
+ req_buf = (uint32_t*) ((uint8_t*)req_buf + RPMB_BLK_SIZE);
+
+#if DEBUG_RPMB
+ dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
+ }
+ *resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
+
+ return 0;
+}
+
+int rpmb_read_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+ struct mmc_command cmd[3] = {{0}, {0}, {0}};
+ int ret = 0;
+ struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
+
+#if DEBUG_RPMB
+ dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+ /* CMD25 program data packet */
+ cmd[0].write_flag = false;
+ cmd[0].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+ cmd[0].argument = 0;
+ cmd[0].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd[0].resp_type = SDHCI_CMD_RESP_R1;
+ cmd[0].trans_mode = SDHCI_MMC_WRITE;
+ cmd[0].data_present = 0x1;
+ cmd[0].data.data_ptr = (void *)req_buf;
+ cmd[0].data.num_blocks = RPMB_MIN_BLK_CNT;
+
+ /* Read actual result with read request */
+ cmd[1].write_flag = false;
+ cmd[1].cmd_index = CMD18_READ_MULTIPLE_BLOCK;
+ cmd[1].argument = 0;
+ cmd[1].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd[1].resp_type = SDHCI_CMD_RESP_R1;
+ cmd[1].trans_mode = SDHCI_MMC_READ;
+ cmd[1].data_present = 0x1;
+ cmd[1].data.data_ptr = (void *)resp_buf;
+ cmd[1].data.num_blocks = blk_cnt;
+ cmd[1].cmd23_support = 0x1;
+
+ ret = mmc_sdhci_rpmb_send(dev, cmd);
+
+ if (ret)
+ {
+ dprintf(CRITICAL, "Failed to Send the RPMB read sequence of commands\n");
+ return -1;
+ }
+
+ if (result->result[1])
+ {
+ dprintf(CRITICAL, "%s\n", str_err[result->result[1]]);
+ }
+
+#if DEBUG_RPMB
+ dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
+ *resp_len = blk_cnt * RPMB_BLK_SIZE;
+
+ return 0;
+}
diff --git a/platform/msm_shared/rpmb/rpmb_listener.c b/platform/msm_shared/rpmb/rpmb_listener.c
new file mode 100644
index 0000000..7cf0b79
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb_listener.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2013-2015, 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>
+
+#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;
+}__PACKED;
+
+struct tz_rpmb_rw_resp
+{
+ uint32_t cmd_id;
+ int32_t status;
+ uint32_t res_buff_len;
+ uint32_t res_buff_offset;
+}__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 / RPMB_SECTOR_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");
+#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");
+#endif
+ resp_p->status = rpmb_write(req_buf, req_p->num_sectors, 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 = 20 * 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;
+}
+
diff --git a/platform/msm_shared/rpmb/rpmb_ufs.c b/platform/msm_shared/rpmb/rpmb_ufs.c
new file mode 100644
index 0000000..3cc4d91
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb_ufs.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2015, 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 <ufs.h>
+#include <ucs.h>
+#include <upiu.h>
+#include <rpmb.h>
+#include <debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <arch/defines.h>
+
+static struct rpmb_frame read_result_reg =
+{
+ .requestresponse[1] = READ_RESULT_FLAG,
+};
+
+int rpmb_read_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+ // validate input parameters
+ ASSERT(req_buf);
+ ASSERT(resp_buf);
+ ASSERT(resp_len);
+
+ STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sec_protocol_cdb));
+ struct scsi_req_build_type req_upiu;
+ struct scsi_sec_protocol_cdb *cdb_out_param, *cdb_in_param;
+ uint32_t blks_remaining;
+ uint32_t blks_to_transfer;
+ uint64_t bytes_to_transfer;
+ uint64_t max_size;
+ blks_remaining = blk_cnt;
+ blks_to_transfer = blks_remaining;
+ bytes_to_transfer = blks_to_transfer * RPMB_FRAME_SIZE;
+
+#ifdef DEBUG_RPMB
+ dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+ // check if total bytes to transfer exceed max supported size
+ max_size = dev->rpmb_rw_size * RPMB_FRAME_SIZE * blk_cnt;
+ if (bytes_to_transfer > max_size)
+ {
+ dprintf(CRITICAL, "RPMB request transfer size %llu greater than max transfer size %llu\n", bytes_to_transfer, max_size);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(SPEW, "rpmb_read: req_buf: 0x%x blk_count: 0x%x\n", *req_buf, blk_cnt);
+ dprintf(INFO, "rpmb_read: bytes_to_transfer: 0x%x blks_to_transfer: 0x%x\n",
+ bytes_to_transfer, blks_to_transfer);
+#endif
+ // send the request
+ cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
+ memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+ cdb_out_param->opcode = SCSI_CMD_SECPROT_OUT;
+ cdb_out_param->cdb1 = SCSI_SEC_PROT;
+ cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+ cdb_out_param->alloc_tlen = BE32(bytes_to_transfer);
+
+ // Flush CDB to memory
+ dsb();
+ arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
+
+ memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+ req_upiu.cdb = (addr_t) cdb_out_param;
+ req_upiu.data_buffer_addr = (addr_t) req_buf;
+ req_upiu.data_len = bytes_to_transfer;
+ req_upiu.flags = UPIU_FLAGS_WRITE;
+ req_upiu.lun = UFS_WLUN_RPMB;
+ req_upiu.dd = UTRD_TARGET_TO_SYSTEM;
+
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB Read request\n");
+#endif
+ if (ucs_do_scsi_cmd(dev, &req_upiu))
+ {
+ dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB Read request complete\n");
+#endif
+ // read the response
+ cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
+ memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+ cdb_in_param->opcode = SCSI_CMD_SECPROT_IN;
+ cdb_in_param->cdb1 = SCSI_SEC_PROT;
+ cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+ cdb_in_param->alloc_tlen = BE32(bytes_to_transfer);
+
+ // Flush CDB to memory
+ dsb();
+ arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
+
+ memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+ req_upiu.cdb = (addr_t) cdb_in_param;
+ req_upiu.data_buffer_addr = (addr_t) resp_buf;
+ req_upiu.data_len = bytes_to_transfer;
+ req_upiu.flags = UPIU_FLAGS_READ;
+ req_upiu.lun = UFS_WLUN_RPMB;
+ req_upiu.dd = UTRD_SYSTEM_TO_TARGET;
+
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB Read response\n");
+#endif
+ if (ucs_do_scsi_cmd(dev, &req_upiu))
+ {
+ dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(SPEW, "Sending RPMB Read response complete\n");
+ dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
+ *resp_len = bytes_to_transfer;
+ return UFS_SUCCESS;
+}
+
+int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+ // validate input parameters
+ ASSERT(req_buf);
+ ASSERT(resp_buf);
+ ASSERT(resp_len);
+
+ STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sec_protocol_cdb));
+ struct scsi_req_build_type req_upiu;
+ struct scsi_sec_protocol_cdb *cdb_out_param, *cdb_in_param;
+ uint32_t blks_remaining;
+ uint32_t blks_to_transfer;
+ uint64_t bytes_to_transfer;
+ uint64_t max_size;
+ uint32_t result_frame_bytes = RPMB_FRAME_SIZE;
+ uint32_t i;
+
+ blks_remaining = blk_cnt;
+ blks_to_transfer = blks_remaining;
+ bytes_to_transfer = blks_to_transfer * RPMB_FRAME_SIZE;
+
+ // check if total bytes to transfer exceed max supported size
+ max_size = dev->rpmb_rw_size * RPMB_FRAME_SIZE * blk_cnt;
+ if (bytes_to_transfer > max_size)
+ {
+ dprintf(CRITICAL, "RPMB request transfer size %llu greater than max transfer size %llu\n", bytes_to_transfer, max_size);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "%s: req_buf: 0x%x blk_count: 0x%x\n", __func__,*req_buf, blk_cnt);
+ dprintf(INFO, "%s: bytes_to_transfer: 0x%x blks_to_transfer: 0x%x\n", __func__
+ bytes_to_transfer, blk_cnt);
+ dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+ for (i = 0; i < blk_cnt; i++)
+ {
+ // send the request
+ cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
+ memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+ cdb_out_param->opcode = SCSI_CMD_SECPROT_OUT;
+ cdb_out_param->cdb1 = SCSI_SEC_PROT;
+ cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+ cdb_out_param->alloc_tlen = BE32(RPMB_FRAME_SIZE);
+
+ // Flush CDB to memory
+ dsb();
+ arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
+
+ memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+ req_upiu.cdb = (addr_t) cdb_out_param;
+ req_upiu.data_buffer_addr = (addr_t) req_buf;
+ req_upiu.data_len = RPMB_FRAME_SIZE;
+ req_upiu.flags = UPIU_FLAGS_WRITE;
+ req_upiu.lun = UFS_WLUN_RPMB;
+ req_upiu.dd = UTRD_TARGET_TO_SYSTEM;
+
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB write request: Start\n");
+#endif
+ if (ucs_do_scsi_cmd(dev, &req_upiu))
+ {
+ dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB write request: Done\n");
+#endif
+ // Result Read
+ cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
+ memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+ cdb_in_param->opcode = SCSI_CMD_SECPROT_OUT;
+ cdb_in_param->cdb1 = SCSI_SEC_PROT;
+ cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+ cdb_in_param->alloc_tlen = BE32(RPMB_FRAME_SIZE);
+
+ // Flush CDB to memory
+ dsb();
+ arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
+
+ memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+ req_upiu.cdb = (addr_t) cdb_in_param;
+ req_upiu.data_buffer_addr = (addr_t) &read_result_reg ;
+ req_upiu.data_len = result_frame_bytes;
+ req_upiu.flags = UPIU_FLAGS_WRITE;
+ req_upiu.lun = UFS_WLUN_RPMB;
+ req_upiu.dd = UTRD_TARGET_TO_SYSTEM;
+
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB Result Read Register: Start \n");
+#endif
+ if (ucs_do_scsi_cmd(dev, &req_upiu))
+ {
+ dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(SPEW, "Sending RPMB Result Read Register: Done\n");
+#endif
+
+ // Retrieve verification result
+ cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
+ memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+ cdb_in_param->opcode = SCSI_CMD_SECPROT_IN;
+ cdb_in_param->cdb1 = SCSI_SEC_PROT;
+ cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+ cdb_in_param->alloc_tlen = BE32(RPMB_FRAME_SIZE);
+
+ // Flush CDB to memory
+ dsb();
+ arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
+
+ memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+ req_upiu.cdb = (addr_t) cdb_in_param;
+ req_upiu.data_buffer_addr = (addr_t) resp_buf;
+ req_upiu.data_len = result_frame_bytes;
+ req_upiu.flags = UPIU_FLAGS_READ;
+ req_upiu.lun = UFS_WLUN_RPMB;
+ req_upiu.dd = UTRD_SYSTEM_TO_TARGET;
+
+#ifdef DEBUG_RPMB
+ dprintf(INFO, "Sending RPMB Response for Result Read Register : Start\n");
+#endif
+ if (ucs_do_scsi_cmd(dev, &req_upiu))
+ {
+ dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+ return -UFS_FAILURE;
+ }
+#ifdef DEBUG_RPMB
+ dprintf(SPEW, "Sending RPMB Response for Result Read Register: Done\n");
+ dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
+
+ req_buf = (uint32_t*) ((uint8_t*)req_buf + RPMB_BLK_SIZE);
+ }
+
+ *resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
+
+ return 0;
+}
diff --git a/platform/msm_shared/rpmb/rules.mk b/platform/msm_shared/rpmb/rules.mk
new file mode 100644
index 0000000..0e76433
--- /dev/null
+++ b/platform/msm_shared/rpmb/rules.mk
@@ -0,0 +1,8 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LOCAL_DIR)/include
+
+OBJS += $(LOCAL_DIR)/rpmb.o \
+ $(LOCAL_DIR)/rpmb_listener.o \
+ $(LOCAL_DIR)/rpmb_emmc.o \
+ $(LOCAL_DIR)/rpmb_ufs.o
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
old mode 100755
new mode 100644
index 793b88c..26eb012
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -533,3 +533,7 @@
ifeq ($(ENABLE_PARTIAL_GOODS_SUPPORT), 1)
OBJS += $(LOCAL_DIR)/partial_goods.o
endif
+
+ifeq ($(ENABLE_RPMB_SUPPORT), 1)
+include platform/msm_shared/rpmb/rules.mk
+endif