1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 1991, 1992 Linus Torvalds
4*4882a593Smuzhiyun * Copyright (C) 1997 Martin Mares
5*4882a593Smuzhiyun * Copyright (C) 2007 H. Peter Anvin
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun * This file builds a disk-image from three different files:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * - setup: 8086 machine code, sets up system parm
12*4882a593Smuzhiyun * - system: 80386 code for actual system
13*4882a593Smuzhiyun * - zoffset.h: header with ZO_* defines
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * It does some checking that all files are of the correct type, and writes
16*4882a593Smuzhiyun * the result to the specified destination, removing headers and padding to
17*4882a593Smuzhiyun * the right amount. It also writes some system data to stdout.
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun * Changes by tytso to allow root device specification
22*4882a593Smuzhiyun * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23*4882a593Smuzhiyun * Cross compiling fixes by Gertjan van Wingerde, July 1996
24*4882a593Smuzhiyun * Rewritten by Martin Mares, April 1997
25*4882a593Smuzhiyun * Substantially overhauled by H. Peter Anvin, April 2007
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <stdio.h>
29*4882a593Smuzhiyun #include <string.h>
30*4882a593Smuzhiyun #include <stdlib.h>
31*4882a593Smuzhiyun #include <stdarg.h>
32*4882a593Smuzhiyun #include <sys/types.h>
33*4882a593Smuzhiyun #include <sys/stat.h>
34*4882a593Smuzhiyun #include <unistd.h>
35*4882a593Smuzhiyun #include <fcntl.h>
36*4882a593Smuzhiyun #include <sys/mman.h>
37*4882a593Smuzhiyun #include <tools/le_byteshift.h>
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun typedef unsigned char u8;
40*4882a593Smuzhiyun typedef unsigned short u16;
41*4882a593Smuzhiyun typedef unsigned int u32;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define DEFAULT_MAJOR_ROOT 0
44*4882a593Smuzhiyun #define DEFAULT_MINOR_ROOT 0
45*4882a593Smuzhiyun #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* Minimal number of setup sectors */
48*4882a593Smuzhiyun #define SETUP_SECT_MIN 5
49*4882a593Smuzhiyun #define SETUP_SECT_MAX 64
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* This must be large enough to hold the entire setup */
52*4882a593Smuzhiyun u8 buf[SETUP_SECT_MAX*512];
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #define PECOFF_RELOC_RESERVE 0x20
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #ifdef CONFIG_EFI_MIXED
57*4882a593Smuzhiyun #define PECOFF_COMPAT_RESERVE 0x20
58*4882a593Smuzhiyun #else
59*4882a593Smuzhiyun #define PECOFF_COMPAT_RESERVE 0x0
60*4882a593Smuzhiyun #endif
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static unsigned long efi32_stub_entry;
63*4882a593Smuzhiyun static unsigned long efi64_stub_entry;
64*4882a593Smuzhiyun static unsigned long efi_pe_entry;
65*4882a593Smuzhiyun static unsigned long efi32_pe_entry;
66*4882a593Smuzhiyun static unsigned long kernel_info;
67*4882a593Smuzhiyun static unsigned long startup_64;
68*4882a593Smuzhiyun static unsigned long _ehead;
69*4882a593Smuzhiyun static unsigned long _end;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /*----------------------------------------------------------------------*/
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static const u32 crctab32[] = {
74*4882a593Smuzhiyun 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
75*4882a593Smuzhiyun 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
76*4882a593Smuzhiyun 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
77*4882a593Smuzhiyun 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
78*4882a593Smuzhiyun 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
79*4882a593Smuzhiyun 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
80*4882a593Smuzhiyun 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
81*4882a593Smuzhiyun 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
82*4882a593Smuzhiyun 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
83*4882a593Smuzhiyun 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
84*4882a593Smuzhiyun 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
85*4882a593Smuzhiyun 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
86*4882a593Smuzhiyun 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
87*4882a593Smuzhiyun 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
88*4882a593Smuzhiyun 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
89*4882a593Smuzhiyun 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
90*4882a593Smuzhiyun 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
91*4882a593Smuzhiyun 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
92*4882a593Smuzhiyun 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
93*4882a593Smuzhiyun 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
94*4882a593Smuzhiyun 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
95*4882a593Smuzhiyun 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
96*4882a593Smuzhiyun 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
97*4882a593Smuzhiyun 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
98*4882a593Smuzhiyun 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
99*4882a593Smuzhiyun 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
100*4882a593Smuzhiyun 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
101*4882a593Smuzhiyun 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
102*4882a593Smuzhiyun 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
103*4882a593Smuzhiyun 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
104*4882a593Smuzhiyun 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
105*4882a593Smuzhiyun 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
106*4882a593Smuzhiyun 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
107*4882a593Smuzhiyun 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
108*4882a593Smuzhiyun 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
109*4882a593Smuzhiyun 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
110*4882a593Smuzhiyun 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
111*4882a593Smuzhiyun 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
112*4882a593Smuzhiyun 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
113*4882a593Smuzhiyun 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
114*4882a593Smuzhiyun 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
115*4882a593Smuzhiyun 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
116*4882a593Smuzhiyun 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
117*4882a593Smuzhiyun 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
118*4882a593Smuzhiyun 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
119*4882a593Smuzhiyun 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
120*4882a593Smuzhiyun 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
121*4882a593Smuzhiyun 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
122*4882a593Smuzhiyun 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
123*4882a593Smuzhiyun 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
124*4882a593Smuzhiyun 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
125*4882a593Smuzhiyun 0x2d02ef8d
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
partial_crc32_one(u8 c,u32 crc)128*4882a593Smuzhiyun static u32 partial_crc32_one(u8 c, u32 crc)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
partial_crc32(const u8 * s,int len,u32 crc)133*4882a593Smuzhiyun static u32 partial_crc32(const u8 *s, int len, u32 crc)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun while (len--)
136*4882a593Smuzhiyun crc = partial_crc32_one(*s++, crc);
137*4882a593Smuzhiyun return crc;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
die(const char * str,...)140*4882a593Smuzhiyun static void die(const char * str, ...)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun va_list args;
143*4882a593Smuzhiyun va_start(args, str);
144*4882a593Smuzhiyun vfprintf(stderr, str, args);
145*4882a593Smuzhiyun va_end(args);
146*4882a593Smuzhiyun fputc('\n', stderr);
147*4882a593Smuzhiyun exit(1);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
usage(void)150*4882a593Smuzhiyun static void usage(void)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun die("Usage: build setup system zoffset.h image");
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun #ifdef CONFIG_EFI_STUB
156*4882a593Smuzhiyun
update_pecoff_section_header_fields(char * section_name,u32 vma,u32 size,u32 datasz,u32 offset)157*4882a593Smuzhiyun static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun unsigned int pe_header;
160*4882a593Smuzhiyun unsigned short num_sections;
161*4882a593Smuzhiyun u8 *section;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun pe_header = get_unaligned_le32(&buf[0x3c]);
164*4882a593Smuzhiyun num_sections = get_unaligned_le16(&buf[pe_header + 6]);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun #ifdef CONFIG_X86_32
167*4882a593Smuzhiyun section = &buf[pe_header + 0xa8];
168*4882a593Smuzhiyun #else
169*4882a593Smuzhiyun section = &buf[pe_header + 0xb8];
170*4882a593Smuzhiyun #endif
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun while (num_sections > 0) {
173*4882a593Smuzhiyun if (strncmp((char*)section, section_name, 8) == 0) {
174*4882a593Smuzhiyun /* section header size field */
175*4882a593Smuzhiyun put_unaligned_le32(size, section + 0x8);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /* section header vma field */
178*4882a593Smuzhiyun put_unaligned_le32(vma, section + 0xc);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* section header 'size of initialised data' field */
181*4882a593Smuzhiyun put_unaligned_le32(datasz, section + 0x10);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* section header 'file offset' field */
184*4882a593Smuzhiyun put_unaligned_le32(offset, section + 0x14);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun break;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun section += 0x28;
189*4882a593Smuzhiyun num_sections--;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
update_pecoff_section_header(char * section_name,u32 offset,u32 size)193*4882a593Smuzhiyun static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun update_pecoff_section_header_fields(section_name, offset, size, size, offset);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
update_pecoff_setup_and_reloc(unsigned int size)198*4882a593Smuzhiyun static void update_pecoff_setup_and_reloc(unsigned int size)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun u32 setup_offset = 0x200;
201*4882a593Smuzhiyun u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
202*4882a593Smuzhiyun #ifdef CONFIG_EFI_MIXED
203*4882a593Smuzhiyun u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
204*4882a593Smuzhiyun #endif
205*4882a593Smuzhiyun u32 setup_size = reloc_offset - setup_offset;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun update_pecoff_section_header(".setup", setup_offset, setup_size);
208*4882a593Smuzhiyun update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /*
211*4882a593Smuzhiyun * Modify .reloc section contents with a single entry. The
212*4882a593Smuzhiyun * relocation is applied to offset 10 of the relocation section.
213*4882a593Smuzhiyun */
214*4882a593Smuzhiyun put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
215*4882a593Smuzhiyun put_unaligned_le32(10, &buf[reloc_offset + 4]);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun #ifdef CONFIG_EFI_MIXED
218*4882a593Smuzhiyun update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /*
221*4882a593Smuzhiyun * Put the IA-32 machine type (0x14c) and the associated entry point
222*4882a593Smuzhiyun * address in the .compat section, so loaders can figure out which other
223*4882a593Smuzhiyun * execution modes this image supports.
224*4882a593Smuzhiyun */
225*4882a593Smuzhiyun buf[compat_offset] = 0x1;
226*4882a593Smuzhiyun buf[compat_offset + 1] = 0x8;
227*4882a593Smuzhiyun put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
228*4882a593Smuzhiyun put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
229*4882a593Smuzhiyun #endif
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
update_pecoff_text(unsigned int text_start,unsigned int file_sz,unsigned int init_sz)232*4882a593Smuzhiyun static void update_pecoff_text(unsigned int text_start, unsigned int file_sz,
233*4882a593Smuzhiyun unsigned int init_sz)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun unsigned int pe_header;
236*4882a593Smuzhiyun unsigned int text_sz = file_sz - text_start;
237*4882a593Smuzhiyun unsigned int bss_sz = init_sz - file_sz;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun pe_header = get_unaligned_le32(&buf[0x3c]);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /*
242*4882a593Smuzhiyun * The PE/COFF loader may load the image at an address which is
243*4882a593Smuzhiyun * misaligned with respect to the kernel_alignment field in the setup
244*4882a593Smuzhiyun * header.
245*4882a593Smuzhiyun *
246*4882a593Smuzhiyun * In order to avoid relocating the kernel to correct the misalignment,
247*4882a593Smuzhiyun * add slack to allow the buffer to be aligned within the declared size
248*4882a593Smuzhiyun * of the image.
249*4882a593Smuzhiyun */
250*4882a593Smuzhiyun bss_sz += CONFIG_PHYSICAL_ALIGN;
251*4882a593Smuzhiyun init_sz += CONFIG_PHYSICAL_ALIGN;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /*
254*4882a593Smuzhiyun * Size of code: Subtract the size of the first sector (512 bytes)
255*4882a593Smuzhiyun * which includes the header.
256*4882a593Smuzhiyun */
257*4882a593Smuzhiyun put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /* Size of image */
260*4882a593Smuzhiyun put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * Address of entry point for PE/COFF executable
264*4882a593Smuzhiyun */
265*4882a593Smuzhiyun put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
268*4882a593Smuzhiyun text_sz, text_start);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
reserve_pecoff_reloc_section(int c)271*4882a593Smuzhiyun static int reserve_pecoff_reloc_section(int c)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun /* Reserve 0x20 bytes for .reloc section */
274*4882a593Smuzhiyun memset(buf+c, 0, PECOFF_RELOC_RESERVE);
275*4882a593Smuzhiyun return PECOFF_RELOC_RESERVE;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
efi_stub_defaults(void)278*4882a593Smuzhiyun static void efi_stub_defaults(void)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun /* Defaults for old kernel */
281*4882a593Smuzhiyun #ifdef CONFIG_X86_32
282*4882a593Smuzhiyun efi_pe_entry = 0x10;
283*4882a593Smuzhiyun #else
284*4882a593Smuzhiyun efi_pe_entry = 0x210;
285*4882a593Smuzhiyun startup_64 = 0x200;
286*4882a593Smuzhiyun #endif
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
efi_stub_entry_update(void)289*4882a593Smuzhiyun static void efi_stub_entry_update(void)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun unsigned long addr = efi32_stub_entry;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun #ifdef CONFIG_X86_64
294*4882a593Smuzhiyun /* Yes, this is really how we defined it :( */
295*4882a593Smuzhiyun addr = efi64_stub_entry - 0x200;
296*4882a593Smuzhiyun #endif
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun #ifdef CONFIG_EFI_MIXED
299*4882a593Smuzhiyun if (efi32_stub_entry != addr)
300*4882a593Smuzhiyun die("32-bit and 64-bit EFI entry points do not match\n");
301*4882a593Smuzhiyun #endif
302*4882a593Smuzhiyun put_unaligned_le32(addr, &buf[0x264]);
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun #else
306*4882a593Smuzhiyun
update_pecoff_setup_and_reloc(unsigned int size)307*4882a593Smuzhiyun static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
update_pecoff_text(unsigned int text_start,unsigned int file_sz,unsigned int init_sz)308*4882a593Smuzhiyun static inline void update_pecoff_text(unsigned int text_start,
309*4882a593Smuzhiyun unsigned int file_sz,
310*4882a593Smuzhiyun unsigned int init_sz) {}
efi_stub_defaults(void)311*4882a593Smuzhiyun static inline void efi_stub_defaults(void) {}
efi_stub_entry_update(void)312*4882a593Smuzhiyun static inline void efi_stub_entry_update(void) {}
313*4882a593Smuzhiyun
reserve_pecoff_reloc_section(int c)314*4882a593Smuzhiyun static inline int reserve_pecoff_reloc_section(int c)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun return 0;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun #endif /* CONFIG_EFI_STUB */
319*4882a593Smuzhiyun
reserve_pecoff_compat_section(int c)320*4882a593Smuzhiyun static int reserve_pecoff_compat_section(int c)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun /* Reserve 0x20 bytes for .compat section */
323*4882a593Smuzhiyun memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
324*4882a593Smuzhiyun return PECOFF_COMPAT_RESERVE;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /*
328*4882a593Smuzhiyun * Parse zoffset.h and find the entry points. We could just #include zoffset.h
329*4882a593Smuzhiyun * but that would mean tools/build would have to be rebuilt every time. It's
330*4882a593Smuzhiyun * not as if parsing it is hard...
331*4882a593Smuzhiyun */
332*4882a593Smuzhiyun #define PARSE_ZOFS(p, sym) do { \
333*4882a593Smuzhiyun if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym))) \
334*4882a593Smuzhiyun sym = strtoul(p + 11 + sizeof(#sym), NULL, 16); \
335*4882a593Smuzhiyun } while (0)
336*4882a593Smuzhiyun
parse_zoffset(char * fname)337*4882a593Smuzhiyun static void parse_zoffset(char *fname)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun FILE *file;
340*4882a593Smuzhiyun char *p;
341*4882a593Smuzhiyun int c;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun file = fopen(fname, "r");
344*4882a593Smuzhiyun if (!file)
345*4882a593Smuzhiyun die("Unable to open `%s': %m", fname);
346*4882a593Smuzhiyun c = fread(buf, 1, sizeof(buf) - 1, file);
347*4882a593Smuzhiyun if (ferror(file))
348*4882a593Smuzhiyun die("read-error on `zoffset.h'");
349*4882a593Smuzhiyun fclose(file);
350*4882a593Smuzhiyun buf[c] = 0;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun p = (char *)buf;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun while (p && *p) {
355*4882a593Smuzhiyun PARSE_ZOFS(p, efi32_stub_entry);
356*4882a593Smuzhiyun PARSE_ZOFS(p, efi64_stub_entry);
357*4882a593Smuzhiyun PARSE_ZOFS(p, efi_pe_entry);
358*4882a593Smuzhiyun PARSE_ZOFS(p, efi32_pe_entry);
359*4882a593Smuzhiyun PARSE_ZOFS(p, kernel_info);
360*4882a593Smuzhiyun PARSE_ZOFS(p, startup_64);
361*4882a593Smuzhiyun PARSE_ZOFS(p, _ehead);
362*4882a593Smuzhiyun PARSE_ZOFS(p, _end);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun p = strchr(p, '\n');
365*4882a593Smuzhiyun while (p && (*p == '\r' || *p == '\n'))
366*4882a593Smuzhiyun p++;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
main(int argc,char ** argv)370*4882a593Smuzhiyun int main(int argc, char ** argv)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun unsigned int i, sz, setup_sectors, init_sz;
373*4882a593Smuzhiyun int c;
374*4882a593Smuzhiyun u32 sys_size;
375*4882a593Smuzhiyun struct stat sb;
376*4882a593Smuzhiyun FILE *file, *dest;
377*4882a593Smuzhiyun int fd;
378*4882a593Smuzhiyun void *kernel;
379*4882a593Smuzhiyun u32 crc = 0xffffffffUL;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun efi_stub_defaults();
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (argc != 5)
384*4882a593Smuzhiyun usage();
385*4882a593Smuzhiyun parse_zoffset(argv[3]);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun dest = fopen(argv[4], "w");
388*4882a593Smuzhiyun if (!dest)
389*4882a593Smuzhiyun die("Unable to write `%s': %m", argv[4]);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /* Copy the setup code */
392*4882a593Smuzhiyun file = fopen(argv[1], "r");
393*4882a593Smuzhiyun if (!file)
394*4882a593Smuzhiyun die("Unable to open `%s': %m", argv[1]);
395*4882a593Smuzhiyun c = fread(buf, 1, sizeof(buf), file);
396*4882a593Smuzhiyun if (ferror(file))
397*4882a593Smuzhiyun die("read-error on `setup'");
398*4882a593Smuzhiyun if (c < 1024)
399*4882a593Smuzhiyun die("The setup must be at least 1024 bytes");
400*4882a593Smuzhiyun if (get_unaligned_le16(&buf[510]) != 0xAA55)
401*4882a593Smuzhiyun die("Boot block hasn't got boot flag (0xAA55)");
402*4882a593Smuzhiyun fclose(file);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun c += reserve_pecoff_compat_section(c);
405*4882a593Smuzhiyun c += reserve_pecoff_reloc_section(c);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* Pad unused space with zeros */
408*4882a593Smuzhiyun setup_sectors = (c + 511) / 512;
409*4882a593Smuzhiyun if (setup_sectors < SETUP_SECT_MIN)
410*4882a593Smuzhiyun setup_sectors = SETUP_SECT_MIN;
411*4882a593Smuzhiyun i = setup_sectors*512;
412*4882a593Smuzhiyun memset(buf+c, 0, i-c);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun update_pecoff_setup_and_reloc(i);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun /* Set the default root device */
417*4882a593Smuzhiyun put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /* Open and stat the kernel file */
420*4882a593Smuzhiyun fd = open(argv[2], O_RDONLY);
421*4882a593Smuzhiyun if (fd < 0)
422*4882a593Smuzhiyun die("Unable to open `%s': %m", argv[2]);
423*4882a593Smuzhiyun if (fstat(fd, &sb))
424*4882a593Smuzhiyun die("Unable to stat `%s': %m", argv[2]);
425*4882a593Smuzhiyun sz = sb.st_size;
426*4882a593Smuzhiyun kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
427*4882a593Smuzhiyun if (kernel == MAP_FAILED)
428*4882a593Smuzhiyun die("Unable to mmap '%s': %m", argv[2]);
429*4882a593Smuzhiyun /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
430*4882a593Smuzhiyun sys_size = (sz + 15 + 4) / 16;
431*4882a593Smuzhiyun #ifdef CONFIG_EFI_STUB
432*4882a593Smuzhiyun /*
433*4882a593Smuzhiyun * COFF requires minimum 32-byte alignment of sections, and
434*4882a593Smuzhiyun * adding a signature is problematic without that alignment.
435*4882a593Smuzhiyun */
436*4882a593Smuzhiyun sys_size = (sys_size + 1) & ~1;
437*4882a593Smuzhiyun #endif
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun /* Patch the setup code with the appropriate size parameters */
440*4882a593Smuzhiyun buf[0x1f1] = setup_sectors-1;
441*4882a593Smuzhiyun put_unaligned_le32(sys_size, &buf[0x1f4]);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun init_sz = get_unaligned_le32(&buf[0x260]);
444*4882a593Smuzhiyun #ifdef CONFIG_EFI_STUB
445*4882a593Smuzhiyun /*
446*4882a593Smuzhiyun * The decompression buffer will start at ImageBase. When relocating
447*4882a593Smuzhiyun * the compressed kernel to its end, we must ensure that the head
448*4882a593Smuzhiyun * section does not get overwritten. The head section occupies
449*4882a593Smuzhiyun * [i, i + _ehead), and the destination is [init_sz - _end, init_sz).
450*4882a593Smuzhiyun *
451*4882a593Smuzhiyun * At present these should never overlap, because 'i' is at most 32k
452*4882a593Smuzhiyun * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the
453*4882a593Smuzhiyun * calculation of INIT_SIZE in boot/header.S ensures that
454*4882a593Smuzhiyun * 'init_sz - _end' is at least 64k.
455*4882a593Smuzhiyun *
456*4882a593Smuzhiyun * For future-proofing, increase init_sz if necessary.
457*4882a593Smuzhiyun */
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (init_sz - _end < i + _ehead) {
460*4882a593Smuzhiyun init_sz = (i + _ehead + _end + 4095) & ~4095;
461*4882a593Smuzhiyun put_unaligned_le32(init_sz, &buf[0x260]);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun #endif
464*4882a593Smuzhiyun update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun efi_stub_entry_update();
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /* Update kernel_info offset. */
469*4882a593Smuzhiyun put_unaligned_le32(kernel_info, &buf[0x268]);
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun crc = partial_crc32(buf, i, crc);
472*4882a593Smuzhiyun if (fwrite(buf, 1, i, dest) != i)
473*4882a593Smuzhiyun die("Writing setup failed");
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /* Copy the kernel code */
476*4882a593Smuzhiyun crc = partial_crc32(kernel, sz, crc);
477*4882a593Smuzhiyun if (fwrite(kernel, 1, sz, dest) != sz)
478*4882a593Smuzhiyun die("Writing kernel failed");
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /* Add padding leaving 4 bytes for the checksum */
481*4882a593Smuzhiyun while (sz++ < (sys_size*16) - 4) {
482*4882a593Smuzhiyun crc = partial_crc32_one('\0', crc);
483*4882a593Smuzhiyun if (fwrite("\0", 1, 1, dest) != 1)
484*4882a593Smuzhiyun die("Writing padding failed");
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /* Write the CRC */
488*4882a593Smuzhiyun put_unaligned_le32(crc, buf);
489*4882a593Smuzhiyun if (fwrite(buf, 1, 4, dest) != 4)
490*4882a593Smuzhiyun die("Writing CRC failed");
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* Catch any delayed write failures */
493*4882a593Smuzhiyun if (fclose(dest))
494*4882a593Smuzhiyun die("Writing image failed");
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun close(fd);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /* Everything is OK */
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501