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;
}
Exemple #2
0
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);
   }