Exemple #1
0
//=========================================================================
// Fork the current process.
// Return the pid of the new process
//=========================================================================
unsigned short DoFork()
{
	unsigned short pid;
	struct FCB *fcbin, *fcbout, *fcberr;

	// Copy task structure, with adjustments
	struct Task *task = (struct Task *) AllocKMem(sizeof(struct Task));

	memcpy((char *) task, (char *) currentTask, sizeof(struct Task));
	pid = task->pid = nextpid++;
	task->currentDirName = AllocKMem(
			(size_t) strlen(currentTask->currentDirName) + 1);
	strcpy(task->currentDirName, currentTask->currentDirName);
	task->parentPort = 0;

	// Create Page Directory
	task->cr3 = (long) VCreatePageDir(pid, currentTask->pid);

	Elf64_Ehdr *header = (Elf64_Ehdr *)UserCode;
	if ((header->e_ident)[1] != 'E')// Not the best of tests, but good enough
		CopyPages(UserCode, task);
	else
	{

		Elf64_Phdr *pheadertable = (Elf64_Phdr *)(UserCode + header->e_phoff);
		int i;

		for (i = 0; i < header->e_phnum; i++)
		{
			if (pheadertable[i].p_type == PT_LOAD)
			{
				CopyPages(pheadertable[i].p_vaddr, task);
			}
		}
	}

	// Copy user stack and kernel stack
	CopyPages(UserStack, task);

	//Page Tables to allow access to E1000
	/*CreatePTEWithPT((struct PML4 *) task->cr3, registers, (long) registers, 0, 7);
	 CreatePTEWithPT((struct PML4 *) task->cr3, registers + 0x1000,
	 (long) registers + 0x1000, 0, 7);
	 CreatePTEWithPT((struct PML4 *) task->cr3, registers + 0x2000,
	 (long) registers + 0x2000, 0, 7);
	 CreatePTEWithPT((struct PML4 *) task->cr3, registers + 0x3000,
	 (long) registers + 0x3000, 0, 7);
	 CreatePTEWithPT((struct PML4 *) task->cr3, registers + 0x4000,
	 (long) registers + 0x4000, 0, 7);
	 CreatePTEWithPT((struct PML4 *) task->cr3, registers + 0x5000,
	 (long) registers + 0x5000, 0, 7);*/
	task->forking = 1;

	// Create FCBs for STDI, STDOUT, and STDERR

	// STDIN
	fcbin = (struct FCB *) AllocKMem(sizeof(struct FCB));
	fcbin->fileDescriptor = STDIN;
	fcbin->deviceType = KBD;
	task->fcbList = fcbin;

	// STDOUT
	fcbout = (struct FCB *) AllocKMem(sizeof(struct FCB));
	fcbout->fileDescriptor = STDOUT;
	fcbout->deviceType = CONS;
	fcbin->nextFCB = fcbout;

	//STDERR
	fcberr = (struct FCB *) AllocKMem(sizeof(struct FCB));
	fcberr->fileDescriptor = STDERR;
	fcberr->deviceType = CONS;
	fcbout->nextFCB = fcberr;
	fcberr->nextFCB = 0;
	task->FDbitmap = 7;

	// Run the forked process
	asm("pushf");
	asm("cli");
	LinkTask(task);
	asm("popf");

	// We want the forked process to return to this point. So we
	// need to save the registers from here to the new task structure.
	SaveRegisters(task);

	// Return 0 to the forked process, the new pid to the forking one.
	if (pid == currentTask->pid)
		pid = 0;
	return pid;
}
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;
}