static bool MakeEnv(char * name,Bit16u * segment) {
	/* If segment to copy environment is 0 copy the caller's environment */
	DOS_PSP psp(dos.psp());
	PhysPt envread,envwrite;
	Bit16u envsize=1;
	bool parentenv=true;

	if (*segment==0) {
		if (!psp.GetEnvironment()) parentenv=false;				//environment seg=0
		envread=PhysMake(psp.GetEnvironment(),0);
	} else {
		if (!*segment) parentenv=false;						//environment seg=0
		envread=PhysMake(*segment,0);
	}

	if (parentenv) {
		for (envsize=0; ;envsize++) {
			if (envsize>=MAXENV - ENV_KEEPFREE) {
				DOS_SetError(DOSERR_ENVIRONMENT_INVALID);
				return false;
			}
			if (mem_readw(envread+envsize)==0) break;
		}
		envsize += 2;									/* account for trailing \0\0 */
	}
	Bit16u size=long2para(envsize+ENV_KEEPFREE);
	if (!DOS_AllocateMemory(segment,&size)) return false;
	envwrite=PhysMake(*segment,0);
	if (parentenv) {
		MEM_BlockCopy(envwrite,envread,envsize);
//		mem_memcpy(envwrite,envread,envsize);
		envwrite+=envsize;
	} else {
		mem_writeb(envwrite++,0);
	}
	mem_writew(envwrite,1);
	envwrite+=2;
	char namebuf[DOS_PATHLENGTH];
	if (DOS_Canonicalize(name,namebuf)) {
		MEM_BlockWrite(envwrite,namebuf,strlen(namebuf)+1);
		return true;
	} else return false;
}
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;
}
Exemplo n.º 3
0
COUNT DosExeLoader(BYTE FAR * namep, exec_blk FAR * exp, COUNT mode)
{
  COUNT rc,
    /*err,     */
    /*env_size,*/
    i;
  UCOUNT nBytesRead;
  UWORD mem,
    env,
    asize,
    start_seg;
  ULONG image_size;
  ULONG image_offset;
  BYTE FAR *sp;
  psp FAR *p;
  psp FAR *q = MK_FP(cu_psp, 0);
  mcb FAR *mp;
  iregs FAR *irp;
  UWORD reloc[2];
  seg FAR *spot;
  LONG exe_size;

  int  ModeLoadHigh = mode & 0x80;
  UBYTE UMBstate = uppermem_link;

  mode &= 0x7f;
    

  /* Clone the environement and create a memory arena     */
  if (mode != OVERLAY)
  {
    if ((rc = ChildEnv(exp, &env, namep)) != SUCCESS)
      return rc;
  }
  else
    mem = exp->load.load_seg;

  /* compute image offset from the header                 */
  asize = 16;
  image_offset = (ULONG)header.exHeaderSize * asize;

  /* compute image size by removing the offset from the   */
  /* number pages scaled to bytes plus the remainder and  */
  /* the psp                                              */
  /*  First scale the size                                */
  asize = 512;
  image_size = (ULONG)header.exPages * asize;
  /* remove the offset                                    */
  image_size -= image_offset;

  /* and finally add in the psp size                      */
  if (mode != OVERLAY)
    image_size += sizeof(psp);             /*TE 03/20/01*/
    
  if (mode != OVERLAY)
  {
    if (  ModeLoadHigh && uppermem_root)
    {
      DosUmbLink(1);                          /* link in UMB's */
      mem_access_mode |= ModeLoadHigh;
    }
  
    /* Now find out how many paragraphs are available       */
    if ((rc = DosMemLargest((seg FAR *) & asize)) != SUCCESS)
    {
      DosMemFree(env);
      return rc;
    }

    exe_size = (LONG) long2para(image_size) + header.exMinAlloc;
    
    
    /* + long2para((LONG) sizeof(psp)); ?? see above
       image_size += sizeof(psp) -- 1999/04/21 ska */
    if (exe_size > asize && (mem_access_mode & 0x80))
    {
      /* First try low memory */
      mem_access_mode &= ~0x80;
      rc = DosMemLargest((seg FAR *) & asize);
      mem_access_mode |= 0x80;
      if (rc != SUCCESS)
      {
        DosMemFree(env);
        return rc;
      }
    }
    if (exe_size > asize)
    {
      DosMemFree(env);
      return DE_NOMEM;
    }
    exe_size = (LONG) long2para(image_size) + header.exMaxAlloc;
    /* + long2para((LONG) sizeof(psp)); ?? -- 1999/04/21 ska */
    if (exe_size > asize)
      exe_size = asize;
    
    /* TE if header.exMinAlloc == header.exMaxAlloc == 0,
       DOS will allocate the largest possible memory area
       and load the image as high as possible into it.
       discovered (and after that found in RBIL), when testing NET */
       
    if ((header.exMinAlloc | header.exMaxAlloc ) == 0)
      exe_size = asize;
      
      
/* /// Removed closing curly brace.  We should not attempt to allocate
       memory if we are overlaying the current process, because the new
       process will simply re-use the block we already have allocated.
       This was causing execl() to fail in applications which use it to
       overlay (replace) the current exe file with a new one.
       Jun 11, 2000 - rbc
  } */


  /* Allocate our memory and pass back any errors         */
  /* We can still get an error on first fit if the above  */
  /* returned size was a bet fit case                     */
  /* ModeLoadHigh = 80 = try high, then low                   */
  if ((rc = DosMemAlloc((seg) exe_size, mem_access_mode | ModeLoadHigh, (seg FAR *) & mem
                        ,(UWORD FAR *) & asize)) < 0)
  {
    if (rc == DE_NOMEM)
    {
      if ((rc = DosMemAlloc(0, LARGEST, (seg FAR *) & mem
                            ,(UWORD FAR *) & asize)) < 0)
      {
        DosMemFree(env);
        return rc;
      }
      /* This should never happen, but ... */
      if (asize < exe_size)
      {
        DosMemFree(mem);
        DosMemFree(env);
        return rc;
      }
    }
    else
    {
      DosMemFree(env);
      return rc;
    }
  }
  else
    /* with no error, we got exactly what we asked for      */
    asize = exe_size;

#ifdef DEBUG  
  printf("loading '%S' at %04x\n", namep, mem);
#endif    

/* /// Added open curly brace and "else" clause.  We should not attempt
       to allocate memory if we are overlaying the current process, because
       the new process will simply re-use the block we already have allocated.
       This was causing execl() to fail in applications which use it to
       overlay (replace) the current exe file with a new one.
       Jun 11, 2000 - rbc */
  }
  else
    asize = exe_size;
/* /// End of additions.  Jun 11, 2000 - rbc */

  if (  ModeLoadHigh && uppermem_root)
    {
    mem_access_mode &= ~ModeLoadHigh;              /* restore old situation */
    DosUmbLink(UMBstate);                          /* restore link state */
    }

   
  if (mode != OVERLAY)
  {
    /* memory found large enough - continue processing      */
    mp = MK_FP(mem, 0);
    ++mem;
  }
  else
    mem = exp->load.load_seg;

  /* create the start seg for later computations          */
  if (mode == OVERLAY)
    start_seg = mem;
  else
  {
    start_seg = mem + long2para((LONG) sizeof(psp));
  }

  /* Now load the executable                              */
  /* If file not found - error                            */
  /* NOTE - this is fatal because we lost it in transit   */
  /* from DosExec!                                        */
  if ((rc = DosOpen(namep, 0)) < 0)
  {
    fatal("(DosExeLoader) exe file lost in transit");
  }
  /* offset to start of image                             */
  if (doslseek(rc, image_offset, 0) != image_offset)
  {
    if (mode != OVERLAY)
    {
      DosMemFree(--mem);
      DosMemFree(env);
    }
    return DE_INVLDDATA;
  }

  /* read in the image in 32K chunks                      */
  if (mode != OVERLAY)
  {
    exe_size = image_size - sizeof(psp);
  }
  else
    exe_size = image_size;

  if (exe_size > 0)
  {
    if (mode != OVERLAY)
    {
      if ((header.exMinAlloc == 0) && (header.exMaxAlloc == 0))
      {
                             /* then the image should be placed as high as possible */
        start_seg = start_seg + mp->m_size - (image_size + 15) / 16;
      }
    }

    sp = MK_FP(start_seg, 0x0);

    do
    {
      nBytesRead = DosRead((COUNT) rc, (COUNT) (exe_size < CHUNK ? exe_size : CHUNK), (VOID FAR *) sp, &UnusedRetVal);
      sp = add_far((VOID FAR *) sp, (ULONG) nBytesRead);
      exe_size -= nBytesRead;
    }
    while (nBytesRead && exe_size > 0);
  }

  /* relocate the image for new segment                   */
  doslseek(rc, (LONG) header.exRelocTable, 0);
  for (i = 0; i < header.exRelocItems; i++)
  {
    if (DosRead(rc, sizeof(reloc), (VOID FAR *) & reloc[0], &UnusedRetVal) != sizeof(reloc))
    {
      return DE_INVLDDATA;
    }
    if (mode == OVERLAY)
    {
      spot = MK_FP(reloc[1] + mem, reloc[0]);
      *spot += exp->load.reloc;
    }
    else
    {
      /*      spot = MK_FP(reloc[1] + mem + 0x10, reloc[0]); */
      spot = MK_FP(reloc[1] + start_seg, reloc[0]);
      *spot += start_seg;
    }
  }

  /* and finally close the file                           */
  DosClose(rc);

  /* exit here for overlay                                */
  if (mode == OVERLAY)
    return SUCCESS;

  /* point to the PSP so we can build it                  */
  p = MK_FP(mem, 0);
  setvec(0x22, (VOID(INRPT FAR *) (VOID)) MK_FP(user_r->CS, user_r->IP));
  new_psp(p, mem + asize);

  asize = patchPSP(mem - 1, env, exp, namep); /* asize = fcbcode */

  /* Transfer control to the executable                   */
  p->ps_parent = cu_psp;
  p->ps_prevpsp = (BYTE FAR *) MK_FP(cu_psp, 0);
  q->ps_stack = (BYTE FAR *) user_r;
  user_r->FLAGS &= ~FLG_CARRY;

  switch (mode)
  {
    case LOADNGO:
      /* build the user area on the stack                     */
      irp = MK_FP(header.exInitSS + start_seg,
              ((header.exInitSP - sizeof(iregs)) & 0xffff));

      /* start allocating REGs                                */
      /* Note: must match es & ds memory segment              */
      irp->ES = irp->DS = mem;
      irp->CS = header.exInitCS + start_seg;
      irp->IP = header.exInitIP;
      irp->AX = asize;             /* asize = fcbcode    */
      irp->BX =
      irp->CX =
      irp->DX =
      irp->SI =
      irp->DI =
      irp->BP = 0;
      irp->FLAGS = 0x200;

      cu_psp = mem;
      dta = p->ps_dta;

      if (InDOS)
        --InDOS;
      exec_user(irp);
      /* We should never be here                      */
      fatal("KERNEL RETURNED!!!");
      break;

    case LOAD:
      cu_psp = mem;
      exp->exec.stack = MK_FP(header.exInitSS + start_seg, header.exInitSP);
      *((UWORD FAR *) exp->exec.stack) = asize; /* fcbcode */
      exp->exec.start_addr = MK_FP(header.exInitCS + start_seg, header.exInitIP);
      return SUCCESS;
  }
  return DE_INVLDFMT;
}
Exemplo n.º 4
0
COUNT ChildEnv(exec_blk FAR * exp, UWORD * pChildEnvSeg, char far * pathname)
{
  BYTE FAR *pSrc;
  BYTE FAR *pDest;
  UWORD nEnvSize;
  COUNT RetCode;
/*  UWORD MaxEnvSize;                                                                                                                                           not used -- 1999/04/21 ska */
  psp FAR *ppsp = MK_FP(cu_psp, 0);

  /* create a new environment for the process             */
  /* copy parent's environment if exec.env_seg == 0       */

  pSrc = exp->exec.env_seg ?
      MK_FP(exp->exec.env_seg, 0) :
      MK_FP(ppsp->ps_environ, 0);

#if 0
  /* Every process requires an environment because of argv[0]
     -- 1999/04/21 ska */
  */
      if (!pSrc)                /* no environment to copy */
  {
    *pChildEnvSeg = 0;
    return SUCCESS;
  }
#endif

  nEnvSize = 1;
  /* This loop had not counted the very last '\0'
     -- 1999/04/21 ska */
  if (pSrc)
  {                             /* if no environment is available, one byte is required */
  
    for (nEnvSize = 0; ; nEnvSize++)
    {
                                /* Test env size and abort if greater than max          */
        if (nEnvSize >= MAXENV - ENV_KEEPFREE)
            return DE_INVLDENV;
        
        if (*(UWORD FAR *)(pSrc+nEnvSize) == 0)
            break;            
    }
    nEnvSize += 2;              /* account for trailing \0\0 */
  }

  /* allocate enough space for env + path                 */
  if ((RetCode = DosMemAlloc(long2para(nEnvSize + ENV_KEEPFREE),
                             mem_access_mode, (seg FAR *) pChildEnvSeg,
                           NULL /*(UWORD FAR *) MaxEnvSize ska */ )) < 0)
    return RetCode;
  pDest = MK_FP(*pChildEnvSeg + 1, 0);

  /* fill the new env and inform the process of its       */
  /* location throught the psp                            */

  /* copy the environment */
  if (pSrc)
  {
    fbcopy(pSrc, pDest, nEnvSize);
    pDest += nEnvSize;
  }
  else
    *pDest++ = '\0';            /* create an empty environment */

                                /* initialize 'extra strings' count */
  *((UWORD FAR *) pDest)++ = 1;

  /* copy complete pathname */
  if ((RetCode = truename(pathname, pDest, TRUE)) != SUCCESS) {
    return RetCode;
  }

  /* Theoretically one could either:
     + resize the already allocated block to best-fit behind the pathname, or
     + generate the filename into a temporary buffer to allocate only the
     minimum required environment -- 1999/04/21 ska */

  return SUCCESS;
}