Bit8u VESA_GetSVGAInformation(Bit16u seg,Bit16u off) { /* Fill 256 byte buffer with VESA information */ PhysPt buffer=PhysMake(seg,off); Bitu i; bool vbe2=false;Bit16u vbe2_pos=256+off; Bitu id=mem_readd(buffer); if (((id==0x56424532)||(id==0x32454256)) && (!int10.vesa_oldvbe)) vbe2=true; if (vbe2) { for (i=0;i<0x200;i++) mem_writeb(buffer+i,0); } else { for (i=0;i<0x100;i++) mem_writeb(buffer+i,0); } /* Fill common data */ MEM_BlockWrite(buffer,(void *)"VESA",4); //Identification if (!int10.vesa_oldvbe) mem_writew(buffer+0x04,0x200); //Vesa version 2.0 else mem_writew(buffer+0x04,0x102); //Vesa version 1.2 if (vbe2) { mem_writed(buffer+0x06,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_oem);i++) real_writeb(seg,vbe2_pos++,string_oem[i]); mem_writew(buffer+0x14,0x200); //VBE 2 software revision mem_writed(buffer+0x16,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_vendorname);i++) real_writeb(seg,vbe2_pos++,string_vendorname[i]); mem_writed(buffer+0x1a,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_productname);i++) real_writeb(seg,vbe2_pos++,string_productname[i]); mem_writed(buffer+0x1e,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_productrev);i++) real_writeb(seg,vbe2_pos++,string_productrev[i]); } else { mem_writed(buffer+0x06,int10.rom.oemstring); //Oemstring } mem_writed(buffer+0x0a,0x0); //Capabilities and flags mem_writed(buffer+0x0e,int10.rom.vesa_modes); //VESA Mode list mem_writew(buffer+0x12,(Bit16u)(vga.vmemsize/(64*1024))); // memory size in 64kb blocks return VESA_SUCCESS; }
Bit8u VESA_GetSVGAInformation(Bit16u seg,Bit16u off) { /* Fill 256 byte buffer with VESA information */ PhysPt buffer=PhysMake(seg,off); Bitu i; bool vbe2=false;Bit16u vbe2_pos; Bitu id=mem_readd(buffer); if (((id==0x56424532)||(id==0x32454256)) && (!int10.vesa_oldvbe)) vbe2=true; if (vbe2) { for (i=0;i<0x200;i++) mem_writeb(buffer+i,0); } else { for (i=0;i<0x100;i++) mem_writeb(buffer+i,0); } /* Fill common data */ MEM_BlockWrite(buffer,(void *)"VESA",4); //Identification if (!int10.vesa_oldvbe) mem_writew(buffer+0x04,0x200); //Vesa version 2.0 else mem_writew(buffer+0x04,0x102); //Vesa version 1.2 if (vbe2) { vbe2_pos=256+off; mem_writed(buffer+0x06,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_oem);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_oem[i]); mem_writew(buffer+0x14,0x200); //VBE 2 software revision mem_writed(buffer+0x16,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_vendorname);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_vendorname[i]); mem_writed(buffer+0x1a,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_productname);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_productname[i]); mem_writed(buffer+0x1e,RealMake(seg,vbe2_pos)); for (i=0;i<sizeof(string_productrev);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_productrev[i]); } else { vbe2_pos=0x20+off; mem_writed(buffer+0x06,int10.rom.oemstring); //Oemstring } if (vesa_bios_modelist_in_info) { /* put the modelist into the VBE struct itself, as modern BIOSes like to do. * NOTICE: This limits the modelist to what is able to fit! Extended modes may not fit, which is why the option is OFF by default. */ uint16_t modesg = int10.rom.vesa_modes >> 16; uint16_t modoff = int10.rom.vesa_modes & 0xFFFF; uint16_t m; mem_writed(buffer+0x0e,RealMake(seg,vbe2_pos)); //VESA Mode list do { if (vbe2) { if (vbe2_pos >= (509+off)) break; } else { if (vbe2_pos >= (253+off)) break; } m = real_readw(modesg,modoff); if (m == 0xFFFF) break; real_writew(seg,vbe2_pos,m); vbe2_pos += 2; modoff += 2; } while (1); real_writew(seg,vbe2_pos,0xFFFF); } else {
static void PC98_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { /* Do some filing */ PhysPt dest; dest=base+(row*CurMode->twidth+cleft)*2; Bit16u fill=' '; Bit16u fattr=attr ? attr : DefaultANSIAttr(); for (Bit8u x=0;x<(Bitu)(cright-cleft);x++) { mem_writew(dest,fill); mem_writew(dest+0x2000,fattr); dest+=2; } }
void CALLBACK_RunRealFar(Bit16u seg,Bit16u off) { reg_sp-=4; mem_writew(SegPhys(ss)+reg_sp,RealOff(CALLBACK_RealPointer(call_stop))); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(CALLBACK_RealPointer(call_stop))); Bit32u oldeip=reg_eip; Bit16u oldcs=SegValue(cs); reg_eip=off; SegSet16(cs,seg); DOSBOX_RunMachine(); reg_eip=oldeip; SegSet16(cs,oldcs); }
void CALLBACK_RunRealFar(Bit16u seg,Bit16u off) { reg_sp-=4; mem_writew(SegPhys(ss)+reg_sp,call_stop<<4); mem_writew(SegPhys(ss)+reg_sp+2,CB_SEG); Bit32u oldeip=reg_eip; Bit16u oldcs=SegValue(cs); reg_eip=off; SegSet16(cs,seg); DOSBOX_RunMachine(); reg_eip=oldeip; SegSet16(cs,oldcs); }
static void SaveRegisters(void) { reg_sp-=18; mem_writew(SegPhys(ss)+reg_sp+ 0,reg_ax); mem_writew(SegPhys(ss)+reg_sp+ 2,reg_cx); mem_writew(SegPhys(ss)+reg_sp+ 4,reg_dx); mem_writew(SegPhys(ss)+reg_sp+ 6,reg_bx); mem_writew(SegPhys(ss)+reg_sp+ 8,reg_si); mem_writew(SegPhys(ss)+reg_sp+10,reg_di); mem_writew(SegPhys(ss)+reg_sp+12,reg_bp); mem_writew(SegPhys(ss)+reg_sp+14,SegValue(ds)); mem_writew(SegPhys(ss)+reg_sp+16,SegValue(es)); }
static void TEXT_FillRow(Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { /* Do some filing */ PhysPt dest; dest=base+(row*CurMode->twidth+cleft)*2; Bit16u fill=(attr<<8)+' '; for (Bit8u x=0;x<(Bitu)(cright-cleft);x++) { mem_writew(dest,fill); dest+=2; } }
bool DOS_Terminate(bool tsr) { dos.return_code=reg_al; dos.return_mode=RETURN_EXIT; Bit16u mempsp = dos.psp(); DOS_PSP curpsp(mempsp); if (mempsp==curpsp.GetParent()) return true; /* Free Files owned by process */ if (!tsr) curpsp.CloseFiles(); /* Get the termination address */ RealPt old22 = curpsp.GetInt22(); /* Restore vector 22,23,24 */ curpsp.RestoreVectors(); /* Set the parent PSP */ dos.psp(curpsp.GetParent()); DOS_PSP parentpsp(curpsp.GetParent()); /* Restore the SS:SP to the previous one */ SegSet16(ss,RealSeg(parentpsp.GetStack())); reg_sp = RealOff(parentpsp.GetStack()); /* Restore the old CS:IP from int 22h */ RestoreRegisters(); /* Set the CS:IP stored in int 0x22 back on the stack */ mem_writew(SegPhys(ss)+reg_sp+0,RealOff(old22)); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(old22)); /* set IOPL=3 (Strike Commander), nested task set, interrupts enabled, test flags cleared */ mem_writew(SegPhys(ss)+reg_sp+4,0x7202); // Free memory owned by process if (!tsr) DOS_FreeProcessMemory(mempsp); DOS_UpdatePSPName(); return true; }
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_IOCTL(void) { Bitu handle=0;Bit8u drive=0; /* calls 0-4,6,7,10,12,16 use a file handle */ if ((reg_al<4) || (reg_al==0x06) || (reg_al==0x07) || (reg_al==0x0a) || (reg_al==0x0c) || (reg_al==0x10)) { handle=RealHandle(reg_bx); if (handle>=DOS_FILES) { DOS_SetError(DOSERR_INVALID_HANDLE); return false; } if (!Files[handle]) { DOS_SetError(DOSERR_INVALID_HANDLE); return false; } } else if (reg_al<0x12) { /* those use a diskdrive except 0x0b */ if (reg_al!=0x0b) { drive=reg_bl;if (!drive) drive = DOS_GetDefaultDrive();else drive--; if( !(( drive < DOS_DRIVES ) && Drives[drive]) ) { DOS_SetError(DOSERR_INVALID_DRIVE); return false; } } } else { LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al); DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } switch(reg_al) { case 0x00: /* Get Device Information */ if (Files[handle]->GetInformation() & 0x8000) { //Check for device reg_dx=Files[handle]->GetInformation(); } else { Bit8u hdrive=Files[handle]->GetDrive(); if (hdrive==0xff) { LOG(LOG_IOCTL,LOG_NORMAL)("00:No drive set"); hdrive=2; // defaulting to C: } /* return drive number in lower 5 bits for block devices */ reg_dx=(Files[handle]->GetInformation()&0xffe0)|hdrive; } reg_ax=reg_dx; //Destroyed officially return true; case 0x01: /* Set Device Information */ if (reg_dh != 0) { DOS_SetError(DOSERR_DATA_INVALID); return false; } else { if (Files[handle]->GetInformation() & 0x8000) { //Check for device reg_al=(Bit8u)(Files[handle]->GetInformation() & 0xff); } else { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } } return true; case 0x02: /* Read from Device Control Channel */ if (Files[handle]->GetInformation() & 0xc000) { /* is character device with IOCTL support */ PhysPt bufptr=PhysMake(SegValue(ds),reg_dx); Bit16u retcode=0; if (((DOS_Device*)(Files[handle]))->ReadFromControlChannel(bufptr,reg_cx,&retcode)) { reg_ax=retcode; return true; } } DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; case 0x03: /* Write to Device Control Channel */ if (Files[handle]->GetInformation() & 0xc000) { /* is character device with IOCTL support */ PhysPt bufptr=PhysMake(SegValue(ds),reg_dx); Bit16u retcode=0; if (((DOS_Device*)(Files[handle]))->WriteToControlChannel(bufptr,reg_cx,&retcode)) { reg_ax=retcode; return true; } } DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; case 0x06: /* Get Input Status */ if (Files[handle]->GetInformation() & 0x8000) { //Check for device reg_al=(Files[handle]->GetInformation() & 0x40) ? 0x0 : 0xff; } else { // FILE Bit32u oldlocation=0; Files[handle]->Seek(&oldlocation, DOS_SEEK_CUR); Bit32u endlocation=0; Files[handle]->Seek(&endlocation, DOS_SEEK_END); if(oldlocation < endlocation){//Still data available reg_al=0xff; } else { reg_al=0x0; //EOF or beyond } Files[handle]->Seek(&oldlocation, DOS_SEEK_SET); //restore filelocation LOG(LOG_IOCTL,LOG_NORMAL)("06:Used Get Input Status on regular file with handle %d",handle); } return true; case 0x07: /* Get Output Status */ LOG(LOG_IOCTL,LOG_NORMAL)("07:Fakes output status is ready for handle %d",handle); reg_al=0xff; return true; case 0x08: /* Check if block device removable */ /* cdrom drives and drive a&b are removable */ if (drive < 2) reg_ax=0; else if (!Drives[drive]->isRemovable()) reg_ax=1; else { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } return true; case 0x09: /* Check if block device remote */ if (Drives[drive]->isRemote()) { reg_dx=0x1000; // device is remote // undocumented bits always clear } else { reg_dx=0x0802; // Open/Close supported; 32bit access supported (any use? fixes Fable installer) // undocumented bits from device attribute word // TODO Set bit 9 on drives that don't support direct I/O } reg_ax=0x300; return true; case 0x0B: /* Set sharing retry count */ if (reg_dx==0) { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } return true; case 0x0D: /* Generic block device request */ { if (Drives[drive]->isRemovable()) { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } PhysPt ptr = SegPhys(ds)+reg_dx; switch (reg_cl) { case 0x60: /* Get Device parameters */ mem_writeb(ptr ,0x03); // special function mem_writeb(ptr+1,(drive>=2)?0x05:0x14); // fixed disc(5), 1.44 floppy(14) mem_writew(ptr+2,drive>=2); // nonremovable ? mem_writew(ptr+4,0x0000); // num of cylinders mem_writeb(ptr+6,0x00); // media type (00=other type) // drive parameter block following mem_writeb(ptr+7,drive); // drive mem_writeb(ptr+8,0x00); // unit number mem_writed(ptr+0x1f,0xffffffff); // next parameter block break; case 0x46: case 0x66: /* Volume label */ { char const* bufin=Drives[drive]->GetLabel(); char buffer[11] ={' '}; char const* find_ext=strchr(bufin,'.'); if (find_ext) { Bitu size=(Bitu)(find_ext-bufin); if (size>8) size=8; memcpy(buffer,bufin,size); find_ext++; memcpy(buffer+size,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); } else { memcpy(buffer,bufin,(strlen(bufin) > 8) ? 8 : strlen(bufin)); } char buf2[8]={ 'F','A','T','1','6',' ',' ',' '}; if(drive<2) buf2[4] = '2'; //FAT12 for floppies mem_writew(ptr+0,0); // 0 mem_writed(ptr+2,0x1234); //Serial number MEM_BlockWrite(ptr+6,buffer,11);//volumename if(reg_cl == 0x66) MEM_BlockWrite(ptr+0x11, buf2,8);//filesystem } break; default : LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL Call 0D:%2X Drive %2X unhandled",reg_cl,drive); DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } return true; } case 0x0E: /* Get Logical Drive Map */ if (Drives[drive]->isRemovable()) { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } reg_al = 0; /* Only 1 logical drive assigned */ return true; default: LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al); DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); break; } 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; }
static bool DOS_MultiplexFunctions(void) { switch (reg_ax) { /* ert, 20100711: Locking extensions */ case 0x1000: /* SHARE.EXE installation check */ if (enable_share_exe_fake) { reg_ax=0xffff; /* Pretend that share.exe is installed.. Of course it's a bloody LIE! */ } else { return false; /* pass it on */ } break; case 0x1216: /* GET ADDRESS OF SYSTEM FILE TABLE ENTRY */ // reg_bx is a system file table entry, should coincide with // the file handle so just use that LOG(LOG_DOSMISC,LOG_ERROR)("Some BAD filetable call used bx=%X",reg_bx); if(reg_bx <= DOS_FILES) CALLBACK_SCF(false); else CALLBACK_SCF(true); if (reg_bx<16) { RealPt sftrealpt=mem_readd(Real2Phys(dos_infoblock.GetPointer())+4); PhysPt sftptr=Real2Phys(sftrealpt); Bitu sftofs=0x06+reg_bx*0x3b; if (Files[reg_bx]) mem_writeb(sftptr+sftofs,Files[reg_bx]->refCtr); else mem_writeb(sftptr+sftofs,0); if (!Files[reg_bx]) return true; Bit32u handle=RealHandle(reg_bx); if (handle>=DOS_FILES) { mem_writew(sftptr+sftofs+0x02,0x02); // file open mode mem_writeb(sftptr+sftofs+0x04,0x00); // file attribute mem_writew(sftptr+sftofs+0x05,Files[reg_bx]->GetInformation()); // device info word mem_writed(sftptr+sftofs+0x07,0); // device driver header mem_writew(sftptr+sftofs+0x0d,0); // packed time mem_writew(sftptr+sftofs+0x0f,0); // packed date mem_writew(sftptr+sftofs+0x11,0); // size mem_writew(sftptr+sftofs+0x15,0); // current position } else { Bit8u drive=Files[reg_bx]->GetDrive(); mem_writew(sftptr+sftofs+0x02,(Bit16u)(Files[reg_bx]->flags&3)); // file open mode mem_writeb(sftptr+sftofs+0x04,(Bit8u)(Files[reg_bx]->attr)); // file attribute mem_writew(sftptr+sftofs+0x05,0x40|drive); // device info word mem_writed(sftptr+sftofs+0x07,RealMake(dos.tables.dpb,drive)); // dpb of the drive mem_writew(sftptr+sftofs+0x0d,Files[reg_bx]->time); // packed file time mem_writew(sftptr+sftofs+0x0f,Files[reg_bx]->date); // packed file date Bit32u curpos=0; Files[reg_bx]->Seek(&curpos,DOS_SEEK_CUR); Bit32u endpos=0; Files[reg_bx]->Seek(&endpos,DOS_SEEK_END); mem_writed(sftptr+sftofs+0x11,endpos); // size mem_writed(sftptr+sftofs+0x15,curpos); // current position Files[reg_bx]->Seek(&curpos,DOS_SEEK_SET); } // fill in filename in fcb style // (space-padded name (8 chars)+space-padded extension (3 chars)) const char* filename=(const char*)Files[reg_bx]->GetName(); if (strrchr(filename,'\\')) filename=strrchr(filename,'\\')+1; if (strrchr(filename,'/')) filename=strrchr(filename,'/')+1; if (!filename) return true; const char* dotpos=strrchr(filename,'.'); if (dotpos) { dotpos++; size_t nlen=strlen(filename); size_t extlen=strlen(dotpos); Bits nmelen=(Bits)nlen-(Bits)extlen; if (nmelen<1) return true; nlen-=(extlen+1); if (nlen>8) nlen=8; size_t i; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<8; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); if (extlen>3) extlen=3; for (i=0; i<extlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),dotpos[i]); for (i=extlen; i<3; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),' '); } else { size_t i; size_t nlen=strlen(filename); if (nlen>8) nlen=8; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<11; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); } SegSet16(es,RealSeg(sftrealpt)); reg_di=RealOff(sftrealpt+sftofs); reg_ax=0xc000; } return true; case 0x1605: /* Windows init broadcast */ if (enable_a20_on_windows_init) { /* This hack exists because Windows 3.1 doesn't seem to enable A20 first during an * initial critical period where it assumes it's on, prior to checking and enabling/disabling it. * * Note that Windows 3.1 also makes this mistake in Standard/286 mode, but it doesn't even * make this callout, so this hack is useless unless you are using Enhanced/386 mode. * If you want to run Windows 3.1 Standard mode with a20=mask you will have to run builtin * command "a20gate on" to turn on the A20 gate prior to starting Windows. */ LOG_MSG("Enabling A20 gate for Windows in response to INIT broadcast"); XMS_EnableA20(true); } /* TODO: Maybe future parts of DOSBox-X will do something with this */ /* TODO: Don't show this by default. Show if the user wants it by a) setting something to "true" in dosbox.conf or b) running a builtin command in Z:\ */ LOG_MSG("DEBUG: INT 2Fh Windows 286/386 DOSX init broadcast issued (ES:BX=%04x:%04x DS:SI=%04x:%04x CX=%04x DX=%04x DI=%04x(aka version %u.%u))", SegValue(es),reg_bx, SegValue(ds),reg_si, reg_cx,reg_dx,reg_di, reg_di>>8,reg_di&0xFF); if (reg_dx & 0x0001) LOG_MSG(" [286 DOS extender]"); else LOG_MSG(" [Enhanced mode]"); LOG_MSG("\n"); /* NTS: The way this protocol works, is that when you (the program hooking this call) receive it, * you first pass the call down to the previous INT 2Fh handler with registers unmodified, * and then when the call unwinds back up the chain, THEN you modify the results to notify * yourself to Windows. So logically, since we're the DOS kernel at the end of the chain, * we should still see ES:BX=0000:0000 and DS:SI=0000:0000 and CX=0000 unmodified from the * way the Windows kernel issued the call. If that's not the case, then we need to issue * a warning because some bastard on the call chain is ruining it for all of us. */ if (SegValue(es) != 0 || reg_bx != 0 || SegValue(ds) != 0 || reg_si != 0 || reg_cx != 0) { LOG_MSG("WARNING: Some registers at this point (the top of the call chain) are nonzero.\n"); LOG_MSG(" That means a TSR or other entity has modified registers on the way down\n"); LOG_MSG(" the call chain. The Windows init broadcast is supposed to be handled\n"); LOG_MSG(" going down the chain by calling the previous INT 2Fh handler with registers\n"); LOG_MSG(" unmodified, and only modify registers on the way back up the chain!\n"); } return false; /* pass it on to other INT 2F handlers */ case 0x1606: /* Windows exit broadcast */ /* TODO: Maybe future parts of DOSBox-X will do something with this */ /* TODO: Don't show this by default. Show if the user wants it by a) setting something to "true" in dosbox.conf or b) running a builtin command in Z:\ */ LOG_MSG("DEBUG: INT 2Fh Windows 286/386 DOSX exit broadcast issued (DX=0x%04x)",reg_dx); if (reg_dx & 0x0001) LOG_MSG(" [286 DOS extender]"); else LOG_MSG(" [Enhanced mode]"); LOG_MSG("\n"); return false; /* pass it on to other INT 2F handlers */ case 0x1607: /* TODO: Don't show this by default. Show if the user wants it by a) setting something to "true" in dosbox.conf or b) running a builtin command in Z:\ * Additionally, if the user WANTS to see every invocation of the IDLE call, then allow them to enable that too */ if (reg_bx != 0x18) { /* don't show the idle call. it's used too often */ const char *str = Win_NameThatVXD(reg_bx); if (str == NULL) str = "??"; LOG_MSG("DEBUG: INT 2Fh Windows virtual device '%s' callout (BX(deviceID)=0x%04x CX(function)=0x%04x)\n", str,reg_bx,reg_cx); } if (reg_bx == 0x15) { /* DOSMGR */ switch (reg_cx) { case 0x0000: // query instance reg_cx = 0x0001; reg_dx = 0x50; // dos driver segment SegSet16(es,0x50); // patch table seg reg_bx = 0x60; // patch table ofs return true; case 0x0001: // set patches reg_ax = 0xb97c; reg_bx = (reg_dx & 0x16); reg_dx = 0xa2ab; return true; case 0x0003: // get size of data struc if (reg_dx==0x0001) { // CDS size requested reg_ax = 0xb97c; reg_dx = 0xa2ab; reg_cx = 0x000e; // size } return true; case 0x0004: // instanced data reg_dx = 0; // none return true; case 0x0005: // get device driver size reg_ax = 0; reg_dx = 0; return true; default: return false; } } else if (reg_bx == 0x18) { /* VMPoll (idle) */ return true; } else return false; case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ //TODO Maybe do some idling but could screw up other systems :) return true; //So no warning in the debugger anymore case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ /* Removing warning */ return true; case 0x4a01: { /* Query free hma space */ Bit32u limit = DOS_HMA_LIMIT(); if (limit == 0) { /* TODO: What does MS-DOS prior to v5.0? */ reg_bx = 0; reg_di = 0xFFFF; SegSet16(es,0xFFFF); LOG(LOG_MISC,LOG_DEBUG)("HMA query: rejected"); return true; } Bit32u start = DOS_HMA_FREE_START(); reg_bx = limit - start; /* free space in bytes */ SegSet16(es,0xffff); reg_di = (start + 0x10) & 0xFFFF; LOG(LOG_MISC,LOG_DEBUG)("HMA query: start=0x%06x limit=0x%06x free=0x%06x -> bx=%u %04x:%04x", start,limit,DOS_HMA_GET_FREE_SPACE(),(int)reg_bx,(int)SegValue(es),(int)reg_di); } return true; case 0x4a02: { /* ALLOCATE HMA SPACE */ Bit32u limit = DOS_HMA_LIMIT(); if (limit == 0) { /* TODO: What does MS-DOS prior to v5.0? */ reg_bx = 0; reg_di = 0xFFFF; SegSet16(es,0xFFFF); LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: rejected"); return true; } /* NTS: According to RBIL, Windows 95 adds a deallocate function and changes HMA allocation up to follow a * MCB chain structure. Which is something we're probably not going to add for awhile. */ /* FIXME: So, according to Ralph Brown Interrupt List, MS-DOS 5 and 6 liked to round up to the next paragraph? */ if (dos.version.major < 7 && (reg_bx & 0xF) != 0) reg_bx = (reg_bx + 0xF) & (~0xF); Bit32u start = DOS_HMA_FREE_START(); if ((start+reg_bx) > limit) { LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: rejected (not enough room) for %u bytes",reg_bx); reg_bx = 0; reg_di = 0xFFFF; SegSet16(es,0xFFFF); return true; } /* convert the start to segment:offset, normalized to FFFF:offset */ reg_di = (start - 0x10) & 0xFFFF; SegSet16(es,0xFFFF); /* let HMA emulation know what was claimed */ LOG(LOG_MISC,LOG_DEBUG)("HMA allocation: %u bytes at FFFF:%04x",reg_bx,reg_di); DOS_HMA_CLAIMED(reg_bx); } return true; } return false; }
void CALLBACK_SIF(bool val) { Bit16u tempf = mem_readw(SegPhys(ss)+reg_sp+4); if (val) tempf |= FLAG_IF; else tempf &= ~FLAG_IF; mem_writew(SegPhys(ss)+reg_sp+4,tempf); }
void SHELL_Init() { /* Add messages */ MSG_Add("SHELL_ILLEGAL_PATH","Illegal Path.\n"); MSG_Add("SHELL_CMD_HELP","If you want a list of all supported commands type \033[33;1mhelp /all\033[0m .\nA short list of the most often used commands:\n"); MSG_Add("SHELL_CMD_ECHO_ON","ECHO is on.\n"); MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off.\n"); MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s.\n"); MSG_Add("SHELL_MISSING_PARAMETER","Required parameter missing.\n"); MSG_Add("SHELL_CMD_CHDIR_ERROR","Unable to change to: %s.\n"); MSG_Add("SHELL_CMD_CHDIR_HINT","To change to different drive type \033[31m%c:\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_2","directoryname is longer than 8 characters and/or contains spaces.\nTry \033[31mcd %s\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_3","You are still on drive Z:, change to a mounted drive with \033[31mC:\033[0m.\n"); MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s.\n"); MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %s.\n"); MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s.\n"); MSG_Add("SHELL_SYNTAXERROR","The syntax of the command is incorrect.\n"); MSG_Add("SHELL_CMD_SET_NOT_SET","Environment variable %s not defined.\n"); MSG_Add("SHELL_CMD_SET_OUT_OF_SPACE","Not enough environment space left.\n"); MSG_Add("SHELL_CMD_IF_EXIST_MISSING_FILENAME","IF EXIST: Missing filename.\n"); MSG_Add("SHELL_CMD_IF_ERRORLEVEL_MISSING_NUMBER","IF ERRORLEVEL: Missing number.\n"); MSG_Add("SHELL_CMD_IF_ERRORLEVEL_INVALID_NUMBER","IF ERRORLEVEL: Invalid number.\n"); MSG_Add("SHELL_CMD_GOTO_MISSING_LABEL","No label supplied to GOTO command.\n"); MSG_Add("SHELL_CMD_GOTO_LABEL_NOT_FOUND","GOTO: Label %s not found.\n"); MSG_Add("SHELL_CMD_FILE_NOT_FOUND","File %s not found.\n"); MSG_Add("SHELL_CMD_FILE_EXISTS","File %s already exists.\n"); MSG_Add("SHELL_CMD_DIR_INTRO","Directory of %s.\n"); MSG_Add("SHELL_CMD_DIR_BYTES_USED","%5d File(s) %17s Bytes.\n"); MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free.\n"); MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\nYou must \033[31mmount\033[0m it first. Type \033[1;33mintro\033[0m or \033[1;33mintro mount\033[0m for more information.\n"); MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\n"); MSG_Add("SHELL_CMD_PAUSE","Press any key to continue.\n"); MSG_Add("SHELL_CMD_PAUSE_HELP","Waits for 1 keystroke to continue.\n"); MSG_Add("SHELL_CMD_COPY_FAILURE","Copy failure : %s.\n"); MSG_Add("SHELL_CMD_COPY_SUCCESS"," %d File(s) copied.\n"); MSG_Add("SHELL_CMD_SUBST_NO_REMOVE","Removing drive not supported. Doing nothing.\n"); MSG_Add("SHELL_CMD_SUBST_FAILURE","SUBST failed. You either made an error in your commandline or the target drive is already used.\nIt's only possible to use SUBST on Local drives"); MSG_Add("SHELL_STARTUP_BEGIN", "\033[44;1m\xC9\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBB\n" "\xBA \033[32mWelcome to DOSBox v%-8s\033[37m \xBA\n" "\xBA \xBA\n" // "\xBA DOSBox runs real and protected mode games. \xBA\n" "\xBA For a short introduction for new users type: \033[33mINTRO\033[37m \xBA\n" "\xBA For supported shell commands type: \033[33mHELP\033[37m \xBA\n" "\xBA \xBA\n" "\xBA To adjust the emulated CPU speed, use \033[31mctrl-F11\033[37m and \033[31mctrl-F12\033[37m. \xBA\n" "\xBA To activate the keymapper \033[31mctrl-F1\033[37m. \xBA\n" "\xBA For more information read the \033[36mREADME\033[37m file in the DOSBox directory. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_CGA","\xBA DOSBox supports Composite CGA mode. \xBA\n" "\xBA Use \033[31m(alt-)F11\033[37m to change the colours when in this mode. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_HERC","\xBA Use \033[31mF11\033[37m to cycle through white, amber, and green monochrome color. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_DEBUG", "\xBA Press \033[31malt-Pause\033[37m to enter the debugger or start the exe with \033[33mDEBUG\033[37m. \xBA\n" "\xBA \xBA\n" ); MSG_Add("SHELL_STARTUP_END", "\xBA \033[32mHAVE FUN!\033[37m \xBA\n" "\xBA \033[32mThe DOSBox Team \033[33mhttp://www.dosbox.com\033[37m \xBA\n" "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC\033[0m\n" //"\n" //Breaks the startup message if you type a mount and a drive change. ); MSG_Add("SHELL_CMD_CHDIR_HELP","Displays/changes the current directory.\n"); MSG_Add("SHELL_CMD_CHDIR_HELP_LONG","CHDIR [drive:][path]\n" "CHDIR [..]\n" "CD [drive:][path]\n" "CD [..]\n\n" " .. Specifies that you want to change to the parent directory.\n\n" "Type CD drive: to display the current directory in the specified drive.\n" "Type CD without parameters to display the current drive and directory.\n"); MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n"); MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\n"); MSG_Add("SHELL_CMD_ECHO_HELP","Display messages and enable/disable command echoing.\n"); MSG_Add("SHELL_CMD_EXIT_HELP","Exit from the shell.\n"); MSG_Add("SHELL_CMD_HELP_HELP","Show help.\n"); MSG_Add("SHELL_CMD_MKDIR_HELP","Make Directory.\n"); MSG_Add("SHELL_CMD_MKDIR_HELP_LONG","MKDIR [drive:][path]\n" "MD [drive:][path]\n"); MSG_Add("SHELL_CMD_RMDIR_HELP","Remove Directory.\n"); MSG_Add("SHELL_CMD_RMDIR_HELP_LONG","RMDIR [drive:][path]\n" "RD [drive:][path]\n"); MSG_Add("SHELL_CMD_SET_HELP","Change environment variables.\n"); MSG_Add("SHELL_CMD_IF_HELP","Performs conditional processing in batch programs.\n"); MSG_Add("SHELL_CMD_GOTO_HELP","Jump to a labeled line in a batch script.\n"); MSG_Add("SHELL_CMD_SHIFT_HELP","Leftshift commandline parameters in a batch script.\n"); MSG_Add("SHELL_CMD_TYPE_HELP","Display the contents of a text-file.\n"); MSG_Add("SHELL_CMD_TYPE_HELP_LONG","TYPE [drive:][path][filename]\n"); MSG_Add("SHELL_CMD_REM_HELP","Add comments in a batch file.\n"); MSG_Add("SHELL_CMD_REM_HELP_LONG","REM [comment]\n"); MSG_Add("SHELL_CMD_NO_WILD","This is a simple version of the command, no wildcards allowed!\n"); MSG_Add("SHELL_CMD_RENAME_HELP","Renames one or more files.\n"); MSG_Add("SHELL_CMD_RENAME_HELP_LONG","RENAME [drive:][path]filename1 filename2.\n" "REN [drive:][path]filename1 filename2.\n\n" "Note that you can not specify a new drive or path for your destination file.\n"); MSG_Add("SHELL_CMD_DELETE_HELP","Removes one or more files.\n"); MSG_Add("SHELL_CMD_COPY_HELP","Copy files.\n"); MSG_Add("SHELL_CMD_CALL_HELP","Start a batch file from within another batch file.\n"); MSG_Add("SHELL_CMD_SUBST_HELP","Assign an internal directory to a drive.\n"); MSG_Add("SHELL_CMD_LOADHIGH_HELP","Loads a program into upper memory (requires xms=true,umb=true).\n"); MSG_Add("SHELL_CMD_CHOICE_HELP","Waits for a keypress and sets ERRORLEVEL.\n"); MSG_Add("SHELL_CMD_CHOICE_HELP_LONG","CHOICE [/C:choices] [/N] [/S] text\n" " /C[:]choices - Specifies allowable keys. Default is: yn.\n" " /N - Do not display the choices at end of prompt.\n" " /S - Enables case-sensitive choices to be selected.\n" " text - The text to display as a prompt.\n"); MSG_Add("SHELL_CMD_ATTRIB_HELP","Does nothing. Provided for compatibility.\n"); MSG_Add("SHELL_CMD_PATH_HELP","Provided for compatibility.\n"); MSG_Add("SHELL_CMD_VER_HELP","View and set the reported DOS version.\n"); MSG_Add("SHELL_CMD_VER_VER","DOSBox version %s. Reported DOS version %d.%02d.\n"); #ifdef IPHONEOS MSG_Add("SHELL_CMD_UNZIP_HELP","Extract zip file to current directory.\n"); #endif /* Regular startup */ call_shellstop=CALLBACK_Allocate(); /* Setup the startup CS:IP to kill the last running machine when exitted */ RealPt newcsip=CALLBACK_RealPointer(call_shellstop); SegSet16(cs,RealSeg(newcsip)); reg_ip=RealOff(newcsip); CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET,"shell stop"); PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart); /* Now call up the shell for the first time */ Bit16u psp_seg=DOS_FIRST_SHELL; Bit16u env_seg=DOS_FIRST_SHELL+19; //DOS_GetMemory(1+(4096/16))+1; Bit16u stack_seg=DOS_GetMemory(2048/16); SegSet16(ss,stack_seg); reg_sp=2046; /* Set up int 24 and psp (Telarium games) */ real_writeb(psp_seg+16+1,0,0xea); /* far jmp */ real_writed(psp_seg+16+1,1,real_readd(0,0x24*4)); real_writed(0,0x24*4,((Bit32u)psp_seg<<16) | ((16+1)<<4)); /* Set up int 23 to "int 20" in the psp. Fixes what.exe */ real_writed(0,0x23*4,((Bit32u)psp_seg<<16)); /* Setup MCBs */ DOS_MCB pspmcb((Bit16u)(psp_seg-1)); pspmcb.SetPSPSeg(psp_seg); // MCB of the command shell psp pspmcb.SetSize(0x10+2); pspmcb.SetType(0x4d); DOS_MCB envmcb((Bit16u)(env_seg-1)); envmcb.SetPSPSeg(psp_seg); // MCB of the command shell environment envmcb.SetSize(DOS_MEM_START-env_seg); envmcb.SetType(0x4d); /* Setup environment */ PhysPt env_write=PhysMake(env_seg,0); MEM_BlockWrite(env_write,path_string,(Bitu)(strlen(path_string)+1)); env_write += (PhysPt)(strlen(path_string)+1); MEM_BlockWrite(env_write,comspec_string,(Bitu)(strlen(comspec_string)+1)); env_write += (PhysPt)(strlen(comspec_string)+1); mem_writeb(env_write++,0); mem_writew(env_write,1); env_write+=2; MEM_BlockWrite(env_write,full_name,(Bitu)(strlen(full_name)+1)); DOS_PSP psp(psp_seg); psp.MakeNew(0); dos.psp(psp_seg); /* The start of the filetable in the psp must look like this: * 01 01 01 00 02 * In order to achieve this: First open 2 files. Close the first and * duplicate the second (so the entries get 01) */ Bit16u dummy=0; DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDIN */ DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDOUT */ DOS_CloseFile(0); /* Close STDIN */ DOS_ForceDuplicateEntry(1,0); /* "new" STDIN */ DOS_ForceDuplicateEntry(1,2); /* STDERR */ DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDAUX */ DOS_OpenFile("CON",OPEN_READWRITE,&dummy); /* STDPRN */ psp.SetParent(psp_seg); /* Set the environment */ psp.SetEnvironment(env_seg); /* Set the command line for the shell start up */ CommandTail tail; tail.count=(Bit8u)strlen(init_line); strcpy(tail.buffer,init_line); MEM_BlockWrite(PhysMake(psp_seg,128),&tail,128); /* Setup internal DOS Variables */ dos.dta(RealMake(psp_seg,0x80)); dos.psp(psp_seg); SHELL_ProgramStart(&first_shell); first_shell->Run(); delete first_shell; first_shell = 0;//Make clear that it shouldn't be used anymore }
void DOS_SetupTables(void) { dos_memseg=0xd000; Bit16u seg,seg2;Bitu i; dos.tables.mediaid=RealMake(DOS_GetMemory(4),0); dos.tables.tempdta=RealMake(DOS_GetMemory(4),0); dos.tables.tempdta_fcbdelete=RealMake(DOS_GetMemory(4),0); for (i=0;i<DOS_DRIVES;i++) mem_writew(Real2Phys(dos.tables.mediaid)+i*2,0); /* Create the DOS Info Block */ dos_infoblock.SetLocation(DOS_INFOBLOCK_SEG); //c2woody /* create SDA */ DOS_SDA(DOS_SDA_SEG,0).Init(); /* Some weird files >20 detection routine */ /* Possibly obselete when SFT is properly handled */ real_writed(DOS_CONSTRING_SEG,0x0a,0x204e4f43); real_writed(DOS_CONSTRING_SEG,0x1a,0x204e4f43); real_writed(DOS_CONSTRING_SEG,0x2a,0x204e4f43); /* create a CON device driver */ seg=DOS_CONDRV_SEG; real_writed(seg,0x00,0xffffffff); // next ptr real_writew(seg,0x04,0x8013); // attributes real_writed(seg,0x06,0xffffffff); // strategy routine real_writed(seg,0x0a,0x204e4f43); // driver name real_writed(seg,0x0e,0x20202020); // driver name dos_infoblock.SetDeviceChainStart(RealMake(seg,0)); /* Create a fake Current Directory Structure */ seg=DOS_CDS_SEG; real_writed(seg,0x00,0x005c3a43); dos_infoblock.SetCurDirStruct(RealMake(seg,0)); /* Allocate DCBS DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */ dos.tables.dcbs=RealMake(DOS_GetMemory(12),0); mem_writed(Real2Phys(dos.tables.dcbs),0); //empty table /* Create a fake FCB SFT */ seg=DOS_GetMemory(4); real_writed(seg,0,0xffffffff); //Last File Table real_writew(seg,4,100); //File Table supports 100 files dos_infoblock.SetFCBTable(RealMake(seg,0)); /* Create a fake disk buffer head */ seg=DOS_GetMemory(6); for (Bitu ct=0; ct<0x20; ct++) real_writeb(seg,ct,0); real_writew(seg,0x00,0xffff); // forward ptr real_writew(seg,0x02,0xffff); // backward ptr real_writeb(seg,0x04,0xff); // not in use real_writeb(seg,0x0a,0x01); // number of FATs real_writed(seg,0x0d,0xffffffff); // pointer to DPB dos_infoblock.SetDiskBufferHeadPt(RealMake(seg,0)); /* Set buffers to a nice value */ dos_infoblock.SetBuffers(50,50); /* case map routine INT 0x21 0x38 */ call_casemap = CALLBACK_Allocate(); CALLBACK_Setup(call_casemap,DOS_CaseMapFunc,CB_RETF,"DOS CaseMap"); /* Add it to country structure */ host_writed(country_info + 0x12, CALLBACK_RealPointer(call_casemap)); dos.tables.country=country_info; }
void DOS_FCB::SetResult(Bit32u size,Bit16u date,Bit16u time,Bit8u attr) { mem_writed(pt + 0x1d,size); mem_writew(pt + 0x19,date); mem_writew(pt + 0x17,time); mem_writeb(pt + 0x0c,attr); }
void DOS_SetupTables(void) { Bit16u seg;Bitu i; dos.tables.mediaid=RealMake(DOS_GetMemory(4),0); dos.tables.tempdta=RealMake(DOS_GetMemory(4),0); dos.tables.tempdta_fcbdelete=RealMake(DOS_GetMemory(4),0); for (i=0;i<DOS_DRIVES;i++) mem_writew(Real2Phys(dos.tables.mediaid)+i*2,0); /* Create the DOS Info Block */ dos_infoblock.SetLocation(DOS_INFOBLOCK_SEG); //c2woody /* create SDA */ DOS_SDA(DOS_SDA_SEG,0).Init(); /* Some weird files >20 detection routine */ /* Possibly obselete when SFT is properly handled */ real_writed(DOS_CONSTRING_SEG,0x0a,0x204e4f43); real_writed(DOS_CONSTRING_SEG,0x1a,0x204e4f43); real_writed(DOS_CONSTRING_SEG,0x2a,0x204e4f43); /* create a CON device driver */ seg=DOS_CONDRV_SEG; real_writed(seg,0x00,0xffffffff); // next ptr real_writew(seg,0x04,0x8013); // attributes real_writed(seg,0x06,0xffffffff); // strategy routine real_writed(seg,0x0a,0x204e4f43); // driver name real_writed(seg,0x0e,0x20202020); // driver name dos_infoblock.SetDeviceChainStart(RealMake(seg,0)); /* Create a fake Current Directory Structure */ seg=DOS_CDS_SEG; real_writed(seg,0x00,0x005c3a43); dos_infoblock.SetCurDirStruct(RealMake(seg,0)); /* Allocate DCBS DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */ dos.tables.dbcs=RealMake(DOS_GetMemory(12),0); mem_writed(Real2Phys(dos.tables.dbcs),0); //empty table /* FILENAME CHARACTER TABLE */ dos.tables.filenamechar=RealMake(DOS_GetMemory(2),0); mem_writew(Real2Phys(dos.tables.filenamechar)+0x00,0x16); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x02,0x01); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x03,0x00); // allowed chars from mem_writeb(Real2Phys(dos.tables.filenamechar)+0x04,0xff); // ...to mem_writeb(Real2Phys(dos.tables.filenamechar)+0x05,0x00); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x06,0x00); // excluded chars from mem_writeb(Real2Phys(dos.tables.filenamechar)+0x07,0x20); // ...to mem_writeb(Real2Phys(dos.tables.filenamechar)+0x08,0x02); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x09,0x0e); // number of illegal separators mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0a,0x2e); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0b,0x22); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0c,0x2f); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0d,0x5c); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0e,0x5b); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0f,0x5d); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x10,0x3a); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x11,0x7c); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x12,0x3c); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x13,0x3e); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x14,0x2b); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x15,0x3d); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x16,0x3b); mem_writeb(Real2Phys(dos.tables.filenamechar)+0x17,0x2c); /* COLLATING SEQUENCE TABLE + UPCASE TABLE*/ // 256 bytes for col table, 128 for upcase, 4 for number of entries dos.tables.collatingseq=RealMake(DOS_GetMemory(25),0); mem_writew(Real2Phys(dos.tables.collatingseq),0x100); for (i=0; i<256; i++) mem_writeb(Real2Phys(dos.tables.collatingseq)+i+2,i); dos.tables.upcase=dos.tables.collatingseq+258; mem_writew(Real2Phys(dos.tables.upcase),0x80); for (i=0; i<128; i++) mem_writeb(Real2Phys(dos.tables.upcase)+i+2,0x80+i); /* Create a fake FCB SFT */ seg=DOS_GetMemory(4); real_writed(seg,0,0xffffffff); //Last File Table real_writew(seg,4,100); //File Table supports 100 files dos_infoblock.SetFCBTable(RealMake(seg,0)); /* Create a fake DPB */ dos.tables.dpb=DOS_GetMemory(2); for(Bitu d=0;d<26;d++) real_writeb(dos.tables.dpb,d,d); /* Create a fake disk buffer head */ seg=DOS_GetMemory(6); for (Bitu ct=0; ct<0x20; ct++) real_writeb(seg,ct,0); real_writew(seg,0x00,0xffff); // forward ptr real_writew(seg,0x02,0xffff); // backward ptr real_writeb(seg,0x04,0xff); // not in use real_writeb(seg,0x0a,0x01); // number of FATs real_writed(seg,0x0d,0xffffffff); // pointer to DPB dos_infoblock.SetDiskBufferHeadPt(RealMake(seg,0)); /* Set buffers to a nice value */ dos_infoblock.SetBuffers(50,50); /* case map routine INT 0x21 0x38 */ call_casemap = CALLBACK_Allocate(); CALLBACK_Setup(call_casemap,DOS_CaseMapFunc,CB_RETF,"DOS CaseMap"); /* Add it to country structure */ host_writed(country_info + 0x12, CALLBACK_RealPointer(call_casemap)); dos.tables.country=country_info; }
bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { Bitu subfct=mem_readb(bufptr); switch (subfct) { case 0x00: if (size!=6) return false; mem_writew(bufptr+0x00,0x0023); // ID mem_writed(bufptr+0x02,0); // private API entry point *retcode=6; return true; case 0x01: { if (size!=6) return false; if (GEMMIS_seg==0) GEMMIS_seg=DOS_GetMemory(0x20); PhysPt GEMMIS_addr=PhysMake(GEMMIS_seg,0); mem_writew(GEMMIS_addr+0x00,0x0004); // flags mem_writew(GEMMIS_addr+0x02,0x019d); // size of this structure mem_writew(GEMMIS_addr+0x04,GEMMIS_VERSION); // version 1.0 (provide ems information only) mem_writed(GEMMIS_addr+0x06,0); // reserved /* build non-EMS frames (0-0xe000) */ for (Bitu frct=0; frct<EMM_PAGEFRAME4K/4; frct++) { mem_writeb(GEMMIS_addr+0x0a+frct*6,0x00); // frame type: NONE mem_writeb(GEMMIS_addr+0x0b+frct*6,0xff); // owner: NONE mem_writew(GEMMIS_addr+0x0c+frct*6,0xffff); // non-EMS frame mem_writeb(GEMMIS_addr+0x0e + frct*6,0xff); // EMS page number (NONE) mem_writeb(GEMMIS_addr+0x0f+frct*6,0xaa); // flags: direct mapping } /* build EMS page frame (0xe000-0xf000) */ for (Bitu frct=0; frct<0x10/4; frct++) { Bitu frnr=(frct+EMM_PAGEFRAME4K/4)*6; mem_writeb(GEMMIS_addr+0x0a+frnr,0x03); // frame type: EMS frame in 64k page mem_writeb(GEMMIS_addr+0x0b+frnr,0xff); // owner: NONE mem_writew(GEMMIS_addr+0x0c+frnr,0x7fff); // no logical page number mem_writeb(GEMMIS_addr+0x0e + frnr,(Bit8u)(frct&0xff)); // physical EMS page number mem_writeb(GEMMIS_addr+0x0f+frnr,0x00); // EMS frame } /* build non-EMS ROM frames (0xf000-0x10000) */ for (Bitu frct=(EMM_PAGEFRAME4K+0x10)/4; frct<0xf0/4; frct++) { mem_writeb(GEMMIS_addr+0x0a+frct*6,0x00); // frame type: NONE mem_writeb(GEMMIS_addr+0x0b+frct*6,0xff); // owner: NONE mem_writew(GEMMIS_addr+0x0c+frct*6,0xffff); // non-EMS frame mem_writeb(GEMMIS_addr+0x0e + frct*6,0xff); // EMS page number (NONE) mem_writeb(GEMMIS_addr+0x0f+frct*6,0xaa); // flags: direct mapping } mem_writeb(GEMMIS_addr+0x18a,0x74); // ??? mem_writeb(GEMMIS_addr+0x18b,0x00); // no UMB descriptors following mem_writeb(GEMMIS_addr+0x18c,0x01); // 1 EMS handle info recort mem_writew(GEMMIS_addr+0x18d,0x0000); // system handle mem_writed(GEMMIS_addr+0x18f,0); // handle name mem_writed(GEMMIS_addr+0x193,0); // handle name mem_writew(GEMMIS_addr+0x197,0x0010); // system handle mem_writed(GEMMIS_addr+0x199,0x00110000); // physical address /* fill buffer with import structure */ mem_writed(bufptr+0x00,GEMMIS_seg<<4); mem_writew(bufptr+0x04,GEMMIS_VERSION); *retcode=6; return true; } case 0x02: if (size!=2) return false; mem_writeb(bufptr+0x00,EMM_VERSION>>4); // version 4.0 mem_writew(bufptr+0x01,EMM_VERSION&0x0f); *retcode=2; return true; } return false; }
static bool DOS_MultiplexFunctions(void) { char name[256]; switch (reg_ax) { case 0x1216: /* GET ADDRESS OF SYSTEM FILE TABLE ENTRY */ // reg_bx is a system file table entry, should coincide with // the file handle so just use that LOG(LOG_DOSMISC,LOG_ERROR)("Some BAD filetable call used bx=%X",reg_bx); if(reg_bx <= DOS_FILES) CALLBACK_SCF(false); else CALLBACK_SCF(true); if (reg_bx<16) { RealPt sftrealpt=mem_readd(Real2Phys(dos_infoblock.GetPointer())+4); PhysPt sftptr=Real2Phys(sftrealpt); Bitu sftofs=0x06+reg_bx*0x3b; if (Files[reg_bx]) mem_writeb(sftptr+sftofs,Files[reg_bx]->refCtr); else mem_writeb(sftptr+sftofs,0); if (!Files[reg_bx]) return true; Bit32u handle=RealHandle(reg_bx); if (handle>=DOS_FILES) { mem_writew(sftptr+sftofs+0x02,0x02); // file open mode mem_writeb(sftptr+sftofs+0x04,0x00); // file attribute mem_writew(sftptr+sftofs+0x05,Files[reg_bx]->GetInformation()); // device info word mem_writed(sftptr+sftofs+0x07,0); // device driver header mem_writew(sftptr+sftofs+0x0d,0); // packed time mem_writew(sftptr+sftofs+0x0f,0); // packed date mem_writew(sftptr+sftofs+0x11,0); // size mem_writew(sftptr+sftofs+0x15,0); // current position } else { Bit8u drive=Files[reg_bx]->GetDrive(); mem_writew(sftptr+sftofs+0x02,(Bit16u)(Files[reg_bx]->flags&3)); // file open mode mem_writeb(sftptr+sftofs+0x04,(Bit8u)(Files[reg_bx]->attr)); // file attribute mem_writew(sftptr+sftofs+0x05,0x40|drive); // device info word mem_writed(sftptr+sftofs+0x07,RealMake(dos.tables.dpb,drive)); // dpb of the drive mem_writew(sftptr+sftofs+0x0d,Files[reg_bx]->time); // packed file time mem_writew(sftptr+sftofs+0x0f,Files[reg_bx]->date); // packed file date Bit32u curpos=0; Files[reg_bx]->Seek(&curpos,DOS_SEEK_CUR); Bit32u endpos=0; Files[reg_bx]->Seek(&endpos,DOS_SEEK_END); mem_writed(sftptr+sftofs+0x11,endpos); // size mem_writed(sftptr+sftofs+0x15,curpos); // current position Files[reg_bx]->Seek(&curpos,DOS_SEEK_SET); } // fill in filename in fcb style // (space-padded name (8 chars)+space-padded extension (3 chars)) const char* filename=(const char*)Files[reg_bx]->GetName(); if (strrchr(filename,'\\')) filename=strrchr(filename,'\\')+1; if (strrchr(filename,'/')) filename=strrchr(filename,'/')+1; if (!filename) return true; const char* dotpos=strrchr(filename,'.'); if (dotpos) { dotpos++; size_t nlen=strlen(filename); size_t extlen=strlen(dotpos); Bits nmelen=(Bits)nlen-(Bits)extlen; if (nmelen<1) return true; nlen-=(extlen+1); if (nlen>8) nlen=8; size_t i; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<8; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); if (extlen>3) extlen=3; for (i=0; i<extlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),dotpos[i]); for (i=extlen; i<3; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x28+i),' '); } else { size_t i; size_t nlen=strlen(filename); if (nlen>8) nlen=8; for (i=0; i<nlen; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),filename[i]); for (i=nlen; i<11; i++) mem_writeb((PhysPt)(sftptr+sftofs+0x20+i),' '); } SegSet16(es,RealSeg(sftrealpt)); reg_di=RealOff(sftrealpt+sftofs); reg_ax=0xc000; } return true; case 0x1607: if (reg_bx == 0x15) { switch (reg_cx) { case 0x0000: // query instance reg_cx = 0x0001; reg_dx = 0x50; // dos driver segment SegSet16(es,0x50); // patch table seg reg_bx = 0x60; // patch table ofs return true; case 0x0001: // set patches reg_ax = 0xb97c; reg_bx = (reg_dx & 0x16); reg_dx = 0xa2ab; return true; case 0x0003: // get size of data struc if (reg_dx==0x0001) { // CDS size requested reg_ax = 0xb97c; reg_dx = 0xa2ab; reg_cx = 0x000e; // size } return true; case 0x0004: // instanced data reg_dx = 0; // none return true; case 0x0005: // get device driver size reg_ax = 0; reg_dx = 0; return true; default: return false; } } else if (reg_bx == 0x18) return true; // idle callout else return false; case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ //TODO Maybe do some idling but could screw up other systems :) return true; //So no warning in the debugger anymore case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ /* Removing warning */ return true; case 0x4a01: /* Query free hma space */ case 0x4a02: /* ALLOCATE HMA SPACE */ LOG(LOG_DOSMISC,LOG_WARN)("INT 2f:4a HMA. DOSBox reports none available."); reg_bx=0; //number of bytes available in HMA or amount successfully allocated //ESDI=ffff:ffff Location of HMA/Allocated memory SegSet16(es,0xffff); reg_di=0xffff; return true; case 0x1300: case 0x1302: reg_ax=0; return true; case 0x1605: return true; case 0x1612: reg_ax=0; name[0]=1; name[1]=0; MEM_BlockWrite(SegPhys(es)+reg_bx,name,0x20); return true; case 0x1613: /* Get SYSTEM.DAT path */ strcpy(name,"C:\\WINDOWS\\SYSTEM.DAT"); MEM_BlockWrite(SegPhys(es)+reg_di,name,(Bitu)(strlen(name)+1)); reg_ax=0; reg_cx=strlen(name); return true; case 0x4a16: /* Open bootlog */ return true; case 0x4a17: /* Write bootlog */ MEM_StrCopy(SegPhys(ds)+reg_dx,name,255); LOG(LOG_DOSMISC,LOG_NORMAL)("BOOTLOG: %s\n",name); return true; case 0x4a33: /* Check MS-DOS Version 7 */ reg_ax=0; return true; } return false; }
void CALLBACK_SZF(bool val) { Bit16u tempf=mem_readw(SegPhys(ss)+reg_sp+4) & 0xFFBF; Bit16u newZF=(val==true) << 6; mem_writew(SegPhys(ss)+reg_sp+4,(tempf | newZF)); };
void CALLBACK_SCF(bool val) { Bit16u tempf=mem_readw(SegPhys(ss)+reg_sp+4) & 0xFFFE; Bit16u newCF=(val==true); mem_writew(SegPhys(ss)+reg_sp+4,(tempf | newCF)); };