1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include "mcuboot_config/mcuboot_config.h"
21 
22 #include <assert.h>
23 #include <stddef.h>
24 #include <inttypes.h>
25 #include <stdio.h>
26 
27 #include <syscfg/syscfg.h>
28 #include <flash_map_backend/flash_map_backend.h>
29 #include <os/os.h>
30 #include <bsp/bsp.h>
31 #include <hal/hal_bsp.h>
32 #include <hal/hal_system.h>
33 #include <hal/hal_flash.h>
34 #include <hal/hal_watchdog.h>
35 #include <sysinit/sysinit.h>
36 #ifdef MCUBOOT_SERIAL
37 #include <hal/hal_gpio.h>
38 #include <hal/hal_nvreg.h>
39 #include <boot_serial/boot_serial.h>
40 #endif
41 #if defined(MCUBOOT_SERIAL)
42 #include <boot_uart/boot_uart.h>
43 #endif
44 #include <console/console.h>
45 #include "bootutil/image.h"
46 #include "bootutil/bootutil.h"
47 #include "bootutil/bootutil_log.h"
48 #include "bootutil/fault_injection_hardening.h"
49 
50 #if MYNEWT_VAL(BOOT_CUSTOM_START)
51 void boot_custom_start(uintptr_t flash_base, struct boot_rsp *rsp);
52 #endif
53 
54 #if defined(MCUBOOT_SERIAL)
55 #define BOOT_SERIAL_REPORT_DUR  \
56     (MYNEWT_VAL(OS_CPUTIME_FREQ) / MYNEWT_VAL(BOOT_SERIAL_REPORT_FREQ))
57 #define BOOT_SERIAL_INPUT_MAX (512)
58 
59 static int boot_read(char *str, int cnt, int *newline);
60 static const struct boot_uart_funcs boot_uart_funcs = {
61     .read = boot_read,
62     .write = boot_uart_write
63 };
64 
65 static int
boot_read(char * str,int cnt,int * newline)66 boot_read(char *str, int cnt, int *newline)
67 {
68 #if MYNEWT_VAL(BOOT_SERIAL_REPORT_PIN) != -1
69     static uint32_t tick = 0;
70 
71     if (tick == 0) {
72         /*
73          * Configure GPIO line as output. This is a pin we toggle at the
74          * given frequency.
75          */
76         hal_gpio_init_out(MYNEWT_VAL(BOOT_SERIAL_REPORT_PIN), 0);
77         tick = os_cputime_get32();
78     } else {
79         if (os_cputime_get32() - tick > BOOT_SERIAL_REPORT_DUR) {
80             hal_gpio_toggle(MYNEWT_VAL(BOOT_SERIAL_REPORT_PIN));
81             tick = os_cputime_get32();
82         }
83     }
84 #endif
85     hal_watchdog_tickle();
86 
87     return boot_uart_read(str, cnt, newline);
88 }
89 
90 #if MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) != 0
91 
92 /** Don't include null-terminator in comparison. */
93 #define BOOT_SERIAL_DETECT_STRING_LEN \
94     (sizeof MYNEWT_VAL(BOOT_SERIAL_DETECT_STRING) - 1)
95 
96 /**
97  * Listens on the UART for the management string.  Blocks for up to
98  * BOOT_SERIAL_DETECT_TIMEOUT milliseconds.
99  *
100  * @return                      true if the management string was received;
101  *                              false if the management string was not received
102  *                                  before the UART listen timeout expired.
103  */
104 static bool
serial_detect_uart_string(void)105 serial_detect_uart_string(void)
106 {
107     uint32_t start_tick;
108     char buf[BOOT_SERIAL_DETECT_STRING_LEN] = { 0 };
109     char ch;
110     int newline;
111     int rc;
112 
113     /* Calculate the timeout duration in OS cputime ticks. */
114     static const uint32_t timeout_dur =
115         MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) /
116         (1000.0 / MYNEWT_VAL(OS_CPUTIME_FREQ));
117 
118     rc = boot_uart_open();
119     assert(rc == 0);
120 
121     start_tick = os_cputime_get32();
122 
123     while (1) {
124         /* Read a single character from the UART. */
125         rc = boot_uart_read(&ch, 1, &newline);
126         if (rc > 0) {
127             /* Eliminate the oldest character in the buffer to make room for
128              * the new one.
129              */
130             memmove(buf, buf + 1, BOOT_SERIAL_DETECT_STRING_LEN - 1);
131             buf[BOOT_SERIAL_DETECT_STRING_LEN - 1] = ch;
132 
133             /* If the full management string has been received, indicate that
134              * the serial boot loader should start.
135              */
136             rc = memcmp(buf,
137                         MYNEWT_VAL(BOOT_SERIAL_DETECT_STRING),
138                         BOOT_SERIAL_DETECT_STRING_LEN);
139             if (rc == 0) {
140                 boot_uart_close();
141                 return true;
142             }
143         }
144 
145         /* Abort the listen on timeout. */
146         if (os_cputime_get32() >= start_tick + timeout_dur) {
147             boot_uart_close();
148             return false;
149         }
150     }
151 }
152 #endif
153 
154 static void
serial_boot_detect(void)155 serial_boot_detect(void)
156 {
157     /*
158      * Read retained register and compare with expected magic value.
159      * If it matches, await for download commands from serial.
160      */
161 #if MYNEWT_VAL(BOOT_SERIAL_NVREG_INDEX) != -1
162     if (hal_nvreg_read(MYNEWT_VAL(BOOT_SERIAL_NVREG_INDEX)) ==
163         MYNEWT_VAL(BOOT_SERIAL_NVREG_MAGIC)) {
164 
165         hal_nvreg_write(MYNEWT_VAL(BOOT_SERIAL_NVREG_INDEX), 0);
166         goto serial_boot;
167     }
168 #endif
169 
170     /*
171      * Configure a GPIO as input, and compare it against expected value.
172      * If it matches, await for download commands from serial.
173      */
174 #if MYNEWT_VAL(BOOT_SERIAL_DETECT_PIN) != -1
175     hal_gpio_init_in(MYNEWT_VAL(BOOT_SERIAL_DETECT_PIN),
176                      MYNEWT_VAL(BOOT_SERIAL_DETECT_PIN_CFG));
177     if (hal_gpio_read(MYNEWT_VAL(BOOT_SERIAL_DETECT_PIN)) ==
178                       MYNEWT_VAL(BOOT_SERIAL_DETECT_PIN_VAL)) {
179         goto serial_boot;
180     }
181 #endif
182 
183     /*
184      * Listen for management pattern in UART input.  If detected, await for
185      * download commands from serial.
186      */
187 #if MYNEWT_VAL(BOOT_SERIAL_DETECT_TIMEOUT) != 0
188     if (serial_detect_uart_string()) {
189         goto serial_boot;
190     }
191 #endif
192     return;
193 serial_boot:
194     boot_uart_open();
195     boot_serial_start(&boot_uart_funcs);
196     assert(0);
197 }
198 #endif
199 
200 /*
201  * Temporary flash_device_base() implementation.
202  *
203  * TODO: remove this when mynewt needs to support flash_device_base()
204  * for devices with nonzero base addresses.
205  */
flash_device_base(uint8_t fd_id,uintptr_t * ret)206 int flash_device_base(uint8_t fd_id, uintptr_t *ret)
207 {
208     *ret = 0;
209     return 0;
210 }
211 
212 int
main(void)213 main(void)
214 {
215     struct boot_rsp rsp;
216     uintptr_t flash_base;
217     int rc;
218     fih_int fih_rc = FIH_FAILURE;
219 
220     hal_bsp_init();
221 
222 #if !MYNEWT_VAL(OS_SCHEDULING) && MYNEWT_VAL(WATCHDOG_INTERVAL)
223     rc = hal_watchdog_init(MYNEWT_VAL(WATCHDOG_INTERVAL));
224     assert(rc == 0);
225 #endif
226 
227 #if defined(MCUBOOT_SERIAL) || defined(MCUBOOT_HAVE_LOGGING) || \
228         MYNEWT_VAL(CRYPTO) || MYNEWT_VAL(HASH)
229     /* initialize uart/crypto without os */
230     os_dev_initialize_all(OS_DEV_INIT_PRIMARY);
231     os_dev_initialize_all(OS_DEV_INIT_SECONDARY);
232     sysinit();
233     console_blocking_mode();
234 #if defined(MCUBOOT_SERIAL)
235     serial_boot_detect();
236     hal_timer_deinit(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM));
237 #endif
238 #else
239     flash_map_init();
240 #endif
241 
242     FIH_CALL(boot_go, fih_rc, &rsp);
243     if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
244         assert(fih_int_decode(fih_rc) == FIH_POSITIVE_VALUE);
245         FIH_PANIC;
246     }
247 
248     rc = flash_device_base(rsp.br_flash_dev_id, &flash_base);
249     assert(rc == 0);
250 
251 #if MYNEWT_VAL(BOOT_CUSTOM_START)
252     boot_custom_start(flash_base, &rsp);
253 #else
254     hal_bsp_deinit();
255     hal_system_start((void *)(flash_base + rsp.br_image_off +
256                               rsp.br_hdr->ih_hdr_size));
257 #endif
258 
259     return 0;
260 }
261