xref: /openbmc/linux/arch/x86/boot/tools/build.c (revision b6dcefde)
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 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 < 3) || (argc > 4))
149 		usage();
150 	if (argc > 3) {
151 		if (!strcmp(argv[3], "CURRENT")) {
152 			if (stat("/", &sb)) {
153 				perror("/");
154 				die("Couldn't stat /");
155 			}
156 			major_root = major(sb.st_dev);
157 			minor_root = minor(sb.st_dev);
158 		} else if (strcmp(argv[3], "FLOPPY")) {
159 			if (stat(argv[3], &sb)) {
160 				perror(argv[3]);
161 				die("Couldn't stat root device.");
162 			}
163 			major_root = major(sb.st_rdev);
164 			minor_root = minor(sb.st_rdev);
165 		} else {
166 			major_root = 0;
167 			minor_root = 0;
168 		}
169 	} else {
170 		major_root = DEFAULT_MAJOR_ROOT;
171 		minor_root = DEFAULT_MINOR_ROOT;
172 	}
173 	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
174 
175 	/* Copy the setup code */
176 	file = fopen(argv[1], "r");
177 	if (!file)
178 		die("Unable to open `%s': %m", argv[1]);
179 	c = fread(buf, 1, sizeof(buf), file);
180 	if (ferror(file))
181 		die("read-error on `setup'");
182 	if (c < 1024)
183 		die("The setup must be at least 1024 bytes");
184 	if (buf[510] != 0x55 || buf[511] != 0xaa)
185 		die("Boot block hasn't got boot flag (0xAA55)");
186 	fclose(file);
187 
188 	/* Pad unused space with zeros */
189 	setup_sectors = (c + 511) / 512;
190 	if (setup_sectors < SETUP_SECT_MIN)
191 		setup_sectors = SETUP_SECT_MIN;
192 	i = setup_sectors*512;
193 	memset(buf+c, 0, i-c);
194 
195 	/* Set the default root device */
196 	buf[508] = minor_root;
197 	buf[509] = major_root;
198 
199 	fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
200 
201 	/* Open and stat the kernel file */
202 	fd = open(argv[2], O_RDONLY);
203 	if (fd < 0)
204 		die("Unable to open `%s': %m", argv[2]);
205 	if (fstat(fd, &sb))
206 		die("Unable to stat `%s': %m", argv[2]);
207 	sz = sb.st_size;
208 	fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
209 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
210 	if (kernel == MAP_FAILED)
211 		die("Unable to mmap '%s': %m", argv[2]);
212 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
213 	sys_size = (sz + 15 + 4) / 16;
214 
215 	/* Patch the setup code with the appropriate size parameters */
216 	buf[0x1f1] = setup_sectors-1;
217 	buf[0x1f4] = sys_size;
218 	buf[0x1f5] = sys_size >> 8;
219 	buf[0x1f6] = sys_size >> 16;
220 	buf[0x1f7] = sys_size >> 24;
221 
222 	crc = partial_crc32(buf, i, crc);
223 	if (fwrite(buf, 1, i, stdout) != i)
224 		die("Writing setup failed");
225 
226 	/* Copy the kernel code */
227 	crc = partial_crc32(kernel, sz, crc);
228 	if (fwrite(kernel, 1, sz, stdout) != sz)
229 		die("Writing kernel failed");
230 
231 	/* Add padding leaving 4 bytes for the checksum */
232 	while (sz++ < (sys_size*16) - 4) {
233 		crc = partial_crc32_one('\0', crc);
234 		if (fwrite("\0", 1, 1, stdout) != 1)
235 			die("Writing padding failed");
236 	}
237 
238 	/* Write the CRC */
239 	fprintf(stderr, "CRC %lx\n", crc);
240 	if (fwrite(&crc, 1, 4, stdout) != 4)
241 		die("Writing CRC failed");
242 
243 	close(fd);
244 
245 	/* Everything is OK */
246 	return 0;
247 }
248