void INT10_SetupVESA(void) { /* Put the mode list somewhere in memory */ Bitu i; i=0; int10.rom.vesa_modes=RealMake(0xc000,int10.rom.used); //TODO Maybe add normal vga modes too, but only seems to complicate things while (ModeList_VGA[i].mode!=0xffff) { bool canuse_mode=false; if (!svga.accepts_mode) canuse_mode=true; else { if (svga.accepts_mode(ModeList_VGA[i].mode)) canuse_mode=true; } if (ModeList_VGA[i].mode>=0x100 && canuse_mode) { if ((!int10.vesa_oldvbe) || (ModeList_VGA[i].mode<0x120)) { phys_writew(PhysMake(0xc000,int10.rom.used),ModeList_VGA[i].mode); int10.rom.used+=2; } } i++; } phys_writew(PhysMake(0xc000,int10.rom.used),0xffff); int10.rom.used+=2; int10.rom.oemstring=RealMake(0xc000,int10.rom.used); Bitu len=(Bitu)(strlen(string_oem)+1); for (i=0;i<len;i++) { phys_writeb(0xc0000+int10.rom.used++,string_oem[i]); } switch (svgaCard) { case SVGA_S3Trio: break; } callback.setwindow=CALLBACK_Allocate(); callback.pmPalette=CALLBACK_Allocate(); callback.pmStart=CALLBACK_Allocate(); CALLBACK_Setup(callback.setwindow,VESA_SetWindow,CB_RETF, "VESA Real Set Window"); /* Prepare the pmode interface */ int10.rom.pmode_interface=RealMake(0xc000,int10.rom.used); int10.rom.used += 8; //Skip the byte later used for offsets /* PM Set Window call */ int10.rom.pmode_interface_window = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 0, int10.rom.pmode_interface_window ); callback.pmWindow=CALLBACK_Allocate(); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmWindow, VESA_PMSetWindow, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Window"); /* PM Set start call */ int10.rom.pmode_interface_start = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 2, int10.rom.pmode_interface_start); callback.pmStart=CALLBACK_Allocate(); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmStart, VESA_PMSetStart, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Start"); /* PM Set Palette call */ int10.rom.pmode_interface_palette = int10.rom.used - RealOff( int10.rom.pmode_interface ); phys_writew( Real2Phys(int10.rom.pmode_interface) + 4, int10.rom.pmode_interface_palette); callback.pmPalette=CALLBACK_Allocate(); int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmPalette, VESA_PMSetPalette, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Palette"); /* Finalize the size and clear the required ports pointer */ phys_writew( Real2Phys(int10.rom.pmode_interface) + 6, 0); int10.rom.pmode_interface_size=int10.rom.used - RealOff( int10.rom.pmode_interface ); }
void fill_smth(void) { Bit8u *dst; Bit32u i; dst = MemBase + PhysMake(datseg, 0x78da); for (i = 104; i > 0; i--, dst += 4) host_writed(dst, 0x7fff7fff); dst = MemBase + PhysMake(datseg, 0x7a7a); for (i = 104; i > 0; i--, dst += 4) host_writed(dst, 0x80018001); }
Program::Program() { /* Find the command line and setup the PSP */ psp = new DOS_PSP(dos.psp()); /* Scan environment for filename */ PhysPt envscan=PhysMake(psp->GetEnvironment(),0); while (mem_readb(envscan)) envscan+=mem_strlen(envscan)+1; envscan+=3; CommandTail tail; MEM_BlockRead(PhysMake(dos.psp(),128),&tail,128); if (tail.count<127) tail.buffer[tail.count]=0; else tail.buffer[126]=0; char filename[256+1]; MEM_StrCopy(envscan,filename,256); cmd = new CommandLine(filename,tail.buffer); }
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; }
static Bitu PROGRAMS_Handler(void) { /* This sets up everything for a program start up call */ Bitu size=sizeof(Bit8u); Bit8u index; /* Read the index from program code in memory */ PhysPt reader=PhysMake(dos.psp(),256+sizeof(exe_block)); HostPt writer=(HostPt)&index; for (;size>0;size--) *writer++=mem_readb(reader++); Program * new_program = NULL; if (index > internal_progs.size()) E_Exit("something is messing with the memory"); InternalProgramEntry *ipe = internal_progs[index]; if (ipe == NULL) E_Exit("Attempt to run internal program slot with nothing allocated"); if (ipe->main == NULL) return CBRET_NONE; PROGRAMS_Main * handler = internal_progs[index]->main; (*handler)(&new_program); try { /* "BOOT" can throw an exception (int(2)) */ new_program->Run(); delete new_program; } catch (...) { /* well if it happened, free the program anyway to avert memory leaks */ delete new_program; throw; /* pass it on */ } return CBRET_NONE; }
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 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 {
Bitu Program::GetEnvCount(void) { PhysPt env_read=PhysMake(psp->GetEnvironment(),0); Bitu num=0; while (mem_readb(env_read)!=0) { for (;mem_readb(env_read);env_read++) {}; env_read++; num++; } return num; }
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 bool LocateEnvironmentBlock(PhysPt &env_base,PhysPt &env_fence,Bitu env_seg) { if (env_seg == 0) { /* The DOS program might have freed it's environment block perhaps. */ return false; } DOS_MCB env_mcb(env_seg-1); /* read the environment block's MCB to determine how large it is */ env_base = PhysMake(env_seg,0); env_fence = env_base + (env_mcb.GetSize() << 4); return true; }
bool Program::GetEnvNum(Bitu num,std::string & result) { char env_string[1024+1]; PhysPt env_read=PhysMake(psp->GetEnvironment(),0); do { MEM_StrCopy(env_read,env_string,1024); if (!env_string[0]) break; if (!num) { result=env_string;return true;} env_read += (PhysPt)(strlen(env_string)+1); num--; } while (1); return false; }
static Bitu PROGRAMS_Handler(void) { /* This sets up everything for a program start up call */ Bitu size=sizeof(Bit8u); Bit8u index; /* Read the index from program code in memory */ PhysPt reader=PhysMake(dos.psp(),256+sizeof(exe_block)); HostPt writer=(HostPt)&index; for (;size>0;size--) *writer++=mem_readb(reader++); Program * new_program; if(index > internal_progs.size()) E_Exit("something is messing with the memory"); PROGRAMS_Main * handler = internal_progs[index]; (*handler)(&new_program); new_program->Run(); delete new_program; return CBRET_NONE; }
void SVGA_Setup_ParadisePVGA1A(void) { svga.write_p3cf = &write_p3cf_pvga1a; svga.read_p3cf = &read_p3cf_pvga1a; svga.set_video_mode = &FinishSetMode_PVGA1A; svga.determine_mode = &DetermineMode_PVGA1A; svga.set_clock = &SetClock_PVGA1A; svga.get_clock = &GetClock_PVGA1A; svga.accepts_mode = &AcceptsMode_PVGA1A; VGA_SetClock(0,CLK_25); VGA_SetClock(1,CLK_28); VGA_SetClock(2,32400); // could not find documentation VGA_SetClock(3,35900); // Adjust memory, default to 512K if (vga.vmemsize == 0) vga.vmemsize = 512*1024; if (vga.vmemsize < 512*1024) { vga.vmemsize = 256*1024; pvga1a.PR1 = 1<<6; } else if (vga.vmemsize > 512*1024) { vga.vmemsize = 1024*1024; pvga1a.PR1 = 3<<6; } else { pvga1a.PR1 = 2<<6; } // Paradise ROM signature PhysPt rom_base=PhysMake(0xc000,0); phys_writeb(rom_base+0x007d,'V'); phys_writeb(rom_base+0x007e,'G'); phys_writeb(rom_base+0x007f,'A'); phys_writeb(rom_base+0x0080,'='); IO_Write(0x3cf, 0x05); // Enable! }
void copy_3d_to_screen(void) { Bit8u *src, *t_src; PhysPt dst, t_dst; signed short i, j; src = Real2Host(ds_readd(0xb128)); dst = PhysMake(0xa000, 0x28f); i = 134; do { t_src = src; t_dst = dst; for (j = 52; j > 0; j--) { mem_writed_inline(t_dst, host_readd(t_src)); t_dst+=4; t_src+=4; } src += 320; dst += 320; i--; } while (i != 0); }
bool Program::GetEnvStr(const char * entry,std::string & result) { /* Walk through the internal environment and see for a match */ PhysPt env_read=PhysMake(psp->GetEnvironment(),0); char env_string[1024+1]; result.erase(); if (!entry[0]) return false; do { MEM_StrCopy(env_read,env_string,1024); if (!env_string[0]) return false; env_read += (PhysPt)(strlen(env_string)+1); char* equal = strchr(env_string,'='); if (!equal) continue; /* replace the = with \0 to get the length */ *equal = 0; if (strlen(env_string) != strlen(entry)) continue; if (strcasecmp(entry,env_string)!=0) continue; /* restore the = to get the original result */ *equal = '='; result = env_string; return true; } while (1); return false; }
void MOUSE_Init(Section* /*sec*/) { // Callback for mouse interrupt 0x33 call_int33=CALLBACK_Allocate(); // RealPt i33loc=RealMake(CB_SEG+1,(call_int33*CB_SIZE)-0x10); RealPt i33loc=RealMake(DOS_GetMemory(0x1)-1,0x10); CALLBACK_Setup(call_int33,&INT33_Handler,CB_MOUSE,Real2Phys(i33loc),"Mouse"); // Wasteland needs low(seg(int33))!=0 and low(ofs(int33))!=0 real_writed(0,0x33<<2,i33loc); call_mouse_bd=CALLBACK_Allocate(); CALLBACK_Setup(call_mouse_bd,&MOUSE_BD_Handler,CB_RETF8, PhysMake(RealSeg(i33loc),RealOff(i33loc)+2),"MouseBD"); // pseudocode for CB_MOUSE (including the special backdoor entry point): // jump near i33hd // callback MOUSE_BD_Handler // retf 8 // label i33hd: // callback INT33_Handler // iret // Callback for ps2 irq call_int74=CALLBACK_Allocate(); CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRQ12,"int 74"); // pseudocode for CB_IRQ12: // push ds // push es // pushad // sti // callback INT74_Handler // doesn't return here, but rather to CB_IRQ12_RET // (ps2 callback/user callback inbetween if requested) int74_ret_callback=CALLBACK_Allocate(); CALLBACK_Setup(int74_ret_callback,&MOUSE_UserInt_CB_Handler,CB_IRQ12_RET,"int 74 ret"); // pseudocode for CB_IRQ12_RET: // callback MOUSE_UserInt_CB_Handler // cli // mov al, 0x20 // out 0xa0, al // out 0x20, al // popad // pop es // pop ds // iret Bit8u hwvec=(MOUSE_IRQ>7)?(0x70+MOUSE_IRQ-8):(0x8+MOUSE_IRQ); RealSetVec(hwvec,CALLBACK_RealPointer(call_int74)); // Callback for ps2 user callback handling useps2callback = false; ps2callbackinit = false; call_ps2=CALLBACK_Allocate(); CALLBACK_Setup(call_ps2,&PS2_Handler,CB_RETF,"ps2 bios callback"); ps2_callback=CALLBACK_RealPointer(call_ps2); memset(&mouse,0,sizeof(mouse)); mouse.hidden = 1; //Hide mouse on startup mouse.timer_in_progress = false; mouse.mode = 0xFF; //Non existing mode mouse.sub_mask=0; mouse.sub_seg=0x6362; // magic value mouse.sub_ofs=0; Mouse_ResetHardware(); Mouse_Reset(); Mouse_SetSensitivity(50,50,50); }
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_InfoBlock::SetLocation(Bit16u segment) { seg = segment; pt=PhysMake(seg,0); /* Clear the initial Block */ for(Bitu i=0;i<sizeof(sDIB);i++) mem_writeb(pt+i,0xff); for(Bitu i=0;i<14;i++) mem_writeb(pt+i,0); sSave(sDIB,regCXfrom5e,(Bit16u)0); sSave(sDIB,countLRUcache,(Bit16u)0); sSave(sDIB,countLRUopens,(Bit16u)0); sSave(sDIB,protFCBs,(Bit16u)0); sSave(sDIB,specialCodeSeg,(Bit16u)0); sSave(sDIB,joindedDrives,(Bit8u)0); sSave(sDIB,lastdrive,(Bit8u)0x01);//increase this if you add drives to cds-chain sSave(sDIB,diskInfoBuffer,RealMake(segment,offsetof(sDIB,diskBufferHeadPt))); sSave(sDIB,setverPtr,(Bit32u)0); sSave(sDIB,a20FixOfs,(Bit16u)0); sSave(sDIB,pspLastIfHMA,(Bit16u)0); sSave(sDIB,blockDevices,(Bit8u)0); sSave(sDIB,bootDrive,(Bit8u)0); sSave(sDIB,useDwordMov,(Bit8u)1); sSave(sDIB,extendedSize,(Bit16u)(MEM_TotalPages()*4-1024)); sSave(sDIB,magicWord,(Bit16u)0x0001); // dos5+ sSave(sDIB,sharingCount,(Bit16u)0); sSave(sDIB,sharingDelay,(Bit16u)0); sSave(sDIB,ptrCONinput,(Bit16u)0); // no unread input available sSave(sDIB,maxSectorLength,(Bit16u)0x200); sSave(sDIB,dirtyDiskBuffers,(Bit16u)0); sSave(sDIB,lookaheadBufPt,(Bit32u)0); sSave(sDIB,lookaheadBufNumber,(Bit16u)0); sSave(sDIB,bufferLocation,(Bit8u)0); // buffer in base memory, no workspace sSave(sDIB,workspaceBuffer,(Bit32u)0); sSave(sDIB,minMemForExec,(Bit16u)0); sSave(sDIB,memAllocScanStart,(Bit16u)DOS_MEM_START); sSave(sDIB,startOfUMBChain,(Bit16u)0xffff); sSave(sDIB,chainingUMB,(Bit8u)0); sSave(sDIB,nulNextDriver,(Bit32u)0xffffffff); sSave(sDIB,nulAttributes,(Bit16u)0x8004); sSave(sDIB,nulStrategy,(Bit32u)0x00000000); sSave(sDIB,nulString[0],(Bit8u)0x4e); sSave(sDIB,nulString[1],(Bit8u)0x55); sSave(sDIB,nulString[2],(Bit8u)0x4c); sSave(sDIB,nulString[3],(Bit8u)0x20); sSave(sDIB,nulString[4],(Bit8u)0x20); sSave(sDIB,nulString[5],(Bit8u)0x20); sSave(sDIB,nulString[6],(Bit8u)0x20); sSave(sDIB,nulString[7],(Bit8u)0x20); /* Create a fake SFT, so programs think there are 100 file handles */ Bit16u sftOffset=offsetof(sDIB,firstFileTable)+0xa2; sSave(sDIB,firstFileTable,RealMake(segment,sftOffset)); real_writed(segment,sftOffset+0x00,RealMake(segment+0x26,0)); //Next File Table real_writew(segment,sftOffset+0x04,100); //File Table supports 100 files real_writed(segment+0x26,0x00,0xffffffff); //Last File Table real_writew(segment+0x26,0x04,100); //File Table supports 100 files }
//Initializer - is startet if executed file is SCHICKM.EXE/BLADEM.EXE or GEN.EXE //Returns true if the desired programm is started bool init_schick(char *name, unsigned short reloc, unsigned short _cs, unsigned short ip) { char borsig[] = "Borland C++ - Copyright 1991 Borland Intl."; char fname[81]; int ver; schick_get_fname(fname, name); if (strcmp(fname, "schickm.exe") && strcmp(fname, "bladem.exe") && strcmp(fname, "gen.exe")) return false; /* Check CS:IP in the EXE-Header are 0:0 * and the first executed instruction is mov dx,i16 */ if (_cs != 0 || ip != 0 || real_readb(reloc+_cs, ip) != 0xba) return false; /* Show CS:IP on the virtual machine and the pointer to 0:0 */ D1_TRAC("\n\nCS:IP 0x%x:0x%x\tMemBase: %p\n", reloc, ip, MemBase); /* Read and show the Datasegment */ datseg_bak = datseg; datseg = real_readw(reloc, ip+1); p_datseg_bak = p_datseg; p_datseg = MemBase + PhysMake(datseg, 0); D1_TRAC("Dseg: 0x%X\n", datseg); /* Check if the start of the Datasegment is Borland C++ */ if (host_readd(p_datseg) != 0 || strcmp((char*)MemBase+PhysMake(datseg, 4), borsig)) { D1_ERR("Kein Borland C++ Kompilat!\n"); return false; } /* check for the game program */ if (!strcmp(fname, "schickm.exe") || !strcmp(fname, "bladem.exe")) { reloc_game = reloc; ver = schick_get_version((char*)p_datseg); if (ver == 0) { D1_ERR("Unbekannte Version von DSA1\n"); return false; } D1_INFO("\nDSA1 Schicksalsklinge gefunden V%d.%02d_%s\n", ver / 100, ver % 100, schick_is_en() ? "en": "de"); /* enable profiler only on this version */ if (ver == 302 && !schick_is_en()) { D1_INFO("Starte Profiler\n"); /* enable status comperator */ schick_status_init(); schick_timer_enable(); schick++; } } /* check for the character generation program */ if (!strcmp(fname, "gen.exe")) { reloc_gen = reloc; ver = schick_gen_get_version((char*)p_datseg); if (ver == 0) { D1_ERR("Unbekannte Version von DSA1 Generierung\n"); return false; } D1_INFO("DSA1 Generierung gefunden V%d.%02d_%s\n", ver / 100, ver % 100, schick_gen_is_en() ? "en": "de"); /* This happens only gen is started from the game. We have to save some values. */ if (!fromgame && schick && !gen) { if (schick_get_version((char*)p_datseg_bak) == 302 && !schick_is_en()) { schick_status_disable(); schick_timer_disable(); } schick--; fromgame++; D1_INFO("Gen gestartet\nreloc (0x%x)\n", (unsigned int)reloc_gen); } /* enable profiler only on this version */ if (ver == 105 && !schick_is_en()) { D1_INFO("Starte Profiler\n"); gen++; } } return true; }
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; }
Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change) { char * string_begin=string; Bit8u ret=0; if (!(parser & PARSE_DFLT_DRIVE)) { // default drive forced, this intentionally invalidates an extended FCB mem_writeb(PhysMake(seg,offset),0); } DOS_FCB fcb(seg,offset,false); // always a non-extended FCB bool hasdrive,hasname,hasext,finished; hasdrive=hasname=hasext=finished=false; Bitu index=0; Bit8u fill=' '; /* First get the old data from the fcb */ #ifdef _MSC_VER #pragma pack (1) #endif union { struct { char drive[2]; char name[9]; char ext[4]; } GCC_ATTRIBUTE (packed) part; char full[DOS_FCBNAME]; } fcb_name; #ifdef _MSC_VER #pragma pack() #endif /* Get the old information from the previous fcb */ fcb.GetName(fcb_name.full); fcb_name.part.drive[0]-='A'-1;fcb_name.part.drive[1]=0; fcb_name.part.name[8]=0;fcb_name.part.ext[3]=0; /* Strip of the leading sepetaror */ if((parser & PARSE_SEP_STOP) && *string) { //ignore leading seperator char sep[] = FCB_SEP;char a[2]; a[0]= *string;a[1]='\0'; if (strcspn(a,sep)==0) string++; } /* strip leading spaces */ while((*string==' ')||(*string=='\t')) string++; /* Check for a drive */ if (string[1]==':') { fcb_name.part.drive[0]=0; hasdrive=true; if (isalpha(string[0]) && Drives[toupper(string[0])-'A']) { fcb_name.part.drive[0]=(char)(toupper(string[0])-'A'+1); } else ret=0xff; string+=2; } /* Special checks for . and .. */ if (string[0]=='.') { string++; if (!string[0]) { hasname=true; ret=PARSE_RET_NOWILD; strcpy(fcb_name.part.name,". "); goto savefcb; } if (string[1]=='.' && !string[1]) { string++; hasname=true; ret=PARSE_RET_NOWILD; strcpy(fcb_name.part.name,".. "); goto savefcb; } goto checkext; } /* Copy the name */ hasname=true;finished=false;fill=' ';index=0; while (index<8) { if (!finished) { if (string[0]=='*') {fill='?';fcb_name.part.name[index]='?';if (!ret) ret=1;finished=true;} else if (string[0]=='?') {fcb_name.part.name[index]='?';if (!ret) ret=1;} else if (isvalid(string[0])) {fcb_name.part.name[index]=(char)(toupper(string[0]));} else { finished=true;continue; } string++; } else { fcb_name.part.name[index]=fill; } index++; } if (!(string[0]=='.')) goto savefcb; string++; checkext: /* Copy the extension */ hasext=true;finished=false;fill=' ';index=0; while (index<3) { if (!finished) { if (string[0]=='*') {fill='?';fcb_name.part.ext[index]='?';finished=true;} else if (string[0]=='?') {fcb_name.part.ext[index]='?';if (!ret) ret=1;} else if (isvalid(string[0])) {fcb_name.part.ext[index]=(char)(toupper(string[0]));} else { finished=true;continue; } string++; } else { fcb_name.part.ext[index]=fill; } index++; } savefcb: if (!hasdrive & !(parser & PARSE_DFLT_DRIVE)) fcb_name.part.drive[0] = 0; if (!hasname & !(parser & PARSE_BLNK_FNAME)) strcpy(fcb_name.part.name," "); if (!hasext & !(parser & PARSE_BLNK_FEXT)) strcpy(fcb_name.part.ext," "); fcb.SetName(fcb_name.part.drive[0],fcb_name.part.name,fcb_name.part.ext); *change=(Bit8u)(string-string_begin); return ret; }
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; }
Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change) { char * string_begin=string; Bit8u ret=0; if (!(parser & PARSE_DFLT_DRIVE)) { // default drive forced, this intentionally invalidates an extended FCB mem_writeb(PhysMake(seg,offset),0); } DOS_FCB fcb(seg,offset,false); // always a non-extended FCB bool hasdrive,hasname,hasext,finished; hasdrive=hasname=hasext=finished=false; Bitu index=0; Bit8u fill=' '; /* First get the old data from the fcb */ #ifdef _MSC_VER #pragma pack (1) #endif union { struct { char drive[2]; char name[9]; char ext[4]; } GCC_ATTRIBUTE (packed) part; char full[DOS_FCBNAME]; } fcb_name; #ifdef _MSC_VER #pragma pack() #endif /* Get the old information from the previous fcb */ fcb.GetName(fcb_name.full); fcb_name.part.drive[0]-='A'-1; fcb_name.part.drive[1]=0; fcb_name.part.name[8]=0; fcb_name.part.ext[3]=0; /* strip leading spaces */ while((*string==' ')||(*string=='\t')) string++; /* Strip of the leading separator */ if((parser & PARSE_SEP_STOP) && *string) { char sep[] = FCB_SEP; char a[2]; a[0] = *string; a[1] = '\0'; if (strcspn(a,sep) == 0) string++; } /* Skip following spaces as well */ while((*string==' ')||(*string=='\t')) string++; /* Check for a drive */ if (string[1]==':') { unsigned char d = *reinterpret_cast<unsigned char*>(&string[0]); if (!isvalid(toupper(d))) { string += 2; //TODO check (for ret value) goto savefcb; } fcb_name.part.drive[0]=0; hasdrive=true; if (isalpha(d) && Drives[toupper(d)-'A']) { //Floppies under dos always exist, but don't bother with that at this level ; //THIS* was here } else ret=0xff; fcb_name.part.drive[0]=DOS_ToUpper(string[0])-'A'+1; //Always do THIS* and continue parsing, just return the right code string+=2; } /* Check for extension only file names */ if (string[0] == '.') { string++; goto checkext; } /* do nothing if not a valid name */ if(!isvalid(string[0])) goto savefcb; hasname=true; finished=false; fill=' '; index=0; /* Copy the name */ while (true) { unsigned char nc = *reinterpret_cast<unsigned char*>(&string[0]); char ncs = (char)toupper(nc); //Should use DOS_ToUpper, but then more calls need to be changed. if (ncs == '*') { //Handle * fill = '?'; ncs = '?'; } if (ncs == '?' && !ret && index < 8) ret = 1; //Don't override bad drive if (!isvalid(ncs)) { //Fill up the name. while(index < 8) fcb_name.part.name[index++] = fill; break; } if (index < 8) { fcb_name.part.name[index++] = (fill == '?')?fill:ncs; } string++; } if (!(string[0]=='.')) goto savefcb; string++; checkext: /* Copy the extension */ hasext=true; finished=false; fill=' '; index=0; while (true) { unsigned char nc = *reinterpret_cast<unsigned char*>(&string[0]); char ncs = (char)toupper(nc); if (ncs == '*') { //Handle * fill = '?'; ncs = '?'; } if (ncs == '?' && !ret && index < 3) ret = 1; if (!isvalid(ncs)) { //Fill up the name. while(index < 3) fcb_name.part.ext[index++] = fill; break; } if (index < 3) { fcb_name.part.ext[index++] = (fill=='?')?fill:ncs; } string++; } savefcb: if (!hasdrive & !(parser & PARSE_DFLT_DRIVE)) fcb_name.part.drive[0] = 0; if (!hasname & !(parser & PARSE_BLNK_FNAME)) strcpy(fcb_name.part.name," "); if (!hasext & !(parser & PARSE_BLNK_FEXT)) strcpy(fcb_name.part.ext," "); fcb.SetName(fcb_name.part.drive[0],fcb_name.part.name,fcb_name.part.ext); fcb.ClearBlockRecsize(); //Undocumented bonus work. *change=(Bit8u)(string-string_begin); return ret; }
void DOS_PSP::SetFCB2(RealPt src) { if (src) MEM_BlockCopy(PhysMake(seg,offsetof(sPSP,fcb2)),Real2Phys(src),16); }
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; }