2134 lines
58 KiB
C
Executable File
2134 lines
58 KiB
C
Executable File
/*
|
|
* (C) Copyright 2007-2013
|
|
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
|
* Jerry Wang <wangflord@allwinnertech.com>
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*/
|
|
#include "usb_base.h"
|
|
#include <scsi.h>
|
|
#include <asm/arch/dma.h>
|
|
#include <sys_partition.h>
|
|
#include <boot_type.h>
|
|
#include "usb_burn.h"
|
|
#include "usb_efex.h"
|
|
#include <smc.h>
|
|
#include <securestorage.h>
|
|
#include <sunxi_board.h>
|
|
#include "key_deal.h"
|
|
#include <smc.h>
|
|
#include "../sprite/sprite_verify.h"
|
|
#include <sys_config.h>
|
|
#include <sys_config_old.h>
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
volatile int sunxi_usb_burn_from_boot_handshake, sunxi_usb_burn_from_boot_init, sunxi_usb_burn_from_boot_setup;
|
|
|
|
__attribute__((weak))
|
|
int sunxi_key_ladder_verify_rotpk_hash(void *input_hash_buf, int len)
|
|
{
|
|
printf("call weak fun: %s\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
__attribute__((weak))
|
|
int smc_set_sst_crypt_name(char *name)
|
|
{
|
|
printf("call weak fun: %s\n",__func__);
|
|
return 0;
|
|
}
|
|
|
|
__attribute__((weak))
|
|
int sunxi_verify_rotpk_hash(void *input_hash_buf, int len)
|
|
{
|
|
printf("call weak fun: %s\n",__func__);
|
|
return -1;
|
|
}
|
|
|
|
__attribute__((weak))
|
|
int sunxi_deal_hdcp_key(char *keydata, int keylen)
|
|
{
|
|
printf("call weak fun: %s\n",__func__);
|
|
return 0;
|
|
}
|
|
|
|
__attribute__((weak))
|
|
int sunxi_secure_object_down( const char *name , char *buf, int len, int encrypt, int write_protect)
|
|
|
|
{
|
|
printf("call weak fun: %s\n",__func__);
|
|
return 0;
|
|
}
|
|
|
|
__attribute__((weak))
|
|
int sunxi_efuse_write(void *key_buf)
|
|
{
|
|
printf("call weak fun: %s\n",__func__);
|
|
return -1;
|
|
}
|
|
|
|
__attribute__((weak))
|
|
int sunxi_efuse_read(void *key_name, void *read_buf,int *len)
|
|
{
|
|
printf("call weak fun: %s\n",__func__);
|
|
return -1;
|
|
}
|
|
|
|
static int sunxi_usb_pburn_write_enable = 0;
|
|
#if defined(SUNXI_USB_30)
|
|
static int sunxi_usb_pburn_status_enable = 1;
|
|
#endif
|
|
static int sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
|
|
|
|
static pburn_trans_set_t trans_data;
|
|
#define DATA_BUFFER_MAX_SIZE (1*1024*1024)
|
|
|
|
static u8 *private_data_ext_buff_step = NULL;
|
|
static u8 *private_data_ext_buff = NULL;
|
|
|
|
static int burn_part_result_state = ERR_NO_SUCCESS;
|
|
long long burn_part_bytes = 0;
|
|
static int fel_verify = 0;
|
|
extern volatile int sunxi_usb_burn_from_boot_handshake;
|
|
extern volatile int sunxi_usb_probe_update_action;
|
|
extern volatile int sunxi_usb_burn_from_boot_setup;
|
|
static uint burn_private_start, burn_private_len;
|
|
static uint burn_part_start, burn_part_len;
|
|
extern int sunxi_get_securemode(void);
|
|
#ifdef CONFIG_BURN_NORMAL_EFUSE
|
|
extern int sunxi_efuse_write(void *key_buf);
|
|
extern int sunxi_efuse_read(void *key_name, void *read_buf,int *len);
|
|
#endif
|
|
|
|
static int sunxi_find_key(char *name)
|
|
{
|
|
if (!strcmp(name, "widevine"))
|
|
return 1;
|
|
else if (!strcmp(name, "ec_key"))
|
|
return 2;
|
|
else if (!strcmp(name, "rsa_key"))
|
|
return 3;
|
|
else if (!strcmp(name, "ec_cert1"))
|
|
return 4;
|
|
else if (!strcmp(name, "ec_cert2"))
|
|
return 5;
|
|
else if (!strcmp(name, "ec_cert3"))
|
|
return 6;
|
|
else if (!strcmp(name, "rsa_cert1"))
|
|
return 7;
|
|
else if (!strcmp(name, "rsa_cert2"))
|
|
return 8;
|
|
else if (!strcmp(name, "rsa_cert3"))
|
|
return 9;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void set_usb_burn_boot_init_flag(int flag )
|
|
{
|
|
sunxi_usb_burn_from_boot_init = flag;
|
|
}
|
|
|
|
static int hex2char(void *dst, void *src,int len)
|
|
{
|
|
int i;
|
|
char *p_out = dst ,*p_in = src;
|
|
|
|
if ((src ==NULL)||(dst == NULL))
|
|
return -1;
|
|
|
|
memset(dst,0x00,len*2);
|
|
for(i=0;i<len;i++)
|
|
{
|
|
sprintf(p_out,"%02x",p_in[i]);
|
|
p_out += 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*******************************************************************************
|
|
* do_usb_req_set_interface
|
|
*
|
|
* Description:
|
|
* void
|
|
*
|
|
* Parameters:
|
|
* void
|
|
*
|
|
* Return value:
|
|
* void
|
|
*
|
|
* note:
|
|
* void
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static int __usb_set_interface(struct usb_device_request *req)
|
|
{
|
|
sunxi_usb_dbg("set interface\n");
|
|
/* Only support interface 0, alternate 0 */
|
|
if((0 == req->wIndex) && (0 == req->wValue))
|
|
{
|
|
sunxi_udc_ep_reset();
|
|
}
|
|
else
|
|
{
|
|
printf("err: invalid wIndex and wValue, (0, %d), (0, %d)\n", req->wIndex, req->wValue);
|
|
return SUNXI_USB_REQ_OP_ERR;
|
|
}
|
|
|
|
return SUNXI_USB_REQ_SUCCESSED;
|
|
}
|
|
|
|
/*
|
|
*******************************************************************************
|
|
* do_usb_req_set_address
|
|
*
|
|
* Description:
|
|
* void
|
|
*
|
|
* Parameters:
|
|
* void
|
|
*
|
|
* Return value:
|
|
* void
|
|
*
|
|
* note:
|
|
* void
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static int __usb_set_address(struct usb_device_request *req)
|
|
{
|
|
uchar address;
|
|
|
|
address = req->wValue & 0x7f;
|
|
#ifdef CONFIG_ARCH_SUN3IW1P1
|
|
/* after enable mmu/dcache, usb may not work well if debug_level=0 */
|
|
int debug_level = get_sunxi_debug_level();
|
|
set_sunxi_debug_level(1);
|
|
printf("set address 0x%x\n", address);
|
|
set_sunxi_debug_level(debug_level);
|
|
#else
|
|
printf("set address 0x%x\n", address);
|
|
#endif
|
|
sunxi_udc_set_address(address);
|
|
|
|
return SUNXI_USB_REQ_SUCCESSED;
|
|
}
|
|
|
|
/*
|
|
*******************************************************************************
|
|
* do_usb_req_set_configuration
|
|
*
|
|
* Description:
|
|
* void
|
|
*
|
|
* Parameters:
|
|
* void
|
|
*
|
|
* Return value:
|
|
* void
|
|
*
|
|
* note:
|
|
* void
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static int __usb_set_configuration(struct usb_device_request *req)
|
|
{
|
|
sunxi_usb_dbg("set configuration\n");
|
|
/* Only support 1 configuration so nak anything else */
|
|
if (1 == req->wValue)
|
|
{
|
|
sunxi_udc_ep_reset();
|
|
}
|
|
else
|
|
{
|
|
printf("err: invalid wValue, (0, %d)\n", req->wValue);
|
|
|
|
return SUNXI_USB_REQ_OP_ERR;
|
|
}
|
|
|
|
sunxi_udc_set_configuration(req->wValue);
|
|
|
|
return SUNXI_USB_REQ_SUCCESSED;
|
|
}
|
|
/*
|
|
*******************************************************************************
|
|
* do_usb_req_get_descriptor
|
|
*
|
|
* Description:
|
|
* void
|
|
*
|
|
* Parameters:
|
|
* void
|
|
*
|
|
* Return value:
|
|
* void
|
|
*
|
|
* note:
|
|
* void
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static int __usb_get_descriptor(struct usb_device_request *req, uchar *buffer)
|
|
{
|
|
int ret = SUNXI_USB_REQ_SUCCESSED;
|
|
|
|
//获取描述符
|
|
switch(req->wValue >> 8)
|
|
{
|
|
case USB_DT_DEVICE: //设备描述符
|
|
{
|
|
struct usb_device_descriptor *dev_dscrptr;
|
|
|
|
sunxi_usb_dbg("get device descriptor\n");
|
|
|
|
dev_dscrptr = (struct usb_device_descriptor *)buffer;
|
|
memset((void *)dev_dscrptr, 0, sizeof(struct usb_device_descriptor));
|
|
|
|
dev_dscrptr->bLength = MIN(req->wLength, sizeof (struct usb_device_descriptor));
|
|
dev_dscrptr->bDescriptorType = USB_DT_DEVICE;
|
|
#ifdef CONFIG_USB_1_1_DEVICE
|
|
dev_dscrptr->bcdUSB = 0x110;
|
|
#else
|
|
dev_dscrptr->bcdUSB = 0x200;
|
|
#endif
|
|
dev_dscrptr->bDeviceClass = 0;
|
|
dev_dscrptr->bDeviceSubClass = 0;
|
|
dev_dscrptr->bDeviceProtocol = 0;
|
|
dev_dscrptr->bMaxPacketSize0 = 0x40;
|
|
dev_dscrptr->idVendor = DRIVER_VENDOR_ID;
|
|
dev_dscrptr->idProduct = DRIVER_PRODUCT_ID;
|
|
dev_dscrptr->bcdDevice = 0xffff;
|
|
//ignored
|
|
//dev_dscrptr->iManufacturer = SUNXI_USB_STRING_IMANUFACTURER;
|
|
//dev_dscrptr->iProduct = SUNXI_USB_STRING_IPRODUCT;
|
|
//dev_dscrptr->iSerialNumber = SUNXI_USB_STRING_ISERIALNUMBER;
|
|
dev_dscrptr->iManufacturer = 0;
|
|
dev_dscrptr->iProduct = 0;
|
|
dev_dscrptr->iSerialNumber = 0;
|
|
dev_dscrptr->bNumConfigurations = 1;
|
|
|
|
sunxi_udc_send_setup(dev_dscrptr->bLength, buffer);
|
|
}
|
|
break;
|
|
|
|
case USB_DT_CONFIG: //配置描述符
|
|
{
|
|
struct usb_configuration_descriptor *config_dscrptr;
|
|
struct usb_interface_descriptor *inter_dscrptr;
|
|
struct usb_endpoint_descriptor *ep_in, *ep_out;
|
|
unsigned char bytes_remaining = req->wLength;
|
|
unsigned char bytes_total = 0;
|
|
|
|
sunxi_usb_dbg("get config descriptor\n");
|
|
|
|
bytes_total = sizeof (struct usb_configuration_descriptor) + \
|
|
sizeof (struct usb_interface_descriptor) + \
|
|
sizeof (struct usb_endpoint_descriptor) + \
|
|
sizeof (struct usb_endpoint_descriptor);
|
|
|
|
memset(buffer, 0, bytes_total);
|
|
|
|
config_dscrptr = (struct usb_configuration_descriptor *)(buffer + 0);
|
|
inter_dscrptr = (struct usb_interface_descriptor *)(buffer + \
|
|
sizeof(struct usb_configuration_descriptor));
|
|
ep_in = (struct usb_endpoint_descriptor *)(buffer + \
|
|
sizeof(struct usb_configuration_descriptor) + \
|
|
sizeof(struct usb_interface_descriptor));
|
|
ep_out = (struct usb_endpoint_descriptor *)(buffer + \
|
|
sizeof(struct usb_configuration_descriptor) + \
|
|
sizeof(struct usb_interface_descriptor) + \
|
|
sizeof(struct usb_endpoint_descriptor));
|
|
|
|
/* configuration */
|
|
config_dscrptr->bLength = MIN(bytes_remaining, sizeof (struct usb_configuration_descriptor));
|
|
config_dscrptr->bDescriptorType = USB_DT_CONFIG;
|
|
config_dscrptr->wTotalLength = bytes_total;
|
|
config_dscrptr->bNumInterfaces = 1;
|
|
config_dscrptr->bConfigurationValue = 1;
|
|
config_dscrptr->iConfiguration = 0;
|
|
config_dscrptr->bmAttributes = 0x80; //not self powered
|
|
config_dscrptr->bMaxPower = 0xFA; //最大电流500ms(0xfa * 2)
|
|
|
|
bytes_remaining -= config_dscrptr->bLength;
|
|
/* interface */
|
|
inter_dscrptr->bLength = MIN (bytes_remaining, sizeof(struct usb_interface_descriptor));
|
|
inter_dscrptr->bDescriptorType = USB_DT_INTERFACE;
|
|
inter_dscrptr->bInterfaceNumber = 0x00;
|
|
inter_dscrptr->bAlternateSetting = 0x00;
|
|
inter_dscrptr->bNumEndpoints = 0x02;
|
|
inter_dscrptr->bInterfaceClass = 0xff;
|
|
inter_dscrptr->bInterfaceSubClass = 0xff;
|
|
inter_dscrptr->bInterfaceProtocol = 0xff;
|
|
inter_dscrptr->iInterface = 0;
|
|
|
|
bytes_remaining -= inter_dscrptr->bLength;
|
|
/* ep_in */
|
|
ep_in->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor));
|
|
ep_in->bDescriptorType = USB_DT_ENDPOINT;
|
|
ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type(); /* IN */
|
|
ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK;
|
|
ep_in->wMaxPacketSize = sunxi_udc_get_ep_max();
|
|
ep_in->bInterval = 0x00;
|
|
|
|
bytes_remaining -= ep_in->bLength;
|
|
/* ep_out */
|
|
ep_out->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor));
|
|
ep_out->bDescriptorType = USB_DT_ENDPOINT;
|
|
ep_out->bEndpointAddress = sunxi_udc_get_ep_out_type(); /* OUT */
|
|
ep_out->bmAttributes = USB_ENDPOINT_XFER_BULK;
|
|
ep_out->wMaxPacketSize = sunxi_udc_get_ep_max();
|
|
ep_out->bInterval = 0x00;
|
|
|
|
bytes_remaining -= ep_out->bLength;
|
|
|
|
sunxi_udc_send_setup(MIN(req->wLength, bytes_total), buffer);
|
|
}
|
|
break;
|
|
|
|
case USB_DT_STRING:
|
|
{
|
|
unsigned char bLength = 0;
|
|
unsigned char string_index = req->wValue & 0xff;
|
|
|
|
sunxi_usb_dbg("get string descriptor\n");
|
|
|
|
/* Language ID */
|
|
if(string_index == 0)
|
|
{
|
|
bLength = MIN(4, req->wLength);
|
|
|
|
buffer[0] = bLength;
|
|
buffer[1] = USB_DT_STRING;
|
|
buffer[2] = 9;
|
|
buffer[3] = 4;
|
|
sunxi_udc_send_setup(bLength, (void *)buffer);
|
|
}
|
|
else
|
|
{
|
|
printf("sunxi usb err: string line %d is not supported\n", string_index);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case USB_DT_DEVICE_QUALIFIER:
|
|
{
|
|
#ifdef CONFIG_USB_1_1_DEVICE
|
|
/* This is an invalid request for usb 1.1, nak it */
|
|
USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
|
|
#else
|
|
struct usb_qualifier_descriptor *qua_dscrpt;
|
|
|
|
sunxi_usb_dbg("get qualifier descriptor\n");
|
|
|
|
qua_dscrpt = (struct usb_qualifier_descriptor *)buffer;
|
|
memset(&buffer, 0, sizeof(struct usb_qualifier_descriptor));
|
|
|
|
qua_dscrpt->bLength = MIN(req->wLength, sizeof(struct usb_qualifier_descriptor));
|
|
qua_dscrpt->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
|
|
qua_dscrpt->bcdUSB = 0x200;
|
|
qua_dscrpt->bDeviceClass = 0xff;
|
|
qua_dscrpt->bDeviceSubClass = 0xff;
|
|
qua_dscrpt->bDeviceProtocol = 0xff;
|
|
qua_dscrpt->bMaxPacketSize0 = 0x40;
|
|
qua_dscrpt->bNumConfigurations = 1;
|
|
qua_dscrpt->breserved = 0;
|
|
|
|
sunxi_udc_send_setup(qua_dscrpt->bLength, buffer);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf("err: unkown wValue(%d)\n", req->wValue);
|
|
|
|
ret = SUNXI_USB_REQ_OP_ERR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*******************************************************************************
|
|
* do_usb_req_get_status
|
|
*
|
|
* Description:
|
|
* void
|
|
*
|
|
* Parameters:
|
|
* void
|
|
*
|
|
* Return value:
|
|
* void
|
|
*
|
|
* note:
|
|
* void
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static int __usb_get_status(struct usb_device_request *req, uchar *buffer)
|
|
{
|
|
unsigned char bLength = 0;
|
|
|
|
sunxi_usb_dbg("get status\n");
|
|
if(0 == req->wLength)
|
|
{
|
|
/* sent zero packet */
|
|
sunxi_udc_send_setup(0, NULL);
|
|
|
|
return SUNXI_USB_REQ_OP_ERR;
|
|
}
|
|
|
|
bLength = MIN(req->wValue, 2);
|
|
|
|
buffer[0] = 1;
|
|
buffer[1] = 0;
|
|
|
|
sunxi_udc_send_setup(bLength, buffer);
|
|
|
|
return SUNXI_USB_REQ_SUCCESSED;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static int __sunxi_pburn_send_status(void *buffer, unsigned int buffer_size)
|
|
{
|
|
return sunxi_udc_send_data((uchar *)buffer, buffer_size);
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
int __sunxi_burn_key(u8 *buff, uint buff_len)
|
|
{
|
|
sunxi_usb_burn_main_info_t *key_main = (sunxi_usb_burn_main_info_t *)buff;
|
|
sunxi_usb_burn_key_info_t *key_list;
|
|
__attribute__((unused)) int ret;
|
|
sunxi_efuse_key_info_t efuse_key_info;
|
|
|
|
int key_count;
|
|
int offset;
|
|
u8 *p_buff = (u8 *)&key_main->key_info;
|
|
//比较key主体的信息
|
|
if(strcmp((const char *)key_main->magic, "key-group-db"))
|
|
{
|
|
printf("key data magic unmatch, err\n");
|
|
|
|
return -1;
|
|
}
|
|
key_count = key_main->count;
|
|
printf("key_count=%d\n", key_count);
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
if(sunxi_secure_storage_init())
|
|
{
|
|
printf("%s secure storage init failed\n", __func__);
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
for(;key_count>0;key_count--, key_list++)
|
|
{
|
|
key_list = (sunxi_usb_burn_key_info_t *)p_buff;
|
|
printf("^^^^^^^^^^^^^^^^^^^\n");
|
|
printf("key index=%d\n", key_main->count - key_count);
|
|
printf("key name=%s\n", key_list->name);
|
|
printf("key type=%d\n", key_list->type);
|
|
printf("key len=%d\n", key_list->len);
|
|
printf("key if_burn=%d\n", key_list->if_burn);
|
|
printf("key if_replace=%d\n", key_list->if_replace);
|
|
printf("key if_crypt=%d\n", key_list->if_crypt);
|
|
printf("key data:\n");
|
|
sunxi_dump(key_list->key_data, key_list->len);
|
|
printf("###################\n");
|
|
offset = (sizeof(sunxi_usb_burn_key_info_t)) + ((key_list->len + 15) & (~15));
|
|
printf("offset=%d\n", offset);
|
|
p_buff += offset;
|
|
|
|
if(!key_list->type)
|
|
{
|
|
memset(&efuse_key_info, 0, sizeof(efuse_key_info));
|
|
strcpy(efuse_key_info.name, (const char *)key_list->name);
|
|
efuse_key_info.len = key_list->len;
|
|
efuse_key_info.key_data = (u8 *)key_list->key_data;
|
|
|
|
if(!strcmp(efuse_key_info.name, "rotpk"))
|
|
{
|
|
printf("ready to burn rootkey\n");
|
|
#ifdef CONFIG_SUNXI_KEY_LADDER
|
|
if (sunxi_key_ladder_verify_rotpk_hash(key_list->key_data, key_list->len)) {
|
|
printf("verity the rootkey failed, stop burn it\n");
|
|
return -1;
|
|
}
|
|
#else
|
|
if(sunxi_verify_rotpk_hash(key_list->key_data, key_list->len))
|
|
{
|
|
printf("verity the rootkey failed, stop burn it\n");
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ((sunxi_get_securemode() == SUNXI_SECURE_MODE_WITH_SECUREOS) || (sunxi_probe_secure_monitor()))
|
|
{
|
|
if (arm_svc_efuse_write(&efuse_key_info)) {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (sunxi_efuse_write(&efuse_key_info)) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!strcmp("hdcpkey", key_list->name))
|
|
{
|
|
ret = sunxi_deal_hdcp_key((char *)key_list->key_data, key_list->len);
|
|
if(ret)
|
|
{
|
|
printf("sunxi deal with hdcp key failed\n");
|
|
return -1;
|
|
}
|
|
} else if (sunxi_find_key(key_list->name))
|
|
{
|
|
ret = sunxi_secure_object_down(key_list->name, (char *)key_list->key_data, key_list->len,
|
|
key_list->if_crypt,key_list->if_replace);
|
|
if(ret)
|
|
{
|
|
printf("sunxi deal with widevine key failed\n");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
sunxi_secure_object_set(key_list->name,
|
|
key_list->if_crypt,
|
|
key_list->if_replace,
|
|
0,0,0 ); /*set secure storage feature*/
|
|
|
|
printf("write key to secure storage\n");
|
|
ret = sunxi_secure_object_write(key_list->name, (char *)key_list->key_data, key_list->len);
|
|
if(ret)
|
|
{
|
|
printf("write key to secure storage failed\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SUNXI_PRIVATE_KEY
|
|
printf("write key to private partition\n");
|
|
ret = save_user_private_data(key_list->name, (char *)key_list->key_data, key_list->len);
|
|
if(ret < 0)
|
|
{
|
|
printf("write key to private failed\n");
|
|
return -1;
|
|
}
|
|
else if(ret == 1) //烧写的key数据长度过大,无法存储在private分区
|
|
{
|
|
printf("the fuck thing had happened\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
if(sunxi_secure_storage_exit())
|
|
{
|
|
printf("sunxi_secure_storage_exit err\n");
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name : __sunxi_read_key_by_name
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
int __sunxi_read_key_by_name(void *buffer, uint buff_len, int *read_len)
|
|
{
|
|
sunxi_usb_burn_key_info_t *key_info = NULL;
|
|
|
|
__attribute__((unused)) int ret = -1;
|
|
__attribute__((unused)) int key_data_len = 0;
|
|
char data_buff[4096]={0};
|
|
|
|
if(buffer == NULL)
|
|
{
|
|
printf("the memory input or output is NULL\n");
|
|
return -1;
|
|
}
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
if(sunxi_secure_storage_init())
|
|
{
|
|
printf("%s secure storage init failed\n", __func__);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
key_info = (sunxi_usb_burn_key_info_t *)buffer;
|
|
|
|
printf("key name=%s\n", key_info->name);
|
|
printf("key type=%d\n", key_info->type);
|
|
printf("key len=%d\n", key_info->len);
|
|
printf("key if_burn=%d\n", key_info->if_burn);
|
|
printf("key if_replace=%d\n", key_info->if_replace);
|
|
printf("key if_crypt=%d\n", key_info->if_crypt);
|
|
|
|
*read_len = sizeof(sunxi_usb_burn_key_info_t);
|
|
|
|
if(!key_info->type)
|
|
{
|
|
if ((gd->securemode == SUNXI_SECURE_MODE_WITH_SECUREOS) || (sunxi_probe_secure_monitor()))
|
|
{
|
|
key_data_len = arm_svc_efuse_read(key_info->name, (void *)data_buff);
|
|
if (key_data_len <= 0)
|
|
{
|
|
printf("efuse read %s err\n", key_info->name);
|
|
return -1;
|
|
}
|
|
|
|
} else {
|
|
if (sunxi_efuse_read(key_info->name, (void *)data_buff, &key_data_len)) {
|
|
printf("efuse read %s err\n", key_info->name);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* convert hex key to char,so that dragonkey tool can display it */
|
|
hex2char((void *)(key_info->key_data), (void *)(data_buff), key_data_len);
|
|
*read_len +=key_data_len*2;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
printf("read key form securestorage\n");
|
|
ret = sunxi_secure_object_read(key_info->name, data_buff, sizeof(sunxi_usb_burn_key_info_t), &key_data_len);
|
|
if (ret < 0)
|
|
printf("read %s form securestorage failed\n", key_info->name);
|
|
else {
|
|
key_info->len = key_data_len;
|
|
memcpy((void *)(key_info->key_data),
|
|
(void *)data_buff, key_data_len);
|
|
*read_len += key_data_len;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SUNXI_PRIVATE_KEY
|
|
printf("read key form private\n");
|
|
memset(data_buff, 0, 4096);
|
|
ret = read_private_key_by_name(key_info->name, data_buff, sizeof(sunxi_usb_burn_key_info_t), &key_data_len);
|
|
if(ret < 0)
|
|
printf("read %s form private failed\n", key_info->name);
|
|
else {
|
|
key_info->len = key_data_len;
|
|
memcpy((void *)(key_info->key_data),
|
|
(void *)data_buff, key_data_len);
|
|
*read_len += key_data_len;
|
|
}
|
|
#endif
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name : __sunxi_read_key_by_name
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
int __sunxi_erase_key(void)
|
|
{
|
|
__attribute__((unused)) int ret;
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
ret = sunxi_secure_storage_init();
|
|
if(ret < 0)
|
|
{
|
|
printf("secure storage init err\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = sunxi_secure_storage_erase_all();
|
|
if(ret < 0)
|
|
{
|
|
printf("erase secure storage failed\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("erase securestorage success\n");
|
|
sunxi_secure_storage_exit();
|
|
#endif
|
|
|
|
#ifdef CONFIG_SUNXI_PRIVATE_KEY
|
|
ret = erase_all_private_data();
|
|
if(ret < 0)
|
|
{
|
|
printf("erase private data failed\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name : __sunxi_read_key_by_name
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
int __sunxi_burn_flag(void)
|
|
{
|
|
int ret;
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
ret = sunxi_secure_storage_init();
|
|
if(ret < 0)
|
|
{
|
|
printf("secure storage init err\n");
|
|
return -1;
|
|
}
|
|
if(sunxi_secure_object_write("key_burned_flag", "key_burned", strlen("key_burned")))
|
|
{
|
|
printf("save burned flag to securestorage failed\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("save burned flag to securestorage success\n");
|
|
sunxi_secure_storage_exit();
|
|
|
|
#else
|
|
|
|
char buffer[512];
|
|
uint private_start, private_len;
|
|
|
|
private_start = sunxi_partition_get_offset_byname("private");
|
|
private_len = sunxi_partition_get_size_byname("private");
|
|
|
|
if((!private_start) || (!private_len))
|
|
{
|
|
printf("private no exist\n");
|
|
return -1;
|
|
}
|
|
|
|
memset(buffer, 0, 512);
|
|
|
|
strcpy(buffer, "key_burned");
|
|
ret = sunxi_flash_write(private_start + private_len - (8192+512)/512, 1, buffer);
|
|
if(!ret)
|
|
{
|
|
printf("save burned flag to private failed\n");
|
|
return -1;
|
|
}
|
|
sunxi_flash_flush();
|
|
printf("save burned flag to private success\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
int sunxi_burn_part_verify(void *veryfy_info, long long burn_bytes)
|
|
{
|
|
long long base_bytes = 0;
|
|
uint active_verify = 0;
|
|
uint origin_verify = 0;
|
|
uint part_start;
|
|
pburn_verify_part_set_t *temp_info = NULL;
|
|
|
|
temp_info = (pburn_verify_part_set_t *)veryfy_info;
|
|
|
|
part_start = sunxi_partition_get_offset_byname(temp_info->name);
|
|
if(!part_start)
|
|
{
|
|
printf("partition %s is not exist\n", temp_info->name);
|
|
return -1;
|
|
}
|
|
|
|
base_bytes = burn_bytes;
|
|
origin_verify = temp_info->check_sum;
|
|
active_verify = sunxi_sprite_part_rawdata_verify(part_start, base_bytes);
|
|
printf("origin checksum=%x, active checksum=%x\n", origin_verify, active_verify);
|
|
if(active_verify != origin_verify)
|
|
{
|
|
printf("sunxi burn: part %s verify error\n", temp_info->name);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
int burn_part_probe(void *burn_part_info)
|
|
{
|
|
pburn_partition_set_t *part_info = NULL;
|
|
int burn_state = 0;
|
|
|
|
part_info = (pburn_partition_set_t *)(burn_part_info);
|
|
if(!strcmp(part_info->magic, "usbburnpart"))
|
|
{
|
|
burn_part_start = sunxi_partition_get_offset_byname(part_info->name);
|
|
burn_part_len = sunxi_partition_get_size_byname(part_info->name);
|
|
if(!burn_part_start)
|
|
{
|
|
printf("partition %s is not exist\n", part_info->name);
|
|
burn_state = ERR_NO_PART_NOEXIST;
|
|
}
|
|
else if(((!burn_part_len) || (burn_part_len < ((part_info->lenlo + 511))/512)) || (part_info->lenlo == 0))
|
|
{
|
|
printf("the burn data size 0x%x is large then 0x%x\n", part_info->lenlo, burn_part_len);
|
|
burn_state = ERR_NO_PART_SIZE_ERR;
|
|
}
|
|
else
|
|
{
|
|
printf("part info check success\n");
|
|
printf("part_info->lenhi=%u\n", part_info->lenhi);
|
|
printf("part_info->lenlo=%u\n", part_info->lenlo);
|
|
burn_part_bytes = part_info->lenhi;
|
|
burn_part_bytes = (burn_part_bytes << 32) + part_info->lenlo;
|
|
burn_state = ERR_NO_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("part magic %s need equal usbburnpart\n", part_info->magic);
|
|
burn_state = ERR_NO_PART_MAGIC_ERR;
|
|
}
|
|
return burn_state;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static int sunxi_pburn_init(void)
|
|
{
|
|
sunxi_usb_dbg("sunxi_pburn_init\n");
|
|
memset(&trans_data, 0, sizeof(pburn_trans_set_t));
|
|
sunxi_usb_pburn_write_enable = 0;
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
|
|
|
|
trans_data.base_recv_buffer = (u8 *)malloc(SUNXI_PBURN_RECV_MEM_SIZE);
|
|
if(!trans_data.base_recv_buffer)
|
|
{
|
|
printf("sunxi usb pburn err: unable to malloc memory for pburn receive\n");
|
|
|
|
return -1;
|
|
}
|
|
|
|
trans_data.base_send_buffer = (u8 *)malloc(SUNXI_PBURN_SEND_MEM_SIZE);
|
|
if(!trans_data.base_send_buffer)
|
|
{
|
|
printf("sunxi usb pburn err: unable to malloc memory for pburn send\n");
|
|
free(trans_data.base_recv_buffer);
|
|
|
|
return -1;
|
|
}
|
|
sunxi_usb_dbg("recv addr 0x%x\n", (uint)trans_data.base_recv_buffer);
|
|
sunxi_usb_dbg("send addr 0x%x\n", (uint)trans_data.base_send_buffer);
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static int sunxi_pburn_exit(void)
|
|
{
|
|
sunxi_usb_dbg("sunxi_pburn_exit\n");
|
|
if(trans_data.base_recv_buffer)
|
|
{
|
|
free(trans_data.base_recv_buffer);
|
|
trans_data.base_recv_buffer = NULL;
|
|
}
|
|
if(trans_data.base_send_buffer)
|
|
{
|
|
free(trans_data.base_send_buffer);
|
|
trans_data.base_send_buffer = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static void sunxi_pburn_reset(void)
|
|
{
|
|
sunxi_usb_pburn_write_enable = 0;
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static void sunxi_pburn_usb_rx_dma_isr(void *p_arg)
|
|
{
|
|
sunxi_usb_dbg("dma int for usb rx occur\n");
|
|
//通知主循环,可以写入数据
|
|
sunxi_usb_pburn_write_enable = 1;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static void sunxi_pburn_usb_tx_dma_isr(void *p_arg)
|
|
{
|
|
sunxi_usb_dbg("dma int for usb tx occur\n");
|
|
#if defined(SUNXI_USB_30)
|
|
sunxi_usb_pburn_status_enable = 1;
|
|
#endif
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static int sunxi_pburn_standard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer)
|
|
{
|
|
int ret = SUNXI_USB_REQ_OP_ERR;
|
|
|
|
switch(cmd)
|
|
{
|
|
case USB_REQ_GET_STATUS:
|
|
{
|
|
ret = __usb_get_status(req, buffer);
|
|
|
|
break;
|
|
}
|
|
//case USB_REQ_CLEAR_FEATURE:
|
|
//case USB_REQ_SET_FEATURE:
|
|
case USB_REQ_SET_ADDRESS:
|
|
{
|
|
ret = __usb_set_address(req);
|
|
|
|
break;
|
|
}
|
|
case USB_REQ_GET_DESCRIPTOR:
|
|
//case USB_REQ_SET_DESCRIPTOR:
|
|
case USB_REQ_GET_CONFIGURATION:
|
|
{
|
|
ret = __usb_get_descriptor(req, buffer);
|
|
|
|
break;
|
|
}
|
|
case USB_REQ_SET_CONFIGURATION:
|
|
{
|
|
ret = __usb_set_configuration(req);
|
|
|
|
break;
|
|
}
|
|
//case USB_REQ_GET_INTERFACE:
|
|
case USB_REQ_SET_INTERFACE:
|
|
{
|
|
ret = __usb_set_interface(req);
|
|
|
|
break;
|
|
}
|
|
//case USB_REQ_SYNCH_FRAME:
|
|
default:
|
|
{
|
|
printf("sunxi pburn error: standard req is not supported\n");
|
|
|
|
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static int sunxi_pburn_nonstandard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer, uint data_status)
|
|
{
|
|
int ret = SUNXI_USB_REQ_SUCCESSED;
|
|
|
|
switch(req->bmRequestType) //PBURN 特有请求
|
|
{
|
|
case 161:
|
|
if(req->bRequest == 0xFE)
|
|
{
|
|
sunxi_usb_dbg("pburn ask for max lun\n");
|
|
|
|
buffer[0] = 0;
|
|
|
|
sunxi_udc_send_setup(1, buffer);
|
|
}
|
|
else
|
|
{
|
|
printf("sunxi usb err: unknown ep0 req in pburn\n");
|
|
|
|
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf("sunxi usb err: unknown non standard ep0 req\n");
|
|
|
|
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
|
|
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
/*
|
|
************************************************************************************************************
|
|
*
|
|
* function
|
|
*
|
|
* name :
|
|
*
|
|
* parmeters :
|
|
*
|
|
* return :
|
|
*
|
|
* note :
|
|
*
|
|
*
|
|
************************************************************************************************************
|
|
*/
|
|
static int sunxi_pburn_state_loop(void *buffer)
|
|
{
|
|
static struct umass_bbb_cbw_t *cbw;
|
|
static struct sunxi_efex_cbw_t *efex_cbw;
|
|
static struct umass_bbb_csw_t csw;
|
|
static uint pburn_flash_start = 0;
|
|
static uint pburn_flash_sectors = 0;
|
|
int ret;
|
|
int burn_key_next_work;
|
|
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 sunxi_efex_cbw_t))
|
|
{
|
|
efex_cbw = (struct sunxi_efex_cbw_t *)sunxi_ubuf->rx_req_buffer;
|
|
if(efex_cbw->magic == CBW_MAGIC)
|
|
{
|
|
printf("try to update \n");
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA;
|
|
trans_data.recv_size = cbw->dCBWDataTransferLength;
|
|
trans_data.act_recv_buffer = trans_data.base_recv_buffer;
|
|
fel_verify = 1;
|
|
sunxi_usb_pburn_write_enable = 0;
|
|
printf("start to recv by dma \n");
|
|
sunxi_udc_start_recv_by_dma(trans_data.act_recv_buffer, 16);
|
|
printf("recv done \n");
|
|
break;
|
|
}
|
|
}
|
|
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%x\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])
|
|
{
|
|
case 0xf8:
|
|
printf("usb update probe \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_update_probe_ok");
|
|
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));
|
|
|
|
csw.bCSWStatus = 0;
|
|
sunxi_usb_burn_from_boot_handshake = 1;
|
|
}
|
|
break;
|
|
case 1: //exit
|
|
{
|
|
__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_update_exit");
|
|
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_probe_update_action = 2;
|
|
csw.bCSWStatus = 0;
|
|
}
|
|
break;
|
|
case 2: //run efex
|
|
{
|
|
__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_update_efex");
|
|
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_probe_update_action = 1;
|
|
csw.bCSWStatus = 0;
|
|
}
|
|
break;
|
|
default:
|
|
printf("usb command = %d not support\n", cbw->CBWCDB[1]);
|
|
break;
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case 0xf0: //自定义命令,用于烧录用户数据
|
|
sunxi_usb_dbg("usb burn secure storage data\n");
|
|
sunxi_usb_dbg("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;
|
|
|
|
if(private_data_ext_buff == NULL)
|
|
{
|
|
printf("malloc memory\n");
|
|
private_data_ext_buff = (u8 *)malloc(DATA_BUFFER_MAX_SIZE);
|
|
if(private_data_ext_buff == NULL)
|
|
{
|
|
printf("there is no memory to store all user key data\n");
|
|
csw.bCSWStatus = -1;
|
|
}
|
|
else
|
|
{
|
|
csw.bCSWStatus = 0;
|
|
sunxi_usb_burn_from_boot_handshake = 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;
|
|
|
|
memset(private_data_ext_buff, 0, DATA_BUFFER_MAX_SIZE);
|
|
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;
|
|
}
|
|
}
|
|
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_flash_flush();
|
|
|
|
if(private_data_ext_buff)
|
|
{
|
|
free(private_data_ext_buff);
|
|
private_data_ext_buff = NULL;
|
|
}
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT;
|
|
}
|
|
break;
|
|
|
|
case 5: //设置烧写key flag
|
|
{
|
|
int ret;
|
|
__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;
|
|
|
|
ret = __sunxi_burn_flag();
|
|
if(ret < 0)
|
|
{
|
|
printf("sunxi burn flag failed\n");
|
|
csw.bCSWStatus = -1;
|
|
}
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
|
|
}
|
|
break;
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
case 6: //huk
|
|
{
|
|
u8 huk[32];
|
|
int ret = -1;
|
|
|
|
memset(huk, 0, 32);
|
|
//ret = smc_create_huk(huk, 32);
|
|
|
|
csw.bCSWStatus = 0;
|
|
trans_data.act_send_buffer = trans_data.base_send_buffer;
|
|
trans_data.send_size = min(cbw->dCBWDataTransferLength, 32);
|
|
|
|
if(ret < 0)
|
|
{
|
|
printf("smc_create_huk failed\n");
|
|
csw.bCSWStatus = -1;
|
|
}
|
|
else
|
|
{
|
|
if(!ret)
|
|
printf("smc_create_huk successed\n");
|
|
else
|
|
printf("smc_create_huk already exist\n");
|
|
memcpy((void *)trans_data.act_send_buffer, huk, 32);
|
|
}
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
|
|
}
|
|
break;
|
|
#endif
|
|
case 7: //read key one by one
|
|
{
|
|
int ret;
|
|
int read_len = 0;
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
|
|
|
|
ret = __sunxi_read_key_by_name(private_data_ext_buff, DATA_BUFFER_MAX_SIZE, &read_len);
|
|
if(!ret)
|
|
{
|
|
printf("read key success\n");
|
|
csw.bCSWStatus = 0;
|
|
}
|
|
else
|
|
{
|
|
printf("read key failed\n");
|
|
csw.bCSWStatus = 1;
|
|
}
|
|
|
|
trans_data.act_send_buffer = trans_data.base_send_buffer;
|
|
trans_data.send_size = max(cbw->dCBWDataTransferLength, read_len);
|
|
|
|
memcpy((void *)trans_data.act_send_buffer, (void *)private_data_ext_buff, read_len);
|
|
printf("read_len=%d\n", read_len);
|
|
printf("the send data:\n");
|
|
sunxi_dump((void *)private_data_ext_buff, read_len);
|
|
}
|
|
break;
|
|
|
|
case 8: //erase all key
|
|
{
|
|
int ret;
|
|
__usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;
|
|
|
|
memset(handshake, 0, sizeof(__usb_handshake_ext_t));
|
|
|
|
csw.bCSWStatus = 0;
|
|
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_ext_t));
|
|
|
|
ret = __sunxi_erase_key();
|
|
if(ret < 0)
|
|
{
|
|
printf("sunxi erase key failed\n");
|
|
strcpy(handshake->magic, "usb_erase_failed");
|
|
handshake->err_no = ERR_NO_ERASE_KEY_FAILED;
|
|
break;
|
|
}
|
|
|
|
strcpy(handshake->magic, "usb_erase_success");
|
|
handshake->err_no = ERR_NO_SUCCESS;
|
|
printf("sunxi erase all key success\n");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0xf3: //自定义命令,用于烧录用户数据
|
|
printf("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));
|
|
/* for private partition, use __usb_handshake_t, magic "usb_burn_handsha" */
|
|
/* for secure storage, use __usb_handshake_sec_t, magic "usb_burn_handshake" */
|
|
strncpy(handshake->magic, "usb_burn_handshake", 16);
|
|
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_object_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;
|
|
|
|
case 0xf7: //自定义命令字,烧录分区数据
|
|
sunxi_usb_dbg("usb burn partition\n");
|
|
sunxi_usb_dbg("usb command = %d\n", cbw->CBWCDB[1]);
|
|
switch (cbw->CBWCDB[1])
|
|
{
|
|
case 0: //握手
|
|
{
|
|
printf("usb command = %d\n", cbw->CBWCDB[1]);
|
|
__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");
|
|
|
|
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;
|
|
|
|
csw.bCSWStatus = 0;
|
|
sunxi_usb_burn_from_boot_handshake = 1;
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
|
|
}
|
|
break;
|
|
|
|
case 1: //小机端接收分区数据
|
|
{
|
|
//pburn_flash_start = *(int *)(cbw->CBWCDB + 4);
|
|
|
|
trans_data.recv_size = cbw->dCBWDataTransferLength;
|
|
trans_data.act_recv_buffer = trans_data.base_recv_buffer;
|
|
|
|
pburn_flash_start += pburn_flash_sectors;
|
|
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
|
|
printf("recv_size=%d\n", trans_data.recv_size);
|
|
pburn_flash_sectors = (trans_data.recv_size + 511)/512;
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA;
|
|
}
|
|
break;
|
|
|
|
case 2: //查询结果
|
|
{
|
|
printf("usb command = %d\n", cbw->CBWCDB[1]);
|
|
__usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer;
|
|
memset(handshake, 0, sizeof(__usb_handshake_ext_t));
|
|
|
|
trans_data.act_send_buffer = trans_data.base_send_buffer;
|
|
trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t));
|
|
|
|
if(burn_part_result_state)
|
|
{
|
|
strcpy(handshake->magic, "usb_burn_error");
|
|
}
|
|
else
|
|
{
|
|
strcpy(handshake->magic, "usb_burn_success");
|
|
}
|
|
csw.bCSWStatus = 0;
|
|
handshake->err_no = burn_part_result_state;
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
|
|
}
|
|
break;
|
|
|
|
case 3: //小机端接收分区信息
|
|
{
|
|
printf("usb command = %d\n", cbw->CBWCDB[1]);
|
|
trans_data.recv_size = cbw->dCBWDataTransferLength;
|
|
trans_data.act_recv_buffer = trans_data.base_recv_buffer;
|
|
|
|
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
|
|
|
|
printf("recv_size=%d\n", trans_data.recv_size);
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_PART_INFO;
|
|
}
|
|
break;
|
|
|
|
case 4: //关闭usb
|
|
{
|
|
printf("usb command = %d\n", cbw->CBWCDB[1]);
|
|
__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;
|
|
#ifdef CONFIG_SUNXI_SECURE_STORAGE
|
|
case 5: //设置烧写key flag
|
|
{
|
|
printf("usb command = %d\n", cbw->CBWCDB[1]);
|
|
__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;
|
|
|
|
if(sunxi_secure_storage_init())
|
|
{
|
|
printf("secure storage init err\n");
|
|
csw.bCSWStatus = -1;
|
|
break;
|
|
}
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA;
|
|
if(sunxi_secure_object_write("key_burned_flag", "key_burned", strlen("key_burned")))
|
|
{
|
|
printf("save burned flag err\n");
|
|
|
|
csw.bCSWStatus = -1;
|
|
}
|
|
sunxi_secure_storage_exit();
|
|
}
|
|
break;
|
|
#endif
|
|
case 7: //接收分区校验数据
|
|
{
|
|
printf("usb command = %d\n", cbw->CBWCDB[1]);
|
|
trans_data.recv_size = cbw->dCBWDataTransferLength;
|
|
trans_data.act_recv_buffer = trans_data.base_recv_buffer;
|
|
|
|
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
|
|
|
|
printf("recv_size=%d\n", trans_data.recv_size);
|
|
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_PART_VERIFY;
|
|
}
|
|
break;
|
|
default:
|
|
printf("usb command = %d not support\n", cbw->CBWCDB[1]);
|
|
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) && (fel_verify == 0 ))
|
|
{
|
|
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;
|
|
}
|
|
if(sunxi_usb_pburn_write_enable == 1)
|
|
{
|
|
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:
|
|
|
|
sunxi_usb_dbg("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));
|
|
|
|
burn_key_next_work = SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN;
|
|
script_parser_fetch("target", "burn_key_next_work", &burn_key_next_work, 1);
|
|
if (burn_key_next_work == SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN)
|
|
{
|
|
printf("Device will shutdown in 3 Secends...\n");
|
|
}
|
|
else if (burn_key_next_work == SUNXI_UPDATE_NEXT_ACTION_REBOOT)
|
|
{
|
|
printf("Device will reboot in 3 Secends...\n");
|
|
}
|
|
else
|
|
{
|
|
burn_key_next_work = SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN;
|
|
printf("invalid value of burn_key_next_work. Default shutdown\n");
|
|
printf("Device will shutdown in 3 Secends...\n");
|
|
}
|
|
|
|
__msdelay(3000);
|
|
|
|
return burn_key_next_work;
|
|
|
|
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;
|
|
|
|
case SUNXI_USB_PBURN_RECEIVE_PART_INFO:
|
|
printf("SUNXI_USB_PBURN_RECEIVE_PART_INFO\n");
|
|
if(sunxi_usb_pburn_write_enable == 1)
|
|
{
|
|
//sunxi_dump((u8 *)(trans_data.act_recv_buffer), 1024);
|
|
burn_part_result_state = burn_part_probe((void*)trans_data.act_recv_buffer);
|
|
if(!burn_part_result_state)
|
|
{
|
|
pburn_flash_start = burn_part_start;
|
|
pburn_flash_sectors = 0;
|
|
}
|
|
csw.bCSWStatus = 0;
|
|
sunxi_usb_pburn_write_enable = 0;
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
|
|
}
|
|
break;
|
|
|
|
case SUNXI_USB_PBURN_RECEIVE_PART_VERIFY:
|
|
printf("SUNXI_USB_PBURN_RECEIVE_PART_VERIFY\n");
|
|
if(sunxi_usb_pburn_write_enable == 1)
|
|
{
|
|
//数据校验
|
|
//sunxi_dump((u8 *)(trans_data.act_recv_buffer), 1024);
|
|
printf("burn_part_bytes=%lld\n", burn_part_bytes);
|
|
ret = sunxi_burn_part_verify((void *)trans_data.act_recv_buffer, burn_part_bytes);
|
|
if(!ret) //数据校验成功
|
|
{
|
|
printf("data verify success\n");
|
|
burn_part_result_state = ERR_NO_SUCCESS;
|
|
}
|
|
else //数据校验失败
|
|
{
|
|
printf("data verify failed\n");
|
|
burn_part_result_state = ERR_NO_PART_VERIFY_ERR;
|
|
}
|
|
csw.bCSWStatus = 0;
|
|
sunxi_usb_pburn_write_enable = 0;
|
|
sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
sunxi_usb_module_init(SUNXI_USB_DEVICE_BURN, \
|
|
sunxi_pburn_init, \
|
|
sunxi_pburn_exit, \
|
|
sunxi_pburn_reset, \
|
|
sunxi_pburn_standard_req_op, \
|
|
sunxi_pburn_nonstandard_req_op, \
|
|
sunxi_pburn_state_loop, \
|
|
sunxi_pburn_usb_rx_dma_isr, \
|
|
sunxi_pburn_usb_tx_dma_isr \
|
|
);
|