162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Makes a tree bootable image for IBM Evaluation boards. 462306a36Sopenharmony_ci * Basically, just take a zImage, skip the ELF header, and stuff 562306a36Sopenharmony_ci * a 32 byte header on the front. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * We use htonl, which is a network macro, to make sure we're doing 862306a36Sopenharmony_ci * The Right Thing on an LE machine. It's non-obvious, but it should 962306a36Sopenharmony_ci * work on anything BSD'ish. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <fcntl.h> 1362306a36Sopenharmony_ci#include <stdio.h> 1462306a36Sopenharmony_ci#include <stdlib.h> 1562306a36Sopenharmony_ci#include <string.h> 1662306a36Sopenharmony_ci#include <sys/stat.h> 1762306a36Sopenharmony_ci#include <unistd.h> 1862306a36Sopenharmony_ci#include <netinet/in.h> 1962306a36Sopenharmony_ci#ifdef __sun__ 2062306a36Sopenharmony_ci#include <inttypes.h> 2162306a36Sopenharmony_ci#else 2262306a36Sopenharmony_ci#include <stdint.h> 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* This gets tacked on the front of the image. There are also a few 2662306a36Sopenharmony_ci * bytes allocated after the _start label used by the boot rom (see 2762306a36Sopenharmony_ci * head.S for details). 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_citypedef struct boot_block { 3062306a36Sopenharmony_ci uint32_t bb_magic; /* 0x0052504F */ 3162306a36Sopenharmony_ci uint32_t bb_dest; /* Target address of the image */ 3262306a36Sopenharmony_ci uint32_t bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */ 3362306a36Sopenharmony_ci uint32_t bb_debug_flag; /* Run debugger or image after load */ 3462306a36Sopenharmony_ci uint32_t bb_entry_point; /* The image address to start */ 3562306a36Sopenharmony_ci uint32_t bb_checksum; /* 32 bit checksum including header */ 3662306a36Sopenharmony_ci uint32_t reserved[2]; 3762306a36Sopenharmony_ci} boot_block_t; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define IMGBLK 512 4062306a36Sopenharmony_ciunsigned int tmpbuf[IMGBLK / sizeof(unsigned int)]; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint main(int argc, char *argv[]) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci int in_fd, out_fd; 4562306a36Sopenharmony_ci int nblks, i; 4662306a36Sopenharmony_ci unsigned int cksum, *cp; 4762306a36Sopenharmony_ci struct stat st; 4862306a36Sopenharmony_ci boot_block_t bt; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (argc < 5) { 5162306a36Sopenharmony_ci fprintf(stderr, "usage: %s <zImage-file> <boot-image> <load address> <entry point>\n",argv[0]); 5262306a36Sopenharmony_ci exit(1); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (stat(argv[1], &st) < 0) { 5662306a36Sopenharmony_ci perror("stat"); 5762306a36Sopenharmony_ci exit(2); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci nblks = (st.st_size + IMGBLK) / IMGBLK; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci bt.bb_magic = htonl(0x0052504F); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* If we have the optional entry point parameter, use it */ 6562306a36Sopenharmony_ci bt.bb_dest = htonl(strtoul(argv[3], NULL, 0)); 6662306a36Sopenharmony_ci bt.bb_entry_point = htonl(strtoul(argv[4], NULL, 0)); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* We know these from the linker command. 6962306a36Sopenharmony_ci * ...and then move it up into memory a little more so the 7062306a36Sopenharmony_ci * relocation can happen. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci bt.bb_num_512blocks = htonl(nblks); 7362306a36Sopenharmony_ci bt.bb_debug_flag = 0; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci bt.bb_checksum = 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* To be neat and tidy :-). 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci bt.reserved[0] = 0; 8062306a36Sopenharmony_ci bt.reserved[1] = 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if ((in_fd = open(argv[1], O_RDONLY)) < 0) { 8362306a36Sopenharmony_ci perror("zImage open"); 8462306a36Sopenharmony_ci exit(3); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) { 8862306a36Sopenharmony_ci perror("bootfile open"); 8962306a36Sopenharmony_ci exit(3); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci cksum = 0; 9362306a36Sopenharmony_ci cp = (void *)&bt; 9462306a36Sopenharmony_ci for (i = 0; i < sizeof(bt) / sizeof(unsigned int); i++) 9562306a36Sopenharmony_ci cksum += *cp++; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Assume zImage is an ELF file, and skip the 64K header. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci if (read(in_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) { 10062306a36Sopenharmony_ci fprintf(stderr, "%s is too small to be an ELF image\n", 10162306a36Sopenharmony_ci argv[1]); 10262306a36Sopenharmony_ci exit(4); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (tmpbuf[0] != htonl(0x7f454c46)) { 10662306a36Sopenharmony_ci fprintf(stderr, "%s is not an ELF image\n", argv[1]); 10762306a36Sopenharmony_ci exit(4); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (lseek(in_fd, (64 * 1024), SEEK_SET) < 0) { 11162306a36Sopenharmony_ci fprintf(stderr, "%s failed to seek in ELF image\n", argv[1]); 11262306a36Sopenharmony_ci exit(4); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci nblks -= (64 * 1024) / IMGBLK; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* And away we go...... 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) { 12062306a36Sopenharmony_ci perror("boot-image write"); 12162306a36Sopenharmony_ci exit(5); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci while (nblks-- > 0) { 12562306a36Sopenharmony_ci if (read(in_fd, tmpbuf, sizeof(tmpbuf)) < 0) { 12662306a36Sopenharmony_ci perror("zImage read"); 12762306a36Sopenharmony_ci exit(5); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci cp = tmpbuf; 13062306a36Sopenharmony_ci for (i = 0; i < sizeof(tmpbuf) / sizeof(unsigned int); i++) 13162306a36Sopenharmony_ci cksum += *cp++; 13262306a36Sopenharmony_ci if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) { 13362306a36Sopenharmony_ci perror("boot-image write"); 13462306a36Sopenharmony_ci exit(5); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* rewrite the header with the computed checksum. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci bt.bb_checksum = htonl(cksum); 14162306a36Sopenharmony_ci if (lseek(out_fd, 0, SEEK_SET) < 0) { 14262306a36Sopenharmony_ci perror("rewrite seek"); 14362306a36Sopenharmony_ci exit(1); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) { 14662306a36Sopenharmony_ci perror("boot-image rewrite"); 14762306a36Sopenharmony_ci exit(1); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci exit(0); 15162306a36Sopenharmony_ci} 152