From af67029cdca902234083e638e190b76cc121283f Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Mon, 16 Sep 2002 13:10:48 +0000 Subject: [PATCH] New execute/terminate that saves registers and segments. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@272 --- src/dos/dos_execute.cpp | 402 ++++++++++++++++------------------------ 1 file changed, 163 insertions(+), 239 deletions(-) diff --git a/src/dos/dos_execute.cpp b/src/dos/dos_execute.cpp index 4ee0ec9c..375eb516 100644 --- a/src/dos/dos_execute.cpp +++ b/src/dos/dos_execute.cpp @@ -21,12 +21,10 @@ #include "mem.h" #include "dos_inc.h" #include "cpu.h" -#if defined (_MSC_VER) -#pragma pack(1) -#endif +#include "callback.h" +#pragma pack(1) struct EXE_Header { - Bit16u signature; /* EXE Signature MZ or ZM */ Bit16u extrabytes; /* Bytes on the last page */ Bit16u pages; /* Pages in file */ @@ -41,13 +39,8 @@ struct EXE_Header { Bit16u initCS; Bit16u reloctable; Bit16u overlay; -} -#if defined (_MSC_VER) -; +} GCC_ATTRIBUTE(packed); #pragma pack() -#else -__attribute__ ((packed)); -#endif #define MAGIC1 0x5a4d #define MAGIC2 0x4d5a @@ -63,31 +56,64 @@ __attribute__ ((packed)); #define OVERLAY 3 + +static void SaveRegisters(void) { + reg_sp-=20; + 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)); + reg_sp+=20; +} + + bool DOS_Terminate(bool tsr) { + dos.return_code=reg_al; + dos.return_mode=RETURN_EXIT; + Bit16u mempsp = dos.psp; DOS_PSP curpsp(dos.psp); if (dos.psp==curpsp.GetParent()) return true; /* Free Files owned by process */ if (!tsr) curpsp.CloseFiles(); - // restore vectors + /* Get the termination address */ + RealPt old22 = RealGetVec(0x22); + /* Restore vector 22,23,24 */ curpsp.RestoreVectors(); - // Set parent psp + /* Set the parent PSP */ dos.psp = curpsp.GetParent(); DOS_PSP parentpsp(curpsp.GetParent()); - /* Restore the DTA */ - parentpsp.SetDTA(curpsp.GetDTA()); + /* Restore the DTA of the parent psp */ + dos.dta = parentpsp.GetDTA(); /* 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 */ - RealPt old22 = curpsp.GetInt22(); - reg_ip = RealOff(old22); - SegSet16 (cs,RealSeg(old22)); + /* Restore the stored registers */ + 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)); // Free memory owned by process if (!tsr) DOS_FreeProcessMemory(mempsp); - return true; } @@ -109,7 +135,6 @@ static bool MakeEnv(char * name,Bit16u * segment) { envread=HostMake(*segment,0); } - //TODO Make a good DOS first psp if (parentenv) { for (envsize=0; ;envsize++) { if (envsize>=MAXENV - ENV_KEEPFREE) { @@ -131,7 +156,7 @@ static bool MakeEnv(char * name,Bit16u * segment) { } *((Bit16u *) envwrite)=1; envwrite+=2; - //TODO put the filename here + return DOS_Canonicalize(name,(char *)envwrite); }; @@ -145,14 +170,14 @@ bool DOS_NewPSP(Bit16u segment, Bit16u size) static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) { - /* Fix the PSP index of this MCB */ + /* Fix the PSP for psp and environment MCB's */ MCB * pspmcb=(MCB *)HostMake(pspseg-1,0); pspmcb->psp_segment=pspseg; MCB * envmcb=(MCB *)HostMake(envseg-1,0); envmcb->psp_segment=pspseg; DOS_PSP psp(pspseg); - psp.MakeNew(memsize+pspseg); + psp.MakeNew(memsize); psp.SetEnvironment(envseg); psp.SetFileHandle(STDIN ,DOS_FindDevice("CON")); psp.SetFileHandle(STDOUT,DOS_FindDevice("CON")); @@ -173,233 +198,132 @@ static void SetupCMDLine(Bit16u pspseg,ParamBlock * block) psp.SetCommandTail(block->exec.cmdtail); } -static bool COM_Load(char * name,ParamBlock * block,Bit8u flag) { - Bit16u fhandle; - Bit16u size;Bit16u readsize; - Bit16u envseg,comseg; - Bit32u pos; - - DOS_PSP callpsp(dos.psp); - - if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; - if (flag!=OVERLAY) { - /* Allocate a new Environment */ - envseg=block->exec.envseg; - if (!MakeEnv(name,&envseg)) return false; - /* Allocate max memory for COM file and PSP */ - size=0xffff; - DOS_AllocateMemory(&comseg,&size); - //TODO Errors check for minimun of 64kb in pages - if (Bit32u(size <<4)<0x1000) { - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - DOS_FreeMemory(envseg); - return false; - } - DOS_AllocateMemory(&comseg,&size); - } else { - comseg=block->overlay.loadseg; - } - /* Memory allocated now load the program */ - /* Now copy the File into allocated memory */ - pos=0; - DOS_SeekFile(fhandle,&pos,0); - readsize=0xffff-256; - if (flag==OVERLAY) { - DOS_ReadFile(fhandle,HostMake(comseg,0),&readsize); - } else { - DOS_ReadFile(fhandle,HostMake(comseg,256),&readsize); - } - DOS_CloseFile(fhandle); - if (flag==OVERLAY) /* Everything what should be done for Overlays */ - return true; - SetupPSP(comseg,size,envseg); - SetupCMDLine(comseg,block); - /* Setup termination Address */ - RealSetVec(0x22,RealMakeSeg(cs,reg_ip)); - DOS_PSP compsp(comseg); - compsp.SetInt22(RealMakeSeg(cs,reg_ip)); - /* Everything setup somewhat setup CS:IP and SS:SP */ - /* First save the SS:SP of program that called execute */ - callpsp.SetStack(RealMakeSeg(ss,reg_sp)); - /* Clear out first Stack entry to point to int 20h at psp:0 */ - real_writew(comseg,0xfffe,0); - dos.psp=comseg; - switch (flag) { - case LOADNGO: - /* copy fcbs */ - compsp.SetFCB1(block->exec.fcb1); - compsp.SetFCB2(block->exec.fcb2); - /* setup reg */ - SegSet16(cs,comseg); - SegSet16(ss,comseg); - SegSet16(ds,comseg); - SegSet16(es,comseg); - flags.intf=true; - reg_ip=0x100; - reg_sp=0xFFFE; - reg_ax=0; - reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0; - return true; - case LOAD: - block->exec.initsssp=RealMake(comseg,0xfffe); - block->exec.initcsip=RealMake(comseg,0x100); - return true; - } - return false; - -} - - -static bool EXE_Load(char * name,ParamBlock* _block,Bit8u flag) { - - EXE_Header header; - Bit16u fhandle;Bit32u i; - Bit16u size,minsize,maxsize,freesize;Bit16u readsize; - Bit16u envseg,pspseg,exeseg; - Bit32u imagesize,headersize; - - // During loading process, th param-block-mem might be overwritten (HostPt!) and - // therefore change the relocation address, so save these values. - ParamBlock block; - memcpy(&block,_block,sizeof(ParamBlock)); - - DOS_PSP callpsp(dos.psp); - - if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; - if (flag!=OVERLAY) { - /* Allocate a new Environment */ - envseg=block.exec.envseg; - if (!MakeEnv(name,&envseg)) return false; - }; - - /* First Read the EXE Header */ - readsize=sizeof(EXE_Header); - DOS_ReadFile(fhandle,(Bit8u*)&header,&readsize); - /* Calculate the size of the image to load */ - headersize=header.headersize*16; - imagesize=header.pages*512-headersize; - if (flag!=OVERLAY) { - minsize=long2para(imagesize+(header.minmemory<<4)+256); - if (header.maxmemory!=0) maxsize=long2para(imagesize+(header.maxmemory<<4)+256); - else maxsize=0xffff; - freesize=0xffff; - /* Check for enough free memory */ - DOS_AllocateMemory(&exeseg,&freesize); - if (minsize>freesize) { - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - DOS_FreeMemory(envseg); - return false; - } - if (maxsize>freesize) { - size=freesize; - } else size=maxsize; - if ((header.minmemory|header.maxmemory)==0) { - size=freesize; - E_Exit("Special case exe header max and min=0"); - } - if (!DOS_AllocateMemory(&pspseg,&size)) { - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - DOS_FreeMemory(envseg); - return false; - } - SetupPSP(pspseg,size,envseg); - SetupCMDLine(pspseg,&block); - exeseg=pspseg+16; - } else { - /* For OVERLAY */ - exeseg=block.overlay.loadseg; - } - /* Load the image in 32k blocks */ - DOS_SeekFile(fhandle,&headersize,0); - Bit8u * imageoff=HostMake(exeseg,0); -//TODO File size checking and remove size - // Remove psp size -// imagesize=256; - // Maybe remove final page and add last bytes on page - if (header.extrabytes) { - imagesize-=512; - imagesize+=header.extrabytes; - }; - while (imagesize>0x7FFF) { - readsize=0x8000; - DOS_ReadFile(fhandle,imageoff,&readsize); - if (readsize!=0x8000) { - E_Exit("Illegal header"); - } - imageoff+=0x8000; - imagesize-=0x8000; - } - if (imagesize>0) { - readsize=(Bit16u) imagesize; - DOS_ReadFile(fhandle,imageoff,&readsize); - } - headersize=header.reloctable; - DOS_SeekFile(fhandle,&headersize,0); - RealPt reloc; - for (i=0;iexec.envseg; + if (!MakeEnv(name,&envseg)) { + DOS_CloseFile(fhandle); + return false; + } + /* 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; + } + if (maxfreeoverlay.loadseg,0; + /* Load the executable */ + loadaddress=HostMake(loadseg,0); + if (iscom) { /* COM Load 64k - 256 bytes max */ + pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); + readsize=0xffff-256; + DOS_ReadFile(fhandle,loadaddress,&readsize); + } else { /* EXE Load in 32kb blocks and then relocate */ + pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); + while (imagesize>0x7FFF) { + readsize=0x8000;DOS_ReadFile(fhandle,loadaddress,&readsize); + if (readsize!=0x8000) E_Exit("Illegal header"); + loadaddress+=0x8000;imagesize-=0x8000; + } + if (imagesize>0) { + readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadaddress,&readsize); + if (readsize!=imagesize) E_Exit("Illegal header"); + } + /* 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;iexec.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 */ + reg_ax=0; + reg_cx=reg_dx=reg_bx=reg_si=reg_di=reg_bp=0; + SegSet16(ds,pspseg);SegSet16(es,pspseg); + return true; + } + return false; } +