xref: /linux/arch/x86/boot/tools/build.c (revision 291f36325f9f252bd76ef5f603995f37e453fc60)
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 {
133079f85e6SMichal Marek 	die("Usage: build setup system [> image]");
13419d8d79cSThomas Gleixner }
13519d8d79cSThomas Gleixner 
13619d8d79cSThomas Gleixner int main(int argc, char ** argv)
13719d8d79cSThomas Gleixner {
138*291f3632SMatt Fleming #ifdef CONFIG_EFI_STUB
139*291f3632SMatt Fleming 	unsigned int file_sz, pe_header;
140*291f3632SMatt Fleming #endif
14119d8d79cSThomas Gleixner 	unsigned int i, sz, setup_sectors;
14219d8d79cSThomas Gleixner 	int c;
14319d8d79cSThomas Gleixner 	u32 sys_size;
14419d8d79cSThomas Gleixner 	struct stat sb;
14519d8d79cSThomas Gleixner 	FILE *file;
14619d8d79cSThomas Gleixner 	int fd;
14719d8d79cSThomas Gleixner 	void *kernel;
1487d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
14919d8d79cSThomas Gleixner 
150079f85e6SMichal Marek 	if (argc != 3)
15119d8d79cSThomas Gleixner 		usage();
15219d8d79cSThomas Gleixner 
15319d8d79cSThomas Gleixner 	/* Copy the setup code */
15419d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
15519d8d79cSThomas Gleixner 	if (!file)
15619d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
15719d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
15819d8d79cSThomas Gleixner 	if (ferror(file))
15919d8d79cSThomas Gleixner 		die("read-error on `setup'");
16019d8d79cSThomas Gleixner 	if (c < 1024)
16119d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
16219d8d79cSThomas Gleixner 	if (buf[510] != 0x55 || buf[511] != 0xaa)
16319d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
16419d8d79cSThomas Gleixner 	fclose(file);
16519d8d79cSThomas Gleixner 
16619d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
16719d8d79cSThomas Gleixner 	setup_sectors = (c + 511) / 512;
16819d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
16919d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
17019d8d79cSThomas Gleixner 	i = setup_sectors*512;
17119d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
17219d8d79cSThomas Gleixner 
17319d8d79cSThomas Gleixner 	/* Set the default root device */
174079f85e6SMichal Marek 	buf[508] = DEFAULT_MINOR_ROOT;
175079f85e6SMichal Marek 	buf[509] = DEFAULT_MAJOR_ROOT;
17619d8d79cSThomas Gleixner 
17719d8d79cSThomas Gleixner 	fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
17819d8d79cSThomas Gleixner 
17919d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
18019d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
18119d8d79cSThomas Gleixner 	if (fd < 0)
18219d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
18319d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
18419d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
18519d8d79cSThomas Gleixner 	sz = sb.st_size;
18619d8d79cSThomas Gleixner 	fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
18719d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
18819d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
18919d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
1907d6e737cSIan Campbell 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
1917d6e737cSIan Campbell 	sys_size = (sz + 15 + 4) / 16;
19219d8d79cSThomas Gleixner 
19319d8d79cSThomas Gleixner 	/* Patch the setup code with the appropriate size parameters */
19419d8d79cSThomas Gleixner 	buf[0x1f1] = setup_sectors-1;
19519d8d79cSThomas Gleixner 	buf[0x1f4] = sys_size;
19619d8d79cSThomas Gleixner 	buf[0x1f5] = sys_size >> 8;
19719d8d79cSThomas Gleixner 	buf[0x1f6] = sys_size >> 16;
19819d8d79cSThomas Gleixner 	buf[0x1f7] = sys_size >> 24;
19919d8d79cSThomas Gleixner 
200*291f3632SMatt Fleming #ifdef CONFIG_EFI_STUB
201*291f3632SMatt Fleming 	file_sz = sz + i + ((sys_size * 16) - sz);
202*291f3632SMatt Fleming 
203*291f3632SMatt Fleming 	pe_header = *(unsigned int *)&buf[0x3c];
204*291f3632SMatt Fleming 
205*291f3632SMatt Fleming 	/* Size of code */
206*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0x1c] = file_sz;
207*291f3632SMatt Fleming 
208*291f3632SMatt Fleming 	/* Size of image */
209*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0x50] = file_sz;
210*291f3632SMatt Fleming 
211*291f3632SMatt Fleming #ifdef CONFIG_X86_32
212*291f3632SMatt Fleming 	/* Address of entry point */
213*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0x28] = i;
214*291f3632SMatt Fleming 
215*291f3632SMatt Fleming 	/* .text size */
216*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0xb0] = file_sz;
217*291f3632SMatt Fleming 
218*291f3632SMatt Fleming 	/* .text size of initialised data */
219*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0xb8] = file_sz;
220*291f3632SMatt Fleming #else
221*291f3632SMatt Fleming 	/*
222*291f3632SMatt Fleming 	 * Address of entry point. startup_32 is at the beginning and
223*291f3632SMatt Fleming 	 * the 64-bit entry point (startup_64) is always 512 bytes
224*291f3632SMatt Fleming 	 * after.
225*291f3632SMatt Fleming 	 */
226*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0x28] = i + 512;
227*291f3632SMatt Fleming 
228*291f3632SMatt Fleming 	/* .text size */
229*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0xc0] = file_sz;
230*291f3632SMatt Fleming 
231*291f3632SMatt Fleming 	/* .text size of initialised data */
232*291f3632SMatt Fleming 	*(unsigned int *)&buf[pe_header + 0xc8] = file_sz;
233*291f3632SMatt Fleming #endif /* CONFIG_X86_32 */
234*291f3632SMatt Fleming #endif /* CONFIG_EFI_STUB */
235*291f3632SMatt Fleming 
2367d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
23719d8d79cSThomas Gleixner 	if (fwrite(buf, 1, i, stdout) != i)
23819d8d79cSThomas Gleixner 		die("Writing setup failed");
23919d8d79cSThomas Gleixner 
24019d8d79cSThomas Gleixner 	/* Copy the kernel code */
2417d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
24219d8d79cSThomas Gleixner 	if (fwrite(kernel, 1, sz, stdout) != sz)
24319d8d79cSThomas Gleixner 		die("Writing kernel failed");
2447d6e737cSIan Campbell 
2457d6e737cSIan Campbell 	/* Add padding leaving 4 bytes for the checksum */
2467d6e737cSIan Campbell 	while (sz++ < (sys_size*16) - 4) {
2477d6e737cSIan Campbell 		crc = partial_crc32_one('\0', crc);
2487d6e737cSIan Campbell 		if (fwrite("\0", 1, 1, stdout) != 1)
2497d6e737cSIan Campbell 			die("Writing padding failed");
2507d6e737cSIan Campbell 	}
2517d6e737cSIan Campbell 
2527d6e737cSIan Campbell 	/* Write the CRC */
2537d6e737cSIan Campbell 	fprintf(stderr, "CRC %lx\n", crc);
2547d6e737cSIan Campbell 	if (fwrite(&crc, 1, 4, stdout) != 4)
2557d6e737cSIan Campbell 		die("Writing CRC failed");
2567d6e737cSIan Campbell 
25719d8d79cSThomas Gleixner 	close(fd);
25819d8d79cSThomas Gleixner 
25919d8d79cSThomas Gleixner 	/* Everything is OK */
26019d8d79cSThomas Gleixner 	return 0;
26119d8d79cSThomas Gleixner }
262