blob: e893617608610c855ae88134124aa0fc2edb6e11 [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;
191 long long unsigned int data_len = UINT_MAX;
192 const struct cbor_attr_t attr[4] = {
193 [0] = {
194 .attribute = "data",
195 .type = CborAttrByteStringType,
196 .addr.bytestring.data = img_data,
197 .addr.bytestring.len = &img_blen,
198 .len = sizeof(img_data)
199 },
200 [1] = {
201 .attribute = "off",
202 .type = CborAttrUnsignedIntegerType,
203 .addr.uinteger = &off,
204 .nodefault = true
205 },
206 [2] = {
207 .attribute = "len",
208 .type = CborAttrUnsignedIntegerType,
209 .addr.uinteger = &data_len,
210 .nodefault = true
211 }
212 };
213 const struct flash_area *fap = NULL;
214 int rc;
215
216 memset(img_data, 0, sizeof(img_data));
217 cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
218 cbor_parser_init(&reader.r, 0, &parser, &value);
219 rc = cbor_read_object(&value, attr);
220 if (rc || off == UINT_MAX) {
221 rc = MGMT_ERR_EINVAL;
222 goto out;
223 }
224
225
226 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 }
249 rc = flash_area_write(fap, curr_off, img_data, img_blen);
250 if (rc) {
251 rc = MGMT_ERR_EINVAL;
252 goto out;
253 }
254 curr_off += img_blen;
255
256out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200257 BOOT_LOG_INF("RX: 0x%x", rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800258 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
259 cbor_encode_text_stringz(&bs_rsp, "rc");
260 cbor_encode_int(&bs_rsp, rc);
261 if (rc == 0) {
262 cbor_encode_text_stringz(&bs_rsp, "off");
263 cbor_encode_uint(&bs_rsp, curr_off);
264 }
265 cbor_encoder_close_container(&bs_root, &bs_rsp);
266
267 boot_serial_output();
268 flash_area_close(fap);
269}
270
271/*
272 * Console echo control. Send empty response, don't do anything.
273 */
274static void
275bs_echo_ctl(char *buf, int len)
276{
277 boot_serial_output();
278}
279
280/*
281 * Reset, and (presumably) boot to newly uploaded image. Flush console
282 * before restarting.
283 */
284static int
285bs_reset(char *buf, int len)
286{
287 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
288 cbor_encode_text_stringz(&bs_rsp, "rc");
289 cbor_encode_int(&bs_rsp, 0);
290 cbor_encoder_close_container(&bs_root, &bs_rsp);
291
292 boot_serial_output();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200293#ifdef __ZEPHYR__
294 k_sleep(250);
295 sys_reboot(SYS_REBOOT_COLD);
296#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800297 os_cputime_delay_usecs(250000);
298 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200299#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800300}
301
302/*
303 * Parse incoming line of input from console.
304 * Expect newtmgr protocol with serial transport.
305 */
306void
307boot_serial_input(char *buf, int len)
308{
309 struct nmgr_hdr *hdr;
310
311 hdr = (struct nmgr_hdr *)buf;
312 if (len < sizeof(*hdr) ||
313 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
314 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
315 return;
316 }
317 bs_hdr = hdr;
318 hdr->nh_group = ntohs(hdr->nh_group);
319
320 buf += sizeof(*hdr);
321 len -= sizeof(*hdr);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800322 bs_writer.bytes_written = 0;
323 cbor_encoder_init(&bs_root, &bs_writer, 0);
324
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200325
Christopher Collins92ea77f2016-12-12 15:59:26 -0800326 /*
327 * Limited support for commands.
328 */
329 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
330 switch (hdr->nh_id) {
331 case IMGMGR_NMGR_OP_STATE:
332 bs_list(buf, len);
333 break;
334 case IMGMGR_NMGR_OP_UPLOAD:
335 bs_upload(buf, len);
336 break;
337 default:
338 break;
339 }
340 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
341 switch (hdr->nh_id) {
342 case NMGR_ID_CONS_ECHO_CTRL:
343 bs_echo_ctl(buf, len);
344 break;
345 case NMGR_ID_RESET:
346 bs_reset(buf, len);
347 break;
348 default:
349 break;
350 }
351 }
352}
353
354static void
355boot_serial_output(void)
356{
357 char *data;
358 int len;
359 uint16_t crc;
360 uint16_t totlen;
361 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
362 char buf[BOOT_SERIAL_OUT_MAX];
363 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
364
365 data = bs_obuf;
366 len = bs_writer.bytes_written;
367
368 bs_hdr->nh_op++;
369 bs_hdr->nh_flags = NMGR_F_CBOR_RSP_COMPLETE;
370 bs_hdr->nh_len = htons(len);
371 bs_hdr->nh_group = htons(bs_hdr->nh_group);
372
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200373#ifdef __ZEPHYR__
374 crc = crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC,
375 false);
376 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
377#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800378 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
379 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200380#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800381 crc = htons(crc);
382
383 console_write(pkt_start, sizeof(pkt_start));
384
385 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
386 totlen = htons(totlen);
387
388 memcpy(buf, &totlen, sizeof(totlen));
389 totlen = sizeof(totlen);
390 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
391 totlen += sizeof(*bs_hdr);
392 memcpy(&buf[totlen], data, len);
393 totlen += len;
394 memcpy(&buf[totlen], &crc, sizeof(crc));
395 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200396#ifdef __ZEPHYR__
397 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200398 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200399 totlen = enc_len;
400#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800401 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200402#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800403 console_write(encoded_buf, totlen);
404 console_write("\n", 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200405 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800406}
407
408/*
409 * Returns 1 if full packet has been received.
410 */
411static int
412boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
413{
414 int rc;
415 uint16_t crc;
416 uint16_t len;
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200417#ifdef __ZEPHYR__
418 int err;
Carles Cufi0165be82018-03-26 17:43:51 +0200419 err = base64_decode( &out[*out_off], maxout, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200420 if (err) {
421 return -1;
422 }
423#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800424 if (*out_off + base64_decode_len(in) >= maxout) {
425 return -1;
426 }
427 rc = base64_decode(in, &out[*out_off]);
428 if (rc < 0) {
429 return -1;
430 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200431#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800432 *out_off += rc;
433
434 if (*out_off > sizeof(uint16_t)) {
435 len = ntohs(*(uint16_t *)out);
436
437 len = min(len, *out_off - sizeof(uint16_t));
438 out += sizeof(uint16_t);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200439#ifdef __ZEPHYR__
440 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
441#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800442 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200443#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800444 if (crc || len <= sizeof(crc)) {
445 return 0;
446 }
447 *out_off -= sizeof(crc);
448 out[*out_off] = '\0';
449
450 return 1;
451 }
452 return 0;
453}
454
455/*
456 * Task which waits reading console, expecting to get image over
457 * serial port.
458 */
459void
460boot_serial_start(int max_input)
461{
462 int rc;
463 int off;
464 char *buf;
465 char *dec;
466 int dec_off;
467 int full_line;
468
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200469#ifdef __ZEPHYR__
470 rc = boot_console_init();
471 buf = in_buf;
472 dec = dec_buf;
473 assert(max_input <= sizeof(in_buf) && max_input <= sizeof(dec_buf));
474#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800475 rc = console_init(NULL);
476 assert(rc == 0);
477 console_echo(0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800478 buf = os_malloc(max_input);
479 dec = os_malloc(max_input);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200480#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800481 assert(buf && dec);
482
483 off = 0;
484 while (1) {
485 rc = console_read(buf + off, max_input - off, &full_line);
486 if (rc <= 0 && !full_line) {
487 continue;
488 }
489 off += rc;
490 if (!full_line) {
491 continue;
492 }
493 if (buf[0] == SHELL_NLIP_PKT_START1 &&
494 buf[1] == SHELL_NLIP_PKT_START2) {
495 dec_off = 0;
496 rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
497 } else if (buf[0] == SHELL_NLIP_DATA_START1 &&
498 buf[1] == SHELL_NLIP_DATA_START2) {
499 rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
500 }
501 if (rc == 1) {
502 boot_serial_input(&dec[2], dec_off - 2);
503 }
504 off = 0;
505 }
506}