bool Program::SetEnv(const char * entry,const char * new_string) { PhysPt env_read=PhysMake(psp->GetEnvironment(),0); PhysPt env_write=env_read; char env_string[1024+1]; do { MEM_StrCopy(env_read,env_string,1024); if (!env_string[0]) break; env_read += (PhysPt)(strlen(env_string)+1); if (!strchr(env_string,'=')) continue; /* Remove corrupt entry? */ if ((strncasecmp(entry,env_string,strlen(entry))==0) && env_string[strlen(entry)]=='=') continue; MEM_BlockWrite(env_write,env_string,(Bitu)(strlen(env_string)+1)); env_write += (PhysPt)(strlen(env_string)+1); } while (1); /* TODO Maybe save the program name sometime. not really needed though */ /* Save the new entry */ if (new_string[0]) { std::string bigentry(entry); for (std::string::iterator it = bigentry.begin(); it != bigentry.end(); ++it) *it = toupper(*it); sprintf(env_string,"%s=%s",bigentry.c_str(),new_string); // sprintf(env_string,"%s=%s",entry,new_string); //oldcode MEM_BlockWrite(env_write,env_string,(Bitu)(strlen(env_string)+1)); env_write += (PhysPt)(strlen(env_string)+1); } /* Clear out the final piece of the environment */ mem_writed(env_write,0); return true; }
Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) { DOS_FCB fcb(seg,offset); Bit8u fhandle,cur_rec; Bit16u cur_block,rec_size; fcb.GetSeqData(fhandle,rec_size); if (fhandle==0xff && rec_size!=0) { if (!DOS_FCBOpen(seg,offset)) return FCB_READ_NODATA; LOG(LOG_FCB,LOG_WARN)("Reopened closed FCB"); fcb.GetSeqData(fhandle,rec_size); } if (rec_size == 0) { rec_size = 128; fcb.SetSeqData(fhandle,rec_size); } fcb.GetRecord(cur_block,cur_rec); Bit32u pos=((cur_block*128)+cur_rec)*rec_size; if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET,true)) return FCB_READ_NODATA; Bit16u toread=rec_size; if (!DOS_ReadFile(fhandle,dos_copybuf,&toread,true)) return FCB_READ_NODATA; if (toread==0) return FCB_READ_NODATA; if (toread < rec_size) { //Zero pad copybuffer to rec_size Bitu i = toread; while(i < rec_size) dos_copybuf[i++] = 0; } MEM_BlockWrite(Real2Phys(dos.dta())+recno*rec_size,dos_copybuf,rec_size); if (++cur_rec>127) { cur_block++; cur_rec=0; } fcb.SetRecord(cur_block,cur_rec); if (toread==rec_size) return FCB_SUCCESS; if (toread==0) return FCB_READ_NODATA; return FCB_READ_PARTIAL; }
bool CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) { int cdrom_fd = open(device_name, O_RDONLY | O_NONBLOCK); if (cdrom_fd == -1) return false; Bits buflen = raw ? num * CD_FRAMESIZE_RAW : num * CD_FRAMESIZE; Bit8u* buf = new Bit8u[buflen]; int ret; if (raw) { struct cdrom_read cdrom_read; cdrom_read.cdread_lba = sector; cdrom_read.cdread_bufaddr = (char*)buf; cdrom_read.cdread_buflen = buflen; ret = ioctl(cdrom_fd, CDROMREADRAW, &cdrom_read); } else { ret = lseek(cdrom_fd, sector * CD_FRAMESIZE, SEEK_SET); if (ret >= 0) ret = read(cdrom_fd, buf, buflen); if (ret != buflen) ret = -1; } close(cdrom_fd); MEM_BlockWrite(buffer, buf, buflen); delete[] buf; return (ret > 0); }
bool CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) { BOOL bStat; DWORD byteCount = 0; Bitu buflen = raw ? num*RAW_SECTOR_SIZE : num*COOKED_SECTOR_SIZE; Bit8u* bufdata = new Bit8u[buflen]; if (!raw) { // Cooked int success = 0; DWORD newPos = SetFilePointer(hIOCTL, sector*COOKED_SECTOR_SIZE, 0, FILE_BEGIN); if (newPos != 0xFFFFFFFF) success = ReadFile(hIOCTL, bufdata, buflen, &byteCount, NULL); bStat = (success!=0); } else { // Raw RAW_READ_INFO in; in.DiskOffset.LowPart = sector*COOKED_SECTOR_SIZE; in.DiskOffset.HighPart = 0; in.SectorCount = num; in.TrackMode = CDDA; bStat = DeviceIoControl(hIOCTL,IOCTL_CDROM_RAW_READ, &in, sizeof(in), bufdata, buflen, &byteCount,NULL); } MEM_BlockWrite(buffer,bufdata,buflen); delete[] bufdata; return (byteCount==buflen) && (bStat>0); }
void DOS_DTA::SetResult(const char * _name,Bit32u _size,Bit16u _date,Bit16u _time,Bit8u _attr) { MEM_BlockWrite(pt+offsetof(sDTA,name),(void *)_name,DOS_NAMELENGTH_ASCII); sSave(sDTA,size,_size); sSave(sDTA,date,_date); sSave(sDTA,time,_time); sSave(sDTA,attr,_attr); }
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 {
void DOS_DTA::SetupSearch(Bit8u _sdrive,Bit8u _sattr,char * pattern) { sSave(sDTA,sdrive,_sdrive); sSave(sDTA,sattr,_sattr); /* Fill with spaces */ Bitu i; for (i=0;i<11;i++) mem_writeb(pt+offsetof(sDTA,sname)+i,' '); char * find_ext; find_ext=strchr(pattern,'.'); if (find_ext) { Bitu size=(Bitu)(find_ext-pattern); if (size>8) size=8; MEM_BlockWrite(pt+offsetof(sDTA,sname),pattern,size); find_ext++; MEM_BlockWrite(pt+offsetof(sDTA,sext),find_ext,(strlen(find_ext)>3) ? 3 : (Bitu)strlen(find_ext)); } else { MEM_BlockWrite(pt+offsetof(sDTA,sname),pattern,(strlen(pattern) > 8) ? 8 : (Bitu)strlen(pattern)); } }
void DOS_DTA::SetupSearch(Bit8u _sdrive,Bit8u _sattr,char * pattern) { sSave(sDTA,sdrive,_sdrive); sSave(sDTA,sattr,_sattr); /* Fill with char 0 */ int i; for (i=0;i<LFN_NAMELENGTH;i++) { if (pattern[i]==0) break; sname[i]=pattern[i]; } while (i<=LFN_NAMELENGTH) sname[i++]=0; for (i=0;i<11;i++) mem_writeb(pt+offsetof(sDTA,spname)+i,0); char * find_ext; find_ext=strchr(pattern,'.'); if (find_ext) { Bitu size=(Bitu)(find_ext-pattern); if (size>8) size=8; MEM_BlockWrite(pt+offsetof(sDTA,spname),pattern,size); find_ext++; MEM_BlockWrite(pt+offsetof(sDTA,spext),find_ext,(strlen(find_ext)>3) ? 3 : (Bitu)strlen(find_ext)); } else { MEM_BlockWrite(pt+offsetof(sDTA,spname),pattern,(strlen(pattern) > 8) ? 8 : (Bitu)strlen(pattern)); } }
void DOS_DTA::SetResult(const char * _name, const char * _lname, Bit32u _size,Bit16u _date,Bit16u _time,Bit8u _attr) { MEM_BlockWrite(pt+offsetof(sDTA,name),(void *)_name,strlen(_name)+1); sSave(sDTA,size,_size); sSave(sDTA,date,_date); sSave(sDTA,time,_time); sSave(sDTA,attr,_attr); fd.hsize=0; fd.size=_size; fd.mdate=_date; fd.mtime=_time; fd.attr=_attr; strcpy(fd.lname,_lname); strcpy(fd.sname,_name); if (!strcmp(fd.lname,fd.sname)) fd.sname[0]=0; }
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; }
static Bitu DOS_21Handler(void) { if (((reg_ah != 0x50) && (reg_ah != 0x51) && (reg_ah != 0x62) && (reg_ah != 0x64)) && (reg_ah<0x6c)) { DOS_PSP psp(dos.psp()); psp.SetStack(RealMake(SegValue(ss),reg_sp-18)); } char name1[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII]; char name2[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII]; static Bitu time_start = 0; //For emulating temporary time changes. switch (reg_ah) { case 0x00: /* Terminate Program */ DOS_Terminate(mem_readw(SegPhys(ss)+reg_sp+2),false,0); break; case 0x01: /* Read character from STDIN, with echo */ { Bit8u c;Bit16u n=1; dos.echo=true; DOS_ReadFile(STDIN,&c,&n); reg_al=c; dos.echo=false; } break; case 0x02: /* Write character to STDOUT */ { Bit8u c=reg_dl;Bit16u n=1; DOS_WriteFile(STDOUT,&c,&n); //Not in the official specs, but happens nonetheless. (last written character) reg_al = c;// reg_al=(c==9)?0x20:c; //Officially: tab to spaces } break; case 0x03: /* Read character from STDAUX */ { Bit16u port = real_readw(0x40,0); if(port!=0 && serialports[0]) { Bit8u status; // RTS/DTR on IO_WriteB(port+4,0x3); serialports[0]->Getchar(®_al, &status, true, 0xFFFFFFFF); } } break; case 0x04: /* Write Character to STDAUX */ { Bit16u port = real_readw(0x40,0); if(port!=0 && serialports[0]) { // RTS/DTR on IO_WriteB(port+4,0x3); serialports[0]->Putchar(reg_dl,true,true, 0xFFFFFFFF); // RTS off IO_WriteB(port+4,0x1); } } break; case 0x05: /* Write Character to PRINTER */ E_Exit("DOS:Unhandled call %02X",reg_ah); break; case 0x06: /* Direct Console Output / Input */ switch (reg_dl) { case 0xFF: /* Input */ { //Simulate DOS overhead for timing sensitive games //MM1 overhead(); //TODO Make this better according to standards if (!DOS_GetSTDINStatus()) { reg_al=0; CALLBACK_SZF(true); break; } Bit8u c;Bit16u n=1; DOS_ReadFile(STDIN,&c,&n); reg_al=c; CALLBACK_SZF(false); break; } default: { Bit8u c = reg_dl;Bit16u n = 1; DOS_WriteFile(STDOUT,&c,&n); reg_al = reg_dl; } break; }; break; case 0x07: /* Character Input, without echo */ { Bit8u c;Bit16u n=1; DOS_ReadFile (STDIN,&c,&n); reg_al=c; break; }; case 0x08: /* Direct Character Input, without echo (checks for breaks officially :)*/ { Bit8u c;Bit16u n=1; DOS_ReadFile (STDIN,&c,&n); reg_al=c; break; }; case 0x09: /* Write string to STDOUT */ { Bit8u c;Bit16u n=1; PhysPt buf=SegPhys(ds)+reg_dx; while ((c=mem_readb(buf++))!='$') { DOS_WriteFile(STDOUT,&c,&n); } } break; case 0x0a: /* Buffered Input */ { //TODO ADD Break checkin in STDIN but can't care that much for it PhysPt data=SegPhys(ds)+reg_dx; Bit8u free=mem_readb(data); Bit8u read=0;Bit8u c;Bit16u n=1; if (!free) break; free--; for(;;) { DOS_ReadFile(STDIN,&c,&n); if (c == 8) { // Backspace if (read) { //Something to backspace. // STDOUT treats backspace as non-destructive. DOS_WriteFile(STDOUT,&c,&n); c = ' '; DOS_WriteFile(STDOUT,&c,&n); c = 8; DOS_WriteFile(STDOUT,&c,&n); --read; } continue; } if (read == free && c != 13) { // Keyboard buffer full Bit8u bell = 7; DOS_WriteFile(STDOUT, &bell, &n); continue; } DOS_WriteFile(STDOUT,&c,&n); mem_writeb(data+read+2,c); if (c==13) break; read++; }; mem_writeb(data+1,read); break; }; case 0x0b: /* Get STDIN Status */ if (!DOS_GetSTDINStatus()) {reg_al=0x00;} else {reg_al=0xFF;} //Simulate some overhead for timing issues //Tankwar menu (needs maybe even more) overhead(); break; case 0x0c: /* Flush Buffer and read STDIN call */ { /* flush buffer if STDIN is CON */ Bit8u handle=RealHandle(STDIN); if (handle!=0xFF && Files[handle] && Files[handle]->IsName("CON")) { Bit8u c;Bit16u n; while (DOS_GetSTDINStatus()) { n=1; DOS_ReadFile(STDIN,&c,&n); } } switch (reg_al) { case 0x1: case 0x6: case 0x7: case 0x8: case 0xa: { Bit8u oldah=reg_ah; reg_ah=reg_al; DOS_21Handler(); reg_ah=oldah; } break; default: // LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al); reg_al=0; break; } } break; //TODO Find out the values for when reg_al!=0 //TODO Hope this doesn't do anything special case 0x0d: /* Disk Reset */ //Sure let's reset a virtual disk break; case 0x0e: /* Select Default Drive */ DOS_SetDefaultDrive(reg_dl); reg_al=DOS_DRIVES; break; case 0x0f: /* Open File using FCB */ if(DOS_FCBOpen(SegValue(ds),reg_dx)){ reg_al=0; }else{ reg_al=0xff; } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x0f FCB-fileopen used, result:al=%d",reg_al); break; case 0x10: /* Close File using FCB */ if(DOS_FCBClose(SegValue(ds),reg_dx)){ reg_al=0; }else{ reg_al=0xff; } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x10 FCB-fileclose used, result:al=%d",reg_al); break; case 0x11: /* Find First Matching File using FCB */ if(DOS_FCBFindFirst(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x11 FCB-FindFirst used, result:al=%d",reg_al); break; case 0x12: /* Find Next Matching File using FCB */ if(DOS_FCBFindNext(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x12 FCB-FindNext used, result:al=%d",reg_al); break; case 0x13: /* Delete File using FCB */ if (DOS_FCBDeleteFile(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x16 FCB-Delete used, result:al=%d",reg_al); break; case 0x14: /* Sequential read from FCB */ reg_al = DOS_FCBRead(SegValue(ds),reg_dx,0); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x14 FCB-Read used, result:al=%d",reg_al); break; case 0x15: /* Sequential write to FCB */ reg_al=DOS_FCBWrite(SegValue(ds),reg_dx,0); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x15 FCB-Write used, result:al=%d",reg_al); break; case 0x16: /* Create or truncate file using FCB */ if (DOS_FCBCreate(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; LOG(LOG_FCB,LOG_NORMAL)("DOS:0x16 FCB-Create used, result:al=%d",reg_al); break; case 0x17: /* Rename file using FCB */ if (DOS_FCBRenameFile(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; break; case 0x1b: /* Get allocation info for default drive */ if (!DOS_GetAllocationInfo(0,®_cx,®_al,®_dx)) reg_al=0xff; break; case 0x1c: /* Get allocation info for specific drive */ if (!DOS_GetAllocationInfo(reg_dl,®_cx,®_al,®_dx)) reg_al=0xff; break; case 0x21: /* Read random record from FCB */ { Bit16u toread=1; reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,&toread,true); } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x21 FCB-Random read used, result:al=%d",reg_al); break; case 0x22: /* Write random record to FCB */ { Bit16u towrite=1; reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,&towrite,true); } LOG(LOG_FCB,LOG_NORMAL)("DOS:0x22 FCB-Random write used, result:al=%d",reg_al); break; case 0x23: /* Get file size for FCB */ if (DOS_FCBGetFileSize(SegValue(ds),reg_dx)) reg_al = 0x00; else reg_al = 0xFF; break; case 0x24: /* Set Random Record number for FCB */ DOS_FCBSetRandomRecord(SegValue(ds),reg_dx); break; case 0x27: /* Random block read from FCB */ reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,®_cx,false); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x27 FCB-Random(block) read used, result:al=%d",reg_al); break; case 0x28: /* Random Block write to FCB */ reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,®_cx,false); LOG(LOG_FCB,LOG_NORMAL)("DOS:0x28 FCB-Random(block) write used, result:al=%d",reg_al); break; case 0x29: /* Parse filename into FCB */ { Bit8u difference; char string[1024]; MEM_StrCopy(SegPhys(ds)+reg_si,string,1023); // 1024 toasts the stack reg_al=FCB_Parsename(SegValue(es),reg_di,reg_al ,string, &difference); reg_si+=difference; } LOG(LOG_FCB,LOG_NORMAL)("DOS:29:FCB Parse Filename, result:al=%d",reg_al); break; case 0x19: /* Get current default drive */ reg_al=DOS_GetDefaultDrive(); break; case 0x1a: /* Set Disk Transfer Area Address */ dos.dta(RealMakeSeg(ds,reg_dx)); break; case 0x25: /* Set Interrupt Vector */ RealSetVec(reg_al,RealMakeSeg(ds,reg_dx)); break; case 0x26: /* Create new PSP */ DOS_NewPSP(reg_dx,DOS_PSP(dos.psp()).GetSize()); reg_al=0xf0; /* al destroyed */ break; case 0x2a: /* Get System Date */ { reg_ax=0; // get time CALLBACK_RunRealInt(0x1a); if(reg_al) DOS_AddDays(reg_al); int a = (14 - dos.date.month)/12; int y = dos.date.year - a; int m = dos.date.month + 12*a - 2; reg_al=(dos.date.day+y+(y/4)-(y/100)+(y/400)+(31*m)/12) % 7; reg_cx=dos.date.year; reg_dh=dos.date.month; reg_dl=dos.date.day; } break; case 0x2b: /* Set System Date */ if (reg_cx<1980) { reg_al=0xff;break;} if ((reg_dh>12) || (reg_dh==0)) { reg_al=0xff;break;} if (reg_dl==0) { reg_al=0xff;break;} if (reg_dl>DOS_DATE_months[reg_dh]) { if(!((reg_dh==2)&&(reg_cx%4 == 0)&&(reg_dl==29))) // february pass { reg_al=0xff;break; } } dos.date.year=reg_cx; dos.date.month=reg_dh; dos.date.day=reg_dl; reg_al=0; break; case 0x2c: { /* Get System Time */ reg_ax=0; // get time CALLBACK_RunRealInt(0x1a); if(reg_al) DOS_AddDays(reg_al); reg_ah=0x2c; Bitu ticks=((Bitu)reg_cx<<16)|reg_dx; if(time_start<=ticks) ticks-=time_start; Bitu time=(Bitu)((100.0/((double)PIT_TICK_RATE/65536.0)) * (double)ticks); reg_dl=(Bit8u)((Bitu)time % 100); // 1/100 seconds time/=100; reg_dh=(Bit8u)((Bitu)time % 60); // seconds time/=60; reg_cl=(Bit8u)((Bitu)time % 60); // minutes time/=60; reg_ch=(Bit8u)((Bitu)time % 24); // hours //Simulate DOS overhead for timing-sensitive games //Robomaze 2 overhead(); break; } case 0x2d: /* Set System Time */ LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Set System Time not supported"); //Check input parameters nonetheless if( reg_ch > 23 || reg_cl > 59 || reg_dh > 59 || reg_dl > 99 ) reg_al = 0xff; else { //Allow time to be set to zero. Restore the orginal time for all other parameters. (QuickBasic) if (reg_cx == 0 && reg_dx == 0) {time_start = mem_readd(BIOS_TIMER);LOG_MSG("Warning: game messes with DOS time!");} else time_start = 0; reg_al = 0; } break; case 0x2e: /* Set Verify flag */ dos.verify=(reg_al==1); break; case 0x2f: /* Get Disk Transfer Area */ SegSet16(es,RealSeg(dos.dta())); reg_bx=RealOff(dos.dta()); break; case 0x30: /* Get DOS Version */ if (reg_al==0) reg_bh=0xFF; /* Fake Microsoft DOS */ if (reg_al==1) reg_bh=0x10; /* DOS is in HMA */ reg_al=dos.version.major; reg_ah=dos.version.minor; /* Serialnumber */ reg_bl=0x00; reg_cx=0x0000; break; case 0x31: /* Terminate and stay resident */ // Important: This service does not set the carry flag! DOS_ResizeMemory(dos.psp(),®_dx); DOS_Terminate(dos.psp(),true,reg_al); break; case 0x1f: /* Get drive parameter block for default drive */ case 0x32: /* Get drive parameter block for specific drive */ { /* Officially a dpb should be returned as well. The disk detection part is implemented */ Bit8u drive=reg_dl; if (!drive || reg_ah==0x1f) drive = DOS_GetDefaultDrive(); else drive--; if (Drives[drive]) { reg_al = 0x00; SegSet16(ds,dos.tables.dpb); reg_bx = drive;//Faking only the first entry (that is the driveletter) LOG(LOG_DOSMISC,LOG_ERROR)("Get drive parameter block."); } else { reg_al=0xff; } } break; case 0x33: /* Extended Break Checking */ switch (reg_al) { case 0:reg_dl=dos.breakcheck;break; /* Get the breakcheck flag */ case 1:dos.breakcheck=(reg_dl>0);break; /* Set the breakcheck flag */ case 2:{bool old=dos.breakcheck;dos.breakcheck=(reg_dl>0);reg_dl=old;}break; case 3: /* Get cpsw */ /* Fallthrough */ case 4: /* Set cpsw */ LOG(LOG_DOSMISC,LOG_ERROR)("Someone playing with cpsw %x",reg_ax); break; case 5:reg_dl=3;break;//TODO should be z /* Always boot from c: :) */ case 6: /* Get true version number */ reg_bl=dos.version.major; reg_bh=dos.version.minor; reg_dl=dos.version.revision; reg_dh=0x10; /* Dos in HMA */ break; default: LOG(LOG_DOSMISC,LOG_ERROR)("Weird 0x33 call %2X",reg_al); reg_al =0xff; break; } break; case 0x34: /* Get INDos Flag */ SegSet16(es,DOS_SDA_SEG); reg_bx=DOS_SDA_OFS + 0x01; break; case 0x35: /* Get interrupt vector */ reg_bx=real_readw(0,((Bit16u)reg_al)*4); SegSet16(es,real_readw(0,((Bit16u)reg_al)*4+2)); break; case 0x36: /* Get Free Disk Space */ { Bit16u bytes,clusters,free; Bit8u sectors; if (DOS_GetFreeDiskSpace(reg_dl,&bytes,§ors,&clusters,&free)) { reg_ax=sectors; reg_bx=free; reg_cx=bytes; reg_dx=clusters; } else { Bit8u drive=reg_dl; if (drive==0) drive=DOS_GetDefaultDrive(); else drive--; if (drive<2) { // floppy drive, non-present drivesdisks issue floppy check through int24 // (critical error handler); needed for Mixed up Mother Goose (hook) // CALLBACK_RunRealInt(0x24); } reg_ax=0xffff; // invalid drive specified } } break; case 0x37: /* Get/Set Switch char Get/Set Availdev thing */ //TODO Give errors for these functions to see if anyone actually uses this shit- switch (reg_al) { case 0: reg_al=0;reg_dl=0x2f;break; /* always return '/' like dos 5.0+ */ case 1: reg_al=0;break; case 2: reg_al=0;reg_dl=0x2f;break; case 3: reg_al=0;break; }; LOG(LOG_MISC,LOG_ERROR)("DOS:0x37:Call for not supported switchchar"); break; case 0x38: /* Set Country Code */ if (reg_al==0) { /* Get country specidic information */ PhysPt dest = SegPhys(ds)+reg_dx; MEM_BlockWrite(dest,dos.tables.country,0x18); reg_ax = reg_bx = 0x01; CALLBACK_SCF(false); break; } else { /* Set country code */ LOG(LOG_MISC,LOG_ERROR)("DOS:Setting country code not supported"); } CALLBACK_SCF(true); break; case 0x39: /* MKDIR Create directory */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_MakeDir(name1)) { reg_ax=0x05; /* ax destroyed */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3a: /* RMDIR Remove directory */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_RemoveDir(name1)) { reg_ax=0x05; /* ax destroyed */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); LOG(LOG_MISC,LOG_NORMAL)("Remove dir failed on %s with error %X",name1,dos.errorcode); } break; case 0x3b: /* CHDIR Set current directory */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_ChangeDir(name1)) { reg_ax=0x00; /* ax destroyed */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3c: /* CREATE Create of truncate file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_CreateFile(name1,reg_cx,®_ax)) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3d: /* OPEN Open existing file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_OpenFile(name1,reg_al,®_ax)) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3e: /* CLOSE Close file */ if (DOS_CloseFile(reg_bx)) { // reg_al=0x01; /* al destroyed. Refcount */ CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x3f: /* READ Read from file or device */ { Bit16u toread=reg_cx; dos.echo=true; if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) { MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread); reg_ax=toread; CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } modify_cycles(reg_ax); dos.echo=false; break; } case 0x40: /* WRITE Write to file or device */ { Bit16u towrite=reg_cx; MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite); if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) { reg_ax=towrite; CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } modify_cycles(reg_ax); break; }; case 0x41: /* UNLINK Delete file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_UnlinkFile(name1)) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; case 0x42: /* LSEEK Set current file position */ { Bit32u pos=(reg_cx<<16) + reg_dx; if (DOS_SeekFile(reg_bx,&pos,reg_al)) { reg_dx=(Bit16u)(pos >> 16); reg_ax=(Bit16u)(pos & 0xFFFF); CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); } break; }
void DOS_FCB::SetName(Bit8u _drive,char * _fname,char * _ext) { sSave(sFCB,drive,_drive); MEM_BlockWrite(pt+offsetof(sFCB,filename),_fname,8); MEM_BlockWrite(pt+offsetof(sFCB,ext),_ext,3); }
static Bitu INT33_Handler(void) { // LOG(LOG_MOUSE,LOG_NORMAL)("MOUSE: %04X %X %X %d %d",reg_ax,reg_bx,reg_cx,POS_X,POS_Y); switch (reg_ax) { case 0x00: /* Reset Driver and Read Status */ Mouse_ResetHardware(); /* fallthrough */ case 0x21: /* Software Reset */ reg_ax=0xffff; reg_bx=MOUSE_BUTTONS; Mouse_Reset(); Mouse_AutoLock(true); break; case 0x01: /* Show Mouse */ if(mouse.hidden) mouse.hidden--; Mouse_AutoLock(true); DrawCursor(); break; case 0x02: /* Hide Mouse */ { if (CurMode->type!=M_TEXT) RestoreCursorBackground(); else RestoreCursorBackgroundText(); mouse.hidden++; } break; case 0x03: /* Return position and Button Status */ reg_bx=mouse.buttons; reg_cx=POS_X; reg_dx=POS_Y; break; case 0x04: /* Position Mouse */ /* If position isn't different from current position * don't change it then. (as position is rounded so numbers get * lost when the rounded number is set) (arena/simulation Wolf) */ if ((Bit16s)reg_cx >= mouse.max_x) mouse.x = static_cast<float>(mouse.max_x); else if (mouse.min_x >= (Bit16s)reg_cx) mouse.x = static_cast<float>(mouse.min_x); else if ((Bit16s)reg_cx != POS_X) mouse.x = static_cast<float>(reg_cx); if ((Bit16s)reg_dx >= mouse.max_y) mouse.y = static_cast<float>(mouse.max_y); else if (mouse.min_y >= (Bit16s)reg_dx) mouse.y = static_cast<float>(mouse.min_y); else if ((Bit16s)reg_dx != POS_Y) mouse.y = static_cast<float>(reg_dx); DrawCursor(); break; case 0x05: /* Return Button Press Data */ { Bit16u but=reg_bx; reg_ax=mouse.buttons; if (but>=MOUSE_BUTTONS) but = MOUSE_BUTTONS - 1; reg_cx=mouse.last_pressed_x[but]; reg_dx=mouse.last_pressed_y[but]; reg_bx=mouse.times_pressed[but]; mouse.times_pressed[but]=0; break; } case 0x06: /* Return Button Release Data */ { Bit16u but=reg_bx; reg_ax=mouse.buttons; if (but>=MOUSE_BUTTONS) but = MOUSE_BUTTONS - 1; reg_cx=mouse.last_released_x[but]; reg_dx=mouse.last_released_y[but]; reg_bx=mouse.times_released[but]; mouse.times_released[but]=0; break; } case 0x07: /* Define horizontal cursor range */ { //lemmings set 1-640 and wants that. iron seeds set 0-640 but doesn't like 640 //Iron seed works if newvideo mode with mode 13 sets 0-639 //Larry 6 actually wants newvideo mode with mode 13 to set it to 0-319 Bit16s max,min; if ((Bit16s)reg_cx<(Bit16s)reg_dx) { min=(Bit16s)reg_cx;max=(Bit16s)reg_dx;} else { min=(Bit16s)reg_dx;max=(Bit16s)reg_cx;} mouse.min_x=min; mouse.max_x=max; /* Battlechess wants this */ if(mouse.x > mouse.max_x) mouse.x = mouse.max_x; if(mouse.x < mouse.min_x) mouse.x = mouse.min_x; /* Or alternatively this: mouse.x = (mouse.max_x - mouse.min_x + 1)/2;*/ LOG(LOG_MOUSE,LOG_NORMAL)("Define Hortizontal range min:%d max:%d",min,max); } break; case 0x08: /* Define vertical cursor range */ { // not sure what to take instead of the CurMode (see case 0x07 as well) // especially the cases where sheight= 400 and we set it with the mouse_reset to 200 //disabled it at the moment. Seems to break syndicate who want 400 in mode 13 Bit16s max,min; if ((Bit16s)reg_cx<(Bit16s)reg_dx) { min=(Bit16s)reg_cx;max=(Bit16s)reg_dx;} else { min=(Bit16s)reg_dx;max=(Bit16s)reg_cx;} mouse.min_y=min; mouse.max_y=max; /* Battlechess wants this */ if(mouse.y > mouse.max_y) mouse.y = mouse.max_y; if(mouse.y < mouse.min_y) mouse.y = mouse.min_y; /* Or alternatively this: mouse.y = (mouse.max_y - mouse.min_y + 1)/2;*/ LOG(LOG_MOUSE,LOG_NORMAL)("Define Vertical range min:%d max:%d",min,max); } break; case 0x09: /* Define GFX Cursor */ { PhysPt src = SegPhys(es)+reg_dx; MEM_BlockRead(src ,userdefScreenMask,CURSORY*2); MEM_BlockRead(src+CURSORY*2,userdefCursorMask,CURSORY*2); mouse.screenMask = userdefScreenMask; mouse.cursorMask = userdefCursorMask; mouse.hotx = reg_bx; mouse.hoty = reg_cx; mouse.cursorType = 2; DrawCursor(); } break; case 0x0a: /* Define Text Cursor */ mouse.cursorType = reg_bx; mouse.textAndMask = reg_cx; mouse.textXorMask = reg_dx; break; case 0x0b: /* Read Motion Data */ reg_cx=(Bit16s)(mouse.mickey_x*mouse.mickeysPerPixel_x); reg_dx=(Bit16s)(mouse.mickey_y*mouse.mickeysPerPixel_y); mouse.mickey_x=0; mouse.mickey_y=0; break; case 0x0c: /* Define interrupt subroutine parameters */ mouse.sub_mask=reg_cx; mouse.sub_seg=SegValue(es); mouse.sub_ofs=reg_dx; Mouse_AutoLock(true); //Some games don't seem to reset the mouse before using break; case 0x0f: /* Define mickey/pixel rate */ Mouse_SetMickeyPixelRate(reg_cx,reg_dx); break; case 0x10: /* Define screen region for updating */ mouse.updateRegion_x[0]=reg_cx; mouse.updateRegion_y[0]=reg_dx; mouse.updateRegion_x[1]=reg_si; mouse.updateRegion_y[1]=reg_di; break; case 0x11: /* Get number of buttons */ reg_ax=0xffff; reg_bx=MOUSE_BUTTONS; break; case 0x13: /* Set double-speed threshold */ mouse.doubleSpeedThreshold=(reg_bx ? reg_bx : 64); break; case 0x14: /* Exchange event-handler */ { Bit16u oldSeg = mouse.sub_seg; Bit16u oldOfs = mouse.sub_ofs; Bit16u oldMask= mouse.sub_mask; // Set new values mouse.sub_mask= reg_cx; mouse.sub_seg = SegValue(es); mouse.sub_ofs = reg_dx; // Return old values reg_cx = oldMask; reg_dx = oldOfs; SegSet16(es,oldSeg); } break; case 0x15: /* Get Driver storage space requirements */ reg_bx = sizeof(mouse); break; case 0x16: /* Save driver state */ { LOG(LOG_MOUSE,LOG_WARN)("Saving driver state..."); PhysPt dest = SegPhys(es)+reg_dx; MEM_BlockWrite(dest, &mouse, sizeof(mouse)); } break; case 0x17: /* load driver state */ { LOG(LOG_MOUSE,LOG_WARN)("Loading driver state..."); PhysPt src = SegPhys(es)+reg_dx; MEM_BlockRead(src, &mouse, sizeof(mouse)); } break; case 0x1a: /* Set mouse sensitivity */ // ToDo : double mouse speed value Mouse_SetSensitivity(reg_bx,reg_cx,reg_dx); LOG(LOG_MOUSE,LOG_WARN)("Set sensitivity used with %d %d (%d)",reg_bx,reg_cx,reg_dx); break; case 0x1b: /* Get mouse sensitivity */ reg_bx = mouse.senv_x_val; reg_cx = mouse.senv_y_val; reg_dx = mouse.dspeed_val; LOG(LOG_MOUSE,LOG_WARN)("Get sensitivity %d %d",reg_bx,reg_cx); break; case 0x1c: /* Set interrupt rate */ /* Can't really set a rate this is host determined */ break; case 0x1d: /* Set display page number */ mouse.page=reg_bl; break; case 0x1e: /* Get display page number */ reg_bx=mouse.page; break; case 0x1f: /* Disable Mousedriver */ /* ES:BX old mouse driver Zero at the moment TODO */ reg_bx=0; SegSet16(es,0); mouse.enabled=false; /* Just for reporting not doing a thing with it */ mouse.oldhidden=mouse.hidden; mouse.hidden=1; break; case 0x20: /* Enable Mousedriver */ mouse.enabled=true; mouse.hidden=mouse.oldhidden; break; case 0x22: /* Set language for messages */ /* * Values for mouse driver language: * * 00h English * 01h French * 02h Dutch * 03h German * 04h Swedish * 05h Finnish * 06h Spanish * 07h Portugese * 08h Italian * */ mouse.language=reg_bx; break; case 0x23: /* Get language for messages */ reg_bx=mouse.language; break; case 0x24: /* Get Software version and mouse type */ reg_bx=0x805; //Version 8.05 woohoo reg_ch=0x04; /* PS/2 type */ reg_cl=0; /* PS/2 (unused) */ break; case 0x26: /* Get Maximum virtual coordinates */ reg_bx=(mouse.enabled ? 0x0000 : 0xffff); reg_cx=(Bit16u)mouse.max_x; reg_dx=(Bit16u)mouse.max_y; break; case 0x31: /* Get Current Minimum/Maximum virtual coordinates */ reg_ax=(Bit16u)mouse.min_x; reg_bx=(Bit16u)mouse.min_y; reg_cx=(Bit16u)mouse.max_x; reg_dx=(Bit16u)mouse.max_y; break; default: LOG(LOG_MOUSE,LOG_ERROR)("Mouse Function %04X not implemented!",reg_ax); break; } return CBRET_NONE; }
Bit8u VESA_GetSVGAModeInformation(Bit16u mode,Bit16u seg,Bit16u off) { MODE_INFO minfo; memset(&minfo,0,sizeof(minfo)); PhysPt buf=PhysMake(seg,off); Bitu pageSize; Bit8u modeAttributes; Bitu i=0; mode&=0x3fff; // vbe2 compatible, ignore lfb and keep screen content bits if (mode<0x100) return 0x01; if (svga.accepts_mode) { if (!svga.accepts_mode(mode)) return 0x01; } while (ModeList_VGA[i].mode!=0xffff) { if (mode==ModeList_VGA[i].mode) goto foundit; else i++; } return VESA_FAIL; foundit: if ((int10.vesa_oldvbe) && (ModeList_VGA[i].mode>=0x120)) return 0x01; VideoModeBlock * mblock=&ModeList_VGA[i]; switch (mblock->type) { case M_LIN4: pageSize = mblock->sheight * mblock->swidth/2; var_write(&minfo.BytesPerScanLine,mblock->swidth/8); var_write(&minfo.NumberOfPlanes,0x4); var_write(&minfo.BitsPerPixel,4); var_write(&minfo.MemoryModel,3); //ega planar mode modeAttributes = 0x1b; // Color, graphics, no linear buffer break; case M_LIN8: pageSize = mblock->sheight * mblock->swidth; var_write(&minfo.BytesPerScanLine,mblock->swidth); var_write(&minfo.NumberOfPlanes,0x1); var_write(&minfo.BitsPerPixel,8); var_write(&minfo.MemoryModel,4); //packed pixel modeAttributes = 0x1b; // Color, graphics if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer break; case M_LIN15: pageSize = mblock->sheight * mblock->swidth*2; var_write(&minfo.BytesPerScanLine,mblock->swidth*2); var_write(&minfo.NumberOfPlanes,0x1); var_write(&minfo.BitsPerPixel,15); var_write(&minfo.MemoryModel,6); //HiColour var_write(&minfo.RedMaskSize,5); var_write(&minfo.RedMaskPos,10); var_write(&minfo.GreenMaskSize,5); var_write(&minfo.GreenMaskPos,5); var_write(&minfo.BlueMaskSize,5); var_write(&minfo.BlueMaskPos,0); var_write(&minfo.ReservedMaskSize,0x01); var_write(&minfo.ReservedMaskPos,0x0f); modeAttributes = 0x1b; // Color, graphics if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer break; case M_LIN16: pageSize = mblock->sheight * mblock->swidth*2; var_write(&minfo.BytesPerScanLine,mblock->swidth*2); var_write(&minfo.NumberOfPlanes,0x1); var_write(&minfo.BitsPerPixel,16); var_write(&minfo.MemoryModel,6); //HiColour var_write(&minfo.RedMaskSize,5); var_write(&minfo.RedMaskPos,11); var_write(&minfo.GreenMaskSize,6); var_write(&minfo.GreenMaskPos,5); var_write(&minfo.BlueMaskSize,5); var_write(&minfo.BlueMaskPos,0); modeAttributes = 0x1b; // Color, graphics if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer break; case M_LIN32: pageSize = mblock->sheight * mblock->swidth*4; var_write(&minfo.BytesPerScanLine,mblock->swidth*4); var_write(&minfo.NumberOfPlanes,0x1); var_write(&minfo.BitsPerPixel,32); var_write(&minfo.MemoryModel,6); //HiColour var_write(&minfo.RedMaskSize,8); var_write(&minfo.RedMaskPos,0x10); var_write(&minfo.GreenMaskSize,0x8); var_write(&minfo.GreenMaskPos,0x8); var_write(&minfo.BlueMaskSize,0x8); var_write(&minfo.BlueMaskPos,0x0); var_write(&minfo.ReservedMaskSize,0x8); var_write(&minfo.ReservedMaskPos,0x18); modeAttributes = 0x1b; // Color, graphics if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer break; case M_TEXT: pageSize = 0; var_write(&minfo.BytesPerScanLine, mblock->twidth * 2); var_write(&minfo.NumberOfPlanes,0x4); var_write(&minfo.BitsPerPixel,4); var_write(&minfo.MemoryModel,0); // text modeAttributes = 0x0f; //Color, text, bios output break; default: return VESA_FAIL; } if (pageSize & 0xFFFF) { // It is documented that many applications assume 64k-aligned page sizes // VBETEST is one of them pageSize += 0x10000; pageSize &= ~0xFFFF; } Bitu pages = 0; if (pageSize > vga.vmemsize) { // mode not supported by current hardware configuration modeAttributes &= ~0x1; } else if (pageSize) { pages = (vga.vmemsize / pageSize)-1; } var_write(&minfo.NumberOfImagePages, pages); var_write(&minfo.ModeAttributes, modeAttributes); var_write(&minfo.WinAAttributes, 0x7); // Exists/readable/writable if (mblock->type==M_TEXT) { var_write(&minfo.WinGranularity,32); var_write(&minfo.WinSize,32); var_write(&minfo.WinASegment,0xb800); var_write(&minfo.XResolution,mblock->twidth); var_write(&minfo.YResolution,mblock->theight); } else { var_write(&minfo.WinGranularity,64); var_write(&minfo.WinSize,64); var_write(&minfo.WinASegment,0xa000); var_write(&minfo.XResolution,mblock->swidth); var_write(&minfo.YResolution,mblock->sheight); } var_write(&minfo.WinFuncPtr,CALLBACK_RealPointer(callback.setwindow)); var_write(&minfo.NumberOfBanks,0x1); var_write(&minfo.Reserved_page,0x1); var_write(&minfo.XCharSize,mblock->cwidth); var_write(&minfo.YCharSize,mblock->cheight); if (!int10.vesa_nolfb) var_write(&minfo.PhysBasePtr,S3_LFB_BASE); MEM_BlockWrite(buf,&minfo,sizeof(MODE_INFO)); return VESA_SUCCESS; }
bool DOS_Shell::Execute(char * name,char * args) { /* return true => don't check for hardware changes in do_command * return false => check for hardware changes in do_command */ char fullname[DOS_PATHLENGTH+4]; //stores results from Which char* p_fullname; char line[CMD_MAXLINE]; if(strlen(args)!= 0){ if(*args != ' '){ //put a space in front line[0]=' ';line[1]=0; strncat(line,args,CMD_MAXLINE-2); line[CMD_MAXLINE-1]=0; } else { safe_strncpy(line,args,CMD_MAXLINE); } }else{ line[0]=0; }; /* check for a drive change */ if (((strcmp(name + 1, ":") == 0) || (strcmp(name + 1, ":\\") == 0)) && isalpha(*name)) { if (!DOS_SetDrive(toupper(name[0])-'A')) { WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0])); } return true; } /* Check for a full name */ p_fullname = Which(name); if (!p_fullname) return false; strcpy(fullname,p_fullname); const char* extension = strrchr(fullname,'.'); __android_log_print(ANDROID_LOG_INFO, "dosbox", "command fullname:%s", fullname); /*always disallow files without extension from being executed. */ /*only internal commands can be run this way and they never get in this handler */ if(extension == 0) { //Check if the result will fit in the parameters. Else abort if(strlen(fullname) >( DOS_PATHLENGTH - 1) ) return false; char temp_name[DOS_PATHLENGTH+4],* temp_fullname; //try to add .com, .exe and .bat extensions to filename strcpy(temp_name,fullname); strcat(temp_name,".COM"); temp_fullname=Which(temp_name); if (temp_fullname) { extension=".com";strcpy(fullname,temp_fullname); } else { strcpy(temp_name,fullname); strcat(temp_name,".EXE"); temp_fullname=Which(temp_name); if (temp_fullname) { extension=".exe";strcpy(fullname,temp_fullname);} else { strcpy(temp_name,fullname); strcat(temp_name,".BAT"); temp_fullname=Which(temp_name); if (temp_fullname) { extension=".bat";strcpy(fullname,temp_fullname);} else { return false; } } } } if (strcasecmp(extension, ".bat") == 0) { /* Run the .bat file */ /* delete old batch file if call is not active*/ bool temp_echo=echo; /*keep the current echostate (as delete bf might change it )*/ if(bf && !call) delete bf; bf=new BatchFile(this,fullname,name,line); echo=temp_echo; //restore it. } else { /* only .bat .exe .com extensions maybe be executed by the shell */ if(strcasecmp(extension, ".com") !=0) { if(strcasecmp(extension, ".exe") !=0) return false; } /* Run the .exe or .com file from the shell */ /* Allocate some stack space for tables in physical memory */ reg_sp-=0x200; //Add Parameter block DOS_ParamBlock block(SegPhys(ss)+reg_sp); block.Clear(); //Add a filename RealPt file_name=RealMakeSeg(ss,reg_sp+0x20); MEM_BlockWrite(Real2Phys(file_name),fullname,(Bitu)(strlen(fullname)+1)); /* HACK: Store full commandline for mount and imgmount */ full_arguments.assign(line); /* Fill the command line */ CommandTail cmdtail; cmdtail.count = 0; memset(&cmdtail.buffer,0,126); //Else some part of the string is unitialized (valgrind) if (strlen(line)>126) line[126]=0; cmdtail.count=(Bit8u)strlen(line); memcpy(cmdtail.buffer,line,strlen(line)); cmdtail.buffer[strlen(line)]=0xd; /* Copy command line in stack block too */ MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmdtail,128); /* Parse FCB (first two parameters) and put them into the current DOS_PSP */ Bit8u add; FCB_Parsename(dos.psp(),0x5C,0x00,cmdtail.buffer,&add); FCB_Parsename(dos.psp(),0x6C,0x00,&cmdtail.buffer[add],&add); block.exec.fcb1=RealMake(dos.psp(),0x5C); block.exec.fcb2=RealMake(dos.psp(),0x6C); /* Set the command line in the block and save it */ block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100); block.SaveData(); #if 0 /* Save CS:IP to some point where i can return them from */ Bit32u oldeip=reg_eip; Bit16u oldcs=SegValue(cs); RealPt newcsip=CALLBACK_RealPointer(call_shellstop); SegSet16(cs,RealSeg(newcsip)); reg_ip=RealOff(newcsip); #endif /* Start up a dos execute interrupt */ reg_ax=0x4b00; //Filename pointer SegSet16(ds,SegValue(ss)); reg_dx=RealOff(file_name); //Paramblock SegSet16(es,SegValue(ss)); reg_bx=reg_sp; SETFLAGBIT(IF,false); CALLBACK_RunRealInt(0x21); /* Restore CS:IP and the stack */ reg_sp+=0x200; #if 0 reg_eip=oldeip; SegSet16(cs,oldcs); #endif } return true; //Executable started }
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 SetName (char const* _name) { MEM_BlockWrite(pt+offsetof(sDeviceHeader,name),_name,8); };
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; }
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; }
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 CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num){ HFILE cdrom_fd = 0; ULONG ulAction = 0; APIRET rc = DosOpen((unsigned char*)device_name, &cdrom_fd, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_DASD | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L); if (rc != NO_ERROR) { return false; } Bitu buflen = raw ? num * CD_FRAMESIZE_RAW : num * CD_FRAMESIZE; Bit8u* buf = new Bit8u[buflen]; int ret = NO_ERROR; if (raw) { struct paramseek { UCHAR sig[4]; UCHAR mode; ULONG sec; paramseek(ULONG sector) { sig[0] = 'C'; sig[1] = 'D'; sig[2] = '0'; sig[3] = '1'; sec = sector; } } param_seek(sector); ULONG paramsize = sizeof (paramseek); rc = DosDevIOCtl(cdrom_fd, IOCTL_CDROMDISK, CDROMDISK_SEEK, ¶m_seek, paramsize, ¶msize, 0, 0, 0); if (rc != NO_ERROR) { return false; } struct paramread { UCHAR sig[4]; UCHAR mode; USHORT number; BYTE sec; BYTE reserved; BYTE interleave; paramread(USHORT num) { sig[0] = 'C'; sig[1] = 'D'; sig[2] = '0'; sig[3] = '1'; mode = 0; number = num; sec = interleave = 0; } } param_read(num); paramsize = sizeof (paramread); ULONG len = buflen; rc = DosDevIOCtl(cdrom_fd, IOCTL_CDROMDISK, CDROMDISK_READLONG, ¶m_read, paramsize, ¶msize, buf, len, &len); if (rc != NO_ERROR) { return false; } } else { ULONG pos = 0; rc = DosSetFilePtr(cdrom_fd, sector * CD_FRAMESIZE, FILE_BEGIN, &pos); if (rc != NO_ERROR) { return false; } ULONG read = 0; rc = DosRead(cdrom_fd, buf, buflen, &read); if (rc != NO_ERROR || read != buflen) { return false; } } rc = DosClose(cdrom_fd); MEM_BlockWrite(buffer, buf, buflen); delete[] buf; return (ret == NO_ERROR); }
void DOS_PSP::RestoreCommandTail() { mem_writeb(pt+offsetof(sPSP,cmdtail.count),strlen(storect)>0?strlen(storect)-1:0); MEM_BlockWrite(pt+offsetof(sPSP,cmdtail.buffer),storect,strlen(storect)); }