xref: /openbmc/linux/arch/x86/boot/tools/build.c (revision 92f42c50)
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>
3792f42c50SMatt Fleming #include <tools/le_byteshift.h>
3819d8d79cSThomas Gleixner 
3919d8d79cSThomas Gleixner typedef unsigned char  u8;
4019d8d79cSThomas Gleixner typedef unsigned short u16;
4119d8d79cSThomas Gleixner typedef unsigned long  u32;
4219d8d79cSThomas Gleixner 
4319d8d79cSThomas Gleixner #define DEFAULT_MAJOR_ROOT 0
4419d8d79cSThomas Gleixner #define DEFAULT_MINOR_ROOT 0
4592f42c50SMatt Fleming #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
4619d8d79cSThomas Gleixner 
4719d8d79cSThomas Gleixner /* Minimal number of setup sectors */
4819d8d79cSThomas Gleixner #define SETUP_SECT_MIN 5
4919d8d79cSThomas Gleixner #define SETUP_SECT_MAX 64
5019d8d79cSThomas Gleixner 
5119d8d79cSThomas Gleixner /* This must be large enough to hold the entire setup */
5219d8d79cSThomas Gleixner u8 buf[SETUP_SECT_MAX*512];
5319d8d79cSThomas Gleixner int is_big_kernel;
5419d8d79cSThomas Gleixner 
557d6e737cSIan Campbell /*----------------------------------------------------------------------*/
567d6e737cSIan Campbell 
577d6e737cSIan Campbell static const u32 crctab32[] = {
587d6e737cSIan Campbell 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
597d6e737cSIan Campbell 	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
607d6e737cSIan Campbell 	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
617d6e737cSIan Campbell 	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
627d6e737cSIan Campbell 	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
637d6e737cSIan Campbell 	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
647d6e737cSIan Campbell 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
657d6e737cSIan Campbell 	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
667d6e737cSIan Campbell 	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
677d6e737cSIan Campbell 	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
687d6e737cSIan Campbell 	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
697d6e737cSIan Campbell 	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
707d6e737cSIan Campbell 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
717d6e737cSIan Campbell 	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
727d6e737cSIan Campbell 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
737d6e737cSIan Campbell 	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
747d6e737cSIan Campbell 	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
757d6e737cSIan Campbell 	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
767d6e737cSIan Campbell 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
777d6e737cSIan Campbell 	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
787d6e737cSIan Campbell 	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
797d6e737cSIan Campbell 	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
807d6e737cSIan Campbell 	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
817d6e737cSIan Campbell 	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
827d6e737cSIan Campbell 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
837d6e737cSIan Campbell 	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
847d6e737cSIan Campbell 	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
857d6e737cSIan Campbell 	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
867d6e737cSIan Campbell 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
877d6e737cSIan Campbell 	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
887d6e737cSIan Campbell 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
897d6e737cSIan Campbell 	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
907d6e737cSIan Campbell 	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
917d6e737cSIan Campbell 	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
927d6e737cSIan Campbell 	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
937d6e737cSIan Campbell 	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
947d6e737cSIan Campbell 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
957d6e737cSIan Campbell 	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
967d6e737cSIan Campbell 	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
977d6e737cSIan Campbell 	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
987d6e737cSIan Campbell 	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
997d6e737cSIan Campbell 	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1007d6e737cSIan Campbell 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1017d6e737cSIan Campbell 	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1027d6e737cSIan Campbell 	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1037d6e737cSIan Campbell 	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1047d6e737cSIan Campbell 	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1057d6e737cSIan Campbell 	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1067d6e737cSIan Campbell 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1077d6e737cSIan Campbell 	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1087d6e737cSIan Campbell 	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1097d6e737cSIan Campbell 	0x2d02ef8d
1107d6e737cSIan Campbell };
1117d6e737cSIan Campbell 
1127d6e737cSIan Campbell static u32 partial_crc32_one(u8 c, u32 crc)
1137d6e737cSIan Campbell {
1147d6e737cSIan Campbell 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1157d6e737cSIan Campbell }
1167d6e737cSIan Campbell 
1177d6e737cSIan Campbell static u32 partial_crc32(const u8 *s, int len, u32 crc)
1187d6e737cSIan Campbell {
1197d6e737cSIan Campbell 	while (len--)
1207d6e737cSIan Campbell 		crc = partial_crc32_one(*s++, crc);
1217d6e737cSIan Campbell 	return crc;
1227d6e737cSIan Campbell }
1237d6e737cSIan Campbell 
12419d8d79cSThomas Gleixner static void die(const char * str, ...)
12519d8d79cSThomas Gleixner {
12619d8d79cSThomas Gleixner 	va_list args;
12719d8d79cSThomas Gleixner 	va_start(args, str);
12819d8d79cSThomas Gleixner 	vfprintf(stderr, str, args);
12919d8d79cSThomas Gleixner 	fputc('\n', stderr);
13019d8d79cSThomas Gleixner 	exit(1);
13119d8d79cSThomas Gleixner }
13219d8d79cSThomas Gleixner 
13319d8d79cSThomas Gleixner static void usage(void)
13419d8d79cSThomas Gleixner {
135079f85e6SMichal Marek 	die("Usage: build setup system [> image]");
13619d8d79cSThomas Gleixner }
13719d8d79cSThomas Gleixner 
13819d8d79cSThomas Gleixner int main(int argc, char ** argv)
13919d8d79cSThomas Gleixner {
140291f3632SMatt Fleming #ifdef CONFIG_EFI_STUB
141291f3632SMatt Fleming 	unsigned int file_sz, pe_header;
142291f3632SMatt Fleming #endif
14319d8d79cSThomas Gleixner 	unsigned int i, sz, setup_sectors;
14419d8d79cSThomas Gleixner 	int c;
14519d8d79cSThomas Gleixner 	u32 sys_size;
14619d8d79cSThomas Gleixner 	struct stat sb;
14719d8d79cSThomas Gleixner 	FILE *file;
14819d8d79cSThomas Gleixner 	int fd;
14919d8d79cSThomas Gleixner 	void *kernel;
1507d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
15119d8d79cSThomas Gleixner 
152079f85e6SMichal Marek 	if (argc != 3)
15319d8d79cSThomas Gleixner 		usage();
15419d8d79cSThomas Gleixner 
15519d8d79cSThomas Gleixner 	/* Copy the setup code */
15619d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
15719d8d79cSThomas Gleixner 	if (!file)
15819d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
15919d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
16019d8d79cSThomas Gleixner 	if (ferror(file))
16119d8d79cSThomas Gleixner 		die("read-error on `setup'");
16219d8d79cSThomas Gleixner 	if (c < 1024)
16319d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
16492f42c50SMatt Fleming 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
16519d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
16619d8d79cSThomas Gleixner 	fclose(file);
16719d8d79cSThomas Gleixner 
16819d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
16919d8d79cSThomas Gleixner 	setup_sectors = (c + 511) / 512;
17019d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
17119d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
17219d8d79cSThomas Gleixner 	i = setup_sectors*512;
17319d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
17419d8d79cSThomas Gleixner 
17519d8d79cSThomas Gleixner 	/* Set the default root device */
17692f42c50SMatt Fleming 	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
17719d8d79cSThomas Gleixner 
17819d8d79cSThomas Gleixner 	fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
17919d8d79cSThomas Gleixner 
18019d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
18119d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
18219d8d79cSThomas Gleixner 	if (fd < 0)
18319d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
18419d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
18519d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
18619d8d79cSThomas Gleixner 	sz = sb.st_size;
18719d8d79cSThomas Gleixner 	fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
18819d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
18919d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
19019d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
1917d6e737cSIan Campbell 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
1927d6e737cSIan Campbell 	sys_size = (sz + 15 + 4) / 16;
19319d8d79cSThomas Gleixner 
19419d8d79cSThomas Gleixner 	/* Patch the setup code with the appropriate size parameters */
19519d8d79cSThomas Gleixner 	buf[0x1f1] = setup_sectors-1;
19692f42c50SMatt Fleming 	put_unaligned_le32(sys_size, &buf[0x1f4]);
19719d8d79cSThomas Gleixner 
198291f3632SMatt Fleming #ifdef CONFIG_EFI_STUB
199291f3632SMatt Fleming 	file_sz = sz + i + ((sys_size * 16) - sz);
200291f3632SMatt Fleming 
20192f42c50SMatt Fleming 	pe_header = get_unaligned_le32(&buf[0x3c]);
202291f3632SMatt Fleming 
203291f3632SMatt Fleming 	/* Size of code */
20492f42c50SMatt Fleming 	put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
205291f3632SMatt Fleming 
206291f3632SMatt Fleming 	/* Size of image */
20792f42c50SMatt Fleming 	put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
208291f3632SMatt Fleming 
209291f3632SMatt Fleming #ifdef CONFIG_X86_32
210291f3632SMatt Fleming 	/* Address of entry point */
21192f42c50SMatt Fleming 	put_unaligned_le32(i, &buf[pe_header + 0x28]);
212291f3632SMatt Fleming 
213291f3632SMatt Fleming 	/* .text size */
21492f42c50SMatt Fleming 	put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
215291f3632SMatt Fleming 
216291f3632SMatt Fleming 	/* .text size of initialised data */
21792f42c50SMatt Fleming 	put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]);
218291f3632SMatt Fleming #else
219291f3632SMatt Fleming 	/*
220291f3632SMatt Fleming 	 * Address of entry point. startup_32 is at the beginning and
221291f3632SMatt Fleming 	 * the 64-bit entry point (startup_64) is always 512 bytes
222291f3632SMatt Fleming 	 * after.
223291f3632SMatt Fleming 	 */
22492f42c50SMatt Fleming 	put_unaligned_le32(i + 512, &buf[pe_header + 0x28]);
225291f3632SMatt Fleming 
226291f3632SMatt Fleming 	/* .text size */
22792f42c50SMatt Fleming 	put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);
228291f3632SMatt Fleming 
229291f3632SMatt Fleming 	/* .text size of initialised data */
23092f42c50SMatt Fleming 	put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]);
23192f42c50SMatt Fleming 
232291f3632SMatt Fleming #endif /* CONFIG_X86_32 */
233291f3632SMatt Fleming #endif /* CONFIG_EFI_STUB */
234291f3632SMatt Fleming 
2357d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
23619d8d79cSThomas Gleixner 	if (fwrite(buf, 1, i, stdout) != i)
23719d8d79cSThomas Gleixner 		die("Writing setup failed");
23819d8d79cSThomas Gleixner 
23919d8d79cSThomas Gleixner 	/* Copy the kernel code */
2407d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
24119d8d79cSThomas Gleixner 	if (fwrite(kernel, 1, sz, stdout) != sz)
24219d8d79cSThomas Gleixner 		die("Writing kernel failed");
2437d6e737cSIan Campbell 
2447d6e737cSIan Campbell 	/* Add padding leaving 4 bytes for the checksum */
2457d6e737cSIan Campbell 	while (sz++ < (sys_size*16) - 4) {
2467d6e737cSIan Campbell 		crc = partial_crc32_one('\0', crc);
2477d6e737cSIan Campbell 		if (fwrite("\0", 1, 1, stdout) != 1)
2487d6e737cSIan Campbell 			die("Writing padding failed");
2497d6e737cSIan Campbell 	}
2507d6e737cSIan Campbell 
2517d6e737cSIan Campbell 	/* Write the CRC */
2527d6e737cSIan Campbell 	fprintf(stderr, "CRC %lx\n", crc);
2537d6e737cSIan Campbell 	if (fwrite(&crc, 1, 4, stdout) != 4)
2547d6e737cSIan Campbell 		die("Writing CRC failed");
2557d6e737cSIan Campbell 
25619d8d79cSThomas Gleixner 	close(fd);
25719d8d79cSThomas Gleixner 
25819d8d79cSThomas Gleixner 	/* Everything is OK */
25919d8d79cSThomas Gleixner 	return 0;
26019d8d79cSThomas Gleixner }
261