2009-05-02 23:03:37 +02:00
|
|
|
/*
|
2009-05-02 23:53:27 +02:00
|
|
|
* Copyright (C) 2002-2004 The DOSBox Team
|
2009-05-02 23:03:37 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2009-05-03 00:02:15 +02:00
|
|
|
* GNU General Public License for more details.
|
2009-05-02 23:03:37 +02:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
/* $Id: dos_execute.cpp,v 1.44 2004/08/04 09:12:53 qbix79 Exp $ */
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
#include <string.h>
|
2009-05-03 00:02:15 +02:00
|
|
|
#include <ctype.h>
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "dosbox.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dos_inc.h"
|
2009-05-02 23:43:00 +02:00
|
|
|
#include "regs.h"
|
2009-05-02 23:20:05 +02:00
|
|
|
#include "callback.h"
|
|
|
|
#include "debug.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
char * RunningProgram="DOSBOX";
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
#ifdef _MSC_VER
|
2009-05-02 23:20:05 +02:00
|
|
|
#pragma pack(1)
|
2009-05-02 23:43:00 +02:00
|
|
|
#endif
|
2009-05-02 23:03:37 +02:00
|
|
|
struct EXE_Header {
|
|
|
|
Bit16u signature; /* EXE Signature MZ or ZM */
|
|
|
|
Bit16u extrabytes; /* Bytes on the last page */
|
|
|
|
Bit16u pages; /* Pages in file */
|
|
|
|
Bit16u relocations; /* Relocations in file */
|
|
|
|
Bit16u headersize; /* Paragraphs in header */
|
|
|
|
Bit16u minmemory; /* Minimum amount of memory */
|
|
|
|
Bit16u maxmemory; /* Maximum amount of memory */
|
|
|
|
Bit16u initSS;
|
|
|
|
Bit16u initSP;
|
|
|
|
Bit16u checksum;
|
|
|
|
Bit16u initIP;
|
|
|
|
Bit16u initCS;
|
|
|
|
Bit16u reloctable;
|
|
|
|
Bit16u overlay;
|
2009-05-02 23:20:05 +02:00
|
|
|
} GCC_ATTRIBUTE(packed);
|
2009-05-02 23:43:00 +02:00
|
|
|
#ifdef _MSC_VER
|
2009-05-02 23:03:37 +02:00
|
|
|
#pragma pack()
|
2009-05-02 23:43:00 +02:00
|
|
|
#endif
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
#define MAGIC1 0x5a4d
|
|
|
|
#define MAGIC2 0x4d5a
|
|
|
|
#define MAXENV 32768u
|
|
|
|
#define ENV_KEEPFREE 83 /* keep unallocated by environment variables */
|
|
|
|
/* The '65' added to nEnvSize does not cover the additional stuff:
|
|
|
|
+ 2 bytes: number of strings
|
|
|
|
+ 80 bytes: maximum absolute filename
|
|
|
|
+ 1 byte: '\0'
|
|
|
|
-- 1999/04/21 ska */
|
|
|
|
#define LOADNGO 0
|
|
|
|
#define LOAD 1
|
|
|
|
#define OVERLAY 3
|
|
|
|
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
|
|
|
|
static void SaveRegisters(void) {
|
2009-05-03 00:02:15 +02:00
|
|
|
reg_sp-=18;
|
2009-05-02 23:20:05 +02:00
|
|
|
mem_writew(SegPhys(ss)+reg_sp+ 0,reg_ax);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+ 2,reg_cx);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+ 4,reg_dx);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+ 6,reg_bx);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+ 8,reg_si);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+10,reg_di);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+12,reg_bp);
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+14,SegValue(ds));
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+16,SegValue(es));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RestoreRegisters(void) {
|
|
|
|
reg_ax=mem_readw(SegPhys(ss)+reg_sp+ 0);
|
|
|
|
reg_cx=mem_readw(SegPhys(ss)+reg_sp+ 2);
|
|
|
|
reg_dx=mem_readw(SegPhys(ss)+reg_sp+ 4);
|
|
|
|
reg_bx=mem_readw(SegPhys(ss)+reg_sp+ 6);
|
|
|
|
reg_si=mem_readw(SegPhys(ss)+reg_sp+ 8);
|
|
|
|
reg_di=mem_readw(SegPhys(ss)+reg_sp+10);
|
|
|
|
reg_bp=mem_readw(SegPhys(ss)+reg_sp+12);
|
|
|
|
SegSet16(ds,mem_readw(SegPhys(ss)+reg_sp+14));
|
|
|
|
SegSet16(es,mem_readw(SegPhys(ss)+reg_sp+16));
|
2009-05-03 00:02:15 +02:00
|
|
|
reg_sp+=18;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
extern void GFX_SetTitle(Bits cycles,Bits frameskip,bool paused);
|
|
|
|
void DOS_UpdatePSPName(void) {
|
|
|
|
DOS_MCB mcb(dos.psp()-1);
|
|
|
|
static char name[9];
|
|
|
|
mcb.GetFileName(name);
|
|
|
|
if (!strlen(name)) strcpy(name,"DOSBOX");
|
|
|
|
RunningProgram=name;
|
|
|
|
GFX_SetTitle(-1,-1,false);
|
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
bool DOS_Terminate(bool tsr) {
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
dos.return_code=reg_al;
|
|
|
|
dos.return_mode=RETURN_EXIT;
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
Bit16u mempsp = dos.psp();
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP curpsp(mempsp);
|
|
|
|
if (mempsp==curpsp.GetParent()) return true;
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Free Files owned by process */
|
2009-05-02 23:43:00 +02:00
|
|
|
if (!tsr) curpsp.CloseFiles();
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Get the termination address */
|
|
|
|
RealPt old22 = curpsp.GetInt22();
|
|
|
|
/* Restore vector 22,23,24 */
|
|
|
|
curpsp.RestoreVectors();
|
|
|
|
/* Set the parent PSP */
|
2009-05-03 00:02:15 +02:00
|
|
|
dos.psp(curpsp.GetParent());
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_PSP parentpsp(curpsp.GetParent());
|
2009-05-03 00:02:15 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Restore the SS:SP to the previous one */
|
|
|
|
SegSet16(ss,RealSeg(parentpsp.GetStack()));
|
|
|
|
reg_sp = RealOff(parentpsp.GetStack());
|
|
|
|
/* Restore the old CS:IP from int 22h */
|
|
|
|
RestoreRegisters();
|
|
|
|
/* Set the CS:IP stored in int 0x22 back on the stack */
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+0,RealOff(old22));
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(old22));
|
2009-05-02 23:53:27 +02:00
|
|
|
mem_writew(SegPhys(ss)+reg_sp+4,0x200); //stack isn't preserved
|
2009-05-02 23:20:05 +02:00
|
|
|
// Free memory owned by process
|
|
|
|
if (!tsr) DOS_FreeProcessMemory(mempsp);
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_UpdatePSPName();
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool MakeEnv(char * name,Bit16u * segment) {
|
|
|
|
/* If segment to copy environment is 0 copy the caller's environment */
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP psp(dos.psp());
|
2009-05-02 23:43:00 +02:00
|
|
|
PhysPt envread,envwrite;
|
2009-05-02 23:03:37 +02:00
|
|
|
Bit16u envsize=1;
|
|
|
|
bool parentenv=true;
|
|
|
|
|
|
|
|
if (*segment==0) {
|
2009-05-02 23:20:05 +02:00
|
|
|
if (!psp.GetEnvironment()) parentenv=false; //environment seg=0
|
2009-05-02 23:43:00 +02:00
|
|
|
envread=PhysMake(psp.GetEnvironment(),0);
|
2009-05-02 23:03:37 +02:00
|
|
|
} else {
|
|
|
|
if (!*segment) parentenv=false; //environment seg=0
|
2009-05-02 23:43:00 +02:00
|
|
|
envread=PhysMake(*segment,0);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (parentenv) {
|
|
|
|
for (envsize=0; ;envsize++) {
|
|
|
|
if (envsize>=MAXENV - ENV_KEEPFREE) {
|
|
|
|
DOS_SetError(DOSERR_ENVIRONMENT_INVALID);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
if (mem_readw(envread+envsize)==0) break;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
envsize += 2; /* account for trailing \0\0 */
|
|
|
|
}
|
|
|
|
Bit16u size=long2para(envsize+ENV_KEEPFREE);
|
|
|
|
if (!DOS_AllocateMemory(segment,&size)) return false;
|
2009-05-02 23:43:00 +02:00
|
|
|
envwrite=PhysMake(*segment,0);
|
2009-05-02 23:03:37 +02:00
|
|
|
if (parentenv) {
|
2009-05-02 23:43:00 +02:00
|
|
|
MEM_BlockCopy(envwrite,envread,envsize);
|
|
|
|
// mem_memcpy(envwrite,envread,envsize);
|
2009-05-02 23:03:37 +02:00
|
|
|
envwrite+=envsize;
|
|
|
|
} else {
|
2009-05-02 23:43:00 +02:00
|
|
|
mem_writeb(envwrite++,0);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
mem_writew(envwrite,1);
|
2009-05-02 23:03:37 +02:00
|
|
|
envwrite+=2;
|
2009-05-02 23:43:00 +02:00
|
|
|
char namebuf[DOS_PATHLENGTH];
|
|
|
|
if (DOS_Canonicalize(name,namebuf)) {
|
|
|
|
MEM_BlockWrite(envwrite,namebuf,strlen(namebuf)+1);
|
|
|
|
return true;
|
|
|
|
} else return false;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
bool DOS_NewPSP(Bit16u segment, Bit16u size) {
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_PSP psp(segment);
|
|
|
|
psp.MakeNew(size);
|
|
|
|
DOS_PSP psp_parent(psp.GetParent());
|
2009-05-02 23:43:00 +02:00
|
|
|
psp.CopyFileTable(&psp_parent,false);
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
bool DOS_ChildPSP(Bit16u segment, Bit16u size) {
|
2009-05-02 23:43:00 +02:00
|
|
|
DOS_PSP psp(segment);
|
|
|
|
psp.MakeNew(size);
|
|
|
|
DOS_PSP psp_parent(psp.GetParent());
|
|
|
|
psp.CopyFileTable(&psp_parent,true);
|
2009-05-02 23:53:27 +02:00
|
|
|
psp.SetEnvironment(psp_parent.GetEnvironment());
|
|
|
|
psp.SetSize(size);
|
2009-05-02 23:43:00 +02:00
|
|
|
return true;
|
|
|
|
};
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) {
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Fix the PSP for psp and environment MCB's */
|
2009-05-02 23:35:44 +02:00
|
|
|
DOS_MCB mcb((Bit16u)(pspseg-1));
|
|
|
|
mcb.SetPSPSeg(pspseg);
|
|
|
|
mcb.SetPt((Bit16u)(envseg-1));
|
|
|
|
mcb.SetPSPSeg(pspseg);
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_PSP psp(pspseg);
|
|
|
|
psp.MakeNew(memsize);
|
|
|
|
psp.SetEnvironment(envseg);
|
2009-05-03 00:02:15 +02:00
|
|
|
|
|
|
|
/* Copy file handles */
|
|
|
|
DOS_PSP oldpsp(dos.psp());
|
|
|
|
psp.CopyFileTable(&oldpsp,true);
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
static void SetupCMDLine(Bit16u pspseg,DOS_ParamBlock & block) {
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_PSP psp(pspseg);
|
|
|
|
// if cmdtail==0 it will inited as empty in SetCommandTail
|
|
|
|
psp.SetCommandTail(block.exec.cmdtail);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
|
|
|
|
EXE_Header head;Bitu i;
|
|
|
|
Bit16u fhandle;Bit16u len;Bit32u pos;
|
|
|
|
Bit16u pspseg,envseg,loadseg,memsize,readsize;
|
2009-05-02 23:43:00 +02:00
|
|
|
PhysPt loadaddress;RealPt relocpt;
|
2009-05-02 23:20:05 +02:00
|
|
|
Bitu headersize,imagesize;
|
|
|
|
DOS_ParamBlock block(block_pt);
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
block.LoadData();
|
2009-05-02 23:27:47 +02:00
|
|
|
if (flags!=LOADNGO && flags!=OVERLAY && flags!=LOAD) {
|
2009-05-02 23:20:05 +02:00
|
|
|
E_Exit("DOS:Not supported execute mode %d for file %s",flags,name);
|
|
|
|
}
|
|
|
|
/* Check for EXE or COM File */
|
|
|
|
bool iscom=false;
|
2009-05-02 23:03:37 +02:00
|
|
|
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
|
2009-05-02 23:20:05 +02:00
|
|
|
len=sizeof(EXE_Header);
|
|
|
|
if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&len)) {
|
|
|
|
DOS_CloseFile(fhandle);
|
|
|
|
return false;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Convert the header to correct endian, i hope this works */
|
|
|
|
HostPt endian=(HostPt)&head;
|
|
|
|
for (i=0;i<sizeof(EXE_Header)/2;i++) {
|
2009-05-02 23:53:27 +02:00
|
|
|
*((Bit16u *)endian)=host_readw(endian);
|
2009-05-02 23:20:05 +02:00
|
|
|
endian+=2;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
if (len<sizeof(EXE_Header)) iscom=true;
|
|
|
|
if ((head.signature!=MAGIC1) && (head.signature!=MAGIC2)) iscom=true;
|
|
|
|
else {
|
2009-05-03 00:02:15 +02:00
|
|
|
headersize = head.headersize*16;
|
|
|
|
imagesize = head.pages*512-headersize;
|
2009-05-02 23:35:44 +02:00
|
|
|
if (imagesize+headersize<512) imagesize = 512-headersize;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
if (flags!=OVERLAY) {
|
|
|
|
/* Create an environment block */
|
2009-05-02 23:12:18 +02:00
|
|
|
envseg=block.exec.envseg;
|
2009-05-02 23:20:05 +02:00
|
|
|
if (!MakeEnv(name,&envseg)) {
|
|
|
|
DOS_CloseFile(fhandle);
|
2009-05-02 23:03:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Get Memory */
|
|
|
|
Bit16u minsize,maxsize;Bit16u maxfree=0xffff;DOS_AllocateMemory(&pspseg,&maxfree);
|
|
|
|
if (iscom) {
|
|
|
|
minsize=0x1000;maxsize=0xffff;
|
|
|
|
} else { /* Exe size calculated from header */
|
|
|
|
minsize=long2para(imagesize+(head.minmemory<<4)+256);
|
|
|
|
if (head.maxmemory!=0) maxsize=long2para(imagesize+(head.maxmemory<<4)+256);
|
|
|
|
else maxsize=0xffff;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
if (maxfree<minsize) {
|
2009-05-02 23:03:37 +02:00
|
|
|
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
|
|
|
|
DOS_FreeMemory(envseg);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
if (maxfree<maxsize) memsize=maxfree;
|
|
|
|
else memsize=maxsize;
|
|
|
|
if (!DOS_AllocateMemory(&pspseg,&memsize)) E_Exit("DOS:Exec error in memory");
|
|
|
|
loadseg=pspseg+16;
|
2009-05-03 00:02:15 +02:00
|
|
|
if ((!iscom) & (head.minmemory == 0) & (head.maxmemory == 0))
|
|
|
|
loadseg = (0x9e000 - imagesize)/16; //c2woody
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
} else loadseg=block.overlay.loadseg;
|
|
|
|
/* Load the executable */
|
2009-05-02 23:43:00 +02:00
|
|
|
Bit8u * loadbuf=(Bit8u *)new Bit8u[0x10000];
|
|
|
|
loadaddress=PhysMake(loadseg,0);
|
2009-05-03 00:02:15 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
if (iscom) { /* COM Load 64k - 256 bytes max */
|
|
|
|
pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
|
|
|
|
readsize=0xffff-256;
|
2009-05-02 23:43:00 +02:00
|
|
|
DOS_ReadFile(fhandle,loadbuf,&readsize);
|
|
|
|
MEM_BlockWrite(loadaddress,loadbuf,readsize);
|
2009-05-03 00:02:15 +02:00
|
|
|
} else { /* EXE Load in 32kb blocks and then relocate */
|
2009-05-02 23:20:05 +02:00
|
|
|
pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
|
|
|
|
while (imagesize>0x7FFF) {
|
2009-05-02 23:43:00 +02:00
|
|
|
readsize=0x8000;DOS_ReadFile(fhandle,loadbuf,&readsize);
|
|
|
|
MEM_BlockWrite(loadaddress,loadbuf,readsize);
|
|
|
|
if (readsize!=0x8000) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header");
|
2009-05-02 23:20:05 +02:00
|
|
|
loadaddress+=0x8000;imagesize-=0x8000;
|
|
|
|
}
|
|
|
|
if (imagesize>0) {
|
2009-05-02 23:43:00 +02:00
|
|
|
readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadbuf,&readsize);
|
|
|
|
MEM_BlockWrite(loadaddress,loadbuf,readsize);
|
|
|
|
if (readsize!=imagesize) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header");
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
|
|
|
/* Relocate the exe image */
|
|
|
|
Bit16u relocate;
|
|
|
|
if (flags==OVERLAY) relocate=block.overlay.relocation;
|
|
|
|
else relocate=loadseg;
|
|
|
|
pos=head.reloctable;DOS_SeekFile(fhandle,&pos,0);
|
|
|
|
for (i=0;i<head.relocations;i++) {
|
|
|
|
readsize=4;DOS_ReadFile(fhandle,(Bit8u *)&relocpt,&readsize);
|
2009-05-02 23:53:27 +02:00
|
|
|
relocpt=host_readd((HostPt)&relocpt); //Endianize
|
2009-05-02 23:20:05 +02:00
|
|
|
PhysPt address=PhysMake(RealSeg(relocpt)+loadseg,RealOff(relocpt));
|
|
|
|
mem_writew(address,mem_readw(address)+relocate);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
delete[] loadbuf;
|
2009-05-02 23:03:37 +02:00
|
|
|
DOS_CloseFile(fhandle);
|
2009-05-02 23:43:00 +02:00
|
|
|
|
|
|
|
/* Setup a psp */
|
|
|
|
if (flags!=OVERLAY) {
|
|
|
|
// Create psp after closing exe, to avoid dead file handle of exe in copied psp
|
|
|
|
SetupPSP(pspseg,memsize,envseg);
|
|
|
|
SetupCMDLine(pspseg,block);
|
|
|
|
};
|
2009-05-02 23:20:05 +02:00
|
|
|
CALLBACK_SCF(false); /* Carry flag cleared for caller if successfull */
|
|
|
|
if (flags==OVERLAY) return true; /* Everything done for overlays */
|
|
|
|
RealPt csip,sssp;
|
2009-05-02 23:03:37 +02:00
|
|
|
if (iscom) {
|
2009-05-02 23:20:05 +02:00
|
|
|
csip=RealMake(pspseg,0x100);
|
|
|
|
sssp=RealMake(pspseg,0xfffe);
|
|
|
|
mem_writew(PhysMake(pspseg,0xfffe),0);
|
2009-05-02 23:03:37 +02:00
|
|
|
} else {
|
2009-05-02 23:20:05 +02:00
|
|
|
csip=RealMake(loadseg+head.initCS,head.initIP);
|
|
|
|
sssp=RealMake(loadseg+head.initSS,head.initSP);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
|
2009-05-02 23:27:47 +02:00
|
|
|
if (flags==LOAD) {
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP callpsp(dos.psp());
|
2009-05-02 23:27:47 +02:00
|
|
|
/* Save the SS:SP on the PSP of calling program */
|
|
|
|
callpsp.SetStack(RealMakeSeg(ss,reg_sp));
|
|
|
|
/* Switch the psp's */
|
2009-05-03 00:02:15 +02:00
|
|
|
dos.psp(pspseg);
|
|
|
|
DOS_PSP newpsp(dos.psp());
|
|
|
|
dos.dta(RealMake(newpsp.GetSegment(),0x80));
|
2009-05-02 23:27:47 +02:00
|
|
|
block.exec.initsssp = sssp;
|
|
|
|
block.exec.initcsip = csip;
|
|
|
|
block.SaveData();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
if (flags==LOADNGO) {
|
|
|
|
/* Get Caller's program CS:IP of the stack and set termination address to that */
|
|
|
|
RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp)));
|
|
|
|
SaveRegisters();
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP callpsp(dos.psp());
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Save the SS:SP on the PSP of calling program */
|
|
|
|
callpsp.SetStack(RealMakeSeg(ss,reg_sp));
|
|
|
|
/* Switch the psp's and set new DTA */
|
2009-05-03 00:02:15 +02:00
|
|
|
dos.psp(pspseg);
|
|
|
|
DOS_PSP newpsp(dos.psp());
|
|
|
|
dos.dta(RealMake(newpsp.GetSegment(),0x80));
|
2009-05-02 23:20:05 +02:00
|
|
|
/* save vectors */
|
|
|
|
newpsp.SaveVectors();
|
|
|
|
/* copy fcbs */
|
|
|
|
newpsp.SetFCB1(block.exec.fcb1);
|
|
|
|
newpsp.SetFCB2(block.exec.fcb2);
|
|
|
|
/* Set the stack for new program */
|
|
|
|
SegSet16(ss,RealSeg(sssp));reg_sp=RealOff(sssp);
|
|
|
|
/* Add some flags and CS:IP on the stack for the IRET */
|
|
|
|
reg_sp-=6;
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+0,RealOff(csip));
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(csip));
|
|
|
|
mem_writew(SegPhys(ss)+reg_sp+4,0x200);
|
|
|
|
/* Setup the rest of the registers */
|
2009-05-02 23:35:44 +02:00
|
|
|
reg_ax=0;reg_si=0x100;
|
|
|
|
reg_cx=reg_dx=reg_bx=reg_di=reg_bp=0;
|
2009-05-02 23:20:05 +02:00
|
|
|
SegSet16(ds,pspseg);SegSet16(es,pspseg);
|
|
|
|
#if C_DEBUG
|
|
|
|
/* Started from debug.com, then set breakpoint at start */
|
|
|
|
DEBUG_CheckExecuteBreakpoint(RealSeg(csip),RealOff(csip));
|
|
|
|
#endif
|
2009-05-03 00:02:15 +02:00
|
|
|
/* Add the filename to PSP and environment MCB's */
|
|
|
|
char stripname[8];Bitu index=0;
|
|
|
|
while (char chr=*name++) {
|
|
|
|
switch (chr) {
|
|
|
|
case ':':case '\\':case '/':index=0;break;
|
|
|
|
default:if (index<8) stripname[index++]=toupper(chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
index=0;
|
|
|
|
while (index<8) {
|
|
|
|
if (stripname[index]=='.') break;
|
|
|
|
if (!stripname[index]) break;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
memset(&stripname[index],0,8-index);
|
|
|
|
DOS_MCB pspmcb(dos.psp()-1);
|
|
|
|
pspmcb.SetFileName(stripname);
|
|
|
|
DOS_UpdatePSPName();
|
2009-05-02 23:20:05 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
|