load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- include/libopenbios/xcoff_load.h | 2 +- libopenbios/load.c | 11 ++++ libopenbios/xcoff_load.c | 105 +++++++++++++++++++++++++++++++++++--- 3 files changed, 110 insertions(+), 8 deletions(-)
diff --git a/include/libopenbios/xcoff_load.h b/include/libopenbios/xcoff_load.h index 2ec693d..854d3ba 100644 --- a/include/libopenbios/xcoff_load.h +++ b/include/libopenbios/xcoff_load.h @@ -21,7 +21,7 @@ #include "libopenbios/sys_info.h"
extern int is_xcoff(COFF_filehdr_t *fhdr); -extern int xcoff_load(struct sys_info *info, const char *filename); +extern int xcoff_load(ihandle_t dev); extern void xcoff_init_program(void);
#endif /* _H_XCOFFLOAD */ diff --git a/libopenbios/load.c b/libopenbios/load.c index 048f459..174d221 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -37,6 +37,10 @@ #include "libopenbios/forth_load.h" #endif
+#ifdef CONFIG_LOADER_XCOFF +#include "libopenbios/xcoff_load.h" +#endif + #ifdef CONFIG_LOADER_BOOTCODE #include "libopenbios/bootcode_load.h" #endif @@ -94,6 +98,13 @@ void load(ihandle_t dev) } #endif
+#ifdef CONFIG_LOADER_XCOFF + if (xcoff_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; + } +#endif + #ifdef CONFIG_LOADER_BOOTCODE /* Check for a "raw" %BOOT bootcode payload */ if (bootcode_load(dev) != LOADER_NOT_SUPPORT) { diff --git a/libopenbios/xcoff_load.c b/libopenbios/xcoff_load.c index bd14343..11c67d9 100644 --- a/libopenbios/xcoff_load.c +++ b/libopenbios/xcoff_load.c @@ -16,7 +16,9 @@
#include "config.h" #include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/xcoff_load.h" +#include "libc/diskio.h"
#include "arch/common/xcoff.h"
@@ -44,10 +46,101 @@ is_xcoff(COFF_filehdr_t *fhdr) }
int -xcoff_load(struct sys_info *info, const char *filename) +xcoff_load(ihandle_t dev) { - // Currently not implemented - return LOADER_NOT_SUPPORT; + COFF_filehdr_t fhdr; + COFF_aouthdr_t ahdr; + COFF_scnhdr_t shdr; + uint32_t offset; + size_t total_size = 0; + int fd, i; + int retval = -1; + + /* 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, &fhdr, sizeof fhdr) != sizeof fhdr) { + DPRINTF("Can't read XCOFF header\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + if (is_xcoff(&fhdr)) + break; + } + + /* Is it executable ? */ + if (fhdr.f_magic != 0x01DF && + (fhdr.f_flags & COFF_F_EXEC) == 0) { + DPRINTF("Not an executable XCOFF file %02x\n", fhdr.f_flags); + return retval; + } + + /* Optional header is a.out ? */ + if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) { + DPRINTF("AOUT optional error size mismatch in XCOFF file\n"); + return retval; + } + + seek_io(fd, sizeof(COFF_filehdr_t)); + read_io(fd, &ahdr, sizeof(COFF_aouthdr_t)); + + /* check a.out magic number */ + if (ahdr.magic != AOUT_MAGIC) { + DPRINTF("Invalid AOUT optional header\n"); + return retval; + } + + offset = sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t); + + DPRINTF("XCOFF file with %d sections\n", fhdr.f_nscns); + + for (i = 0; i < fhdr.f_nscns; i++) { + DPRINTF("Read header at offset %0x\n", offset); + seek_io(fd, offset); + read_io(fd, &shdr, sizeof(COFF_scnhdr_t)); + + DPRINTF("Initializing '%s' section from %0x %0x to %0x (%0x)\n", + shdr.s_name, offset, shdr.s_scnptr, + shdr.s_vaddr, shdr.s_size); + + if (strcmp(shdr.s_name, ".text") == 0) { + read_io(fd, (void *)shdr.s_vaddr, shdr.s_size); + total_size += shdr.s_size; +#ifdef CONFIG_PPC + flush_icache_range((char*)(uintptr_t)shdr.s_vaddr, + (char*)(uintptr_t)(shdr.s_vaddr + shdr.s_size)); +#endif + } else if (strcmp(shdr.s_name, ".data") == 0) { + read_io(fd, (void *)shdr.s_vaddr, shdr.s_size); + total_size += shdr.s_size; + + } else if (strcmp(shdr.s_name, ".bss") == 0) { + memset((void *)(uintptr_t)shdr.s_vaddr, 0, shdr.s_size); + total_size += shdr.s_size; + } else { + DPRINTF(" Skip '%s' section\n", shdr.s_name); + } + offset += sizeof(COFF_scnhdr_t); + } + + DPRINTF("XCOFF entry point: %x\n", *(uint32_t*)ahdr.entry); + + // Initialise load-state + PUSH(total_size); + feval("load-state >ls.file-size !"); + feval("xcoff load-state >ls.file-type !"); + +out: + close_io(fd); + return retval; }
void @@ -61,8 +154,6 @@ xcoff_init_program(void) size_t total_size = 0; int i;
- feval("0 state-valid !"); - feval("load-base"); base = (char*)cell2pointer(POP());
@@ -139,9 +230,9 @@ xcoff_init_program(void) // Initialise load-state PUSH(*(uint32_t*)(uintptr_t)ahdr->entry); feval("load-state >ls.entry !"); - PUSH(total_size); - feval("load-state >ls.file-size !"); feval("xcoff load-state >ls.file-type !");
+ arch_init_program(); + feval("-1 state-valid !"); }