2 * As we have seek, this implementation can be straightforward.
3 * 2003-07 by SONE Takeshi
7 #include "kernel/kernel.h"
8 #include "libc/diskio.h"
9 #include "arch/common/elf_boot.h"
10 #include "libopenbios/elf_load.h"
11 #include "libopenbios/sys_info.h"
12 #include "libopenbios/ipchecksum.h"
13 #include "libopenbios/bindings.h"
14 #include "libopenbios/ofmem.h"
20 #define MAX_HEADERS 0x20
21 #define BS 0x100 /* smallest step used when looking for the ELF header */
24 extern void flush_icache_range( char *start
, char *stop
);
27 /* FreeBSD and possibly others mask the high 8 bits */
28 #define addr_fixup(addr) ((addr) & 0x00ffffff)
30 static char *image_name
, *image_version
;
33 /* Note: avoid name collision with platforms which have their own version of calloc() */
34 static void *ob_calloc(size_t nmemb
, size_t size
)
36 size_t alloc_size
= nmemb
* size
;
39 if (alloc_size
< nmemb
|| alloc_size
< size
) {
40 printf("calloc overflow: %u, %u\n", nmemb
, size
);
44 mem
= malloc(alloc_size
);
45 memset(mem
, 0, alloc_size
);
50 static int check_mem_ranges(struct sys_info
*info
,
51 Elf_phdr
*phdr
, int phnum
)
54 unsigned long start
, end
;
55 unsigned long prog_start
, prog_end
;
58 prog_start
= virt_to_phys(&_start
);
59 prog_end
= virt_to_phys(&_end
);
61 for (i
= 0; i
< phnum
; i
++) {
62 if (phdr
[i
].p_type
!= PT_LOAD
)
64 start
= addr_fixup(phdr
[i
].p_paddr
);
65 end
= start
+ phdr
[i
].p_memsz
;
66 if (start
< prog_start
&& end
> prog_start
)
68 if (start
< prog_end
&& end
> prog_end
)
71 for (j
= 0; j
< info
->n_memranges
; j
++) {
72 if (mem
[j
].base
<= start
&& mem
[j
].base
+ mem
[j
].size
>= end
)
75 if (j
>= info
->n_memranges
)
81 printf("%s occupies [%#lx-%#lx]\n", program_name
, prog_start
, prog_end
);
84 printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i
, start
, end
-1);
88 static unsigned long process_image_notes(Elf_phdr
*phdr
, int phnum
,
89 unsigned short *sum_ptr
,
95 unsigned long addr
, end
;
100 for (i
= 0; i
< phnum
; i
++) {
101 if (phdr
[i
].p_type
!= PT_NOTE
)
103 buf
= malloc(phdr
[i
].p_filesz
);
104 seek_io(fd
, offset
+ phdr
[i
].p_offset
);
105 if ((size_t)read_io(fd
, buf
, phdr
[i
].p_filesz
) != phdr
[i
].p_filesz
) {
106 printf("Can't read note segment\n");
109 addr
= (unsigned long) buf
;
110 end
= addr
+ phdr
[i
].p_filesz
;
112 nhdr
= (Elf_Nhdr
*) addr
;
113 addr
+= sizeof(Elf_Nhdr
);
114 name
= (const char *) addr
;
115 addr
+= (nhdr
->n_namesz
+3) & ~3;
116 desc
= (void *) addr
;
117 addr
+= (nhdr
->n_descsz
+3) & ~3;
119 if (nhdr
->n_namesz
==sizeof(ELF_NOTE_BOOT
)
120 && memcmp(name
, ELF_NOTE_BOOT
, sizeof(ELF_NOTE_BOOT
))==0) {
121 if (nhdr
->n_type
== EIN_PROGRAM_NAME
) {
122 image_name
= ob_calloc(1, nhdr
->n_descsz
+ 1);
123 memcpy(image_name
, desc
, nhdr
->n_descsz
);
125 if (nhdr
->n_type
== EIN_PROGRAM_VERSION
) {
126 image_version
= ob_calloc(1, nhdr
->n_descsz
+ 1);
127 memcpy(image_version
, desc
, nhdr
->n_descsz
);
129 if (nhdr
->n_type
== EIN_PROGRAM_CHECKSUM
) {
130 *sum_ptr
= *(unsigned short *) desc
;
131 debug("Image checksum: %#04x\n", *sum_ptr
);
132 /* Where in the file */
133 retval
= phdr
[i
].p_offset
134 + (unsigned long) desc
- (unsigned long) buf
;
146 static int load_segments(Elf_phdr
*phdr
, int phnum
,
147 unsigned long checksum_offset
,
148 unsigned int offset
, unsigned long *bytes
)
150 //unsigned int start_time, time;
154 // start_time = currticks();
155 for (i
= 0; i
< phnum
; i
++) {
156 if (phdr
[i
].p_type
!= PT_LOAD
)
158 debug("segment %d addr:" FMT_elf
" file:" FMT_elf
" mem:" FMT_elf
" ",
159 i
, addr_fixup(phdr
[i
].p_paddr
), phdr
[i
].p_filesz
, phdr
[i
].p_memsz
);
160 seek_io(fd
, offset
+ phdr
[i
].p_offset
);
161 debug("loading... ");
162 if ((size_t)read_io(fd
, phys_to_virt(addr_fixup(phdr
[i
].p_paddr
)), phdr
[i
].p_filesz
)
163 != phdr
[i
].p_filesz
) {
164 printf("Can't read program segment %d\n", i
);
167 bytes
+= phdr
[i
].p_filesz
;
168 debug("clearing... ");
169 memset(phys_to_virt(addr_fixup(phdr
[i
].p_paddr
) + phdr
[i
].p_filesz
), 0,
170 phdr
[i
].p_memsz
- phdr
[i
].p_filesz
);
171 if (phdr
[i
].p_offset
<= checksum_offset
172 && phdr
[i
].p_offset
+ phdr
[i
].p_filesz
>= checksum_offset
+2) {
173 debug("clearing checksum... ");
174 memset(phys_to_virt(addr_fixup(phdr
[i
].p_paddr
) + checksum_offset
175 - phdr
[i
].p_offset
), 0, 2);
180 // time = currticks() - start_time;
181 //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time,
182 // time? bytes/time : 0);
183 debug("Loaded %lu bytes \n", *bytes
);
188 static int verify_image(Elf_ehdr
*ehdr
, Elf_phdr
*phdr
, int phnum
,
189 unsigned short image_sum
)
191 unsigned short sum
, part_sum
;
192 unsigned long offset
;
198 part_sum
= ipchksum(ehdr
, sizeof *ehdr
);
199 sum
= add_ipchksums(offset
, sum
, part_sum
);
200 offset
+= sizeof *ehdr
;
202 part_sum
= ipchksum(phdr
, phnum
* sizeof(*phdr
));
203 sum
= add_ipchksums(offset
, sum
, part_sum
);
204 offset
+= phnum
* sizeof(*phdr
);
206 for (i
= 0; i
< phnum
; i
++) {
207 if (phdr
[i
].p_type
!= PT_LOAD
)
209 part_sum
= ipchksum(phys_to_virt(addr_fixup(phdr
[i
].p_paddr
)), phdr
[i
].p_memsz
);
210 sum
= add_ipchksums(offset
, sum
, part_sum
);
211 offset
+= phdr
[i
].p_memsz
;
214 if (sum
!= image_sum
) {
215 printf("Verify FAILED (image:%#04x vs computed:%#04x)\n",
222 static inline unsigned padded(unsigned s
)
227 static Elf_Bhdr
*add_boot_note(Elf_Bhdr
*bhdr
, const char *name
,
228 unsigned type
, const char *desc
, unsigned descsz
)
231 unsigned ent_size
, new_size
, pad
;
237 nhdr
.n_namesz
= name
? strlen(name
)+1 : 0;
238 nhdr
.n_descsz
= descsz
;
240 ent_size
= sizeof(nhdr
) + padded(nhdr
.n_namesz
) + padded(nhdr
.n_descsz
);
241 if (bhdr
->b_size
+ ent_size
> 0xffff) {
242 printf("Boot notes too big\n");
246 if (bhdr
->b_size
+ ent_size
> bhdr
->b_checksum
) {
248 new_size
= bhdr
->b_checksum
* 2;
249 } while (new_size
< bhdr
->b_size
+ ent_size
);
250 if (new_size
> 0xffff)
252 debug("expanding boot note size to %u\n", new_size
);
254 bhdr
= realloc(bhdr
, new_size
);
255 bhdr
->b_checksum
= new_size
;
257 printf("Boot notes too big\n");
263 addr
= (char *) bhdr
;
264 addr
+= bhdr
->b_size
;
265 memcpy(addr
, &nhdr
, sizeof(nhdr
));
266 addr
+= sizeof(nhdr
);
268 if (name
&& nhdr
.n_namesz
) {
269 memcpy(addr
, name
, nhdr
.n_namesz
);
270 addr
+= nhdr
.n_namesz
;
271 pad
= padded(nhdr
.n_namesz
) - nhdr
.n_namesz
;
272 memset(addr
, 0, pad
);
276 memcpy(addr
, desc
, nhdr
.n_descsz
);
277 addr
+= nhdr
.n_descsz
;
278 pad
= padded(nhdr
.n_descsz
) - nhdr
.n_descsz
;
279 memset(addr
, 0, pad
);
281 bhdr
->b_size
+= ent_size
;
286 static inline Elf_Bhdr
*add_note_string(Elf_Bhdr
*bhdr
, const char *name
,
287 unsigned type
, const char *desc
)
289 return add_boot_note(bhdr
, name
, type
, desc
, strlen(desc
) + 1);
292 static Elf_Bhdr
*build_boot_notes(struct sys_info
*info
, const char *cmdline
)
297 bhdr
->b_signature
= ELF_BHDR_MAGIC
;
298 bhdr
->b_size
= sizeof *bhdr
;
299 bhdr
->b_checksum
= 256; /* XXX cache the current buffer size here */
303 bhdr
= add_note_string(bhdr
, NULL
, EBN_FIRMWARE_TYPE
, info
->firmware
);
304 bhdr
= add_note_string(bhdr
, NULL
, EBN_BOOTLOADER_NAME
, program_name
);
305 bhdr
= add_note_string(bhdr
, NULL
, EBN_BOOTLOADER_VERSION
, program_version
);
307 bhdr
= add_note_string(bhdr
, NULL
, EBN_COMMAND_LINE
, cmdline
);
310 bhdr
->b_checksum
= 0;
311 bhdr
->b_checksum
= ipchksum(bhdr
, bhdr
->b_size
);
316 is_elf(Elf_ehdr
*ehdr
)
318 return (ehdr
->e_ident
[EI_MAG0
] == ELFMAG0
319 && ehdr
->e_ident
[EI_MAG1
] == ELFMAG1
320 && ehdr
->e_ident
[EI_MAG2
] == ELFMAG2
321 && ehdr
->e_ident
[EI_MAG3
] == ELFMAG3
322 && ehdr
->e_ident
[EI_CLASS
] == ARCH_ELF_CLASS
323 && ehdr
->e_ident
[EI_DATA
] == ARCH_ELF_DATA
324 && ehdr
->e_ident
[EI_VERSION
] == EV_CURRENT
325 && ehdr
->e_type
== ET_EXEC
326 && ARCH_ELF_MACHINE_OK(ehdr
->e_machine
)
327 && ehdr
->e_version
== EV_CURRENT
328 && ehdr
->e_phentsize
== sizeof(Elf_phdr
));
332 find_elf(Elf_ehdr
*ehdr
)
336 for (offset
= 0; offset
< MAX_HEADERS
* BS
; offset
+= BS
) {
337 if ((size_t)read_io(fd
, ehdr
, sizeof ehdr
) != sizeof ehdr
) {
338 debug("Can't read ELF header\n");
343 debug("Found ELF header at offset %d\n", offset
);
350 debug("Not a bootable ELF image\n");
355 elf_readhdrs(int offset
, Elf_ehdr
*ehdr
)
357 unsigned long phdr_size
;
360 phdr_size
= ehdr
->e_phnum
* sizeof(Elf_phdr
);
361 phdr
= malloc(phdr_size
);
362 seek_io(fd
, offset
+ ehdr
->e_phoff
);
363 if ((size_t)read_io(fd
, phdr
, phdr_size
) != phdr_size
) {
364 printf("Can't read program header\n");
372 elf_load(struct sys_info
*info
, ihandle_t dev
, const char *cmdline
, void **boot_notes
)
375 Elf_phdr
*phdr
= NULL
;
376 unsigned long checksum_offset
, file_size
;
377 unsigned short checksum
= 0;
381 image_name
= image_version
= NULL
;
383 /* Mark the saved-program-state as invalid */
384 feval("0 state-valid !");
391 offset
= find_elf(&ehdr
);
393 retval
= LOADER_NOT_SUPPORT
;
398 printk("ELF header:\n");
399 printk(" ehdr.e_type = %d\n", (int)ehdr
.e_type
);
400 printk(" ehdr.e_machine = %d\n", (int)ehdr
.e_machine
);
401 printk(" ehdr.e_version = %d\n", (int)ehdr
.e_version
);
402 printk(" ehdr.e_entry = 0x%08x\n", (int)ehdr
.e_entry
);
403 printk(" ehdr.e_phoff = 0x%08x\n", (int)ehdr
.e_phoff
);
404 printk(" ehdr.e_shoff = 0x%08x\n", (int)ehdr
.e_shoff
);
405 printk(" ehdr.e_flags = %d\n", (int)ehdr
.e_flags
);
406 printk(" ehdr.e_ehsize = 0x%08x\n", (int)ehdr
.e_ehsize
);
407 printk(" ehdr.e_phentsize = 0x%08x\n", (int)ehdr
.e_phentsize
);
408 printk(" ehdr.e_phnum = %d\n", (int)ehdr
.e_phnum
);
411 if (ehdr
.e_phnum
> MAX_HEADERS
) {
412 printk ("elfload: too many program headers (MAX_HEADERS)\n");
417 phdr
= elf_readhdrs(offset
, &ehdr
);
421 if (!check_mem_ranges(info
, phdr
, ehdr
.e_phnum
))
424 checksum_offset
= process_image_notes(phdr
, ehdr
.e_phnum
, &checksum
, offset
);
426 printf("Loading %s", image_name
? image_name
: "image");
428 printf(" version %s", image_version
);
431 if (!load_segments(phdr
, ehdr
.e_phnum
, checksum_offset
, offset
, &file_size
))
434 if (checksum_offset
) {
435 if (!verify_image(&ehdr
, phdr
, ehdr
.e_phnum
, checksum
))
439 /* If we are attempting an ELF boot image, we pass a non-NULL pointer
440 into boot_notes and mark the image as elf-boot rather than standard
443 *boot_notes
= (void *)virt_to_phys(build_boot_notes(info
, cmdline
));
444 feval("elf-boot saved-program-state >sps.file-type !");
446 feval("elf saved-program-state >sps.file-type !");
449 //debug("current time: %lu\n", currticks());
451 debug("entry point is " FMT_elf
"\n", addr_fixup(ehdr
.e_entry
));
453 // Initialise saved-program-state
454 PUSH(addr_fixup(ehdr
.e_entry
));
455 feval("saved-program-state >sps.entry !");
457 feval("saved-program-state >sps.file-size !");
459 feval("-1 state-valid !");
473 elf_init_program(void)
479 size_t size
, total_size
= 0;
483 /* TODO: manage ELF notes section */
484 feval("0 state-valid !");
488 ehdr
= (Elf_ehdr
*)base
;
491 debug("Not a valid ELF memory image\n");
495 phdr
= (Elf_phdr
*)(base
+ ehdr
->e_phoff
);
497 for (i
= 0; i
< ehdr
->e_phnum
; i
++) {
500 debug("filesz: %08lX memsz: %08lX p_offset: %08lX "
502 (unsigned long)phdr
[i
].p_filesz
, (unsigned long)phdr
[i
].p_memsz
,
503 (unsigned long)phdr
[i
].p_offset
, (unsigned long)phdr
[i
].p_vaddr
);
506 size
= MIN(phdr
[i
].p_filesz
, phdr
[i
].p_memsz
);
509 #ifndef CONFIG_SPARC32
510 if( ofmem_claim( phdr
[i
].p_vaddr
, phdr
[i
].p_memsz
, 0 ) == -1 ) {
511 printk("Ignoring failed claim for va %lx memsz %lx!\n",
512 (unsigned long)phdr
[i
].p_vaddr
,
513 (unsigned long)phdr
[i
].p_memsz
);
516 /* Workaround for archs where sizeof(int) != pointer size */
517 tmp
= phdr
[i
].p_vaddr
;
520 memcpy(addr
, base
+ phdr
[i
].p_offset
, size
);
525 flush_icache_range( addr
, addr
+ size
);
529 // Initialise saved-program-state
531 feval("saved-program-state >sps.entry !");
533 feval("saved-program-state >sps.file-size !");
534 feval("elf saved-program-state >sps.file-type !");
536 feval("-1 state-valid !");