From 0a14341cf8f60e6a9ba2edb0802507cbb073e806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:52 +0200 Subject: tools: kwboot: Initialize rfds to zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly zero out the rfds fd_set with FD_ZERO() before using it. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 7e1be296230..695d433b96e 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1151,6 +1151,7 @@ kwboot_terminal(int tty) fd_set rfds; int nfds = 0; + FD_ZERO(&rfds); FD_SET(tty, &rfds); nfds = nfds < tty ? tty : nfds; -- cgit v1.2.3 From 2ecca3d0d76023f219ac4350b0112cd19fbdda2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:53 +0200 Subject: tools: kwboot: Fix initialization of tty device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly disable 2 stop bits by clearing CSTOPB flag, disable modem control flow by clearing CRTSCTS flag and do not send hangup after closing device by clearing HUPCL flag. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 695d433b96e..c55b41025b0 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -657,6 +657,7 @@ kwboot_open_tty(const char *path, int baudrate) cfmakeraw(&tio); tio.c_cflag |= CREAD | CLOCAL; + tio.c_cflag &= ~(CSTOPB | HUPCL | CRTSCTS); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; -- cgit v1.2.3 From 5923ef686a61c7ac15ed990487e4a4fd312ddeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:54 +0200 Subject: tools: kwboot: Reserve enough space for patching kwbimage in memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPI image header and data parts do not have to be aligned to 128 byte xmodem block size. So reserve additional memory for aligning header part and additional memory for aligning data part. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index c55b41025b0..4e29317f107 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1672,8 +1672,10 @@ main(int argc, char **argv) else /* ensure we have enough space for baudrate change code */ after_img_rsv += KWBOOT_BAUDRATE_BIN_HEADER_SZ + + KWBOOT_XM_BLKSZ + sizeof(kwboot_pre_baud_code) + - sizeof(kwboot_baud_code); + sizeof(kwboot_baud_code) + + KWBOOT_XM_BLKSZ; if (imgpath) { img = kwboot_read_image(imgpath, &size, after_img_rsv); -- cgit v1.2.3 From ad9a3ac5005e7b70a50b621a5340cead6fcc673f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:55 +0200 Subject: tools: kwboot: Validate 4-byte image data checksum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Data part of the image contains 4-byte checksum. Validate it when processing the image. Signed-off-by: Pali Rohár [ refactored ] Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 4e29317f107..bc443015351 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1251,6 +1251,37 @@ kwboot_hdr_csum8(const void *hdr) return csum; } +static uint32_t * +kwboot_img_csum32_ptr(void *img) +{ + struct main_hdr_v1 *hdr = img; + uint32_t datasz; + + datasz = le32_to_cpu(hdr->blocksize) - sizeof(uint32_t); + + return img + le32_to_cpu(hdr->srcaddr) + datasz; +} + +static uint32_t +kwboot_img_csum32(const void *img) +{ + const struct main_hdr_v1 *hdr = img; + uint32_t datasz, csum = 0; + const uint32_t *data; + + datasz = le32_to_cpu(hdr->blocksize) - sizeof(csum); + if (datasz % sizeof(uint32_t)) + return 0; + + data = img + le32_to_cpu(hdr->srcaddr); + while (datasz > 0) { + csum += le32_to_cpu(*data++); + datasz -= 4; + } + + return cpu_to_le32(csum); +} + static int kwboot_img_is_secure(void *img) { @@ -1462,6 +1493,9 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) *size < le32_to_cpu(hdr->srcaddr) + le32_to_cpu(hdr->blocksize)) goto err; + if (kwboot_img_csum32(img) != *kwboot_img_csum32_ptr(img)) + goto err; + is_secure = kwboot_img_is_secure(img); if (hdr->blockid != IBR_HDR_UART_ID) { -- cgit v1.2.3 From 063cb352814b5363aebb4c733a41b951787b1f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:56 +0200 Subject: tools: kwboot: Inject baudrate change back code after data part MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some vendor U-Boot kwbimage binaries (e.g. those for A375) have load address set to zero. Therefore it is not possible to inject code which changes baudrate back to 115200 Bd before the data part. So instead inject it after the data part and change kwbimage execution address to that offset. Also store original execution address into baudrate change code, so after it changes baudrate back to 115200 Bd, it can jump to orignal address. Signed-off-by: Pali Rohár [ refactored ] Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 72 +++++++++++++++++++++++++--------------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index bc443015351..bf26a667b73 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1295,34 +1295,22 @@ kwboot_img_is_secure(void *img) } static void * -kwboot_img_grow_data_left(void *img, size_t *size, size_t grow) +kwboot_img_grow_data_right(void *img, size_t *size, size_t grow) { - uint32_t hdrsz, datasz, srcaddr; struct main_hdr_v1 *hdr = img; - uint8_t *data; - - srcaddr = le32_to_cpu(hdr->srcaddr); - - hdrsz = kwbheader_size(hdr); - data = (uint8_t *)img + srcaddr; - datasz = *size - srcaddr; - - /* only move data if there is not enough space */ - if (hdrsz + grow > srcaddr) { - size_t need = hdrsz + grow - srcaddr; - - /* move data by enough bytes */ - memmove(data + need, data, datasz); - *size += need; - srcaddr += need; - } + void *result; - srcaddr -= grow; - hdr->srcaddr = cpu_to_le32(srcaddr); - hdr->destaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) - grow); + /* + * 32-bit checksum comes after end of image code, so we will be putting + * new code there. So we get this pointer and then increase data size + * (since increasing data size changes kwboot_img_csum32_ptr() return + * value). + */ + result = kwboot_img_csum32_ptr(img); hdr->blocksize = cpu_to_le32(le32_to_cpu(hdr->blocksize) + grow); + *size += grow; - return (uint8_t *)img + srcaddr; + return result; } static void @@ -1400,14 +1388,20 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) } static void -_copy_baudrate_change_code(struct main_hdr_v1 *hdr, void *dst, int pre, - int old_baud, int new_baud) +_inject_baudrate_change_code(void *img, size_t *size, int pre, + int old_baud, int new_baud) { - size_t codesz = sizeof(kwboot_baud_code); - uint8_t *code = dst; + uint32_t codesz = sizeof(kwboot_baud_code); + struct main_hdr_v1 *hdr = img; + uint8_t *code; if (pre) { - size_t presz = sizeof(kwboot_pre_baud_code); + uint32_t presz = sizeof(kwboot_pre_baud_code); + uint32_t orig_datasz; + + orig_datasz = le32_to_cpu(hdr->blocksize) - sizeof(uint32_t); + + code = kwboot_img_grow_data_right(img, size, presz + codesz); /* * We need to prepend code that loads lr register with original @@ -1421,9 +1415,12 @@ _copy_baudrate_change_code(struct main_hdr_v1 *hdr, void *dst, int pre, memcpy(code, kwboot_pre_baud_code, presz); *(uint32_t *)code = hdr->execaddr; - hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) + 4); + hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) + + orig_datasz + 4); code += presz; + } else { + code = kwboot_add_bin_ohdr_v1(img, size, codesz); } memcpy(code, kwboot_baud_code, codesz - 8); @@ -1516,9 +1513,6 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) } if (baudrate) { - uint32_t codesz = sizeof(kwboot_baud_code); - void *code; - if (image_ver == 0) { fprintf(stderr, "Cannot inject code for changing baudrate into v0 image header\n"); @@ -1539,20 +1533,16 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) */ kwboot_printv("Injecting binary header code for changing baudrate to %d Bd\n", baudrate); - - code = kwboot_add_bin_ohdr_v1(img, size, codesz); - _copy_baudrate_change_code(hdr, code, 0, 115200, baudrate); + _inject_baudrate_change_code(img, size, 0, 115200, baudrate); /* * Now inject code that changes the baudrate back to 115200 Bd. - * This code is prepended to the data part of the image, so it - * is executed before U-Boot proper. + * This code is appended after the data part of the image, and + * execaddr is changed so that it is executed before U-Boot + * proper. */ kwboot_printv("Injecting code for changing baudrate back\n"); - - codesz += sizeof(kwboot_pre_baud_code); - code = kwboot_img_grow_data_left(img, size, codesz); - _copy_baudrate_change_code(hdr, code, 1, baudrate, 115200); + _inject_baudrate_change_code(img, size, 1, baudrate, 115200); /* recompute header size */ hdrsz = kwbheader_size(hdr); -- cgit v1.2.3 From 82c5a0ac713500f4da9d8562cd4764c733b65e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:57 +0200 Subject: tools: kwboot: Recalculate 4-byte data checksum after injecting baudrate code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If data part of image is modified, update 4-byte data checksum. It looks like A385 BootROM does not verify this checksum for image loaded via UART, but we do not know if other BootROMs are also ignoring it. It is always better to provide correct checksum. Signed-off-by: Pali Rohár [ refactored ] Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index bf26a667b73..1131c2eb1c4 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1544,6 +1544,9 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) kwboot_printv("Injecting code for changing baudrate back\n"); _inject_baudrate_change_code(img, size, 1, baudrate, 115200); + /* Update the 32-bit data checksum */ + *kwboot_img_csum32_ptr(img) = kwboot_img_csum32(img); + /* recompute header size */ hdrsz = kwbheader_size(hdr); } -- cgit v1.2.3 From 4bebab69a9483fd6ae85b06a088790a6c77f90ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:58 +0200 Subject: tools: kwboot: Correctly set configuration of UART for BootROM messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For kwbimage v1, tell BootROM to send BootROM messages to UART port number 0 (used also for UART booting) with default baudrate (which should be 115200) and do not touch UART MPP configuration. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 1131c2eb1c4..62288382289 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1507,6 +1507,17 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) } if (!is_secure) { + if (image_ver == 1) { + /* + * Tell BootROM to send BootROM messages to UART port + * number 0 (used also for UART booting) with default + * baudrate (which should be 115200) and do not touch + * UART MPP configuration. + */ + hdr->options &= ~0x1F; + hdr->options |= MAIN_HDR_V1_OPT_BAUD_DEFAULT; + hdr->options |= 0 << 3; + } if (image_ver == 0) ((struct main_hdr_v0 *)img)->nandeccmode = IBR_HDR_ECC_DISABLED; hdr->nandpagesize = 0; -- cgit v1.2.3 From 8e2e7ca1fe3a822aec31b4672b4615c07afa89c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:12:59 +0200 Subject: tools: kwboot: Show verbose message when waiting for baudrate change magic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is hard to debug why kwboot is failing when the last message is 'Finishing transfer' and no additional output. So show verbose message when kwboot finished transfer and is waiting for baudrate change magic sequence. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 62288382289..7fd28aa7547 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1065,7 +1065,7 @@ kwboot_xmodem(int tty, const void *_img, size_t size, int baudrate) if (baudrate) { char buf[sizeof(kwb_baud_magic)]; - /* Wait 1s for baudrate change magic */ + kwboot_printv("Waiting 1s for baudrate change magic\n"); rc = kwboot_tty_recv(tty, buf, sizeof(buf), 1000); if (rc) return rc; -- cgit v1.2.3 From ed792c2938331a68f4b271a6d4d0250057449608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:13:00 +0200 Subject: tools: kwboot: Simplify code for aligning image header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expression (hdrsz % KWBOOT_XM_BLKSZ) is non-zero therefore expression (KWBOOT_XM_BLKSZ - hdrsz % KWBOOT_XM_BLKSZ) is always less than value KWBOOT_XM_BLKSZ. So there is no need to add another modulo. Also rename variable `offset` to `grow` which better describes what is stored in this variable. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 7fd28aa7547..adec4ec97da 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1563,8 +1563,7 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) } if (hdrsz % KWBOOT_XM_BLKSZ) { - size_t offset = (KWBOOT_XM_BLKSZ - hdrsz % KWBOOT_XM_BLKSZ) % - KWBOOT_XM_BLKSZ; + size_t grow = KWBOOT_XM_BLKSZ - hdrsz % KWBOOT_XM_BLKSZ; if (is_secure) { fprintf(stderr, "Cannot align image with secure header\n"); @@ -1572,7 +1571,7 @@ kwboot_img_patch(void *img, size_t *size, int baudrate) } kwboot_printv("Aligning image header to Xmodem block size\n"); - kwboot_img_grow_hdr(img, size, offset); + kwboot_img_grow_hdr(img, size, grow); } hdr->checksum = kwboot_hdr_csum8(hdr) - csum; -- cgit v1.2.3 From e511cc3b1ad8ced8e18464edf22f5b8a83ec1cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:13:01 +0200 Subject: tools: kwboot: Do not modify kwbimage header before increasing its size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures that kwboot_img_grow_hdr() function still sees valid kwbimage header. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index adec4ec97da..bb7555369cc 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1352,17 +1352,18 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) uint32_t num_args; uint32_t offset; uint32_t ohdrsz; + uint8_t *prev_ext; if (hdr->ext & 0x1) { for_each_opt_hdr_v1 (ohdr, img) if (opt_hdr_v1_next(ohdr) == NULL) break; - *opt_hdr_v1_ext(ohdr) |= 1; - ohdr = opt_hdr_v1_next(ohdr); + prev_ext = opt_hdr_v1_ext(ohdr); + ohdr = _opt_hdr_v1_next(ohdr); } else { - hdr->ext |= 1; ohdr = (void *)(hdr + 1); + prev_ext = &hdr->ext; } /* @@ -1377,6 +1378,8 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4; kwboot_img_grow_hdr(hdr, size, ohdrsz); + *prev_ext |= 1; + ohdr->headertype = OPT_HDR_V1_BINARY_TYPE; ohdr->headersz_msb = ohdrsz >> 16; ohdr->headersz_lsb = cpu_to_le16(ohdrsz & 0xffff); -- cgit v1.2.3 From d656f5a0ee224f29253573a6641ccb8fc1a3afad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:13:02 +0200 Subject: tools: kwboot: Calculate real used space in kwbimage header when calling kwboot_img_grow_hdr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Size of the header stored in kwbimage may be larger than real used size in the kwbimage header. If there is unused space in kwbimage header then use it for growing it. So update code to calculate used space of kwbimage header. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index bb7555369cc..5d7cb7a774f 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1318,11 +1318,20 @@ kwboot_img_grow_hdr(void *img, size_t *size, size_t grow) { uint32_t hdrsz, datasz, srcaddr; struct main_hdr_v1 *hdr = img; + struct opt_hdr_v1 *ohdr; uint8_t *data; srcaddr = le32_to_cpu(hdr->srcaddr); - hdrsz = kwbheader_size(img); + /* calculate real used space in kwbimage header */ + if (kwbimage_version(img) == 0) { + hdrsz = kwbheader_size(img); + } else { + hdrsz = sizeof(*hdr); + for_each_opt_hdr_v1 (ohdr, hdr) + hdrsz += opt_hdr_v1_size(ohdr); + } + data = (uint8_t *)img + srcaddr; datasz = *size - srcaddr; @@ -1339,8 +1348,10 @@ kwboot_img_grow_hdr(void *img, size_t *size, size_t grow) if (kwbimage_version(img) == 1) { hdrsz += grow; - hdr->headersz_msb = hdrsz >> 16; - hdr->headersz_lsb = cpu_to_le16(hdrsz & 0xffff); + if (hdrsz > kwbheader_size(img)) { + hdr->headersz_msb = hdrsz >> 16; + hdr->headersz_lsb = cpu_to_le16(hdrsz & 0xffff); + } } } -- cgit v1.2.3 From d14a342073ca7ed108ca1c2477e102da431a527c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:13:03 +0200 Subject: tools: kwboot: Change retry loop from decreasing to increasing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch does not change behavior of the code, just allows to implement new changes more easily. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 5d7cb7a774f..16c5a848256 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -925,7 +925,7 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block, int allow_non_xm, *done_print = 0; - retries = 16; + retries = 0; do { rc = kwboot_tty_send(fd, block, sizeof(*block)); if (rc) @@ -944,7 +944,7 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block, int allow_non_xm, if (!allow_non_xm && c != ACK) kwboot_progress(-1, '+'); - } while (c == NAK && retries-- > 0); + } while (c == NAK && retries++ < 16); if (non_xm_print) kwboot_printv("\n"); @@ -973,7 +973,7 @@ kwboot_xm_finish(int fd) kwboot_printv("Finishing transfer\n"); - retries = 16; + retries = 0; do { rc = kwboot_tty_send_char(fd, EOT); if (rc) @@ -982,7 +982,7 @@ kwboot_xm_finish(int fd) rc = kwboot_xm_recv_reply(fd, &c, 0, NULL, 0, NULL); if (rc) return rc; - } while (c == NAK && retries-- > 0); + } while (c == NAK && retries++ < 16); return _xm_reply_to_error(c); } -- cgit v1.2.3 From a6fcac274a99c9675f4b6841321e085c79326429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 25 Oct 2021 15:13:04 +0200 Subject: tools: kwboot: Resend first 3 xmodem retry packets immediately MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when kwboot receive some garbage reply which does not understand, it waits 1s before it tries to resend packet again. The most common error on UART is that receiver sees some bit flipped which results in invalid reply. This behavior slows down xmodem transfer over UART as basically on every error kwboot is waiting one second. To fix this, try to resend xmodem packet for first 3 attempts immediately without any delay. If broken reply is received also after the 3 attempts, continue retrying with 1s delay like it was before. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 16c5a848256..bb7cae9f054 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -851,7 +851,8 @@ kwboot_baud_magic_handle(int fd, char c, int baudrate) } static int -kwboot_xm_recv_reply(int fd, char *c, int allow_non_xm, int *non_xm_print, +kwboot_xm_recv_reply(int fd, char *c, int nak_on_non_xm, + int allow_non_xm, int *non_xm_print, int baudrate, int *baud_changed) { int timeout = allow_non_xm ? KWBOOT_HDR_RSP_TIMEO : blk_rsp_timeo; @@ -904,6 +905,10 @@ kwboot_xm_recv_reply(int fd, char *c, int allow_non_xm, int *non_xm_print, *non_xm_print = 1; } } else { + if (nak_on_non_xm) { + *c = NAK; + break; + } timeout = recv_until - _now(); if (timeout < 0) { errno = ETIMEDOUT; @@ -937,7 +942,8 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block, int allow_non_xm, *done_print = 1; } - rc = kwboot_xm_recv_reply(fd, &c, allow_non_xm, &non_xm_print, + rc = kwboot_xm_recv_reply(fd, &c, retries < 3, + allow_non_xm, &non_xm_print, baudrate, &baud_changed); if (rc) goto can; @@ -979,7 +985,8 @@ kwboot_xm_finish(int fd) if (rc) return rc; - rc = kwboot_xm_recv_reply(fd, &c, 0, NULL, 0, NULL); + rc = kwboot_xm_recv_reply(fd, &c, retries < 3, + 0, NULL, 0, NULL); if (rc) return rc; } while (c == NAK && retries++ < 16); -- cgit v1.2.3 From 455c0d22fb084550ecc6aaf810a9c7b684b2dee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 Oct 2021 20:56:58 +0200 Subject: tools: kwboot: Fix sending retry of last header packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the trasfer of last header packet, it is possible that baudrate change pattern is received, and also that NAK byte is received so that the packet should be sent again. Thus we should not clear the baudrate change state when sending retry of that packet. Move code for initializing state variables from kwboot_xm_recv_reply() to kwboot_xm_sendblock(). Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index bb7cae9f054..b2c48812c38 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -859,11 +859,6 @@ kwboot_xm_recv_reply(int fd, char *c, int nak_on_non_xm, uint64_t recv_until = _now() + timeout; int rc; - if (non_xm_print) - *non_xm_print = 0; - if (baud_changed) - *baud_changed = 0; - while (1) { rc = kwboot_tty_recv(fd, c, 1, timeout); if (rc) { @@ -929,6 +924,8 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block, int allow_non_xm, char c; *done_print = 0; + non_xm_print = 0; + baud_changed = 0; retries = 0; do { -- cgit v1.2.3 From cab817d260341244f011f7a0c490df51b33c05aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 Oct 2021 20:56:59 +0200 Subject: tools: kwboot: Do not call tcdrain() after each sent packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kwboot puts each xmodem packet to kernel queue, then waits until all bytes of that packet are transmitted over UART and then waits for xmodem reply until it is received into kernel queue. If some reply is received during the time we are waiting until all bytes are transmitted, then kernel puts them into the queue and returns it to kwboot in next read() call. So there is no need to wait (with tcdrain() function) until all bytes from xmodem packet are transmitted over UART, since any reply received either during that time or after is returned to kwboot with the next read(). Therefore do not call tcdrain() after each xmodem packet sent. Instead directly wait for any reply after putting xmodem packet into write kernel queue. This change could speed up xmodem transfer in case tcdrain() function waits for a longer time. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index b2c48812c38..a6bfd3d4ce0 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -404,7 +404,7 @@ out: } static int -kwboot_tty_send(int fd, const void *buf, size_t len) +kwboot_tty_send(int fd, const void *buf, size_t len, int nodrain) { if (!buf) return 0; @@ -412,13 +412,16 @@ kwboot_tty_send(int fd, const void *buf, size_t len) if (kwboot_write(fd, buf, len) < 0) return -1; + if (nodrain) + return 0; + return tcdrain(fd); } static int kwboot_tty_send_char(int fd, unsigned char c) { - return kwboot_tty_send(fd, &c, 1); + return kwboot_tty_send(fd, &c, 1, 0); } static speed_t @@ -705,7 +708,7 @@ kwboot_bootmsg(int tty, void *msg) break; for (count = 0; count < 128; count++) { - rc = kwboot_tty_send(tty, msg, 8); + rc = kwboot_tty_send(tty, msg, 8, 0); if (rc) { usleep(msg_req_delay * 1000); continue; @@ -737,7 +740,7 @@ kwboot_debugmsg(int tty, void *msg) if (rc) break; - rc = kwboot_tty_send(tty, msg, 8); + rc = kwboot_tty_send(tty, msg, 8, 0); if (rc) { usleep(msg_req_delay * 1000); continue; @@ -929,7 +932,7 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block, int allow_non_xm, retries = 0; do { - rc = kwboot_tty_send(fd, block, sizeof(*block)); + rc = kwboot_tty_send(fd, block, sizeof(*block), 1); if (rc) return rc; -- cgit v1.2.3 From 56452295c315397255d05e91940976f68c247d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 Oct 2021 20:57:00 +0200 Subject: tools: kwboot: Increase delay after changing baudrate in ARM code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase loop cycles from 600000 to 2998272, which should increase delay from 1ms to about 5ms on 1200 MHz CPU. The Number 2998272 was chosen as the nearest value around 3000000 which can be encoded into one ARM mov instruction. It avoids usage of movt instruction which is not supported by ARMv5te cores. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index a6bfd3d4ce0..84294cadfe1 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -119,7 +119,7 @@ static unsigned char kwboot_baud_code[] = { /* ; writel(UART_BASE + DLL, new_dll); */ /* ; writel(UART_BASE + DLH, new_dlh); */ /* ; writel(UART_BASE + LCR, lcr & ~DLAB); */ - /* ; msleep(1); */ + /* ; msleep(5); */ /* ; return 0; */ /* ; } */ @@ -130,7 +130,7 @@ static unsigned char kwboot_baud_code[] = { 0x01, 0x00, 0x4d, 0xe3, /* movt r0, #0xd001 */ /* ; r2 = address of preamble string */ - 0xd0, 0x20, 0x8f, 0xe2, /* adr r2, preamble */ + 0xcc, 0x20, 0x8f, 0xe2, /* adr r2, preamble */ /* ; Send preamble string over UART */ /* .Lloop_preamble: */ @@ -177,15 +177,15 @@ static unsigned char kwboot_baud_code[] = { /* ; Read old baudrate value */ /* ; r2 = old_baudrate */ - 0x8c, 0x20, 0x9f, 0xe5, /* ldr r2, old_baudrate */ + 0x88, 0x20, 0x9f, 0xe5, /* ldr r2, old_baudrate */ /* ; Calculate base clock */ /* ; r1 = r2 * r1 */ 0x92, 0x01, 0x01, 0xe0, /* mul r1, r2, r1 */ /* ; Read new baudrate value */ - /* ; r2 = baudrate */ - 0x88, 0x20, 0x9f, 0xe5, /* ldr r2, baudrate */ + /* ; r2 = new_baudrate */ + 0x84, 0x20, 0x9f, 0xe5, /* ldr r2, new_baudrate */ /* ; Calculate new Divisor Latch */ /* ; r1 = DIV_ROUND(r1, r2) = */ @@ -225,10 +225,10 @@ static unsigned char kwboot_baud_code[] = { 0x80, 0x10, 0xc1, 0xe3, /* bic r1, r1, #0x80 */ 0x0c, 0x10, 0x80, 0xe5, /* str r1, [r0, #0x0c] */ - /* ; Sleep 1ms ~~ 600000 cycles at 1200 MHz */ - /* ; r1 = 600000 */ - 0x9f, 0x1d, 0xa0, 0xe3, /* mov r1, #0x27c0 */ - 0x09, 0x10, 0x40, 0xe3, /* movt r1, #0x0009 */ + /* ; Loop 0x2dc000 (2998272) cycles */ + /* ; which is about 5ms on 1200 MHz CPU */ + /* ; r1 = 0x2dc000 */ + 0xb7, 0x19, 0xa0, 0xe3, /* mov r1, #0x2dc000 */ /* .Lloop_sleep: */ 0x01, 0x10, 0x41, 0xe2, /* sub r1, r1, #1 */ 0x00, 0x00, 0x51, 0xe3, /* cmp r1, #0 */ -- cgit v1.2.3 From 558176dcb14d589b5854bea0988301e27b60091d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 Oct 2021 20:57:01 +0200 Subject: tools: kwboot: Replace ARM mov + movt instruction pair by mov + orr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older Armada SoCs have custom ARMv5te compatible core which does not support movt instruction. So replace mov + movt instruction pair used for immediate move construction by mov + orr instructions which are supported also by ARMv5te. After this change kwboot ARM code should be compatible with any 32-bit ARM core compatible by ARMv2 or new. At least GNU AS does not throw any error or warning. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 84294cadfe1..62c218ef646 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -126,8 +126,8 @@ static unsigned char kwboot_baud_code[] = { 0xfe, 0x5f, 0x2d, 0xe9, /* push { r1 - r12, lr } */ /* ; r0 = UART_BASE */ - 0x02, 0x0a, 0xa0, 0xe3, /* mov r0, #0x2000 */ - 0x01, 0x00, 0x4d, 0xe3, /* movt r0, #0xd001 */ + 0x0d, 0x02, 0xa0, 0xe3, /* mov r0, #0xd0000000 */ + 0x12, 0x0a, 0x80, 0xe3, /* orr r0, r0, #0x12000 */ /* ; r2 = address of preamble string */ 0xcc, 0x20, 0x8f, 0xe2, /* adr r2, preamble */ -- cgit v1.2.3 From 8dbe027fc7d371d17a17a8bb5af8e99b5f20802b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 Oct 2021 20:57:02 +0200 Subject: tools: kwboot: Do not use stack when setting baudrate back to default value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ARM code we inject into the image to change baudrate back to the default value of 115200 Baud, which is run after successful UART transfer of the whole image, cannot use stack as at this stage stack pointer is not initialized yet. Stack can only be used when BootROM is executing binary header, to preserve state of registers, since BootROM expects that. Change the ARM baudrate code to not use stack at all and put binary header specific pre + post code (which stores and restores registers) into separate arrays. The baudrate change code now jumps at it's end and expects that there is either code which returns to the BootROM or jumps to the original exec address. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 112 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 47 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 62c218ef646..359b43c0d8b 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -78,14 +78,7 @@ struct kwboot_block { #define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */ #define KWBOOT_HDR_RSP_TIMEO 10000 /* ms */ -/* ARM code making baudrate changing function return to original exec address */ -static unsigned char kwboot_pre_baud_code[] = { - /* exec_addr: */ - 0x00, 0x00, 0x00, 0x00, /* .word 0 */ - 0x0c, 0xe0, 0x1f, 0xe5, /* ldr lr, exec_addr */ -}; - -/* ARM code for binary header injection to change baudrate */ +/* ARM code to change baudrate */ static unsigned char kwboot_baud_code[] = { /* ; #define UART_BASE 0xd0012000 */ /* ; #define THR 0x00 */ @@ -123,14 +116,12 @@ static unsigned char kwboot_baud_code[] = { /* ; return 0; */ /* ; } */ - 0xfe, 0x5f, 0x2d, 0xe9, /* push { r1 - r12, lr } */ - /* ; r0 = UART_BASE */ 0x0d, 0x02, 0xa0, 0xe3, /* mov r0, #0xd0000000 */ 0x12, 0x0a, 0x80, 0xe3, /* orr r0, r0, #0x12000 */ /* ; r2 = address of preamble string */ - 0xcc, 0x20, 0x8f, 0xe2, /* adr r2, preamble */ + 0xc8, 0x20, 0x8f, 0xe2, /* adr r2, preamble */ /* ; Send preamble string over UART */ /* .Lloop_preamble: */ @@ -177,7 +168,7 @@ static unsigned char kwboot_baud_code[] = { /* ; Read old baudrate value */ /* ; r2 = old_baudrate */ - 0x88, 0x20, 0x9f, 0xe5, /* ldr r2, old_baudrate */ + 0x84, 0x20, 0x9f, 0xe5, /* ldr r2, old_baudrate */ /* ; Calculate base clock */ /* ; r1 = r2 * r1 */ @@ -185,7 +176,7 @@ static unsigned char kwboot_baud_code[] = { /* ; Read new baudrate value */ /* ; r2 = new_baudrate */ - 0x84, 0x20, 0x9f, 0xe5, /* ldr r2, new_baudrate */ + 0x80, 0x20, 0x9f, 0xe5, /* ldr r2, new_baudrate */ /* ; Calculate new Divisor Latch */ /* ; r1 = DIV_ROUND(r1, r2) = */ @@ -234,9 +225,7 @@ static unsigned char kwboot_baud_code[] = { 0x00, 0x00, 0x51, 0xe3, /* cmp r1, #0 */ 0xfc, 0xff, 0xff, 0x1a, /* bne .Lloop_sleep */ - /* ; Return 0 - no error */ - 0x00, 0x00, 0xa0, 0xe3, /* mov r0, #0 */ - 0xfe, 0x9f, 0xbd, 0xe8, /* pop { r1 - r12, pc } */ + 0x05, 0x00, 0x00, 0xea, /* b end */ /* ; Preamble string */ /* preamble: */ @@ -252,10 +241,29 @@ static unsigned char kwboot_baud_code[] = { /* ; Placeholder for new baudrate value */ /* new_baudrate: */ 0x00, 0x00, 0x00, 0x00, /* .word 0 */ + + /* end: */ +}; + +/* ARM code for storing registers for future returning back to the bootrom */ +static unsigned char kwboot_baud_code_binhdr_pre[] = { + 0xfe, 0x5f, 0x2d, 0xe9, /* push { r1 - r12, lr } */ }; -#define KWBOOT_BAUDRATE_BIN_HEADER_SZ (sizeof(kwboot_baud_code) + \ - sizeof(struct opt_hdr_v1) + 8 + 16) +/* ARM code for returning back to the bootrom */ +static unsigned char kwboot_baud_code_binhdr_post[] = { + /* ; Return 0 - no error */ + 0x00, 0x00, 0xa0, 0xe3, /* mov r0, #0 */ + 0xfe, 0x9f, 0xbd, 0xe8, /* pop { r1 - r12, pc } */ +}; + +/* ARM code for jumping to the original image exec_addr */ +static unsigned char kwboot_baud_code_data_jump[] = { + 0x04, 0xf0, 0x1f, 0xe5, /* ldr pc, exec_addr */ + /* ; Placeholder for exec_addr */ + /* exec_addr: */ + 0x00, 0x00, 0x00, 0x00, /* .word 0 */ +}; static const char kwb_baud_magic[16] = "$baudratechange"; @@ -1409,44 +1417,51 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) } static void -_inject_baudrate_change_code(void *img, size_t *size, int pre, +_inject_baudrate_change_code(void *img, size_t *size, int for_data, int old_baud, int new_baud) { - uint32_t codesz = sizeof(kwboot_baud_code); struct main_hdr_v1 *hdr = img; + uint32_t orig_datasz; + uint32_t codesz; uint8_t *code; - if (pre) { - uint32_t presz = sizeof(kwboot_pre_baud_code); - uint32_t orig_datasz; - + if (for_data) { orig_datasz = le32_to_cpu(hdr->blocksize) - sizeof(uint32_t); - code = kwboot_img_grow_data_right(img, size, presz + codesz); - - /* - * We need to prepend code that loads lr register with original - * value of hdr->execaddr. We do this by putting the original - * exec address before the code that loads it relatively from - * it's beginning. - * Afterwards we change the exec address to this code (which is - * at offset 4, because the first 4 bytes contain the original - * exec address). - */ - memcpy(code, kwboot_pre_baud_code, presz); - *(uint32_t *)code = hdr->execaddr; - - hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) + - orig_datasz + 4); - - code += presz; + codesz = sizeof(kwboot_baud_code) + + sizeof(kwboot_baud_code_data_jump); + code = kwboot_img_grow_data_right(img, size, codesz); } else { + codesz = sizeof(kwboot_baud_code_binhdr_pre) + + sizeof(kwboot_baud_code) + + sizeof(kwboot_baud_code_binhdr_post); code = kwboot_add_bin_ohdr_v1(img, size, codesz); + + codesz = sizeof(kwboot_baud_code_binhdr_pre); + memcpy(code, kwboot_baud_code_binhdr_pre, codesz); + code += codesz; } - memcpy(code, kwboot_baud_code, codesz - 8); - *(uint32_t *)(code + codesz - 8) = cpu_to_le32(old_baud); - *(uint32_t *)(code + codesz - 4) = cpu_to_le32(new_baud); + codesz = sizeof(kwboot_baud_code) - 2 * sizeof(uint32_t); + memcpy(code, kwboot_baud_code, codesz); + code += codesz; + *(uint32_t *)code = cpu_to_le32(old_baud); + code += sizeof(uint32_t); + *(uint32_t *)code = cpu_to_le32(new_baud); + code += sizeof(uint32_t); + + if (for_data) { + codesz = sizeof(kwboot_baud_code_data_jump) - sizeof(uint32_t); + memcpy(code, kwboot_baud_code_data_jump, codesz); + code += codesz; + *(uint32_t *)code = hdr->execaddr; + code += sizeof(uint32_t); + hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) + orig_datasz); + } else { + codesz = sizeof(kwboot_baud_code_binhdr_post); + memcpy(code, kwboot_baud_code_binhdr_post, codesz); + code += codesz; + } } static int @@ -1729,10 +1744,13 @@ main(int argc, char **argv) baudrate = 0; else /* ensure we have enough space for baudrate change code */ - after_img_rsv += KWBOOT_BAUDRATE_BIN_HEADER_SZ + + after_img_rsv += sizeof(struct opt_hdr_v1) + 8 + 16 + + sizeof(kwboot_baud_code_binhdr_pre) + + sizeof(kwboot_baud_code) + + sizeof(kwboot_baud_code_binhdr_post) + KWBOOT_XM_BLKSZ + - sizeof(kwboot_pre_baud_code) + sizeof(kwboot_baud_code) + + sizeof(kwboot_baud_code_data_jump) + KWBOOT_XM_BLKSZ; if (imgpath) { -- cgit v1.2.3 From 62a98f496a0e8b0ffd67320e24834d400e45d841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 1 Nov 2021 14:00:02 +0100 Subject: tools: kwboot: Do not send magic seq when changing baudrate back to 115200 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After successful transfer of whole image only two things can happen: - BootROM starts execution of data block, which changes UART baudrate back to 115200 Bd, - board crashes and causes CPU reset In both cases UART baudrate is reset to the default speed. So there is no need to send special magic sequence to inform kwboot that baudrate is going to be reset and kwboot does not need to wait for this event and can do it immediately after BootROM acknowledges end of xmodem transfer. Move ARM code for sending magic sequence from main baudrate change section to binhdr_pre section which is executed only before changing baudrate from the default value of 115200 Bd to some new value. Remove kwboot code waiting for magic sequence after successful xmodem transfer. Rationale: sometimes when using very high UART speeds, magic sequence is damaged and kwboot fails at this last stage. Removal of this magic sequence makes booting more stable. Data transfer protocol (xmodem) is using checksums and retransmit, so it already deals with possible errors on transfer line. Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwboot.c | 115 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 55 deletions(-) (limited to 'tools') diff --git a/tools/kwboot.c b/tools/kwboot.c index 359b43c0d8b..bacca153011 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -81,23 +81,15 @@ struct kwboot_block { /* ARM code to change baudrate */ static unsigned char kwboot_baud_code[] = { /* ; #define UART_BASE 0xd0012000 */ - /* ; #define THR 0x00 */ /* ; #define DLL 0x00 */ /* ; #define DLH 0x04 */ /* ; #define LCR 0x0c */ /* ; #define DLAB 0x80 */ /* ; #define LSR 0x14 */ - /* ; #define THRE 0x20 */ /* ; #define TEMT 0x40 */ /* ; #define DIV_ROUND(a, b) ((a + b/2) / b) */ /* ; */ /* ; u32 set_baudrate(u32 old_b, u32 new_b) { */ - /* ; const u8 *str = "$baudratechange"; */ - /* ; u8 c; */ - /* ; do { */ - /* ; c = *str++; */ - /* ; writel(UART_BASE + THR, c); */ - /* ; } while (c); */ /* ; while */ /* ; (!(readl(UART_BASE + LSR) & TEMT)); */ /* ; u32 lcr = readl(UART_BASE + LCR); */ @@ -120,29 +112,6 @@ static unsigned char kwboot_baud_code[] = { 0x0d, 0x02, 0xa0, 0xe3, /* mov r0, #0xd0000000 */ 0x12, 0x0a, 0x80, 0xe3, /* orr r0, r0, #0x12000 */ - /* ; r2 = address of preamble string */ - 0xc8, 0x20, 0x8f, 0xe2, /* adr r2, preamble */ - - /* ; Send preamble string over UART */ - /* .Lloop_preamble: */ - /* */ - /* ; Wait until Transmitter Holding is Empty */ - /* .Lloop_thre: */ - /* ; r1 = UART_BASE[LSR] & THRE */ - 0x14, 0x10, 0x90, 0xe5, /* ldr r1, [r0, #0x14] */ - 0x20, 0x00, 0x11, 0xe3, /* tst r1, #0x20 */ - 0xfc, 0xff, 0xff, 0x0a, /* beq .Lloop_thre */ - - /* ; Put character into Transmitter FIFO */ - /* ; r1 = *r2++ */ - 0x01, 0x10, 0xd2, 0xe4, /* ldrb r1, [r2], #1 */ - /* ; UART_BASE[THR] = r1 */ - 0x00, 0x10, 0x80, 0xe5, /* str r1, [r0, #0x0] */ - - /* ; Loop until end of preamble string */ - 0x00, 0x00, 0x51, 0xe3, /* cmp r1, #0 */ - 0xf8, 0xff, 0xff, 0x1a, /* bne .Lloop_preamble */ - /* ; Wait until Transmitter FIFO is Empty */ /* .Lloop_txempty: */ /* ; r1 = UART_BASE[LSR] & TEMT */ @@ -168,7 +137,7 @@ static unsigned char kwboot_baud_code[] = { /* ; Read old baudrate value */ /* ; r2 = old_baudrate */ - 0x84, 0x20, 0x9f, 0xe5, /* ldr r2, old_baudrate */ + 0x74, 0x20, 0x9f, 0xe5, /* ldr r2, old_baudrate */ /* ; Calculate base clock */ /* ; r1 = r2 * r1 */ @@ -176,7 +145,7 @@ static unsigned char kwboot_baud_code[] = { /* ; Read new baudrate value */ /* ; r2 = new_baudrate */ - 0x80, 0x20, 0x9f, 0xe5, /* ldr r2, new_baudrate */ + 0x70, 0x20, 0x9f, 0xe5, /* ldr r2, new_baudrate */ /* ; Calculate new Divisor Latch */ /* ; r1 = DIV_ROUND(r1, r2) = */ @@ -225,14 +194,8 @@ static unsigned char kwboot_baud_code[] = { 0x00, 0x00, 0x51, 0xe3, /* cmp r1, #0 */ 0xfc, 0xff, 0xff, 0x1a, /* bne .Lloop_sleep */ - 0x05, 0x00, 0x00, 0xea, /* b end */ - - /* ; Preamble string */ - /* preamble: */ - 0x24, 0x62, 0x61, 0x75, /* .asciz "$baudratechange" */ - 0x64, 0x72, 0x61, 0x74, - 0x65, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x00, + /* ; Jump to the end of execution */ + 0x01, 0x00, 0x00, 0xea, /* b end */ /* ; Placeholder for old baudrate value */ /* old_baudrate: */ @@ -245,12 +208,66 @@ static unsigned char kwboot_baud_code[] = { /* end: */ }; -/* ARM code for storing registers for future returning back to the bootrom */ +/* ARM code from binary header executed by BootROM before changing baudrate */ static unsigned char kwboot_baud_code_binhdr_pre[] = { + /* ; #define UART_BASE 0xd0012000 */ + /* ; #define THR 0x00 */ + /* ; #define LSR 0x14 */ + /* ; #define THRE 0x20 */ + /* ; */ + /* ; void send_preamble(void) { */ + /* ; const u8 *str = "$baudratechange"; */ + /* ; u8 c; */ + /* ; do { */ + /* ; while */ + /* ; ((readl(UART_BASE + LSR) & THRE)); */ + /* ; c = *str++; */ + /* ; writel(UART_BASE + THR, c); */ + /* ; } while (c); */ + /* ; } */ + + /* ; Preserve registers for BootROM */ 0xfe, 0x5f, 0x2d, 0xe9, /* push { r1 - r12, lr } */ + + /* ; r0 = UART_BASE */ + 0x0d, 0x02, 0xa0, 0xe3, /* mov r0, #0xd0000000 */ + 0x12, 0x0a, 0x80, 0xe3, /* orr r0, r0, #0x12000 */ + + /* ; r2 = address of preamble string */ + 0x00, 0x20, 0x8f, 0xe2, /* adr r2, .Lstr_preamble */ + + /* ; Skip preamble data section */ + 0x03, 0x00, 0x00, 0xea, /* b .Lloop_preamble */ + + /* ; Preamble string */ + /* .Lstr_preamble: */ + 0x24, 0x62, 0x61, 0x75, /* .asciz "$baudratechange" */ + 0x64, 0x72, 0x61, 0x74, + 0x65, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x00, + + /* ; Send preamble string over UART */ + /* .Lloop_preamble: */ + /* */ + /* ; Wait until Transmitter Holding is Empty */ + /* .Lloop_thre: */ + /* ; r1 = UART_BASE[LSR] & THRE */ + 0x14, 0x10, 0x90, 0xe5, /* ldr r1, [r0, #0x14] */ + 0x20, 0x00, 0x11, 0xe3, /* tst r1, #0x20 */ + 0xfc, 0xff, 0xff, 0x0a, /* beq .Lloop_thre */ + + /* ; Put character into Transmitter FIFO */ + /* ; r1 = *r2++ */ + 0x01, 0x10, 0xd2, 0xe4, /* ldrb r1, [r2], #1 */ + /* ; UART_BASE[THR] = r1 */ + 0x00, 0x10, 0x80, 0xe5, /* str r1, [r0, #0x0] */ + + /* ; Loop until end of preamble string */ + 0x00, 0x00, 0x51, 0xe3, /* cmp r1, #0 */ + 0xf8, 0xff, 0xff, 0x1a, /* bne .Lloop_preamble */ }; -/* ARM code for returning back to the bootrom */ +/* ARM code for returning from binary header back to BootROM */ static unsigned char kwboot_baud_code_binhdr_post[] = { /* ; Return 0 - no error */ 0x00, 0x00, 0xa0, 0xe3, /* mov r0, #0 */ @@ -1078,18 +1095,6 @@ kwboot_xmodem(int tty, const void *_img, size_t size, int baudrate) return rc; if (baudrate) { - char buf[sizeof(kwb_baud_magic)]; - - kwboot_printv("Waiting 1s for baudrate change magic\n"); - rc = kwboot_tty_recv(tty, buf, sizeof(buf), 1000); - if (rc) - return rc; - - if (memcmp(buf, kwb_baud_magic, sizeof(buf))) { - errno = EPROTO; - return -1; - } - kwboot_printv("\nChanging baudrate back to 115200 Bd\n\n"); rc = kwboot_tty_change_baudrate(tty, 115200); if (rc) -- cgit v1.2.3