xref: /netbsd-src/external/gpl3/binutils.old/usr.sbin/ncdcs/ncdcs.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1*e992f068Schristos /* $NetBSD: ncdcs.c,v 1.8 2024/06/29 16:36:18 christos Exp $ */
216dce513Schristos /*
316dce513Schristos ** Program to prepare an ELF file for download to an IBM Network
416dce513Schristos ** Station 300 or 1000 running the NCD firmware.
516dce513Schristos **
616dce513Schristos ** This may also work for other loaders based on NCD code.
716dce513Schristos **
816dce513Schristos ** The program expects a signature and some marker fields a couple
916dce513Schristos ** bytes into the image itself, where the checksum gets patched in.
1016dce513Schristos ** The checksum itself is a 16bit CRC over the ELF header, the ELF
1116dce513Schristos ** program header, and the image portion of the ELF file. The start
1216dce513Schristos ** value for the CRC is 0xffff, and no final xor is performed.
1316dce513Schristos **
1416dce513Schristos ** Usage: ncdcs <infile> [outfile]
1516dce513Schristos ** e.g.   ncdcs zImage zImage.ncd
1616dce513Schristos **
1716dce513Schristos ** Copyright 2002 Jochen Roth
1816dce513Schristos ** NetBSD changes copyright 2003 John Gordon
1916dce513Schristos **
2016dce513Schristos ** This program is free software; you can redistribute it and/or
2116dce513Schristos ** modify it under the terms of the GNU General Public License,
2216dce513Schristos ** Version 2, as published by the Free Software Foundation.
2316dce513Schristos **
2416dce513Schristos */
2516dce513Schristos 
2616dce513Schristos 
2716dce513Schristos #include <stdio.h>
2816dce513Schristos #include <stdlib.h>
2916dce513Schristos #include <string.h>
3016dce513Schristos #include <sys/types.h>
3116dce513Schristos #include <sys/wait.h>
3216dce513Schristos #include <sys/stat.h>
3316dce513Schristos #include <unistd.h>
3416dce513Schristos #include <fcntl.h>
3516dce513Schristos #include <errno.h>
3616dce513Schristos 
3716dce513Schristos #ifdef __NetBSD__
3816dce513Schristos 
3916dce513Schristos unsigned short crc16(unsigned short crc, unsigned char *buf, unsigned len);
4016dce513Schristos unsigned short get_be_16(unsigned char *p);
4116dce513Schristos unsigned long get_be_32(unsigned char *p);
4216dce513Schristos void put_be_16(unsigned char *p, unsigned short x);
4316dce513Schristos void put_be_32(unsigned char *p, unsigned long x);
4416dce513Schristos 
4516dce513Schristos #endif
4616dce513Schristos 
4716dce513Schristos static const unsigned short crc16_table[256] = {
4816dce513Schristos 	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
4916dce513Schristos 	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
5016dce513Schristos 	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
5116dce513Schristos 	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
5216dce513Schristos 	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
5316dce513Schristos 	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
5416dce513Schristos 	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
5516dce513Schristos 	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
5616dce513Schristos 	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
5716dce513Schristos 	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
5816dce513Schristos 	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
5916dce513Schristos 	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
6016dce513Schristos 	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
6116dce513Schristos 	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
6216dce513Schristos 	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
6316dce513Schristos 	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
6416dce513Schristos 	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
6516dce513Schristos 	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
6616dce513Schristos 	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
6716dce513Schristos 	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
6816dce513Schristos 	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
6916dce513Schristos 	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
7016dce513Schristos 	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
7116dce513Schristos 	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
7216dce513Schristos 	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
7316dce513Schristos 	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
7416dce513Schristos 	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
7516dce513Schristos 	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
7616dce513Schristos 	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
7716dce513Schristos 	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
7816dce513Schristos 	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
7916dce513Schristos 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
8016dce513Schristos };
8116dce513Schristos 
8216dce513Schristos 
crc16(unsigned short crc,unsigned char * buf,unsigned len)8316dce513Schristos unsigned short crc16(unsigned short crc, unsigned char *buf, unsigned len)
8416dce513Schristos {
8516dce513Schristos 	while(len--) {
8616dce513Schristos 		crc = crc16_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
8716dce513Schristos 	}
8816dce513Schristos 	return(crc);
8916dce513Schristos }
9016dce513Schristos 
9116dce513Schristos 
get_be_16(unsigned char * p)9216dce513Schristos unsigned short get_be_16(unsigned char *p)
9316dce513Schristos {
9416dce513Schristos 	unsigned short x = 0;
9516dce513Schristos 	x = (unsigned short)p[0];
9616dce513Schristos 	x = (x<<8) + (unsigned short)p[1];
9716dce513Schristos 	return(x);
9816dce513Schristos }
9916dce513Schristos 
10016dce513Schristos 
get_be_32(unsigned char * p)10116dce513Schristos unsigned long get_be_32(unsigned char *p)
10216dce513Schristos {
10316dce513Schristos 	unsigned long x = 0;
10416dce513Schristos 	x = (unsigned long)p[0];
10516dce513Schristos 	x = (x<<8) + (unsigned long)p[1];
10616dce513Schristos 	x = (x<<8) + (unsigned long)p[2];
10716dce513Schristos 	x = (x<<8) + (unsigned long)p[3];
10816dce513Schristos 	return(x);
10916dce513Schristos }
11016dce513Schristos 
11116dce513Schristos 
put_be_16(unsigned char * p,unsigned short x)11216dce513Schristos void put_be_16(unsigned char *p, unsigned short x)
11316dce513Schristos {
11416dce513Schristos 	p[0] = (x >> 8);
11516dce513Schristos 	p[1] = x;
11616dce513Schristos }
11716dce513Schristos 
11816dce513Schristos 
put_be_32(unsigned char * p,unsigned long x)11916dce513Schristos void put_be_32(unsigned char *p, unsigned long x)
12016dce513Schristos {
12116dce513Schristos 	p[0] = (x >> 24);
12216dce513Schristos 	p[1] = (x >> 16);
12316dce513Schristos 	p[2] = (x >> 8);
12416dce513Schristos 	p[3] = x;
12516dce513Schristos }
12616dce513Schristos 
12716dce513Schristos 
main(int argc,char * argv[])12816dce513Schristos int main(int argc, char *argv[])
12916dce513Schristos {
13016dce513Schristos 	char		*infile, *outfile;
13116dce513Schristos 	struct stat	st;
13216dce513Schristos 	unsigned char	*buf, *image, *p;
13316dce513Schristos 	int		fd, filesize, old_filesize;
13416dce513Schristos 	unsigned long	hdr_len, img_len, img_offset;
13516dce513Schristos 	unsigned short	crc, old_crc;
13616dce513Schristos 
13716dce513Schristos 	/* check arguments */
13816dce513Schristos 
13916dce513Schristos 	if(argc < 2 || argc > 3 || argv[1][0] == '-') {
14016dce513Schristos 		printf("usage: %s <elf-image> [ncd-image]\n", argv[0]);
14116dce513Schristos 		return(1);
14216dce513Schristos 	}
14316dce513Schristos 
14416dce513Schristos 	infile = argv[1];
14516dce513Schristos 	outfile = argc > 2 ? argv[2] : NULL;
14616dce513Schristos 
14716dce513Schristos 	/* determine file size, allocate buffer, open and read elf file */
14816dce513Schristos 
14916dce513Schristos 	if ((fd = open(infile, O_RDONLY)) == -1) {
15016dce513Schristos 		perror(infile);
15116dce513Schristos 		return(-1);
15216dce513Schristos 	}
15316dce513Schristos 
15416dce513Schristos 	if (fstat(fd, &st) == -1) {
15516dce513Schristos 		perror(infile);
15616dce513Schristos 		close(fd);
15716dce513Schristos 		return(-1);
15816dce513Schristos 	}
15916dce513Schristos 	buf = malloc(st.st_size + 4);
16016dce513Schristos 	if (buf == NULL) {
16116dce513Schristos 		perror(infile);
16216dce513Schristos 		close(fd);
16316dce513Schristos 		return(-1);
16416dce513Schristos 	}
16516dce513Schristos 	filesize = read(fd, buf, st.st_size);
16616dce513Schristos 	if (filesize != st.st_size) {
16716dce513Schristos 		perror(infile);
16816dce513Schristos 		close(fd);
16916dce513Schristos 		return(-1);
17016dce513Schristos 	}
17116dce513Schristos 	close(fd);
17216dce513Schristos 
17316dce513Schristos 	/* verify elf header */
17416dce513Schristos 
17516dce513Schristos 	if(memcmp(buf, "\177ELF", 4)) {
17616dce513Schristos 		fprintf(stderr, "%s: not an ELF file\n", infile);
17716dce513Schristos 		return(-1);
17816dce513Schristos 	}
17916dce513Schristos 	if(buf[0x04] != 1 || buf[0x05] != 2 || get_be_16(buf+0x12) != 20) {
18016dce513Schristos 		fprintf(stderr, "%s: not a 32bit big-endian PPC ELF file\n", infile);
18116dce513Schristos 		return(-1);
18216dce513Schristos 	}
18316dce513Schristos 	if(get_be_32(buf+0x1c) != 0x34) {
18416dce513Schristos 		fprintf(stderr, "%s: ELF PPC program header not at expected offset\n", infile);
18516dce513Schristos 		return(-1);
18616dce513Schristos 	}
18716dce513Schristos 
18816dce513Schristos 	if((img_offset = get_be_32(buf+0x38)) != 0x10000) {
18916dce513Schristos 	        /*
19016dce513Schristos 	         * Doesn't seem to bother the device when the header is less
19116dce513Schristos 		 * than 64K, and the default builds for NetBSD always generate
19216dce513Schristos 		 * images that are not padded to a 64K boundary...
19316dce513Schristos 	         */
19416dce513Schristos #ifndef __NetBSD__
19516dce513Schristos 		fprintf(stderr, "warning: %s: size of ELF header is not 64k\n", infile);
19616dce513Schristos #endif
19716dce513Schristos 	}
19816dce513Schristos 
19916dce513Schristos 	/* verify checksum area markers */
20016dce513Schristos 
20116dce513Schristos 	image = buf + img_offset;
20216dce513Schristos 	if(memcmp(image + 0x10, "XncdPPC", 8)) {
20316dce513Schristos 		fprintf(stderr, "%s: missing XncdPPC marker\n", infile);
20416dce513Schristos 		return(-1);
20516dce513Schristos 	}
20616dce513Schristos 
20716dce513Schristos 	/* zero out the checksum and size fields, then compute checksum */
20816dce513Schristos 
20916dce513Schristos 	p = image + 0x18;
21016dce513Schristos 	old_crc = get_be_16(p);
21116dce513Schristos 	old_filesize = get_be_32(p+4);
21216dce513Schristos 
21316dce513Schristos 	memset(p, 0, 8);
21416dce513Schristos 
21516dce513Schristos 	hdr_len = get_be_16(buf+0x28) + get_be_16(buf+0x2a);
21616dce513Schristos 	img_len = get_be_32(buf+0x44);
21716dce513Schristos 
21816dce513Schristos 	crc = 0xffff;
21916dce513Schristos 	crc = crc16(crc, buf, hdr_len);
22016dce513Schristos 	crc = crc16(crc, buf + img_offset, img_len);
22116dce513Schristos 
22216dce513Schristos 	printf("%s: hdr_len=0x%x img_offset=0x%x img_len=0x%x crc=0x%04x fsz=0x%06x\n", infile, (int) hdr_len, (int) img_offset, (int) img_len, crc, filesize);
22316dce513Schristos 
22416dce513Schristos 	if(outfile) {
22516dce513Schristos 		/* patch in the crc and the total file size (???) */
22616dce513Schristos 
22716dce513Schristos 		put_be_16(p, crc);
22816dce513Schristos 		put_be_32(p+4, filesize);
22916dce513Schristos 
23016dce513Schristos 		if((fd = open(outfile, O_RDWR|O_CREAT|O_TRUNC, st.st_mode)) < 0) {
23116dce513Schristos 			perror(outfile);
23216dce513Schristos 			return(-1);
23316dce513Schristos 		}
23416dce513Schristos 
23516dce513Schristos 		if(write(fd, buf, filesize) != filesize) {
23616dce513Schristos 			perror(outfile);
23716dce513Schristos 			return(-1);
23816dce513Schristos 		}
23916dce513Schristos 		close(fd);
24016dce513Schristos 	} else {
24116dce513Schristos 		/* Check the crc and filesize fields in the file */
24216dce513Schristos 
24316dce513Schristos 		if((crc == old_crc) && (filesize == old_filesize)) {
24416dce513Schristos 			printf("%s: NCD crc and filesize seem ok.\n", infile);
24516dce513Schristos 		} else {
24616dce513Schristos 			printf("%s: NCD current crc=0x%04x fsz=0x%06x\n", infile, old_crc, old_filesize);
24716dce513Schristos 		}
24816dce513Schristos 	}
24916dce513Schristos 
25016dce513Schristos 	return(0);
25116dce513Schristos }
252