blob: 7467c9f84463c7ba77e4062c753d88b21849ec39 [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#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
28#include "bootutil/bootutil_log.h"
29
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020030#ifdef __ZEPHYR__
31#include <misc/reboot.h>
32#include <misc/byteorder.h>
33#include <misc/__assert.h>
34#include <flash.h>
35#include <crc16.h>
36#include <serial_adapter/serial_adapter.h>
Carles Cufi0165be82018-03-26 17:43:51 +020037#include <base64.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020038#else
Christopher Collins92ea77f2016-12-12 15:59:26 -080039#include <bsp/bsp.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080040#include <hal/hal_system.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080041#include <os/endian.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080042#include <os/os_cputime.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080043#include <console/console.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020044#include <crc/crc16.h>
45#include <base64/base64.h>
46#endif /* __ZEPHYR__ */
Christopher Collins92ea77f2016-12-12 15:59:26 -080047
48#include <tinycbor/cbor.h>
49#include <tinycbor/cbor_buf_reader.h>
50#include <cborattr/cborattr.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020051
52#include <flash_map/flash_map.h>
53#include <hal/hal_flash.h>
54#include <os/os.h>
55#include <os/os_malloc.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080056
57#include <bootutil/image.h>
58
59#include "boot_serial/boot_serial.h"
60#include "boot_serial_priv.h"
61
62#define BOOT_SERIAL_OUT_MAX 48
63
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020064#ifdef __ZEPHYR__
Carles Cufi0165be82018-03-26 17:43:51 +020065/* base64 lib encodes data to null-terminated string */
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020066#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
67
68#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
69#define CRC_CITT_POLYMINAL 0x1021
70
71#define ntohs(x) sys_be16_to_cpu(x)
72#define htons(x) sys_cpu_to_be16(x)
73
74static char in_buf[CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1];
75static char dec_buf[CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1];
76#endif
77
Christopher Collins92ea77f2016-12-12 15:59:26 -080078static uint32_t curr_off;
79static uint32_t img_size;
80static struct nmgr_hdr *bs_hdr;
81
82static char bs_obuf[BOOT_SERIAL_OUT_MAX];
83
84static int bs_cbor_writer(struct cbor_encoder_writer *, const char *data,
85 int len);
86static void boot_serial_output(void);
87
88static struct cbor_encoder_writer bs_writer = {
89 .write = bs_cbor_writer
90};
91static CborEncoder bs_root;
92static CborEncoder bs_rsp;
93
94int
95bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
96{
97 memcpy(&bs_obuf[cew->bytes_written], data, len);
98 cew->bytes_written += len;
99
100 return 0;
101}
102
103/*
104 * Looks for 'name' from NULL-terminated json data in buf.
105 * Returns pointer to first character of value for that name.
106 * Returns NULL if 'name' is not found.
107 */
108char *
109bs_find_val(char *buf, char *name)
110{
111 char *ptr;
112
113 ptr = strstr(buf, name);
114 if (!ptr) {
115 return NULL;
116 }
117 ptr += strlen(name);
118
119 while (*ptr != '\0') {
120 if (*ptr != ':' && !isspace(*ptr)) {
121 break;
122 }
123 ++ptr;
124 }
125 if (*ptr == '\0') {
126 ptr = NULL;
127 }
128 return ptr;
129}
130
131/*
132 * List images.
133 */
134static void
135bs_list(char *buf, int len)
136{
137 CborEncoder images;
138 CborEncoder image;
139 struct image_header hdr;
140 uint8_t tmpbuf[64];
141 int i, area_id;
142 const struct flash_area *fap;
143
144 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
145 cbor_encode_text_stringz(&bs_rsp, "images");
146 cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
147 for (i = 0; i < 2; i++) {
148 area_id = flash_area_id_from_image_slot(i);
149 if (flash_area_open(area_id, &fap)) {
150 continue;
151 }
152
153 flash_area_read(fap, 0, &hdr, sizeof(hdr));
154
155 if (hdr.ih_magic != IMAGE_MAGIC ||
156 bootutil_img_validate(&hdr, fap, tmpbuf, sizeof(tmpbuf),
157 NULL, 0, NULL)) {
158 flash_area_close(fap);
159 continue;
160 }
161 flash_area_close(fap);
162
163 cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
164 cbor_encode_text_stringz(&image, "slot");
165 cbor_encode_int(&image, i);
166 cbor_encode_text_stringz(&image, "version");
167
168 len = snprintf((char *)tmpbuf, sizeof(tmpbuf),
169 "%u.%u.%u.%u", hdr.ih_ver.iv_major, hdr.ih_ver.iv_minor,
170 hdr.ih_ver.iv_revision, (unsigned int)hdr.ih_ver.iv_build_num);
171 cbor_encode_text_stringz(&image, (char *)tmpbuf);
172 cbor_encoder_close_container(&images, &image);
173 }
174 cbor_encoder_close_container(&bs_rsp, &images);
175 cbor_encoder_close_container(&bs_root, &bs_rsp);
176 boot_serial_output();
177}
178
179/*
180 * Image upload request.
181 */
182static void
183bs_upload(char *buf, int len)
184{
185 CborParser parser;
186 struct cbor_buf_reader reader;
187 struct CborValue value;
188 uint8_t img_data[400];
189 long long unsigned int off = UINT_MAX;
190 size_t img_blen = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300191 uint8_t rem_bytes;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800192 long long unsigned int data_len = UINT_MAX;
193 const struct cbor_attr_t attr[4] = {
194 [0] = {
195 .attribute = "data",
196 .type = CborAttrByteStringType,
197 .addr.bytestring.data = img_data,
198 .addr.bytestring.len = &img_blen,
199 .len = sizeof(img_data)
200 },
201 [1] = {
202 .attribute = "off",
203 .type = CborAttrUnsignedIntegerType,
204 .addr.uinteger = &off,
205 .nodefault = true
206 },
207 [2] = {
208 .attribute = "len",
209 .type = CborAttrUnsignedIntegerType,
210 .addr.uinteger = &data_len,
211 .nodefault = true
212 }
213 };
214 const struct flash_area *fap = NULL;
215 int rc;
216
217 memset(img_data, 0, sizeof(img_data));
218 cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
219 cbor_parser_init(&reader.r, 0, &parser, &value);
220 rc = cbor_read_object(&value, attr);
221 if (rc || off == UINT_MAX) {
222 rc = MGMT_ERR_EINVAL;
223 goto out;
224 }
225
Christopher Collins92ea77f2016-12-12 15:59:26 -0800226 rc = flash_area_open(flash_area_id_from_image_slot(0), &fap);
227 if (rc) {
228 rc = MGMT_ERR_EINVAL;
229 goto out;
230 }
231
232 if (off == 0) {
233 curr_off = 0;
234 if (data_len > fap->fa_size) {
235 rc = MGMT_ERR_EINVAL;
236 goto out;
237 }
238 rc = flash_area_erase(fap, 0, fap->fa_size);
239 if (rc) {
240 rc = MGMT_ERR_EINVAL;
241 goto out;
242 }
243 img_size = data_len;
244 }
245 if (off != curr_off) {
246 rc = 0;
247 goto out;
248 }
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300249 if (curr_off + img_blen < img_size) {
250 rem_bytes = img_blen % flash_area_align(fap);
251 if (rem_bytes) {
252 img_blen -= rem_bytes;
253 }
254 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800255 rc = flash_area_write(fap, curr_off, img_data, img_blen);
256 if (rc) {
257 rc = MGMT_ERR_EINVAL;
258 goto out;
259 }
260 curr_off += img_blen;
261
262out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200263 BOOT_LOG_INF("RX: 0x%x", rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800264 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
265 cbor_encode_text_stringz(&bs_rsp, "rc");
266 cbor_encode_int(&bs_rsp, rc);
267 if (rc == 0) {
268 cbor_encode_text_stringz(&bs_rsp, "off");
269 cbor_encode_uint(&bs_rsp, curr_off);
270 }
271 cbor_encoder_close_container(&bs_root, &bs_rsp);
272
273 boot_serial_output();
274 flash_area_close(fap);
275}
276
277/*
278 * Console echo control. Send empty response, don't do anything.
279 */
280static void
281bs_echo_ctl(char *buf, int len)
282{
283 boot_serial_output();
284}
285
286/*
287 * Reset, and (presumably) boot to newly uploaded image. Flush console
288 * before restarting.
289 */
290static int
291bs_reset(char *buf, int len)
292{
293 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
294 cbor_encode_text_stringz(&bs_rsp, "rc");
295 cbor_encode_int(&bs_rsp, 0);
296 cbor_encoder_close_container(&bs_root, &bs_rsp);
297
298 boot_serial_output();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200299#ifdef __ZEPHYR__
300 k_sleep(250);
301 sys_reboot(SYS_REBOOT_COLD);
302#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800303 os_cputime_delay_usecs(250000);
304 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200305#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800306}
307
308/*
309 * Parse incoming line of input from console.
310 * Expect newtmgr protocol with serial transport.
311 */
312void
313boot_serial_input(char *buf, int len)
314{
315 struct nmgr_hdr *hdr;
316
317 hdr = (struct nmgr_hdr *)buf;
318 if (len < sizeof(*hdr) ||
319 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
320 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
321 return;
322 }
323 bs_hdr = hdr;
324 hdr->nh_group = ntohs(hdr->nh_group);
325
326 buf += sizeof(*hdr);
327 len -= sizeof(*hdr);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800328 bs_writer.bytes_written = 0;
329 cbor_encoder_init(&bs_root, &bs_writer, 0);
330
331 /*
332 * Limited support for commands.
333 */
334 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
335 switch (hdr->nh_id) {
336 case IMGMGR_NMGR_OP_STATE:
337 bs_list(buf, len);
338 break;
339 case IMGMGR_NMGR_OP_UPLOAD:
340 bs_upload(buf, len);
341 break;
342 default:
343 break;
344 }
345 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
346 switch (hdr->nh_id) {
347 case NMGR_ID_CONS_ECHO_CTRL:
348 bs_echo_ctl(buf, len);
349 break;
350 case NMGR_ID_RESET:
351 bs_reset(buf, len);
352 break;
353 default:
354 break;
355 }
356 }
357}
358
359static void
360boot_serial_output(void)
361{
362 char *data;
363 int len;
364 uint16_t crc;
365 uint16_t totlen;
366 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
367 char buf[BOOT_SERIAL_OUT_MAX];
368 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
369
370 data = bs_obuf;
371 len = bs_writer.bytes_written;
372
373 bs_hdr->nh_op++;
374 bs_hdr->nh_flags = NMGR_F_CBOR_RSP_COMPLETE;
375 bs_hdr->nh_len = htons(len);
376 bs_hdr->nh_group = htons(bs_hdr->nh_group);
377
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200378#ifdef __ZEPHYR__
379 crc = crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC,
380 false);
381 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
382#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800383 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
384 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200385#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800386 crc = htons(crc);
387
388 console_write(pkt_start, sizeof(pkt_start));
389
390 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
391 totlen = htons(totlen);
392
393 memcpy(buf, &totlen, sizeof(totlen));
394 totlen = sizeof(totlen);
395 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
396 totlen += sizeof(*bs_hdr);
397 memcpy(&buf[totlen], data, len);
398 totlen += len;
399 memcpy(&buf[totlen], &crc, sizeof(crc));
400 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200401#ifdef __ZEPHYR__
402 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200403 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200404 totlen = enc_len;
405#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800406 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200407#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800408 console_write(encoded_buf, totlen);
409 console_write("\n", 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200410 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800411}
412
413/*
414 * Returns 1 if full packet has been received.
415 */
416static int
417boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
418{
419 int rc;
420 uint16_t crc;
421 uint16_t len;
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200422#ifdef __ZEPHYR__
423 int err;
Carles Cufi0165be82018-03-26 17:43:51 +0200424 err = base64_decode( &out[*out_off], maxout, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200425 if (err) {
426 return -1;
427 }
428#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800429 if (*out_off + base64_decode_len(in) >= maxout) {
430 return -1;
431 }
432 rc = base64_decode(in, &out[*out_off]);
433 if (rc < 0) {
434 return -1;
435 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200436#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800437 *out_off += rc;
438
439 if (*out_off > sizeof(uint16_t)) {
440 len = ntohs(*(uint16_t *)out);
441
442 len = min(len, *out_off - sizeof(uint16_t));
443 out += sizeof(uint16_t);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200444#ifdef __ZEPHYR__
445 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
446#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800447 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200448#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800449 if (crc || len <= sizeof(crc)) {
450 return 0;
451 }
452 *out_off -= sizeof(crc);
453 out[*out_off] = '\0';
454
455 return 1;
456 }
457 return 0;
458}
459
460/*
461 * Task which waits reading console, expecting to get image over
462 * serial port.
463 */
464void
465boot_serial_start(int max_input)
466{
467 int rc;
468 int off;
469 char *buf;
470 char *dec;
471 int dec_off;
472 int full_line;
473
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200474#ifdef __ZEPHYR__
475 rc = boot_console_init();
476 buf = in_buf;
477 dec = dec_buf;
478 assert(max_input <= sizeof(in_buf) && max_input <= sizeof(dec_buf));
479#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800480 rc = console_init(NULL);
481 assert(rc == 0);
482 console_echo(0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800483 buf = os_malloc(max_input);
484 dec = os_malloc(max_input);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200485#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800486 assert(buf && dec);
487
488 off = 0;
489 while (1) {
490 rc = console_read(buf + off, max_input - off, &full_line);
491 if (rc <= 0 && !full_line) {
492 continue;
493 }
494 off += rc;
495 if (!full_line) {
496 continue;
497 }
498 if (buf[0] == SHELL_NLIP_PKT_START1 &&
499 buf[1] == SHELL_NLIP_PKT_START2) {
500 dec_off = 0;
501 rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
502 } else if (buf[0] == SHELL_NLIP_DATA_START1 &&
503 buf[1] == SHELL_NLIP_DATA_START2) {
504 rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
505 }
506 if (rc == 1) {
507 boot_serial_input(&dec[2], dec_off - 2);
508 }
509 off = 0;
510 }
511}