/* * Samsung TZIC Driver * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define KMSG_COMPONENT "TZIC" #include #include #include #include #include #include #include #include #include #include #include #include #include // multiple oemflag //#include // one oemflag => old version #include #define TZIC_DEV "tzic" static DEFINE_MUTEX(tzic_mutex); static struct class *driver_class; static dev_t tzic_device_no; static struct cdev tzic_cdev; #define HLOS_IMG_TAMPER_FUSE 0 typedef enum { OEMFLAG_MIN_FLAG = 2, OEMFLAG_TZ_DRM, OEMFLAG_FIDD, OEMFLAG_CC, OEMFLAG_NUM_OF_FLAG, } Sec_OemFlagID_t; typedef struct { u32 name; u32 value; }t_flag; #ifndef SCM_SVC_FUSE #define SCM_SVC_FUSE 0x08 #endif #define SCM_BLOW_SW_FUSE_ID 0x01 #define SCM_IS_SW_FUSE_BLOWN_ID 0x02 #define TZIC_IOC_MAGIC 0x9E #define TZIC_IOCTL_GET_FUSE_REQ _IO(TZIC_IOC_MAGIC, 0) #define TZIC_IOCTL_SET_FUSE_REQ _IO(TZIC_IOC_MAGIC, 1) #define TZIC_IOCTL_SET_FUSE_REQ_DEFAULT _IO(TZIC_IOC_MAGIC, 2) #define TZIC_IOCTL_GET_FUSE_REQ_NEW _IO(TZIC_IOC_MAGIC, 10) #define TZIC_IOCTL_SET_FUSE_REQ_NEW _IO(TZIC_IOC_MAGIC, 11) #define STATE_IC_BAD 1 #define STATE_IC_GOOD 0 #define LOG printk static int ic = STATE_IC_GOOD; static int set_tamper_fuse_cmd(void); static uint8_t get_tamper_fuse_cmd(void); static int set_tamper_fuse_cmd_new(uint32_t flag); static uint8_t get_tamper_fuse_cmd_new(uint32_t flag); static int set_tamper_fuse_cmd() { struct scm_desc desc = {0}; uint32_t fuse_id; desc.args[0] = fuse_id = HLOS_IMG_TAMPER_FUSE; desc.arginfo = SCM_ARGS(1); if (!is_scm_armv8()) { return scm_call(SCM_SVC_FUSE, SCM_BLOW_SW_FUSE_ID, &fuse_id, sizeof(fuse_id), NULL, 0); } else { return scm_call2(SCM_SIP_FNID(SCM_SVC_FUSE, SCM_BLOW_SW_FUSE_ID), &desc); } } static int set_tamper_fuse_cmd_new(uint32_t flag) { struct scm_desc desc = {0}; uint32_t fuse_id; desc.args[0] = fuse_id = flag; desc.arginfo = SCM_ARGS(1); if (!is_scm_armv8()) { return scm_call(SCM_SVC_FUSE, SCM_BLOW_SW_FUSE_ID, &fuse_id, sizeof(fuse_id), NULL, 0); } else { return scm_call2(SCM_SIP_FNID(SCM_SVC_FUSE, SCM_BLOW_SW_FUSE_ID), &desc); } } static uint8_t get_tamper_fuse_cmd() { int ret; uint32_t fuse_id; uint8_t resp_buf; size_t resp_len; struct scm_desc desc = {0}; resp_len = sizeof(resp_buf); desc.args[0] = fuse_id = HLOS_IMG_TAMPER_FUSE; desc.arginfo = SCM_ARGS(1); if (!is_scm_armv8()) { ret = scm_call(SCM_SVC_FUSE, SCM_IS_SW_FUSE_BLOWN_ID, &fuse_id, sizeof(fuse_id), &resp_buf, resp_len); } else { ret = scm_call2(SCM_SIP_FNID(SCM_SVC_FUSE, SCM_IS_SW_FUSE_BLOWN_ID), &desc); resp_buf = desc.ret[0]; } if (ret) { printk("scm_call/2 returned %d", ret); resp_buf = 0xff; } ic = resp_buf; return resp_buf; } static uint8_t get_tamper_fuse_cmd_new(uint32_t flag) { int ret; uint32_t fuse_id; uint8_t resp_buf; size_t resp_len; struct scm_desc desc = {0}; resp_len = sizeof(resp_buf); desc.args[0] = fuse_id = flag; desc.arginfo = SCM_ARGS(1); if (!is_scm_armv8()) { ret = scm_call(SCM_SVC_FUSE, SCM_IS_SW_FUSE_BLOWN_ID, &fuse_id, sizeof(fuse_id), &resp_buf, resp_len); } else { ret = scm_call2(SCM_SIP_FNID(SCM_SVC_FUSE, SCM_IS_SW_FUSE_BLOWN_ID), &desc); resp_buf = desc.ret[0]; } if (ret) { printk("scm_call/2 returned %d", ret); resp_buf = 0xff; } ic = resp_buf; return resp_buf; } static long tzic_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret = 0; int i = 0; t_flag param; switch(cmd){ case TZIC_IOCTL_GET_FUSE_REQ: LOG(KERN_INFO "[oemflag]get_fuse\n"); ret = get_tamper_fuse_cmd(); LOG(KERN_INFO "[oemflag]tamper_fuse value = %x\n", ret); break; case TZIC_IOCTL_SET_FUSE_REQ: LOG(KERN_INFO "[oemflag]set_fuse\n"); ret = get_tamper_fuse_cmd(); LOG(KERN_INFO "[oemflag]tamper_fuse before = %x\n", ret); LOG(KERN_INFO "[oemflag]ioctl set_fuse\n"); mutex_lock(&tzic_mutex); ret = set_tamper_fuse_cmd(); mutex_unlock(&tzic_mutex); if (ret) LOG(KERN_INFO "[oemflag]failed tzic_set_fuse_cmd: %d\n", ret); ret = get_tamper_fuse_cmd(); LOG(KERN_INFO "[oemflag]tamper_fuse after = %x\n", ret); break; case TZIC_IOCTL_SET_FUSE_REQ_DEFAULT://SET ALL OEM FLAG EXCEPT 0 LOG(KERN_INFO "[oemflag]set_fuse_default\n"); ret=copy_from_user( ¶m, (void *)arg, sizeof(param) ); if(ret) { LOG(KERN_INFO "[oemflag]ERROR copy from user\n"); return ret; } for (i=OEMFLAG_MIN_FLAG+1;i