blob: a387bdcda2726a58108942cd95a907b66f8d29cf [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__
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +020031#include <power/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
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +010061#include "serial_recovery_cbor.h"
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +020062#include "bootutil/boot_hooks.h"
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +010063
Carlos Falgueras Garcíaa4b4b0f2021-06-22 10:00:22 +020064BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010065
Marko Kiiskila149b4572018-06-06 14:18:54 +030066#define BOOT_SERIAL_INPUT_MAX 512
Andrzej Puzdrowskic9ac5cc2021-11-19 11:58:05 +010067#define BOOT_SERIAL_OUT_MAX (128 * BOOT_IMAGE_NUMBER)
Christopher Collins92ea77f2016-12-12 15:59:26 -080068
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020069#ifdef __ZEPHYR__
Carles Cufi0165be82018-03-26 17:43:51 +020070/* base64 lib encodes data to null-terminated string */
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020071#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
72
73#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
74#define CRC_CITT_POLYMINAL 0x1021
75
76#define ntohs(x) sys_be16_to_cpu(x)
77#define htons(x) sys_cpu_to_be16(x)
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020078#endif
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010079
Fabio Utzig6f49c272019-08-23 11:42:58 -030080#if (BOOT_IMAGE_NUMBER > 1)
81#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
82#else
83#define IMAGES_ITER(x)
84#endif
85
Marko Kiiskila149b4572018-06-06 14:18:54 +030086static char in_buf[BOOT_SERIAL_INPUT_MAX + 1];
87static char dec_buf[BOOT_SERIAL_INPUT_MAX + 1];
Marko Kiiskila8b1ce3a2018-06-14 13:20:46 -070088const struct boot_uart_funcs *boot_uf;
Christopher Collins92ea77f2016-12-12 15:59:26 -080089static uint32_t curr_off;
90static uint32_t img_size;
91static struct nmgr_hdr *bs_hdr;
92
93static char bs_obuf[BOOT_SERIAL_OUT_MAX];
94
Christopher Collins92ea77f2016-12-12 15:59:26 -080095static void boot_serial_output(void);
96
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +010097static cbor_state_backups_t dummy_backups;
98static cbor_state_t cbor_state = {
99 .backups = &dummy_backups
Christopher Collins92ea77f2016-12-12 15:59:26 -0800100};
Christopher Collins92ea77f2016-12-12 15:59:26 -0800101
Dominik Ermel3d51e432021-06-25 17:29:50 +0000102/**
Dominik Ermelbd69c3d2021-07-28 11:27:31 +0000103 * Function that processes MGMT_GROUP_ID_PERUSER mcumgr group and may be
104 * used to process any groups that have not been processed by generic boot
105 * serial implementation.
Dominik Ermel3d51e432021-06-25 17:29:50 +0000106 *
107 * @param[in] hdr -- the decoded header of mcumgr message;
108 * @param[in] buffer -- buffer with first mcumgr message;
109 * @param[in] len -- length of of data in buffer;
110 * @param[out] *cs -- object with encoded response.
111 *
112 * @return 0 on success; non-0 error code otherwise.
113 */
114extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr,
115 const char *buffer,
116 int len, cbor_state_t *cs);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800117
118/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300119 * Convert version into string without use of snprintf().
Christopher Collins92ea77f2016-12-12 15:59:26 -0800120 */
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300121static int
122u32toa(char *tgt, uint32_t val)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800123{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300124 char *dst;
125 uint32_t d = 1;
126 uint32_t dgt;
127 int n = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800128
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300129 dst = tgt;
130 while (val / d >= 10) {
131 d *= 10;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800132 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300133 while (d) {
134 dgt = val / d;
135 val %= d;
136 d /= 10;
137 if (n || dgt > 0 || d == 0) {
138 *dst++ = dgt + '0';
139 ++n;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800140 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800141 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300142 *dst = '\0';
143
144 return dst - tgt;
145}
146
147/*
148 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
149 */
150static void
151bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
152{
153 int off;
154
155 off = u32toa(dst, ver->iv_major);
156 dst[off++] = '.';
157 off += u32toa(dst + off, ver->iv_minor);
158 dst[off++] = '.';
159 off += u32toa(dst + off, ver->iv_revision);
160 dst[off++] = '.';
161 off += u32toa(dst + off, ver->iv_build_num);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800162}
163
164/*
165 * List images.
166 */
167static void
168bs_list(char *buf, int len)
169{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800170 struct image_header hdr;
171 uint8_t tmpbuf[64];
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100172 uint32_t slot, area_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800173 const struct flash_area *fap;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300174 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800175
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100176 map_start_encode(&cbor_state, 1);
177 tstrx_put(&cbor_state, "images");
178 list_start_encode(&cbor_state, 5);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300179 image_index = 0;
180 IMAGES_ITER(image_index) {
181 for (slot = 0; slot < 2; slot++) {
182 area_id = flash_area_id_from_multi_image_slot(image_index, slot);
183 if (flash_area_open(area_id, &fap)) {
184 continue;
185 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800186
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200187 int rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
188 BOOT_HOOK_REGULAR, image_index, slot, &hdr);
189 if (rc == BOOT_HOOK_REGULAR)
190 {
191 flash_area_read(fap, 0, &hdr, sizeof(hdr));
192 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800193
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200194 fih_int fih_rc = FIH_FAILURE;
195
196 if (hdr.ih_magic == IMAGE_MAGIC)
197 {
198 BOOT_HOOK_CALL_FIH(boot_image_check_hook,
199 fih_int_encode(BOOT_HOOK_REGULAR),
200 fih_rc, image_index, slot);
201 if (fih_eq(fih_rc, BOOT_HOOK_REGULAR))
202 {
203 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf),
204 NULL, 0, NULL);
205 }
206 }
207
208 flash_area_close(fap);
209
210 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
Fabio Utzig6f49c272019-08-23 11:42:58 -0300211 continue;
212 }
Fabio Utzig6f49c272019-08-23 11:42:58 -0300213
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100214 map_start_encode(&cbor_state, 20);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300215
216#if (BOOT_IMAGE_NUMBER > 1)
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100217 tstrx_put(&cbor_state, "image");
218 uintx32_put(&cbor_state, image_index);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300219#endif
220
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100221 tstrx_put(&cbor_state, "slot");
222 uintx32_put(&cbor_state, slot);
223 tstrx_put(&cbor_state, "version");
Fabio Utzig6f49c272019-08-23 11:42:58 -0300224
225 bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100226 tstrx_put_term(&cbor_state, (char *)tmpbuf);
227 map_end_encode(&cbor_state, 20);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800228 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800229 }
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100230 list_end_encode(&cbor_state, 5);
231 map_end_encode(&cbor_state, 1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800232 boot_serial_output();
233}
234
235/*
236 * Image upload request.
237 */
238static void
239bs_upload(char *buf, int len)
240{
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100241 const uint8_t *img_data = NULL;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100242 long long int off = UINT64_MAX;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800243 size_t img_blen = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300244 uint8_t rem_bytes;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100245 long long int data_len = UINT64_MAX;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300246 int img_num;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300247 size_t slen;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800248 const struct flash_area *fap = NULL;
249 int rc;
Dominik Ermel3d4e55d2021-07-09 11:14:10 +0000250#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200251 static off_t off_last = -1;
252 struct flash_sector sector;
253#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800254
Fabio Utzig6f49c272019-08-23 11:42:58 -0300255 img_num = 0;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300256
257 /*
258 * Expected data format.
259 * {
Fabio Utzig6f49c272019-08-23 11:42:58 -0300260 * "image":<image number in a multi-image set (OPTIONAL)>
261 * "data":<image data>
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300262 * "len":<image len>
263 * "off":<current offset of image data>
264 * }
265 */
266
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +0200267 struct Upload upload;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100268 uint32_t decoded_len;
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +0200269 bool result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len);
270
271 if (!result || (len != decoded_len)) {
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100272 goto out_invalid_data;
273 }
Dominik Ermel470e2f32020-01-10 13:28:48 +0000274
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100275 for (int i = 0; i < upload._Upload_members_count; i++) {
Øyvind Rønningstad212a35b2021-05-07 21:06:48 +0200276 struct Member_ *member = &upload._Upload_members[i];
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100277 switch(member->_Member_choice) {
278 case _Member_image:
279 img_num = member->_Member_image;
280 break;
281 case _Member_data:
282 img_data = member->_Member_data.value;
283 slen = member->_Member_data.len;
284 img_blen = slen;
285 break;
286 case _Member_len:
287 data_len = member->_Member_len;
288 break;
289 case _Member_off:
290 off = member->_Member_off;
291 break;
292 case _Member_sha:
293 default:
294 /* Nothing to do. */
295 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300296 }
297 }
Øyvind Rønningstadf42a8202019-12-13 03:27:54 +0100298
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100299 if (off == UINT64_MAX || img_data == NULL) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300300 /*
301 * Offset must be set in every block.
302 */
303 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800304 }
305
Dominik Ermel48decca2021-07-09 10:23:58 +0000306#if !defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
Fabio Utzig6f49c272019-08-23 11:42:58 -0300307 rc = flash_area_open(flash_area_id_from_multi_image_slot(img_num, 0), &fap);
Dominik Ermel48decca2021-07-09 10:23:58 +0000308#else
309 rc = flash_area_open(flash_area_id_from_direct_image(img_num), &fap);
310#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800311 if (rc) {
312 rc = MGMT_ERR_EINVAL;
313 goto out;
314 }
315
316 if (off == 0) {
317 curr_off = 0;
Dominik Ermel260ae092021-04-23 05:38:45 +0000318 if (data_len > flash_area_get_size(fap)) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300319 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800320 }
Dominik Ermel3d4e55d2021-07-09 11:14:10 +0000321#ifndef MCUBOOT_ERASE_PROGRESSIVELY
Dominik Ermel260ae092021-04-23 05:38:45 +0000322 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800323 if (rc) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300324 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800325 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200326#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800327 img_size = data_len;
328 }
329 if (off != curr_off) {
330 rc = 0;
331 goto out;
332 }
Andrzej Puzdrowskif48de7a2020-10-19 09:42:02 +0200333
334 if (curr_off + img_blen > img_size) {
335 rc = MGMT_ERR_EINVAL;
336 goto out;
337 }
338
339 rem_bytes = img_blen % flash_area_align(fap);
340
341 if ((curr_off + img_blen < img_size) && rem_bytes) {
342 img_blen -= rem_bytes;
343 rem_bytes = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300344 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200345
Dominik Ermel3d4e55d2021-07-09 11:14:10 +0000346#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200347 rc = flash_area_sector_from_off(curr_off + img_blen, &sector);
348 if (rc) {
349 BOOT_LOG_ERR("Unable to determine flash sector size");
350 goto out;
351 }
Dominik Ermel260ae092021-04-23 05:38:45 +0000352 if (off_last != flash_sector_get_off(&sector)) {
353 off_last = flash_sector_get_off(&sector);
354 BOOT_LOG_INF("Erasing sector at offset 0x%x", flash_sector_get_off(&sector));
355 rc = flash_area_erase(fap, flash_sector_get_off(&sector),
356 flash_sector_get_size(&sector));
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200357 if (rc) {
358 BOOT_LOG_ERR("Error %d while erasing sector", rc);
359 goto out;
360 }
361 }
362#endif
363
364 BOOT_LOG_INF("Writing at 0x%x until 0x%x", curr_off, curr_off + img_blen);
Andrzej Puzdrowskif48de7a2020-10-19 09:42:02 +0200365 if (rem_bytes) {
366 /* the last chunk of the image might be unaligned */
367 uint8_t wbs_aligned[BOOT_MAX_ALIGN];
368 size_t w_size = img_blen - rem_bytes;
369
370 if (w_size) {
371 rc = flash_area_write(fap, curr_off, img_data, w_size);
372 if (rc) {
373 goto out_invalid_data;
374 }
375 curr_off += w_size;
376 img_blen -= w_size;
377 img_data += w_size;
378 }
379
380 if (img_blen) {
381 memcpy(wbs_aligned, img_data, rem_bytes);
382 memset(wbs_aligned + rem_bytes, flash_area_erased_val(fap),
383 sizeof(wbs_aligned) - rem_bytes);
384 rc = flash_area_write(fap, curr_off, wbs_aligned, flash_area_align(fap));
385 }
386
387 } else {
388 rc = flash_area_write(fap, curr_off, img_data, img_blen);
389 }
390
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300391 if (rc == 0) {
392 curr_off += img_blen;
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200393 if (curr_off == img_size) {
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200394#ifdef MCUBOOT_ERASE_PROGRESSIVELY
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200395 /* get the last sector offset */
396 rc = flash_area_sector_from_off(boot_status_off(fap), &sector);
397 if (rc) {
398 BOOT_LOG_ERR("Unable to determine flash sector of"
399 "the image trailer");
400 goto out;
401 }
402 /* Assure that sector for image trailer was erased. */
403 /* Check whether it was erased during previous upload. */
Dominik Ermel260ae092021-04-23 05:38:45 +0000404 if (off_last < flash_sector_get_off(&sector)) {
405 BOOT_LOG_INF("Erasing sector at offset 0x%x",
406 flash_sector_get_off(&sector));
407 rc = flash_area_erase(fap, flash_sector_get_off(&sector),
408 flash_sector_get_size(&sector));
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200409 if (rc) {
410 BOOT_LOG_ERR("Error %d while erasing sector", rc);
411 goto out;
412 }
413 }
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200414#endif
Andrzej Puzdrowski4f9c7302021-07-16 17:34:43 +0200415 rc = BOOT_HOOK_CALL(boot_serial_uploaded_hook, 0, img_num, fap,
416 img_size);
417 if (rc) {
418 BOOT_LOG_ERR("Error %d post upload hook", rc);
419 goto out;
420 }
421 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300422 } else {
423 out_invalid_data:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800424 rc = MGMT_ERR_EINVAL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800425 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200426
Christopher Collins92ea77f2016-12-12 15:59:26 -0800427out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200428 BOOT_LOG_INF("RX: 0x%x", rc);
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100429 map_start_encode(&cbor_state, 10);
430 tstrx_put(&cbor_state, "rc");
431 uintx32_put(&cbor_state, rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800432 if (rc == 0) {
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100433 tstrx_put(&cbor_state, "off");
434 uintx32_put(&cbor_state, curr_off);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800435 }
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100436 map_end_encode(&cbor_state, 10);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800437
438 boot_serial_output();
439 flash_area_close(fap);
440}
441
442/*
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000443 * Send rc code only.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800444 */
445static void
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000446bs_rc_rsp(int rc_code)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800447{
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100448 map_start_encode(&cbor_state, 10);
449 tstrx_put(&cbor_state, "rc");
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000450 uintx32_put(&cbor_state, rc_code);
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100451 map_end_encode(&cbor_state, 10);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800452 boot_serial_output();
453}
454
455/*
456 * Reset, and (presumably) boot to newly uploaded image. Flush console
457 * before restarting.
458 */
Andrzej Puzdrowski268cdd02018-04-10 12:57:54 +0200459static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800460bs_reset(char *buf, int len)
461{
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000462 bs_rc_rsp(0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800463
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200464#ifdef __ZEPHYR__
Andrzej Puzdrowski0cf0dbd2021-05-14 11:55:57 +0200465#ifdef CONFIG_MULTITHREADING
Carles Cufi7e7b4ad2020-03-30 19:12:02 +0200466 k_sleep(K_MSEC(250));
Andrzej Puzdrowski0cf0dbd2021-05-14 11:55:57 +0200467#else
468 k_busy_wait(250000);
469#endif
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200470 sys_reboot(SYS_REBOOT_COLD);
471#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800472 os_cputime_delay_usecs(250000);
473 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200474#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800475}
476
477/*
478 * Parse incoming line of input from console.
479 * Expect newtmgr protocol with serial transport.
480 */
481void
482boot_serial_input(char *buf, int len)
483{
484 struct nmgr_hdr *hdr;
485
486 hdr = (struct nmgr_hdr *)buf;
487 if (len < sizeof(*hdr) ||
488 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
489 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
490 return;
491 }
492 bs_hdr = hdr;
493 hdr->nh_group = ntohs(hdr->nh_group);
494
495 buf += sizeof(*hdr);
496 len -= sizeof(*hdr);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300497
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100498 cbor_state.payload_mut = (uint8_t *)bs_obuf;
499 cbor_state.payload_end = (const uint8_t *)bs_obuf
500 + sizeof(bs_obuf);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800501
502 /*
503 * Limited support for commands.
504 */
505 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
506 switch (hdr->nh_id) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300507 case IMGMGR_NMGR_ID_STATE:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800508 bs_list(buf, len);
509 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300510 case IMGMGR_NMGR_ID_UPLOAD:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800511 bs_upload(buf, len);
512 break;
513 default:
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000514 bs_rc_rsp(MGMT_ERR_ENOTSUP);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800515 break;
516 }
517 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
518 switch (hdr->nh_id) {
519 case NMGR_ID_CONS_ECHO_CTRL:
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000520 bs_rc_rsp(0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800521 break;
522 case NMGR_ID_RESET:
523 bs_reset(buf, len);
524 break;
525 default:
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000526 bs_rc_rsp(MGMT_ERR_ENOTSUP);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800527 break;
528 }
Dominik Ermelbd69c3d2021-07-28 11:27:31 +0000529 } else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) {
Dominik Ermel3d51e432021-06-25 17:29:50 +0000530 if (bs_peruser_system_specific(hdr, buf, len, &cbor_state) == 0) {
531 boot_serial_output();
532 }
Dominik Ermelc9dc2242021-07-28 17:08:23 +0000533 } else {
534 bs_rc_rsp(MGMT_ERR_ENOTSUP);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800535 }
536}
537
538static void
539boot_serial_output(void)
540{
541 char *data;
542 int len;
543 uint16_t crc;
544 uint16_t totlen;
545 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
546 char buf[BOOT_SERIAL_OUT_MAX];
547 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
548
549 data = bs_obuf;
Øyvind Rønningstad9f4aefd2021-03-08 21:11:25 +0100550 len = (uint32_t)cbor_state.payload_mut - (uint32_t)bs_obuf;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800551
552 bs_hdr->nh_op++;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300553 bs_hdr->nh_flags = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800554 bs_hdr->nh_len = htons(len);
555 bs_hdr->nh_group = htons(bs_hdr->nh_group);
556
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200557#ifdef __ZEPHYR__
Kumar Gala0813efe2020-05-27 12:25:41 -0500558 crc = crc16((uint8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL,
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300559 CRC16_INITIAL_CRC, false);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200560 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
561#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800562 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
563 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200564#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800565 crc = htons(crc);
566
Marko Kiiskila149b4572018-06-06 14:18:54 +0300567 boot_uf->write(pkt_start, sizeof(pkt_start));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800568
569 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
570 totlen = htons(totlen);
571
572 memcpy(buf, &totlen, sizeof(totlen));
573 totlen = sizeof(totlen);
574 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
575 totlen += sizeof(*bs_hdr);
576 memcpy(&buf[totlen], data, len);
577 totlen += len;
578 memcpy(&buf[totlen], &crc, sizeof(crc));
579 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200580#ifdef __ZEPHYR__
581 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200582 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200583 totlen = enc_len;
584#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800585 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200586#endif
Marko Kiiskila149b4572018-06-06 14:18:54 +0300587 boot_uf->write(encoded_buf, totlen);
588 boot_uf->write("\n\r", 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200589 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800590}
591
592/*
593 * Returns 1 if full packet has been received.
594 */
595static int
596boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
597{
598 int rc;
599 uint16_t crc;
600 uint16_t len;
Marko Kiiskilae5aeee42018-12-21 15:00:16 +0200601
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200602#ifdef __ZEPHYR__
603 int err;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200604 err = base64_decode( &out[*out_off], maxout - *out_off, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200605 if (err) {
606 return -1;
607 }
608#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800609 if (*out_off + base64_decode_len(in) >= maxout) {
610 return -1;
611 }
612 rc = base64_decode(in, &out[*out_off]);
613 if (rc < 0) {
614 return -1;
615 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200616#endif
Fabio Utzig6f49c272019-08-23 11:42:58 -0300617
Christopher Collins92ea77f2016-12-12 15:59:26 -0800618 *out_off += rc;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300619 if (*out_off <= sizeof(uint16_t)) {
620 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800621 }
Fabio Utzig6f49c272019-08-23 11:42:58 -0300622
623 len = ntohs(*(uint16_t *)out);
624 if (len != *out_off - sizeof(uint16_t)) {
625 return 0;
626 }
627
628 if (len > *out_off - sizeof(uint16_t)) {
629 len = *out_off - sizeof(uint16_t);
630 }
631
632 out += sizeof(uint16_t);
633#ifdef __ZEPHYR__
634 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
635#else
636 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
637#endif
638 if (crc || len <= sizeof(crc)) {
639 return 0;
640 }
641 *out_off -= sizeof(crc);
642 out[*out_off] = '\0';
643
644 return 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800645}
646
647/*
648 * Task which waits reading console, expecting to get image over
649 * serial port.
650 */
651void
Marko Kiiskila149b4572018-06-06 14:18:54 +0300652boot_serial_start(const struct boot_uart_funcs *f)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800653{
654 int rc;
655 int off;
David Brown57f0df32020-05-12 08:39:21 -0600656 int dec_off = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800657 int full_line;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300658 int max_input;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800659
Marko Kiiskila149b4572018-06-06 14:18:54 +0300660 boot_uf = f;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300661 max_input = sizeof(in_buf);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800662
663 off = 0;
664 while (1) {
Andrzej Puzdrowskiaea38eb2021-06-11 12:28:59 +0200665 MCUBOOT_CPU_IDLE();
Hein Wessels56d28f02021-11-19 08:42:08 +0100666 MCUBOOT_WATCHDOG_FEED();
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200667 rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800668 if (rc <= 0 && !full_line) {
669 continue;
670 }
671 off += rc;
672 if (!full_line) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300673 if (off == max_input) {
674 /*
675 * Full line, no newline yet. Reset the input buffer.
676 */
677 off = 0;
678 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800679 continue;
680 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200681 if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
682 in_buf[1] == SHELL_NLIP_PKT_START2) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800683 dec_off = 0;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200684 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
685 } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
686 in_buf[1] == SHELL_NLIP_DATA_START2) {
687 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800688 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200689
690 /* serve errors: out of decode memory, or bad encoding */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800691 if (rc == 1) {
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200692 boot_serial_input(&dec_buf[2], dec_off - 2);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800693 }
694 off = 0;
695 }
696}