2 * Copyright (C) 1991, 1992 Linus Torvalds
3 * Copyright (C) 1997 Martin Mares
4 * Copyright (C) 2007 H. Peter Anvin
8 * This file builds a disk-image from two different files:
10 * - setup: 8086 machine code, sets up system parm
11 * - system: 80386 code for actual system
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.
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
30 #include <sys/types.h>
35 #include <tools/le_byteshift.h>
37 typedef unsigned char u8;
38 typedef unsigned short u16;
39 typedef unsigned int u32;
41 #define DEFAULT_MAJOR_ROOT 0
42 #define DEFAULT_MINOR_ROOT 0
43 #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
45 /* Minimal number of setup sectors */
46 #define SETUP_SECT_MIN 5
47 #define SETUP_SECT_MAX 64
49 /* This must be large enough to hold the entire setup */
50 u8 buf[SETUP_SECT_MAX*512];
53 #define PECOFF_RELOC_RESERVE 0x20
55 /*----------------------------------------------------------------------*/
57 static 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,
112 static u32 partial_crc32_one(u8 c, u32 crc)
114 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
117 static u32 partial_crc32(const u8 *s, int len, u32 crc)
120 crc = partial_crc32_one(*s++, crc);
124 static void die(const char * str, ...)
128 vfprintf(stderr, str, args);
133 static void usage(void)
135 die("Usage: build setup system [> image]");
138 #ifdef CONFIG_EFI_STUB
140 static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
142 unsigned int pe_header;
143 unsigned short num_sections;
146 pe_header = get_unaligned_le32(&buf[0x3c]);
147 num_sections = get_unaligned_le16(&buf[pe_header + 6]);
150 section = &buf[pe_header + 0xa8];
152 section = &buf[pe_header + 0xb8];
155 while (num_sections > 0) {
156 if (strncmp((char*)section, section_name, 8) == 0) {
157 /* section header size field */
158 put_unaligned_le32(size, section + 0x8);
160 /* section header vma field */
161 put_unaligned_le32(offset, section + 0xc);
163 /* section header 'size of initialised data' field */
164 put_unaligned_le32(size, section + 0x10);
166 /* section header 'file offset' field */
167 put_unaligned_le32(offset, section + 0x14);
176 static void update_pecoff_setup_and_reloc(unsigned int size)
178 u32 setup_offset = 0x200;
179 u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
180 u32 setup_size = reloc_offset - setup_offset;
182 update_pecoff_section_header(".setup", setup_offset, setup_size);
183 update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
186 * Modify .reloc section contents with a single entry. The
187 * relocation is applied to offset 10 of the relocation section.
189 put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
190 put_unaligned_le32(10, &buf[reloc_offset + 4]);
193 static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
195 unsigned int pe_header;
196 unsigned int text_sz = file_sz - text_start;
198 pe_header = get_unaligned_le32(&buf[0x3c]);
201 put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
204 * Size of code: Subtract the size of the first sector (512 bytes)
205 * which includes the header.
207 put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
211 * Address of entry point.
213 * The EFI stub entry point is +16 bytes from the start of
216 put_unaligned_le32(text_start + 16, &buf[pe_header + 0x28]);
219 * Address of entry point. startup_32 is at the beginning and
220 * the 64-bit entry point (startup_64) is always 512 bytes
221 * after. The EFI stub entry point is 16 bytes after that, as
222 * the first instruction allows legacy loaders to jump over
223 * the EFI stub initialisation
225 put_unaligned_le32(text_start + 528, &buf[pe_header + 0x28]);
226 #endif /* CONFIG_X86_32 */
228 update_pecoff_section_header(".text", text_start, text_sz);
231 #endif /* CONFIG_EFI_STUB */
233 int main(int argc, char ** argv)
235 unsigned int i, sz, setup_sectors;
242 u32 crc = 0xffffffffUL;
247 /* Copy the setup code */
248 file = fopen(argv[1], "r");
250 die("Unable to open `%s': %m", argv[1]);
251 c = fread(buf, 1, sizeof(buf), file);
253 die("read-error on `setup'");
255 die("The setup must be at least 1024 bytes");
256 if (get_unaligned_le16(&buf[510]) != 0xAA55)
257 die("Boot block hasn't got boot flag (0xAA55)");
260 #ifdef CONFIG_EFI_STUB
261 /* Reserve 0x20 bytes for .reloc section */
262 memset(buf+c, 0, PECOFF_RELOC_RESERVE);
263 c += PECOFF_RELOC_RESERVE;
266 /* Pad unused space with zeros */
267 setup_sectors = (c + 511) / 512;
268 if (setup_sectors < SETUP_SECT_MIN)
269 setup_sectors = SETUP_SECT_MIN;
270 i = setup_sectors*512;
271 memset(buf+c, 0, i-c);
273 #ifdef CONFIG_EFI_STUB
274 update_pecoff_setup_and_reloc(i);
277 /* Set the default root device */
278 put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
280 fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
282 /* Open and stat the kernel file */
283 fd = open(argv[2], O_RDONLY);
285 die("Unable to open `%s': %m", argv[2]);
287 die("Unable to stat `%s': %m", argv[2]);
289 fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
290 kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
291 if (kernel == MAP_FAILED)
292 die("Unable to mmap '%s': %m", argv[2]);
293 /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
294 sys_size = (sz + 15 + 4) / 16;
296 /* Patch the setup code with the appropriate size parameters */
297 buf[0x1f1] = setup_sectors-1;
298 put_unaligned_le32(sys_size, &buf[0x1f4]);
300 #ifdef CONFIG_EFI_STUB
301 update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
304 crc = partial_crc32(buf, i, crc);
305 if (fwrite(buf, 1, i, stdout) != i)
306 die("Writing setup failed");
308 /* Copy the kernel code */
309 crc = partial_crc32(kernel, sz, crc);
310 if (fwrite(kernel, 1, sz, stdout) != sz)
311 die("Writing kernel failed");
313 /* Add padding leaving 4 bytes for the checksum */
314 while (sz++ < (sys_size*16) - 4) {
315 crc = partial_crc32_one('\0', crc);
316 if (fwrite("\0", 1, 1, stdout) != 1)
317 die("Writing padding failed");
321 fprintf(stderr, "CRC %x\n", crc);
322 put_unaligned_le32(crc, buf);
323 if (fwrite(buf, 1, 4, stdout) != 4)
324 die("Writing CRC failed");
328 /* Everything is OK */