ppc64: Don't set Kp bit on SLB
[openbios.git] / libopenbios / elf_load.c
blob9c7850e117cf8a19d36daa8fd0babd4151681450
1 /* ELF Boot loader
2 * As we have seek, this implementation can be straightforward.
3 * 2003-07 by SONE Takeshi
4 */
6 #include "config.h"
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"
15 #define printf printk
16 #define debug printk
18 #define DEBUG 0
20 #define MAX_HEADERS 0x20
21 #define BS 0x100 /* smallest step used when looking for the ELF header */
23 #ifdef CONFIG_PPC
24 extern void flush_icache_range( char *start, char *stop );
25 #endif
27 /* FreeBSD and possibly others mask the high 8 bits */
28 #define addr_fixup(addr) ((addr) & 0x00ffffff)
30 static char *image_name, *image_version;
31 static int fd;
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;
37 void *mem;
39 if (alloc_size < nmemb || alloc_size < size) {
40 printf("calloc overflow: %u, %u\n", nmemb, size);
41 return NULL;
44 mem = malloc(alloc_size);
45 memset(mem, 0, alloc_size);
47 return mem;
50 static int check_mem_ranges(struct sys_info *info,
51 Elf_phdr *phdr, int phnum)
53 int i, j;
54 unsigned long start, end;
55 unsigned long prog_start, prog_end;
56 struct memrange *mem;
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)
63 continue;
64 start = addr_fixup(phdr[i].p_paddr);
65 end = start + phdr[i].p_memsz;
66 if (start < prog_start && end > prog_start)
67 goto conflict;
68 if (start < prog_end && end > prog_end)
69 goto conflict;
70 mem=info->memrange;
71 for (j = 0; j < info->n_memranges; j++) {
72 if (mem[j].base <= start && mem[j].base + mem[j].size >= end)
73 break;
75 if (j >= info->n_memranges)
76 goto badseg;
78 return 1;
80 conflict:
81 printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
83 badseg:
84 printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
85 return 0;
88 static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
89 unsigned short *sum_ptr,
90 unsigned int offset)
92 int i;
93 char *buf = NULL;
94 int retval = 0;
95 unsigned long addr, end;
96 Elf_Nhdr *nhdr;
97 const char *name;
98 void *desc;
100 for (i = 0; i < phnum; i++) {
101 if (phdr[i].p_type != PT_NOTE)
102 continue;
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");
107 goto out;
109 addr = (unsigned long) buf;
110 end = addr + phdr[i].p_filesz;
111 while (addr < end) {
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;
139 out:
140 close_io(fd);
141 if (buf)
142 free(buf);
143 return retval;
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;
151 int i;
153 *bytes = 0;
154 // start_time = currticks();
155 for (i = 0; i < phnum; i++) {
156 if (phdr[i].p_type != PT_LOAD)
157 continue;
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);
165 return 0;
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);
177 debug("ok\n");
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);
185 return 1;
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;
193 int i;
195 sum = 0;
196 offset = 0;
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)
208 continue;
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",
216 image_sum, sum);
217 return 0;
219 return 1;
222 static inline unsigned padded(unsigned s)
224 return (s + 3) & ~3;
227 static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
228 unsigned type, const char *desc, unsigned descsz)
230 Elf_Nhdr nhdr;
231 unsigned ent_size, new_size, pad;
232 char *addr;
234 if (!bhdr)
235 return NULL;
237 nhdr.n_namesz = name? strlen(name)+1 : 0;
238 nhdr.n_descsz = descsz;
239 nhdr.n_type = type;
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");
243 free(bhdr);
244 return NULL;
246 if (bhdr->b_size + ent_size > bhdr->b_checksum) {
247 do {
248 new_size = bhdr->b_checksum * 2;
249 } while (new_size < bhdr->b_size + ent_size);
250 if (new_size > 0xffff)
251 new_size = 0xffff;
252 debug("expanding boot note size to %u\n", new_size);
253 #ifdef HAVE_REALLOC
254 bhdr = realloc(bhdr, new_size);
255 bhdr->b_checksum = new_size;
256 #else
257 printf("Boot notes too big\n");
258 free(bhdr);
259 return NULL;
260 #endif
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);
273 addr += 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;
282 bhdr->b_records++;
283 return bhdr;
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)
294 Elf_Bhdr *bhdr;
296 bhdr = malloc(256);
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 */
300 bhdr->b_records = 0;
302 if (info->firmware)
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);
306 if (cmdline)
307 bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline);
308 if (!bhdr)
309 return bhdr;
310 bhdr->b_checksum = 0;
311 bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size);
312 return bhdr;
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)
334 int offset;
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");
339 return 0;
342 if (is_elf(ehdr)) {
343 debug("Found ELF header at offset %d\n", offset);
344 return offset;
347 seek_io(fd, offset);
350 debug("Not a bootable ELF image\n");
351 return 0;
354 Elf_phdr *
355 elf_readhdrs(int offset, Elf_ehdr *ehdr)
357 unsigned long phdr_size;
358 Elf_phdr *phdr;
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");
365 return NULL;
368 return phdr;
371 int
372 elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_notes)
374 Elf_ehdr ehdr;
375 Elf_phdr *phdr = NULL;
376 unsigned long checksum_offset, file_size;
377 unsigned short checksum = 0;
378 int retval = -1;
379 unsigned int offset;
381 image_name = image_version = NULL;
383 /* Mark the saved-program-state as invalid */
384 feval("0 state-valid !");
386 fd = open_ih(dev);
387 if (fd == -1) {
388 goto out;
391 offset = find_elf(&ehdr);
392 if (!offset) {
393 retval = LOADER_NOT_SUPPORT;
394 goto out;
397 #if DEBUG
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);
409 #endif
411 if (ehdr.e_phnum > MAX_HEADERS) {
412 printk ("elfload: too many program headers (MAX_HEADERS)\n");
413 retval = 0;
414 goto out;
417 phdr = elf_readhdrs(offset, &ehdr);
418 if (!phdr)
419 goto out;
421 if (!check_mem_ranges(info, phdr, ehdr.e_phnum))
422 goto out;
424 checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum, offset);
426 printf("Loading %s", image_name ? image_name : "image");
427 if (image_version)
428 printf(" version %s", image_version);
429 printf("...\n");
431 if (!load_segments(phdr, ehdr.e_phnum, checksum_offset, offset, &file_size))
432 goto out;
434 if (checksum_offset) {
435 if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
436 goto out;
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
441 ELF */
442 if (boot_notes) {
443 *boot_notes = (void *)virt_to_phys(build_boot_notes(info, cmdline));
444 feval("elf-boot saved-program-state >sps.file-type !");
445 } else {
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 !");
456 PUSH(file_size);
457 feval("saved-program-state >sps.file-size !");
459 feval("-1 state-valid !");
461 out:
462 close_io(fd);
463 if (phdr)
464 free(phdr);
465 if (image_name)
466 free(image_name);
467 if (image_version)
468 free(image_version);
469 return retval;
472 void
473 elf_init_program(void)
475 char *base;
476 int i;
477 Elf_ehdr *ehdr;
478 Elf_phdr *phdr;
479 size_t size, total_size = 0;
480 char *addr;
481 uintptr_t tmp;
483 /* TODO: manage ELF notes section */
484 feval("0 state-valid !");
485 feval("load-base");
486 base = (char*)cell2pointer(POP());
488 ehdr = (Elf_ehdr *)base;
490 if (!is_elf(ehdr)) {
491 debug("Not a valid ELF memory image\n");
492 return;
495 phdr = (Elf_phdr *)(base + ehdr->e_phoff);
497 for (i = 0; i < ehdr->e_phnum; i++) {
499 #if DEBUG
500 debug("filesz: %08lX memsz: %08lX p_offset: %08lX "
501 "p_vaddr %08lX\n",
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 );
504 #endif
506 size = MIN(phdr[i].p_filesz, phdr[i].p_memsz);
507 if (!size)
508 continue;
509 #if !defined(CONFIG_SPARC32) && !defined(CONFIG_X86)
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);
515 #endif
516 /* Workaround for archs where sizeof(int) != pointer size */
517 tmp = phdr[i].p_vaddr;
518 addr = (char *)tmp;
520 memcpy(addr, base + phdr[i].p_offset, size);
522 total_size += size;
524 #ifdef CONFIG_PPC
525 flush_icache_range( addr, addr + size );
526 #endif
529 // Initialise saved-program-state
530 PUSH(ehdr->e_entry);
531 feval("saved-program-state >sps.entry !");
532 PUSH(total_size);
533 feval("saved-program-state >sps.file-size !");
534 feval("elf saved-program-state >sps.file-type !");
536 feval("-1 state-valid !");