/* a.out boot loader * As we have seek, this implementation can be straightforward. * 2003-07 by SONE Takeshi */ #include "openbios/config.h" #include "openbios/kernel.h" #include "a.out.h" #include "sys_info.h" #include "loadfs.h" #define printf printk #define debug printk #define addr_fixup(addr) ((addr) & 0x00ffffff) static char *image_name, *image_version; const char *program_name, *program_version; static int check_mem_ranges(struct sys_info *info, unsigned long start, unsigned long size) { int j; unsigned long end; unsigned long prog_start, prog_end; struct memrange *mem; prog_start = virt_to_phys(&_start); prog_end = virt_to_phys(&_end); end = start + size; if (start < prog_start && end > prog_start) goto conflict; if (start < prog_end && end > prog_end) goto conflict; mem = info->memrange; for (j = 0; j < info->n_memranges; j++) { if (mem[j].base <= start && mem[j].base + mem[j].size >= end) break; } if (j >= info->n_memranges) goto badseg; return 1; conflict: printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end); badseg: printf("A.out file [%#lx-%#lx] doesn't fit into memory\n", start, end - 1); return 0; } int aout_load(struct sys_info *info, const char *filename, const char *cmdline) { int retval = -1; int image_retval; struct exec ehdr; unsigned long start, size; image_name = image_version = 0; if (!file_open(filename)) goto out; if (lfile_read(&ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read a.out header\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (N_BADMAG(ehdr)) { debug("Not a bootable a.out image\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (N_MAGIC(ehdr) == NMAGIC) { size = N_DATADDR(ehdr) + ehdr.a_data; } else { size = ehdr.a_text + ehdr.a_data; } start = 0x4000; // N_TXTADDR(ehdr); if (!check_mem_ranges(info, start, size)) goto out; printf("Loading a.out %s...\n", image_name ? image_name : "image"); file_seek(N_TXTOFF(ehdr)); if (N_MAGIC(ehdr) == NMAGIC) { if (lfile_read(start, ehdr.a_text) != ehdr.a_text) { printf("Can't read program text segment (size 0x%lx)\n", ehdr.a_text); goto out; } if (lfile_read(start + N_DATADDR(ehdr), ehdr.a_data) != ehdr.a_data) { printf("Can't read program data segment (size 0x%lx)\n", ehdr.a_data); goto out; } } else { if (lfile_read(start, size) != size) { printf("Can't read program (size 0x%lx)\n", size); goto out; } } debug("Loaded %lu bytes\n", size); debug("entry point is %#x\n", start); printf("Jumping to entry point...\n"); #if 1 { extern unsigned int qemu_mem_size; void *init_openprom(unsigned long memsize, const char *cmdline, char boot_device); int (*entry)(const void *romvec, int p2, int p3, int p4, int p5); const void *romvec; romvec = init_openprom(qemu_mem_size, cmdline, 'c'); entry = (void *) addr_fixup(start); image_retval = entry(romvec, 0, 0, 0, 0); } #endif printf("Image returned with return value %#x\n", image_retval); retval = 0; out: return retval; }