|
|
1.1 root 1: /* ELF Boot loader
2: * As we have seek, this implementation can be straightforward.
3: * 2003-07 by SONE Takeshi
4: */
5:
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
17:
18: #define DEBUG 0
19:
20: #define MAX_HEADERS 0x20
21: #define BS 0x100 /* smallest step used when looking for the ELF header */
22:
23: #ifdef CONFIG_PPC
24: extern void flush_icache_range( char *start, char *stop );
25: #endif
26:
27: /* FreeBSD and possibly others mask the high 8 bits */
28: #define addr_fixup(addr) ((addr) & 0x00ffffff)
29:
30: static char *image_name, *image_version;
31: static int fd;
32:
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)
35: {
36: size_t alloc_size = nmemb * size;
37: void *mem;
38:
39: if (alloc_size < nmemb || alloc_size < size) {
40: printf("calloc overflow: %u, %u\n", nmemb, size);
41: return NULL;
42: }
43:
44: mem = malloc(alloc_size);
45: memset(mem, 0, alloc_size);
46:
47: return mem;
48: }
49:
50: static int check_mem_ranges(struct sys_info *info,
51: Elf_phdr *phdr, int phnum)
52: {
53: int i, j;
54: unsigned long start, end;
55: unsigned long prog_start, prog_end;
56: struct memrange *mem;
57:
58: prog_start = virt_to_phys(&_start);
59: prog_end = virt_to_phys(&_end);
60:
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;
74: }
75: if (j >= info->n_memranges)
76: goto badseg;
77: }
78: return 1;
79:
80: conflict:
81: printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
82:
83: badseg:
84: printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
85: return 0;
86: }
87:
88: static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
89: unsigned short *sum_ptr,
90: unsigned int offset)
91: {
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;
99:
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;
108: }
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;
118:
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);
124: }
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);
128: }
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;
135: }
136: }
137: }
138: }
139: out:
140: close_io(fd);
141: if (buf)
142: free(buf);
143: return retval;
144: }
145:
146: static int load_segments(Elf_phdr *phdr, int phnum,
147: unsigned long checksum_offset,
148: unsigned int offset, unsigned long *bytes)
149: {
150: //unsigned int start_time, time;
151: int i;
152:
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;
166: }
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);
176: }
177: debug("ok\n");
178:
179: }
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);
184:
185: return 1;
186: }
187:
188: static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum,
189: unsigned short image_sum)
190: {
191: unsigned short sum, part_sum;
192: unsigned long offset;
193: int i;
194:
195: sum = 0;
196: offset = 0;
197:
198: part_sum = ipchksum(ehdr, sizeof *ehdr);
199: sum = add_ipchksums(offset, sum, part_sum);
200: offset += sizeof *ehdr;
201:
202: part_sum = ipchksum(phdr, phnum * sizeof(*phdr));
203: sum = add_ipchksums(offset, sum, part_sum);
204: offset += phnum * sizeof(*phdr);
205:
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;
212: }
213:
214: if (sum != image_sum) {
215: printf("Verify FAILED (image:%#04x vs computed:%#04x)\n",
216: image_sum, sum);
217: return 0;
218: }
219: return 1;
220: }
221:
222: static inline unsigned padded(unsigned s)
223: {
224: return (s + 3) & ~3;
225: }
226:
227: static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
228: unsigned type, const char *desc, unsigned descsz)
229: {
230: Elf_Nhdr nhdr;
231: unsigned ent_size, new_size, pad;
232: char *addr;
233:
234: if (!bhdr)
235: return NULL;
236:
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;
245: }
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
261: }
262:
263: addr = (char *) bhdr;
264: addr += bhdr->b_size;
265: memcpy(addr, &nhdr, sizeof(nhdr));
266: addr += sizeof(nhdr);
267:
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;
274: }
275:
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);
280:
281: bhdr->b_size += ent_size;
282: bhdr->b_records++;
283: return bhdr;
284: }
285:
286: static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name,
287: unsigned type, const char *desc)
288: {
289: return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1);
290: }
291:
292: static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline)
293: {
294: Elf_Bhdr *bhdr;
295:
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;
301:
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;
313: }
314:
315: int
316: is_elf(Elf_ehdr *ehdr)
317: {
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));
329: }
330:
331: int
332: find_elf(Elf_ehdr *ehdr)
333: {
334: int offset;
335:
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;
340: }
341:
342: if (is_elf(ehdr)) {
343: debug("Found ELF header at offset %d\n", offset);
344: return offset;
345: }
346:
347: seek_io(fd, offset);
348: }
349:
350: debug("Not a bootable ELF image\n");
351: return 0;
352: }
353:
354: Elf_phdr *
355: elf_readhdrs(int offset, Elf_ehdr *ehdr)
356: {
357: unsigned long phdr_size;
358: Elf_phdr *phdr;
359:
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;
366: }
367:
368: return phdr;
369: }
370:
371: int
372: elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_notes)
373: {
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;
380:
381: image_name = image_version = NULL;
382:
383: /* Mark the saved-program-state as invalid */
384: feval("0 state-valid !");
385:
386: fd = open_ih(dev);
387: if (fd == -1) {
388: goto out;
389: }
390:
391: offset = find_elf(&ehdr);
392: if (!offset) {
393: retval = LOADER_NOT_SUPPORT;
394: goto out;
395: }
396:
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
410:
411: if (ehdr.e_phnum > MAX_HEADERS) {
412: printk ("elfload: too many program headers (MAX_HEADERS)\n");
413: retval = 0;
414: goto out;
415: }
416:
417: phdr = elf_readhdrs(offset, &ehdr);
418: if (!phdr)
419: goto out;
420:
421: if (!check_mem_ranges(info, phdr, ehdr.e_phnum))
422: goto out;
423:
424: checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum, offset);
425:
426: printf("Loading %s", image_name ? image_name : "image");
427: if (image_version)
428: printf(" version %s", image_version);
429: printf("...\n");
430:
431: if (!load_segments(phdr, ehdr.e_phnum, checksum_offset, offset, &file_size))
432: goto out;
433:
434: if (checksum_offset) {
435: if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
436: goto out;
437: }
438:
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 !");
447: }
448:
449: //debug("current time: %lu\n", currticks());
450:
451: debug("entry point is " FMT_elf "\n", addr_fixup(ehdr.e_entry));
452:
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 !");
458:
459: feval("-1 state-valid !");
460:
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;
470: }
471:
472: void
473: elf_init_program(void)
474: {
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;
482:
483: /* TODO: manage ELF notes section */
484: feval("0 state-valid !");
485: feval("load-base");
486: base = (char*)cell2pointer(POP());
487:
488: ehdr = (Elf_ehdr *)base;
489:
490: if (!is_elf(ehdr)) {
491: debug("Not a valid ELF memory image\n");
492: return;
493: }
494:
495: phdr = (Elf_phdr *)(base + ehdr->e_phoff);
496:
497: for (i = 0; i < ehdr->e_phnum; i++) {
498:
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
505:
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);
514: }
515: #endif
516: /* Workaround for archs where sizeof(int) != pointer size */
517: tmp = phdr[i].p_vaddr;
518: addr = (char *)tmp;
519:
520: memcpy(addr, base + phdr[i].p_offset, size);
521:
522: total_size += size;
523:
524: #ifdef CONFIG_PPC
525: flush_icache_range( addr, addr + size );
526: #endif
527: }
528:
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 !");
535:
536: feval("-1 state-valid !");
537: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.