#include <stdint.h>
#include <termios.h>
#include <time.h>
-#include <sys/mman.h>
#include <sys/stat.h>
/*
}
static void *
-kwboot_mmap_image(const char *path, size_t *size)
+kwboot_read_image(const char *path, size_t *size, size_t reserve)
{
int rc, fd;
struct stat st;
void *img;
+ off_t tot;
rc = -1;
img = NULL;
if (rc)
goto out;
- img = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
- if (img == MAP_FAILED) {
- img = NULL;
+ img = malloc(st.st_size + reserve);
+ if (!img)
goto out;
+
+ tot = 0;
+ while (tot < st.st_size) {
+ ssize_t rd = read(fd, img + tot, st.st_size - tot);
+
+ if (rd < 0)
+ goto out;
+
+ tot += rd;
+
+ if (!rd && tot < st.st_size) {
+ errno = EIO;
+ goto out;
+ }
}
rc = 0;
*size = st.st_size;
out:
if (rc && img) {
- munmap(img, st.st_size);
+ free(img);
img = NULL;
}
if (fd >= 0)
return 0;
}
+static void
+kwboot_img_grow_hdr(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(img);
+ 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);
+
+ hdr->srcaddr = cpu_to_le32(srcaddr + need);
+ *size += need;
+ }
+
+ if (kwbimage_version(img) == 1) {
+ hdrsz += grow;
+ hdr->headersz_msb = hdrsz >> 16;
+ hdr->headersz_lsb = cpu_to_le16(hdrsz & 0xffff);
+ }
+}
+
static int
-kwboot_img_patch_hdr(void *img, size_t size)
+kwboot_img_patch_hdr(void *img, size_t *size)
{
int rc;
struct main_hdr_v1 *hdr;
rc = -1;
hdr = img;
- if (size < hdrsz) {
+ if (*size < hdrsz) {
errno = EINVAL;
goto out;
}
hdrsz = kwbheader_size(hdr);
- if (size < hdrsz) {
+ if (*size < hdrsz) {
errno = EINVAL;
goto out;
}
break;
}
+ if (hdrsz > le32_to_cpu(hdr->srcaddr) ||
+ *size < le32_to_cpu(hdr->srcaddr) + le32_to_cpu(hdr->blocksize)) {
+ errno = EINVAL;
+ goto out;
+ }
+
is_secure = kwboot_img_is_secure(img);
if (hdr->blockid != IBR_HDR_UART_ID) {
hdr->blockid = IBR_HDR_UART_ID;
}
+ if (hdrsz % KWBOOT_XM_BLKSZ) {
+ size_t offset = (KWBOOT_XM_BLKSZ - hdrsz % KWBOOT_XM_BLKSZ) %
+ KWBOOT_XM_BLKSZ;
+
+ if (is_secure) {
+ fprintf(stderr, "Cannot align image with secure header\n");
+ errno = EINVAL;
+ goto out;
+ }
+
+ kwboot_printv("Aligning image header to Xmodem block size\n");
+ kwboot_img_grow_hdr(img, size, offset);
+ }
+
hdr->checksum = kwboot_hdr_csum8(hdr) - csum;
+ *size = le32_to_cpu(hdr->srcaddr) + le32_to_cpu(hdr->blocksize);
rc = 0;
out:
return rc;
}
if (imgpath) {
- img = kwboot_mmap_image(imgpath, &size);
+ img = kwboot_read_image(imgpath, &size, KWBOOT_XM_BLKSZ);
if (!img) {
perror(imgpath);
goto out;
}
- rc = kwboot_img_patch_hdr(img, size);
+ rc = kwboot_img_patch_hdr(img, &size);
if (rc) {
fprintf(stderr, "%s: Invalid image.\n", imgpath);
goto out;
close(tty);
if (img)
- munmap(img, size);
+ free(img);
return rv;