• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <variant/variant.h>
18 
19 #include <bl.h>
20 
21 #include <plat/cmsis.h>
22 #include <plat/gpio.h>
23 
24 #include <nanohub/sha2.h>
25 #include <nanohub/aes.h>
26 #include <nanohub/rsa.h>
27 #include <nanohub/nanohub.h>
28 
29 #include <printf.h>
30 #include <string.h>
31 
32 static uint32_t blVerifyOsImage(const uint8_t *addr, struct OsUpdateHdr **start, uint32_t *size);
33 
34 
35 //for comms protocol
36 #define BL_SYNC_IN                      0x5A
37 #define BL_ACK                          0x79
38 #define BL_NAK                          0x1F
39 #define BL_SYNC_OUT                     0xA5
40 
41 #define BL_CMD_GET                      0x00
42 #define BL_CMD_READ_MEM                 0x11
43 #define BL_CMD_WRITE_MEM                0x31
44 #define BL_CMD_ERASE                    0x44
45 #define BL_CMD_GET_SIZES                0xEE /* our own command. reports: {u32 osSz, u32 sharedSz, u32 eeSz} all in big endian */
46 #define BL_CMD_UPDATE_FINISHED          0xEF /* our own command. attempts to verify the update -> ACK/NAK. MUST be called after upload to mark it as completed */
47 
48 #define BL_ERROR                        0xDEADBEAF /* returned in place of command in case of exchange errors */
49 
50 
51 #define BL_SHARED_AREA_FAKE_ERASE_BLK   0xFFF0
52 #define BL_SHARED_AREA_FAKE_ADDR        0x50000000
53 
54 
55 //linker provides these
56 extern uint32_t __pubkeys_start[];
57 extern uint32_t __pubkeys_end[];
58 extern uint8_t __eedata_start[];
59 extern uint8_t __eedata_end[];
60 extern uint8_t __code_start[];
61 extern uint8_t __code_end[];
62 extern uint8_t __shared_start[];
63 extern uint8_t __shared_end[];
64 
65 enum BlFlashType
66 {
67     BL_FLASH_BL,
68     BL_FLASH_EEDATA,
69     BL_FLASH_KERNEL,
70     BL_FLASH_SHARED
71 };
72 
73 static const struct blFlashTable   // For erase code, we need to know which page a given memory address is in
74 {
75     uint8_t *address;
76     uint32_t length;
77     uint32_t type;
78 } mBlFlashTable[] =
79 #ifndef BL_FLASH_TABLE
80 {
81     { (uint8_t *)(&BL),                      0x04000, BL_FLASH_BL     },
82     { (uint8_t *)(__eedata_start),           0x04000, BL_FLASH_EEDATA },
83     { (uint8_t *)(__eedata_start + 0x04000), 0x04000, BL_FLASH_EEDATA },
84     { (uint8_t *)(__code_start),             0x04000, BL_FLASH_KERNEL },
85     { (uint8_t *)(__code_start + 0x04000),   0x10000, BL_FLASH_KERNEL },
86     { (uint8_t *)(__code_start + 0x14000),   0x20000, BL_FLASH_KERNEL },
87     { (uint8_t *)(__shared_start),           0x20000, BL_FLASH_SHARED },
88     { (uint8_t *)(__shared_start + 0x20000), 0x20000, BL_FLASH_SHARED },
89 };
90 #else
91 BL_FLASH_TABLE;
92 #endif
93 
94 static const char mOsUpdateMagic[] = OS_UPDT_MAGIC;
95 
96 #ifdef DEBUG_UART_PIN
97 
blLogPutcharF(void * userData,char ch)98 static bool blLogPutcharF(void *userData, char ch)
99 {
100     if (ch == '\n')
101         gpioBitbangedUartOut('\r');
102 
103     gpioBitbangedUartOut(ch);
104 
105     return true;
106 }
107 
blLog(const char * str,...)108 void blLog(const char *str, ...)
109 {
110     va_list vl;
111 
112     va_start(vl, str);
113     cvprintf(blLogPutcharF, 0, NULL, str, vl);
114     va_end(vl);
115 }
116 
117 #else
118 
119 #define blLog(...)
120 
121 #endif
122 
blExtApiGetVersion(void)123 static uint32_t blExtApiGetVersion(void)
124 {
125     return BL_VERSION_CUR;
126 }
127 
blProgramFlash(uint8_t * dst,const uint8_t * src,uint32_t length,uint32_t key1,uint32_t key2)128 static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
129 {
130     const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
131     uint32_t offset, i, j = 0;
132     uint8_t *ptr;
133 
134     if (((length == 0)) ||
135         ((0xFFFFFFFF - (uint32_t)dst) < (length - 1)) ||
136         ((dst < mBlFlashTable[0].address)) ||
137         ((dst + length) > (mBlFlashTable[sector_cnt-1].address +
138                            mBlFlashTable[sector_cnt-1].length))) {
139         return false;
140     }
141 
142     // compute which flash block we are starting from
143     for (i = 0; i < sector_cnt; i++) {
144         if (dst >= mBlFlashTable[i].address &&
145             dst < (mBlFlashTable[i].address + mBlFlashTable[i].length)) {
146             break;
147         }
148     }
149 
150     // now loop through all the flash blocks and see if we have to do any
151     // 0 -> 1 transitions of a bit. If so, return false
152     // 1 -> 0 transitions of a bit do not require an erase
153     offset = (uint32_t)(dst - mBlFlashTable[i].address);
154     ptr = mBlFlashTable[i].address;
155     while (j < length && i < sector_cnt) {
156         if (offset == mBlFlashTable[i].length) {
157             i++;
158             offset = 0;
159             ptr = mBlFlashTable[i].address;
160         }
161 
162         if ((ptr[offset] & src[j]) != src[j]) {
163             return false;
164         } else {
165             j++;
166             offset++;
167         }
168     }
169 
170     if (!blPlatProgramFlash(dst, src, length, key1, key2))
171         return false;
172 
173     return !memcmp(dst, src, length);
174 }
175 
blExtApiGetSnum(uint32_t * snum,uint32_t length)176 static void blExtApiGetSnum(uint32_t *snum, uint32_t length)
177 {
178     blGetSnum(snum, length);
179 }
180 
blProgramTypedArea(uint8_t * dst,const uint8_t * src,uint32_t length,uint32_t type,uint32_t key1,uint32_t key2)181 static bool blProgramTypedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t type, uint32_t key1, uint32_t key2)
182 {
183     const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
184     uint32_t i;
185 
186     for (i = 0; i < sector_cnt; i++) {
187 
188         if ((dst >= mBlFlashTable[i].address &&
189              dst < (mBlFlashTable[i].address + mBlFlashTable[i].length)) ||
190             (dst < mBlFlashTable[i].address &&
191              (dst + length > mBlFlashTable[i].address))) {
192             if (mBlFlashTable[i].type != type)
193                 return false;
194         }
195     }
196 
197     return blProgramFlash(dst, src, length, key1, key2);
198 }
199 
blExtApiProgramSharedArea(uint8_t * dst,const uint8_t * src,uint32_t length,uint32_t key1,uint32_t key2)200 static bool blExtApiProgramSharedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
201 {
202     return blProgramTypedArea(dst, src, length, BL_FLASH_SHARED, key1, key2);
203 }
204 
blExtApiProgramEe(uint8_t * dst,const uint8_t * src,uint32_t length,uint32_t key1,uint32_t key2)205 static bool blExtApiProgramEe(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2)
206 {
207     return blProgramTypedArea(dst, src, length, BL_FLASH_EEDATA, key1, key2);
208 }
209 
blEraseTypedArea(uint32_t type,uint32_t key1,uint32_t key2)210 static bool blEraseTypedArea(uint32_t type, uint32_t key1, uint32_t key2)
211 {
212     const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable);
213     uint32_t i, erase_cnt = 0;
214     uint8_t erase_mask[sector_cnt];
215 
216     for (i = 0; i < sector_cnt; i++) {
217         if (mBlFlashTable[i].type == type) {
218             erase_mask[i] = 1;
219             erase_cnt++;
220         } else {
221             erase_mask[i] = 0;
222         }
223     }
224 
225     if (erase_cnt)
226         blEraseSectors(sector_cnt, erase_mask, key1, key2);
227 
228     return true; //we assume erase worked
229 }
230 
blExtApiEraseSharedArea(uint32_t key1,uint32_t key2)231 static bool blExtApiEraseSharedArea(uint32_t key1, uint32_t key2)
232 {
233     return blEraseTypedArea(BL_FLASH_SHARED, key1, key2);
234 }
235 
blVerifyOsUpdate(struct OsUpdateHdr ** start,uint32_t * size)236 static uint32_t blVerifyOsUpdate(struct OsUpdateHdr **start, uint32_t *size)
237 {
238     uint32_t ret;
239     int i;
240 
241     for (i = 0; i < BL_SCAN_OFFSET; i += 4) {
242         ret = blVerifyOsImage(__shared_start + i, start, size);
243         if (ret != OS_UPDT_HDR_CHECK_FAILED)
244             break;
245     }
246 
247     return ret;
248 }
249 
blExtApiVerifyOsUpdate(void)250 static uint32_t blExtApiVerifyOsUpdate(void)
251 {
252     return blVerifyOsUpdate(NULL, NULL);
253 }
254 
blExtApiReboot(void)255 static void blExtApiReboot(void)
256 {
257     blReboot();
258 }
259 
blExtApiGetRsaKeyInfo(uint32_t * numKeys)260 static const uint32_t *blExtApiGetRsaKeyInfo(uint32_t *numKeys)
261 {
262     uint32_t numWords = __pubkeys_end - __pubkeys_start;
263 
264     if (numWords % RSA_WORDS) // something is wrong
265         return NULL;
266 
267     *numKeys = numWords / RSA_WORDS;
268     return __pubkeys_start;
269 }
270 
blExtApiSigPaddingVerify(const uint32_t * rsaResult)271 static const uint32_t* blExtApiSigPaddingVerify(const uint32_t *rsaResult)
272 {
273     uint32_t i;
274 
275     //all but first and last word of padding MUST have no zero bytes
276     for (i = SHA2_HASH_WORDS + 1; i < RSA_WORDS - 1; i++) {
277         if (!(uint8_t)(rsaResult[i] >>  0))
278             return NULL;
279         if (!(uint8_t)(rsaResult[i] >>  8))
280             return NULL;
281         if (!(uint8_t)(rsaResult[i] >> 16))
282             return NULL;
283         if (!(uint8_t)(rsaResult[i] >> 24))
284             return NULL;
285     }
286 
287     //first padding word must have all nonzero bytes except low byte
288     if ((rsaResult[SHA2_HASH_WORDS] & 0xff) || !(rsaResult[SHA2_HASH_WORDS] & 0xff00) || !(rsaResult[SHA2_HASH_WORDS] & 0xff0000) || !(rsaResult[SHA2_HASH_WORDS] & 0xff000000))
289         return NULL;
290 
291     //last padding word must have 0x0002 in top 16 bits and nonzero random bytes in lower bytes
292     if ((rsaResult[RSA_WORDS - 1] >> 16) != 2)
293         return NULL;
294     if (!(rsaResult[RSA_WORDS - 1] & 0xff00) || !(rsaResult[RSA_WORDS - 1] & 0xff))
295         return NULL;
296 
297     return rsaResult;
298 }
299 
blApplyVerifiedUpdate(const struct OsUpdateHdr * os)300 static void blApplyVerifiedUpdate(const struct OsUpdateHdr *os) //only called if an update has been found to exist and be valid, signed, etc!
301 {
302     //copy shared to code, and if successful, erase shared area
303     if (blEraseTypedArea(BL_FLASH_KERNEL, BL_FLASH_KEY1, BL_FLASH_KEY2))
304         if (blProgramTypedArea(__code_start, (const uint8_t*)(os + 1), os->size, BL_FLASH_KERNEL, BL_FLASH_KEY1, BL_FLASH_KEY2))
305             (void)blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2);
306 }
307 
blWriteMark(struct OsUpdateHdr * hdr,uint32_t mark)308 static void blWriteMark(struct OsUpdateHdr *hdr, uint32_t mark)
309 {
310     uint8_t dstVal = mark;
311 
312     (void)blExtApiProgramSharedArea(&hdr->marker, &dstVal, sizeof(hdr->marker), BL_FLASH_KEY1, BL_FLASH_KEY2);
313 }
314 
blUpdateMark(uint32_t old,uint32_t new)315 static void blUpdateMark(uint32_t old, uint32_t new)
316 {
317     struct OsUpdateHdr *hdr = (struct OsUpdateHdr *)__shared_start;
318 
319     if (hdr->marker != old)
320         return;
321 
322     blWriteMark(hdr, new);
323 }
324 
blVerifyOsImage(const uint8_t * addr,struct OsUpdateHdr ** start,uint32_t * size)325 static uint32_t blVerifyOsImage(const uint8_t *addr, struct OsUpdateHdr **start, uint32_t *size)
326 {
327     const uint32_t *rsaKey, *osSigHash, *osSigPubkey, *ourHash, *rsaResult, *expectedHash = NULL;
328     struct OsUpdateHdr *hdr = (struct OsUpdateHdr*)addr;
329     struct OsUpdateHdr cpy;
330     uint32_t i, numRsaKeys = 0, rsaStateVar1, rsaStateVar2, rsaStep = 0;
331     const uint8_t *updateBinaryData;
332     bool isValid = false;
333     struct Sha2state sha;
334     struct RsaState rsa;
335     uint32_t ret = OS_UPDT_HDR_CHECK_FAILED;
336     const uint32_t overhead = sizeof(*hdr) + 2 * RSA_WORDS;
337 
338     // header does not fit or is not aligned
339     if (addr < __shared_start || addr > (__shared_end - overhead) || ((uintptr_t)addr & 3))
340         return OS_UPDT_HDR_CHECK_FAILED;
341 
342     // image does not fit
343     if (hdr->size > (__shared_end - addr - overhead))
344         return OS_UPDT_HDR_CHECK_FAILED;
345 
346     // OS magic does not match
347     if (memcmp(hdr->magic, mOsUpdateMagic, sizeof(hdr->magic)) != 0)
348         return OS_UPDT_HDR_CHECK_FAILED;
349 
350     // we don't allow shortcuts on success path, but we want to fail quickly
351     if (hdr->marker == OS_UPDT_MARKER_INVALID)
352         return OS_UPDT_HDR_MARKER_INVALID;
353 
354     // download did not finish
355     if (hdr->marker == OS_UPDT_MARKER_INPROGRESS)
356         return OS_UPDT_HDR_MARKER_INVALID;
357 
358     //get pointers
359     updateBinaryData = (const uint8_t*)(hdr + 1);
360     osSigHash = (const uint32_t*)(updateBinaryData + hdr->size);
361     osSigPubkey = osSigHash + RSA_WORDS;
362 
363     //make sure the pub key is known
364     for (i = 0, rsaKey = blExtApiGetRsaKeyInfo(&numRsaKeys); i < numRsaKeys; i++, rsaKey += RSA_WORDS) {
365         if (memcmp(rsaKey, osSigPubkey, RSA_BYTES) == 0)
366             break;
367     }
368 
369     if (i == numRsaKeys) {
370         ret = OS_UPDT_UNKNOWN_PUBKEY;
371         //signed with an unknown key -> fail
372         goto fail;
373     }
374 
375     //decode sig using pubkey
376     do {
377         rsaResult = rsaPubOpIterative(&rsa, osSigHash, osSigPubkey, &rsaStateVar1, &rsaStateVar2, &rsaStep);
378     } while (rsaStep);
379 
380     if (!rsaResult) {
381         //decode fails -> invalid sig
382         ret = OS_UPDT_INVALID_SIGNATURE;
383         goto fail;
384     }
385 
386     //verify padding
387     expectedHash = blExtApiSigPaddingVerify(rsaResult);
388 
389     if (!expectedHash) {
390         //padding check fails -> invalid sig
391         ret = OS_UPDT_INVALID_SIGNATURE_HASH;
392         goto fail;
393     }
394 
395     //hash the update
396     sha2init(&sha);
397 
398     memcpy(&cpy, hdr, sizeof(cpy));
399     cpy.marker = OS_UPDT_MARKER_INPROGRESS;
400     sha2processBytes(&sha, &cpy, sizeof(cpy));
401     sha2processBytes(&sha, (uint8_t*)(hdr + 1), hdr->size);
402     ourHash = sha2finish(&sha);
403 
404     //verify hash match
405     if (memcmp(expectedHash, ourHash, SHA2_HASH_SIZE) != 0) {
406         //hash does not match -> data tampered with
407         ret = OS_UPDT_INVALID_SIGNATURE_HASH; // same error; do not disclose nature of hash problem
408         goto fail;
409     }
410 
411     //it is valid
412     isValid = true;
413     ret = OS_UPDT_SUCCESS;
414     if (start)
415         *start = hdr;
416     if (size)
417         *size = hdr->size;
418 
419 fail:
420     //mark it appropriately
421     blWriteMark(hdr, isValid ? OS_UPDT_MARKER_VERIFIED : OS_UPDT_MARKER_INVALID);
422     return ret;
423 }
424 
blUpdateVerify()425 static inline bool blUpdateVerify()
426 {
427     return blVerifyOsImage(__shared_start, NULL, NULL) == OS_UPDT_SUCCESS;
428 }
429 
blLoaderRxByte()430 static uint8_t blLoaderRxByte()
431 {
432     return blSpiTxRxByte(0);
433 }
434 
blLoaderTxByte(uint32_t val)435 static void blLoaderTxByte(uint32_t val)
436 {
437     blSpiTxRxByte(val);
438 }
439 
blLoaderTxBytes(const void * data,uint32_t len)440 static void blLoaderTxBytes(const void *data, uint32_t len)
441 {
442     const uint8_t *buf = (const uint8_t*)data;
443 
444     blLoaderTxByte(len - 1);
445     while (len--)
446         blLoaderTxByte(*buf++);
447 }
448 
blLoaderSendSyncOut()449 static bool blLoaderSendSyncOut()
450 {
451     return blSpiTxRxByte(BL_SYNC_OUT) == BL_SYNC_IN;
452 }
453 
blLoaderSendAck(bool ack)454 static bool blLoaderSendAck(bool ack)
455 {
456     blLoaderRxByte();
457     blLoaderTxByte(ack ? BL_ACK : BL_NAK);
458     return blLoaderRxByte() == BL_ACK;
459 }
460 
blLoaderRxCmd()461 static uint32_t blLoaderRxCmd()
462 {
463     uint8_t cmd = blLoaderRxByte();
464     uint8_t cmdNot = blSpiTxRxByte(BL_ACK);
465     return (cmd ^ cmdNot) == 0xFF ? cmd : BL_ERROR;
466 }
467 
blLoader(bool force)468 static void blLoader(bool force)
469 {
470     bool seenErase = false;
471     uint32_t nextAddr = 0;
472     uint32_t expectedSize = 0;
473 
474     blSetup();
475 
476     //if int pin is not low, do not bother any further
477     if (blHostActive() || force) {
478 
479         blConfigIo();
480 
481         //if we saw a sync, do the bootloader thing
482         if (blSyncWait(BL_SYNC_IN)) {
483             static const uint8_t supportedCmds[] = {BL_CMD_GET, BL_CMD_READ_MEM, BL_CMD_WRITE_MEM, BL_CMD_ERASE, BL_CMD_GET_SIZES, BL_CMD_UPDATE_FINISHED};
484             uint32_t allSizes[] = {__builtin_bswap32(__code_end - __code_start), __builtin_bswap32(__shared_end - __shared_start), __builtin_bswap32(__eedata_end - __eedata_start)};
485             bool ack = true;  //we ack the sync
486 
487             ack = blLoaderSendSyncOut();
488 
489             //loop forever listening to commands
490             while (1) {
491                 uint32_t sync, cmd, addr = 0, len, checksum = 0, i;
492                 uint8_t data[256];
493 
494                 //send ack or NAK for last thing
495                 if (!blLoaderSendAck(ack))
496                     goto out;
497 
498                 while ((sync = blLoaderRxByte()) != BL_SYNC_IN);
499                 cmd = blLoaderRxCmd();
500 
501                 ack = false;
502                 if (sync == BL_SYNC_IN && cmd != BL_ERROR)
503                 switch (cmd) {
504                 case BL_CMD_GET:
505 
506                     //ACK the command
507                     (void)blLoaderSendAck(true);
508 
509                     blLoaderTxBytes(supportedCmds, sizeof(supportedCmds));
510                     ack = true;
511                     break;
512 
513                 case BL_CMD_READ_MEM:
514                     if (!seenErase)  //no reading till we erase the shared area (this way we do not leak encrypted apps' plaintexts)
515                         break;
516 
517                     //ACK the command
518                     (void)blLoaderSendAck(true);
519 
520                     //get address
521                     for (i = 0; i < 4; i++) {
522                         uint32_t byte = blLoaderRxByte();
523                         checksum ^= byte;
524                         addr = (addr << 8) + byte;
525                     }
526 
527                     //reject addresses outside of our fake area or on invalid checksum
528                     if (blLoaderRxByte() != checksum || addr < BL_SHARED_AREA_FAKE_ADDR || addr - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
529                        break;
530 
531                     //ack the address
532                     (void)blLoaderSendAck(true);
533 
534                     //get the length
535                     len = blLoaderRxByte();
536 
537                     //reject invalid checksum
538                     if (blLoaderRxByte() != (uint8_t)~len || addr + len - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
539                        break;
540 
541                     len++;
542 
543                     //reject reads past the end of the shared area
544                     if (addr + len - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
545                        break;
546 
547                     //ack the length
548                     (void)blLoaderSendAck(true);
549 
550                     //read the data & send it
551                     blLoaderTxBytes(__shared_start + addr - BL_SHARED_AREA_FAKE_ADDR, len);
552                     ack = true;
553                     break;
554 
555                 case BL_CMD_WRITE_MEM:
556                     if (!seenErase)  //no writing till we erase the shared area (this way we do not purposefully modify encrypted apps' plaintexts in a nefarious fashion)
557                         break;
558 
559                     //ACK the command
560                     (void)blLoaderSendAck(true);
561 
562                     //get address
563                     for (i = 0; i < 4; i++) {
564                         uint32_t byte = blLoaderRxByte();
565                         checksum ^= byte;
566                         addr = (addr << 8) + byte;
567                     }
568 
569                     //reject addresses outside of our fake area or on invalid checksum
570                     if (blLoaderRxByte() != checksum ||
571                         addr < BL_SHARED_AREA_FAKE_ADDR ||
572                         addr - BL_SHARED_AREA_FAKE_ADDR > __shared_end - __shared_start)
573                         break;
574 
575                     addr -= BL_SHARED_AREA_FAKE_ADDR;
576                     if (addr != nextAddr)
577                         break;
578 
579                     //ack the address
580                     (void)blLoaderSendAck(true);
581 
582                     //get the length
583                     checksum = len = blLoaderRxByte();
584                     len++;
585 
586                     //get bytes
587                     for (i = 0; i < len; i++) {
588                         uint32_t byte = blLoaderRxByte();
589                         checksum ^= byte;
590                         data[i] = byte;
591                     }
592 
593                     //reject writes that takes out outside fo shared area or invalid checksums
594                     if (blLoaderRxByte() != checksum || addr + len > __shared_end - __shared_start)
595                        break;
596 
597                     // OBSOLETE: superseded by sequential contiguous write requirement
598                     //if (addr && addr < sizeof(struct OsUpdateHdr))
599                     //    break;
600 
601                     //a write starting at zero must be big enough to contain a full OS update header
602                     if (!addr) {
603                         const struct OsUpdateHdr *hdr = (const struct OsUpdateHdr*)data;
604 
605                         //verify it is at least as big as the header
606                         if (len < sizeof(struct OsUpdateHdr))
607                             break;
608 
609                         //check for magic
610                         for (i = 0; i < sizeof(hdr->magic) && hdr->magic[i] == mOsUpdateMagic[i]; i++);
611 
612                         //verify magic check passed & marker is properly set to inprogress
613                         if (i != sizeof(hdr->magic) || hdr->marker != OS_UPDT_MARKER_INPROGRESS)
614                             break;
615                         expectedSize = sizeof(*hdr) + hdr->size + 2 * RSA_BYTES;
616                     }
617                     if (addr + len > expectedSize)
618                         break;
619 
620                     //do it
621                     ack = blExtApiProgramSharedArea(__shared_start + addr, data, len, BL_FLASH_KEY1, BL_FLASH_KEY2);
622                     blResetRxData();
623                     nextAddr += len;
624                     break;
625 
626                 case BL_CMD_ERASE:
627 
628                     //ACK the command
629                     (void)blLoaderSendAck(true);
630 
631                     //get address
632                     for (i = 0; i < 2; i++) {
633                         uint32_t byte = blLoaderRxByte();
634                         checksum ^= byte;
635                         addr = (addr << 8) + byte;
636                     }
637 
638                     //reject addresses that are not our magic address or on invalid checksum
639                     if (blLoaderRxByte() != checksum || addr != BL_SHARED_AREA_FAKE_ERASE_BLK)
640                         break;
641 
642                     //do it
643                     ack = blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2);
644                     if (ack) {
645                         seenErase = true;
646                         nextAddr = 0;
647                         expectedSize = 0;
648                     }
649                     blResetRxData();
650                     break;
651 
652                 case BL_CMD_GET_SIZES:
653 
654                     //ACK the command
655                     (void)blLoaderSendAck(true);
656 
657                     blLoaderTxBytes(allSizes, sizeof(allSizes));
658                     break;
659 
660                 case BL_CMD_UPDATE_FINISHED:
661                     blUpdateMark(OS_UPDT_MARKER_INPROGRESS, OS_UPDT_MARKER_DOWNLOADED);
662                     ack = blUpdateVerify();
663                     break;
664                 }
665             }
666         }
667     }
668 
669 out:
670     blCleanup();
671 }
672 
blMain(uint32_t appBase)673 void blMain(uint32_t appBase)
674 {
675     bool forceLoad = false;
676 
677     blLog("NanohubOS bootloader up @ %p\n", &blMain);
678 
679     //enter SPI loader if requested
680     do {
681         uint32_t res;
682         struct OsUpdateHdr *os;
683 
684         blLoader(forceLoad);
685         res = blVerifyOsUpdate(&os, NULL);
686         if (res == OS_UPDT_SUCCESS)
687             blApplyVerifiedUpdate(os);
688         else if (res != OS_UPDT_HDR_CHECK_FAILED)
689             blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2);
690 
691         forceLoad = true;
692     } while (*(volatile uint32_t*)appBase == 0xFFFFFFFF);
693 }
694 
695 const struct BlApiTable __attribute__((section(".blapi"))) __BL_API =
696 {
697     .blGetVersion = &blExtApiGetVersion,
698     .blReboot = &blExtApiReboot,
699     .blGetSnum = &blExtApiGetSnum,
700     .blProgramShared = &blExtApiProgramSharedArea,
701     .blEraseShared = &blExtApiEraseSharedArea,
702     .blProgramEe = &blExtApiProgramEe,
703     .blGetPubKeysInfo = &blExtApiGetRsaKeyInfo,
704     .blRsaPubOpIterative = &rsaPubOpIterative,
705     .blSha2init = &sha2init,
706     .blSha2processBytes = &sha2processBytes,
707     .blSha2finish = &sha2finish,
708     .blAesInitForEncr = &aesInitForEncr,
709     .blAesInitForDecr = &aesInitForDecr,
710     .blAesEncr = &aesEncr,
711     .blAesDecr = &aesDecr,
712     .blAesCbcInitForEncr = &aesCbcInitForEncr,
713     .blAesCbcInitForDecr = &aesCbcInitForDecr,
714     .blAesCbcEncr = &aesCbcEncr,
715     .blAesCbcDecr = &aesCbcDecr,
716     .blSigPaddingVerify = &blExtApiSigPaddingVerify,
717     .blVerifyOsUpdate = &blExtApiVerifyOsUpdate,
718 };
719