/* ******************************************************************************* * __erase_part * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __erase_part(char *name) { void *addr = (void *)FASTBOOT_ERASE_BUFFER; u32 start, unerased_sectors; u32 nblock = FASTBOOT_ERASE_BUFFER_SIZE/512; char response[68]; start = sunxi_partition_get_offset_byname(name); unerased_sectors = sunxi_partition_get_size_byname(name); if((!start) || (!unerased_sectors)) { printf("sunxi fastboot erase FAIL: partition %s does not exist\n", name); sprintf(response, "FAILerase: partition %s does not exist", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } memset(addr, 0xff, FASTBOOT_ERASE_BUFFER_SIZE); while(unerased_sectors >= nblock) { if(!sunxi_flash_write(start, nblock, addr)) { printf("sunxi fastboot erase FAIL: failed to erase partition %s \n", name); sprintf(response,"FAILerase: failed to erase partition %s", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } start += nblock; unerased_sectors -= nblock; } if(unerased_sectors) { if(!sunxi_flash_write(start, unerased_sectors, addr)) { printf("sunxi fastboot erase FAIL: failed to erase partition %s \n", name); sprintf(response,"FAILerase: failed to erase partition %s", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } } printf("sunxi fastboot: partition '%s' erased\n", name); sprintf(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); return 0; }
int do_sunxi_boot_signature(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int ret; int m_ok = 1; ret = signature_verify("boot"); if(!ret) { ret = signature_verify("system"); } if(ret) { printf("signature verify failed\n"); __u32 private_start; __u32 private_size; __u32 erase_block_once=SIG_ERASE_BUFFER_SIZE; char last_back[SIG_SMALL_BUFFER_SIZE]; char* private_data = NULL; private_start = sunxi_partition_get_offset_byname("private"); private_size = sunxi_partition_get_size_byname("private") * 512; private_data = malloc(SIG_ERASE_BUFFER_SIZE); if(!private_data) { printf("not enough memory for sig erase\n"); private_data = last_back; erase_block_once = SIG_SMALL_BUFFER_SIZE; m_ok = 0; } memset(private_data,0xff,erase_block_once); while(private_size>=erase_block_once) { sunxi_flash_write(private_start,erase_block_once/512,private_data); private_start += erase_block_once/512; private_size -= erase_block_once; } if(private_size) { sunxi_flash_write(private_start,private_size/512,private_data); } if(m_ok) { free(private_data); } } return 0; }
int sunxi_flash_read_bootlogo(u32 start, int buf, const char *part_name) { int ret; u32 rblock; u32 start_block = start; void *addr; addr = (void *)buf; start_block = sunxi_partition_get_offset_byname((const char *)part_name); rblock = sunxi_partition_get_size_byname((const char *)part_name); ret = sunxi_flash_read(start_block, rblock, (void *)addr); if(ret != 0) { printf("read bootlogo partition successful,start_block=0x%x,rblock=0x%x ,ret=%d\n",start_block,rblock,ret); } else { printf("read bootlogo partition fail,start_block=0x%x,rblock=0x%x ,ret=%d\n",start_block,rblock,ret); } return ret; }
int sunxi_keydata_burn_by_usb(void) { char buffer[512]; #ifdef CONFIG_SUNXI_SECURE_STORAGE #ifndef SUNXI_SECURESTORAGE_TEST_ERASE int data_len; #endif #endif int ret; uint burn_private_start, burn_private_len; int workmode = uboot_spare_head.boot_data.work_mode; int if_need_burn_key=0; ret = script_parser_fetch("target", "burn_key", &if_need_burn_key, 1); if((ret) || (if_need_burn_key != 1)) { return 0; } if(workmode != WORK_MODE_BOOT) //非启动模式,不执行 { puts("out of usb burn from boot: not boot mode\n"); return 0; } if(gd->vbus_status == SUNXI_VBUS_NOT_EXIST) //vbus不存在,不执行 { puts("out of usb burn from boot: without usb\n"); return 0; } if(gd->power_step_level == BATTERY_RATIO_TOO_LOW_WITH_DCIN) { puts("out of usb burn from boot: not enough energy\n"); return 0; } memset(buffer, 0, 512); #ifdef CONFIG_SUNXI_SECURE_STORAGE if(sunxi_secure_storage_init()) #endif { printf("sunxi secure storage is not supported\n"); burn_private_start = sunxi_partition_get_offset_byname("private"); burn_private_len = sunxi_partition_get_size_byname("private"); if(!burn_private_start) { printf("private partition is not exist\n"); return -1; } else { ret = sunxi_flash_read(burn_private_start + burn_private_len - (8192+512)/512, 1, buffer); if(ret != 1) { printf("cant read private part\n"); return -1; } if(!strcmp(buffer, "key_burned")) { printf("find key burned flag\n"); return 0; } } } #ifdef CONFIG_SUNXI_SECURE_STORAGE else { #ifndef SUNXI_SECURESTORAGE_TEST_ERASE ret = sunxi_secure_storage_read("key_burned_flag", buffer, 512, &data_len); if(ret) { printf("sunxi secure storage has no flag\n"); } else { if(!strcmp(buffer, "key_burned")) { printf("wrn: data has clean\n"); return 0; } } #else if(!sunxi_secure_storage_erase_data_only("key_burned_flag")) sunxi_secure_storage_exit(); return 0; #endif } #endif return do_burn_from_boot(NULL, 0, 0, NULL); }
/* ******************************************************************************* * __flash_to_part * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __flash_to_part(char *name) { char *addr = trans_data.base_recv_buffer; u32 start, data_sectors; u32 part_sectors; u32 nblock = FASTBOOT_TRANSFER_BUFFER_SIZE/512; char response[68]; start = sunxi_partition_get_offset_byname(name); part_sectors = sunxi_partition_get_size_byname(name); if((!start) || (!part_sectors)) { uint addr_in_hex; int ret; printf("sunxi fastboot download FAIL: partition %s does not exist\n", name); printf("probe it as a dram address\n"); ret = strict_strtoul((const char *)name, 16, (long unsigned int*)&addr_in_hex); if(ret) { printf("sunxi fatboot download FAIL: it is not a dram address\n"); sprintf(response, "FAILdownload: partition %s does not exist", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } else { printf("ready to move data to 0x%x, bytes 0x%x\n", addr_in_hex, trans_data.try_to_recv); memcpy((void *)addr_in_hex, addr, trans_data.try_to_recv); } } else { int format; printf("ready to download bytes 0x%x\n", trans_data.try_to_recv); format = unsparse_probe(addr, trans_data.try_to_recv, start); if(ANDROID_FORMAT_DETECT == format) { if(unsparse_direct_write(addr, trans_data.try_to_recv)) { printf("sunxi fastboot download FAIL: failed to write partition %s \n", name); sprintf(response,"FAILdownload: write partition %s err", name); return -1; } } else { data_sectors = (trans_data.try_to_recv + 511)/512; if(data_sectors > part_sectors) { printf("sunxi fastboot download FAIL: partition %s size 0x%x is smaller than data size 0x%x\n", name, trans_data.act_recv, data_sectors * 512); sprintf(response, "FAILdownload: partition size < data size"); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } while(data_sectors >= nblock) { if(!sunxi_flash_write(start, nblock, addr)) { printf("sunxi fastboot download FAIL: failed to write partition %s \n", name); sprintf(response,"FAILdownload: write partition %s err", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } start += nblock; data_sectors -= nblock; addr += FASTBOOT_TRANSFER_BUFFER_SIZE; } if(data_sectors) { if(!sunxi_flash_write(start, data_sectors, addr)) { printf("sunxi fastboot download FAIL: failed to write partition %s \n", name); sprintf(response,"FAILdownload: write partition %s err", name); __sunxi_fastboot_send_status(response, strlen(response)); return -1; } } } } printf("sunxi fastboot: successed in downloading partition '%s'\n", name); sprintf(response, "OKAY"); __sunxi_fastboot_send_status(response, strlen(response)); return 0; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_pburn_state_loop(void *buffer) { static struct umass_bbb_cbw_t *cbw; static struct umass_bbb_csw_t csw; static uint pburn_flash_start = 0; //static uint pburn_flash_sectors = 0; int ret; sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer; switch(sunxi_usb_pburn_status) { case SUNXI_USB_PBURN_IDLE: if(sunxi_ubuf->rx_ready_for_data == 1) { sunxi_usb_pburn_status = SUNXI_USB_PBURN_SETUP; } break; case SUNXI_USB_PBURN_SETUP: sunxi_usb_dbg("SUNXI_USB_PBURN_SETUP\n"); if(sunxi_ubuf->rx_req_length != sizeof(struct umass_bbb_cbw_t)) { printf("sunxi usb error: received bytes 0x%x is not equal cbw struct size 0x%zx\n", sunxi_ubuf->rx_req_length, sizeof(struct umass_bbb_cbw_t)); sunxi_ubuf->rx_ready_for_data = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; break; } cbw = (struct umass_bbb_cbw_t *)sunxi_ubuf->rx_req_buffer; if(CBWSIGNATURE != cbw->dCBWSignature) { printf("sunxi usb error: the cbw signature 0x%x is bad, need 0x%x\n", cbw->dCBWSignature, CBWSIGNATURE); sunxi_ubuf->rx_ready_for_data = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; break; } csw.dCSWSignature = CSWSIGNATURE; csw.dCSWTag = cbw->dCBWTag; #if defined(SUNXI_USB_30) sunxi_usb_pburn_status_enable = 1; #endif sunxi_usb_dbg("usb cbw command = 0x%x\n", cbw->CBWCDB[0]); switch(cbw->CBWCDB[0]) { #ifdef CONFIG_SUNXI_SECURE_STORAGE case 0xf0: //自定义命令,用于烧录用户数据 sunxi_usb_dbg("usb burn secure storage data\n"); printf("usb command = %d\n", cbw->CBWCDB[1]); switch(cbw->CBWCDB[1]) { case 0: //握手 { __usb_handshake_sec_t *handshake = (__usb_handshake_sec_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_sec_t)); strcpy(handshake->magic, "usb_burn_handshake"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t)); sunxi_usb_burn_from_boot_setup = 1; private_data_ext_buff = (u8 *)malloc(4 * 1024 * 1024); if(private_data_ext_buff == NULL) { printf("there is no memorfy to store all user key data\n"); csw.bCSWStatus = -1; } else { csw.bCSWStatus = 0; sunxi_usb_burn_from_boot_handshake = 1; } private_data_ext_buff_step = private_data_ext_buff; } break; case 1: //小机端接收数据 { trans_data.recv_size = cbw->dCBWDataTransferLength; sunxi_usb_pburn_write_enable = 0; sunxi_udc_start_recv_by_dma(private_data_ext_buff_step, trans_data.recv_size); //start dma to receive data printf("recv_size=%d\n", trans_data.recv_size); sunxi_dump(private_data_ext_buff, trans_data.recv_size); sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_NULL; } break; case 2: //工具端声明数据传输已经完毕,要求获取烧录状态 { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); //strcpy(handshake->magic, "usb_burn_receive_data_all"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; printf("recv_size=%d\n", trans_data.recv_size); sunxi_dump(private_data_ext_buff, trans_data.recv_size); int ret = __sunxi_burn_key(private_data_ext_buff, trans_data.recv_size); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); //开始根据数据类型进行烧录动作 if(!ret) //数据烧写成功 { strcpy(handshake->magic, "usb_burn_success"); csw.bCSWStatus = 0; } else //数据烧写失败 { strcpy(handshake->magic, "usb_burn_error"); csw.bCSWStatus = -1; } if(private_data_ext_buff) { free(private_data_ext_buff); } } break; // case 3: //小机端读取每个key // { // uint start, sectors; // uint offset; // // start = *(int *)(cbw->CBWCDB + 4); //读数据的偏移量 // sectors = *(int *)(cbw->CBWCDB + 8); //扇区数; // // trans_data.send_size = min(cbw->dCBWDataTransferLength, sectors * 512); // trans_data.act_send_buffer = (uint)trans_data.base_send_buffer; // // offset = burn_private_start; // ret = sunxi_flash_read(start + offset, sectors, trans_data.base_send_buffer); // if(!ret) // { // printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors); // // csw.bCSWStatus = 1; // } // else // { // csw.bCSWStatus = 0; // } // // sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; // } // break; case 4: //关闭usb { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_finish"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size); csw.bCSWStatus = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT; } break; case 5: { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_saved"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); csw.bCSWStatus = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; if(sunxi_secure_storage_write("key_burned_flag", "key_burned", strlen("key_burned"))) { printf("save burned flag err\n"); csw.bCSWStatus = -1; } sunxi_secure_storage_exit(); } break; default: break; } break; #endif case 0xf3: //自定义命令,用于烧录用户数据 sunxi_usb_dbg("usb burn private\n"); printf("usb command = %d\n", cbw->CBWCDB[1]); switch(cbw->CBWCDB[1]) { case 0: //握手 { __usb_handshake_t *handshake = (__usb_handshake_t *)trans_data.base_send_buffer; burn_private_start = sunxi_partition_get_offset_byname("private"); burn_private_len = sunxi_partition_get_size_byname("private"); if(!burn_private_start) { printf("private partition is not exist\n"); csw.bCSWStatus = -1; } else { csw.bCSWStatus = 0; } memset(handshake, 0, sizeof(__usb_handshake_t)); strcpy(handshake->magic, "usb_burn_handshake"); handshake->sizelo = burn_private_len; handshake->sizehi = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; sunxi_usb_burn_from_boot_setup = 1; sunxi_usb_burn_from_boot_handshake = 1; trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_t)); } break; case 1: //小机端接收数据 { //pburn_flash_sectors = *(int *)(cbw->CBWCDB + 8); //pburn_flash_start = *(int *)(cbw->CBWCDB + 4); memcpy(&pburn_flash_start,(cbw->CBWCDB + 4),4); trans_data.recv_size = cbw->dCBWDataTransferLength; trans_data.act_recv_buffer = trans_data.base_recv_buffer; pburn_flash_start += burn_private_start; sunxi_usb_pburn_write_enable = 0; sunxi_udc_start_recv_by_dma(trans_data.act_recv_buffer, trans_data.recv_size); //start dma to receive data sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA; } break; case 3: //小机端发送数据 { uint start, sectors; //start = *(int *)(cbw->CBWCDB + 4); //读数据的偏移量 //sectors = *(int *)(cbw->CBWCDB + 8); //扇区数; memcpy(&start,(cbw->CBWCDB + 4),4); memcpy(§ors,(cbw->CBWCDB + 8),4); printf("start=%d, sectors=%d\n", start, sectors); trans_data.send_size = min(cbw->dCBWDataTransferLength, sectors * 512); trans_data.act_send_buffer = trans_data.base_send_buffer; printf("send size=%d\n", trans_data.send_size); ret = sunxi_flash_read(start + burn_private_start, sectors, trans_data.base_send_buffer); if(!ret) { printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors); csw.bCSWStatus = 1; } else { csw.bCSWStatus = 0; } sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; } break; case 4: //关闭usb { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_finish"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size); csw.bCSWStatus = 0; sunxi_flash_flush(); sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT; } break; case 5: { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; char buffer[512]; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_saved"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); csw.bCSWStatus = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; memset(buffer, 0, 512); strcpy(buffer, "key_burned"); if(!sunxi_flash_write(burn_private_start + burn_private_len - (8192+512)/512, 1, buffer)) { printf("save burned flag err\n"); csw.bCSWStatus = -1; } sunxi_flash_flush(); #ifdef CONFIG_SUNXI_SECURE_STORAGE if(sunxi_secure_storage_init()) { printf("init secure storage failed\n"); csw.bCSWStatus = -1; } else { if(sunxi_secure_storage_write("key_burned_flag", "key_burned", strlen("key_burned"))) { printf("save burned flag err\n"); csw.bCSWStatus = -1; } } sunxi_secure_storage_exit(); #endif } break; default: break; } break; default: sunxi_usb_dbg("not supported command 0x%x now\n", cbw->CBWCDB[0]); sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength); csw.bCSWStatus = 1; sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; break; } break; case SUNXI_USB_PBURN_SEND_DATA: sunxi_usb_dbg("SUNXI_USB_SEND_DATA\n"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; printf("SUNXI_USB_SEND_DATA=%d\n", trans_data.send_size); sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size); #if defined(SUNXI_USB_30) sunxi_usb_pburn_status_enable = 0; #endif break; case SUNXI_USB_PBURN_RECEIVE_DATA: sunxi_usb_dbg("SUNXI_USB_RECEIVE_DATA\n"); if(sunxi_usb_pburn_write_enable == 1) { sunxi_usb_dbg("write flash, start 0x%x, sectors 0x%x\n", pburn_flash_start, trans_data.recv_size/512); ret = sunxi_flash_write(pburn_flash_start, (trans_data.recv_size+511)/512, (void *)trans_data.act_recv_buffer); if(!ret) { printf("sunxi flash write err: start,0x%x sectors 0x%x\n", pburn_flash_start, (trans_data.recv_size+511)/512); csw.bCSWStatus = 1; } else { csw.bCSWStatus = 0; } sunxi_usb_pburn_write_enable = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; } break; case SUNXI_USB_PBURN_STATUS: sunxi_usb_dbg("SUNXI_USB_PBURN_STATUS\n"); #if defined(SUNXI_USB_30) if(sunxi_usb_pburn_status_enable) #endif { sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; sunxi_ubuf->rx_ready_for_data = 0; __sunxi_pburn_send_status(&csw, sizeof(struct umass_bbb_csw_t)); } break; case SUNXI_USB_PBURN_EXIT: printf("SUNXI_USB_PBURN_EXIT\n"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; sunxi_ubuf->rx_ready_for_data = 0; __sunxi_pburn_send_status(&csw, sizeof(struct umass_bbb_csw_t)); printf("Device will shutdown in 3 Secends...\n"); __msdelay(3000); return SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN; case SUNXI_USB_PBURN_RECEIVE_NULL: sunxi_usb_dbg("SUNXI_USB_PBURN_RECEIVE_NULL\n"); if(sunxi_usb_pburn_write_enable == 1) { csw.bCSWStatus = 0; sunxi_usb_pburn_write_enable = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; } break; default: break; } return 0; }