static ssize_t qfprom_read_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u32 *p_buf = NULL; int ret = 0; if(!qfprom_address){ printk("%s: qfprom address is NULL\n", __func__); return -EINVAL; } p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf){ printk("%s : buffer memory alloc fail\n", __func__); ret = -ENOMEM; } ret = qfuse_read_single_row(qfprom_address, 0, p_buf); qfprom_address = 0; if(ret == 0){ qfprom_lsb_value = p_buf[0]; qfprom_msb_value = p_buf[1]; kfree(p_buf); return count; } else if(ret < 0) printk("%s: scm call fail\n", __func__); else printk("%s: qfprom write status error = %x\n", __func__, ret); kfree(p_buf); return -EINVAL; }
/* this api handle diag command(fusing check command) from ATD * if fusing value 0 ==> is not fused * if fusing value 1 ==> fused (secure boot enable, jtag disable, oem config, hw secondary key, RW permission) */ static ssize_t qfusing_show(struct device* dev, struct device_attribute* attr, char* buf) { int fusing=0; int i,ret; u32 key_status=0; u32* p_buf=NULL; if(fusing_flag==0) { key_status = qfprom_secondary_hwkey_status(); if((key_status&SEC_HW_KEY_BLOWN)!=SEC_HW_KEY_BLOWN) { printk("%s: hw key is not blown\n",__func__); goto err_mem; } else { msleep(10); printk("%s:secondary HW key check complete!!!!!\n",__func__); p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf) { printk("%s: memory alloc fail\n",__func__); goto err_mem; } for(i=0;i<ARRAY_SIZE(blow_data);i++) { if(blow_data[i].qfprom_addr==QFPROM_CHECK_HW_KEY) continue; ret = qfuse_read_single_row(blow_data[i].qfprom_addr,0,p_buf); if(ret!=0) { printk("%s: qfprom 0x%x read fail\n",__func__,blow_data[i].qfprom_addr); goto err; } else { if(((p_buf[0]&blow_data[i].lsb_data)==blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data)==blow_data[i].msb_data)) { printk("%s: 0x%x chekc complete\n",__func__,blow_data[i].qfprom_addr); continue; } else { printk("%s: fusing value is not match\n",__func__); goto err; } msleep(10); } } fusing=1; } } else { if(fusing_flag==FUSING_COMPLETED_STATE) fusing=1; } err: kfree(p_buf); err_mem: return sprintf(buf,"%x\n",fusing); }
u32 qfprom_verification_blow_data(void) { int i, ret; u32 key_status = 0; u32 *p_buf = NULL; u32 fusing_verification=0; p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf) { printk("%s: memory alloc fail\n", __func__); goto err_mem; } for(i=0;i<ARRAY_SIZE(blow_data);i++) { if(blow_data[i].qfprom_addr == QFPROM_CHECK_HW_KEY) { key_status = qfprom_secondary_hwkey_status(); if((key_status&SEC_KEY_DERIVATION_BLOWN) == SEC_KEY_DERIVATION_BLOWN) { fusing_verification |= (0x1<<i); printk("%s: hw key is blown\n", __func__); } printk("%s:secondary HW key check complete!!!!!\n", __func__); continue; } msleep(10); ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf); if(ret != 0) { printk("%s: qfprom 0x%x read fail\n", __func__, blow_data[i].qfprom_addr); continue; } else { if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) { printk("%s: 0x%x check complete\n", __func__, blow_data[i].qfprom_addr); fusing_verification |= (0x1<<i); printk("%s: %d fusing_verification\n",__func__,fusing_verification); } else { printk("%s: 0x%x fusing value is not match\n", __func__,blow_data[i].qfprom_addr); } msleep(10); } } err_mem: kfree(p_buf); return fusing_verification; }
int qfprom_read_one_row(u32 address, u32 *buf) { int ret = 0; printk(KERN_INFO "%s : address %x\n", __func__, address); switch (qfprom_read_kind) { case 0: ret = qfuse_read_single_row(address, 0, buf); break; case 1: ret = 0; buf[0] = qfprom_read(address); buf[1] = qfprom_read(address + 4); break; case 2: /* ret = qfprom_read_from_misc(address, &buf[0], &buf[1]); */ break; } printk(KERN_INFO "%s : return %x\n", __func__, ret); return ret; }
static ssize_t qfprom_sdp_enum_show(struct device* dev, struct device_attribute* attr, char* buf) { int ret; struct qfprom_blow_data sdp_data = { QFPROM_DEBUG_DISABLE, 0x200, 0x0 }; unsigned int mask = 0x00000200; u32* p_buf=NULL; p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf) { printk("%s: memory alloc fail\n",__func__); ret=-EINVAL; return -EINVAL; } ret = qfuse_read_single_row(sdp_data.qfprom_addr,0,p_buf); if(ret!=0) { printk("%s: qfprom 0x%x read fail\n", __func__, sdp_data.qfprom_addr); kfree(p_buf); return -EINVAL; } printk("%s: sdp_enum is lsb : %x, msb : %x\n", __func__, p_buf[0]&sdp_data.lsb_data, p_buf[1]&sdp_data.msb_data); ret = (p_buf[0]&sdp_data.lsb_data & mask) >> 9; kfree(p_buf); return sprintf(buf,"%d", ret); }
int qfprom_blow_secondary_hwkey_region(void) { int ret; u32 addr, lsb, msb; int i; u32 *p_buf = NULL; p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf){ printk("%s : buffer memory alloc fail\n", __func__); return -ENOMEM; } /* we check read permission * if read permission region is blown, we can see all hw secondary key is blown * because permission fuse is follow to secondary hw key */ ret = qfuse_read_single_row(QFPROM_RD_WR_PERMISSION, 0, p_buf); if(ret != 0){ printk("%s: qfuse addr %x read fail, ret=%d\n", __func__, QFPROM_RD_WR_PERMISSION, ret); ret = -EINVAL; goto err; } if((p_buf[0]&0x0C000000) == 0x0C000000) { printk("%s: All hw key was written already\n", __func__); ret = 0; goto err; } addr = QFPROM_SECONDARY_HW_KEY; for(i=0;i<7;i++){ /* we can read hw secondary key region because before read permission is set */ /* ret = qfuse_read_single_row(addr, 0, p_buf); if(ret != 0){ printk("%s: qfuse addr %x read fail, ret=%d\n", __func__, addr,ret); ret = -EINVAL; goto err; } printk("%s:Currently, secondary key addr=0x%x, lsb=0x%x, msb=0x%x\n", __func__, addr,p_buf[0], p_buf[1]); */ msleep(10); /* if you have not written ever hw key before, value to read will be zero * so create random using tzbsp * LSB region */ if(!p_buf[0]){ lsb = qfprom_create_random(); if(!lsb) { ret = -EINVAL; goto err; } msleep(5); } else { /* dont create random value and rewrite value to read */ printk("hw lsb key was blow already in 0x%x addr\n", addr); lsb = p_buf[0]; } /* if you have not written ever hw key before, value to read will be zero * so create random using tzbsp * MSB region */ if(!p_buf[1]) { msb = qfprom_create_random(); if(!msb) { ret = -EINVAL; goto err; } msleep(5); } else { printk("hw msb key was blow already in 0x%x addr\n", addr+4); msb = p_buf[1]; } /* must mask FEC bit */ lsb = lsb&HW_KEY_LSB_FEC_MASK; msb = msb&HW_KEY_MSB_FEC_MASK; printk("We start to writing secondary key !!!\n"); printk("addr=0x%x, lsb=0x%x, msb=0x%x\n", addr, lsb, msb); msleep(10); ret = qfuse_write_single_row(addr, lsb, msb); if(ret != 0) { printk("%s:qfus addr 0x%x write error, ret=%d\n", __func__, addr, ret); ret = -EINVAL; goto err; } else { /* write double check routine */ printk("hw secondary key write successful\n"); msleep(10); /* ret = qfuse_read_single_row(addr, 0, p_buf); if(ret != 0) { printk("%s:read fail when double check routine, ret=%d\n", __func__, ret); goto err; } if((p_buf[0]==lsb)&&(p_buf[1]==msb)) printk("%s: hw key write double check successful!!!!!!!\n",__func__); else { printk("%s: hw key double check error, read_lsb=0x%x,read_msb=0x%x\n",__func__,p_buf[0],p_buf[1]); ret = -EINVAL; goto err; } */ } addr = addr+8; msleep(10); } err: kfree(p_buf); return ret; }
/* this api handle diag command(fusing command) from ATD * this api fuse secure boot, jtag disable, oem config, secondary hw key, R/W permission * this api check secondary hw key status before fusing R/W permission */ static ssize_t qfusing_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; int i = 0; u32 *p_buf = NULL; u32 fusing_flag=0; if(!sysfs_streq(buf, "fusing")){ printk("%s:argument fault\n", __func__); ret = -EINVAL; goto err; } p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL); if(!p_buf) { printk("%s: memory alloc fail\n", __func__); ret = -EINVAL; goto err;; } for(i=0;i<ARRAY_SIZE(blow_data);i++){ if(blow_data[i].qfprom_addr==QFPROM_CHECK_HW_KEY) { /* We dont check secondary hw key status * But qfprom_blow secondary_hwkey_region api does not create random if qfprom block was written * The api create random if was not written only * So HW key region to be written is not written by new random key * The reason to not check hw key status reg is to check 7 hw key block to be written */ ret = qfprom_blow_secondary_hwkey_region(); if(ret < 0) { printk("%s: hw key region blow error\n", __func__); goto err_fuse; } fusing_flag |= (0x1<<i); printk("%s: HW secondary key region is blown successfully\n", __func__); continue; } msleep(10); ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf); if(ret != 0) { printk("%s: qfprom addr %x read fail, ret=%d\n", __func__, blow_data[i].qfprom_addr, ret); goto err_fuse; } printk("%s:read addr 0x%x, lsb 0x%x, msb 0x%x\n", __func__, blow_data[i].qfprom_addr, p_buf[0], p_buf[1]); /* Don't rewrite if value to read is same value to write */ if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) { printk("%s: 0x%x was blown already\n", __func__, blow_data[i].qfprom_addr); } else { msleep(10); ret = qfuse_write_single_row(blow_data[i].qfprom_addr, blow_data[i].lsb_data, blow_data[i].msb_data); if(ret != 0) { printk("%s: qfuse addr %x blow write error!!!\n", __func__, blow_data[i].qfprom_addr); ret = -EINVAL; goto err_fuse; } else { /* double check routine*/ msleep(10); printk("%s: qfprom 0x%x addr write double check routine\n", __func__, blow_data[i].qfprom_addr); ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf); if(ret != 0) { printk("%s: read fail when double check, ret=%d\n", __func__, ret); ret = -EINVAL; goto err_fuse; } if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) { printk("%s:write double check successfully", __func__); } else { printk("%s:qfprom write successful but error when double check\n", __func__); ret = -EINVAL; goto err_fuse; } } } fusing_flag |= (0x1<<i); } printk("%s: fusing flag = 0x%x\n", __func__, fusing_flag); printk("%s: fusing complete!!!!!!!!!!!!!!!!!!!!\n", __func__); kfree(p_buf); return count; err_fuse: kfree(p_buf); err: return ret; }
/* this api handle diag command(fusing check command) from ATD * if fusing value 0 ==> is not fused * if fusing value 1 ==> fused (secure boot enable, jtag disable, * oem config, hw secondary key, RW permission) */ static ssize_t qfusing_show(struct device *dev, struct device_attribute *attr, char *buf) { int fusing = 0; int i, ret; u32 key_status = 0; u32 *p_buf = NULL; if(fusing_flag==0) { //////////////////////////////////////// // workaround for apq8064 // // hardcoding to understand easily.// p_buf = kmalloc(sizeof(u32) * 2, GFP_KERNEL); if (!p_buf) { printk("%s: memory alloc fail\n", __func__); goto err_mem; } memset(p_buf, 0x00, sizeof(u32) * 2); msleep(10); ret = qfuse_read_single_row(QFPROM_DEBUG_ENABLE, 0, p_buf); printk("%s: addr = 0x%x LSB = 0x%x MSB = 0x%x\n", __func__, QFPROM_DEBUG_ENABLE, p_buf[0], p_buf[1]); if (ret != 0) { printk("%s: qfprom read fail error=%d\n", __func__,ret); kfree(p_buf); goto err_mem; } if ((p_buf[0] == 0xC1000000) && (p_buf[1] == 0x0000006F)) { printk("old versionwill be passed unquestioningly for factory process"); goto workaround_for_old_apq8064; } else if ((p_buf[0] == 0xC1300000) && (p_buf[1]== 0x0000006F)) { printk("new version will be passed unquestioningly for factory process"); goto workaround_for_new_apq8064; } else { printk("empty or strange will be passed unquestioningly for factory process"); goto workaround_for_new_apq8064; } //////////////////////////////////////// workaround_for_new_apq8064: key_status = qfprom_secondary_hwkey_status(); if ((key_status & SEC_HW_KEY_BLOWN) != SEC_HW_KEY_BLOWN) { printk("%s: hw key is not blown\n",__func__); goto err; } else { msleep(10); printk("%s:secondary HW key check complete!!!!!\n",__func__); workaround_for_old_apq8064: for (i = 0; i < ARRAY_SIZE(blow_data); i++) { if (blow_data[i].qfprom_addr == QFPROM_CHECK_HW_KEY) continue; memset(p_buf, 0x00, sizeof(u32) * 2); msleep(10); ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf); printk("%s: addr = 0x%x LSB = 0x%x MSB = 0x%x\n", __func__, blow_data[i].qfprom_addr, p_buf[0], p_buf[1]); if (ret != 0) { printk("%s: qfprom read fail error=%d\n", __func__,ret); goto err; } else { //////////////////////////////////////// // workaround for apq8064 // // hardcoding to understand easily.// if (blow_data[i].qfprom_addr == QFPROM_DEBUG_ENABLE) { if ((p_buf[0] == 0xC1000000) && (p_buf[1] == 0x0000006F)) { printk("old version will be passed unquestioningly for factory process"); continue; } } /////////////////////////////////////// if(((p_buf[0]&blow_data[i].lsb_data)==blow_data[i].lsb_data) && ((p_buf[1]&blow_data[i].msb_data)==blow_data[i].msb_data)) { printk("%s: 0x%x chekc complete\n",__func__,blow_data[i].qfprom_addr); continue; } else { printk ("%s: fusing value is not match\n", __func__); goto err; } msleep(10); } } fusing = 1; } } else { if(fusing_flag==FUSING_COMPLETED_STATE) fusing=1; } err: kfree(p_buf); err_mem: return sprintf(buf, "%x\n", fusing); }