/* * (C) Copyright 2000-2003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * 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 */ /* * Allwinner secure storage data format */ #include #include #include #include #include #include #include "sprite_storage_crypt.h" extern void sunxi_dump(void *addr, unsigned int size); //#define SST_DEBUG #ifdef SST_DEBUG int __command_dump(cmd_t *cmd) { printf(" ->command\n "); printf(" : cmd_tyep = " ); switch(cmd->cmd_type){ case SST_CMD_POLLING: printf(" SST_CMD_POLLING\n"); break; case SST_CMD_BIND_REQ: printf(" SST_CMD_BIND_REQ\n"); break; case SST_CMD_WORK_DONE: printf(" SST_CMD_WORK_DONE\n"); break; case SST_CMD_UPDATE_REQ: printf(" SST_CMD_UPDATE_REQ\n"); break; case SST_CMD_INITIALIZED: printf(" SST_CMD_INITIALIZED\n"); break; default: break; } printf(" : cmd_parma[0] = 0x%x\n", cmd->cmd_param[0] ); printf(" : cmd_parma[1] = 0x%x\n", cmd->cmd_param[1] ); printf(" : cmd_parma[2] = 0x%x\n", cmd->cmd_param[2] ); printf(" : cmd_parma[3] = 0x%x\n", cmd->cmd_param[3] ); printf(" : cmd_buf = 0x%x\n", (unsigned int)(cmd->cmd_buf) ); printf(" : cmd_buf_len = 0x%x\n", cmd->cmd_buf_len ); printf(" : resp_type = " ); switch(cmd->resp_type){ case SST_RESP_DUMMY: printf(" SST_RESP_DUMMY\n"); break; case SST_RESP_READ: printf(" SST_RESP_READ\n"); break; case SST_RESP_READ_DONE: printf(" SST_RESP_READ_DONE\n"); break; case SST_RESP_WRITE: printf(" SST_RESP_WRITE\n"); break; case SST_RESP_WRITE_DONE: printf(" SST_RESP_WRITE_DONE\n"); break; case SST_RESP_DELETE: printf(" SST_RESP_DELETE\n"); break; case SST_RESP_BIND_DONE: printf(" SST_RESP_BIND_DONE\n"); break; case SST_RESP_UPDATE_DONE: printf(" SST_RESP_UPDATE_DONE\n"); break; case SST_RESP_INITED_DONE: printf(" SST_RESP_INITED_DONE\n"); break; default: printf("\n"); break; } printf(" : resp_ret[0] = 0x%x\n", cmd->resp_ret[0] ); printf(" : resp_ret[1] = 0x%x\n", cmd->resp_ret[1] ); printf(" : resp_ret[2] = 0x%x\n", cmd->resp_ret[2] ); printf(" : resp_ret[3] = 0x%x\n", cmd->resp_ret[3] ); printf(" : resp_buf = 0x%x\n", (unsigned int)(cmd->resp_buf) ); printf(" : resp_buf_len = 0x%x\n", cmd->resp_buf_len ); return (0); } void __param_dump(struct te_oper_param *param) { printf("Param dump :0x%x\n", (unsigned int)param ); printf(" param->index = %d\n", param->index); printf(" param->type = 0x%x\n", param->type); printf(" param->Mem.base = 0x%x\n", (unsigned int)param->u.Mem.base); printf(" param->Mem.phys= 0x%x\n", (unsigned int)param->u.Mem.phys); printf(" param->Mem.len= 0x%x\n", param->u.Mem.len); return ; } void __request_dump(struct te_request *r ) { printf("Request dump :0x%x\n", (unsigned int)r); printf(" request->type = 0x%x\n", r->type); printf(" request->session_id = 0x%x\n", r->session_id); printf(" request->command_id = 0x%x\n", r->command_id); printf(" request->params = 0x%x\n", (unsigned int)(r->params)); printf(" request->params_size = 0x%x\n", r->params_size); } #else void __request_dump(struct te_request *r ) { return ; } void __param_dump(struct te_oper_param *param) { return ; } int __command_dump(cmd_t *cmd) { return 0; } #endif #ifdef CONFIG_SUNXI_SECURE_SYSTEM static char oem_class[MAX_OEM_STORE_NUM][64] ; static char *align_resp_buf = NULL, *align_cmd_buf = NULL ; static int parse_resp( struct te_request * request, struct te_oper_param *param, cmd_t *cmd ) { __command_dump(cmd); if(cmd->resp_buf != NULL ) memcpy(cmd->resp_buf, align_resp_buf, cmd->resp_buf_len); return 0 ; } static int package_cmd( struct te_request * request, struct te_oper_param *param, cmd_t *cmd ) { unsigned int i =0 ; __command_dump(cmd); char *cmd_buf, *resp_buf ; if(!align_cmd_buf || !align_resp_buf ){ cmd_buf = malloc(SZ_8K); resp_buf = malloc(SZ_8K); if(!cmd_buf || !resp_buf){ printf("smc load sst out of memory\n"); free(cmd_buf); free(resp_buf); return -1 ; } align_cmd_buf = (char *)ALIGN_BUF((unsigned int)cmd_buf, SZ_4K ) ; align_resp_buf= (char *)ALIGN_BUF((unsigned int)resp_buf,SZ_4K) ; } memset(request,0, sizeof(*request)) ; memset(param,0, sizeof(*param)) ; request->type = TEE_SMC_SST_COMMAND ; request->params = param ; request->params_size = 3 ; request->params->index = i =0 ; param[0].type = (uint32_t)TE_PARAM_TYPE_MEM_RW; param[0].u.Mem.base = cmd; param[0].u.Mem.phys =(void *)virt_to_phys(cmd); param[0].u.Mem.len= sizeof(*cmd); i ++; memset(¶m[i],0, sizeof(*param)); param[i].index = i ; if( cmd->cmd_buf != NULL ){ memcpy(align_cmd_buf, cmd->cmd_buf,cmd->cmd_buf_len ); param[i].type = TE_PARAM_TYPE_MEM_RO; param[i].u.Mem.base = align_cmd_buf; param[i].u.Mem.phys = (void *)virt_to_phys(align_cmd_buf); param[i].u.Mem.len= cmd->cmd_buf_len; } i ++; memset(¶m[i],0, sizeof(*param)); param[i].index = i ; if( cmd->resp_buf != NULL ){ param[i].type = (uint32_t)TE_PARAM_TYPE_MEM_RW; param[i].u.Mem.base = align_resp_buf; param[i].u.Mem.phys =(void *)virt_to_phys(align_resp_buf); param[i].u.Mem.len= cmd->resp_buf_len; } __request_dump(request); for(i =0 ;i< 3; i++) __param_dump(¶m[i]); return 0; } extern u32 sunxi_smc_call(u32 arg0, u32 arg1, u32 arg2, u32 arg3); static int post_cmd_wait_resp( cmd_t *cmd ) { int ret = -1 ; struct te_request *request; struct te_oper_param *param; request = malloc(sizeof(*request)); param = malloc(sizeof(*param)); if(!request || !param){ printf("post cmd out of memory\n"); return -1 ; } package_cmd(request,param, cmd); /* Send request to Swd and wait */ printf("begin to enter smc\n"); ret =sunxi_smc_call( TEE_SMC_SST_COMMAND, virt_to_phys(request), virt_to_phys(param), 0 ); printf("after smc\n"); /* Parse the return from Swd */ parse_resp(request, param, cmd); free(request); free(param); return ret ; } int sst_oem_item_id(char *item) { int id ; for(id =0; id cmd_type = SST_CMD_BIND_REQ; cmd->cmd_param[0] = OEM_DATA ; cmd->cmd_param[1] = id ; cmd->cmd_buf = (unsigned char *)src ; cmd->cmd_buf_len = len ; cmd->resp_buf =(unsigned char *)dst; cmd->resp_buf_len = MAX_STORE_LEN; cmd->resp_ret[0] = -1 ; cmd->status = SST_STAS_CMD_RDY; /* Send the command */ ret = post_cmd_wait_resp(cmd ); if( ret != 0 ){ printf(" command procedure error 0x%x\n", ret); free(cmd); return (- 1); } /* Check response */ if( cmd->resp_ret[0] != SST_RESP_RET_SUCCESS ){ printf(" cmd response fail:0x%x error\n", cmd->resp_ret[0]); free(cmd); return (- 1 ); } if( cmd->status != SST_STAS_CMD_RET ){ printf(" cmd status:0x%x error\n", cmd->status); free(cmd); return (- 1 ); } if( cmd->resp_type != SST_RESP_BIND_DONE ) { printf(" bind error in Swd:\ len = 0x%x , response type =0x%x \n", cmd->resp_buf_len, cmd->resp_type); free(cmd); return (- 1); } *retLen = cmd->resp_ret[1]; } while( 0 ) ; free(cmd); return 0; } static int sst_cmd_update_object( unsigned int type , unsigned int id , char *src, unsigned int len, char * name ) { cmd_t *cmd ; int ret = -1 ; unsigned char *name_buf ; cmd = malloc(sizeof(*cmd)); name_buf = malloc(strnlen(name, 64)); if(!cmd || !name_buf){ printf("sst_cmd_binding_store out of memory\n"); free(name_buf); return -1 ; } memset(cmd, 0, sizeof(*cmd)); do{ memset(cmd, 0 ,sizeof(*cmd)) ; cmd->cmd_type = SST_CMD_UPDATE_REQ; cmd->cmd_param[0] = type ; cmd->cmd_param[1] = id ; cmd->cmd_buf = (unsigned char *)src ; cmd->cmd_buf_len = len ; cmd->resp_ret[0] = -1 ; cmd->status = SST_STAS_CMD_RDY; if(name != NULL && type == OEM_DATA ){ memcpy(name_buf, name, strnlen(name,64)); cmd->resp_buf = (unsigned char *)name_buf ; cmd->resp_buf_len = strnlen(name,64) ; } /* Send the command */ ret = post_cmd_wait_resp(cmd ); if( ret != 0 ){ printf(" command procedure error 0x%x\n", ret); free(cmd); free(name_buf); return (- 1); } /* Check response */ if( cmd->resp_ret[0] != SST_RESP_RET_SUCCESS ){ printf(" cmd response fail:0x%x error\n", cmd->resp_ret[0]); free(cmd); free(name_buf); return (- 1 ); } if( cmd->status != SST_STAS_CMD_RET ){ printf(" cmd status:0x%x error\n", cmd->status); free(cmd); free(name_buf); return (- 1 ); } if( cmd->resp_type != SST_RESP_UPDATE_DONE ) { printf(" update error in Swd:\ len = 0x%x , response type =0x%x \n", cmd->resp_buf_len, cmd->resp_type); free(cmd); free(name_buf); return (- 1); } } while( 0 ) ; free(cmd); free(name_buf); return 0; } int smc_load_sst_encrypt( char *name, char *in, unsigned int len, char *out, unsigned int *outLen) { int id ,ret ; if( (id = sst_oem_item_id(name)) <0 ) return 1 ; ret = sst_cmd_binding_store((unsigned int)id, in , len, out, outLen ); return ret ; } int smc_load_sst_decrypt(char *name, char *in, unsigned int len) { int id ,ret ; if( (id = sst_oem_item_id(name)) <0 ) return 1 ; ret = sst_cmd_update_object(OEM_DATA ,(unsigned int)id, in , len, name ); return ret ; } int smc_set_sst_crypt_name(char *name) { int id ; if( (id = sst_oem_item_id(name)) >0 ) return 0 ;/*The name had been set*/ printf("set name[%s] to encrypt list\n", name); for(id =0; id name); ret = smc_load_sst_encrypt("Widevine", (char *)so->data,so->actual_len, en_buffer, &retLen); if(ret <0){ printf("smc load sst encrypt fail\n"); return -1 ; } printf("Encrypt Widevine data: \n"); sunxi_dump(en_buffer, retLen); memcpy(so->data, en_buffer, retLen); so->actual_len = retLen; so->re_encrypt = STORE_REENCRYPT_MAGIC; so->crc = crc32( 0 , (void *)so, sizeof(*so)-4 ); printf("so name %s\n",so->name); /*call to decrypt data to secure memory*/ ret = smc_load_sst_decrypt(so->name, (char *)so->data,so->actual_len); if(ret <0){ printf("smc_load sst decrypt fail\n"); return -1 ; } return 0 ; } #endif