xref: /linux/arch/x86/boot/tools/build.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Copyright (C) 1991, 1992  Linus Torvalds
4  *  Copyright (C) 1997 Martin Mares
5  *  Copyright (C) 2007 H. Peter Anvin
6  */
7 
8 /*
9  * This file builds a disk-image from three different files:
10  *
11  * - setup: 8086 machine code, sets up system parm
12  * - system: 80386 code for actual system
13  * - zoffset.h: header with ZO_* defines
14  *
15  * It does some checking that all files are of the correct type, and writes
16  * the result to the specified destination, removing headers and padding to
17  * the right amount. It also writes some system data to stdout.
18  */
19 
20 /*
21  * Changes by tytso to allow root device specification
22  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23  * Cross compiling fixes by Gertjan van Wingerde, July 1996
24  * Rewritten by Martin Mares, April 1997
25  * Substantially overhauled by H. Peter Anvin, April 2007
26  */
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/mman.h>
37 #include <tools/le_byteshift.h>
38 
39 typedef unsigned char  u8;
40 typedef unsigned short u16;
41 typedef unsigned int   u32;
42 
43 /* Minimal number of setup sectors */
44 #define SETUP_SECT_MIN 5
45 #define SETUP_SECT_MAX 64
46 
47 /* This must be large enough to hold the entire setup */
48 u8 buf[SETUP_SECT_MAX*512];
49 
50 static unsigned long _edata;
51 
52 /*----------------------------------------------------------------------*/
53 
54 static const u32 crctab32[] = {
55 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
56 	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
57 	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
58 	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
59 	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
60 	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
61 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
62 	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
63 	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
64 	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
65 	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
66 	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
67 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
68 	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
69 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
70 	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
71 	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
72 	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
73 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
74 	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
75 	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
76 	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
77 	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
78 	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
79 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
80 	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
81 	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
82 	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
83 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
84 	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
85 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
86 	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
87 	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
88 	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
89 	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
90 	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
91 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
92 	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
93 	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
94 	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
95 	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
96 	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
97 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
98 	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
99 	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
100 	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
101 	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
102 	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
103 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
104 	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
105 	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
106 	0x2d02ef8d
107 };
108 
partial_crc32_one(u8 c,u32 crc)109 static u32 partial_crc32_one(u8 c, u32 crc)
110 {
111 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
112 }
113 
partial_crc32(const u8 * s,int len,u32 crc)114 static u32 partial_crc32(const u8 *s, int len, u32 crc)
115 {
116 	while (len--)
117 		crc = partial_crc32_one(*s++, crc);
118 	return crc;
119 }
120 
die(const char * str,...)121 static void die(const char * str, ...)
122 {
123 	va_list args;
124 	va_start(args, str);
125 	vfprintf(stderr, str, args);
126 	va_end(args);
127 	fputc('\n', stderr);
128 	exit(1);
129 }
130 
usage(void)131 static void usage(void)
132 {
133 	die("Usage: build setup system zoffset.h image");
134 }
135 
136 /*
137  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
138  * but that would mean tools/build would have to be rebuilt every time. It's
139  * not as if parsing it is hard...
140  */
141 #define PARSE_ZOFS(p, sym) do { \
142 	if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))	\
143 		sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);		\
144 } while (0)
145 
parse_zoffset(char * fname)146 static void parse_zoffset(char *fname)
147 {
148 	FILE *file;
149 	char *p;
150 	int c;
151 
152 	file = fopen(fname, "r");
153 	if (!file)
154 		die("Unable to open `%s': %m", fname);
155 	c = fread(buf, 1, sizeof(buf) - 1, file);
156 	if (ferror(file))
157 		die("read-error on `zoffset.h'");
158 	fclose(file);
159 	buf[c] = 0;
160 
161 	p = (char *)buf;
162 
163 	while (p && *p) {
164 		PARSE_ZOFS(p, _edata);
165 
166 		p = strchr(p, '\n');
167 		while (p && (*p == '\r' || *p == '\n'))
168 			p++;
169 	}
170 }
171 
main(int argc,char ** argv)172 int main(int argc, char ** argv)
173 {
174 	unsigned int i, sz, setup_sectors;
175 	int c;
176 	struct stat sb;
177 	FILE *file, *dest;
178 	int fd;
179 	void *kernel;
180 	u32 crc = 0xffffffffUL;
181 
182 	if (argc != 5)
183 		usage();
184 	parse_zoffset(argv[3]);
185 
186 	dest = fopen(argv[4], "w");
187 	if (!dest)
188 		die("Unable to write `%s': %m", argv[4]);
189 
190 	/* Copy the setup code */
191 	file = fopen(argv[1], "r");
192 	if (!file)
193 		die("Unable to open `%s': %m", argv[1]);
194 	c = fread(buf, 1, sizeof(buf), file);
195 	if (ferror(file))
196 		die("read-error on `setup'");
197 	if (c < 1024)
198 		die("The setup must be at least 1024 bytes");
199 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
200 		die("Boot block hasn't got boot flag (0xAA55)");
201 	fclose(file);
202 
203 	/* Pad unused space with zeros */
204 	setup_sectors = (c + 4095) / 4096;
205 	setup_sectors *= 8;
206 	if (setup_sectors < SETUP_SECT_MIN)
207 		setup_sectors = SETUP_SECT_MIN;
208 	i = setup_sectors*512;
209 	memset(buf+c, 0, i-c);
210 
211 	/* Open and stat the kernel file */
212 	fd = open(argv[2], O_RDONLY);
213 	if (fd < 0)
214 		die("Unable to open `%s': %m", argv[2]);
215 	if (fstat(fd, &sb))
216 		die("Unable to stat `%s': %m", argv[2]);
217 	if (_edata != sb.st_size)
218 		die("Unexpected file size `%s': %u != %u", argv[2], _edata,
219 		    sb.st_size);
220 	sz = _edata - 4;
221 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
222 	if (kernel == MAP_FAILED)
223 		die("Unable to mmap '%s': %m", argv[2]);
224 
225 	crc = partial_crc32(buf, i, crc);
226 	if (fwrite(buf, 1, i, dest) != i)
227 		die("Writing setup failed");
228 
229 	/* Copy the kernel code */
230 	crc = partial_crc32(kernel, sz, crc);
231 	if (fwrite(kernel, 1, sz, dest) != sz)
232 		die("Writing kernel failed");
233 
234 	/* Write the CRC */
235 	put_unaligned_le32(crc, buf);
236 	if (fwrite(buf, 1, 4, dest) != 4)
237 		die("Writing CRC failed");
238 
239 	/* Catch any delayed write failures */
240 	if (fclose(dest))
241 		die("Writing image failed");
242 
243 	close(fd);
244 
245 	/* Everything is OK */
246 	return 0;
247 }
248