Loading arch/arm/mach-msm/include/mach/qseecomi.h +22 −8 Original line number Diff line number Diff line Loading @@ -18,13 +18,15 @@ #define QSEECOM_KEY_ID_SIZE 32 #define QSEOS_RESULT_FAIL_LOAD_KS -57 #define QSEOS_RESULT_FAIL_SAVE_KS -58 #define QSEOS_RESULT_FAIL_MAX_KEYS -59 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -60 #define QSEOS_RESULT_FAIL_KEY_ID_DNE -61 #define QSEOS_RESULT_FAIL_KS_OP -62 #define QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63 #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63 #define QSEOS_RESULT_FAIL_KS_OP -64 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65 #define QSEOS_RESULT_FAIL_MAX_KEYS -66 #define QSEOS_RESULT_FAIL_SAVE_KS -67 #define QSEOS_RESULT_FAIL_LOAD_KS -68 #define QSEOS_RESULT_FAIL_KS_ALREADY_DONE -69 #define QSEOS_RESULT_FAIL_KEY_ID_DNE -70 #define QSEOS_RESULT_FAIL_INCORRECT_PSWD -71 enum qseecom_command_scm_resp_type { QSEOS_APP_ID = 0xEE01, Loading Loading @@ -52,6 +54,7 @@ enum qseecom_qceos_cmd_id { QSEOS_DELETE_KEY, QSEOS_MAX_KEY_COUNT, QSEOS_SET_KEY, QSEOS_UPDATE_KEY_USERINFO, QSEOS_CMD_MAX = 0xEFFFFFFF }; Loading Loading @@ -166,6 +169,7 @@ __packed struct qseecom_key_generate_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_select_ireq { Loading @@ -175,13 +179,23 @@ __packed struct qseecom_key_select_ireq { uint32_t pipe_type; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; unsigned char hash[QSEECOM_HASH_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_delete_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_userinfo_update_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t current_hash32[QSEECOM_HASH_SIZE]; uint8_t new_hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_max_count_query_ireq { Loading drivers/misc/qseecom.c +181 −81 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/firmware.h> #include <linux/freezer.h> #include <linux/scatterlist.h> #include <linux/delay.h> #include <mach/board.h> #include <mach/msm_bus.h> #include <mach/msm_bus_board.h> Loading Loading @@ -204,25 +205,15 @@ struct qseecom_dev_handle { enum qseecom_bandwidth_request_mode mode; }; enum qseecom_set_clear_key_flag { QSEECOM_CLEAR_CE_KEY_CMD = 0, QSEECOM_SET_CE_KEY_CMD, }; struct qseecom_set_key_parameter { uint32_t ce_hw; uint32_t pipe; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; unsigned char hash32[QSEECOM_HASH_SIZE]; enum qseecom_set_clear_key_flag set_clear_key_flag; }; struct qseecom_sg_entry { uint32_t phys_addr; uint32_t len; }; uint8_t *key_id_array[QSEECOM_KEY_ID_SIZE] = { "Disk Encryption" }; /* Function proto types */ static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t); static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t); Loading Loading @@ -2600,25 +2591,20 @@ static int __qseecom_get_ce_pipe_info( static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, uint8_t *key_id, uint32_t flags) struct qseecom_key_generate_ireq *ireq) { struct qseecom_key_generate_ireq ireq; struct qseecom_command_scm_resp resp; int ret; if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE); ireq.flags = flags; ireq.qsee_command_id = QSEOS_GENERATE_KEY; __qseecom_enable_clk(CLK_QSEE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(struct qseecom_key_generate_ireq), ireq, sizeof(struct qseecom_key_generate_ireq), &resp, sizeof(resp)); if (ret) { pr_err("scm call to generate key failed : %d\n", ret); Loading Loading @@ -2656,25 +2642,20 @@ static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data, static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, uint8_t *key_id, uint32_t flags) struct qseecom_key_delete_ireq *ireq) { struct qseecom_key_delete_ireq ireq; struct qseecom_command_scm_resp resp; int ret; if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE); ireq.flags = flags; ireq.qsee_command_id = QSEOS_DELETE_KEY; __qseecom_enable_clk(CLK_QSEE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(struct qseecom_key_delete_ireq), ireq, sizeof(struct qseecom_key_delete_ireq), &resp, sizeof(struct qseecom_command_scm_resp)); if (ret) { pr_err("scm call to delete key failed : %d\n", ret); Loading Loading @@ -2704,13 +2685,13 @@ static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data, static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, struct qseecom_set_key_parameter *set_key_para) struct qseecom_key_select_ireq *ireq) { struct qseecom_key_select_ireq ireq; struct qseecom_command_scm_resp resp; int ret; if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } Loading @@ -2719,24 +2700,8 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, if (qseecom.qsee.instance != qseecom.ce_drv.instance) __qseecom_enable_clk(CLK_CE_DRV); memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE); ireq.qsee_command_id = QSEOS_SET_KEY; ireq.ce = set_key_para->ce_hw; ireq.pipe = set_key_para->pipe; ireq.flags = set_key_para->flags; /* set both PIPE_ENC and PIPE_ENC_XTS*/ ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS; if (set_key_para->set_clear_key_flag == QSEECOM_SET_CE_KEY_CMD) memcpy((void *)ireq.hash, (void *)set_key_para->hash32, QSEECOM_HASH_SIZE); else memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(struct qseecom_key_select_ireq), ireq, sizeof(struct qseecom_key_select_ireq), &resp, sizeof(struct qseecom_command_scm_resp)); if (ret) { pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret); Loading Loading @@ -2769,16 +2734,63 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, return ret; } static int __qseecom_update_current_key_user_info( struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, struct qseecom_key_userinfo_update_ireq *ireq) { struct qseecom_command_scm_resp resp; int ret; if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } __qseecom_enable_clk(CLK_QSEE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, ireq, sizeof(struct qseecom_key_userinfo_update_ireq), &resp, sizeof(struct qseecom_command_scm_resp)); if (ret) { pr_err("scm call to update key userinfo failed : %d\n", ret); __qseecom_disable_clk(CLK_QSEE); if (qseecom.qsee.instance != qseecom.ce_drv.instance) __qseecom_disable_clk(CLK_CE_DRV); return ret; } switch (resp.result) { case QSEOS_RESULT_SUCCESS: break; case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) pr_err("process_incomplete_cmd FAILED, resp.result %d\n", resp.result); break; case QSEOS_RESULT_FAILURE: default: pr_err("Set key scm call failed resp.result %d\n", resp.result); ret = -EINVAL; break; } __qseecom_disable_clk(CLK_QSEE); return ret; } static int qseecom_create_key(struct qseecom_dev_handle *data, void __user *argp) { uint32_t ce_hw = 0; uint32_t pipe = 0; uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0}; int ret = 0; uint32_t flags = 0; struct qseecom_set_key_parameter set_key_para; struct qseecom_create_key_req create_key_req; struct qseecom_key_generate_ireq generate_key_ireq; struct qseecom_key_select_ireq set_key_ireq; ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req)); if (ret) { Loading @@ -2786,7 +2798,8 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, return ret; } if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || create_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", create_key_req.usage); return -EFAULT; } Loading @@ -2797,23 +2810,41 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, return -EINVAL; } generate_key_ireq.flags = flags; generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY; memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); memcpy((void *)generate_key_ireq.key_id, (void *)key_id_array[create_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memcpy((void *)generate_key_ireq.hash32, (void *)create_key_req.hash32, QSEECOM_HASH_SIZE); ret = __qseecom_generate_and_save_key(data, create_key_req.usage, key_id, flags); &generate_key_ireq); if (ret) { pr_err("Failed to generate key on storage: %d\n", ret); return -EFAULT; } set_key_para.ce_hw = ce_hw; set_key_para.pipe = pipe; memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE); set_key_para.flags = flags; set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD; memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32, set_key_ireq.qsee_command_id = QSEOS_SET_KEY; set_key_ireq.ce = ce_hw; set_key_ireq.pipe = pipe; set_key_ireq.flags = flags; /* set both PIPE_ENC and PIPE_ENC_XTS*/ set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS; memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); memcpy((void *)set_key_ireq.key_id, (void *)key_id_array[create_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32, QSEECOM_HASH_SIZE); ret = __qseecom_set_clear_ce_key(data, create_key_req.usage, &set_key_para); &set_key_ireq); msleep(2000); if (ret) { pr_err("Failed to create key: pipe %d, ce %d: %d\n", pipe, ce_hw, ret); Loading @@ -2828,12 +2859,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, { uint32_t ce_hw = 0; uint32_t pipe = 0; uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0}; int ret = 0; uint32_t flags = 0; int i; struct qseecom_wipe_key_req wipe_key_req; struct qseecom_set_key_parameter clear_key_para; struct qseecom_key_delete_ireq delete_key_ireq; struct qseecom_key_select_ireq clear_key_ireq; ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req)); if (ret) { Loading @@ -2841,7 +2872,8 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, return ret; } if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage); return -EFAULT; } Loading @@ -2852,22 +2884,32 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, return -EINVAL; } ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id, flags); delete_key_ireq.flags = flags; delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY; memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memcpy((void *)delete_key_ireq.key_id, (void *)key_id_array[wipe_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, &delete_key_ireq); if (ret) { pr_err("Failed to delete key from ssd storage: %d\n", ret); return -EFAULT; } /* an invalid key_id 0xff is used to indicate clear key*/ clear_key_ireq.qsee_command_id = QSEOS_SET_KEY; clear_key_ireq.ce = ce_hw; clear_key_ireq.pipe = pipe; clear_key_ireq.flags = flags; clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS; for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++) clear_key_para.key_id[i] = 0xff; clear_key_para.ce_hw = ce_hw; clear_key_para.pipe = pipe; clear_key_para.flags = flags; clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD; clear_key_ireq.key_id[i] = 0xff; memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage, &clear_key_para); &clear_key_ireq); if (ret) { pr_err("Failed to wipe key: pipe %d, ce %d: %d\n", pipe, ce_hw, ret); Loading @@ -2877,6 +2919,48 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, return ret; } static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, void __user *argp) { int ret = 0; uint32_t flags = 0; struct qseecom_update_key_userinfo_req update_key_req; struct qseecom_key_userinfo_update_ireq ireq; ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req)); if (ret) { pr_err("copy_from_user failed\n"); return ret; } if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || update_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", update_key_req.usage); return -EFAULT; } ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO; ireq.flags = flags; memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE); memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE); memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memcpy((void *)ireq.current_hash32, (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE); memcpy((void *)ireq.new_hash32, (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE); ret = __qseecom_update_current_key_user_info(data, update_key_req.usage, &ireq); msleep(2000); if (ret) { pr_err("Failed to update key info: %d\n", ret); return -EFAULT; } return ret; } static int qseecom_is_es_activated(void __user *argp) { struct qseecom_is_es_activated_req req; Loading Loading @@ -3284,14 +3368,12 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, return -EINVAL; } data->released = true; mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_create_key(data, argp); if (ret) pr_err("failed to create encryption key: %d\n", ret); atomic_dec(&data->ioctl_count); mutex_unlock(&app_access_lock); break; } case QSEECOM_IOCTL_WIPE_KEY_REQ: { Loading @@ -3307,13 +3389,31 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, return -EINVAL; } data->released = true; mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_wipe_key(data, argp); if (ret) pr_err("failed to wipe encryption key: %d\n", ret); atomic_dec(&data->ioctl_count); mutex_unlock(&app_access_lock); break; } case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: { if (data->type != QSEECOM_GENERIC) { pr_err("update key req: invalid handle (%d)\n", data->type); ret = -EINVAL; break; } if (qseecom.qsee_version < QSEE_VERSION_05) { pr_err("Update Key feature unsupported in qsee ver %u\n", qseecom.qsee_version); return -EINVAL; } data->released = true; atomic_inc(&data->ioctl_count); ret = qseecom_update_key_user_info(data, argp); if (ret) pr_err("failed to update key user info: %d\n", ret); atomic_dec(&data->ioctl_count); break; } case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: { Loading include/uapi/linux/qseecom.h +11 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ struct qseecom_send_svc_cmd_req { enum qseecom_key_management_usage_type { QSEOS_KM_USAGE_DISK_ENCRYPTION = 0x01, QSEOS_KM_USAGE_MAX }; struct qseecom_create_key_req { Loading @@ -138,6 +139,12 @@ struct qseecom_wipe_key_req { enum qseecom_key_management_usage_type usage; }; struct qseecom_update_key_userinfo_req { unsigned char current_hash32[QSEECOM_HASH_SIZE]; unsigned char new_hash32[QSEECOM_HASH_SIZE]; enum qseecom_key_management_usage_type usage; }; #define SHA256_DIGEST_LENGTH (256/8) /* * struct qseecom_save_partition_hash_req Loading Loading @@ -247,4 +254,8 @@ struct qseecom_send_modfd_listener_resp { #define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 23, int) #define QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 24, struct qseecom_update_key_userinfo_req) #endif /* _UAPI_QSEECOM_H_ */ Loading
arch/arm/mach-msm/include/mach/qseecomi.h +22 −8 Original line number Diff line number Diff line Loading @@ -18,13 +18,15 @@ #define QSEECOM_KEY_ID_SIZE 32 #define QSEOS_RESULT_FAIL_LOAD_KS -57 #define QSEOS_RESULT_FAIL_SAVE_KS -58 #define QSEOS_RESULT_FAIL_MAX_KEYS -59 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -60 #define QSEOS_RESULT_FAIL_KEY_ID_DNE -61 #define QSEOS_RESULT_FAIL_KS_OP -62 #define QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63 #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63 #define QSEOS_RESULT_FAIL_KS_OP -64 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65 #define QSEOS_RESULT_FAIL_MAX_KEYS -66 #define QSEOS_RESULT_FAIL_SAVE_KS -67 #define QSEOS_RESULT_FAIL_LOAD_KS -68 #define QSEOS_RESULT_FAIL_KS_ALREADY_DONE -69 #define QSEOS_RESULT_FAIL_KEY_ID_DNE -70 #define QSEOS_RESULT_FAIL_INCORRECT_PSWD -71 enum qseecom_command_scm_resp_type { QSEOS_APP_ID = 0xEE01, Loading Loading @@ -52,6 +54,7 @@ enum qseecom_qceos_cmd_id { QSEOS_DELETE_KEY, QSEOS_MAX_KEY_COUNT, QSEOS_SET_KEY, QSEOS_UPDATE_KEY_USERINFO, QSEOS_CMD_MAX = 0xEFFFFFFF }; Loading Loading @@ -166,6 +169,7 @@ __packed struct qseecom_key_generate_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_select_ireq { Loading @@ -175,13 +179,23 @@ __packed struct qseecom_key_select_ireq { uint32_t pipe_type; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; unsigned char hash[QSEECOM_HASH_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_delete_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_userinfo_update_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t current_hash32[QSEECOM_HASH_SIZE]; uint8_t new_hash32[QSEECOM_HASH_SIZE]; }; __packed struct qseecom_key_max_count_query_ireq { Loading
drivers/misc/qseecom.c +181 −81 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <linux/firmware.h> #include <linux/freezer.h> #include <linux/scatterlist.h> #include <linux/delay.h> #include <mach/board.h> #include <mach/msm_bus.h> #include <mach/msm_bus_board.h> Loading Loading @@ -204,25 +205,15 @@ struct qseecom_dev_handle { enum qseecom_bandwidth_request_mode mode; }; enum qseecom_set_clear_key_flag { QSEECOM_CLEAR_CE_KEY_CMD = 0, QSEECOM_SET_CE_KEY_CMD, }; struct qseecom_set_key_parameter { uint32_t ce_hw; uint32_t pipe; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; unsigned char hash32[QSEECOM_HASH_SIZE]; enum qseecom_set_clear_key_flag set_clear_key_flag; }; struct qseecom_sg_entry { uint32_t phys_addr; uint32_t len; }; uint8_t *key_id_array[QSEECOM_KEY_ID_SIZE] = { "Disk Encryption" }; /* Function proto types */ static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t); static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t); Loading Loading @@ -2600,25 +2591,20 @@ static int __qseecom_get_ce_pipe_info( static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, uint8_t *key_id, uint32_t flags) struct qseecom_key_generate_ireq *ireq) { struct qseecom_key_generate_ireq ireq; struct qseecom_command_scm_resp resp; int ret; if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE); ireq.flags = flags; ireq.qsee_command_id = QSEOS_GENERATE_KEY; __qseecom_enable_clk(CLK_QSEE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(struct qseecom_key_generate_ireq), ireq, sizeof(struct qseecom_key_generate_ireq), &resp, sizeof(resp)); if (ret) { pr_err("scm call to generate key failed : %d\n", ret); Loading Loading @@ -2656,25 +2642,20 @@ static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data, static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, uint8_t *key_id, uint32_t flags) struct qseecom_key_delete_ireq *ireq) { struct qseecom_key_delete_ireq ireq; struct qseecom_command_scm_resp resp; int ret; if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE); ireq.flags = flags; ireq.qsee_command_id = QSEOS_DELETE_KEY; __qseecom_enable_clk(CLK_QSEE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(struct qseecom_key_delete_ireq), ireq, sizeof(struct qseecom_key_delete_ireq), &resp, sizeof(struct qseecom_command_scm_resp)); if (ret) { pr_err("scm call to delete key failed : %d\n", ret); Loading Loading @@ -2704,13 +2685,13 @@ static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data, static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, struct qseecom_set_key_parameter *set_key_para) struct qseecom_key_select_ireq *ireq) { struct qseecom_key_select_ireq ireq; struct qseecom_command_scm_resp resp; int ret; if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } Loading @@ -2719,24 +2700,8 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, if (qseecom.qsee.instance != qseecom.ce_drv.instance) __qseecom_enable_clk(CLK_CE_DRV); memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE); ireq.qsee_command_id = QSEOS_SET_KEY; ireq.ce = set_key_para->ce_hw; ireq.pipe = set_key_para->pipe; ireq.flags = set_key_para->flags; /* set both PIPE_ENC and PIPE_ENC_XTS*/ ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS; if (set_key_para->set_clear_key_flag == QSEECOM_SET_CE_KEY_CMD) memcpy((void *)ireq.hash, (void *)set_key_para->hash32, QSEECOM_HASH_SIZE); else memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &ireq, sizeof(struct qseecom_key_select_ireq), ireq, sizeof(struct qseecom_key_select_ireq), &resp, sizeof(struct qseecom_command_scm_resp)); if (ret) { pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret); Loading Loading @@ -2769,16 +2734,63 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data, return ret; } static int __qseecom_update_current_key_user_info( struct qseecom_dev_handle *data, enum qseecom_key_management_usage_type usage, struct qseecom_key_userinfo_update_ireq *ireq) { struct qseecom_command_scm_resp resp; int ret; if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", usage); return -EFAULT; } __qseecom_enable_clk(CLK_QSEE); ret = scm_call(SCM_SVC_TZSCHEDULER, 1, ireq, sizeof(struct qseecom_key_userinfo_update_ireq), &resp, sizeof(struct qseecom_command_scm_resp)); if (ret) { pr_err("scm call to update key userinfo failed : %d\n", ret); __qseecom_disable_clk(CLK_QSEE); if (qseecom.qsee.instance != qseecom.ce_drv.instance) __qseecom_disable_clk(CLK_CE_DRV); return ret; } switch (resp.result) { case QSEOS_RESULT_SUCCESS: break; case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) pr_err("process_incomplete_cmd FAILED, resp.result %d\n", resp.result); break; case QSEOS_RESULT_FAILURE: default: pr_err("Set key scm call failed resp.result %d\n", resp.result); ret = -EINVAL; break; } __qseecom_disable_clk(CLK_QSEE); return ret; } static int qseecom_create_key(struct qseecom_dev_handle *data, void __user *argp) { uint32_t ce_hw = 0; uint32_t pipe = 0; uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0}; int ret = 0; uint32_t flags = 0; struct qseecom_set_key_parameter set_key_para; struct qseecom_create_key_req create_key_req; struct qseecom_key_generate_ireq generate_key_ireq; struct qseecom_key_select_ireq set_key_ireq; ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req)); if (ret) { Loading @@ -2786,7 +2798,8 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, return ret; } if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || create_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", create_key_req.usage); return -EFAULT; } Loading @@ -2797,23 +2810,41 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, return -EINVAL; } generate_key_ireq.flags = flags; generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY; memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); memcpy((void *)generate_key_ireq.key_id, (void *)key_id_array[create_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memcpy((void *)generate_key_ireq.hash32, (void *)create_key_req.hash32, QSEECOM_HASH_SIZE); ret = __qseecom_generate_and_save_key(data, create_key_req.usage, key_id, flags); &generate_key_ireq); if (ret) { pr_err("Failed to generate key on storage: %d\n", ret); return -EFAULT; } set_key_para.ce_hw = ce_hw; set_key_para.pipe = pipe; memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE); set_key_para.flags = flags; set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD; memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32, set_key_ireq.qsee_command_id = QSEOS_SET_KEY; set_key_ireq.ce = ce_hw; set_key_ireq.pipe = pipe; set_key_ireq.flags = flags; /* set both PIPE_ENC and PIPE_ENC_XTS*/ set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS; memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); memcpy((void *)set_key_ireq.key_id, (void *)key_id_array[create_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32, QSEECOM_HASH_SIZE); ret = __qseecom_set_clear_ce_key(data, create_key_req.usage, &set_key_para); &set_key_ireq); msleep(2000); if (ret) { pr_err("Failed to create key: pipe %d, ce %d: %d\n", pipe, ce_hw, ret); Loading @@ -2828,12 +2859,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, { uint32_t ce_hw = 0; uint32_t pipe = 0; uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0}; int ret = 0; uint32_t flags = 0; int i; struct qseecom_wipe_key_req wipe_key_req; struct qseecom_set_key_parameter clear_key_para; struct qseecom_key_delete_ireq delete_key_ireq; struct qseecom_key_select_ireq clear_key_ireq; ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req)); if (ret) { Loading @@ -2841,7 +2872,8 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, return ret; } if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) { if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage); return -EFAULT; } Loading @@ -2852,22 +2884,32 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, return -EINVAL; } ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id, flags); delete_key_ireq.flags = flags; delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY; memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memcpy((void *)delete_key_ireq.key_id, (void *)key_id_array[wipe_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, &delete_key_ireq); if (ret) { pr_err("Failed to delete key from ssd storage: %d\n", ret); return -EFAULT; } /* an invalid key_id 0xff is used to indicate clear key*/ clear_key_ireq.qsee_command_id = QSEOS_SET_KEY; clear_key_ireq.ce = ce_hw; clear_key_ireq.pipe = pipe; clear_key_ireq.flags = flags; clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS; for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++) clear_key_para.key_id[i] = 0xff; clear_key_para.ce_hw = ce_hw; clear_key_para.pipe = pipe; clear_key_para.flags = flags; clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD; clear_key_ireq.key_id[i] = 0xff; memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage, &clear_key_para); &clear_key_ireq); if (ret) { pr_err("Failed to wipe key: pipe %d, ce %d: %d\n", pipe, ce_hw, ret); Loading @@ -2877,6 +2919,48 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, return ret; } static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, void __user *argp) { int ret = 0; uint32_t flags = 0; struct qseecom_update_key_userinfo_req update_key_req; struct qseecom_key_userinfo_update_ireq ireq; ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req)); if (ret) { pr_err("copy_from_user failed\n"); return ret; } if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || update_key_req.usage >= QSEOS_KM_USAGE_MAX) { pr_err("Error:: unsupported usage %d\n", update_key_req.usage); return -EFAULT; } ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO; ireq.flags = flags; memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE); memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE); memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE); memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1], QSEECOM_KEY_ID_SIZE); memcpy((void *)ireq.current_hash32, (void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE); memcpy((void *)ireq.new_hash32, (void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE); ret = __qseecom_update_current_key_user_info(data, update_key_req.usage, &ireq); msleep(2000); if (ret) { pr_err("Failed to update key info: %d\n", ret); return -EFAULT; } return ret; } static int qseecom_is_es_activated(void __user *argp) { struct qseecom_is_es_activated_req req; Loading Loading @@ -3284,14 +3368,12 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, return -EINVAL; } data->released = true; mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_create_key(data, argp); if (ret) pr_err("failed to create encryption key: %d\n", ret); atomic_dec(&data->ioctl_count); mutex_unlock(&app_access_lock); break; } case QSEECOM_IOCTL_WIPE_KEY_REQ: { Loading @@ -3307,13 +3389,31 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, return -EINVAL; } data->released = true; mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_wipe_key(data, argp); if (ret) pr_err("failed to wipe encryption key: %d\n", ret); atomic_dec(&data->ioctl_count); mutex_unlock(&app_access_lock); break; } case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: { if (data->type != QSEECOM_GENERIC) { pr_err("update key req: invalid handle (%d)\n", data->type); ret = -EINVAL; break; } if (qseecom.qsee_version < QSEE_VERSION_05) { pr_err("Update Key feature unsupported in qsee ver %u\n", qseecom.qsee_version); return -EINVAL; } data->released = true; atomic_inc(&data->ioctl_count); ret = qseecom_update_key_user_info(data, argp); if (ret) pr_err("failed to update key user info: %d\n", ret); atomic_dec(&data->ioctl_count); break; } case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: { Loading
include/uapi/linux/qseecom.h +11 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ struct qseecom_send_svc_cmd_req { enum qseecom_key_management_usage_type { QSEOS_KM_USAGE_DISK_ENCRYPTION = 0x01, QSEOS_KM_USAGE_MAX }; struct qseecom_create_key_req { Loading @@ -138,6 +139,12 @@ struct qseecom_wipe_key_req { enum qseecom_key_management_usage_type usage; }; struct qseecom_update_key_userinfo_req { unsigned char current_hash32[QSEECOM_HASH_SIZE]; unsigned char new_hash32[QSEECOM_HASH_SIZE]; enum qseecom_key_management_usage_type usage; }; #define SHA256_DIGEST_LENGTH (256/8) /* * struct qseecom_save_partition_hash_req Loading Loading @@ -247,4 +254,8 @@ struct qseecom_send_modfd_listener_resp { #define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 23, int) #define QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 24, struct qseecom_update_key_userinfo_req) #endif /* _UAPI_QSEECOM_H_ */