/* * arm-header.c * * Program to wrap a file into flash blocks and add the magic header and * footer that the ARM Integrator boot monitor expects. This thing expects * you to compile one program into 0x24000000 and the result need to be * flashed in using U-Boot with cp.b 0x24000000 0xN. * * Written by Linus Walleij * License terms: GPLv2 */ #include #include #include #include #include #include #include #include /* * You might want to edit TEXT_ADDRESS, which is the address to which * U-Boot is compiled and identical to the address you would jump to * to start it. */ #define TEXT_ADDRESS 0x01000000U #define FLASH_PAGE_SIZE 0x20000U #define FLASH_START 0x24000000U #define FOOTER_MAGIC 0xA0FFFF9FU static uint32_t getword(unsigned char *p) { return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; } /* This sums the integers and wraps the carry into bit 0 */ static uint32_t wrap_sum(uint32_t sum, uint32_t val) { uint32_t newsum; newsum = sum + val; /* wrap the carry to bit 0 */ if (newsum < sum) newsum++; return newsum; } static void le_wr(unsigned char *buf, uint32_t val) { buf[0] = val & 0xFFU; buf[1] = (val >> 8) & 0xFFU; buf[2] = (val >> 16) & 0xFFU; buf[3] = (val >> 24) & 0xFFU; } static uint32_t le_wr_sum(unsigned char *buf, uint32_t sum, uint32_t val) { le_wr(buf, val); return wrap_sum(sum, val); } int main(int argc, char **argv) { int fdin; int fdout; struct stat sb; uint32_t filesize; uint32_t padding; int ret = 0; const char *pathin; const char *pathout; unsigned char *buffer; uint32_t pages; unsigned char *infop; unsigned char *footp; uint32_t sum; size_t bufsize; size_t bytes; int i; if (argc < 3) { printf("Too few arguments.\n"); printf("%s \n", argv[0]); } pathin = argv[1]; pathout = argv[2]; ret = stat(pathin, &sb); if (ret < 0) return ret; filesize = sb.st_size; padding = filesize % 4; printf("INFILE: %s, size: %08x bytes\n", pathin, filesize); /* File + extended header size + footer size */ bufsize = filesize + padding + 48 + 20; /* Round to flash page size */ pages = (bufsize / FLASH_PAGE_SIZE) + 1; bufsize = (bufsize / FLASH_PAGE_SIZE + 1) * FLASH_PAGE_SIZE; printf("Allocate %u pages of %08x bytes each, total %08x bytes\n", pages, FLASH_PAGE_SIZE, bufsize); buffer = malloc(bufsize); if (!buffer) { printf("OOM: could not allocate buffer\n"); return 0; } /* ununsed flash memory has all bits set = 0xff */ memset(buffer, 0xff, bufsize); /* Read file to buffer */ fdin = open(pathin, O_RDONLY); if (!fdin) { printf("ERROR: could not open input file\n"); return 0; } bytes = read(fdin, buffer, filesize); if (bytes < filesize) { printf("ERROR: could not read entire file\n"); return 0; } close(fdin); /* Pad with zeroes */ for (i = 0; i < padding; i++) buffer[filesize + i] = 0x00; if (padding > 0) printf("Padded image with %u bytes\n", padding); /* PREP HEADER AND FOOTER */ infop = buffer + filesize + padding; footp = buffer + bufsize - 20; /* FOOTER INFO */ sum = 0; sum = le_wr_sum(footp, sum, FLASH_START + filesize); footp += 4; sum = le_wr_sum(footp, sum, FLASH_START); footp += 4; sum = le_wr_sum(footp, sum, FOOTER_MAGIC); footp += 4; /* * Image type: * 0x00000001: ARM executable * 0x00000008: ARM backup */ sum = le_wr_sum(footp, sum, 0x00000001U); footp += 4; le_wr(footp, ~(sum)); printf("footer checksum: 0x%08x\n", ~(sum)); /* HEADER INFO */ sum = 0; /* Sum the file */ for (i = 0; i < filesize; i+=4) sum = wrap_sum(sum, getword(&buffer[i])); /* * Boot reqs * Bit 0: non-bootable * Bit 1: decompress * Bit 2: initialize memory * Bit 3: copy image to RAM before executing * So we just initialize memory and run! */ sum = le_wr_sum(infop, sum, 0x0000000CU); infop += 4; /* File index */ sum = le_wr_sum(infop, sum, 0x00000000U); infop += 4; /* Load address */ sum = le_wr_sum(infop, sum, TEXT_ADDRESS); infop += 4; /* Image size */ sum = le_wr_sum(infop, sum, filesize); infop += 4; /* Execution address */ sum = le_wr_sum(infop, sum, TEXT_ADDRESS); infop += 4; /* Name 1 */ sum = le_wr_sum(infop, sum, 0x6f422d55U); infop += 4; /* Name 2 */ sum = le_wr_sum(infop, sum, 0x0000746fU); infop += 4; /* Name 3 */ sum = le_wr_sum(infop, sum, 0x00000000U); infop += 4; /* Name 4 */ sum = le_wr_sum(infop, sum, 0x00000000U); infop += 4; /* Pointer to header */ sum = le_wr_sum(infop, sum, 0x00000000U); infop += 4; /* Header length */ sum = le_wr_sum(infop, sum, 0x00000000U); infop += 4; /* Header type */ sum = le_wr_sum(infop, sum, 0x00000000U); infop += 4; /* Checksum - apparently one is subtracted from the checksum */ le_wr(infop, ~(sum)); printf("file & header checksum: 0x%08x\n", ~(sum)); printf("OUTFILE: %s, size: %08x bytes\n", pathout, bufsize); fdout = open(pathout, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP); if (!fdout) { printf("ERROR: could not open output file\n"); return 0; } bytes = write(fdout, buffer, bufsize); if (bytes < bufsize) { printf("ERROR: could not write complete output file\n"); return 0; } close(fdout); free(buffer); return 0; }