/*************************************************************************** * Copyright (c) 2003-2008, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: write image to flash. * * Revision History: * * $brcm_Log: $ * * ***************************************************************************/ #include "bstd.h" #include "bdbg.h" #include "image_recv.h" #include "ramheader.h" #include "bfds.h" #include "gist.h" #include "bchp_sun_top_ctrl.h" BDBG_MODULE(image_write); bresult image_flash_install(uint32_t base, uint32_t offset, uint8_t * data, uint32_t size); bresult image_flash_install_fupdate(uint32_t base, uint32_t offset, uint8_t * data, uint32_t size); #if (CONFIG_ENABLE_SCM == 1) static int auth_image_authenticate(uint8_t *data); #endif struct image_wstate_t { bool berased; int wpct; } ; static struct image_wstate_t wstate = {0,0}; #define IMAGE1_SELECTOR_MASK 0x100 #define SWAP_IMAGE(x,y) do { void *tmp = x; x=y;y=tmp; } while (0) bresult image_write(struct image_t * image) { boot_header_t * ram0; boot_header_t * ram1; uint32_t ram_offset; unsigned int order0, order1, boot_order, reverse; #if (CONFIG_ENABLE_SCM==1) int res; #endif wstate.berased = false; wstate.wpct = 100; #if (CONFIG_ENABLE_SCM == 1) /* authenticate receive image */ res = auth_image_authenticate(image->data); if (res != 0) { BDBG_WRN(("Image signature is not correct.. discard downloaded image")); return berr_external_error; } #endif /* find running image */ ram0 = (boot_header_t *)FLASH_APP0_START; ram1 = (boot_header_t *)FLASH_APP1_START; /* figure out which image to replace */ order0 = order1 = boot_order = reverse = 0; if ((image->size + sizeof(boot_header_t)) > FLASH_APP0_SIZE) { /* couldn't store backup image, overwrite current image */ ram1 = ram0; } else { if (CHIP_ID == ram0->chip_id) order0 = ram0->boot_order; if (CHIP_ID == ram1->chip_id) order1 = ram1->boot_order; if (BREG_Read32(GetREG(), BCHP_SUN_TOP_CTRL_UNCLEARED_SCRATCH) & IMAGE1_SELECTOR_MASK) { if (order1 < order0) { SWAP_IMAGE(ram0, ram1); reverse = 1; } } else { if (order1 > order0) { SWAP_IMAGE(ram0, ram1); } } if (CHIP_ID == ram0->chip_id) { if (reverse) boot_order = ram0->boot_order-1; else boot_order = ram0->boot_order+1; } else { ram1 = ram0; } } /* for now we will only write out first image */ ram_offset = (uint32_t)ram1 - (uint32_t)FLASH_BASE; BDBG_WRN(("writing at 0x%x, size:%d", ram_offset, image->size)); /* fill boot_header space */ BKNI_Memset(image->header, 0xff, sizeof(boot_header_t)); ram0 = (boot_header_t *)image->header; ram0->boot_order = boot_order; ram0->chip_id = 0x7572; return image_flash_install(FLASH_BASE, ram_offset, (uint8_t*)image->header, image->size+sizeof(boot_header_t)); } bresult image_flash_install(uint32_t base, uint32_t offset, uint8_t * data, uint32_t size) { bresult res; int fds_err; bfds_handle store; bfds_properties fprop; int sector_count; int i; void * page_data; uint32_t remaining_size; uint32_t block_size; uint32_t curr_offset; res = berr_external_error; if (BFDS_OK != bfds_open(&store)){ goto ExitFunc; } if (BFDS_OK != bfds_get_properties(store, &fprop)){ goto ExitFunc; } sector_count = size / fprop.flash_sector_size; if(size % fprop.flash_sector_size){ sector_count += 1; } curr_offset = offset; for(i = 0; i < sector_count; i++){ fds_err = bfds_sector_erase(store, curr_offset); if(BFDS_OK != fds_err){ goto ExitFunc; } curr_offset += fprop.flash_sector_size; } wstate.berased = true; i = 0; bos_sleep(100); /* yield for osi update */ curr_offset = offset; page_data = data; remaining_size = size; while(remaining_size > 0){ if(remaining_size > fprop.flash_page_size){ block_size = fprop.flash_page_size; }else{ block_size = remaining_size; } fds_err = bfds_page_program(store, curr_offset, page_data, block_size); if(BFDS_OK != fds_err){ goto ExitFunc; } remaining_size -= block_size; page_data = (void*)((uint32_t)page_data + block_size); curr_offset += block_size; wstate.wpct = (remaining_size*100)/size; if ((wstate.wpct % 4) == 0) { if (wstate.wpct/4 != i) { i = wstate.wpct/4; bos_sleep(100); } } } return 0; ExitFunc: return res; } bresult image_flash_install_fupdate(uint32_t base, uint32_t offset, uint8_t * data, uint32_t size) { bresult res; int fds_err; bfds_handle store; bfds_properties fprop; int sector_count; int i; void * page_data; uint32_t remaining_size; uint32_t block_size; uint32_t curr_offset; res = berr_external_error; if (BFDS_OK != bfds_open(&store)){ goto ExitFunc; } if (BFDS_OK != bfds_get_properties(store, &fprop)){ goto ExitFunc; } sector_count = fprop.flash_total_size / fprop.flash_sector_size; curr_offset = offset; for(i = 0; i < sector_count; i++){ fds_err = bfds_sector_erase(store, curr_offset); if(BFDS_OK != fds_err){ goto ExitFunc; } curr_offset += fprop.flash_sector_size; } wstate.berased = true; i = 0; bos_sleep(100); /* yield for osi update */ curr_offset = offset; page_data = data; remaining_size = size; while(remaining_size > 0){ if(remaining_size > fprop.flash_page_size){ block_size = fprop.flash_page_size; }else{ block_size = remaining_size; } fds_err = bfds_page_program(store, curr_offset, page_data, block_size); if(BFDS_OK != fds_err){ goto ExitFunc; } remaining_size -= block_size; page_data = (void*)((uint32_t)page_data + block_size); curr_offset += block_size; wstate.wpct = (remaining_size*100)/size; if ((wstate.wpct % 4) == 0) { if (wstate.wpct/4 != i) { i = wstate.wpct/4; bos_sleep(100); } } } return 0; ExitFunc: return res; } void image_get_wstate(bool *berased, int *wpct) { *berased = wstate.berased; *wpct = wstate.wpct; } #if (CONFIG_ENABLE_SCM == 1) #include "signature.c" const unsigned int broadcom_test_key[0x100/4] = { 0xbb4b3dac,0xaad0a0f7,0x69efdb63,0x0f0cf45d, 0xa8bee481,0xdae2ced3,0xb2a35773,0xb859cb6d, 0xc42a5f7d,0x0b02b5a6,0x40e81bde,0x592afa2c, 0xc6b0f440,0xc27adc14,0xa499709b,0xc6c06c05, 0x7fc11902,0xbcc63a02,0x68f07420,0xa701267f, 0xee6db3b1,0x7d563cd6,0xf749d20a,0x38f546f8, 0x805bbc09,0xa184b617,0xd1d2f5d7,0xe20de8be, 0x84b471a7,0x8d57e5f5,0x7d3cec98,0x290f3ad1, 0x1e6dbfa9,0x5e28a674,0xf02d0afc,0xe8f90d41, 0x033c6fd2,0x2b02f77d,0xcfe718af,0x0741699b, 0x4c933cba,0x71135d5e,0x3016bb7a,0x449efe72, 0xbfdd6f79,0x5849551a,0xa6e38ac3,0x9d74c7aa, 0xc6a3eb11,0xa20d3d63,0x55d74702,0xdaa1bd7c, 0x8af2ab33,0x694ba3bf,0xbd39dd1e,0x4b371322, 0x4593bf32,0x037837ba,0x1c854644,0xd6815619, 0x0e9720de,0xea891def,0x4bffc70f,0x1c1b92a7, }; /* production SCM modulus */ const unsigned int scm_key[0x100/4] = { 0xbb4b3dac,0xaad0a0f7,0x69efdb63,0x0f0cf45d, 0xa8bee481,0xdae2ced3,0xb2a35773,0xb859cb6d, 0xc42a5f7d,0x0b02b5a6,0x40e81bde,0x592afa2c, 0xc6b0f440,0xc27adc14,0xa499709b,0xc6c06c05, 0x7fc11902,0xbcc63a02,0x68f07420,0xa701267f, 0xee6db3b1,0x7d563cd6,0xf749d20a,0x38f546f8, 0x805bbc09,0xa184b617,0xd1d2f5d7,0xe20de8be, 0x84b471a7,0x8d57e5f5,0x7d3cec98,0x290f3ad1, 0x1e6dbfa9,0x5e28a674,0xf02d0afc,0xe8f90d41, 0x033c6fd2,0x2b02f77d,0xcfe718af,0x0741699b, 0x4c933cba,0x71135d5e,0x3016bb7a,0x449efe72, 0xbfdd6f79,0x5849551a,0xa6e38ac3,0x9d74c7aa, 0xc6a3eb11,0xa20d3d63,0x55d74702,0xdaa1bd7c, 0x8af2ab33,0x694ba3bf,0xbd39dd1e,0x4b371322, 0x4593bf32,0x037837ba,0x1c854644,0xd6815619, 0x0e9720de,0xea891def,0x4bffc70f,0x1c1b92a7, }; static int auth_image_authenticate(uint8_t *data) { application_info_header_t *ah; unsigned long signed_size; unsigned long signature_addr; scm_info_header_t *sh; int res; res = 1; ah = (application_info_header_t *)data; if (ah->chip_id != 0x7572) { BDBG_WRN(("Application header not found")); goto ExitFunc; } /* TODO:: key should be read from storage.. */ signed_size = sizeof(application_info_header_t) + ah->image_size; signature_addr = (unsigned long)ah + signed_size; res = signature_check((unsigned long)ah, signed_size, signature_addr, (unsigned long)broadcom_test_key); if (0 != res) { BDBG_WRN(("Application signature check failed")); res = 0; /* currently we are attaching fake.sig for application. */ /* goto ExitFunc; */ } sh = (scm_info_header_t *)(signature_addr + 0x100); if ((CHIP_ID != sh->chip_id) || (SCM_MAGIC != sh->scm_magic)) { res = 1; BDBG_WRN(("DSP loader header not found")); goto ExitFunc; } signed_size = sizeof(scm_info_header_t) + sh->image_size; signature_addr = (unsigned long)sh + signed_size; res = signature_check((unsigned long)sh, signed_size, signature_addr, (unsigned long)scm_key); if (0 != res) { BDBG_WRN(("DSP loader signature check failed")); } ExitFunc: return res; } #endif /* * return application info header structure if exists * * bank: 0 or 1 for BANK A/B * bact: [return] will be true if it's active image * return pointer application header. If not exists, will be NULL */ void *image_get_header(int bank, bool *bact) { boot_header_t * ram0; boot_header_t * ram1; application_info_header_t *app_header = NULL; unsigned int order0, order1, reverse = 0; int active = -1; ram0 = (boot_header_t *)FLASH_APP0_START; ram1 = (boot_header_t *)FLASH_APP1_START; *bact = false; if (BREG_Read32(GetREG(), BCHP_SUN_TOP_CTRL_UNCLEARED_SCRATCH) & IMAGE1_SELECTOR_MASK) reverse = 1; if (CHIP_ID == ram0->chip_id) { order0 = ram0->boot_order; if (CHIP_ID == ram1->chip_id) { order1 = ram1->boot_order; if (reverse && (order1 < order0)) active = 1; else if (!reverse && (order1 > order0)) active = 1; else active = 0; if (bank == 1) app_header = (application_info_header_t *)(FLASH_APP1_START + sizeof(boot_header_t)); } else { active = 0; } if (bank == 0) app_header = (application_info_header_t *)(FLASH_APP0_START + sizeof(boot_header_t)); } else if (CHIP_ID == ram1->chip_id) { active = 1; if (bank == 1) app_header = (application_info_header_t *)(FLASH_APP1_START + sizeof(boot_header_t)); } if (bank == active) *bact = true; /* verify application header is correct or not */ if (app_header && ((app_header->chip_id != CHIP_ID) || (app_header->dta_magic != DTA_MAGIC))) { /* invalid application header */ app_header = NULL; } return (void *)app_header; } /* Please do not remove! */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: nil */ /* End: */