blob: 7c1d0d97fb4eadf9adc8222e9c8d2c74065c07bc [file] [log] [blame]
Christopher Collins92ea77f2016-12-12 15:59:26 -08001/*
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#include <assert.h>
20#include <stddef.h>
21#include <inttypes.h>
22#include <ctype.h>
23#include <stdio.h>
24
25#include "sysflash/sysflash.h"
26
Fabio Utzig1a2e41a2017-11-17 12:13:09 -020027#include "bootutil/bootutil_log.h"
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +010028#include "cbor_encode.h"
Fabio Utzig1a2e41a2017-11-17 12:13:09 -020029
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020030#ifdef __ZEPHYR__
Dominik Ermel1eedec32021-12-16 12:55:02 +000031#include <sys/reboot.h>
Andrzej Puzdrowskif1d189c2019-12-12 09:34:11 +010032#include <sys/byteorder.h>
33#include <sys/__assert.h>
Peter Bigot54c1e3f2020-01-25 05:50:12 -060034#include <drivers/flash.h>
Andrzej Puzdrowskif1d189c2019-12-12 09:34:11 +010035#include <sys/crc.h>
36#include <sys/base64.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020037#else
Christopher Collins92ea77f2016-12-12 15:59:26 -080038#include <bsp/bsp.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080039#include <hal/hal_system.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080040#include <os/endian.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080041#include <os/os_cputime.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020042#include <crc/crc16.h>
43#include <base64/base64.h>
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +020044#endif /* __ZEPHYR__ */
45
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020046#include <flash_map_backend/flash_map_backend.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020047#include <hal/hal_flash.h>
48#include <os/os.h>
49#include <os/os_malloc.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080050
51#include <bootutil/image.h>
Andrzej Puzdrowskif48de7a2020-10-19 09:42:02 +020052#include <bootutil/bootutil.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080053
54#include "boot_serial/boot_serial.h"
55#include "boot_serial_priv.h"
56
Dominik Ermel3d4e55d2021-07-09 11:14:10 +000057#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +020058#include "bootutil_priv.h"
59#endif
60
Wouter Cappelle953a7612021-05-03 16:53:05 +020061#ifdef MCUBOOT_ENC_IMAGES
62#include "single_loader.h"
63#endif
64
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +010065#include "serial_recovery_cbor.h"
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +020066#include "bootutil/boot_hooks.h"
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +010067
Carlos Falgueras Garcíaa4b4b0f2021-06-22 10:00:22 +020068BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010069
Marko Kiiskila149b4572018-06-06 14:18:54 +030070#define BOOT_SERIAL_INPUT_MAX 512
Andrzej Puzdrowskic9ac5cc2021-11-19 11:58:05 +010071#define BOOT_SERIAL_OUT_MAX (128 * BOOT_IMAGE_NUMBER)
Christopher Collins92ea77f2016-12-12 15:59:26 -080072
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020073#ifdef __ZEPHYR__
Carles Cufi0165be82018-03-26 17:43:51 +020074/* base64 lib encodes data to null-terminated string */
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020075#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
76
77#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
78#define CRC_CITT_POLYMINAL 0x1021
79
80#define ntohs(x) sys_be16_to_cpu(x)
81#define htons(x) sys_cpu_to_be16(x)
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020082#endif
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010083
Fabio Utzig6f49c272019-08-23 11:42:58 -030084#if (BOOT_IMAGE_NUMBER > 1)
85#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
86#else
87#define IMAGES_ITER(x)
88#endif
89
Marko Kiiskila149b4572018-06-06 14:18:54 +030090static char in_buf[BOOT_SERIAL_INPUT_MAX + 1];
91static char dec_buf[BOOT_SERIAL_INPUT_MAX + 1];
Marko Kiiskila8b1ce3a2018-06-14 13:20:46 -070092const struct boot_uart_funcs *boot_uf;
Christopher Collins92ea77f2016-12-12 15:59:26 -080093static uint32_t curr_off;
94static uint32_t img_size;
95static struct nmgr_hdr *bs_hdr;
96
97static char bs_obuf[BOOT_SERIAL_OUT_MAX];
98
Christopher Collins92ea77f2016-12-12 15:59:26 -080099static void boot_serial_output(void);
100
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100101static cbor_state_backups_t dummy_backups;
102static cbor_state_t cbor_state = {
103 .backups = &dummy_backups
Christopher Collins92ea77f2016-12-12 15:59:26 -0800104};
Christopher Collins92ea77f2016-12-12 15:59:26 -0800105
Dominik Ermel3d51e432021-06-25 17:29:50 +0000106/**
Dominik Ermelbd69c3d2021-07-28 11:27:31 +0000107 * Function that processes MGMT_GROUP_ID_PERUSER mcumgr group and may be
108 * used to process any groups that have not been processed by generic boot
109 * serial implementation.
Dominik Ermel3d51e432021-06-25 17:29:50 +0000110 *
111 * @param[in] hdr -- the decoded header of mcumgr message;
112 * @param[in] buffer -- buffer with first mcumgr message;
113 * @param[in] len -- length of of data in buffer;
114 * @param[out] *cs -- object with encoded response.
115 *
116 * @return 0 on success; non-0 error code otherwise.
117 */
118extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr,
119 const char *buffer,
120 int len, cbor_state_t *cs);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800121
122/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300123 * Convert version into string without use of snprintf().
Christopher Collins92ea77f2016-12-12 15:59:26 -0800124 */
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300125static int
126u32toa(char *tgt, uint32_t val)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800127{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300128 char *dst;
129 uint32_t d = 1;
130 uint32_t dgt;
131 int n = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800132
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300133 dst = tgt;
134 while (val / d >= 10) {
135 d *= 10;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800136 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300137 while (d) {
138 dgt = val / d;
139 val %= d;
140 d /= 10;
141 if (n || dgt > 0 || d == 0) {
142 *dst++ = dgt + '0';
143 ++n;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800144 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800145 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300146 *dst = '\0';
147
148 return dst - tgt;
149}
150
151/*
152 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
153 */
154static void
155bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
156{
157 int off;
158
159 off = u32toa(dst, ver->iv_major);
160 dst[off++] = '.';
161 off += u32toa(dst + off, ver->iv_minor);
162 dst[off++] = '.';
163 off += u32toa(dst + off, ver->iv_revision);
164 dst[off++] = '.';
165 off += u32toa(dst + off, ver->iv_build_num);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800166}
167
168/*
169 * List images.
170 */
171static void
172bs_list(char *buf, int len)
173{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800174 struct image_header hdr;
175 uint8_t tmpbuf[64];
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100176 uint32_t slot, area_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800177 const struct flash_area *fap;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300178 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800179
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100180 map_start_encode(&cbor_state, 1);
181 tstrx_put(&cbor_state, "images");
182 list_start_encode(&cbor_state, 5);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300183 image_index = 0;
184 IMAGES_ITER(image_index) {
185 for (slot = 0; slot < 2; slot++) {
186 area_id = flash_area_id_from_multi_image_slot(image_index, slot);
187 if (flash_area_open(area_id, &fap)) {
188 continue;
189 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800190
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200191 int rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
192 BOOT_HOOK_REGULAR, image_index, slot, &hdr);
193 if (rc == BOOT_HOOK_REGULAR)
194 {
195 flash_area_read(fap, 0, &hdr, sizeof(hdr));
196 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800197
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200198 fih_int fih_rc = FIH_FAILURE;
199
200 if (hdr.ih_magic == IMAGE_MAGIC)
201 {
202 BOOT_HOOK_CALL_FIH(boot_image_check_hook,
203 fih_int_encode(BOOT_HOOK_REGULAR),
204 fih_rc, image_index, slot);
205 if (fih_eq(fih_rc, BOOT_HOOK_REGULAR))
206 {
Wouter Cappelle953a7612021-05-03 16:53:05 +0200207#ifdef MCUBOOT_ENC_IMAGES
208 if (slot == 0 && IS_ENCRYPTED(&hdr)) {
209 /* Clear the encrypted flag we didn't supply a key
210 * This flag could be set if there was a decryption in place
211 * performed before. We will try to validate the image without
212 * decryption by clearing the flag in the heder. If
213 * still encrypted the validation will fail.
214 */
215 hdr.ih_flags &= ~(ENCRYPTIONFLAGS);
216 }
217#endif
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200218 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf),
219 NULL, 0, NULL);
220 }
221 }
222
223 flash_area_close(fap);
224
225 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
Fabio Utzig6f49c272019-08-23 11:42:58 -0300226 continue;
227 }
Fabio Utzig6f49c272019-08-23 11:42:58 -0300228
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100229 map_start_encode(&cbor_state, 20);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300230
231#if (BOOT_IMAGE_NUMBER > 1)
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100232 tstrx_put(&cbor_state, "image");
233 uintx32_put(&cbor_state, image_index);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300234#endif
235
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100236 tstrx_put(&cbor_state, "slot");
237 uintx32_put(&cbor_state, slot);
238 tstrx_put(&cbor_state, "version");
Fabio Utzig6f49c272019-08-23 11:42:58 -0300239
240 bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100241 tstrx_put_term(&cbor_state, (char *)tmpbuf);
242 map_end_encode(&cbor_state, 20);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800243 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800244 }
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100245 list_end_encode(&cbor_state, 5);
246 map_end_encode(&cbor_state, 1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800247 boot_serial_output();
248}
249
250/*
251 * Image upload request.
252 */
253static void
254bs_upload(char *buf, int len)
255{
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100256 const uint8_t *img_data = NULL;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100257 long long int off = UINT64_MAX;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800258 size_t img_blen = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300259 uint8_t rem_bytes;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100260 long long int data_len = UINT64_MAX;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300261 int img_num;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300262 size_t slen;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800263 const struct flash_area *fap = NULL;
264 int rc;
Dominik Ermel3d4e55d2021-07-09 11:14:10 +0000265#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200266 static off_t off_last = -1;
267 struct flash_sector sector;
268#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800269
Fabio Utzig6f49c272019-08-23 11:42:58 -0300270 img_num = 0;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300271
272 /*
273 * Expected data format.
274 * {
Fabio Utzig6f49c272019-08-23 11:42:58 -0300275 * "image":<image number in a multi-image set (OPTIONAL)>
276 * "data":<image data>
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300277 * "len":<image len>
278 * "off":<current offset of image data>
279 * }
280 */
281
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +0200282 struct Upload upload;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100283 uint32_t decoded_len;
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +0200284 bool result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len);
285
286 if (!result || (len != decoded_len)) {
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100287 goto out_invalid_data;
288 }
Dominik Ermel470e2f32020-01-10 13:28:48 +0000289
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100290 for (int i = 0; i < upload._Upload_members_count; i++) {
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +0200291 struct Member_ *member = &upload._Upload_members[i];
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100292 switch(member->_Member_choice) {
293 case _Member_image:
294 img_num = member->_Member_image;
295 break;
296 case _Member_data:
297 img_data = member->_Member_data.value;
298 slen = member->_Member_data.len;
299 img_blen = slen;
300 break;
301 case _Member_len:
302 data_len = member->_Member_len;
303 break;
304 case _Member_off:
305 off = member->_Member_off;
306 break;
307 case _Member_sha:
308 default:
309 /* Nothing to do. */
310 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300311 }
312 }
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100313
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100314 if (off == UINT64_MAX || img_data == NULL) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300315 /*
316 * Offset must be set in every block.
317 */
318 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800319 }
320
Dominik Ermel48decca2021-07-09 10:23:58 +0000321#if !defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
Fabio Utzig6f49c272019-08-23 11:42:58 -0300322 rc = flash_area_open(flash_area_id_from_multi_image_slot(img_num, 0), &fap);
Dominik Ermel48decca2021-07-09 10:23:58 +0000323#else
324 rc = flash_area_open(flash_area_id_from_direct_image(img_num), &fap);
325#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800326 if (rc) {
327 rc = MGMT_ERR_EINVAL;
328 goto out;
329 }
330
331 if (off == 0) {
332 curr_off = 0;
Dominik Ermel260ae092021-04-23 05:38:45 +0000333 if (data_len > flash_area_get_size(fap)) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300334 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800335 }
Wouter Cappellebb7a39d2021-05-03 16:44:44 +0200336#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
337 /* We are using swap state at end of flash area to store validation
338 * result. Make sure the user cannot write it from an image to skip validation.
339 */
340 if (data_len > (flash_area_get_size(fap) - BOOT_MAGIC_SZ)) {
341 goto out_invalid_data;
342 }
343#endif
Dominik Ermel3d4e55d2021-07-09 11:14:10 +0000344#ifndef MCUBOOT_ERASE_PROGRESSIVELY
Dominik Ermel260ae092021-04-23 05:38:45 +0000345 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800346 if (rc) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300347 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800348 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200349#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800350 img_size = data_len;
351 }
352 if (off != curr_off) {
353 rc = 0;
354 goto out;
355 }
Andrzej Puzdrowskif48de7a2020-10-19 09:42:02 +0200356
357 if (curr_off + img_blen > img_size) {
358 rc = MGMT_ERR_EINVAL;
359 goto out;
360 }
361
362 rem_bytes = img_blen % flash_area_align(fap);
363
364 if ((curr_off + img_blen < img_size) && rem_bytes) {
365 img_blen -= rem_bytes;
366 rem_bytes = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300367 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200368
Dominik Ermel3d4e55d2021-07-09 11:14:10 +0000369#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200370 rc = flash_area_sector_from_off(curr_off + img_blen, &sector);
371 if (rc) {
372 BOOT_LOG_ERR("Unable to determine flash sector size");
373 goto out;
374 }
Dominik Ermel260ae092021-04-23 05:38:45 +0000375 if (off_last != flash_sector_get_off(&sector)) {
376 off_last = flash_sector_get_off(&sector);
377 BOOT_LOG_INF("Erasing sector at offset 0x%x", flash_sector_get_off(&sector));
378 rc = flash_area_erase(fap, flash_sector_get_off(&sector),
379 flash_sector_get_size(&sector));
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200380 if (rc) {
381 BOOT_LOG_ERR("Error %d while erasing sector", rc);
382 goto out;
383 }
384 }
385#endif
386
387 BOOT_LOG_INF("Writing at 0x%x until 0x%x", curr_off, curr_off + img_blen);
Andrzej Puzdrowskif48de7a2020-10-19 09:42:02 +0200388 if (rem_bytes) {
389 /* the last chunk of the image might be unaligned */
390 uint8_t wbs_aligned[BOOT_MAX_ALIGN];
391 size_t w_size = img_blen - rem_bytes;
392
393 if (w_size) {
394 rc = flash_area_write(fap, curr_off, img_data, w_size);
395 if (rc) {
396 goto out_invalid_data;
397 }
398 curr_off += w_size;
399 img_blen -= w_size;
400 img_data += w_size;
401 }
402
403 if (img_blen) {
404 memcpy(wbs_aligned, img_data, rem_bytes);
405 memset(wbs_aligned + rem_bytes, flash_area_erased_val(fap),
406 sizeof(wbs_aligned) - rem_bytes);
407 rc = flash_area_write(fap, curr_off, wbs_aligned, flash_area_align(fap));
408 }
409
410 } else {
411 rc = flash_area_write(fap, curr_off, img_data, img_blen);
412 }
413
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300414 if (rc == 0) {
415 curr_off += img_blen;
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200416 if (curr_off == img_size) {
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200417#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200418 /* get the last sector offset */
419 rc = flash_area_sector_from_off(boot_status_off(fap), &sector);
420 if (rc) {
421 BOOT_LOG_ERR("Unable to determine flash sector of"
422 "the image trailer");
423 goto out;
424 }
425 /* Assure that sector for image trailer was erased. */
426 /* Check whether it was erased during previous upload. */
Dominik Ermel260ae092021-04-23 05:38:45 +0000427 if (off_last < flash_sector_get_off(&sector)) {
428 BOOT_LOG_INF("Erasing sector at offset 0x%x",
429 flash_sector_get_off(&sector));
430 rc = flash_area_erase(fap, flash_sector_get_off(&sector),
431 flash_sector_get_size(&sector));
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200432 if (rc) {
433 BOOT_LOG_ERR("Error %d while erasing sector", rc);
434 goto out;
435 }
436 }
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200437#endif
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200438 rc = BOOT_HOOK_CALL(boot_serial_uploaded_hook, 0, img_num, fap,
439 img_size);
440 if (rc) {
441 BOOT_LOG_ERR("Error %d post upload hook", rc);
442 goto out;
443 }
444 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300445 } else {
446 out_invalid_data:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800447 rc = MGMT_ERR_EINVAL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800448 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200449
Christopher Collins92ea77f2016-12-12 15:59:26 -0800450out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200451 BOOT_LOG_INF("RX: 0x%x", rc);
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100452 map_start_encode(&cbor_state, 10);
453 tstrx_put(&cbor_state, "rc");
454 uintx32_put(&cbor_state, rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800455 if (rc == 0) {
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100456 tstrx_put(&cbor_state, "off");
457 uintx32_put(&cbor_state, curr_off);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800458 }
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100459 map_end_encode(&cbor_state, 10);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800460
461 boot_serial_output();
462 flash_area_close(fap);
Wouter Cappelle953a7612021-05-03 16:53:05 +0200463
464#ifdef MCUBOOT_ENC_IMAGES
465 if (curr_off == img_size) {
466 /* Last sector received, now start a decryption on the image if it is encrypted*/
467 rc = boot_handle_enc_fw();
468 }
469#endif //#ifdef MCUBOOT_ENC_IMAGES
Christopher Collins92ea77f2016-12-12 15:59:26 -0800470}
471
472/*
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000473 * Send rc code only.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800474 */
475static void
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000476bs_rc_rsp(int rc_code)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800477{
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100478 map_start_encode(&cbor_state, 10);
479 tstrx_put(&cbor_state, "rc");
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000480 uintx32_put(&cbor_state, rc_code);
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100481 map_end_encode(&cbor_state, 10);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800482 boot_serial_output();
483}
484
485/*
486 * Reset, and (presumably) boot to newly uploaded image. Flush console
487 * before restarting.
488 */
Andrzej Puzdrowski268cdd02018-04-10 12:57:54 +0200489static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800490bs_reset(char *buf, int len)
491{
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000492 bs_rc_rsp(0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800493
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200494#ifdef __ZEPHYR__
Andrzej Puzdrowski0cf0dbd2021-05-14 11:55:57 +0200495#ifdef CONFIG_MULTITHREADING
Carles Cufi7e7b4ad2020-03-30 19:12:02 +0200496 k_sleep(K_MSEC(250));
Andrzej Puzdrowski0cf0dbd2021-05-14 11:55:57 +0200497#else
498 k_busy_wait(250000);
499#endif
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200500 sys_reboot(SYS_REBOOT_COLD);
501#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800502 os_cputime_delay_usecs(250000);
503 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200504#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800505}
506
507/*
508 * Parse incoming line of input from console.
509 * Expect newtmgr protocol with serial transport.
510 */
511void
512boot_serial_input(char *buf, int len)
513{
514 struct nmgr_hdr *hdr;
515
516 hdr = (struct nmgr_hdr *)buf;
517 if (len < sizeof(*hdr) ||
518 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
519 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
520 return;
521 }
522 bs_hdr = hdr;
523 hdr->nh_group = ntohs(hdr->nh_group);
524
525 buf += sizeof(*hdr);
526 len -= sizeof(*hdr);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300527
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100528 cbor_state.payload_mut = (uint8_t *)bs_obuf;
529 cbor_state.payload_end = (const uint8_t *)bs_obuf
530 + sizeof(bs_obuf);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800531
532 /*
533 * Limited support for commands.
534 */
535 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
536 switch (hdr->nh_id) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300537 case IMGMGR_NMGR_ID_STATE:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800538 bs_list(buf, len);
539 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300540 case IMGMGR_NMGR_ID_UPLOAD:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800541 bs_upload(buf, len);
542 break;
543 default:
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000544 bs_rc_rsp(MGMT_ERR_ENOTSUP);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800545 break;
546 }
547 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
548 switch (hdr->nh_id) {
549 case NMGR_ID_CONS_ECHO_CTRL:
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000550 bs_rc_rsp(0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800551 break;
552 case NMGR_ID_RESET:
553 bs_reset(buf, len);
554 break;
555 default:
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000556 bs_rc_rsp(MGMT_ERR_ENOTSUP);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800557 break;
558 }
Dominik Ermelbd69c3d2021-07-28 11:27:31 +0000559 } else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) {
Dominik Ermel3d51e432021-06-25 17:29:50 +0000560 if (bs_peruser_system_specific(hdr, buf, len, &cbor_state) == 0) {
561 boot_serial_output();
562 }
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000563 } else {
564 bs_rc_rsp(MGMT_ERR_ENOTSUP);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800565 }
566}
567
568static void
569boot_serial_output(void)
570{
571 char *data;
572 int len;
573 uint16_t crc;
574 uint16_t totlen;
575 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
576 char buf[BOOT_SERIAL_OUT_MAX];
577 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
578
579 data = bs_obuf;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100580 len = (uint32_t)cbor_state.payload_mut - (uint32_t)bs_obuf;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800581
582 bs_hdr->nh_op++;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300583 bs_hdr->nh_flags = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800584 bs_hdr->nh_len = htons(len);
585 bs_hdr->nh_group = htons(bs_hdr->nh_group);
586
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200587#ifdef __ZEPHYR__
Kumar Gala0813efe2020-05-27 12:25:41 -0500588 crc = crc16((uint8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL,
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300589 CRC16_INITIAL_CRC, false);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200590 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
591#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800592 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
593 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200594#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800595 crc = htons(crc);
596
Marko Kiiskila149b4572018-06-06 14:18:54 +0300597 boot_uf->write(pkt_start, sizeof(pkt_start));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800598
599 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
600 totlen = htons(totlen);
601
602 memcpy(buf, &totlen, sizeof(totlen));
603 totlen = sizeof(totlen);
604 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
605 totlen += sizeof(*bs_hdr);
606 memcpy(&buf[totlen], data, len);
607 totlen += len;
608 memcpy(&buf[totlen], &crc, sizeof(crc));
609 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200610#ifdef __ZEPHYR__
611 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200612 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200613 totlen = enc_len;
614#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800615 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200616#endif
Marko Kiiskila149b4572018-06-06 14:18:54 +0300617 boot_uf->write(encoded_buf, totlen);
618 boot_uf->write("\n\r", 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200619 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800620}
621
622/*
623 * Returns 1 if full packet has been received.
624 */
625static int
626boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
627{
628 int rc;
629 uint16_t crc;
630 uint16_t len;
Marko Kiiskilae5aeee42018-12-21 15:00:16 +0200631
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200632#ifdef __ZEPHYR__
633 int err;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200634 err = base64_decode( &out[*out_off], maxout - *out_off, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200635 if (err) {
636 return -1;
637 }
638#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800639 if (*out_off + base64_decode_len(in) >= maxout) {
640 return -1;
641 }
642 rc = base64_decode(in, &out[*out_off]);
643 if (rc < 0) {
644 return -1;
645 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200646#endif
Fabio Utzig6f49c272019-08-23 11:42:58 -0300647
Christopher Collins92ea77f2016-12-12 15:59:26 -0800648 *out_off += rc;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300649 if (*out_off <= sizeof(uint16_t)) {
650 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800651 }
Fabio Utzig6f49c272019-08-23 11:42:58 -0300652
653 len = ntohs(*(uint16_t *)out);
654 if (len != *out_off - sizeof(uint16_t)) {
655 return 0;
656 }
657
658 if (len > *out_off - sizeof(uint16_t)) {
659 len = *out_off - sizeof(uint16_t);
660 }
661
662 out += sizeof(uint16_t);
663#ifdef __ZEPHYR__
664 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
665#else
666 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
667#endif
668 if (crc || len <= sizeof(crc)) {
669 return 0;
670 }
671 *out_off -= sizeof(crc);
672 out[*out_off] = '\0';
673
674 return 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800675}
676
677/*
678 * Task which waits reading console, expecting to get image over
679 * serial port.
680 */
681void
Marko Kiiskila149b4572018-06-06 14:18:54 +0300682boot_serial_start(const struct boot_uart_funcs *f)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800683{
684 int rc;
685 int off;
David Brown57f0df32020-05-12 08:39:21 -0600686 int dec_off = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800687 int full_line;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300688 int max_input;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800689
Marko Kiiskila149b4572018-06-06 14:18:54 +0300690 boot_uf = f;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300691 max_input = sizeof(in_buf);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800692
693 off = 0;
694 while (1) {
Andrzej Puzdrowskiaea38eb2021-06-11 12:28:59 +0200695 MCUBOOT_CPU_IDLE();
Hein Wessels56d28f02021-11-19 08:42:08 +0100696 MCUBOOT_WATCHDOG_FEED();
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200697 rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800698 if (rc <= 0 && !full_line) {
699 continue;
700 }
701 off += rc;
702 if (!full_line) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300703 if (off == max_input) {
704 /*
705 * Full line, no newline yet. Reset the input buffer.
706 */
707 off = 0;
708 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800709 continue;
710 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200711 if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
712 in_buf[1] == SHELL_NLIP_PKT_START2) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800713 dec_off = 0;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200714 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
715 } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
716 in_buf[1] == SHELL_NLIP_DATA_START2) {
717 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800718 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200719
720 /* serve errors: out of decode memory, or bad encoding */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800721 if (rc == 1) {
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200722 boot_serial_input(&dec_buf[2], dec_off - 2);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800723 }
724 off = 0;
725 }
726}