1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2015 Daniel Campora
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 
31 #include "py/mpconfig.h"
32 #include "hw_ints.h"
33 #include "hw_types.h"
34 #include "hw_gpio.h"
35 #include "hw_memmap.h"
36 #include "hw_gprcm.h"
37 #include "hw_common_reg.h"
38 #include "pin.h"
39 #include "gpio.h"
40 #include "rom_map.h"
41 #include "prcm.h"
42 #include "simplelink.h"
43 #include "interrupt.h"
44 #include "gpio.h"
45 #include "flc.h"
46 #include "bootmgr.h"
47 #include "shamd5.h"
48 #include "cryptohash.h"
49 #include "utils.h"
50 #include "cc3200_hal.h"
51 #include "debug.h"
52 #include "mperror.h"
53 #include "antenna.h"
54 
55 
56 //*****************************************************************************
57 // Local Constants
58 //*****************************************************************************
59 #define SL_STOP_TIMEOUT                     35
60 #define BOOTMGR_HASH_ALGO                   SHAMD5_ALGO_MD5
61 #define BOOTMGR_HASH_SIZE                   32
62 #define BOOTMGR_BUFF_SIZE                   512
63 
64 #define BOOTMGR_WAIT_SAFE_MODE_0_MS         500
65 
66 #define BOOTMGR_WAIT_SAFE_MODE_1_MS         3000
67 #define BOOTMGR_WAIT_SAFE_MODE_1_BLINK_MS   500
68 
69 #define BOOTMGR_WAIT_SAFE_MODE_2_MS         3000
70 #define BOOTMGR_WAIT_SAFE_MODE_2_BLINK_MS   250
71 
72 #define BOOTMGR_WAIT_SAFE_MODE_3_MS         1500
73 #define BOOTMGR_WAIT_SAFE_MODE_3_BLINK_MS   100
74 
75 //*****************************************************************************
76 // Exported functions declarations
77 //*****************************************************************************
78 extern void bootmgr_run_app (_u32 base);
79 
80 //*****************************************************************************
81 // Local functions declarations
82 //*****************************************************************************
83 static void bootmgr_board_init (void);
84 static bool bootmgr_verify (_u8 *image);
85 static void bootmgr_load_and_execute (_u8 *image);
86 static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force_wait);
87 static bool safe_boot_request_start (uint32_t wait_time);
88 static void wait_for_safe_boot (sBootInfo_t *psBootInfo);
89 static void bootmgr_image_loader (sBootInfo_t *psBootInfo);
90 
91 //*****************************************************************************
92 // Private data
93 //*****************************************************************************
94 static _u8 bootmgr_file_buf[BOOTMGR_BUFF_SIZE];
95 static _u8 bootmgr_hash_buf[BOOTMGR_HASH_SIZE + 1];
96 
97 //*****************************************************************************
98 // Vector Table
99 //*****************************************************************************
100 extern void (* const g_pfnVectors[])(void);
101 
102 //*****************************************************************************
103 // WLAN Event handler callback hookup function
104 //*****************************************************************************
SimpleLinkWlanEventHandler(SlWlanEvent_t * pWlanEvent)105 void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent)
106 {
107 
108 }
109 
110 //*****************************************************************************
111 // HTTP Server callback hookup function
112 //*****************************************************************************
SimpleLinkHttpServerCallback(SlHttpServerEvent_t * pHttpEvent,SlHttpServerResponse_t * pHttpResponse)113 void SimpleLinkHttpServerCallback(SlHttpServerEvent_t *pHttpEvent,
114                                   SlHttpServerResponse_t *pHttpResponse)
115 {
116 
117 }
118 
119 //*****************************************************************************
120 // Net APP Event callback hookup function
121 //*****************************************************************************
SimpleLinkNetAppEventHandler(SlNetAppEvent_t * pNetAppEvent)122 void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent)
123 {
124 
125 }
126 
127 //*****************************************************************************
128 // General Event callback hookup function
129 //*****************************************************************************
SimpleLinkGeneralEventHandler(SlDeviceEvent_t * pDevEvent)130 void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent)
131 {
132 
133 }
134 
135 //*****************************************************************************
136 // Socket Event callback hookup function
137 //*****************************************************************************
SimpleLinkSockEventHandler(SlSockEvent_t * pSock)138 void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
139 {
140 
141 }
142 
143 //*****************************************************************************
144 //! Board Initialization & Configuration
145 //*****************************************************************************
bootmgr_board_init(void)146 static void bootmgr_board_init(void) {
147     // set the vector table base
148     MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
149 
150     // enable processor interrupts
151     MAP_IntMasterEnable();
152     MAP_IntEnable(FAULT_SYSTICK);
153 
154     // mandatory MCU initialization
155     PRCMCC3200MCUInit();
156 
157     // clear all the special bits, since we can't trust their content after reset
158     // except for the WDT reset one!!
159     PRCMClearSpecialBit(PRCM_SAFE_BOOT_BIT);
160     PRCMClearSpecialBit(PRCM_FIRST_BOOT_BIT);
161 
162     // check the reset after clearing the special bits
163     mperror_bootloader_check_reset_cause();
164 
165 #if MICROPY_HW_ANTENNA_DIVERSITY
166     // configure the antenna selection pins
167     antenna_init0();
168 #endif
169 
170     // enable the data hashing engine
171     CRYPTOHASH_Init();
172 
173     // init the system led and the system switch
174     mperror_init0();
175 }
176 
177 //*****************************************************************************
178 //! Verifies the integrity of the new application binary
179 //*****************************************************************************
bootmgr_verify(_u8 * image)180 static bool bootmgr_verify (_u8 *image) {
181     SlFsFileInfo_t FsFileInfo;
182     _u32 reqlen, offset = 0;
183     _i32 fHandle;
184 
185     // open the file for reading
186     if (0 == sl_FsOpen(image, FS_MODE_OPEN_READ, NULL, &fHandle)) {
187         // get the file size
188         sl_FsGetInfo(image, 0, &FsFileInfo);
189 
190         if (FsFileInfo.FileLen > BOOTMGR_HASH_SIZE) {
191             FsFileInfo.FileLen -= BOOTMGR_HASH_SIZE;
192             CRYPTOHASH_SHAMD5Start(BOOTMGR_HASH_ALGO, FsFileInfo.FileLen);
193             do {
194                 if ((FsFileInfo.FileLen - offset) > BOOTMGR_BUFF_SIZE) {
195                     reqlen = BOOTMGR_BUFF_SIZE;
196                 }
197                 else {
198                     reqlen = FsFileInfo.FileLen - offset;
199                 }
200 
201                 offset += sl_FsRead(fHandle, offset, bootmgr_file_buf, reqlen);
202                 CRYPTOHASH_SHAMD5Update(bootmgr_file_buf, reqlen);
203             } while (offset < FsFileInfo.FileLen);
204 
205             CRYPTOHASH_SHAMD5Read (bootmgr_file_buf);
206 
207             // convert the resulting hash to hex
208             for (_u32 i = 0; i < (BOOTMGR_HASH_SIZE / 2); i++) {
209                 snprintf ((char *)&bootmgr_hash_buf[(i * 2)], 3, "%02x", bootmgr_file_buf[i]);
210             }
211 
212             // read the hash from the file and close it
213             sl_FsRead(fHandle, offset, bootmgr_file_buf, BOOTMGR_HASH_SIZE);
214             sl_FsClose (fHandle, NULL, NULL, 0);
215             bootmgr_file_buf[BOOTMGR_HASH_SIZE] = '\0';
216             // compare both hashes
217             if (!strcmp((const char *)bootmgr_hash_buf, (const char *)bootmgr_file_buf)) {
218                 // it's a match
219                 return true;
220             }
221         }
222         // close the file
223         sl_FsClose(fHandle, NULL, NULL, 0);
224     }
225     return false;
226 }
227 
228 //*****************************************************************************
229 //! Loads the application from sFlash and executes
230 //*****************************************************************************
bootmgr_load_and_execute(_u8 * image)231 static void bootmgr_load_and_execute (_u8 *image) {
232     SlFsFileInfo_t pFsFileInfo;
233     _i32 fhandle;
234     // open the application binary
235     if (!sl_FsOpen(image, FS_MODE_OPEN_READ, NULL, &fhandle)) {
236         // get the file size
237         if (!sl_FsGetInfo(image, 0, &pFsFileInfo)) {
238             // read the application into SRAM
239             if (pFsFileInfo.FileLen == sl_FsRead(fhandle, 0, (unsigned char *)APP_IMG_SRAM_OFFSET, pFsFileInfo.FileLen)) {
240                 // close the file
241                 sl_FsClose(fhandle, 0, 0, 0);
242                 // stop the network services
243                 sl_Stop(SL_STOP_TIMEOUT);
244                 // execute the application
245                 bootmgr_run_app(APP_IMG_SRAM_OFFSET);
246             }
247         }
248     }
249 }
250 
251 //*****************************************************************************
252 //! Wait while the safe mode pin is being held high and blink the system led
253 //! with the specified period
254 //*****************************************************************************
wait_while_blinking(uint32_t wait_time,uint32_t period,bool force_wait)255 static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force_wait) {
256     _u32 count;
257     for (count = 0; (force_wait || MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) &&
258          ((period * count) < wait_time); count++) {
259         // toogle the led
260         MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
261         UtilsDelay(UTILS_DELAY_US_TO_COUNT(period * 1000));
262     }
263     return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false;
264 }
265 
safe_boot_request_start(uint32_t wait_time)266 static bool safe_boot_request_start (uint32_t wait_time) {
267     if (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) {
268         UtilsDelay(UTILS_DELAY_US_TO_COUNT(wait_time * 1000));
269     }
270     return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false;
271 }
272 
273 //*****************************************************************************
274 //! Check for the safe mode pin
275 //*****************************************************************************
wait_for_safe_boot(sBootInfo_t * psBootInfo)276 static void wait_for_safe_boot (sBootInfo_t *psBootInfo) {
277     if (safe_boot_request_start(BOOTMGR_WAIT_SAFE_MODE_0_MS)) {
278         if (wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_1_MS, BOOTMGR_WAIT_SAFE_MODE_1_BLINK_MS, false)) {
279             // go back one step in time
280             psBootInfo->ActiveImg = psBootInfo->PrevImg;
281             if (wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_2_MS, BOOTMGR_WAIT_SAFE_MODE_2_BLINK_MS, false)) {
282                 // go back directly to the factory image
283                 psBootInfo->ActiveImg = IMG_ACT_FACTORY;
284                 wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_3_MS, BOOTMGR_WAIT_SAFE_MODE_3_BLINK_MS, true);
285             }
286         }
287         // turn off the system led
288         MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
289         // request a safe boot to the application
290         PRCMSetSpecialBit(PRCM_SAFE_BOOT_BIT);
291     }
292     // deinit the safe boot pin
293     mperror_deinit_sfe_pin();
294 }
295 
296 //*****************************************************************************
297 //! Load the proper image based on the information from the boot info
298 //! and launch it.
299 //*****************************************************************************
bootmgr_image_loader(sBootInfo_t * psBootInfo)300 static void bootmgr_image_loader(sBootInfo_t *psBootInfo) {
301     _i32 fhandle;
302     _u8 *image;
303 
304     // search for the active image
305     switch (psBootInfo->ActiveImg) {
306     case IMG_ACT_UPDATE1:
307         image = (unsigned char *)IMG_UPDATE1;
308         break;
309     case IMG_ACT_UPDATE2:
310         image = (unsigned char *)IMG_UPDATE2;
311         break;
312     default:
313         image = (unsigned char *)IMG_FACTORY;
314         break;
315     }
316 
317     // do we have a new image that needs to be verified?
318     if ((psBootInfo->ActiveImg != IMG_ACT_FACTORY) && (psBootInfo->Status == IMG_STATUS_CHECK)) {
319         if (!bootmgr_verify(image)) {
320             // verification failed, delete the broken file
321             sl_FsDel(image, 0);
322             // switch to the previous image
323             psBootInfo->ActiveImg = psBootInfo->PrevImg;
324             psBootInfo->PrevImg = IMG_ACT_FACTORY;
325         }
326         // in any case, change the status to "READY"
327         psBootInfo->Status = IMG_STATUS_READY;
328         // write the new boot info
329         if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_WRITE, NULL, &fhandle)) {
330             sl_FsWrite(fhandle, 0, (unsigned char *)psBootInfo, sizeof(sBootInfo_t));
331             // close the file
332             sl_FsClose(fhandle, 0, 0, 0);
333         }
334     }
335 
336     // this one might modify the boot info hence it MUST be called after
337     // bootmgr_verify! (so that the changes are not saved to flash)
338     wait_for_safe_boot(psBootInfo);
339 
340     // select the active image again, since it might have changed
341     switch (psBootInfo->ActiveImg) {
342     case IMG_ACT_UPDATE1:
343         image = (unsigned char *)IMG_UPDATE1;
344         break;
345     case IMG_ACT_UPDATE2:
346         image = (unsigned char *)IMG_UPDATE2;
347         break;
348     default:
349         image = (unsigned char *)IMG_FACTORY;
350         break;
351     }
352     bootmgr_load_and_execute(image);
353 }
354 
355 //*****************************************************************************
356 //! Main function
357 //*****************************************************************************
main(void)358 int main (void) {
359     sBootInfo_t sBootInfo = { .ActiveImg = IMG_ACT_FACTORY, .Status = IMG_STATUS_READY, .PrevImg = IMG_ACT_FACTORY };
360     bool bootapp = false;
361     _i32 fhandle;
362 
363     // board setup
364     bootmgr_board_init();
365 
366     // start simplelink since we need it to access the sflash
367     sl_Start(0, 0, 0);
368 
369     // if a boot info file is found, load it, else, create a new one with the default boot info
370     if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) {
371         if (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) {
372             bootapp = true;
373         }
374         sl_FsClose(fhandle, 0, 0, 0);
375     }
376     // boot info file not present, it means that this is the first boot after being programmed
377     if (!bootapp) {
378         // create a new boot info file
379         _u32 BootInfoCreateFlag  = _FS_FILE_OPEN_FLAG_COMMIT | _FS_FILE_PUBLIC_WRITE | _FS_FILE_PUBLIC_READ;
380         if (!sl_FsOpen ((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_CREATE((2 * sizeof(sBootInfo_t)),
381                         BootInfoCreateFlag), NULL, &fhandle)) {
382             // write the default boot info.
383             if (sizeof(sBootInfo_t) == sl_FsWrite(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) {
384                 bootapp = true;
385             }
386             sl_FsClose(fhandle, 0, 0, 0);
387         }
388         // signal the first boot to the application
389         PRCMSetSpecialBit(PRCM_FIRST_BOOT_BIT);
390     }
391 
392     if (bootapp) {
393         // load and execute the image based on the boot info
394         bootmgr_image_loader(&sBootInfo);
395     }
396 
397     // stop simplelink
398     sl_Stop(SL_STOP_TIMEOUT);
399 
400     // if we've reached this point, then it means that a fatal error has occurred and the
401     // application could not be loaded, so, loop forever and signal the crash to the user
402     while (true) {
403         // keep the bld on
404         MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN);
405         __asm volatile(" dsb \n"
406                        " isb \n"
407                        " wfi \n");
408     }
409 }
410 
411 //*****************************************************************************
412 //! The following stub function is needed to link mp_vprintf
413 //*****************************************************************************
414 #include "py/qstr.h"
415 
qstr_data(qstr q,size_t * len)416 const byte *qstr_data(qstr q, size_t *len) {
417     *len = 0;
418     return NULL;
419 }
420