diff options
Diffstat (limited to 'arch/x86/boot/tools/build.c')
-rw-r--r-- | arch/x86/boot/tools/build.c | 172 |
1 files changed, 109 insertions, 63 deletions
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c index 3f61f6e2b46f..4b8e165ee572 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c | |||
@@ -50,6 +50,8 @@ typedef unsigned int u32; | |||
50 | u8 buf[SETUP_SECT_MAX*512]; | 50 | u8 buf[SETUP_SECT_MAX*512]; |
51 | int is_big_kernel; | 51 | int is_big_kernel; |
52 | 52 | ||
53 | #define PECOFF_RELOC_RESERVE 0x20 | ||
54 | |||
53 | /*----------------------------------------------------------------------*/ | 55 | /*----------------------------------------------------------------------*/ |
54 | 56 | ||
55 | static const u32 crctab32[] = { | 57 | static const u32 crctab32[] = { |
@@ -133,11 +135,103 @@ static void usage(void) | |||
133 | die("Usage: build setup system [> image]"); | 135 | die("Usage: build setup system [> image]"); |
134 | } | 136 | } |
135 | 137 | ||
136 | int main(int argc, char ** argv) | ||
137 | { | ||
138 | #ifdef CONFIG_EFI_STUB | 138 | #ifdef CONFIG_EFI_STUB |
139 | unsigned int file_sz, pe_header; | 139 | |
140 | static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) | ||
141 | { | ||
142 | unsigned int pe_header; | ||
143 | unsigned short num_sections; | ||
144 | u8 *section; | ||
145 | |||
146 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
147 | num_sections = get_unaligned_le16(&buf[pe_header + 6]); | ||
148 | |||
149 | #ifdef CONFIG_X86_32 | ||
150 | section = &buf[pe_header + 0xa8]; | ||
151 | #else | ||
152 | section = &buf[pe_header + 0xb8]; | ||
140 | #endif | 153 | #endif |
154 | |||
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); | ||
159 | |||
160 | /* section header vma field */ | ||
161 | put_unaligned_le32(offset, section + 0xc); | ||
162 | |||
163 | /* section header 'size of initialised data' field */ | ||
164 | put_unaligned_le32(size, section + 0x10); | ||
165 | |||
166 | /* section header 'file offset' field */ | ||
167 | put_unaligned_le32(offset, section + 0x14); | ||
168 | |||
169 | break; | ||
170 | } | ||
171 | section += 0x28; | ||
172 | num_sections--; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void update_pecoff_setup_and_reloc(unsigned int size) | ||
177 | { | ||
178 | u32 setup_offset = 0x200; | ||
179 | u32 reloc_offset = size - PECOFF_RELOC_RESERVE; | ||
180 | u32 setup_size = reloc_offset - setup_offset; | ||
181 | |||
182 | update_pecoff_section_header(".setup", setup_offset, setup_size); | ||
183 | update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE); | ||
184 | |||
185 | /* | ||
186 | * Modify .reloc section contents with a single entry. The | ||
187 | * relocation is applied to offset 10 of the relocation section. | ||
188 | */ | ||
189 | put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); | ||
190 | put_unaligned_le32(10, &buf[reloc_offset + 4]); | ||
191 | } | ||
192 | |||
193 | static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) | ||
194 | { | ||
195 | unsigned int pe_header; | ||
196 | unsigned int text_sz = file_sz - text_start; | ||
197 | |||
198 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
199 | |||
200 | /* Size of image */ | ||
201 | put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); | ||
202 | |||
203 | /* | ||
204 | * Size of code: Subtract the size of the first sector (512 bytes) | ||
205 | * which includes the header. | ||
206 | */ | ||
207 | put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]); | ||
208 | |||
209 | #ifdef CONFIG_X86_32 | ||
210 | /* | ||
211 | * Address of entry point. | ||
212 | * | ||
213 | * The EFI stub entry point is +16 bytes from the start of | ||
214 | * the .text section. | ||
215 | */ | ||
216 | put_unaligned_le32(text_start + 16, &buf[pe_header + 0x28]); | ||
217 | #else | ||
218 | /* | ||
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 | ||
224 | */ | ||
225 | put_unaligned_le32(text_start + 528, &buf[pe_header + 0x28]); | ||
226 | #endif /* CONFIG_X86_32 */ | ||
227 | |||
228 | update_pecoff_section_header(".text", text_start, text_sz); | ||
229 | } | ||
230 | |||
231 | #endif /* CONFIG_EFI_STUB */ | ||
232 | |||
233 | int main(int argc, char ** argv) | ||
234 | { | ||
141 | unsigned int i, sz, setup_sectors; | 235 | unsigned int i, sz, setup_sectors; |
142 | int c; | 236 | int c; |
143 | u32 sys_size; | 237 | u32 sys_size; |
@@ -163,6 +257,12 @@ int main(int argc, char ** argv) | |||
163 | die("Boot block hasn't got boot flag (0xAA55)"); | 257 | die("Boot block hasn't got boot flag (0xAA55)"); |
164 | fclose(file); | 258 | fclose(file); |
165 | 259 | ||
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; | ||
264 | #endif | ||
265 | |||
166 | /* Pad unused space with zeros */ | 266 | /* Pad unused space with zeros */ |
167 | setup_sectors = (c + 511) / 512; | 267 | setup_sectors = (c + 511) / 512; |
168 | if (setup_sectors < SETUP_SECT_MIN) | 268 | if (setup_sectors < SETUP_SECT_MIN) |
@@ -170,6 +270,10 @@ int main(int argc, char ** argv) | |||
170 | i = setup_sectors*512; | 270 | i = setup_sectors*512; |
171 | memset(buf+c, 0, i-c); | 271 | memset(buf+c, 0, i-c); |
172 | 272 | ||
273 | #ifdef CONFIG_EFI_STUB | ||
274 | update_pecoff_setup_and_reloc(i); | ||
275 | #endif | ||
276 | |||
173 | /* Set the default root device */ | 277 | /* Set the default root device */ |
174 | put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); | 278 | put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); |
175 | 279 | ||
@@ -194,66 +298,8 @@ int main(int argc, char ** argv) | |||
194 | put_unaligned_le32(sys_size, &buf[0x1f4]); | 298 | put_unaligned_le32(sys_size, &buf[0x1f4]); |
195 | 299 | ||
196 | #ifdef CONFIG_EFI_STUB | 300 | #ifdef CONFIG_EFI_STUB |
197 | file_sz = sz + i + ((sys_size * 16) - sz); | 301 | update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz)); |
198 | 302 | #endif | |
199 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
200 | |||
201 | /* Size of image */ | ||
202 | put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); | ||
203 | |||
204 | /* | ||
205 | * Subtract the size of the first section (512 bytes) which | ||
206 | * includes the header and .reloc section. The remaining size | ||
207 | * is that of the .text section. | ||
208 | */ | ||
209 | file_sz -= 512; | ||
210 | |||
211 | /* Size of code */ | ||
212 | put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]); | ||
213 | |||
214 | #ifdef CONFIG_X86_32 | ||
215 | /* | ||
216 | * Address of entry point. | ||
217 | * | ||
218 | * The EFI stub entry point is +16 bytes from the start of | ||
219 | * the .text section. | ||
220 | */ | ||
221 | put_unaligned_le32(i + 16, &buf[pe_header + 0x28]); | ||
222 | |||
223 | /* .text size */ | ||
224 | put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]); | ||
225 | |||
226 | /* .text vma */ | ||
227 | put_unaligned_le32(0x200, &buf[pe_header + 0xb4]); | ||
228 | |||
229 | /* .text size of initialised data */ | ||
230 | put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]); | ||
231 | |||
232 | /* .text file offset */ | ||
233 | put_unaligned_le32(0x200, &buf[pe_header + 0xbc]); | ||
234 | #else | ||
235 | /* | ||
236 | * Address of entry point. startup_32 is at the beginning and | ||
237 | * the 64-bit entry point (startup_64) is always 512 bytes | ||
238 | * after. The EFI stub entry point is 16 bytes after that, as | ||
239 | * the first instruction allows legacy loaders to jump over | ||
240 | * the EFI stub initialisation | ||
241 | */ | ||
242 | put_unaligned_le32(i + 528, &buf[pe_header + 0x28]); | ||
243 | |||
244 | /* .text size */ | ||
245 | put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]); | ||
246 | |||
247 | /* .text vma */ | ||
248 | put_unaligned_le32(0x200, &buf[pe_header + 0xc4]); | ||
249 | |||
250 | /* .text size of initialised data */ | ||
251 | put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]); | ||
252 | |||
253 | /* .text file offset */ | ||
254 | put_unaligned_le32(0x200, &buf[pe_header + 0xcc]); | ||
255 | #endif /* CONFIG_X86_32 */ | ||
256 | #endif /* CONFIG_EFI_STUB */ | ||
257 | 303 | ||
258 | crc = partial_crc32(buf, i, crc); | 304 | crc = partial_crc32(buf, i, crc); |
259 | if (fwrite(buf, 1, i, stdout) != i) | 305 | if (fwrite(buf, 1, i, stdout) != i) |