xref: /openbmc/linux/arch/x86/boot/tools/build.c (revision 686b58ce)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
219d8d79cSThomas Gleixner /*
319d8d79cSThomas Gleixner  *  Copyright (C) 1991, 1992  Linus Torvalds
419d8d79cSThomas Gleixner  *  Copyright (C) 1997 Martin Mares
519d8d79cSThomas Gleixner  *  Copyright (C) 2007 H. Peter Anvin
619d8d79cSThomas Gleixner  */
719d8d79cSThomas Gleixner 
819d8d79cSThomas Gleixner /*
9809373e2SKees Cook  * This file builds a disk-image from three different files:
1019d8d79cSThomas Gleixner  *
1119d8d79cSThomas Gleixner  * - setup: 8086 machine code, sets up system parm
1219d8d79cSThomas Gleixner  * - system: 80386 code for actual system
13809373e2SKees Cook  * - zoffset.h: header with ZO_* defines
1419d8d79cSThomas Gleixner  *
15809373e2SKees Cook  * It does some checking that all files are of the correct type, and writes
16809373e2SKees Cook  * the result to the specified destination, removing headers and padding to
17809373e2SKees Cook  * the right amount. It also writes some system data to stdout.
1819d8d79cSThomas Gleixner  */
1919d8d79cSThomas Gleixner 
2019d8d79cSThomas Gleixner /*
2119d8d79cSThomas Gleixner  * Changes by tytso to allow root device specification
2219d8d79cSThomas Gleixner  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
2319d8d79cSThomas Gleixner  * Cross compiling fixes by Gertjan van Wingerde, July 1996
2419d8d79cSThomas Gleixner  * Rewritten by Martin Mares, April 1997
2519d8d79cSThomas Gleixner  * Substantially overhauled by H. Peter Anvin, April 2007
2619d8d79cSThomas Gleixner  */
2719d8d79cSThomas Gleixner 
2819d8d79cSThomas Gleixner #include <stdio.h>
2919d8d79cSThomas Gleixner #include <string.h>
3019d8d79cSThomas Gleixner #include <stdlib.h>
3119d8d79cSThomas Gleixner #include <stdarg.h>
3219d8d79cSThomas Gleixner #include <sys/types.h>
3319d8d79cSThomas Gleixner #include <sys/stat.h>
3419d8d79cSThomas Gleixner #include <unistd.h>
3519d8d79cSThomas Gleixner #include <fcntl.h>
3619d8d79cSThomas Gleixner #include <sys/mman.h>
3792f42c50SMatt Fleming #include <tools/le_byteshift.h>
3819d8d79cSThomas Gleixner 
3919d8d79cSThomas Gleixner typedef unsigned char  u8;
4019d8d79cSThomas Gleixner typedef unsigned short u16;
41a51f4047SH. Peter Anvin typedef unsigned int   u32;
4219d8d79cSThomas Gleixner 
4319d8d79cSThomas Gleixner /* Minimal number of setup sectors */
4419d8d79cSThomas Gleixner #define SETUP_SECT_MIN 5
4519d8d79cSThomas Gleixner #define SETUP_SECT_MAX 64
4619d8d79cSThomas Gleixner 
4719d8d79cSThomas Gleixner /* This must be large enough to hold the entire setup */
4819d8d79cSThomas Gleixner u8 buf[SETUP_SECT_MAX*512];
4919d8d79cSThomas Gleixner 
500cf3d613SArd Biesheuvel static unsigned long _edata;
5199f857dbSDavid Woodhouse 
527d6e737cSIan Campbell /*----------------------------------------------------------------------*/
537d6e737cSIan Campbell 
547d6e737cSIan Campbell static const u32 crctab32[] = {
557d6e737cSIan Campbell 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
567d6e737cSIan Campbell 	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
577d6e737cSIan Campbell 	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
587d6e737cSIan Campbell 	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
597d6e737cSIan Campbell 	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
607d6e737cSIan Campbell 	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
617d6e737cSIan Campbell 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
627d6e737cSIan Campbell 	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
637d6e737cSIan Campbell 	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
647d6e737cSIan Campbell 	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
657d6e737cSIan Campbell 	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
667d6e737cSIan Campbell 	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
677d6e737cSIan Campbell 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
687d6e737cSIan Campbell 	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
697d6e737cSIan Campbell 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
707d6e737cSIan Campbell 	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
717d6e737cSIan Campbell 	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
727d6e737cSIan Campbell 	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
737d6e737cSIan Campbell 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
747d6e737cSIan Campbell 	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
757d6e737cSIan Campbell 	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
767d6e737cSIan Campbell 	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
777d6e737cSIan Campbell 	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
787d6e737cSIan Campbell 	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
797d6e737cSIan Campbell 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
807d6e737cSIan Campbell 	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
817d6e737cSIan Campbell 	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
827d6e737cSIan Campbell 	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
837d6e737cSIan Campbell 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
847d6e737cSIan Campbell 	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
857d6e737cSIan Campbell 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
867d6e737cSIan Campbell 	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
877d6e737cSIan Campbell 	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
887d6e737cSIan Campbell 	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
897d6e737cSIan Campbell 	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
907d6e737cSIan Campbell 	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
917d6e737cSIan Campbell 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
927d6e737cSIan Campbell 	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
937d6e737cSIan Campbell 	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
947d6e737cSIan Campbell 	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
957d6e737cSIan Campbell 	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
967d6e737cSIan Campbell 	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
977d6e737cSIan Campbell 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
987d6e737cSIan Campbell 	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
997d6e737cSIan Campbell 	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1007d6e737cSIan Campbell 	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1017d6e737cSIan Campbell 	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1027d6e737cSIan Campbell 	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1037d6e737cSIan Campbell 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1047d6e737cSIan Campbell 	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1057d6e737cSIan Campbell 	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1067d6e737cSIan Campbell 	0x2d02ef8d
1077d6e737cSIan Campbell };
1087d6e737cSIan Campbell 
partial_crc32_one(u8 c,u32 crc)1097d6e737cSIan Campbell static u32 partial_crc32_one(u8 c, u32 crc)
1107d6e737cSIan Campbell {
1117d6e737cSIan Campbell 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1127d6e737cSIan Campbell }
1137d6e737cSIan Campbell 
partial_crc32(const u8 * s,int len,u32 crc)1147d6e737cSIan Campbell static u32 partial_crc32(const u8 *s, int len, u32 crc)
1157d6e737cSIan Campbell {
1167d6e737cSIan Campbell 	while (len--)
1177d6e737cSIan Campbell 		crc = partial_crc32_one(*s++, crc);
1187d6e737cSIan Campbell 	return crc;
1197d6e737cSIan Campbell }
1207d6e737cSIan Campbell 
die(const char * str,...)12119d8d79cSThomas Gleixner static void die(const char * str, ...)
12219d8d79cSThomas Gleixner {
12319d8d79cSThomas Gleixner 	va_list args;
12419d8d79cSThomas Gleixner 	va_start(args, str);
12519d8d79cSThomas Gleixner 	vfprintf(stderr, str, args);
12669be4efeSMattias Jacobsson 	va_end(args);
12719d8d79cSThomas Gleixner 	fputc('\n', stderr);
12819d8d79cSThomas Gleixner 	exit(1);
12919d8d79cSThomas Gleixner }
13019d8d79cSThomas Gleixner 
usage(void)13119d8d79cSThomas Gleixner static void usage(void)
13219d8d79cSThomas Gleixner {
133809373e2SKees Cook 	die("Usage: build setup system zoffset.h image");
13419d8d79cSThomas Gleixner }
13519d8d79cSThomas Gleixner 
13699f857dbSDavid Woodhouse /*
13799f857dbSDavid Woodhouse  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
13899f857dbSDavid Woodhouse  * but that would mean tools/build would have to be rebuilt every time. It's
13999f857dbSDavid Woodhouse  * not as if parsing it is hard...
14099f857dbSDavid Woodhouse  */
14199f857dbSDavid Woodhouse #define PARSE_ZOFS(p, sym) do { \
14299f857dbSDavid Woodhouse 	if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))	\
14399f857dbSDavid Woodhouse 		sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);		\
14499f857dbSDavid Woodhouse } while (0)
14599f857dbSDavid Woodhouse 
parse_zoffset(char * fname)14699f857dbSDavid Woodhouse static void parse_zoffset(char *fname)
14799f857dbSDavid Woodhouse {
14899f857dbSDavid Woodhouse 	FILE *file;
14999f857dbSDavid Woodhouse 	char *p;
15099f857dbSDavid Woodhouse 	int c;
15199f857dbSDavid Woodhouse 
15299f857dbSDavid Woodhouse 	file = fopen(fname, "r");
15399f857dbSDavid Woodhouse 	if (!file)
15499f857dbSDavid Woodhouse 		die("Unable to open `%s': %m", fname);
15599f857dbSDavid Woodhouse 	c = fread(buf, 1, sizeof(buf) - 1, file);
15699f857dbSDavid Woodhouse 	if (ferror(file))
15799f857dbSDavid Woodhouse 		die("read-error on `zoffset.h'");
158062f4871SJiri Slaby 	fclose(file);
15999f857dbSDavid Woodhouse 	buf[c] = 0;
16099f857dbSDavid Woodhouse 
16199f857dbSDavid Woodhouse 	p = (char *)buf;
16299f857dbSDavid Woodhouse 
16399f857dbSDavid Woodhouse 	while (p && *p) {
1640cf3d613SArd Biesheuvel 		PARSE_ZOFS(p, _edata);
16599f857dbSDavid Woodhouse 
16699f857dbSDavid Woodhouse 		p = strchr(p, '\n');
16799f857dbSDavid Woodhouse 		while (p && (*p == '\r' || *p == '\n'))
16899f857dbSDavid Woodhouse 			p++;
16999f857dbSDavid Woodhouse 	}
17099f857dbSDavid Woodhouse }
17199f857dbSDavid Woodhouse 
main(int argc,char ** argv)17219d8d79cSThomas Gleixner int main(int argc, char ** argv)
17319d8d79cSThomas Gleixner {
1744bac079dSArd Biesheuvel 	unsigned int i, sz, setup_sectors;
17519d8d79cSThomas Gleixner 	int c;
17619d8d79cSThomas Gleixner 	struct stat sb;
177809373e2SKees Cook 	FILE *file, *dest;
17819d8d79cSThomas Gleixner 	int fd;
17919d8d79cSThomas Gleixner 	void *kernel;
1807d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
18119d8d79cSThomas Gleixner 
182809373e2SKees Cook 	if (argc != 5)
18319d8d79cSThomas Gleixner 		usage();
184809373e2SKees Cook 	parse_zoffset(argv[3]);
185809373e2SKees Cook 
186809373e2SKees Cook 	dest = fopen(argv[4], "w");
187809373e2SKees Cook 	if (!dest)
188809373e2SKees Cook 		die("Unable to write `%s': %m", argv[4]);
18919d8d79cSThomas Gleixner 
19019d8d79cSThomas Gleixner 	/* Copy the setup code */
19119d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
19219d8d79cSThomas Gleixner 	if (!file)
19319d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
19419d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
19519d8d79cSThomas Gleixner 	if (ferror(file))
19619d8d79cSThomas Gleixner 		die("read-error on `setup'");
19719d8d79cSThomas Gleixner 	if (c < 1024)
19819d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
19992f42c50SMatt Fleming 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
20019d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
20119d8d79cSThomas Gleixner 	fclose(file);
20219d8d79cSThomas Gleixner 
20319d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
204*686b58ceSArd Biesheuvel 	setup_sectors = (c + 4095) / 4096;
205*686b58ceSArd Biesheuvel 	setup_sectors *= 8;
20619d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
20719d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
20819d8d79cSThomas Gleixner 	i = setup_sectors*512;
20919d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
21019d8d79cSThomas Gleixner 
21119d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
21219d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
21319d8d79cSThomas Gleixner 	if (fd < 0)
21419d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
21519d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
21619d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
2170cf3d613SArd Biesheuvel 	if (_edata != sb.st_size)
2180cf3d613SArd Biesheuvel 		die("Unexpected file size `%s': %u != %u", argv[2], _edata,
2190cf3d613SArd Biesheuvel 		    sb.st_size);
2200cf3d613SArd Biesheuvel 	sz = _edata - 4;
22119d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
22219d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
22319d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
2242c33c27fSDaniel Kiper 
2257d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
226809373e2SKees Cook 	if (fwrite(buf, 1, i, dest) != i)
22719d8d79cSThomas Gleixner 		die("Writing setup failed");
22819d8d79cSThomas Gleixner 
22919d8d79cSThomas Gleixner 	/* Copy the kernel code */
2307d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
231809373e2SKees Cook 	if (fwrite(kernel, 1, sz, dest) != sz)
23219d8d79cSThomas Gleixner 		die("Writing kernel failed");
2337d6e737cSIan Campbell 
2347d6e737cSIan Campbell 	/* Write the CRC */
235a51f4047SH. Peter Anvin 	put_unaligned_le32(crc, buf);
236809373e2SKees Cook 	if (fwrite(buf, 1, 4, dest) != 4)
2377d6e737cSIan Campbell 		die("Writing CRC failed");
2387d6e737cSIan Campbell 
239809373e2SKees Cook 	/* Catch any delayed write failures */
240809373e2SKees Cook 	if (fclose(dest))
241809373e2SKees Cook 		die("Writing image failed");
242809373e2SKees Cook 
24319d8d79cSThomas Gleixner 	close(fd);
24419d8d79cSThomas Gleixner 
24519d8d79cSThomas Gleixner 	/* Everything is OK */
24619d8d79cSThomas Gleixner 	return 0;
24719d8d79cSThomas Gleixner }
248