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