예제 #1
0
파일: umem.c 프로젝트: ragnar76/emutos
long    xmfree(long addr)
{
    MD *p,**q;
    MPB *mpb;

#if DBGUMEM
    kprintf("BDOS: Mfree(0x%08lx)\n", (long) addr);
#endif
    if(addr >= start_stram && addr <= end_stram) {
        mpb = &pmd;
#if CONF_WITH_ALT_RAM
    } else if(has_alt_ram) {
        mpb = &pmdalt;
#endif
    } else {
        return EIMBA;
    }

    for (p = *(q = &mpb->mp_mal); p; p = *(q = &p->m_link))
        if (addr == p->m_start)
            break;

    if (!p)
        return(EIMBA);

    *q = p->m_link;
    freeit(p,mpb);

    return(E_OK);
}
예제 #2
0
/*
 *  xmfree - Function 0x49 (Mfree)
 */
long xmfree(void *addr)
{
    MD *p,**q;
    MPB *mpb;

    KDEBUG(("BDOS: Mfree(0x%08lx)\n",(ULONG)addr));

    if (((UBYTE *)addr >= start_stram) && ((UBYTE *)addr <= end_stram)) {
        mpb = &pmd;
#if CONF_WITH_ALT_RAM
    } else if (has_alt_ram) {
        mpb = &pmdalt;
#endif
    } else {
        return EIMBA;
    }

    for (p = *(q = &mpb->mp_mal); p; p = *(q = &p->m_link))
        if ((UBYTE *)addr == p->m_start)
            break;

    if (!p)
        return EIMBA;

    *q = p->m_link;
    freeit(p,mpb);
    dump_mem_map();

    return E_OK;
}
예제 #3
0
/* Recursively free all elements in the linked list.  If freeit != NULL
 * call it on each datum in the list */
void FAST_FUNC llist_free(llist_t *elm, void (*freeit)(void *data))
{
	while (elm) {
		void *data = llist_pop(&elm);

		if (freeit)
			freeit(data);
	}
}
예제 #4
0
// Free all the elements of a linked list
// Call freeit() on each element before freeing it.
static void dlist_free(struct double_list *list, void (*freeit)(void *data))
{
	while (list) {
		void *pop = list;
		list = list->next;
		freeit(pop);
		// Bail out also if list is circular.
		if (list == pop) break;
	}
}
예제 #5
0
/* free each item in the allocated list, that is owned by 'p' */
static void free_all_owned(PD *p, MPB *mpb)
{
    MD *m, **q;

    for (m = *(q = &mpb->mp_mal); m; m = *q) {
        if (m->m_own == p) {
            *q = m->m_link;
            freeit(m,mpb);
        } else {
            q = &m->m_link;
        }
    }
}
예제 #6
0
파일: umem.c 프로젝트: ragnar76/emutos
long    xsetblk(int n, void *blk, long len)
{
    MD *m,*p;
    MPB *mpb;

#if DBGUMEM
    kprintf("BDOS: Mshrink(0x%08lx, %ld)\n", (long) blk, len);
#endif
    if(((long)blk) >= start_stram && ((long)blk) <= end_stram) {
        mpb = &pmd;
#if DBGUMEM
        kprintf("BDOS: xsetblk - mpb = &pmd\n");
#endif
#if CONF_WITH_ALT_RAM
    } else if(has_alt_ram) {
        mpb = &pmdalt;
#if DBGUMEM
        kprintf("BDOS: xsetblk - mpb = &pmdalt\n");
#endif
#endif /* CONF_WITH_ALT_RAM */
    } else {
        return EIMBA;
    }

    /*
     * Traverse the list of memory descriptors looking for this block.
     */

    for (p = mpb->mp_mal; p; p = p->m_link)
        if(  (long) blk == p->m_start  )
            break;

    /*
     * If block address doesn't match any memory descriptor, then abort.
     */

    if (!p)
        return(EIMBA);

    /*
     * Round the size to a multiple of 4 bytes to keep alignment.
     * Alignment on long boundaries matters in FastRAM.
     */

    len = (len + 3) & ~3;
#if DBGUMEM
    kprintf("BDOS: xsetblk - new length = %ld\n", len);
#endif

    /*
     * If the caller is not shrinking the block size, then abort.
     */

    if (p->m_length < len)
        return(EGSBF);

    /*
     * Create a memory descriptor for the freed portion of memory.
     */

    m = MGET(MD);

#if     DBGUMEM
    /* what if 0? */
    if( m == 0 )
        panic("umem.c/xsetblk: Null Return From MGET\n") ;
#endif

    m->m_start = p->m_start + len;
    m->m_length = p->m_length - len;
    p->m_length = len;
    freeit(m,mpb);

    return(E_OK);
}
예제 #7
0
long xexec(WORD flag, char *path, char *tail, char *env)
{
    PD *p;
    PGMHDR01 hdr;
    MD *m, *env_md;
    LONG rc;
    long max, needed;
    FH fh;

    KDEBUG(("BDOS xexec: flag or mode = %d\n",flag));

    /* first branch - actions that do not require loading files */
    switch(flag) {
#if DETECT_NATIVE_FEATURES
    case PE_RELOCATE:   /* internal use only, see bootstrap() in bios/bios.c */
        p = (PD *) tail;
        rc = kpgm_relocate(p, (long)path);
        if (rc) {
            KDEBUG(("BDOS xexec: kpgm_reloc returned %ld (0x%lx)\n",rc,rc));
            return rc;
        }

        /* invalidate instruction cache for the TEXT segment only
         * programs that jump into their DATA, BSS or HEAP are kindly invited
         * to do their cache management themselves.
         */
        invalidate_instruction_cache( p+1, p->p_tlen);

        return (long)p;
#endif
    case PE_BASEPAGE:           /* just create a basepage */
        path = (char *) 0L;     /* (same as basepage+flags with flags set to zero) */
    /* drop thru */
    case PE_BASEPAGEFLAGS:      /* create a basepage, respecting the flags */
        env_md = alloc_env(env);
        if (env_md == NULL) {
            KDEBUG(("BDOS xexec: not enough memory!\n"));
            return ENSMEM;
        }
        m = alloc_tpa((ULONG)path,sizeof(PD),&max);

        if (m == NULL) {    /* not even enough memory for basepage */
            freeit(env_md, &pmd);
            KDEBUG(("BDOS xexec: No memory for basepage\n"));
            return ENSMEM;
        }

        p = (PD *) m->m_start;

        /* memory ownership */
        m->m_own = env_md->m_own = run;

        /* initialize the PD */
        init_pd_fields(p, tail, max, env_md);
        p->p_flags = (ULONG)path;   /* set the flags */
        init_pd_files(p);

        return (long)p;
    case PE_GOTHENFREE:
        /* set the owner of the memory to be this process */
        p = (PD *) tail;
        set_owner(p, p, find_mpb(p));
        set_owner(p->p_env, p, find_mpb(p->p_env));
    /* fall through */
    case PE_GO:
        p = (PD *) tail;
        proc_go(p);
        /* should not return ? */
        return (long)p;
    case PE_LOADGO:
    case PE_LOAD:
        break;
    default:
        return EINVFN;
    }

    /* we now need to load a file */
    KDEBUG(("BDOS xexec: trying to find the command ...\n"));
    if (ixsfirst(path,0,0L)) {
        KDEBUG(("BDOS xexec: command %s not found!!!\n",path));
        return EFILNF;      /*  file not found      */
    }

    /* load the header - if I/O error occurs now, the longjmp in rwabs will
     * jump directly back to bdosmain.c, which is not a problem because
     * we haven't allocated anything yet.
     */
    rc = kpgmhdrld(path, &hdr, &fh);
    if (rc) {
        KDEBUG(("BDOS xexec: kpgmhdrld returned %ld (0x%lx)\n",rc,rc));
        return rc;
    }

    /* allocate the environment first, always in ST RAM */
    env_md = alloc_env(env);
    if (env_md == NULL) {
        KDEBUG(("BDOS xexec: not enough memory!\n"));
        return ENSMEM;
    }

    /* allocate the basepage depending on memory policy */
    needed = hdr.h01_tlen + hdr.h01_dlen + hdr.h01_blen + sizeof(PD);
    m = alloc_tpa(hdr.h01_flags,needed,&max);

    /* if failed, free env_md and return */
    if (m == NULL) {
        KDEBUG(("BDOS xexec: no memory for TPA\n"));
        freeit(env_md, &pmd);
        return ENSMEM;
    }

    p = (PD *) m->m_start;

    /* memory ownership - the owner is either the new process being created,
     * or the parent
     */
    if (flag == PE_LOADGO) {
        m->m_own = env_md->m_own = p;
    } else {
        m->m_own = env_md->m_own = run;
    }

    /* initialize the fields in the PD structure */
    init_pd_fields(p, tail, max, env_md);

    /* set the flags (must be done after init_pd) */
    p->p_flags = hdr.h01_flags;

    /* use static variable to avoid the obscure longjmp warning */
    cur_p = p;
    cur_m = m;
    cur_env_md = env_md;

    /* we have now allocated memory, so we need to intercept longjmp. */
    memcpy(bakbuf, errbuf, sizeof(errbuf));
    if (setjmp(errbuf)) {

        KDEBUG(("Error and longjmp in xexec()!\n"));

        /* free any memory allocated yet */
        freeit(cur_env_md, &pmd);
        freeit(cur_m, find_mpb(cur_m->m_start));

        /* we still have to jump back to bdosmain.c so that the proper error
         * handling can occur.
         */
        longjmp(bakbuf, 1);
    }

    /* now, load the rest of the program and perform relocation */
    rc = kpgmld(cur_p, fh, &hdr);
    if (rc) {
        KDEBUG(("BDOS xexec: kpgmld returned %ld (0x%lx)\n",rc,rc));
        /* free any memory allocated yet */
        freeit(cur_env_md, &pmd);
        freeit(cur_m, find_mpb(cur_m->m_start));

        return rc;
    }

    /* at this point the program has been correctly loaded in memory, and
     * more I/O errors cannot occur, so it is safe now to finish initializing
     * the new process.
     */
    init_pd_files(cur_p);

    /* invalidate instruction cache for the TEXT segment only
     * programs that jump into their DATA, BSS or HEAP are kindly invited
     * to do their cache management themselves.
     */
    invalidate_instruction_cache(((char *)cur_p) + sizeof(PD), hdr.h01_tlen);

    if (flag != PE_LOAD)
        proc_go(cur_p);
    return (long)cur_p;
}
예제 #8
0
int
_f_open(
	FIOSPTR	css,	/* Fortran statement state			      */
	unit	**cup_p,/* input: pointer to currently open unit.  output:    */
			/* pointer to new unit.				      */
	olist	*olptr,	/* OPEN information 				      */
	int	isf90)	/* 1 if being opened from CF90, 0 if CF77	      */
{
	register short	is_bin;		/* 1 if binary; else 0 		*/
	register short	is_fmt;		/* 1 if formatted; 0 if unformatted */
	register short	is_seq;		/* 1 if sequential; 0 if direct */
	register short	is_sys;		/* 1 if system; else 0 		*/
	register short	no_mem;		/* 1 if malloc() fails */
	register int	aifound;	/* 1 if assign/asgcmd info found */
	register int	errn;		/* Error code */
	register int	gamask;		/* Global assign mask */
	register int	oflags;		/* O_EXCL/O_CREAT */
	register int	P_value;	/* -P option value */
	register int	stdfn;		/* 1 if std file stdin/stdout/stderr */
	register int	stdfnum;	/* standard file descriptor number */
	register int	stat_ok;	/* 1 if statbuf is valid */
	register int	tufs;		/* requested file structure (default) */
	register int	uscope;		/* File scope */
	register unum_t	unum;		/* unit number */
	char		namebuf[MXUNITSZ]; /* buffer to construct file name */
	char		*fname;		/* FILE= specifier or default filename*/
	char		*aname;		/* actual file name */
	char		*atstr;		/* assign attributes string */
	unit		*cup;
	assign_info	ai;
	struct stat	statbuf;

	unum	= olptr->ounit;

	if (! GOOD_UNUM(unum))
		FERROR1(olptr->oerr, FEIVUNIT, unum);

/*
 *	Check for a re-open before initializing any unit table fields.
 */
	if (OPEN_UPTR(*cup_p)) {
		/*
		 * The unit is connected, but we have already checked in
		 * $OPN for reconnection to the same file with unchanged
		 * attributes.  Thus, we know that we may disconnect the unit
		 * here before continuing the set up of the new connection.
		 *
		 * We unlock it so that _alloc_unit may find it again and
		 * lock it.  
		 */

		errn	= _unit_close(*cup_p, CLST_UNSPEC, NULL);

		if (errn != 0)
			FERROR(olptr->oerr, errn);

		_release_cup(*cup_p);		/* unlock the unit */
	}

/*
 *	"aname" receives the actual name to be opened by the system.
 *	It starts out the same as fname, but might later be reassigned
 *	by assign.
 */

	aname	= NULL;
	fname	= NULL;
	stdfn	= 0;
	no_mem	= 0;

	if (olptr->ofile == NULL) {		/* If no name specified */

		if (olptr->ostatus == OS_SCRATCH) {	 /* If SCRATCH */
			int scratchfd;
			/*
			 * Scratch files have no name (see INQUIRE).
			 */
			fname	= NULL;
			aname = strdup("FXXXXXX");
		        scratchfd = mkstemp(aname);
			close(scratchfd); /* because mkstemp opens the file */
		}
		else if (unum == 0 || unum == 5 || unum == 6 ||
			 RSVD_UNUM(unum)) {
			stdfn	= 1;	/* Possible standard file */
			stdfnum	= -1;

			switch (unum) {

			case 5:	/* Connect 5 and 100 to stdin */
			case 100:
				stdfnum	= STDIN_FILENO;
				break;
			case 6:	/* Connect 6 and 101 to stdout */
			case 101:
				stdfnum	= STDOUT_FILENO;
				break;
			case 0:	/* Connect 0 and 102 to stderr/errfile */
			case 102:		/* (see finit.c) */
				stdfnum	= fileno(errfile);
				break;
			default:
				_ferr(css, FEINTUNK);	/* deep weeds */
			}
		}
		else {			/* not scratch nor standard file */

			(void) _fortname(namebuf, unum); /* Make default name */

			fname	= strdup(namebuf);
			aname	= strdup(namebuf);
			no_mem	= (aname == NULL) || (fname == NULL);
		}
	}
	else {				/* Copy user supplied name */
		if ((fname = malloc(olptr->ofilelen + 1)) != NULL) {
			_copy_n_trim(olptr->ofile, olptr->ofilelen, fname);
			aname	= strdup(fname);
		}

		no_mem	= (aname == NULL) || (fname == NULL);
	}

	if (no_mem) {			/* If malloc() failed */

		freeit(aname);
		freeit(fname);

		FERROR(olptr->oerr, FENOMEMY);		/* No memory */
	}


	is_bin	= (olptr->oform == OS_BINARY) ? 1 : 0;
	is_fmt	= (olptr->oform == OS_FORMATTED) ? 1 : 0;
	is_seq	= (olptr->oaccess == OS_SEQUENTIAL ? 1 : 0);
	is_sys	= (olptr->oform == OS_SYSTEM) ? 1 : 0;

/*
 *	The ASN_G_SF/SU/DF/DU masks map to the ACCESS/FORM specifiers on OPEN.
 */
	switch ((is_seq << 3) | is_fmt) {

		case 011:	/* Sequential Formatted */
			gamask	= ASN_G_SF;
			break;

		case 010:	/* Sequential Unformatted */
			gamask	= ASN_G_SU;
			break;

		case 001:	/* Direct Formatted */
			gamask	= ASN_G_DF;
			break;

		case 000:	/* Direct Unformatted */
			gamask	= ASN_G_DU;
			break;
	}

	gamask	= gamask | ASN_G_ALL;
	atstr	= NULL;
	aifound	= _assign_asgcmd_info(fname, unum, gamask, &ai, &atstr,
			     olptr->oerr);
#ifdef KEY /* Bug 4924 */
        /* Ignore "-F f77.mips" if the file is not sequential and thus has no
	 * headers. Otherwise, we would select an ffio layer which gives a
	 * runtime error on non-sequential files. Today f77.mips is the only
	 * value we support; if we supported some other value which permitted
	 * non-sequential access, this test would need to be made more precise.
	 */
        if (!is_seq) {
	  ai.F_filter_flg = 0;
	}
#endif /* KEY Bug 4924 */

	if (aifound == -1) {
		freeit(fname);
		freeit(aname);
		freeit(atstr);
		FERROR(olptr->oerr, errno);
	}

/*
 *	Set up the scoping of this unit.   -P process is default.
 */
	uscope	= AS_PROCESS;		/* actual scope */
	P_value	= AS_PROCESS;		/* -P option value, if any */

	if (aifound == 1 && ai.P_ioscop_flg) {
		uscope	= ai.P_ioscop;
		P_value	= ai.P_ioscop;
		/* Map -P private and -P global to the new spelling */
#ifdef _CRAYMPP
		if (ai.P_ioscop == AS_PRIVATE)
			uscope	= AS_PROCESS;
#else
		if (ai.P_ioscop == AS_PRIVATE)
			uscope	= AS_THREAD;

		if (ai.P_ioscop == AS_GLOBAL)
			uscope	= AS_PROCESS;
#endif
	}

#ifdef	_CRAYMPP
	if (uscope == AS_GLOBAL)
		FERROR(olptr->oerr, FENOGLOB);

	if (uscope == AS_THREAD)
		FERROR(olptr->oerr, FENOTHRD);

	if (uscope == AS_TEAM)
		FERROR(olptr->oerr, FENOTEAM);
#else
	if (uscope == AS_TEAM)
		FERROR(olptr->oerr, FENOTEAM);
#endif

/*
 *	Now that we know the unit number and scope we can get a pointer to the 
 *	unit table.
 */
#ifdef _CRAYMPP
	cup	= _alloc_unit(unum, 1);		/* TEMPORARY */
#else
	cup	= _alloc_unit(unum, (uscope == AS_THREAD));
#endif
	if (cup == NULL)
		FERROR1(olptr->oerr, errno, unum);

	*cup_p		= cup;

/*
 *	Record OPEN specifiers in unit table
 */
	cup->ubinary	= is_bin;
	cup->ufmt	= is_fmt;
	cup->useq	= is_seq;
	cup->usystem	= is_sys;
	cup->ublnk	= (olptr->oblank == OS_ZERO ? 1 : 0);
	cup->uposition	= olptr->oposition;
	cup->uaction	= olptr->oaction;
	cup->udelim	= olptr->odelim;
	cup->upad	= olptr->opad;
	cup->urecl	= olptr->orecl;

/*
 *	Initialize the cf77/f90 mode.  It might be changed in f_asgn() later.
 */
	cup->uft90	= isf90;

	if (aifound == 1 && ai.a_actfil_flg) {
		stdfn	= 0;	/* standard file overridden */

		freeit(aname);
		aname	= strdup(ai.a_actfil);

		if (aname == NULL) {
			freeit(atstr);
			freeit(fname);
			FERROR(olptr->oerr, FENOMEMY);
		}
	}
 
	if (aifound == 1 && ai.D_fildes_flg) {
		stdfn	= 1;	/* indicate standard file */
		stdfnum	= ai.D_fildes;

		freeit(aname);
		aname	= NULL;
	}

/*
 *	Units connected to stdin, stdout, or stderr may not have thread scope
 *	on PVP systems.
 */
#ifdef	_CRAYMPP
	if (stdfn && uscope == AS_TEAM) {
		freeit(fname);
		freeit(aname);
		freeit(atstr);
		FERROR(olptr->oerr, FENOTEAM);
	}
#else
	if (stdfn && uscope == AS_THREAD) {
		freeit(fname);
		freeit(aname);
		freeit(atstr);
		FERROR(olptr->oerr, (P_value==AS_PRIVATE)? FENOPRIV: FENOTHRD);
	}
#endif

/*
 *	Set up cup->urecsize, the maximum record size.  If RECL was
 *	specified (it's required on direct access files; optional
 *	on sequential access files), then RECL becomes the maximum
 *	record size for all formatted I/O on this unit.  Otherwise
 *	we use default values for the maximum record size for both
 *	regular I/O and list-directed/namelist output.
 */

	if (cup->ufmt) {	/* If formatted file */

		if (cup->urecl > 0) {	/* If RECL specified */
			cup->urecsize	= cup->urecl;
			cup->uldwsize	= cup->urecl;
		}
		else {			/* Else set defaults */
			cup->urecsize	= _f_rcsz;
			cup->uldwsize	= _f_ldsz;
		}

		/* Allocate line buffer for formatted files */

		cup->ulinebuf	= (long *) malloc(sizeof(long) *
						(cup->urecsize + 1));

		if (cup->ulinebuf == NULL) {
			freeit(fname);
			freeit(aname);
			freeit(atstr);
			FERROR(olptr->oerr, FENOMEMY);
		}
	}

/*
 *	See if the file exists.  We don't know the filename for sure if FFIO
 *	is being used though.
 */
	errn	= 0;
	stat_ok	= 0;

	if (stdfn) {
		errn	= fstat(stdfnum, &statbuf);
		stat_ok	= 1;
	}
	else if (aifound == 0 || ai.F_filter_flg == 0) {
		errn	= stat(aname, &statbuf);
		stat_ok	= 1;
	}

	/*
	 * ENOENT means the file doesn't exist.  EINTR means the request
	 * was interrupted.  If we got an EINTR error, retry the stat
	 * request a few times.  A persistent EINTR error or any other
	 * stat error besides ENOENT is fatal.
	 *
	 * On UNICOS and UNICOS/mk systems, a EINTR error should never
	 * occur on a stat request... but we've seen some on UNICOS/mk
	 * for a reason the kernel developers do not understand.
	 */

	if (stat_ok && errn == -1) {	/* If we did a stat and it failed */
		register short	retry = 0;

		while (errn == -1 && errno == EINTR && retry++ < 10) {
			if (stdfn)
				errn	= fstat(stdfnum, &statbuf);
			else 
				errn	= stat(aname, &statbuf);
		}

		if (errn == -1) {	/* We have a hard failure */

			stat_ok	= 0;

			if (errno != ENOENT) {	/* If not ENOENT, abort */
				freeit(fname);
				freeit(aname);
				freeit(atstr);
				freeit(cup->ulinebuf);
				FERROR(olptr->oerr, errno);
			}
		}
	}

	/* Select the file structure */

	if (aifound == 1 && (ai.s_fstrct_flg || ai.F_filter_flg)) {
		if (ai.F_filter_flg)
			tufs	= FS_FDC;
		else
			tufs	= ai.s_fstrct;
	}
	else {
		/* Select default file structure */

		if ( cup->ufmt )		/* if formatted */
#if	defined(__mips) || defined(_LITTLE_ENDIAN)
			tufs	= (cup->useq) ? FS_TEXT : FS_UNBLOCKED;
#else
			tufs	= FS_TEXT;
#endif
		else {				/* else unformatted */
#ifdef	_UNICOS
 			tufs	= (cup->useq) ? FS_COS : FS_UNBLOCKED;
#else	/* else NOT _UNICOS */
 			tufs	= (cup->useq) ? FS_F77 : FS_UNBLOCKED;
#endif	/* END _UNICOS */
			if (is_bin || is_sys) {
				/*
				 * Use UNBLOCKED layer for direct or
				 * sequential unformatted IO that does
				 * not contain record control images.
				 * Formatted IO is not allowed (i.e., a) 
				 */
				tufs	= FS_UNBLOCKED;
			}

		}

		/* See if the device is a tape and handle it accordingly */

		if (stat_ok && _gsys_qtape(&statbuf) != 0)
			tufs	= FS_TAPE;
	}
예제 #9
0
파일: proc.c 프로젝트: ragnar76/emutos
long xexec(WORD flag, char *path, char *tail, char *env)
{
    PD *p;
    PGMHDR01 hdr;
    MD *m, *env_md;
    LONG rc;
    long max, needed;
    FH fh;

    D(("BDOS: xexec - flag or mode = %d\n", flag));

    /* first branch - actions that do not require loading files */
    switch(flag) {
    case PE_RELOCATE: 
        p = (PD *) tail;
        rc = kpgm_relocate(p, (long)path);
        if(rc) {
            D(("BDOS: xexec - kpgm_relloc returned %ld (0x%lx)\n", rc, rc));
            return(rc);
        }

        /* invalidate instruction cache for the TEXT segment only
         * programs that jump into their DATA, BSS or HEAP are kindly invited 
         * to do their cache management themselves.
         */
        invalidate_icache( p+1, p->p_tlen);

        return (long) p;
    case PE_BASEPAGE:        
        /* just create a basepage */
        env_md = alloc_env(env);
        if(env_md == NULL) {
            D(("xexec: Not Enough Memory!\n"));
            return(ENSMEM);
        }
        max = (long) ffit(-1L, &pmd); 
        if(max >= sizeof(PD)) {
            m = ffit(max, &pmd);
            p = (PD *) m->m_start;
        } else {
            /* not even enough memory for basepage */
            freeit(env_md, &pmd);
            D(("xexec: No memory for TPA\n"));
            return(ENSMEM);
        }
        /* memory ownership */
        m->m_own = env_md->m_own = run;

        /* initialize the PD */
        init_pd_fields(p, tail, max, env_md);
        init_pd_files(p);

        return (long) p;
    case PE_GOTHENFREE:
        /* set the owner of the memory to be this process */
        p = (PD *) tail;
        set_owner(p, p, find_mpb(p));
        set_owner(p->p_env, p, find_mpb(p->p_env));
        /* fall through */
    case PE_GO:
        p = (PD *) tail;
        proc_go(p);
        /* should not return ? */
        return (long)p;
    case PE_LOADGO:
    case PE_LOAD:
        break;
    default:
        return EINVFN;
    }
    
    /* we now need to load a file */
    D(("BDOS: xexec - trying to find the command ...\n"));
    if (ixsfirst(path,0,0L)) {
        D(("BDOS: Command %s not found!!!\n", path));
        return(EFILNF);     /*  file not found      */
    }

    /* load the header - if IO error occurs now, the longjmp in rwabs will
     * jump directly back to bdosmain.c, which is not a problem because
     * we haven't allocated anything yet.
     */
    rc = kpgmhdrld(path, &hdr, &fh);
    if(rc) {
        D(("BDOS: xexec - kpgmhdrld returned %ld (0x%lx)\n", rc, rc));
        return(rc);
    }

    /* allocate the environment first, always in ST RAM */
    env_md = alloc_env(env);
    if ( env_md == NULL ) {
        D(("xexec: Not Enough Memory!\n"));
        return(ENSMEM);
    }
    
    /* allocate the basepage depending on memory policy */
    needed = hdr.h01_tlen + hdr.h01_dlen + hdr.h01_blen + sizeof(PD);
    max = 0;
        
    /* first try */
    p = NULL;
    m = NULL;
#if CONF_WITH_ALT_RAM
    if(has_alt_ram && (hdr.h01_flags & PF_TTRAMLOAD)) {
        /* use alternate ram preferably */
        max = (long) ffit(-1L, &pmdalt); 
        if(max >= needed) {
            m = ffit(max, &pmdalt);
            p = (PD *) m->m_start;
        } 
    }
#endif
    /* second try */
    if(p == NULL) {
        max = (long) ffit(-1L, &pmd); 
        if(max >= needed) {
            m = ffit(max, &pmd);
            p = (PD *) m->m_start;
        } 
    }
    /* still failed? free env_md and return */
    if(p == NULL) {
        D(("xexec: No memory for TPA\n"));
        freeit(env_md, &pmd);
        return(ENSMEM);
    }
    assert(m != NULL);

    /* memory ownership - the owner is either the new process being created,
     * or the parent 
     */
    if(flag == PE_LOADGO) {
        m->m_own = env_md->m_own = p;
    } else {
        m->m_own = env_md->m_own = run;
    }   

    /* initialize the fields in the PD structure */
    init_pd_fields(p, tail, max, env_md);
    
    /* set the flags (must be done after init_pd) */
    p->p_flags = hdr.h01_flags;

    /* use static variable to avoid the obscure longjmp warning */
    cur_p = p;
    cur_m = m;
    cur_env_md = env_md;

    /* we have now allocated memory, so we need to intercept longjmp. */
    memcpy(bakbuf, errbuf, sizeof(errbuf));
    if ( setjmp(errbuf) ) {

        kprintf("Error and longjmp in xexec()!\n");

        /* free any memory allocated yet */
        freeit(cur_env_md, &pmd);
        freeit(cur_m, find_mpb((void *)cur_m->m_start));
        
        /* we still have to jump back to bdosmain.c so that the proper error
         * handling can occur.
         */
        longjmp(bakbuf, 1);
    }

    /* now, load the rest of the program and perform relocation */
    rc = kpgmld(cur_p, fh, &hdr);
    if ( rc ) {
        D(("BDOS: xexec - kpgmld returned %ld (0x%lx)\n", rc, rc));
        /* free any memory allocated yet */
        freeit(cur_env_md, &pmd);
        freeit(cur_m, find_mpb((void *)cur_m->m_start));
    
        return rc;
    }

    /* at this point the program has been correctly loaded in memory, and 
     * more IO errors cannot occur, so it is safe now to finish initializing
     * the new process.
     */
    init_pd_files(cur_p);
    
    /* invalidate instruction cache for the TEXT segment only
     * programs that jump into their DATA, BSS or HEAP are kindly invited 
     * to do their cache management themselves.
     */
    invalidate_icache(((char *)cur_p) + sizeof(PD), hdr.h01_tlen);

    if(flag != PE_LOAD)
        proc_go(cur_p);
    return (long) cur_p;
}