| 1 | /*************************************************************************** |
|---|
| 2 | * Copyright (c) 2003-2010, Broadcom Corporation |
|---|
| 3 | * All Rights Reserved |
|---|
| 4 | * Confidential Property of Broadcom Corporation |
|---|
| 5 | * |
|---|
| 6 | * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE |
|---|
| 7 | * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR |
|---|
| 8 | * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. |
|---|
| 9 | * |
|---|
| 10 | * $brcm_Workfile: $ |
|---|
| 11 | * $brcm_Revision: $ |
|---|
| 12 | * $brcm_Date: $ |
|---|
| 13 | * |
|---|
| 14 | * Module Description: Stage 2 C entry point. |
|---|
| 15 | * |
|---|
| 16 | * Revision History: |
|---|
| 17 | * |
|---|
| 18 | * $brcm_Log: $ |
|---|
| 19 | * |
|---|
| 20 | * |
|---|
| 21 | ***************************************************************************/ |
|---|
| 22 | #include "bstd.h" |
|---|
| 23 | #include "image_selector.h" |
|---|
| 24 | #include "ramheader.h" |
|---|
| 25 | |
|---|
| 26 | #define KSEG0_KSEG1(x) ((0x20000000) | (unsigned long)(x)) |
|---|
| 27 | #if defined(RSA_BITS) |
|---|
| 28 | #define SIGNATURE_SIZE (RSA_BITS/8) |
|---|
| 29 | #else |
|---|
| 30 | #define SIGNATURE_SIZE 0x80 |
|---|
| 31 | #endif |
|---|
| 32 | |
|---|
| 33 | #define XPT_OTP_MC1_BASE 0xb053802c |
|---|
| 34 | |
|---|
| 35 | /* starting location of bootloader in flash */ |
|---|
| 36 | extern unsigned int flash_start; |
|---|
| 37 | /* combined size of stage 1 and 2 bootloaders */ |
|---|
| 38 | extern unsigned int _bootloader_size; |
|---|
| 39 | |
|---|
| 40 | /* write character on serial port */ |
|---|
| 41 | extern void _writeasm(int c); |
|---|
| 42 | /* copy memory block from word aligned src to word aligned destination |
|---|
| 43 | with word aligned size. All pointer and size must be 4 bytes aligned */ |
|---|
| 44 | extern void aligned_copy(void * src, void * dst, unsigned int n); |
|---|
| 45 | extern void clear_all_d_cache(void); |
|---|
| 46 | extern void invalidate_all_i_cache(void); |
|---|
| 47 | |
|---|
| 48 | /* constants and static data */ |
|---|
| 49 | const unsigned int stage3_vma = 0x80000000; |
|---|
| 50 | const unsigned int scm_vma = 0x80016000; |
|---|
| 51 | #if 1 |
|---|
| 52 | const unsigned int scm_key[0x100/4] = |
|---|
| 53 | { |
|---|
| 54 | 0xbb4b3dac,0xaad0a0f7,0x69efdb63,0x0f0cf45d, |
|---|
| 55 | 0xa8bee481,0xdae2ced3,0xb2a35773,0xb859cb6d, |
|---|
| 56 | 0xc42a5f7d,0x0b02b5a6,0x40e81bde,0x592afa2c, |
|---|
| 57 | 0xc6b0f440,0xc27adc14,0xa499709b,0xc6c06c05, |
|---|
| 58 | 0x7fc11902,0xbcc63a02,0x68f07420,0xa701267f, |
|---|
| 59 | 0xee6db3b1,0x7d563cd6,0xf749d20a,0x38f546f8, |
|---|
| 60 | 0x805bbc09,0xa184b617,0xd1d2f5d7,0xe20de8be, |
|---|
| 61 | 0x84b471a7,0x8d57e5f5,0x7d3cec98,0x290f3ad1, |
|---|
| 62 | 0x1e6dbfa9,0x5e28a674,0xf02d0afc,0xe8f90d41, |
|---|
| 63 | 0x033c6fd2,0x2b02f77d,0xcfe718af,0x0741699b, |
|---|
| 64 | 0x4c933cba,0x71135d5e,0x3016bb7a,0x449efe72, |
|---|
| 65 | 0xbfdd6f79,0x5849551a,0xa6e38ac3,0x9d74c7aa, |
|---|
| 66 | 0xc6a3eb11,0xa20d3d63,0x55d74702,0xdaa1bd7c, |
|---|
| 67 | 0x8af2ab33,0x694ba3bf,0xbd39dd1e,0x4b371322, |
|---|
| 68 | 0x4593bf32,0x037837ba,0x1c854644,0xd6815619, |
|---|
| 69 | 0x0e9720de,0xea891def,0x4bffc70f,0x1c1b92a7, |
|---|
| 70 | }; |
|---|
| 71 | #else |
|---|
| 72 | const unsigned int scm_key[0x100/4] = |
|---|
| 73 | { |
|---|
| 74 | /* test public key generated from privkey2048.pem */ |
|---|
| 75 | 0xc743ee55,0xb3143b8d,0xb427ecb5,0xf31cc652, |
|---|
| 76 | 0x3760d7d7,0xb1c8a2b7,0x4f853b90,0x9ae6fba0, |
|---|
| 77 | 0x6d750313,0x33bfb2d9,0x5fb5e078,0xe65b01ce, |
|---|
| 78 | 0xab976eb2,0x1cab3054,0x807b0111,0x9758d712, |
|---|
| 79 | 0x315760c5,0x4312a951,0xea31d43f,0xdaee15ff, |
|---|
| 80 | 0xfb432017,0x54d4762d,0x191b4950,0x95ed9b0c, |
|---|
| 81 | 0xe89b47b7,0xb3c41116,0x9b294f0e,0xb84662cb, |
|---|
| 82 | 0x63405466,0x49b70d4d,0x69fff19f,0x4804b8e0, |
|---|
| 83 | 0x080965f5,0xe8765ab5,0xf5dbbf20,0xdd70df30, |
|---|
| 84 | 0xf51644a3,0x900eba4d,0x1e9a9670,0x60518e67, |
|---|
| 85 | 0x3a1038cb,0xb8fe6752,0x75b86eff,0x107a9a47, |
|---|
| 86 | 0xcce14416,0x7d47ffd8,0xdd30fcfc,0x79b30b7c, |
|---|
| 87 | 0xa2ba451c,0x0716442e,0x2d912f8a,0x6a31e3fc, |
|---|
| 88 | 0x92bf8d4c,0x24112f41,0xaf6bc6b1,0x3b9a1925, |
|---|
| 89 | 0x87a104f2,0x2e1793c2,0x79e7c4d7,0x535b8cbe, |
|---|
| 90 | 0xe6f4debd,0xbaf2a446,0x8a4d7c5d,0x22508e73, |
|---|
| 91 | }; |
|---|
| 92 | #endif |
|---|
| 93 | |
|---|
| 94 | extern unsigned int key1[]; |
|---|
| 95 | unsigned int key1_copy[SIGNATURE_SIZE/4]; |
|---|
| 96 | |
|---|
| 97 | #define OTP_MID() (((*(uint32_t*)XPT_OTP_MC1_BASE) >> 18) | ((*(uint32_t*)(XPT_OTP_MC1_BASE + 4)) << (32 - 18))) |
|---|
| 98 | |
|---|
| 99 | /* forward declarations */ |
|---|
| 100 | int signature_check(unsigned long in, unsigned long size, unsigned long signature, unsigned long public_key); |
|---|
| 101 | void invoke_dsp_loader(void); |
|---|
| 102 | void print_string(char *s); |
|---|
| 103 | |
|---|
| 104 | void bootloader_main(void) |
|---|
| 105 | { |
|---|
| 106 | unsigned int * stage3_start; |
|---|
| 107 | unsigned int stage3_size; |
|---|
| 108 | unsigned int oem_key; |
|---|
| 109 | unsigned int oem_mid; |
|---|
| 110 | unsigned int signature; |
|---|
| 111 | |
|---|
| 112 | print_string("\r\nS2 " __DATE__":" __TIME__ "\r\n"); |
|---|
| 113 | // __asm__("1: b 1b; nop;"); |
|---|
| 114 | invoke_dsp_loader(); |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | stage3_start = (unsigned int *)((unsigned int)&_bootloader_size + (unsigned int)&flash_start + SIGNATURE_SIZE); |
|---|
| 118 | stage3_size = *(stage3_start + 4) + SIGNATURE_SIZE; |
|---|
| 119 | aligned_copy(stage3_start, (void*)stage3_vma, stage3_size); |
|---|
| 120 | |
|---|
| 121 | aligned_copy(key1, key1_copy, SIGNATURE_SIZE); |
|---|
| 122 | oem_key = stage3_vma + 0x400; /* key offset in the image */ |
|---|
| 123 | oem_mid = oem_key + 0x100; |
|---|
| 124 | signature = oem_mid + 0x40; |
|---|
| 125 | /* authenticate key */ |
|---|
| 126 | oem_mid = *((unsigned int*)oem_mid); |
|---|
| 127 | if(OTP_MID() != oem_mid){ |
|---|
| 128 | _writeasm('m'); |
|---|
| 129 | /* market id check failed, make sure chip is secure */ |
|---|
| 130 | if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) |
|---|
| 131 | __asm__("wait ; 1: b 1b ; nop ;"); |
|---|
| 132 | |
|---|
| 133 | } |
|---|
| 134 | if(0 != signature_check((unsigned long)oem_key, (SIGNATURE_SIZE+0x40), signature, (unsigned long)key1_copy)){ |
|---|
| 135 | _writeasm('k'); |
|---|
| 136 | /* signature check failed, make sure chip is secure */ |
|---|
| 137 | if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) |
|---|
| 138 | __asm__("wait ; 1: b 1b ; nop ;"); |
|---|
| 139 | } |
|---|
| 140 | /* authenticate s3 with oem key */ |
|---|
| 141 | stage3_size -= SIGNATURE_SIZE; |
|---|
| 142 | signature = stage3_vma + stage3_size; |
|---|
| 143 | if(0 != signature_check((unsigned long)stage3_vma, stage3_size, signature, (unsigned long)oem_key)){ |
|---|
| 144 | _writeasm('b'); |
|---|
| 145 | /* signature check failed, make sure chip is secure */ |
|---|
| 146 | if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) |
|---|
| 147 | __asm__("wait ; 1: b 1b ; nop ;"); |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | clear_all_d_cache(); |
|---|
| 151 | invalidate_all_i_cache(); |
|---|
| 152 | |
|---|
| 153 | ((void (*)(void))stage3_vma)(); |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | /* watchdog signature DLWD */ |
|---|
| 157 | #define WD_SIGNATURE 0x444C5744 |
|---|
| 158 | /* watchdog timeout 5 seconds */ |
|---|
| 159 | #define WD_TIMEOUT 0x80befc0 |
|---|
| 160 | /* watchdog singature register. LMC_CORE.SCB_DATA[10] */ |
|---|
| 161 | #define WD_SIGNATURE_REG 0xB0340928 |
|---|
| 162 | #define WD_TIMEOUT_REG 0xB04066E8 |
|---|
| 163 | #define WD_WDCMG_REG 0xB04066EC |
|---|
| 164 | #define WD_WDCRS_REG 0xB04066F4 |
|---|
| 165 | |
|---|
| 166 | /* |
|---|
| 167 | Steps: |
|---|
| 168 | - check if rebooted from watchdog |
|---|
| 169 | - if did check if watchdog was from dsp loader |
|---|
| 170 | - find active image |
|---|
| 171 | - find scm in the active image |
|---|
| 172 | - compute size of scm including header and signature |
|---|
| 173 | - copy scm with header and signature in to ram |
|---|
| 174 | - authenticate scm |
|---|
| 175 | - setup watchdog |
|---|
| 176 | - run scm loader |
|---|
| 177 | - clear watchdog |
|---|
| 178 | */ |
|---|
| 179 | void invoke_dsp_loader(void) |
|---|
| 180 | { |
|---|
| 181 | void * image; |
|---|
| 182 | void * image_ram; |
|---|
| 183 | scm_info_header_t * sh; |
|---|
| 184 | unsigned long size; |
|---|
| 185 | unsigned long scm_sig; |
|---|
| 186 | uint32_t val; |
|---|
| 187 | |
|---|
| 188 | /* check if we got here after watchdog fired */ |
|---|
| 189 | val = *(uint32_t*)WD_WDCRS_REG; |
|---|
| 190 | if(1 == val){ |
|---|
| 191 | val = *(uint32_t*)WD_SIGNATURE_REG; |
|---|
| 192 | if(WD_SIGNATURE == val){ |
|---|
| 193 | *(uint32_t*)WD_SIGNATURE_REG = 0; |
|---|
| 194 | /* just return if WD is fired and let second stage select another |
|---|
| 195 | image */ |
|---|
| 196 | goto ExitFunc; |
|---|
| 197 | } |
|---|
| 198 | } |
|---|
| 199 | image = active_image_address(); |
|---|
| 200 | |
|---|
| 201 | image = dsp_loader_address(image); |
|---|
| 202 | if(NULL == image){ |
|---|
| 203 | goto ExitFunc; |
|---|
| 204 | } |
|---|
| 205 | sh = (scm_info_header_t *) image; |
|---|
| 206 | size = sh->image_size + sizeof(scm_info_header_t) + SIGNATURE_SIZE; |
|---|
| 207 | if(0x20000 < size){ |
|---|
| 208 | /* size is too large */ |
|---|
| 209 | goto ExitFunc; |
|---|
| 210 | } |
|---|
| 211 | image_ram = (void *)(scm_vma - sizeof(scm_info_header_t)); |
|---|
| 212 | aligned_copy(image, image_ram, size); |
|---|
| 213 | /* adjust size for authentication */ |
|---|
| 214 | size -= SIGNATURE_SIZE; |
|---|
| 215 | scm_sig = (unsigned long)image_ram + size; |
|---|
| 216 | if(0 != signature_check((unsigned long)image_ram, size, scm_sig, (unsigned long)scm_key)){ |
|---|
| 217 | print_string("Dsp loader invalid.\n\r"); |
|---|
| 218 | /* signature check failed, make sure chip is secure */ |
|---|
| 219 | if(4 == ((*(uint32_t*)XPT_OTP_MC1_BASE) & 4)) |
|---|
| 220 | goto ExitFunc; |
|---|
| 221 | /* if chip is not secure contunue with scm loading */ |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | print_string("Loading dsp..."); |
|---|
| 225 | /* setup and start WD */ |
|---|
| 226 | *(uint32_t*)WD_SIGNATURE_REG = WD_SIGNATURE; |
|---|
| 227 | *(uint32_t*)WD_TIMEOUT_REG = WD_TIMEOUT; |
|---|
| 228 | *(uint32_t*)WD_WDCMG_REG = 0xff00; |
|---|
| 229 | *(uint32_t*)WD_WDCMG_REG = 0x00ff; |
|---|
| 230 | |
|---|
| 231 | clear_all_d_cache(); |
|---|
| 232 | invalidate_all_i_cache(); |
|---|
| 233 | /* invoke scm loader */ |
|---|
| 234 | ((void (*)(void))scm_vma)(); |
|---|
| 235 | /* stop WD */ |
|---|
| 236 | *(uint32_t*)WD_SIGNATURE_REG = 0; |
|---|
| 237 | *(uint32_t*)WD_WDCMG_REG = 0xee00; |
|---|
| 238 | *(uint32_t*)WD_WDCMG_REG = 0x00ee; |
|---|
| 239 | print_string("done\n\r"); |
|---|
| 240 | ExitFunc: |
|---|
| 241 | return; |
|---|
| 242 | } |
|---|
| 243 | |
|---|
| 244 | void print_string(char *s) |
|---|
| 245 | { |
|---|
| 246 | while (*s) |
|---|
| 247 | { |
|---|
| 248 | _writeasm(*s++); |
|---|
| 249 | } |
|---|
| 250 | return; |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | |
|---|
| 254 | #include "signature.c" |
|---|
| 255 | |
|---|
| 256 | /* Please do not remove! */ |
|---|
| 257 | /* Local Variables: */ |
|---|
| 258 | /* mode: C */ |
|---|
| 259 | /* indent-tabs-mode: nil */ |
|---|
| 260 | /* End: */ |
|---|