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;
}
Esempio n. 2
0
Bitu XMS_Handler(void) {
//	LOG(LOG_MISC,LOG_ERROR)("XMS: CALL %02X",reg_ah);
	switch (reg_ah) {
	case XMS_GET_VERSION:										/* 00 */
		reg_ax=XMS_VERSION;
		reg_bx=XMS_DRIVER_VERSION;
		reg_dx=0;	/* No we don't have HMA */
		break;
	case XMS_ALLOCATE_HIGH_MEMORY:								/* 01 */
		reg_ax=0;
		reg_bl=HIGH_MEMORY_NOT_EXIST;
		break;
	case XMS_FREE_HIGH_MEMORY:									/* 02 */
		reg_ax=0;
		reg_bl=HIGH_MEMORY_NOT_EXIST;
		break;
		
	case XMS_GLOBAL_ENABLE_A20:									/* 03 */
	case XMS_LOCAL_ENABLE_A20:									/* 05 */
		SET_RESULT(XMS_EnableA20(true));
		break;
	case XMS_GLOBAL_DISABLE_A20:								/* 04 */
	case XMS_LOCAL_DISABLE_A20:									/* 06 */
		SET_RESULT(XMS_EnableA20(false));
		break;	
	case XMS_QUERY_A20:											/* 07 */
		reg_ax = XMS_GetEnabledA20();
		reg_bl = 0;
		break;
	case XMS_QUERY_FREE_EXTENDED_MEMORY:						/* 08 */
		reg_bl = XMS_QueryFreeMemory(reg_ax,reg_dx);
		break;
	case XMS_ALLOCATE_ANY_MEMORY:								/* 89 */
		reg_edx &= 0xffff;
		// fall through
	case XMS_ALLOCATE_EXTENDED_MEMORY:							/* 09 */
		{
		Bit16u handle = 0;
		SET_RESULT(XMS_AllocateMemory(reg_dx,handle));
		reg_dx = handle;
		}; break;
	case XMS_FREE_EXTENDED_MEMORY:								/* 0a */
		SET_RESULT(XMS_FreeMemory(reg_dx));
		break;
	case XMS_MOVE_EXTENDED_MEMORY_BLOCK:						/* 0b */
		SET_RESULT(XMS_MoveMemory(SegPhys(ds)+reg_si),false);
		break;
	case XMS_LOCK_EXTENDED_MEMORY_BLOCK: {						/* 0c */
		Bit32u address;
		Bitu res = XMS_LockMemory(reg_dx, address);
		if(res) reg_bl = (Bit8u)res;
		reg_ax = (res==0);
		if (res==0) { // success
			reg_bx=(Bit16u)(address & 0xFFFF);
			reg_dx=(Bit16u)(address >> 16);
		};
		}; break;
	case XMS_UNLOCK_EXTENDED_MEMORY_BLOCK:						/* 0d */
		SET_RESULT(XMS_UnlockMemory(reg_dx));
		break;
	case XMS_GET_EMB_HANDLE_INFORMATION:  						/* 0e */
		SET_RESULT(XMS_GetHandleInformation(reg_dx,reg_bh,reg_bl,reg_dx),false);
		break;
	case XMS_RESIZE_ANY_EXTENDED_MEMORY_BLOCK:					/* 0x8f */
		if(reg_ebx > reg_bx) LOG_MSG("64MB memory limit!");
		//fall through
	case XMS_RESIZE_EXTENDED_MEMORY_BLOCK:						/* 0f */
		SET_RESULT(XMS_ResizeMemory(reg_dx, reg_bx));
		break;
	case XMS_ALLOCATE_UMB: {									/* 10 */
		if (!umb_available) {
			reg_ax=0;
			reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED;
			break;
		}
		Bit16u umb_start=dos_infoblock.GetStartOfUMBChain();
		if (umb_start==0xffff) {
			reg_ax=0;
			reg_bl=UMB_NO_BLOCKS_AVAILABLE;
			reg_dx=0;	// no upper memory available
			break;
		}
		/* Save status and linkage of upper UMB chain and link upper
		   memory to the regular MCB chain */
		Bit8u umb_flag=dos_infoblock.GetUMBChainState();
		if ((umb_flag&1)==0) DOS_LinkUMBsToMemChain(1);
		Bit8u old_memstrat=DOS_GetMemAllocStrategy()&0xff;
		DOS_SetMemAllocStrategy(0x40);	// search in UMBs only

		Bit16u size=reg_dx;Bit16u seg;
		if (DOS_AllocateMemory(&seg,&size)) {
			reg_ax=1;
			reg_bx=seg;
		} else {
			reg_ax=0;
			if (size==0) reg_bl=UMB_NO_BLOCKS_AVAILABLE;
			else reg_bl=UMB_ONLY_SMALLER_BLOCK;
			reg_dx=size;	// size of largest available UMB
		}

		/* Restore status and linkage of upper UMB chain */
		Bit8u current_umb_flag=dos_infoblock.GetUMBChainState();
		if ((current_umb_flag&1)!=(umb_flag&1)) DOS_LinkUMBsToMemChain(umb_flag);
		DOS_SetMemAllocStrategy(old_memstrat);
		}
		break;
	case XMS_DEALLOCATE_UMB:									/* 11 */
		if (!umb_available) {
			reg_ax=0;
			reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED;
			break;
		}
		if (dos_infoblock.GetStartOfUMBChain()!=0xffff) {
			if (DOS_FreeMemory(reg_dx)) {
				reg_ax=0x0001;
				break;
			}
		}
		reg_ax=0x0000;
		reg_bl=UMB_NO_BLOCKS_AVAILABLE;
		break;
	case XMS_QUERY_ANY_FREE_MEMORY:								/* 88 */
		reg_bl = XMS_QueryFreeMemory(reg_ax,reg_dx);
		reg_eax &= 0xffff;
		reg_edx &= 0xffff;
		reg_ecx = (MEM_TotalPages()*MEM_PAGESIZE)-1;			// highest known physical memory address
		break;
	case XMS_GET_EMB_HANDLE_INFORMATION_EXT: {					/* 8e */
		Bit8u free_handles;
		Bitu result = XMS_GetHandleInformation(reg_dx,reg_bh,free_handles,reg_dx);
		if (result != 0) reg_bl = result;
		else {
			reg_edx &= 0xffff;
			reg_cx = free_handles;
		}
		reg_ax = (result==0);
		} break;
	default:
		LOG(LOG_MISC,LOG_ERROR)("XMS: unknown function %02X",reg_ah);
		reg_ax=0;
		reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED;
	}