VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/Etherboot-src/filo/main/elfload.c@ 566

Last change on this file since 566 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* ELF Boot loader
2 * As we have seek, this implementation can be straightforward.
3 * 2003-07 by SONE Takeshi
4 */
5#include <etherboot.h>
6#include <elf.h>
7#include <bits/elf_x.h>
8#include <elf_boot.h>
9#include <lib.h>
10#include <sys_info.h>
11
12#include <fs.h>
13#define DEBUG_THIS DEBUG_ELFBOOT
14#include <debug.h>
15
16#if 1
17//Use that in Etherboot
18extern int elf_start(unsigned long __unused_i386, unsigned long entry, unsigned long param);
19#define start_elf(x,y) elf_start(0, x, y)
20#else
21// original in filo
22extern unsigned int start_elf(unsigned long entry_point, unsigned long param);
23#endif
24
25extern char _virt_start[], _end[];
26
27static char *image_name, *image_version;
28
29static int check_mem_ranges(struct sys_info *info,
30 Elf_phdr *phdr, int phnum)
31{
32 int i, j;
33 unsigned long start, end;
34 unsigned long prog_start, prog_end;
35#if 0
36 struct memrange *mem;
37#else
38 struct e820entry *mem;
39#endif
40
41 prog_start = virt_to_phys(&_virt_start);
42 prog_end = virt_to_phys(&_end);
43
44 for (i = 0; i < phnum; i++) {
45 if (phdr[i].p_type != PT_LOAD)
46 continue;
47 start = phdr[i].p_paddr;
48 end = start + phdr[i].p_memsz;
49 if (start < prog_start && end > prog_start)
50 goto conflict;
51 if (start < prog_end && end > prog_end)
52 goto conflict;
53#if 0
54 for (j = 0; j < info->n_memranges; j++) {
55 mem = &info->memrange[j];
56 if (mem->base <= start && mem->base + mem->size >= end)
57 break;
58 }
59 if (j >= info->n_memranges)
60 goto badseg;
61#else
62#define LB_MEM_RAM 1
63 for (j = 0; j < meminfo.map_count; j++) {
64 mem = &meminfo.map[j];
65 if (mem->type!=LB_MEM_RAM) continue;
66 if (mem->addr <= start && mem->addr + mem->size >= end)
67 break;
68 }
69 if (j >= meminfo.map_count)
70 goto badseg;
71#endif
72 }
73 return 1;
74
75conflict:
76 printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
77
78badseg:
79 printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
80 return 0;
81}
82
83static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
84 unsigned short *sum_ptr)
85{
86 int i;
87 char *buf = NULL;
88 int retval = 0;
89 unsigned long addr, end;
90 Elf_Nhdr *nhdr;
91 const char *name;
92 void *desc;
93
94 for (i = 0; i < phnum; i++) {
95 if (phdr[i].p_type != PT_NOTE)
96 continue;
97 buf = allot(phdr[i].p_filesz);
98 file_seek(phdr[i].p_offset);
99 if (file_read(buf, phdr[i].p_filesz) != phdr[i].p_filesz) {
100 printf("Can't read note segment\n");
101 goto out;
102 }
103 addr = (unsigned long) buf;
104 end = addr + phdr[i].p_filesz;
105 while (addr < end) {
106 nhdr = (Elf_Nhdr *) addr;
107 addr += sizeof(Elf_Nhdr);
108 name = (const char *) addr;
109 addr += (nhdr->n_namesz+3) & ~3;
110 desc = (void *) addr;
111 addr += (nhdr->n_descsz+3) & ~3;
112
113 if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT)
114 && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) {
115 if (nhdr->n_type == EIN_PROGRAM_NAME) {
116 image_name = calloc(1, nhdr->n_descsz + 1);
117 memcpy(image_name, desc, nhdr->n_descsz);
118 }
119 if (nhdr->n_type == EIN_PROGRAM_VERSION) {
120 image_version = calloc(1, nhdr->n_descsz + 1);
121 memcpy(image_version, desc, nhdr->n_descsz);
122 }
123 if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) {
124 *sum_ptr = *(unsigned short *) desc;
125 debug("Image checksum: %04x\n", *sum_ptr);
126 /* Where in the file */
127 retval = phdr[i].p_offset
128 + (unsigned long) desc - (unsigned long) buf;
129 }
130 }
131 }
132 }
133out:
134 if (buf)
135 forget(buf);
136 return retval;
137}
138
139static int load_segments(Elf_phdr *phdr, int phnum,
140 unsigned long checksum_offset)
141{
142 unsigned long bytes;
143 unsigned int start_time, time;
144 int i;
145 int j;
146
147 bytes = 0;
148 start_time = currticks();
149#if 0
150 for (j = 0; j < phnum; j++) {
151 if (phdr[j].p_type != PT_LOAD)
152 continue;
153 debug("0 segment %d addr:%#x file:%#x mem:%#x, phdr%#x\n",
154 j, phdr[j].p_paddr, phdr[j].p_filesz, phdr[j].p_memsz, virt_to_phys(&phdr[j]));
155 }
156#endif
157
158 for (i = 0; i < phnum; i++) {
159 if (phdr[i].p_type != PT_LOAD)
160 continue;
161 debug("segment %d addr:%#x file:%#x mem:%#x phdr:%#x ",
162 i, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz, virt_to_phys(&phdr[i]));
163 file_seek(phdr[i].p_offset);
164 debug("loading... ");
165 if (file_read(phys_to_virt(phdr[i].p_paddr), phdr[i].p_filesz)
166 != phdr[i].p_filesz) {
167 printf("Can't read program segment %d\n", i);
168 return 0;
169 }
170 bytes += phdr[i].p_filesz;
171 debug("clearing... ");
172 memset(phys_to_virt(phdr[i].p_paddr + phdr[i].p_filesz), 0,
173 phdr[i].p_memsz - phdr[i].p_filesz);
174 if (phdr[i].p_offset <= checksum_offset
175 && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) {
176 debug("clearing checksum... ");
177 memset(phys_to_virt(phdr[i].p_paddr + checksum_offset
178 - phdr[i].p_offset), 0, 2);
179 }
180 debug("ok\n");
181
182 }
183 time = (currticks() - start_time)*1000/18;
184 printf("Loaded %d bytes in %dms (%dKB/s)\n", bytes, time,
185 time? bytes/time : 0);
186 return 1;
187}
188
189static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum,
190 unsigned short image_sum)
191{
192 unsigned short sum, part_sum;
193 unsigned long offset;
194 int i;
195
196 sum = 0;
197 offset = 0;
198
199 part_sum = ipchksum(ehdr, sizeof *ehdr);
200 sum = add_ipchksums(offset, sum, part_sum);
201 offset += sizeof *ehdr;
202
203 part_sum = ipchksum(phdr, phnum * sizeof(*phdr));
204 sum = add_ipchksums(offset, sum, part_sum);
205 offset += phnum * sizeof(*phdr);
206
207 for (i = 0; i < phnum; i++) {
208 if (phdr[i].p_type != PT_LOAD)
209 continue;
210 part_sum = ipchksum(phys_to_virt(phdr[i].p_paddr), phdr[i].p_memsz);
211 sum = add_ipchksums(offset, sum, part_sum);
212 offset += phdr[i].p_memsz;
213 }
214
215 if (sum != image_sum) {
216 printf("Verify FAILED (image:%04x vs computed:%04x)\n",
217 image_sum, sum);
218 return 0;
219 }
220 return 1;
221}
222
223static inline unsigned const padded(unsigned s)
224{
225 return (s + 3) & ~3;
226}
227
228static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
229 unsigned type, const char *desc, unsigned descsz)
230{
231 Elf_Nhdr nhdr;
232 unsigned ent_size, new_size, pad;
233 char *addr;
234
235 if (!bhdr)
236 return NULL;
237
238 nhdr.n_namesz = name? strlen(name)+1 : 0;
239 nhdr.n_descsz = descsz;
240 nhdr.n_type = type;
241 ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz);
242 if (bhdr->b_size + ent_size > 0xffff) {
243 printf("Boot notes too big\n");
244 forget(bhdr);
245 return NULL;
246 }
247 if (bhdr->b_size + ent_size > bhdr->b_checksum) {
248 do {
249 new_size = bhdr->b_checksum * 2;
250 } while (new_size < bhdr->b_size + ent_size);
251 if (new_size > 0xffff)
252 new_size = 0xffff;
253 debug("expanding boot note size to %u\n", new_size);
254 bhdr = realloc(bhdr, new_size);
255 bhdr->b_checksum = new_size;
256 }
257
258 addr = (char *) bhdr;
259 addr += bhdr->b_size;
260 memcpy(addr, &nhdr, sizeof(nhdr));
261 addr += sizeof(nhdr);
262
263 memcpy(addr, name, nhdr.n_namesz);
264 addr += nhdr.n_namesz;
265 pad = padded(nhdr.n_namesz) - nhdr.n_namesz;
266 memset(addr, 0, pad);
267 addr += pad;
268
269 memcpy(addr, desc, nhdr.n_descsz);
270 addr += nhdr.n_descsz;
271 pad = padded(nhdr.n_descsz) - nhdr.n_descsz;
272 memset(addr, 0, pad);
273 addr += pad;
274
275 bhdr->b_size += ent_size;
276 bhdr->b_records++;
277 return bhdr;
278}
279
280static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name,
281 unsigned type, const char *desc)
282{
283 return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1);
284}
285
286static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline)
287{
288 Elf_Bhdr *bhdr;
289
290 bhdr = allot(256);
291 bhdr->b_signature = ELF_BHDR_MAGIC;
292 bhdr->b_size = sizeof *bhdr;
293 bhdr->b_checksum = 256; /* XXX cache the current buffer size here */
294 bhdr->b_records = 0;
295
296 if (info->firmware)
297 bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware);
298 bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name);
299 bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version);
300 if (cmdline)
301 bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline);
302 if (!bhdr)
303 return bhdr;
304 bhdr->b_checksum = 0;
305 bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size);
306 return bhdr;
307}
308
309int elf_load(struct sys_info *info, const char *filename, const char *cmdline)
310{
311 Elf_ehdr ehdr;
312 Elf_phdr *phdr = NULL;
313 unsigned long phdr_size;
314 unsigned long checksum_offset;
315 unsigned short checksum;
316 Elf_Bhdr *boot_notes = NULL;
317 int retval = -1;
318 int image_retval;
319
320 image_name = image_version = 0;
321
322 if (!file_open(filename))
323 goto out;
324
325 if (file_read(&ehdr, sizeof ehdr) != sizeof ehdr) {
326 debug("Can't read ELF header\n");
327 retval = LOADER_NOT_SUPPORT;
328 goto out;
329 }
330
331 if (ehdr.e_ident[EI_MAG0] != ELFMAG0
332 || ehdr.e_ident[EI_MAG1] != ELFMAG1
333 || ehdr.e_ident[EI_MAG2] != ELFMAG2
334 || ehdr.e_ident[EI_MAG3] != ELFMAG3
335 || ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS
336 || ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA
337 || ehdr.e_ident[EI_VERSION] != EV_CURRENT
338 || ehdr.e_type != ET_EXEC
339 || !ARCH_ELF_MACHINE_OK(ehdr.e_machine)
340 || ehdr.e_version != EV_CURRENT
341 || ehdr.e_phentsize != sizeof(Elf_phdr)) {
342 debug("Not a bootable ELF image\n");
343 retval = LOADER_NOT_SUPPORT;
344 goto out;
345 }
346
347 phdr_size = ehdr.e_phnum * sizeof *phdr;
348 phdr = allot(phdr_size);//hack LYH otherwise some one clear the last entry
349 file_seek(ehdr.e_phoff);
350 if (file_read(phdr, phdr_size) != phdr_size) {
351 printf("Can't read program header\n");
352 goto out;
353 }
354
355 if (!check_mem_ranges(info, phdr, ehdr.e_phnum))
356 goto out;
357
358 checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum);
359
360 printf("Loading %s", image_name ? image_name : "image");
361 if (image_version)
362 printf(" version %s", image_version);
363 printf("...\n");
364
365 if (!load_segments(phdr, ehdr.e_phnum, checksum_offset))
366 goto out;
367
368 if (checksum_offset) {
369 if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
370 goto out;
371 }
372
373 boot_notes = build_boot_notes(info, cmdline);
374
375 debug("current time: %x\n", currticks());
376
377 debug("entry point is %#x\n", ehdr.e_entry);
378 printf("Jumping to entry point...\n");
379
380 image_retval = start_elf(ehdr.e_entry, virt_to_phys(boot_notes));
381#if 0
382 console_init();
383#endif
384
385 printf("Image returned with return value %#x\n", image_retval);
386 retval = 0;
387
388out:
389 if (phdr)
390 forget(phdr);
391 if (boot_notes)
392 forget(boot_notes);
393 if (image_name)
394 forget(image_name);
395 if (image_version)
396 forget(image_version);
397 return retval;
398}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette