Home | History | Annotate | Download | only in core
      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 
     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 
    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 
    123 static uint32_t blExtApiGetVersion(void)
    124 {
    125     return BL_VERSION_CUR;
    126 }
    127 
    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 
    176 static void blExtApiGetSnum(uint32_t *snum, uint32_t length)
    177 {
    178     blGetSnum(snum, length);
    179 }
    180 
    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 
    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 
    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 
    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 
    231 static bool blExtApiEraseSharedArea(uint32_t key1, uint32_t key2)
    232 {
    233     return blEraseTypedArea(BL_FLASH_SHARED, key1, key2);
    234 }
    235 
    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 
    250 static uint32_t blExtApiVerifyOsUpdate(void)
    251 {
    252     return blVerifyOsUpdate(NULL, NULL);
    253 }
    254 
    255 static void blExtApiReboot(void)
    256 {
    257     blReboot();
    258 }
    259 
    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 
    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 
    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 
    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 
    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 
    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 
    425 static inline bool blUpdateVerify()
    426 {
    427     return blVerifyOsImage(__shared_start, NULL, NULL) == OS_UPDT_SUCCESS;
    428 }
    429 
    430 static uint8_t blLoaderRxByte()
    431 {
    432     return blSpiTxRxByte(0);
    433 }
    434 
    435 static void blLoaderTxByte(uint32_t val)
    436 {
    437     blSpiTxRxByte(val);
    438 }
    439 
    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 
    449 static bool blLoaderSendSyncOut()
    450 {
    451     return blSpiTxRxByte(BL_SYNC_OUT) == BL_SYNC_IN;
    452 }
    453 
    454 static bool blLoaderSendAck(bool ack)
    455 {
    456     blLoaderRxByte();
    457     blLoaderTxByte(ack ? BL_ACK : BL_NAK);
    458     return blLoaderRxByte() == BL_ACK;
    459 }
    460 
    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 
    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 
    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