/*************************************************************************** * Copyright (c) 2003-2010, 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: Stage 2 C entry point. * * Revision History: * * $brcm_Log: $ * * ***************************************************************************/ #include "bstd.h" #include "image_selector.h" #include "ramheader.h" #define KSEG0_KSEG1(x) ((0x20000000) | (unsigned long)(x)) #if defined(RSA_BITS) #define SIGNATURE_SIZE (RSA_BITS/8) #else #define SIGNATURE_SIZE 0x80 #endif #define XPT_OTP_MC1_BASE 0xb053802c /* starting location of bootloader in flash */ extern unsigned int flash_start; /* combined size of stage 1 and 2 bootloaders */ extern unsigned int _bootloader_size; /* write character on serial port */ extern void _writeasm(int c); /* copy memory block from word aligned src to word aligned destination with word aligned size. All pointer and size must be 4 bytes aligned */ extern void aligned_copy(void * src, void * dst, unsigned int n); extern void clear_all_d_cache(void); extern void invalidate_all_i_cache(void); /* constants and static data */ const unsigned int stage3_vma = 0x80000000; const unsigned int scm_vma = 0x80016000; #if 1 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, }; #else const unsigned int scm_key[0x100/4] = { /* test public key generated from privkey2048.pem */ 0xc743ee55,0xb3143b8d,0xb427ecb5,0xf31cc652, 0x3760d7d7,0xb1c8a2b7,0x4f853b90,0x9ae6fba0, 0x6d750313,0x33bfb2d9,0x5fb5e078,0xe65b01ce, 0xab976eb2,0x1cab3054,0x807b0111,0x9758d712, 0x315760c5,0x4312a951,0xea31d43f,0xdaee15ff, 0xfb432017,0x54d4762d,0x191b4950,0x95ed9b0c, 0xe89b47b7,0xb3c41116,0x9b294f0e,0xb84662cb, 0x63405466,0x49b70d4d,0x69fff19f,0x4804b8e0, 0x080965f5,0xe8765ab5,0xf5dbbf20,0xdd70df30, 0xf51644a3,0x900eba4d,0x1e9a9670,0x60518e67, 0x3a1038cb,0xb8fe6752,0x75b86eff,0x107a9a47, 0xcce14416,0x7d47ffd8,0xdd30fcfc,0x79b30b7c, 0xa2ba451c,0x0716442e,0x2d912f8a,0x6a31e3fc, 0x92bf8d4c,0x24112f41,0xaf6bc6b1,0x3b9a1925, 0x87a104f2,0x2e1793c2,0x79e7c4d7,0x535b8cbe, 0xe6f4debd,0xbaf2a446,0x8a4d7c5d,0x22508e73, }; #endif extern unsigned int key1[]; unsigned int key1_copy[SIGNATURE_SIZE/4]; #define OTP_MID() (((*(uint32_t*)XPT_OTP_MC1_BASE) >> 18) | ((*(uint32_t*)(XPT_OTP_MC1_BASE + 4)) << (32 - 18))) /* forward declarations */ int signature_check(unsigned long in, unsigned long size, unsigned long signature, unsigned long public_key); void invoke_dsp_loader(void); void print_string(char *s); void bootloader_main(void) { unsigned int * stage3_start; unsigned int stage3_size; unsigned int oem_key; unsigned int oem_mid; unsigned int signature; print_string("\r\nS2 " __DATE__":" __TIME__ "\r\n"); // __asm__("1: b 1b; nop;"); invoke_dsp_loader(); stage3_start = (unsigned int *)((unsigned int)&_bootloader_size + (unsigned int)&flash_start + SIGNATURE_SIZE); stage3_size = *(stage3_start + 4) + SIGNATURE_SIZE; aligned_copy(stage3_start, (void*)stage3_vma, stage3_size); aligned_copy(key1, key1_copy, SIGNATURE_SIZE); oem_key = stage3_vma + 0x400; /* key offset in the image */ oem_mid = oem_key + 0x100; signature = oem_mid + 0x40; /* authenticate key */ oem_mid = *((unsigned int*)oem_mid); if(OTP_MID() != oem_mid){ _writeasm('m'); /* market id check failed, make sure chip is secure */ if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) __asm__("wait ; 1: b 1b ; nop ;"); } if(0 != signature_check((unsigned long)oem_key, (SIGNATURE_SIZE+0x40), signature, (unsigned long)key1_copy)){ _writeasm('k'); /* signature check failed, make sure chip is secure */ if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) __asm__("wait ; 1: b 1b ; nop ;"); } /* authenticate s3 with oem key */ stage3_size -= SIGNATURE_SIZE; signature = stage3_vma + stage3_size; if(0 != signature_check((unsigned long)stage3_vma, stage3_size, signature, (unsigned long)oem_key)){ _writeasm('b'); /* signature check failed, make sure chip is secure */ if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) __asm__("wait ; 1: b 1b ; nop ;"); } clear_all_d_cache(); invalidate_all_i_cache(); ((void (*)(void))stage3_vma)(); } /* watchdog signature DLWD */ #define WD_SIGNATURE 0x444C5744 /* watchdog timeout 5 seconds */ #define WD_TIMEOUT 0x80befc0 /* watchdog singature register. LMC_CORE.SCB_DATA[10] */ #define WD_SIGNATURE_REG 0xB0340928 #define WD_TIMEOUT_REG 0xB04066E8 #define WD_WDCMG_REG 0xB04066EC #define WD_WDCRS_REG 0xB04066F4 /* Steps: - check if rebooted from watchdog - if did check if watchdog was from dsp loader - find active image - find scm in the active image - compute size of scm including header and signature - copy scm with header and signature in to ram - authenticate scm - setup watchdog - run scm loader - clear watchdog */ void invoke_dsp_loader(void) { void * image; void * image_ram; scm_info_header_t * sh; unsigned long size; unsigned long scm_sig; uint32_t val; /* check if we got here after watchdog fired */ val = *(uint32_t*)WD_WDCRS_REG; if(1 == val){ val = *(uint32_t*)WD_SIGNATURE_REG; if(WD_SIGNATURE == val){ *(uint32_t*)WD_SIGNATURE_REG = 0; /* just return if WD is fired and let second stage select another image */ goto ExitFunc; } } image = active_image_address(); image = dsp_loader_address(image); if(NULL == image){ goto ExitFunc; } sh = (scm_info_header_t *) image; size = sh->image_size + sizeof(scm_info_header_t) + SIGNATURE_SIZE; if(0x20000 < size){ /* size is too large */ goto ExitFunc; } image_ram = (void *)(scm_vma - sizeof(scm_info_header_t)); aligned_copy(image, image_ram, size); /* adjust size for authentication */ size -= SIGNATURE_SIZE; scm_sig = (unsigned long)image_ram + size; if(0 != signature_check((unsigned long)image_ram, size, scm_sig, (unsigned long)scm_key)){ print_string("Dsp loader invalid.\n\r"); /* signature check failed, make sure chip is secure */ if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) goto ExitFunc; /* if chip is not secure contunue with scm loading */ } print_string("Loading dsp..."); /* setup and start WD */ *(uint32_t*)WD_SIGNATURE_REG = WD_SIGNATURE; *(uint32_t*)WD_TIMEOUT_REG = WD_TIMEOUT; *(uint32_t*)WD_WDCMG_REG = 0xff00; *(uint32_t*)WD_WDCMG_REG = 0x00ff; clear_all_d_cache(); invalidate_all_i_cache(); /* invoke scm loader */ ((void (*)(void))scm_vma)(); /* stop WD */ *(uint32_t*)WD_SIGNATURE_REG = 0; *(uint32_t*)WD_WDCMG_REG = 0xee00; *(uint32_t*)WD_WDCMG_REG = 0x00ee; print_string("done\n\r"); ExitFunc: return; } void print_string(char *s) { while (*s) { _writeasm(*s++); } return; } #include "signature.c" /* Please do not remove! */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: nil */ /* End: */