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; PhysPt loadaddress;RealPt relocpt; Bitu headersize,imagesize; DOS_ParamBlock block(block_pt); block.LoadData(); if (flags!=LOADNGO && flags!=OVERLAY && flags!=LOAD) { E_Exit("DOS:Not supported execute mode %d for file %s",flags,name); } /* Check for EXE or COM File */ bool iscom=false; if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; len=sizeof(EXE_Header); if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&len)) { DOS_CloseFile(fhandle); return false; } if (len<sizeof(EXE_Header)) { if (len==0) { /* Prevent executing zero byte files */ DOS_SetError(DOSERR_ACCESS_DENIED); DOS_CloseFile(fhandle); return false; } /* Otherwise must be a .com file */ iscom=true; } else { /* Convert the header to correct endian, i hope this works */ HostPt endian=(HostPt)&head; for (i=0;i<sizeof(EXE_Header)/2;i++) { *((Bit16u *)endian)=host_readw(endian); endian+=2; } if ((head.signature!=MAGIC1) && (head.signature!=MAGIC2)) iscom=true; else { if(head.pages & ~0x07ff) /* 1 MB dos maximum address limit. Fixes TC3 IDE (kippesoep) */ LOG(LOG_EXEC,LOG_NORMAL)("Weird header: head.pages > 1 MB"); head.pages&=0x07ff; headersize = head.headersize*16; imagesize = head.pages*512-headersize; if (imagesize+headersize<512) imagesize = 512-headersize; } } Bit8u * loadbuf=(Bit8u *)new Bit8u[0x10000]; if (flags!=OVERLAY) { /* Create an environment block */ envseg=block.exec.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; if (machine==MCH_PCJR) { /* try to load file into memory below 96k */ pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); Bit16u dataread=0x1800; DOS_ReadFile(fhandle,loadbuf,&dataread); if (dataread<0x1800) maxsize=dataread; if (minsize>maxsize) minsize=maxsize; } } 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 (maxfree<minsize) { DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); DOS_FreeMemory(envseg); return false; } if (maxfree<maxsize) memsize=maxfree; else memsize=maxsize; if (!DOS_AllocateMemory(&pspseg,&memsize)) E_Exit("DOS:Exec error in memory"); if (iscom && (machine==MCH_PCJR) && (pspseg<0x2000)) { maxsize=0xffff; /* resize to full extent of memory block */ DOS_ResizeMemory(pspseg,&maxsize); /* now try to lock out memory above segment 0x2000 */ if ((real_readb(0x2000,0)==0x5a) && (real_readw(0x2000,1)==0) && (real_readw(0x2000,3)==0x7ffe)) { /* MCB after PCJr graphics memory region is still free */ if (pspseg+maxsize==0x17ff) { DOS_MCB cmcb((Bit16u)(pspseg-1)); cmcb.SetType(0x5a); // last block } } } loadseg=pspseg+16; if (!iscom) { /* Check if requested to load program into upper part of allocated memory */ if ((head.minmemory == 0) && (head.maxmemory == 0)) loadseg = ((pspseg+memsize)*0x10-imagesize)/0x10; } } else loadseg=block.overlay.loadseg; /* Load the executable */ loadaddress=PhysMake(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,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,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,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); // if (readsize!=0x8000) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); loadaddress+=0x8000;imagesize-=0x8000; } if (imagesize>0) { readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); // if (readsize!=imagesize) LOG(LOG_EXEC,LOG_NORMAL)("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;i<head.relocations;i++) { readsize=4;DOS_ReadFile(fhandle,(Bit8u *)&relocpt,&readsize); relocpt=host_readd((HostPt)&relocpt); //Endianize PhysPt address=PhysMake(RealSeg(relocpt)+loadseg,RealOff(relocpt)); mem_writew(address,mem_readw(address)+relocate); } } delete[] loadbuf; DOS_CloseFile(fhandle); /* 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); }; CALLBACK_SCF(false); /* Carry flag cleared for caller if successfull */ if (flags==OVERLAY) return true; /* Everything done for overlays */ RealPt csip,sssp; if (iscom) { csip=RealMake(pspseg,0x100); sssp=RealMake(pspseg,0xfffe); mem_writew(PhysMake(pspseg,0xfffe),0); } else { csip=RealMake(loadseg+head.initCS,head.initIP); sssp=RealMake(loadseg+head.initSS,head.initSP); } if (flags==LOAD) { DOS_PSP callpsp(dos.psp()); /* Save the SS:SP on the PSP of calling program */ callpsp.SetStack(RealMakeSeg(ss,reg_sp)); /* Switch the psp's */ dos.psp(pspseg); DOS_PSP newpsp(dos.psp()); dos.dta(RealMake(newpsp.GetSegment(),0x80)); block.exec.initsssp = sssp; block.exec.initcsip = csip; block.SaveData(); return true; } 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(); DOS_PSP callpsp(dos.psp()); /* Save the SS:SP on the PSP of calling program */ callpsp.SetStack(RealMakeSeg(ss,reg_sp)); /* Switch the psp's and set new DTA */ dos.psp(pspseg); DOS_PSP newpsp(dos.psp()); dos.dta(RealMake(newpsp.GetSegment(),0x80)); /* 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)); /* DOS starts programs with a RETF, so our IRET should not modify critical flags (IOPL in v86 mode); interrupt flag is set explicitly, test flags cleared */ mem_writew(SegPhys(ss)+reg_sp+4,(reg_flags&(~FMASK_TEST))|FLAG_IF); /* Setup the rest of the registers */ reg_ax=reg_bx=0;reg_cx=0xff; reg_dx=pspseg; reg_si=RealOff(csip); reg_di=RealOff(sssp); reg_bp=0x91c; /* DOS internal stack begin relict */ 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 /* 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(); return true; } return false; }
ULONG ulExecProg (CHAR *szProgName) { ULONG ulBootDrive; ULONG ulAppType; CHAR szCmdName[CCHMAXPATH]; CHAR szLine[CCHMAXPATH]; PSZ pszScanEnv; RESULTCODES rcTermination; APIRET rcFailure = 0; PCHAR pszEnvironment; /* * Diese Routine versucht eine Shell zu starten. */ pszEnvironment = MakeEnv (pShareInitOS2->pszEnvironment); if ( !(rcFailure = ScanEnv(ENV_SAMWORKPLACE, &pszScanEnv, pszEnvironment)) ) { rcFailure = DosQueryAppType(pszScanEnv, &ulAppType); if ( !rcFailure ) if ( ( (ulAppType & 7) == FAPPTYP_NOTSPEC) || ( (ulAppType & 7) == FAPPTYP_WINDOWAPI) ) rcFailure = DosExecPgm (szLine, /* Object name buffer */ sizeof(szLine), /* Length of object name buffer */ EXEC_ASYNCRESULT, /* Execution flags */ "", /* Argument string */ pszEnvironment, /* Environment */ &rcTermination, /* Termination codes */ pszScanEnv); /* Program file name */ else rcFailure = 1; } if (rcFailure) { WinAlarm (HWND_DESKTOP, WA_ERROR); DebugS (1, "DosExecPgm <1> failed"); } if (rcFailure) { rcFailure = DosExecPgm (szLine, /* Object name buffer */ sizeof(szLine), /* Length of object name buffer */ EXEC_ASYNCRESULT, /* Execution flags */ "", /* Argument string */ pszEnvironment, /* Environment */ &rcTermination, /* Termination codes */ szProgName); /* Program file name */ } if (rcFailure) { if (!(rcFailure = DosScanEnv (ENV_SAMWORKPLACE, &pszScanEnv))) rcFailure = DosExecPgm (szLine, /* Object name buffer */ sizeof(szLine), /* Length of object name buffer */ EXEC_ASYNCRESULT, /* Execution flags */ "", /* Argument string */ pszEnvironment, /* Environment */ &rcTermination, /* Termination codes */ pszScanEnv); /* Program file name */ } if (rcFailure) { DebugS (1, "DosExecPgm <2> failed"); DosQuerySysInfo (QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &ulBootDrive, sizeof (ULONG)); memset (szCmdName, '\0', sizeof(szCmdName)); szCmdName[0] = (CHAR) (ulBootDrive - 1) + 'A'; strcpy (szCmdName+1, ":\\OS2\\PMSHELL.EXE"); rcFailure = DosExecPgm (szLine, /* Object name buffer */ sizeof(szLine), /* Length of object name buffer */ EXEC_ASYNCRESULT, /* Execution flags */ "", /* Argument string */ pszEnvironment, /* Environment */ &rcTermination, /* Termination codes */ szCmdName); /* Program file name */ } /* Falls Shell nicht gestartet werden konnte, wird cmd.exe aufgerufen */ if (rcFailure) { DebugS (1, "DosExecPgm <3> failed"); if (!(rcFailure = DosScanEnv ("COMSPEC", &pszScanEnv))) rcFailure = DosExecPgm (szLine, /* Object name buffer */ sizeof(szLine), /* Length of object name buffer */ EXEC_ASYNCRESULT, /* Execution flags */ "/K", /* Argument string */ pszEnvironment, /* Environment */ &rcTermination, /* Termination codes */ pszScanEnv); /* Program file name */ } if (rcFailure) { DebugS (1, "DosExecPgm <4> failed"); DosQuerySysInfo (QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &ulBootDrive, sizeof (ULONG)); memset (szCmdName, '\0', sizeof(szCmdName)); szCmdName[0] = (CHAR) (ulBootDrive - 1) + 'A'; strcpy (szCmdName+1, ":\\OS2\\CMD.EXE"); rcFailure = DosExecPgm (szLine, /* Object name buffer */ sizeof(szLine), /* Length of object name buffer */ EXEC_ASYNCRESULT, /* Execution flags */ "/K", /* Argument string */ pszEnvironment, /* Environment */ &rcTermination, /* Termination codes */ szCmdName); /* Program file name */ } DosFreeMem(pszEnvironment); if (rcFailure) { intSammyRetCode = rcFailure; WinPostQueueMsg (hmq, WM_CLOSE, 0L, 0L); DebugS (1, "DosExecPgm <5> failed"); } return (rcFailure ? 0 : rcTermination.codeTerminate); }