1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
20cfcccb4SJosh Boyer /*
30cfcccb4SJosh Boyer * Makes a tree bootable image for IBM Evaluation boards.
40cfcccb4SJosh Boyer * Basically, just take a zImage, skip the ELF header, and stuff
50cfcccb4SJosh Boyer * a 32 byte header on the front.
60cfcccb4SJosh Boyer *
70cfcccb4SJosh Boyer * We use htonl, which is a network macro, to make sure we're doing
80cfcccb4SJosh Boyer * The Right Thing on an LE machine. It's non-obvious, but it should
90cfcccb4SJosh Boyer * work on anything BSD'ish.
100cfcccb4SJosh Boyer */
110cfcccb4SJosh Boyer
120cfcccb4SJosh Boyer #include <fcntl.h>
130cfcccb4SJosh Boyer #include <stdio.h>
140cfcccb4SJosh Boyer #include <stdlib.h>
150cfcccb4SJosh Boyer #include <string.h>
160cfcccb4SJosh Boyer #include <sys/stat.h>
170cfcccb4SJosh Boyer #include <unistd.h>
180cfcccb4SJosh Boyer #include <netinet/in.h>
190cfcccb4SJosh Boyer #ifdef __sun__
200cfcccb4SJosh Boyer #include <inttypes.h>
210cfcccb4SJosh Boyer #else
220cfcccb4SJosh Boyer #include <stdint.h>
230cfcccb4SJosh Boyer #endif
240cfcccb4SJosh Boyer
250cfcccb4SJosh Boyer /* This gets tacked on the front of the image. There are also a few
260cfcccb4SJosh Boyer * bytes allocated after the _start label used by the boot rom (see
270cfcccb4SJosh Boyer * head.S for details).
280cfcccb4SJosh Boyer */
290cfcccb4SJosh Boyer typedef struct boot_block {
300cfcccb4SJosh Boyer uint32_t bb_magic; /* 0x0052504F */
310cfcccb4SJosh Boyer uint32_t bb_dest; /* Target address of the image */
320cfcccb4SJosh Boyer uint32_t bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */
330cfcccb4SJosh Boyer uint32_t bb_debug_flag; /* Run debugger or image after load */
340cfcccb4SJosh Boyer uint32_t bb_entry_point; /* The image address to start */
350cfcccb4SJosh Boyer uint32_t bb_checksum; /* 32 bit checksum including header */
360cfcccb4SJosh Boyer uint32_t reserved[2];
370cfcccb4SJosh Boyer } boot_block_t;
380cfcccb4SJosh Boyer
390cfcccb4SJosh Boyer #define IMGBLK 512
403c15a688SStephen Rothwell unsigned int tmpbuf[IMGBLK / sizeof(unsigned int)];
410cfcccb4SJosh Boyer
main(int argc,char * argv[])420cfcccb4SJosh Boyer int main(int argc, char *argv[])
430cfcccb4SJosh Boyer {
440cfcccb4SJosh Boyer int in_fd, out_fd;
450cfcccb4SJosh Boyer int nblks, i;
4693f1cc60STimur Tabi unsigned int cksum, *cp;
470cfcccb4SJosh Boyer struct stat st;
480cfcccb4SJosh Boyer boot_block_t bt;
490cfcccb4SJosh Boyer
50f6dfc805SDavid Gibson if (argc < 5) {
51f6dfc805SDavid Gibson fprintf(stderr, "usage: %s <zImage-file> <boot-image> <load address> <entry point>\n",argv[0]);
520cfcccb4SJosh Boyer exit(1);
530cfcccb4SJosh Boyer }
540cfcccb4SJosh Boyer
550cfcccb4SJosh Boyer if (stat(argv[1], &st) < 0) {
560cfcccb4SJosh Boyer perror("stat");
570cfcccb4SJosh Boyer exit(2);
580cfcccb4SJosh Boyer }
590cfcccb4SJosh Boyer
600cfcccb4SJosh Boyer nblks = (st.st_size + IMGBLK) / IMGBLK;
610cfcccb4SJosh Boyer
620cfcccb4SJosh Boyer bt.bb_magic = htonl(0x0052504F);
630cfcccb4SJosh Boyer
640cfcccb4SJosh Boyer /* If we have the optional entry point parameter, use it */
65f6dfc805SDavid Gibson bt.bb_dest = htonl(strtoul(argv[3], NULL, 0));
66f6dfc805SDavid Gibson bt.bb_entry_point = htonl(strtoul(argv[4], NULL, 0));
670cfcccb4SJosh Boyer
680cfcccb4SJosh Boyer /* We know these from the linker command.
690cfcccb4SJosh Boyer * ...and then move it up into memory a little more so the
700cfcccb4SJosh Boyer * relocation can happen.
710cfcccb4SJosh Boyer */
720cfcccb4SJosh Boyer bt.bb_num_512blocks = htonl(nblks);
730cfcccb4SJosh Boyer bt.bb_debug_flag = 0;
740cfcccb4SJosh Boyer
750cfcccb4SJosh Boyer bt.bb_checksum = 0;
760cfcccb4SJosh Boyer
770cfcccb4SJosh Boyer /* To be neat and tidy :-).
780cfcccb4SJosh Boyer */
790cfcccb4SJosh Boyer bt.reserved[0] = 0;
800cfcccb4SJosh Boyer bt.reserved[1] = 0;
810cfcccb4SJosh Boyer
820cfcccb4SJosh Boyer if ((in_fd = open(argv[1], O_RDONLY)) < 0) {
830cfcccb4SJosh Boyer perror("zImage open");
840cfcccb4SJosh Boyer exit(3);
850cfcccb4SJosh Boyer }
860cfcccb4SJosh Boyer
870cfcccb4SJosh Boyer if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) {
880cfcccb4SJosh Boyer perror("bootfile open");
890cfcccb4SJosh Boyer exit(3);
900cfcccb4SJosh Boyer }
910cfcccb4SJosh Boyer
920cfcccb4SJosh Boyer cksum = 0;
930cfcccb4SJosh Boyer cp = (void *)&bt;
9493f1cc60STimur Tabi for (i = 0; i < sizeof(bt) / sizeof(unsigned int); i++)
950cfcccb4SJosh Boyer cksum += *cp++;
960cfcccb4SJosh Boyer
970cfcccb4SJosh Boyer /* Assume zImage is an ELF file, and skip the 64K header.
980cfcccb4SJosh Boyer */
993c15a688SStephen Rothwell if (read(in_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
1000cfcccb4SJosh Boyer fprintf(stderr, "%s is too small to be an ELF image\n",
1010cfcccb4SJosh Boyer argv[1]);
1020cfcccb4SJosh Boyer exit(4);
1030cfcccb4SJosh Boyer }
1040cfcccb4SJosh Boyer
1053c15a688SStephen Rothwell if (tmpbuf[0] != htonl(0x7f454c46)) {
1060cfcccb4SJosh Boyer fprintf(stderr, "%s is not an ELF image\n", argv[1]);
1070cfcccb4SJosh Boyer exit(4);
1080cfcccb4SJosh Boyer }
1090cfcccb4SJosh Boyer
1100cfcccb4SJosh Boyer if (lseek(in_fd, (64 * 1024), SEEK_SET) < 0) {
1110cfcccb4SJosh Boyer fprintf(stderr, "%s failed to seek in ELF image\n", argv[1]);
1120cfcccb4SJosh Boyer exit(4);
1130cfcccb4SJosh Boyer }
1140cfcccb4SJosh Boyer
1150cfcccb4SJosh Boyer nblks -= (64 * 1024) / IMGBLK;
1160cfcccb4SJosh Boyer
1170cfcccb4SJosh Boyer /* And away we go......
1180cfcccb4SJosh Boyer */
1190cfcccb4SJosh Boyer if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
1200cfcccb4SJosh Boyer perror("boot-image write");
1210cfcccb4SJosh Boyer exit(5);
1220cfcccb4SJosh Boyer }
1230cfcccb4SJosh Boyer
1240cfcccb4SJosh Boyer while (nblks-- > 0) {
1253c15a688SStephen Rothwell if (read(in_fd, tmpbuf, sizeof(tmpbuf)) < 0) {
1260cfcccb4SJosh Boyer perror("zImage read");
1270cfcccb4SJosh Boyer exit(5);
1280cfcccb4SJosh Boyer }
1293c15a688SStephen Rothwell cp = tmpbuf;
13093f1cc60STimur Tabi for (i = 0; i < sizeof(tmpbuf) / sizeof(unsigned int); i++)
1310cfcccb4SJosh Boyer cksum += *cp++;
1320cfcccb4SJosh Boyer if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
1330cfcccb4SJosh Boyer perror("boot-image write");
1340cfcccb4SJosh Boyer exit(5);
1350cfcccb4SJosh Boyer }
1360cfcccb4SJosh Boyer }
1370cfcccb4SJosh Boyer
1380cfcccb4SJosh Boyer /* rewrite the header with the computed checksum.
1390cfcccb4SJosh Boyer */
1400cfcccb4SJosh Boyer bt.bb_checksum = htonl(cksum);
1410cfcccb4SJosh Boyer if (lseek(out_fd, 0, SEEK_SET) < 0) {
1420cfcccb4SJosh Boyer perror("rewrite seek");
1430cfcccb4SJosh Boyer exit(1);
1440cfcccb4SJosh Boyer }
1450cfcccb4SJosh Boyer if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
1460cfcccb4SJosh Boyer perror("boot-image rewrite");
1470cfcccb4SJosh Boyer exit(1);
1480cfcccb4SJosh Boyer }
1490cfcccb4SJosh Boyer
1500cfcccb4SJosh Boyer exit(0);
1510cfcccb4SJosh Boyer }
152