blob: f2ac95ece0cc4fd6468cc42653fddde2c7f7110d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 1991, 1992 Linus Torvalds
3 * Copyright (C) 1997 Martin Mares
H. Peter Anvin4fd06962007-07-11 12:18:56 -07004 * Copyright (C) 2007 H. Peter Anvin
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 */
6
7/*
H. Peter Anvin9aa39092007-07-13 16:28:27 -07008 * This file builds a disk-image from two different files:
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * - 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
H. Peter Anvin4fd06962007-07-11 12:18:56 -070023 * Substantially overhauled by H. Peter Anvin, April 2007
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 */
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>
H. Peter Anvin4fd06962007-07-11 12:18:56 -070035#include <sys/mman.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/boot.h>
Matt Fleming92f42c52012-02-28 13:37:24 +000037#include <tools/le_byteshift.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
H. Peter Anvin4fd06962007-07-11 12:18:56 -070039typedef unsigned char u8;
40typedef unsigned short u16;
41typedef unsigned long u32;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#define DEFAULT_MAJOR_ROOT 0
44#define DEFAULT_MINOR_ROOT 0
Matt Fleming92f42c52012-02-28 13:37:24 +000045#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
H. Peter Anvin4fd06962007-07-11 12:18:56 -070047/* Minimal number of setup sectors */
48#define SETUP_SECT_MIN 5
49#define SETUP_SECT_MAX 64
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
H. Peter Anvin4fd06962007-07-11 12:18:56 -070051/* This must be large enough to hold the entire setup */
52u8 buf[SETUP_SECT_MAX*512];
Linus Torvalds1da177e2005-04-16 15:20:36 -070053int is_big_kernel;
54
Ian Campbell7d6e7372008-02-17 20:06:35 +010055/*----------------------------------------------------------------------*/
56
57static const u32 crctab32[] = {
58 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
59 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
60 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
61 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
62 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
63 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
64 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
65 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
66 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
67 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
68 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
69 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
70 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
71 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
72 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
73 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
74 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
75 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
76 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
77 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
78 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
79 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
80 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
81 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
82 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
83 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
84 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
85 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
86 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
87 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
88 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
89 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
90 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
91 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
92 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
93 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
94 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
95 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
96 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
97 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
98 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
99 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
100 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
101 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
102 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
103 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
104 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
105 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
106 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
107 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
108 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
109 0x2d02ef8d
110};
111
112static u32 partial_crc32_one(u8 c, u32 crc)
113{
114 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
115}
116
117static u32 partial_crc32(const u8 *s, int len, u32 crc)
118{
119 while (len--)
120 crc = partial_crc32_one(*s++, crc);
121 return crc;
122}
123
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700124static void die(const char * str, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 va_list args;
127 va_start(args, str);
128 vfprintf(stderr, str, args);
129 fputc('\n', stderr);
130 exit(1);
131}
132
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700133static void usage(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
Michal Marek079f85e2011-04-12 13:30:24 +0200135 die("Usage: build setup system [> image]");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
138int main(int argc, char ** argv)
139{
Matt Fleming291f3632011-12-12 21:27:52 +0000140#ifdef CONFIG_EFI_STUB
141 unsigned int file_sz, pe_header;
142#endif
KAMBAROV, ZAURa8f50342005-06-28 20:45:06 -0700143 unsigned int i, sz, setup_sectors;
144 int c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 u32 sys_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 struct stat sb;
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700147 FILE *file;
148 int fd;
149 void *kernel;
Ian Campbell7d6e7372008-02-17 20:06:35 +0100150 u32 crc = 0xffffffffUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Michal Marek079f85e2011-04-12 13:30:24 +0200152 if (argc != 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 usage();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700155 /* Copy the setup code */
156 file = fopen(argv[1], "r");
157 if (!file)
158 die("Unable to open `%s': %m", argv[1]);
159 c = fread(buf, 1, sizeof(buf), file);
160 if (ferror(file))
161 die("read-error on `setup'");
162 if (c < 1024)
163 die("The setup must be at least 1024 bytes");
Matt Fleming92f42c52012-02-28 13:37:24 +0000164 if (get_unaligned_le16(&buf[510]) != 0xAA55)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 die("Boot block hasn't got boot flag (0xAA55)");
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700166 fclose(file);
167
168 /* Pad unused space with zeros */
169 setup_sectors = (c + 511) / 512;
170 if (setup_sectors < SETUP_SECT_MIN)
171 setup_sectors = SETUP_SECT_MIN;
172 i = setup_sectors*512;
173 memset(buf+c, 0, i-c);
174
175 /* Set the default root device */
Matt Fleming92f42c52012-02-28 13:37:24 +0000176 put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700178 fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700180 /* Open and stat the kernel file */
181 fd = open(argv[2], O_RDONLY);
182 if (fd < 0)
183 die("Unable to open `%s': %m", argv[2]);
184 if (fstat(fd, &sb))
185 die("Unable to stat `%s': %m", argv[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 sz = sb.st_size;
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700187 fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
188 kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
189 if (kernel == MAP_FAILED)
190 die("Unable to mmap '%s': %m", argv[2]);
Ian Campbell7d6e7372008-02-17 20:06:35 +0100191 /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
192 sys_size = (sz + 15 + 4) / 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700194 /* Patch the setup code with the appropriate size parameters */
195 buf[0x1f1] = setup_sectors-1;
Matt Fleming92f42c52012-02-28 13:37:24 +0000196 put_unaligned_le32(sys_size, &buf[0x1f4]);
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700197
Matt Fleming291f3632011-12-12 21:27:52 +0000198#ifdef CONFIG_EFI_STUB
199 file_sz = sz + i + ((sys_size * 16) - sz);
200
Matt Fleming92f42c52012-02-28 13:37:24 +0000201 pe_header = get_unaligned_le32(&buf[0x3c]);
Matt Fleming291f3632011-12-12 21:27:52 +0000202
203 /* Size of code */
Matt Fleming92f42c52012-02-28 13:37:24 +0000204 put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
Matt Fleming291f3632011-12-12 21:27:52 +0000205
206 /* Size of image */
Matt Fleming92f42c52012-02-28 13:37:24 +0000207 put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
Matt Fleming291f3632011-12-12 21:27:52 +0000208
209#ifdef CONFIG_X86_32
210 /* Address of entry point */
Matt Fleming92f42c52012-02-28 13:37:24 +0000211 put_unaligned_le32(i, &buf[pe_header + 0x28]);
Matt Fleming291f3632011-12-12 21:27:52 +0000212
213 /* .text size */
Matt Fleming92f42c52012-02-28 13:37:24 +0000214 put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
Matt Fleming291f3632011-12-12 21:27:52 +0000215
216 /* .text size of initialised data */
Matt Fleming92f42c52012-02-28 13:37:24 +0000217 put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]);
Matt Fleming291f3632011-12-12 21:27:52 +0000218#else
219 /*
220 * Address of entry point. startup_32 is at the beginning and
221 * the 64-bit entry point (startup_64) is always 512 bytes
222 * after.
223 */
Matt Fleming92f42c52012-02-28 13:37:24 +0000224 put_unaligned_le32(i + 512, &buf[pe_header + 0x28]);
Matt Fleming291f3632011-12-12 21:27:52 +0000225
226 /* .text size */
Matt Fleming92f42c52012-02-28 13:37:24 +0000227 put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);
Matt Fleming291f3632011-12-12 21:27:52 +0000228
229 /* .text size of initialised data */
Matt Fleming92f42c52012-02-28 13:37:24 +0000230 put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]);
231
Matt Fleming291f3632011-12-12 21:27:52 +0000232#endif /* CONFIG_X86_32 */
233#endif /* CONFIG_EFI_STUB */
234
Ian Campbell7d6e7372008-02-17 20:06:35 +0100235 crc = partial_crc32(buf, i, crc);
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700236 if (fwrite(buf, 1, i, stdout) != i)
237 die("Writing setup failed");
238
239 /* Copy the kernel code */
Ian Campbell7d6e7372008-02-17 20:06:35 +0100240 crc = partial_crc32(kernel, sz, crc);
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700241 if (fwrite(kernel, 1, sz, stdout) != sz)
242 die("Writing kernel failed");
Ian Campbell7d6e7372008-02-17 20:06:35 +0100243
244 /* Add padding leaving 4 bytes for the checksum */
245 while (sz++ < (sys_size*16) - 4) {
246 crc = partial_crc32_one('\0', crc);
247 if (fwrite("\0", 1, 1, stdout) != 1)
248 die("Writing padding failed");
249 }
250
251 /* Write the CRC */
252 fprintf(stderr, "CRC %lx\n", crc);
253 if (fwrite(&crc, 1, 4, stdout) != 4)
254 die("Writing CRC failed");
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 close(fd);
257
H. Peter Anvin4fd06962007-07-11 12:18:56 -0700258 /* Everything is OK */
259 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260}