diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/openbios/libopenbios/aout_load.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/openbios/libopenbios/aout_load.c')
-rw-r--r-- | roms/openbios/libopenbios/aout_load.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/roms/openbios/libopenbios/aout_load.c b/roms/openbios/libopenbios/aout_load.c new file mode 100644 index 000000000..548a9f8c0 --- /dev/null +++ b/roms/openbios/libopenbios/aout_load.c @@ -0,0 +1,178 @@ +/* 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 !"); +} |