www.pudn.com > tfs.rar > tfsloader.c


/* tfsloader.c:
 *  This file contains the code that is specific to each of the file types
 *  supported by TFS as the binary executable type.
 *  Currently, COFF, ELF and A.OUT are supported.  This requires that
 *  TFS_EBIN_COFF, TFS_EBIN_ELF or TFS_EBIN_AOUT, respectively, be set in
 *  the monitor's config.h file.
 *
 *  General notice:
 *  This code is part of a boot-monitor package developed as a generic base
 *  platform for embedded system designs.  As such, it is likely to be
 *  distributed to various projects beyond the control of the original
 *  author.  Please notify the author of any enhancements made or bugs found
 *  so that all may benefit from the changes.  In addition, notification back
 *  to the author will allow the new user to pick up changes that may have
 *  been made by other users after this version of the code was distributed.
 *
 *  Note1: the majority of this code was edited with 4-space tabs.
 *  Note2: as more and more contributions are accepted, the term "author"
 *         is becoming a mis-representation of credit.
 *
 *  Original author:    Ed Sutter
 *  Email:              esutter@lucent.com
 *  Phone:              908-582-2351
 */
#include "config.h"
#include "stddefs.h"
#include "genlib.h"
#include "tfs.h"
#include "tfsprivate.h"
#include "coff.h"
#include "elf.h"
//#include "aout.h"
#if INCLUDE_TFS

#if TFS_EBIN_AOUT

/* tfsloadaout():
 *  The file pointed to by fp has been determined to be an A.OUT
 *  formatted file.  This function loads the sections of that file into
 *  the designated locations and returns the address of the entry point.
 *  Caches are flushed after loading text section.
 */
int
tfsloadebin(TFILE *fp,int verbose,long *entrypoint,int verifyonly)
{
    uchar   *tfrom, *dfrom;
    struct  exec *ehdr;

    if (tfsTrace)
        printf("tfsloadaout(%s)\n",TFS_NAME(fp));

    /* Establish file header pointer... */
    ehdr = (struct exec *)(TFS_BASE(fp));

    /* Return error if relocatable... */
    if ((ehdr->a_trsize) || (ehdr->a_drsize))
        return(TFSERR_BADHDR);

    /* Establish locations from which text and data are to be */
    /* copied from ... */
    tfrom = (uchar *)(ehdr+1);
    dfrom = tfrom+ehdr->a_text;

    /* Copy/verify text and data sections to RAM: */
    if (verbose)
        printf("%-10s: ","text");
    if (tfsmemcpy((char *)(ehdr->a_entry),(char *)tfrom,
        ehdr->a_text,verbose,verifyonly) != 0)
        return(TFSERR_MEMFAIL);

    /* Flush caches after writing to space that will be executed from... */
    flushDcache((char *)ehdr->a_entry,ehdr->a_text);
    invalidateIcache((char *)ehdr->a_entry,ehdr->a_text);

    if (verbose)
        printf("%-10s: ","data");
    if (tfsmemcpy((char *)(ehdr->a_entry+ehdr->a_text),(char *)dfrom,
        ehdr->a_data,verbose,verifyonly) != 0)
        return(TFSERR_MEMFAIL);

    /* Clear out bss space: */
    if (verbose)
        printf("%-10s: ","bss");
    if (tfsmemset((char *)(ehdr->a_entry+ehdr->a_text+ehdr->a_data),
        0,ehdr->a_bss,verbose,verifyonly) != 0)
        return(TFSERR_MEMFAIL);


    if (verbose & !verifyonly)
        printf("entrypoint: 0x%lx\n",ehdr->a_entry);

    /* Store entry point: */
    if (entrypoint)
        *entrypoint = (long)(ehdr->a_entry);

    return(TFS_OKAY);
}

#elif TFS_EBIN_COFF

/* tfsloadcoff():
 *  The file pointed to by fp has been determined to be a COFF file.
 *  This function loads the sections of that file into the designated 
 *  locations.
 *  Caches are flushed after loading each loadable section.
 */
int
tfsloadebin(TFILE *fp,int verbose,long *entrypoint,int verifyonly)
{
    int     i, err;
    FILHDR  *fhdr;
    AOUTHDR *ahdr;
    SCNHDR  *shdr;

    if (tfsTrace)
        printf("tfsloadcoff(%s)\n",TFS_NAME(fp));

    /* Establish file header pointers... */
    fhdr = (FILHDR *)(TFS_BASE(fp));
    if ((fhdr->f_opthdr == 0) || ((fhdr->f_flags & F_EXEC) == 0))
        return(TFSERR_BADHDR);
    
    err = 0;
    ahdr = (AOUTHDR *)(fhdr+1);
    shdr = (SCNHDR *)((uchar *)ahdr + fhdr->f_opthdr);

    /* For each section header, relocate or clear if necessary... */
    for (i=0;!err && if_nscns;i++) {
        if (shdr->s_size == 0) {
            shdr++;
            continue;
        }
        if (verbose)
            printf("%-10s: ",shdr->s_name);
        if (ISLOADABLE(shdr->s_flags)) {
            if (TFS_ISCPRS(fp)) {
                int     outsize;

                outsize = decompress((char *)shdr->s_scnptr+(int)fhdr,
                    shdr->s_size,(char *)shdr->s_paddr);
                if (outsize == -1) {
                    err++;
                    shdr++;
                    continue;
                }
                if (verbose)
                    printf("dcmp %7d bytes from 0x%08lx to 0x%08lx\n",outsize,
                        shdr->s_scnptr+(ulong)fhdr,shdr->s_paddr);
            }
            else {
                if (tfsmemcpy((char *)(shdr->s_paddr),
                    (char *)(shdr->s_scnptr+(int)fhdr),
                    shdr->s_size,verbose,verifyonly) != 0)
                    err++;
            }
            /* Flush caches for each loadable section... */
            flushDcache((char *)shdr->s_paddr,shdr->s_size);
            invalidateIcache((char *)shdr->s_paddr,shdr->s_size);
        }
        else if (ISBSS(shdr->s_flags)) {
            if (tfsmemset((char *)(shdr->s_paddr),0,shdr->s_size,
                verbose,verifyonly) != 0)
                err++;
        }
        else if (verbose)
            printf("???\n");
        shdr++;
    }

    if (verbose & !verifyonly)
        printf("entrypoint: 0x%lx\n",ahdr->entry);

    if (err)
        return(TFSERR_MEMFAIL);

    /* Store entry point: */
    if (entrypoint)
        *entrypoint = (long)(ahdr->entry);

    return(TFS_OKAY);
}

#elif TFS_EBIN_ELF

/* tfsloadelf():
 *  The file pointed to by fp has been determined to be an ELF file.
 *  This function loads the sections of that file into the designated 
 *  locations.
 *  Caches are flushed after loading each loadable section.
 */
int
tfsloadebin(TFILE *fp,int verbose,long *entrypoint,int verifyonly)
{
    Elf32_Word  size, notproctot;
    int         i, err;
    char        *shname_strings;
    ELFFHDR     *ehdr;
    ELFSHDR     *shdr;

    if (tfsTrace)
        printf("tfsloadelf(%s)\n",TFS_NAME(fp));

    /* Establish file header pointers... */
    ehdr = (ELFFHDR *)(TFS_BASE(fp));
    shdr = (ELFSHDR *)((int)ehdr + ehdr->e_shoff);
    err = 0;

    /* Verify basic file sanity... */
    if ((ehdr->e_ident[0] != 0x7f) || (ehdr->e_ident[1] != 'E') ||
        (ehdr->e_ident[2] != 'L') || (ehdr->e_ident[3] != 'F'))
        return(TFSERR_BADHDR);

    /* Store the section name string table base: */
    shname_strings = (char *)ehdr + shdr[ehdr->e_shstrndx].sh_offset;

    notproctot = 0;

    /* For each section header, relocate or clear if necessary... */
    for (i=0;!err && ie_shnum;i++,shdr++) {
        if ((size = shdr->sh_size) == 0)
            continue;

        if ((verbose) && (ehdr->e_shstrndx != SHN_UNDEF))
            printf("%-10s: ", shname_strings + shdr->sh_name);

        if (!(shdr->sh_flags & SHF_ALLOC)) {
            notproctot += size;
            if (verbose)
                printf("     %7ld bytes not processed (tot=%ld)\n",
                    size,notproctot);
            continue;
        }

        if (shdr->sh_type == SHT_NOBITS) {
            if (tfsmemset((uchar *)(shdr->sh_addr),0,size,
                verbose,verifyonly) != 0)
                err++;
        }
        else {
            if (TFS_ISCPRS(fp)) {
                int     outsize;

                outsize = decompress((char *)(ehdr)+shdr->sh_offset,size,
                    (char *)shdr->sh_addr);
                if (outsize == -1) {
                    err++;
                    continue;
                }
                if (verbose)
                    printf("dcmp %7d bytes from 0x%08lx to 0x%08lx\n",outsize,
                        (ulong)(ehdr)+shdr->sh_offset,shdr->sh_addr);
            }
            else {
                if (tfsmemcpy((uchar *)(shdr->sh_addr),
                    (uchar *)((int)ehdr+shdr->sh_offset),
                    size,verbose,verifyonly) != 0)
                    err++;
            }
            /* Flush caches for each loadable section... */
            flushDcache((char *)shdr->sh_addr,size);
            invalidateIcache((char *)shdr->sh_addr,size);
        }
    }

    if (err)
        return(TFSERR_MEMFAIL);

    if (verbose & !verifyonly)
        printf("entrypoint: 0x%lx\n",ehdr->e_entry);

    /* Store entry point: */
    if (entrypoint)
        *entrypoint = (long)(ehdr->e_entry);

    return(TFS_OKAY);
}

#endif  /* TFS_EBIN_XXXX */
#endif  /* INCLUDE_TFS */