xref: /linux/arch/x86/boot/tools/build.c (revision 079f85e624189292d1c818b47764916bf8cf84a8)
119d8d79cSThomas Gleixner /*
219d8d79cSThomas Gleixner  *  Copyright (C) 1991, 1992  Linus Torvalds
319d8d79cSThomas Gleixner  *  Copyright (C) 1997 Martin Mares
419d8d79cSThomas Gleixner  *  Copyright (C) 2007 H. Peter Anvin
519d8d79cSThomas Gleixner  */
619d8d79cSThomas Gleixner 
719d8d79cSThomas Gleixner /*
819d8d79cSThomas Gleixner  * This file builds a disk-image from two different files:
919d8d79cSThomas Gleixner  *
1019d8d79cSThomas Gleixner  * - setup: 8086 machine code, sets up system parm
1119d8d79cSThomas Gleixner  * - system: 80386 code for actual system
1219d8d79cSThomas Gleixner  *
1319d8d79cSThomas Gleixner  * It does some checking that all files are of the correct type, and
1419d8d79cSThomas Gleixner  * just writes the result to stdout, removing headers and padding to
1519d8d79cSThomas Gleixner  * the right amount. It also writes some system data to stderr.
1619d8d79cSThomas Gleixner  */
1719d8d79cSThomas Gleixner 
1819d8d79cSThomas Gleixner /*
1919d8d79cSThomas Gleixner  * Changes by tytso to allow root device specification
2019d8d79cSThomas Gleixner  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
2119d8d79cSThomas Gleixner  * Cross compiling fixes by Gertjan van Wingerde, July 1996
2219d8d79cSThomas Gleixner  * Rewritten by Martin Mares, April 1997
2319d8d79cSThomas Gleixner  * Substantially overhauled by H. Peter Anvin, April 2007
2419d8d79cSThomas Gleixner  */
2519d8d79cSThomas Gleixner 
2619d8d79cSThomas Gleixner #include <stdio.h>
2719d8d79cSThomas Gleixner #include <string.h>
2819d8d79cSThomas Gleixner #include <stdlib.h>
2919d8d79cSThomas Gleixner #include <stdarg.h>
3019d8d79cSThomas Gleixner #include <sys/types.h>
3119d8d79cSThomas Gleixner #include <sys/stat.h>
3219d8d79cSThomas Gleixner #include <sys/sysmacros.h>
3319d8d79cSThomas Gleixner #include <unistd.h>
3419d8d79cSThomas Gleixner #include <fcntl.h>
3519d8d79cSThomas Gleixner #include <sys/mman.h>
3619d8d79cSThomas Gleixner #include <asm/boot.h>
3719d8d79cSThomas Gleixner 
3819d8d79cSThomas Gleixner typedef unsigned char  u8;
3919d8d79cSThomas Gleixner typedef unsigned short u16;
4019d8d79cSThomas Gleixner typedef unsigned long  u32;
4119d8d79cSThomas Gleixner 
4219d8d79cSThomas Gleixner #define DEFAULT_MAJOR_ROOT 0
4319d8d79cSThomas Gleixner #define DEFAULT_MINOR_ROOT 0
4419d8d79cSThomas Gleixner 
4519d8d79cSThomas Gleixner /* Minimal number of setup sectors */
4619d8d79cSThomas Gleixner #define SETUP_SECT_MIN 5
4719d8d79cSThomas Gleixner #define SETUP_SECT_MAX 64
4819d8d79cSThomas Gleixner 
4919d8d79cSThomas Gleixner /* This must be large enough to hold the entire setup */
5019d8d79cSThomas Gleixner u8 buf[SETUP_SECT_MAX*512];
5119d8d79cSThomas Gleixner int is_big_kernel;
5219d8d79cSThomas Gleixner 
537d6e737cSIan Campbell /*----------------------------------------------------------------------*/
547d6e737cSIan Campbell 
557d6e737cSIan Campbell static const u32 crctab32[] = {
567d6e737cSIan Campbell 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
577d6e737cSIan Campbell 	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
587d6e737cSIan Campbell 	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
597d6e737cSIan Campbell 	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
607d6e737cSIan Campbell 	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
617d6e737cSIan Campbell 	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
627d6e737cSIan Campbell 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
637d6e737cSIan Campbell 	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
647d6e737cSIan Campbell 	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
657d6e737cSIan Campbell 	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
667d6e737cSIan Campbell 	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
677d6e737cSIan Campbell 	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
687d6e737cSIan Campbell 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
697d6e737cSIan Campbell 	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
707d6e737cSIan Campbell 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
717d6e737cSIan Campbell 	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
727d6e737cSIan Campbell 	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
737d6e737cSIan Campbell 	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
747d6e737cSIan Campbell 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
757d6e737cSIan Campbell 	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
767d6e737cSIan Campbell 	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
777d6e737cSIan Campbell 	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
787d6e737cSIan Campbell 	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
797d6e737cSIan Campbell 	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
807d6e737cSIan Campbell 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
817d6e737cSIan Campbell 	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
827d6e737cSIan Campbell 	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
837d6e737cSIan Campbell 	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
847d6e737cSIan Campbell 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
857d6e737cSIan Campbell 	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
867d6e737cSIan Campbell 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
877d6e737cSIan Campbell 	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
887d6e737cSIan Campbell 	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
897d6e737cSIan Campbell 	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
907d6e737cSIan Campbell 	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
917d6e737cSIan Campbell 	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
927d6e737cSIan Campbell 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
937d6e737cSIan Campbell 	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
947d6e737cSIan Campbell 	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
957d6e737cSIan Campbell 	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
967d6e737cSIan Campbell 	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
977d6e737cSIan Campbell 	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
987d6e737cSIan Campbell 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
997d6e737cSIan Campbell 	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1007d6e737cSIan Campbell 	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1017d6e737cSIan Campbell 	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1027d6e737cSIan Campbell 	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1037d6e737cSIan Campbell 	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1047d6e737cSIan Campbell 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1057d6e737cSIan Campbell 	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1067d6e737cSIan Campbell 	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1077d6e737cSIan Campbell 	0x2d02ef8d
1087d6e737cSIan Campbell };
1097d6e737cSIan Campbell 
1107d6e737cSIan Campbell static u32 partial_crc32_one(u8 c, u32 crc)
1117d6e737cSIan Campbell {
1127d6e737cSIan Campbell 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1137d6e737cSIan Campbell }
1147d6e737cSIan Campbell 
1157d6e737cSIan Campbell static u32 partial_crc32(const u8 *s, int len, u32 crc)
1167d6e737cSIan Campbell {
1177d6e737cSIan Campbell 	while (len--)
1187d6e737cSIan Campbell 		crc = partial_crc32_one(*s++, crc);
1197d6e737cSIan Campbell 	return crc;
1207d6e737cSIan Campbell }
1217d6e737cSIan Campbell 
12219d8d79cSThomas Gleixner static void die(const char * str, ...)
12319d8d79cSThomas Gleixner {
12419d8d79cSThomas Gleixner 	va_list args;
12519d8d79cSThomas Gleixner 	va_start(args, str);
12619d8d79cSThomas Gleixner 	vfprintf(stderr, str, args);
12719d8d79cSThomas Gleixner 	fputc('\n', stderr);
12819d8d79cSThomas Gleixner 	exit(1);
12919d8d79cSThomas Gleixner }
13019d8d79cSThomas Gleixner 
13119d8d79cSThomas Gleixner static void usage(void)
13219d8d79cSThomas Gleixner {
133*079f85e6SMichal Marek 	die("Usage: build setup system [> image]");
13419d8d79cSThomas Gleixner }
13519d8d79cSThomas Gleixner 
13619d8d79cSThomas Gleixner int main(int argc, char ** argv)
13719d8d79cSThomas Gleixner {
13819d8d79cSThomas Gleixner 	unsigned int i, sz, setup_sectors;
13919d8d79cSThomas Gleixner 	int c;
14019d8d79cSThomas Gleixner 	u32 sys_size;
14119d8d79cSThomas Gleixner 	struct stat sb;
14219d8d79cSThomas Gleixner 	FILE *file;
14319d8d79cSThomas Gleixner 	int fd;
14419d8d79cSThomas Gleixner 	void *kernel;
1457d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
14619d8d79cSThomas Gleixner 
147*079f85e6SMichal Marek 	if (argc != 3)
14819d8d79cSThomas Gleixner 		usage();
14919d8d79cSThomas Gleixner 
15019d8d79cSThomas Gleixner 	/* Copy the setup code */
15119d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
15219d8d79cSThomas Gleixner 	if (!file)
15319d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
15419d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
15519d8d79cSThomas Gleixner 	if (ferror(file))
15619d8d79cSThomas Gleixner 		die("read-error on `setup'");
15719d8d79cSThomas Gleixner 	if (c < 1024)
15819d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
15919d8d79cSThomas Gleixner 	if (buf[510] != 0x55 || buf[511] != 0xaa)
16019d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
16119d8d79cSThomas Gleixner 	fclose(file);
16219d8d79cSThomas Gleixner 
16319d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
16419d8d79cSThomas Gleixner 	setup_sectors = (c + 511) / 512;
16519d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
16619d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
16719d8d79cSThomas Gleixner 	i = setup_sectors*512;
16819d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
16919d8d79cSThomas Gleixner 
17019d8d79cSThomas Gleixner 	/* Set the default root device */
171*079f85e6SMichal Marek 	buf[508] = DEFAULT_MINOR_ROOT;
172*079f85e6SMichal Marek 	buf[509] = DEFAULT_MAJOR_ROOT;
17319d8d79cSThomas Gleixner 
17419d8d79cSThomas Gleixner 	fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
17519d8d79cSThomas Gleixner 
17619d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
17719d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
17819d8d79cSThomas Gleixner 	if (fd < 0)
17919d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
18019d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
18119d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
18219d8d79cSThomas Gleixner 	sz = sb.st_size;
18319d8d79cSThomas Gleixner 	fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
18419d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
18519d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
18619d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
1877d6e737cSIan Campbell 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
1887d6e737cSIan Campbell 	sys_size = (sz + 15 + 4) / 16;
18919d8d79cSThomas Gleixner 
19019d8d79cSThomas Gleixner 	/* Patch the setup code with the appropriate size parameters */
19119d8d79cSThomas Gleixner 	buf[0x1f1] = setup_sectors-1;
19219d8d79cSThomas Gleixner 	buf[0x1f4] = sys_size;
19319d8d79cSThomas Gleixner 	buf[0x1f5] = sys_size >> 8;
19419d8d79cSThomas Gleixner 	buf[0x1f6] = sys_size >> 16;
19519d8d79cSThomas Gleixner 	buf[0x1f7] = sys_size >> 24;
19619d8d79cSThomas Gleixner 
1977d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
19819d8d79cSThomas Gleixner 	if (fwrite(buf, 1, i, stdout) != i)
19919d8d79cSThomas Gleixner 		die("Writing setup failed");
20019d8d79cSThomas Gleixner 
20119d8d79cSThomas Gleixner 	/* Copy the kernel code */
2027d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
20319d8d79cSThomas Gleixner 	if (fwrite(kernel, 1, sz, stdout) != sz)
20419d8d79cSThomas Gleixner 		die("Writing kernel failed");
2057d6e737cSIan Campbell 
2067d6e737cSIan Campbell 	/* Add padding leaving 4 bytes for the checksum */
2077d6e737cSIan Campbell 	while (sz++ < (sys_size*16) - 4) {
2087d6e737cSIan Campbell 		crc = partial_crc32_one('\0', crc);
2097d6e737cSIan Campbell 		if (fwrite("\0", 1, 1, stdout) != 1)
2107d6e737cSIan Campbell 			die("Writing padding failed");
2117d6e737cSIan Campbell 	}
2127d6e737cSIan Campbell 
2137d6e737cSIan Campbell 	/* Write the CRC */
2147d6e737cSIan Campbell 	fprintf(stderr, "CRC %lx\n", crc);
2157d6e737cSIan Campbell 	if (fwrite(&crc, 1, 4, stdout) != 4)
2167d6e737cSIan Campbell 		die("Writing CRC failed");
2177d6e737cSIan Campbell 
21819d8d79cSThomas Gleixner 	close(fd);
21919d8d79cSThomas Gleixner 
22019d8d79cSThomas Gleixner 	/* Everything is OK */
22119d8d79cSThomas Gleixner 	return 0;
22219d8d79cSThomas Gleixner }
223