/*****************************************************************************
* FILE: loadprg.c *
* *
* DESC: *
* - loader for coff/a.out programs *
* - set args,environment *
* - load text,data (if not DPMI 1.0) *
* *
* Copyright (C) 1993,1994 *
* Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld *
* email: rainer@mathematik.uni-bielefeld.de *
* *
*****************************************************************************/
#include <string.h>
#include "DPMI.H"
#include "DPMI10.H"
#include "PRINTF.H"
#include "RMLIB.H"
#include "PROCESS.H"
#include "FS.H"
#include "GNUAOUT.H"
#include "LOADPRG.H"
#include "COPY32.H"
#include "START32.H"
#include "CDOSX32.H"
#include "RSX.H"
#include "DOSERRNO.H"
static int skip_exe_hdr(int filehandle, DWORD * headoff, NEWPROCESS *p)
{
struct exe_hdr exehdr;
struct emx_hdr2 emxhdr;
rm_read(filehandle, &exehdr, sizeof(struct exe_hdr));
if (exehdr.signatur == 0x5a4d) { /* falls exe-kopf */
*headoff = ((DWORD) exehdr.hdr_para) * 16;
rm_lseek(filehandle, *headoff, SEEK_SET);
rm_read(filehandle, &emxhdr, sizeof(emxhdr));
if (memcmp(emxhdr.sig, "emx", 3) == 0) {
*headoff = *(DWORD *) emxhdr.next_hdr;
if (emxhdr.option[0]) {
char *s = emxhdr.option;
for (; *s != '\0'; ++s) {
while (*s == ' ')
++s;
if (*s == '-') {
s = scan_for_option(++s, p);
} else
break;
}
}
}
else if (memcmp(emxhdr.sig, "rsx", 3) == 0)
goto fail; /* prevent loading rsx32.exe as a.out */
else { /* not a emx file */
long new_off;
rm_lseek(filehandle, 0x3C, SEEK_SET);
rm_read(filehandle, &new_off, sizeof(long));
if (new_off) {
char pe_sig[4];
rm_lseek(filehandle, new_off, SEEK_SET);
rm_read(filehandle, pe_sig, sizeof(pe_sig));
if (pe_sig[0])
*headoff = new_off + 4;
}
else { /* djgpp */
*headoff = (DWORD) exehdr.high * 512L;
if (exehdr.low)
*headoff += (DWORD) exehdr.low - 512L;
}
}
} /* exe files */
if (rm_lseek(filehandle, *headoff, SEEK_SET) == -1L)
goto fail;
return 0;
fail:
*headoff = 0;
rm_lseek(filehandle, 0, SEEK_SET);
return -1;
}
/*
** arguments and environment at process start
**
** environment and argument strings
** argv[]
** envp[]
** pointer to env[0]
** pointer to argv[0]
** int argc
** <- ESP
*/
int argvenv(int argc, char **argv, int envc, char **env, NEWPROCESS * proc)
{
int i;
DWORD len, stkp;
DWORD *vectors;
UINT count = 3; /* 0=argc 1=argv 2=env */
vectors = (DWORD *) iobuf;
stkp = proc->stackp32;
/* store env strings in user stack, built vectors */
for (i = 0; i < envc; i++) {
len = (DWORD) (UINT) strlen(env[i]) + 1;
stkp -= len;
stkp &= ~3L; /* align4 */
cpy16_32(proc->data32sel, stkp, env[i], len);
vectors[count++] = stkp;
}
vectors[count++] = 0; /* last is a NULL pointer */
/* store arg strings in user stack, built vectors */
for (i = 0; i < argc; i++) {
len = (DWORD) (UINT) strlen(argv[i]) + 1;
stkp -= len;
stkp &= ~3L;
cpy16_32(proc->data32sel, stkp, argv[i], len);
vectors[count] = stkp;
count++;
/* for emx: add flag */
stkp -= 1;
put_user_byte(proc->data32sel, stkp, 0x80);
}
vectors[count++] = 0; /* last is a NULL pointer */
stkp &= ~3L;
len = (DWORD) (count * sizeof(long));
stkp -= len;
vectors[0] = argc;
vectors[1] = stkp + (4L + envc) * sizeof(long); /* & vectors[3+nenvp+1] */
vectors[2] = stkp + 3 * sizeof(long); /* & vectors[3] */
cpy16_32(proc->data32sel, stkp, vectors, len);
if (proc->p_flags & PF_EMX_FILE)
stkp += 3 * 4;
proc->stackp32 = stkp;
return 0;
}
void cpy_exename_to_stack(NEWPROCESS *proc, char *name)
{
int len = strlen(name) + 1;
long name_pos = proc->stackp32 - (long) (len + 2 * sizeof(DWORD));
proc->stackp32 -= sizeof(DWORD);
store32(proc->data32sel, proc->stackp32, name_pos);
proc->stackp32 -= sizeof(DWORD);
store32(proc->data32sel, proc->stackp32, (long) len);
proc->stackp32 -= (long) len;
cpy16_32(proc->data32sel, proc->stackp32, name, (long) len);
}
int readin_file(short handle, short r_ds, long r_edx, long count)
{
long bytes;
int rc;
while (count > 0) {
bytes = (count <= IOBUF_SIZE) ? count : (DWORD) IOBUF_SIZE;
rc = rm_read(handle, iobuf, (short) bytes);
cpy16_32(r_ds, r_edx, iobuf, rc);
if (bytes != rc)
break;
count -= bytes;
r_edx += bytes;
}
return 0;
}
/*
**
** RSX program layout:
**
**
** DPMI 0.9 : fixed stack
** never ending heap
**
** emx style
** |--------------------------------------------------------------
** |stack| code | data/bss | stack,if>64KB | heap -> ...
** |--------------------------------------------------------------
** 0 ^64 KB ^(n x 64KB)
**
**
** old djgpp style
** |--------------------------------------------------------------
** | | code | stack | data/bss | heap -> ...
** |--------------------------------------------------------------
** 0 ^4K ^0x400000
**
** djgpp style 1.11
** |--------------------------------------------------------------
** | code | data/bss | stack | heap -> ...
** |--------------------------------------------------------------
** 0 ^ 4 Kb align ^
**
**
**
** DPMI 1.0 : address room = 64 MegaBytes
**
** |--------------------------------------------...-----------------------|
** | | code | | data/bss | heap -> <- stack | mappings |
** | | | | | | DOS 1MB |
** |--------------------------------------------...-----------------------|
** 0 ^60 64
**
*/
#define SHORT_EMX_STACK (0x10000L-0x1000L) /* 64 KB - one R/O page */
#define DEFAULT_STACK (0x40000L) /* 256 KB */
#define TEXT 0
#define DATA 1
#define BSS 2
int load_protected_program(char *filename, NEWPROCESS * proc)
{
FILEHDR file_hdr;
AOUTHDR aout_hdr;
SCNHDR scnd_hdr[3];
DWORD tdbsegm, stacksegm;
DWORD headoff;
UINT stack32sel;
int fhandle;
int use_dpmi10;
if ((fhandle = rm_open(filename, RM_O_RDONLY | RM_O_DENYWR)) == -1)
return doserror_to_errno(_doserrno);
/* skip exe-header, return correct offset in file */
headoff = 0;
skip_exe_hdr(fhandle, &headoff, proc);
/* read file header */
rm_read(fhandle, &file_hdr, sizeof(file_hdr));
if (file_hdr.f_magic == 0x14C) { /* COFF header */
rm_read(fhandle, &aout_hdr, sizeof(aout_hdr));
rm_lseek(fhandle, headoff + sizeof(file_hdr) + file_hdr.f_opthdr, 0);
rm_read(fhandle, scnd_hdr, sizeof(scnd_hdr));
if ((scnd_hdr[TEXT].s_scnptr & 0xFF) == 0xA8) { /* DJGPP */
scnd_hdr[TEXT].s_vaddr &= ~0xFFL;
scnd_hdr[TEXT].s_scnptr &= ~0xFFL; /* align */
scnd_hdr[TEXT].s_size += 0xa8L;
proc->p_flags |= PF_DJGPP_FILE;
}
else {
DWORD image_base;
rm_lseek(fhandle, headoff + sizeof(file_hdr) + file_hdr.f_opthdr, 0);
rm_read(fhandle, &image_base, 4);
if (image_base == 0x400000L)
proc->p_flags |= PF_TNT_FILE;
printf("image base %lX\n", image_base);
}
}
else if (file_hdr.f_magic == 0x10B) {
GNUOUT gnu_hdr;
rm_lseek(fhandle, headoff, 0);
rm_read(fhandle, &gnu_hdr, sizeof(gnu_hdr));
aout_hdr.magic = 0x10B;
aout_hdr.tsize = gnu_hdr.a_text;
aout_hdr.dsize = gnu_hdr.a_data;
aout_hdr.bsize = gnu_hdr.a_bss;
aout_hdr.entry = gnu_hdr.a_entry;
scnd_hdr[TEXT].s_size = gnu_hdr.a_text;
scnd_hdr[DATA].s_size = gnu_hdr.a_data;
scnd_hdr[BSS].s_size = gnu_hdr.a_bss;
if (gnu_hdr.a_entry == 0x10000L) { /* EMX STYLE */
scnd_hdr[TEXT].s_vaddr = 0x10000L;
scnd_hdr[DATA].s_vaddr =
0x10000L + ((gnu_hdr.a_text + 0xFFFFL) & ~0xFFFFL);
scnd_hdr[BSS].s_vaddr =
scnd_hdr[DATA].s_vaddr + gnu_hdr.a_data;
scnd_hdr[TEXT].s_scnptr = 1024;
scnd_hdr[DATA].s_scnptr = 1024 + gnu_hdr.a_text;
proc->p_flags |= PF_EMX_FILE;
}
else { /* OLD DJGPP STYLE */
scnd_hdr[TEXT].s_vaddr = 0x400000L;
scnd_hdr[DATA].s_vaddr =
0x400000L + ((gnu_hdr.a_text + 0x3FFFFFL) & ~0x3FFFFFL);
scnd_hdr[BSS].s_vaddr =
scnd_hdr[DATA].s_vaddr + gnu_hdr.a_data;
scnd_hdr[TEXT].s_scnptr = 0;
scnd_hdr[DATA].s_scnptr = (gnu_hdr.a_text + 0xFFFL) & ~0xFFFL;
proc->p_flags |= PF_DJGPP_FILE;
}
}
else { /* not a valid header */
rm_close(fhandle);
return EMX_ENOEXEC;
}
proc->filehandle = (long) fhandle;
proc->text_off = headoff + scnd_hdr[TEXT].s_scnptr;
proc->data_off = headoff + scnd_hdr[DATA].s_scnptr;
proc->text_start = scnd_hdr[TEXT].s_vaddr;
proc->text_end = scnd_hdr[TEXT].s_vaddr + scnd_hdr[TEXT].s_size;
proc->bss_start = scnd_hdr[BSS].s_vaddr;
proc->bss_end = scnd_hdr[BSS].s_vaddr + scnd_hdr[BSS].s_size;
proc->data_start = scnd_hdr[DATA].s_vaddr;
proc->data_end = (proc->bss_end + 4095L) & ~4095L;
proc->entry = aout_hdr.entry;
/* compute size of text-data-bss and stack segment for AllocMem() */
tdbsegm = proc->data_end;
if (opt_stackval)
stacksegm = (DWORD) opt_stackval *1024;
else
stacksegm = DEFAULT_STACK;
if (proc == &RSX_PROCESS) { /* emu don't need much stack */
stacksegm = SHORT_EMX_STACK;
use_dpmi10 = 0;
} else
use_dpmi10 = (dpmi10) ? 1 : 0;
if (use_dpmi10)
proc->p_flags |= PF_USEDPMI10;
/* look for empty space for stack */
if (aout_hdr.entry == 0x10000L && stacksegm <= SHORT_EMX_STACK) {
stacksegm = 0;
/* place stack in the first 64KB segment */
proc->stack_top = proc->text_start;
proc->stack_down = 0x1000L;
} else if (aout_hdr.entry == 0x1020L
&& stacksegm <= (proc->data_start - proc->text_end)) {
stacksegm = 0;
/* place stack between code and data */
proc->stack_top = proc->data_start;
proc->stack_down = proc->text_end + 0x1000;
} else {
/* put stack after data/bss */
proc->stack_top = proc->data_end + stacksegm;
proc->stack_down = proc->data_end;
/* sorry, work around window bug */
if ((proc->p_flags & PF_DJGPP_FILE) && proc->stack_down <= 0x11000L
&& proc != &RSX_PROCESS) {
DWORD add_stack = 0x11000L - proc->stack_down;
proc->stack_top += add_stack;
proc->stack_down += add_stack;
stacksegm += add_stack;
}
}
if (use_dpmi10) {
stacksegm = 0;
proc->stack_top = DPMI_PRG_DATA;
proc->stack_down = proc->data_end;
}
proc->stacksize = proc->stack_top - proc->stack_down;
proc->stackp32 = proc->stack_top - 4L;
proc->init_brk = proc->data_end + stacksegm;
proc->brk_value = proc->init_brk;
proc->pagefree = 0;
/* total memory for process */
if (use_dpmi10) {
proc->pagefree = DPMI_PRG_DATA - proc->membytes;
proc->membytes = DPMI_PRG_ROOM;
} else {
proc->membytes = tdbsegm + stacksegm;
/* prealloc more heap */
if (opt_memalloc) {
proc->pagefree = (long) opt_memalloc * 1024;
proc->membytes += (long) opt_memalloc * 1024;
} else if (opt_memaccess || (proc->options & OPT_MEMACCESS)) {
proc->pagefree = 0x21000;
proc->membytes += 0x21000;
}
}
/* since dosmem isn't used by DPMI we put rsx387 in dos memory */
if (proc == &RSX_PROCESS && rsx387_in_dosmem) {
UINT segment, selectors;
if (AllocDosMem((UINT) (proc->membytes >> 4), &segment, &selectors)) {
if (AllocMem(proc->membytes, &(proc->memhandle), &(proc->memaddress)))
return EMX_ENOMEM;
} else {
proc->memaddress = (DWORD) segment << 4;
proc->memhandle = (DWORD) selectors;
}
}
/* get memory from DPMI-host */
else if (!use_dpmi10) {
if (AllocMem(proc->membytes, &(proc->memhandle), &(proc->memaddress)))
return EMX_ENOMEM;
} else if (AllocLinearMemory(proc->membytes, 0L, 0L, &proc->memhandle, &proc->memaddress))
return EMX_ENOMEM;
/* alloc 32bit cs,ds ldt selector */
if (AllocLDT(3, &(proc->code32sel)))
return EMX_EIO;
proc->data32sel = proc->code32sel + sel_incr;
stack32sel = proc->data32sel + sel_incr;
/* fill descriptors */
SetBaseAddress(proc->code32sel, proc->memaddress);
SetBaseAddress(proc->data32sel, proc->memaddress);
SetBaseAddress(stack32sel, proc->memaddress);
SetAccess(proc->code32sel, APP_CODE_SEL, DEFAULT_BIT);
SetAccess(proc->data32sel, APP_DATA_SEL, BIG_BIT);
SetAccess(stack32sel, APP_DATA_SEL | EXPAND_BIT, BIG_BIT | GRANULAR_BIT);
/* allow execute data & stack (DJGPP / GDB need this) */
SetLimit(proc->code32sel, proc->membytes - 1L);
if (!use_dpmi10) {
if (opt_memaccess || (proc->options & OPT_MEMACCESS))
SetLimit(proc->data32sel, 0xFFFFFFFF);
else
SetLimit(proc->data32sel, proc->membytes - 1L);
} else
SetLimit(proc->data32sel, DPMI_PRG_ROOM - 1L);
/* set stack expand down segment to first stack address */
SetLimit(stack32sel, proc->stack_down - 1L);
/* map first DOS MB at the end of linear Addressroom (60MB) */
if (use_dpmi10 && (opt_memaccess || (proc->options & OPT_MEMACCESS)))
MapDOSMemInMemoryBlock(proc->memhandle, DPMI_PRG_DATA, 256L, 0L);
if (!use_dpmi10) {
/* read in code */
rm_lseek(fhandle, proc->text_off, SEEK_SET);
readin_file(fhandle,
proc->data32sel, scnd_hdr[TEXT].s_vaddr,
scnd_hdr[TEXT].s_size);
/* read in data,bss */
rm_lseek(fhandle, proc->data_off, SEEK_SET);
readin_file(fhandle,
proc->data32sel, scnd_hdr[DATA].s_vaddr,
scnd_hdr[DATA].s_size);
rm_close(fhandle);
/* zero bss segment */
if (scnd_hdr[BSS].s_size)
bzero32(proc->data32sel, scnd_hdr[BSS].s_vaddr, scnd_hdr[BSS].s_size);
} else { /* uncommit first stack page! */
WORD page = 9;
ModifyPageAttributes(proc->memhandle, proc->stack_top - 4096, 1, &page);
}
return 0;
}
/* this structure that starts a core file */
struct user_area {
WORD u_magic ;
WORD u_reserved1 ;
DWORD u_data_base ;
DWORD u_data_end ;
DWORD u_data_off ;
DWORD u_heap_base ;
DWORD u_heap_end ;
DWORD u_heap_off ;
DWORD u_heap_brk ;
DWORD u_stack_base;
DWORD u_stack_end ;
DWORD u_stack_off ;
DWORD u_stack_low ;
DWORD u_ar0 ;
DWORD u_fpvalid ;
DWORD u_fpstate[27] ;
DWORD u_fpstatus;
DWORD u_reserved3[23];
REG386 u_regs;
};
#define U_OFFSET 0x400
int write_section(short handle, short r_ds, long r_edx, long count)
{
long bytes;
int rc;
while (count > 0) {
bytes = (count <= IOBUF_SIZE) ? count : (DWORD) IOBUF_SIZE;
cpy32_16(r_ds, r_edx, iobuf, bytes);
rc = rm_write(handle, iobuf, (short) bytes);
if (bytes != rc)
return -1;
count -= bytes;
r_edx += bytes;
}
return 0;
}
#include "PRINTF.H"
int write_core(unsigned handle, NEWPROCESS *proc)
{
struct user_area ua;
DWORD data_size;
DWORD heap_size;
memset(& ua, 0, sizeof(ua));
ua.u_magic = 0x10F;
ua.u_ar0 = 0xE0000000L + (DWORD)(UINT)&(((struct user_area *)0)->u_regs);
memcpy(& ua.u_regs, &(proc->regs), sizeof(REG386));
ua.u_data_base = proc->data_start;
ua.u_data_end = proc->bss_end; /* bss not rounded */
data_size = proc->data_end - proc->data_start; /* data is page-aligned */
ua.u_data_off = U_OFFSET;
ua.u_heap_base = proc->init_brk;
ua.u_heap_end = (proc->brk_value + 0xFFFL) & ~0xFFFL;
ua.u_heap_brk = proc->brk_value;
heap_size = ua.u_heap_end - ua.u_heap_base;
ua.u_heap_off = ua.u_data_off + data_size;
ua.u_stack_base = proc->stack_down;
ua.u_stack_end = proc->stack_top;
ua.u_stack_low = proc->regs.esp;
ua.u_stack_off = ua.u_heap_off + heap_size;
rm_write(handle, &ua, sizeof(ua)); /* header */
memset(iobuf, 0, U_OFFSET);
rm_write(handle, iobuf, U_OFFSET - sizeof(ua));
rm_lseek(handle, ua.u_data_off, 0);
if (write_section(handle, proc->data32sel, ua.u_data_base, data_size))
goto bad_write;
rm_lseek(handle, ua.u_heap_off, 0);
if (write_section(handle, proc->data32sel, ua.u_heap_base, heap_size))
goto bad_write;
rm_lseek(handle, ua.u_stack_off, 0);
if (write_section(handle, proc->data32sel, ua.u_stack_low,
ua.u_stack_end - ua.u_stack_low))
goto bad_write;
rm_close(handle);
return 0;
bad_write:
return -1;
}
int write_core_file(NEWPROCESS *proc)
{
int handle, ret;
static char core_name[]="CORE";
handle = rm_creat(core_name, _A_NORMAL);
if (handle == -1)
return -1;
puts("writing core file");
ret = write_core(handle, proc);
rm_close(handle);
/* if (ret == -1) unlink(core_name); */
return ret;
}