#define OPT_HDR_V1_BINARY_TYPE 0x2
#define OPT_HDR_V1_REGISTER_TYPE 0x3
+#define KWBHEADER_V0_SIZE(hdr) \
+ (((hdr)->ext & 0x1) ? sizeof(struct kwb_header) : \
+ sizeof(struct main_hdr_v0))
+
#define KWBHEADER_V1_SIZE(hdr) \
(((hdr)->headersz_msb << 16) | le16_to_cpu((hdr)->headersz_lsb))
* header, byte 8 was reserved, and always set to 0. In the v1 header,
* byte 8 has been changed to a proper field, set to 1.
*/
-static inline unsigned int image_version(void *header)
+static inline unsigned int image_version(const void *header)
{
- unsigned char *ptr = header;
+ const unsigned char *ptr = header;
return ptr[8];
}
#define NAK 21 /* target block negative ack */
#define CAN 24 /* target/sender transfer cancellation */
+#define KWBOOT_XM_BLKSZ 128 /* xmodem block size */
+
struct kwboot_block {
uint8_t soh;
uint8_t pnum;
uint8_t _pnum;
- uint8_t data[128];
+ uint8_t data[KWBOOT_XM_BLKSZ];
uint8_t csum;
} __packed;
kwboot_xm_makeblock(struct kwboot_block *block, const void *data,
size_t size, int pnum)
{
- const size_t blksz = sizeof(block->data);
size_t i, n;
block->soh = SOH;
block->pnum = pnum;
block->_pnum = ~block->pnum;
- n = size < blksz ? size : blksz;
+ n = size < KWBOOT_XM_BLKSZ ? size : KWBOOT_XM_BLKSZ;
memcpy(&block->data[0], data, n);
- memset(&block->data[n], 0, blksz - n);
+ memset(&block->data[n], 0, KWBOOT_XM_BLKSZ - n);
block->csum = 0;
for (i = 0; i < n; i++)
}
static int
-kwboot_xmodem(int tty, const void *_data, size_t size)
+kwboot_xmodem_one(int tty, int *pnum, int header, const uint8_t *data,
+ size_t size)
{
- const uint8_t *data = _data;
- int rc, pnum, N, err;
-
- pnum = 1;
- N = 0;
+ size_t sent, left;
+ int rc;
- kwboot_printv("Sending boot image...\n");
+ kwboot_printv("Sending boot image %s (%zu bytes)...\n",
+ header ? "header" : "data", size);
- sleep(2); /* flush isn't effective without it */
- tcflush(tty, TCIOFLUSH);
+ left = size;
+ sent = 0;
- do {
+ while (sent < size) {
struct kwboot_block block;
- int n;
+ size_t blksz;
- n = kwboot_xm_makeblock(&block,
- data + N, size - N,
- pnum++);
- if (!n)
- break;
+ blksz = kwboot_xm_makeblock(&block, data, left, (*pnum)++);
+ data += blksz;
rc = kwboot_xm_sendblock(tty, &block);
if (rc)
goto out;
- N += n;
- kwboot_progress(N * 100 / size, '.');
- } while (1);
+ sent += blksz;
+ left -= blksz;
+
+ kwboot_progress(sent * 100 / size, '.');
+ }
- rc = kwboot_tty_send_char(tty, EOT);
+ kwboot_printv("Done\n");
+ return 0;
out:
kwboot_printv("\n");
return rc;
+}
-can:
- err = errno;
- kwboot_tty_send_char(tty, CAN);
- errno = err;
- goto out;
+static int
+kwboot_xmodem(int tty, const void *_img, size_t size)
+{
+ const uint8_t *img = _img;
+ int rc, pnum;
+ size_t hdrsz;
+
+ if (image_version(img) == 0)
+ hdrsz = KWBHEADER_V0_SIZE((struct main_hdr_v0 *)img);
+ else
+ hdrsz = KWBHEADER_V1_SIZE((struct main_hdr_v1 *)img);
+
+ kwboot_printv("Waiting 2s and flushing tty\n");
+ sleep(2); /* flush isn't effective without it */
+ tcflush(tty, TCIOFLUSH);
+
+ pnum = 1;
+
+ rc = kwboot_xmodem_one(tty, &pnum, 1, img, hdrsz);
+ if (rc)
+ return rc;
+
+ img += hdrsz;
+ size -= hdrsz;
+
+ rc = kwboot_xmodem_one(tty, &pnum, 0, img, size);
+ if (rc)
+ return rc;
+
+ return kwboot_tty_send_char(tty, EOT);
}
static int