/* a.out boot loader * As we have seek, this implementation can be straightforward. * 2003-07 by SONE Takeshi */ #include "config.h" #include "kernel/kernel.h" #ifdef CONFIG_SPARC64 #define CONFIG_SPARC64_PAGE_SIZE_8KB #endif #include "libopenbios/sys_info.h" #include "libopenbios/bindings.h" #include "libopenbios/aout_load.h" #include "libopenbios/initprogram.h" #include "libc/diskio.h" #define printf printk #define debug printk #define addr_fixup(addr) ((addr) & 0x00ffffff) static char *image_name, *image_version; static int fd; 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 is_aout(struct exec *ehdr) { return ((ehdr->a_info & 0xffff) == OMAGIC || (ehdr->a_info & 0xffff) == NMAGIC || (ehdr->a_info & 0xffff) == ZMAGIC || (ehdr->a_info & 0xffff) == QMAGIC); } int aout_load(struct sys_info *info, ihandle_t dev) { int retval = -1; struct exec ehdr; unsigned long start, size; unsigned int offset; image_name = image_version = NULL; /* Mark the saved-program-state as invalid */ feval("0 state-valid !"); fd = open_ih(dev); if (fd == -1) { goto out; } for (offset = 0; offset < 16 * 512; offset += 512) { seek_io(fd, offset); if (read_io(fd, &ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read a.out header\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (is_aout(&ehdr)) break; } if (!is_aout(&ehdr)) { debug("Not a bootable a.out image\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (ehdr.a_text == 0x30800007) ehdr.a_text=64*1024; if (N_MAGIC(ehdr) == NMAGIC) { size = addr_fixup(N_DATADDR(ehdr)) + addr_fixup(ehdr.a_data); } else { size = addr_fixup(ehdr.a_text) + addr_fixup(ehdr.a_data); } if (size < 7680) size = 7680; fword("load-base"); start = POP(); // N_TXTADDR(ehdr); memcpy((void *)start, &ehdr, sizeof(ehdr)); if (!check_mem_ranges(info, start, size)) goto out; printf("Loading a.out %s...\n", image_name ? image_name : "image"); seek_io(fd, offset + N_TXTOFF(ehdr)); if (N_MAGIC(ehdr) == NMAGIC) { if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), ehdr.a_text) != ehdr.a_text) { printf("Can't read program text segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_text); goto out; } if ((size_t)read_io(fd, (void *)(start + N_DATADDR(ehdr)), ehdr.a_data) != ehdr.a_data) { printf("Can't read program data segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_data); goto out; } } else { if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), size) != size) { printf("Can't read program (size 0x" FMT_sizet ")\n", size); goto out; } } debug("Loaded %lu bytes\n", size); debug("entry point is %#lx\n", start); // Initialise saved-program-state PUSH(size); feval("load-state >ls.file-size !"); feval("aout load-state >ls.file-type !"); out: close_io(fd); return retval; } void aout_init_program(void) { ucell start, size; // Relocate a.out text down from load-base to load-base - header. This // is similar to what OBP does and is needed for NextStep. fword("load-base"); start = POP(); feval("load-state >ls.file-size @"); size = POP(); memmove((char *)start - sizeof(struct exec), (char *)start, size); PUSH(start); feval("load-state >ls.entry !"); arch_init_program(); feval("-1 state-valid !"); }