page ,160 title bios system initialization ; ;---------------------------------------------------------------------------- ; ; Modification history ; ; 26-Feb-1991 sudeepb Ported for NT DOSEm ;---------------------------------------------------------------------------- include version.inc ; set version build flags include biosseg.inc ; establish bios segment structure lf equ 10 cr equ 13 tab equ 9 have_install_cmd equ 00000001b ; config.sys has install= commands has_installed equ 00000010b ; sysinit_base installed. default_filenum = 8 break macro ; dummy empty macro endm include sysvar.inc include pdb.inc ; M020 include syscall.inc include doscntry.inc include devsym.inc include devmark.inc include umb.inc include dossym.inc include dossvc.inc include cmdsvc.inc include softpc.inc stacksw equ true ;include switchable hardware stacks if ibmjapver noexec equ true else noexec equ false endif ; external variable defined in ibmbio module for multi-track multrk_on equ 10000000b ;user spcified mutitrack=on,or system turns ; it on after handling config.sys file as a ; default value,if multrk_flag = multrk_off1. multrk_off1 equ 00000000b ;initial value. no "multitrack=" command entered. multrk_off2 equ 00000001b ;user specified multitrack=off. Bios_Data segment extrn multrk_flag:word extrn keyrd_func:byte extrn keysts_func:byte Bios_Data ends ; end of multi-track definition. sysinitseg segment assume cs:sysinitseg,ds:nothing,es:nothing,ss:nothing extrn badopm:byte,crlfm:byte,badcom:byte,badmem:byte,badblock:byte extrn badsiz_pre:byte,badld_pre:byte extrn badstack:byte,badcountrycom:byte extrn badcountry:byte,insufmemory:byte extrn condev:byte,auxdev:byte,prndev:byte,commnd:byte,config:byte extrn cntry_drv:byte,cntry_root:byte,cntry_path:byte extrn memory_size:word extrn buffers:word extrn files:byte,num_cds:byte extrn dosinfo:dword extrn fcbs:byte,keep:byte extrn confbot:word,alloclim:word,command_line:byte extrn zero:byte,sepchr:byte extrn count:word,chrptr:word,cntryfilehandle:word extrn memlo:word,memhi:word,prmblk:word,ldoff:word extrn packet:byte,unitcount:byte,break_addr:dword extrn bpb_addr:dword,drivenumber:byte,sysi_country:dword extrn config_size:word extrn install_flag:word extrn badorder:byte extrn errorcmd:byte extrn linecount:word extrn showcount:byte extrn buffer_linenum:word extrn h_buffers:word extrn badparm:byte extrn configmsgflag:word extrn org_count:word extrn multi_pass_id:byte extrn mem_err:near,setdoscountryinfo:near extrn pararound:near,tempcds:near extrn set_country_path:near,move_asciiz:near,delim:near extrn badfil:near,round:near extrn do_install_exec:near extrn setdevmark:near extrn print:near,organize:near,newline:near extrn parseline:near extrn badload:near,calldev:near,prnerr:near extrn runhigh:byte extrn IsXMSLoaded:near extrn TryToMovDOSHi:near ifdef DBCS extrn testkanj:near endif extrn bEchoConfig:byte ; NTVDM flag off\on echo of cfg processing if stacksw ; internal stack parameters entrysize equ 8 mincount equ 8 defaultcount equ 9 maxcount equ 64 minsize equ 32 defaultsize equ 128 maxsize equ 512 DOS_FLAG_OFFSET equ 86h extrn stack_count:word extrn stack_size:word extrn stack_addr:dword endif public doconf public getchr public multi_pass public AllocUMB public AllocUMBLow ; NTVDM public multdeviceflag multdeviceflag db 0 public devmark_addr devmark_addr dw ? ;segment address for devmark. public setdevmarkflag setdevmarkflag db 0 ;flag used for devmark ems_stub_installed db 0 IFDEF DONT_LOAD_OS2_DD ; M045 Os2ChkBuf DD 0 ; Tmp read buffer ENDIF ; M045 badparm_ptr label dword badparm_off dw 0 badparm_seg dw 0 ;****************************************************************************** ;take care of config.sys file. ;system parser data and code. ;****************************************************************************** ;******************************************************************* ; parser options set for msbio sysconf module ;******************************************************************* ; ;**** default assemble swiches definition ************************** ifndef farsw farsw equ 0 ; near call expected endif ifndef datesw datesw equ 0 ; check date format endif ifndef timesw timesw equ 0 ; check time format endif ifndef filesw filesw equ 1 ; check file specification endif ifndef capsw capsw equ 0 ; perform caps if specified endif ifndef cmpxsw cmpxsw equ 0 ; check complex list endif ifndef numsw numsw equ 1 ; check numeric value endif ifndef keysw keysw equ 0 ; support keywords endif ifndef swsw swsw equ 1 ; support switches endif ifndef val1sw val1sw equ 1 ; support value definition 1 endif ifndef val2sw val2sw equ 0 ; support value definition 2 endif ifndef val3sw val3sw equ 1 ; support value definition 3 endif ifndef drvsw drvsw equ 1 ; support drive only format endif ifndef qussw qussw equ 0 ; support quoted string format endif include parse.asm ;together with psdata.inc ;control block definitions for parser. ;--------------------------------------------------- ; buffer = [n | n,m] {/e} p_parms struc dw ? db 1 ; an extra delimiter list db 1 ; length is 1 db ';' ; delimiter p_parms ends p_pos struc dw ? ; numeric value?? dw ? ; function dw ? ; result value buffer ; note: by defining result_val before this structure, we could remove ; the "result_val" from every structure invocation dw ? ; value list db 0 ; no switches/keywords p_pos ends p_range struc db 1 ; range definition db 1 ; 1 definition of range db 1 ; item tag for this range dd ? ; numeric min dd ? ; numeric max p_range ends buf_parms p_parms buf_parmsx dw 201h,buf_pos1,buf_pos2 ; min 1, max 2 positionals db 1 ; one switch dw sw_x_ctrl db 0 ; no keywords buf_pos1 p_pos <8000h,0,result_val,buf_range_1> ; numeric buf_range_1 p_range <,,,1,99> ; M050 buf_pos2 p_pos <8001h,0,result_val,buf_range_2> ; optional num. buf_range_2 p_range <,,,0,8> sw_x_ctrl p_pos <0,0,result_val,noval,1> ; followed by one switch switch_x db '/X',0 ; M016 p_buffers dw 0 ; local variables p_h_buffers dw 0 p_buffer_slash_x db 0 ;common definitions ------------ noval db 0 result_val label byte db ? ; type returned db ? ; item tag returned dw ? ; es:offset of the switch defined rv_byte label byte rv_dword dd ? ; value if number,or seg:offset to string. ;------------------------------- ; break = [ on | off ] brk_parms p_parms brk_parmsx dw 101h,brk_pos ; min,max = 1 positional db 0 ; no switches db 0 ; no keywords brk_pos p_pos <2000h,0,result_val,on_off_string> ; simple string on_off_string label byte db 3 ; signals that there is a string choice db 0 ; no range definition db 0 ; no numeric values choice db 2 ; 2 strings for choice db 1 ; the 1st string tag dw on_string db 2 ; the 2nd string tag dw off_string on_string db "ON",0 off_string db "OFF",0 p_ctrl_break db 0 ; local variable ;-------------------------------- ; country = n {m {path}} ; or ; country = n,,path cntry_parms p_parms cntry_parmsx dw 301h,cntry_pos1,cntry_pos2,cntry_pos3 ; min 1, max 3 pos. db 0 ; no switches db 0 ; no keywords cntry_pos1 p_pos <8000h,0,result_val,cc_range> ; numeric value cc_range p_range <,,,1,999> cntry_pos2 p_pos <8001h,0,result_val,cc_range> ; optional num. cntry_pos3 p_pos <201h,0,result_val,noval> ; optional filespec p_cntry_code dw 0 ; local variable p_code_page dw 0 ; local variable ;-------------------------------- ; files = n files_parms p_parms files_parmsx dw 101h,files_pos ; min,max 1 positional db 0 ; no switches db 0 ; no keywords files_pos p_pos <8000h,0,result_val,files_range,0> ; numeric value files_range p_range <,,,8,255> p_files db 0 ; local variable ;------------------------------- ; fcbs = n,m fcbs_parms p_parms fcbs_parmsx dw 201h,fcbs_pos_1,fcbs_pos_2 ; min,max = 2 positional db 0 ; no switches db 0 ; no keywords fcbs_pos_1 p_pos <8000h,0,result_val,fcbs_range> ; numeric value fcbs_range p_range <,,,1,255> fcbs_pos_2 p_pos <8000h,0,result_val,fcbs_keep_range> ; numeric value fcbs_keep_range p_range <,,,0,255> p_fcbs db 0 ; local variable p_keep db 0 ; local variable ;------------------------------- ; lastdrive = x ldrv_parms p_parms ldrv_parmsx dw 101h,ldrv_pos ; min,max = 1 positional db 0 ; no switches db 0 ; no keywords ldrv_pos p_pos <110h,10h,result_val,noval> ; drive only, ignore colon ; remove colon at end p_ldrv db 0 ; local variable ;------------------------------- ; stacks = n,m stks_parms p_parms stks_parmsx dw 202h,stks_pos_1,stks_pos_2 ; min,max = 2 positionals db 0 ; no switches db 0 ; no keywords stks_pos_1 p_pos <8000h,0,result_val,stks_range> ; numeric value stks_range p_range <,,,0,64> stks_pos_2 p_pos <8000h,0,result_val,stk_size_range> ; numeric value stk_size_range p_range <,,,0,512> p_stack_count dw 0 ; local variable p_stack_size dw 0 ; local variable ;------------------------------- ; multitrack = [ on | off ] mtrk_parms p_parms mtrk_parmsx dw 101h,mtrk_pos ; min,max = 1 positional db 0 ; no switches db 0 ; no keywords mtrk_pos p_pos <2000h,0,result_val,on_off_string> ; simple string p_mtrk db 0 ; local variable ;------------------------------- ; switches=/k swit_parms p_parms swit_parmsx dw 0 ; no positionals db 3 ; 2 switches for now. M059 M063 dw swit_k_ctrl ; /k control dw swit_t_ctrl ; /t control M059 dw swit_w_ctrl ; /w control M063 db 0 ; no keywords swit_k_ctrl p_pos <0,0,result_val,noval,1> ; switch string follows swit_k db '/K',0 swit_t_ctrl p_pos <0,0,result_val,noval,1> ; switch string follows M059 swit_t db '/T',0 ; M059 swit_w_ctrl p_pos <0,0,result_val,noval,1> ; switch string follows M063 swit_w db '/W',0 ; M063 p_swit_k db 0 ; local variable p_swit_t db 0 ; local variable M059 p_swit_w db 0 ; local variable M063 ;------------------------------- ; DOS = [ high | low ] dos_parms p_parms dos_parmsx db 1 ; min parameters db 2 ; max parameters dw dos_pos ; dw dos_pos ; db 0 ; no switches db 0 ; no keywords dos_pos p_pos <2000h,0,result_val,dos_strings> ; simple string p_pos <2000h,0,result_val,dos_strings> ; simple string dos_strings label byte db 3 ; signals that there is a string choice db 0 ; no range definition db 0 ; no numeric values choice db 4 ; 4 strings for choice db 1 ; the 1st string tag dw hi_string db 2 ; the 2nd string tag dw lo_string db 3 dw umb_string db 4 dw noumb_string hi_string db "HIGH",0 lo_string db "LOW",0 umb_string db "UMB",0 noumb_string db "NOUMB",0 p_dos_hi db 0 ; local variable ; BUGBUG : I dont know whether PARSER uses ; this variable or not ;****************************************************************************** public DevEntry DevSize dw ? ; size of the device driver being loaded(paras) DevLoadAddr dw ? ; Mem addr where the device driver is 2 b loaded DevLoadEnd dw ? ; MaxAddr to which device can be loaded DevEntry dd ? ; Entry point to the device driver DevBrkAddr dd ? ; Break address of the device driver ; DevUMB db 0 ; byte indicating whether to load DDs in UMBs DevUMBAddr dw 0 ; cuurent UMB used fro loading devices (paras) DevUMBSize dw 0 ; Size of the current UMB being used (paras) DevUMBFree dw 0 ; Start of free are in the current UMB (paras) ; DevXMSAddr dd ? ; DevExecAddr dw ? ; Device load address parameter to Exec call DevExecReloc dw ? ; Device load relocation factor ; DeviceHi db 0 ; Flag indicating whther the current device ; is being loaded into UMB DevSizeOption dw ? ; SIZE= option ; Int12Lied db 0 ; did we trap int 12 ? OldInt12Mem dw ? ; value in 40:13h (int 12 ram) ThreeComName db 'PROTMAN$' ; 3Com Device name ; FirstUMBLinked db 0 DevDOSData dw ? ; segment of DOS Data DevCmdLine dd ? ; Current Command line DevSavedDelim db ? ; The delimiter which was replaced with null ; to use the file name in the command line ; ;---------------------------------------------------------------------------- ; ; procedure : doconf ; ; Config file is parsed intitially with this routine. For the ; Subsequent passes 'multi_pass' entry is used . ; ;---------------------------------------------------------------------------- ; doconf proc near push cs pop ds assume ds:sysinitseg mov ax,(char_oper shl 8) ;get switch character int 21h mov [command_line+1],dl ; set in default command line mov dx,offset config ;now pointing to file description mov ax,open shl 8 ;open file "config.sys" stc ;in case of int 24 int 21h ;function request jnc noprob ; brif opened okay mov multi_pass_id,11 ; set it to unreasonable number ret noprob: ;get file size (note < 64k!!) mov bx,ax xor cx,cx xor dx,dx mov ax,(lseek shl 8) or 2 int 21h mov [count],ax xor dx,dx mov ax,lseek shl 8 ;reset pointer to beginning of file int 21h mov dx,[confbot] ;use current confbot value mov ax,[count] mov [config_size],ax ;save the size of config.sys file. call pararound sub dx,ax sub dx,11h ;room for header mov [confbot],dx ; config starts here. new conbot value. call tempcds ; finally get cds to "safe" location assume ds:nothing,es:nothing mov dx,[confbot] mov ds,dx mov es,dx xor dx,dx mov cx,[count] mov ah,read stc ;in case of int 24 int 21h ;function request pushf ; find the eof mark in the file. if present,then trim length. push ax push di push cx mov al,1ah ; eof mark mov di,dx ; point ro buffer jcxz puteol ; no chars repnz scasb ; find end jnz puteol ; none found and count exahusted ; we found a 1a. back up dec di ; backup past 1a ; just for the halibut,stick in an extra eol puteol: mov al,cr stosb mov al,lf stosb sub di,dx ; difference moved mov count,di ; new count pop cx pop di pop ax push cs pop ds assume ds:sysinitseg push ax mov ah,close int 21h pop ax popf jc conferr ;if not we've got a problem cmp cx,ax jz getcom ;couldn't read the file conferr: mov dx,offset config ;want to print config error call badfil endconv: ret ; ;---------------------------------------------------------------------------- ; ; entry : multi_pass ; ; called to execute device=,install= commands ; ;---------------------------------------------------------------------------- ; multi_pass: push cs pop ds cmp multi_pass_id,10 jae endconv ; do nothing. just return. push confbot pop es ; es -> confbot mov si,org_count mov count,si ; set count xor si,si mov chrptr,si ; reset chrptr,linecount mov linecount,si call getchr jmp short conflp getcom: call organize ;organize the file call getchr conflp: jc endconv ;*** call reset_dos_version ; still need to reset version even ibmdos handles this through ;*** ; function 4bh call,since ibmdos does not know when load/overlay call finishes. inc linecount ; increase linecount. mov multdeviceflag,0 ; reset multdeviceflag. mov setdevmarkflag,0 ; reset setdevmarkflag. cmp al,lf ; linefeed? je blank_line ; then ignore this line. mov ah,al call getchr jnc tryi cmp multi_pass_id,2 jae endconv ;do not show badop again for multi_pass. jmp badop coff: push cs pop ds call newline jmp conflp blank_line: call getchr jmp conflp coff_p: push cs pop ds ;to handle install= commands,we are going to use multi-pass. ;the first pass handles the other commands and only set install_flag when ;it finds any install command. the second pass will only handle the ;install= command. ;------------------------------------------------------------------------------ ;install command ;------------------------------------------------------------------------------ tryi: cmp multi_pass_id,0 ; the initial pass for DOS=HI je multi_try_doshi cmp multi_pass_id,2 ; the second pass was for ifs= je coff ; now it is NOPs ; This pass can be made use of if ; we want do some config.sys process ; after device drivers are loaded ; and before install= commands ; are processed cmp multi_pass_id,3 ; the third pass for install= ? je multi_try_i cmp ah, 'H' je coff cmp ah, 'E' je coff cmp ah,'I' ; install= command? jne tryb ; the first pass is for normal operation. or install_flag,have_install_cmd ; set the flag jmp coff ; and handles the next command multi_try_i: cmp ah,'I' ; install= command? jne multi_pass_filter ; no. ignore this. call do_install_exec ;install it. jmp coff ;to handle next install= command. multi_pass_filter: cmp ah,'Y' ; comment? je multi_pass_adjust cmp ah,'Z' ; bad command? je multi_pass_adjust cmp ah,'0' ; rem? jne coff ; ignore the rest of the commands. multi_pass_adjust: ; these commands need to dec chrptr ; adjust chrptr,count inc count ; for newline proc. multi_pass_coff: jmp coff ; to handle next install= commands. ;---------------------------------------------------------------------------- ; DOS=HIGH/LOW command ; ; EchoConfig command turns on con echo for config processing ; NTVDM 14-Aug-1992 Jonle ;---------------------------------------------------------------------------- ; multi_try_doshi: cmp ah, 'H' je it_is_h cmp ah, 'E' jne multi_pass_filter mov cs:bEchoConfig, ah ; init console CMDSVC SVC_CMDINITCONSOLE jmp coff it_is_h: ; M003 - removed initing DevUMB ; & runhigh mov di,offset dos_parms xor cx,cx mov dx,cx h_do_parse: call sysinit_parse jnc h_parse_ok ; parse error h_badparm: call badparm_p ; show message and end the serach loop. jmp short h_end h_parse_ok: cmp ax,$p_rc_eol ; end of line? jz h_end ; then end the $endloop call ProcDOS jmp short h_do_parse h_end: jmp coff ;------------------------------------------------------------------------------ ; buffer command ;------------------------------------------------------------------------------ ;******************************************************************************* ; * ; function: parse the parameters of buffers= command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; buffers set * ; buffer_slash_x flag set if /x option chosen. * ; h_buffers set if secondary buffer cache specified. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di points to buf_parms; /*parse control definition*/ * ; set dx,cx to 0; * ; reset buffer_slash_x; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; if (result_val.$p_synonym_ptr == slash_e) then /*not a switch * ; buffer_slash_x = 1 * ; else if (cx == 1) then /* first positional */ * ; buffers = result_val.$p_picked_val; * ; else h_buffers = result_val.$p_picked_val; * ; else {show error message;error exit} * ; }; * ; if (buffer_slash_x is off & buffers > 99) then show_error; * ; }; * ; * ;******************************************************************************* tryb: cmp ah,'B' jnz tryc ; NTVDM - buffers command is ignored ; 15-Aug-1992 Jonle jmp coff if 0 mov p_buffer_slash_x,0 mov di,offset buf_parms xor cx,cx mov dx,cx do7: call sysinit_parse jnc if7 ; parse error, call badparm_p ; and show messages and end the search loop. jmp short sr7 if7: cmp ax,$p_rc_eol ; end of line? jz en7 ; then jmp to $endloop for semantic check cmp result_val.$p_synonym_ptr,offset switch_x jnz if11 ; mov p_buffer_slash_x,1 ; set the flag M016 jmp short en11 if11: mov ax,word ptr result_val.$p_picked_val cmp cx,1 jnz if13 mov p_buffers,ax jmp short en11 if13: mov p_h_buffers,ax en11: jmp do7 en7: cmp p_buffers,99 jbe if18 ; cmp p_buffer_slash_x,0 ; M016 ; jnz if18 call badparm_p mov p_h_buffers,0 jmp short sr7 if18: mov ax,p_buffers ; we don't have any problem. mov buffers,ax ; now,let's set it really. mov ax,p_h_buffers mov h_buffers,ax ; mov al,p_buffer_slash_x ; M016 ; mov buffer_slash_x,al mov ax,linecount mov buffer_linenum,ax ; save the line number for the future use. sr7: jmp coff endif ;------------------------------------------------------------------------------ ; break command ;------------------------------------------------------------------------------ ;**************************************************************************** ; * ; function: parse the parameters of break = command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; turn the control-c check on or off. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di to brk_parms; * ; set dx,cx to 0; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; if (result_val.$p_item_tag == 1) then /*on */ * ; set p_ctrl_break,on; * ; else /*off */ * ; set p_ctrl_break,off; * ; else {show message;error_exit}; * ; }; * ; if (no error) then * ; dos function call to set ctrl_break check according to * ; }; * ; * ;**************************************************************************** tryc: cmp ah,'C' jnz trym mov di,offset brk_parms xor cx,cx mov dx,cx do22: call sysinit_parse jnc if22 ; parse error call badparm_p ; show message and end the serach loop. jmp short sr22 if22: cmp ax,$p_rc_eol ; end of line? jz en22 ; then end the $endloop cmp result_val.$p_item_tag,1 jnz if26 mov p_ctrl_break,1 ; turn it on jmp short en26 if26: mov p_ctrl_break,0 ; turn it off en26: jmp short do22 ; we actually set the ctrl break en22: mov ah,set_ctrl_c_trapping ; if we don't have any parse error. mov al,1 mov dl,p_ctrl_break int 21h sr22: jmp coff ;------------------------------------------------------------------------------ ; multitrack command ;------------------------------------------------------------------------------ ;****************************************************************************** ; * ; function: parse the parameters of multitrack= command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; turn multrk_flag on or off. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di to brk_parms; * ; set dx,cx to 0; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; if (result_val.$p_item_tag == 1) then /*on */ * ; set p_mtrk,on; * ; else /*off */ * ; set p_mtrk,off; * ; else {show message;error_exit}; * ; }; * ; if (no error) then * ; dos function call to set multrk_flag according to p_mtrk. * ; * ; }; * ; * ;****************************************************************************** trym: cmp ah,'M' jnz tryu mov di,offset mtrk_parms xor cx,cx mov dx,cx do31: call sysinit_parse jnc if31 ; parse error call badparm_p ; show message and end the serach loop. jmp short sr31 if31: cmp ax,$p_rc_eol ; end of line? jz en31 ; then end the $endloop cmp result_val.$p_item_tag,1 jnz if35 mov p_mtrk,1 ; turn it on temporarily. jmp short en35 if35: mov p_mtrk,0 ; turn it off temporarily. en35: jmp short do31 ; we actually set the multrk_flag here en31: push ds mov ax,Bios_Data mov ds,ax assume ds:Bios_Data cmp p_mtrk,0 jnz if39 mov multrk_flag,multrk_off2 ; 0001h jmp short en39 if39: mov multrk_flag,multrk_on ; 8000h en39: pop ds assume ds:sysinitseg sr31: jmp coff ; ;----------------------------------------------------------------------------- ; devicehigh command ;----------------------------------------------------------------------------- ; assume ds:nothing tryu: cmp ah, 'U' jne tryd mov badparm_off, si ; stash it there in case of an error mov badparm_seg, es call ParseSize ; process the size= option jnc @f call badparm_p jmp coff @@: push si push es @@: mov al, es:[si] cmp al, cr je @f cmp al, lf je @f call delim jz @f inc si jmp @b @@: mov DevSavedDelim, al ; Save the delimiter before replacing ; it with null mov byte ptr es:[si], 0 pop es pop si mov DeviceHi, 0 cmp DevUMB, 0 ; do we support UMBs je LoadDevice ; no, we don't mov DeviceHi, 1 jmp short LoadDevice ; ;------------------------------------------------------------------------------ ; device command ;------------------------------------------------------------------------------ assume ds:nothing tryd: cmp ah,'D' jz gotd jmp tryq gotd: mov DeviceHi, 0 ; not to be loaded in UMB ;M007 mov DevSizeOption, 0 mov DevSavedDelim, ' ' ; In case of DEVICE= the null has to ; be replaced with a ' ' LoadDevice: mov bx,cs ;device= or devicehigh= command. mov ds,bx mov word ptr [bpb_addr],si ; pass the command line to the dvice mov word ptr [bpb_addr+2],es mov word ptr DevCmdLine, si ; save it for ourself mov word ptr DevCmdLine+2, es call round call SizeDevice jc BadFile call InitDevLoad mov ax, DevLoadAddr add ax, DevSize jc NoMem cmp DevLoadEnd, ax jae LoadDev NoMem: jmp mem_err BadFile: cmp byte ptr es:[si], cr jne @f jmp badop @@: call badload jmp coff LoadDev: push es pop ds assume ds:nothing mov dx,si ;ds:dx points to file name if noexec les bx,dword ptr cs:[memlo] call ldfil ;load in the device driver else call ExecDev ; load device driver using exec call endif badldreset: push ds pop es ;es:si back to config.sys push cs pop ds ;ds back to sysinit jc BadFile goodld: push es push si ; ??? call RemoveNull push es push si push cs pop es ;NTVDM: block device drivers are not supported. ; Putup user warning popup for unsupported device driver ; 29-Sep-1992 Jonle ; push ds push si lds si, DevEntry ; peek the header attribute test word ptr ds:[si.sdevatt],devtyp ; IS block device driver? pop si pop ds jnz got_device_com_cont ; no! pop si ;clear the stack pop es mov ax, NOSUPPORT_DRIVER BOP BOP_NOSUPPORT jmp short erase_dev_do got_device_com_cont: call LieInt12Mem call UpdatePDB ; update the PSP:2 value M020 cmp cs:multdeviceflag, 0 ; Pass limit only for the 1st device ; driver in the file ; M027 jne skip_pass_limit ; ; M027 mov word ptr break_addr, 0 ; pass the limit to the DD mov bx, DevLoadEnd mov word ptr break_addr+2, bx skip_pass_limit: ; M027 mov bx,sdevstrat call calldev ; calldev (sdevstrat); mov bx,sdevint call calldev ; calldev (sdevint); call TrueInt12Mem mov ax, word ptr break_addr ; move break addr from the req packet mov word ptr DevBrkAddr, ax mov ax, word ptr break_addr+2 mov word ptr DevBrkAddr+2, ax assume ds:nothing cmp DevUMB, 0 jz @f call AllocUMB @@: ; ;------ If we are waiting to be moved into hma lets try it now !!! ; cmp runhigh, 0ffh jne @f call TryToMovDOSHi ; move DOS into HMA if reqd @@: pop si pop ds mov byte ptr [si],0 ; *p = 0; push cs pop ds jmp short was_device_com erase_dev_do: ; modified to show message "error in config.sys..." pop si pop es push cs pop ds ; test [setdevmarkflag],setbrkdone ;if already set_break is done, ; jnz skip1_resetmemhi ; then do not ; dec [memhi] ;adjust memhi by a paragrah of devmark. skip1_resetmemhi: cmp configmsgflag,0 je no_error_line_msg call error_line ; no "error in config.sys" msg for device driver. dcr d493 mov configmsgflag,0 ;set the default value again. no_error_line_msg: jmp coff ; ;---------------------------------------------------------------------------- ; was_device_com: mov ax,word ptr [DevBrkAddr+2] cmp ax,DevLoadEnd jbe breakok pop si pop es jmp BadFile breakok: lds si,DevEntry ;ds:si points to header les di,cs:[dosinfo] ;es:di point to dos info mov ax,ds:[si.sdevatt] ;ax Dev attributes ; ;------ lets deal with character devices, ; NTVDM: removed check for block drivers, jonle ; ischardev: or cs:[setdevmarkflag],for_devmark call DevSetBreak ; go ahead and alloc mem for device jc erase_dev_do ;device driver's init routine failed. test ax,iscin ;is it a console in? jz tryclk mov word ptr es:[di.sysi_con],si mov word ptr es:[di.sysi_con+2],ds tryclk: test ax,isclock ;is it a clock device? jz linkit mov word ptr es:[di+sysi_clock],si mov word ptr es:[di+sysi_clock+2],ds linkit: mov cx,word ptr es:[di.sysi_dev] ;dx:cx = head of list mov dx,word ptr es:[di.sysi_dev+2] mov word ptr es:[di.sysi_dev],si ;set head of list in dos mov word ptr es:[di.sysi_dev+2],ds mov ax,ds:[si] ;get pointer to next device mov word ptr cs:[DevEntry],ax ;and save it mov word ptr ds:[si],cx ;link in the driver mov word ptr ds:[si+2],dx enddev: pop si pop es inc ax ;ax = ffff (no more devs if yes)? jz coffj3 inc cs:multdeviceflag ; possibly multiple device driver. call DevBreak ; M009 jmp goodld ; otherwise pretend we loaded it in coffj3: mov cs:multdeviceflag,0 ; reset the flag call DevBreak jmp coff bad_bpb_size_sector: pop si pop es mov dx,offset badsiz_pre mov bx,offset crlfm call prnerr ; test [setdevmarkflag],setbrkdone ;if already set_break is done, ; jnz skip2_resetmemhi ; then do not ; dec [memhi] ;adjust memhi by a paragrah of devmark. skip2_resetmemhi: jmp coff ;------------------------------------------------------------------------------ ; country command ; the syntax is: ; country=country id {,codepage {,path}} ; country=country id {,,path} :default codepage id in dos ;------------------------------------------------------------------------------ tryq: cmp ah,'Q' jz tryq_cont jmp tryf tryq_cont: mov cntry_drv,0 ; reset the drive,path to default value. mov p_code_page,0 mov di,offset cntry_parms xor cx,cx mov dx,cx do52: call sysinit_parse jnc if52 ; parse error,check error code and call cntry_error ; show message and end the search loop. mov p_cntry_code,-1 ; signals that parse error. jmp short sr52 if52: cmp ax,$p_rc_eol ; end of line? jz sr52 ; then end the search loop cmp result_val.$p_type,$p_number ; numeric? jnz if56 mov ax,word ptr result_val.$p_picked_val cmp cx,1 jnz if57 mov p_cntry_code,ax jmp short en57 if57: mov p_code_page,ax en57: jmp short en56 ; path entered if56: push ds push es push si push di push cs pop es lds si,rv_dword ; move the path to known place. mov di,offset cntry_drv call move_asciiz pop di pop si pop es pop ds en56: jmp do52 sr52: cmp p_cntry_code,-1 ; had a parse error? jne tryq_open jmp coff tryqbad: ;"invalid country code or code page" stc mov dx,offset badcountry jmp tryqchkerr tryq_open: cmp cntry_drv,0 je tryq_def mov dx,offset cntry_drv jmp short tryq_openit tryq_def: mov dx,offset cntry_root tryq_openit: mov ax,3d00h ;open a file stc int 21h jc tryqfilebad ;open failure mov cs:cntryfilehandle,ax ;save file handle mov bx,ax mov ax,cs:p_cntry_code mov dx,cs:p_code_page ; now,ax=country id,bx=filehandle mov cx,cs:[memhi] add cx,384 ; need 6k buffer to handle country.sys ; M023 cmp cx,cs:[alloclim] ja tryqmemory ;cannot allocate the buffer for country.sys mov si,offset cntry_drv ;ds:si -> cntry_drv cmp byte ptr [si],0 ;default path? jne tryq_set_for_dos inc si inc si ;ds:si -> cntry_root tryq_set_for_dos: les di,cs:sysi_country ;es:di -> country info tab in dos push di ;save di add di,ccpath_countrysys call move_asciiz ;set the path to country.sys in dos. pop di ;es:di -> country info tab again. mov cx,cs:[memhi] mov ds,cx xor si,si ;ds:si -> 2k buffer to be used. call setdoscountryinfo ;now do the job!!! jnc tryqchkerr ;read error or could not find country,code page combination cmp cx,-1 ;could not find matching country_id,code page? je tryqbad ;then "invalid country code or code page" tryqfilebad: push cs pop es cmp cs:cntry_drv,0 ;is the default file used? je tryqdefbad mov si,offset cntry_drv jmp short tryqbadload tryqdefbad: ;default file has been used. mov si,offset cntry_root ;es:si -> \country.sys in sysinit_seg tryqbadload: call badload ;ds will be restored to sysinit_seg mov cx,cs:[confbot] mov es,cx ;restore es -> confbot. jmp short coffj4 tryqmemory: mov dx,offset insufmemory tryqchkerr: mov cx,cs:[confbot] mov es,cx ;restore es -> confbot seg push cs pop ds ;retore ds to sysinit_seg jnc coffj4 ;if no error,then exit call print ;else show error message call error_line coffj4: mov bx,cntryfilehandle mov ah,3eh int 21h ;close a file. don't care even if it fails. jmp coff cntry_error proc near ;function: show "invalid country code or code page" messages,or ; "error in country command" depending on the error code ; in ax returned by sysparse; ;in: ax - error code ; ds - sysinitseg ; es - confbot ;out: show message. dx destroyed. cmp ax,$p_out_of_range jnz if64 mov dx,offset badcountry ;"invalid country code or code page" jmp short en64 if64: mov dx,offset badcountrycom ;"error in contry command" en64: call print call error_line ret cntry_error endp ;------------------------------------------------------------------------------ ; files command ;------------------------------------------------------------------------------ ;******************************************************************************* ; function: parse the parameters of files= command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; variable files set. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di points to files_parms; * ; set dx,cx to 0; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; files = result_val.$p_picked_val * ; else * ; error exit; * ; }; * ; }; * ; * ;******************************************************************************* tryf: cmp ah,'F' jnz tryl mov di,offset files_parms xor cx,cx mov dx,cx do67: call sysinit_parse jnc if67 ; parse error call badparm_p ; and show messages and end the search loop. jmp short sr67 if67: cmp ax,$p_rc_eol ; end of line? jz en67 ; then end the $endloop mov al,byte ptr result_val.$p_picked_val mov p_files,al ; save it temporarily jmp short do67 en67: mov al,p_files SVC SVC_DEMWOWFILES ; For WOW VDM Set the file= to max. mov files,al ; no error. really set the value now. sr67: jmp coff ;------------------------------------------------------------------------------ ; lastdrive command ;------------------------------------------------------------------------------ ;******************************************************************************* ; function: parse the parameters of lastdrive= command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; set the variable num_cds. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di points to ldrv_parms; * ; set dx,cx to 0; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; set num_cds to the returned value; * ; else /*error exit*/ * ; error exit; * ; }; * ; }; * ; * ;******************************************************************************* tryl: cmp ah,'L' jnz tryp jmp coff ;NTVDM Ignore the lastdrive command. Dos will figure this from the host OS. ; 17-Aug-1992 Jonle if 0 mov di,offset ldrv_parms xor cx,cx mov dx,cx do73: call sysinit_parse jnc if73 ; parse error call badparm_p ; and show messages and end the search loop. jmp short sr73 if73: cmp ax,$p_rc_eol ; end of line? jz en73 ; then end the $endloop mov al,rv_byte ; pick up the drive number mov p_ldrv,al ; save it temporarily jmp do73 en73: mov al,p_ldrv mov num_cds,al ; no error. really set the value now. sr73: jmp coff endif ;-------------------------------------------------------------------------- ; setting drive parameters ;-------------------------------------------------------------------------- tryp: cmp ah,'P' jnz tryk jmp coff ; sudeepb 04-Mar-1991 : Ignoring DRIVEPARM command ; call parseline ; jc trypbad ; ; call setparms ; call diddleback ; jc trypbad ; jmp coff ;trypbad:jmp badop ;-------------------------------------------------------------------------- ; setting internal stack parameters ; stacks=m,n where ; m is the number of stacks (range 8 to 64,default 9) ; n is the stack size (range 32 to 512 bytes,default 128) ; j.k. 5/5/86: stacks=0,0 implies no stack installation. ; any combinations that are not within the specified limits will ; result in "unrecognized command" error. ;-------------------------------------------------------------------------- ;**************************************************************************** ; * ; function: parse the parameters of stacks= command. * ; the minimum value for "number of stacks" and "stack size" is * ; 8 and 32 each. in the definition of sysparse value list,they * ; are set to 0. this is for accepting the exceptional case of * ; stacks=0,0 case (,which means do not install the stack.) * ; so,after sysparse is done,we have to check if the entered * ; values (stack_count,stack_size) are within the actual range, * ; (or if "0,0" pair has been entered.) * ; input : * ; es:si -> parameters in command line. * ; output: * ; set the variables stack_count,stack_size. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di points to stks_parms; * ; set dx,cx to 0; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; { if (cx == 1) then /* first positional = stack count */ * ; p_stack_count = result_val.$p_picked_val; * ; if (cx == 2) then /* second positional = stack size */ * ; p_stack_size = result_val.$p_picked_val; * ; } * ; else /*error exit*/ * ; error exit; * ; }; * ; here check p_stack_count,p_stack_size if it meets the condition; * ; if o.k.,then set stack_count,stack_size; * ; else error_exit; * ; }; * ;**************************************************************************** tryk: cmp ah,'K' je do_tryk jmp trys if stacksw do_tryk: mov di,offset stks_parms xor cx,cx mov dx,cx do79: call sysinit_parse jnc if79 ; parse error mov dx,offset badstack ; "invalid stack parameter" call print ; and show messages and end the search loop. call error_line jmp sr79 if79: cmp ax,$p_rc_eol ; end of line? jz en79 ; then end the $endloop mov ax,word ptr result_val.$p_picked_val cmp cx,1 jnz if83 mov p_stack_count,ax jmp short en83 if83: mov p_stack_size,ax en83: jmp do79 en79: cmp p_stack_count,0 jz if87 cmp p_stack_count,mincount jb ll88 cmp p_stack_size,minsize jnb if88 ll88: mov p_stack_count,-1 ; invalid if88: jmp short en87 if87: cmp p_stack_size,0 jz en87 mov p_stack_count,-1 ; invalid en87: cmp p_stack_count,-1 ; invalid? jnz if94 mov stack_count,defaultcount ;reset to default value. mov stack_size,defaultsize mov word ptr stack_addr,0 mov dx,offset badstack call print call error_line jmp short sr79 if94: mov ax,p_stack_count mov stack_count,ax mov ax,p_stack_size mov stack_size,ax mov word ptr stack_addr,-1 ; stacks= been accepted. sr79: jmp coff endif ;------------------------------------------------------------------------ ; shell command ;------------------------------------------------------------------------ trys: cmp ah,'S' jnz tryx mov [command_line+1],0 mov di,offset commnd + 1 mov [di-1],al storeshell: call getchr or al,al jz getshparms cmp al," " jb endsh mov [di],al inc di jmp storeshell endsh: mov byte ptr [di],0 ; push di ; mov di,offset commnd ; SVC SVC_SETSHELLNAME ; pop di call getchr cmp al,lf jnz conv call getchr conv: jmp conflp getshparms: mov byte ptr [di],0 mov di,offset command_line+1 parmloop: call getchr cmp al," " jb endsh mov [di],al inc di jmp parmloop ;------------------------------------------------------------------------ ; fcbs command ;------------------------------------------------------------------------ ;************************************************************************ ; function: parse the parameters of fcbs= command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; set the variables fcbs,keep. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di points to fcbs_parms; * ; set dx,cx to 0; * ; while (end of command line) * ; { sysparse; * ; if (no error) then * ; { if (cx == 1) then /* first positional = fcbs */ * ; fcbs = result_val.$p_picked_val; * ; if (cx == 2) then /* second positional = keep */ * ; keep = result_val.$p_picked_val; * ; } * ; else /*error exit*/ * ; error exit; * ; }; * ; }; * ;************************************************************************ tryx: cmp ah,'X' jnz tryy mov di,offset fcbs_parms xor cx,cx mov dx,cx do98: call sysinit_parse jnc if98 ; parse error call badparm_p ; and show messages and end the search loop. jmp short sr98 if98: cmp ax,$p_rc_eol ; end of line? jz en98 ; then end the $endloop mov al,byte ptr result_val.$p_picked_val cmp cx,1 ; the first positional? jnz if102 mov p_fcbs,al jmp short en102 if102: mov p_keep,al en102: jmp do98 en98: mov al,p_fcbs ; M017 mov fcbs,al ; M017 mov keep,0 ; M017 sr98: jmp coff ;------------------------------------------------------------------------- ; comment= do nothing. just decrese chrptr,and increase count for correct ; line number ;------------------------------------------------------------------------- tryy: cmp ah,'Y' jne try0 donothing: dec chrptr inc count jmp coff ;------------------------------------------------------------------------ ; rem command ;------------------------------------------------------------------------ try0: ;do nothing with this line. cmp ah,'0' je donothing ;----------------------------------------------------------------------- ; switches command ;----------------------------------------------------------------------- ;**************************************************************************** ; * ; function: parse the option switches specified. * ; note - this command is intended for the future use also. when we need to * ; to set system data flag,use this command. * ; * ; input : * ; es:si -> parameters in command line. * ; output: * ; p_swit_k set if /k option chosen. * ; * ; subroutines to be called: * ; sysinit_parse * ; logic: * ; { * ; set di points to swit_parms; /*parse control definition*/ * ; set dx,cx to 0; * ; while (end of command line) * ; { sysinit_parse; * ; if (no error) then * ; if (result_val.$p_synonym_ptr == swit_k) then * ; p_swit_k = 1 * ; endif * ; else {show error message;error exit} * ; }; * ; }; * ; * ;**************************************************************************** cmp ah,'1' ;switches= command entered? je do_try1 jmp tryt do_try1: mov di,offset swit_parms xor cx,cx mov dx,cx do110: call sysinit_parse jnc if110 ; parse error call badparm_p ; and show messages and end the search loop. jmp short sr110 if110: cmp ax,$p_rc_eol ; end of line? jz en110 ; then jmp to $endloop for semantic check cmp result_val.$p_synonym_ptr,offset swit_k jnz if115 ; ;M059 mov p_swit_k,1 ; set the flag jmp do110 if115: ;M059 cmp result_val.$p_synonym_ptr, offset swit_t ;M059 jne if116 ;M059 M063 mov p_swit_t, 1 ;M059 jmp do110 ;M059 if116: cmp result_val.$p_synonym_ptr, offset swit_w ;M063 jne do110 ;M063 mov p_swit_w, 1 ;M063 jmp do110 ;M063 en110: cmp p_swit_k,1 ;if /k entered, push ds mov ax,Bios_Data mov ds,ax assume ds:Bios_Data jnz if117 mov keyrd_func,0 ;use the conventional keyboard functions mov keysts_func,1 if117: ; mov al, p_swit_t ;M059 ; mov t_switch, al ;M059 cmp p_swit_w, 0 ;M063 je skip_dos_flag ;M063 push es push bx mov ah, GET_IN_VARS ;M063 int 21h ;M063 or byte ptr es:[DOS_FLAG_OFFSET], SUPPRESS_WINA20 ;M063 pop bx pop es skip_dos_flag: ;M063 pop ds assume ds:sysinitseg sr110: jmp coff ;------------------------------------------------------------------------ ; NTCMDPROMPT command. This command forces SCS functionality to use ; cmd.exe prompt rather than command.com's prompt on shelling out ; and on finding a TSR. ;------------------------------------------------------------------------ tryt: cmp ah,'T' je tryt_5 jmp short tryo tryt_5: push si push bp xor ax,ax mov bp,ax mov si,ax mov al,4 mov ah,setdpb int 21h pop bp pop si jmp coff ;------------------------------------------------------------------------ ; DOSONLY command. This command forces only DOS binaries to run from ; command.com prompt. non_dos binaries will putup the stub message ; of unable to run it under DOS. ;------------------------------------------------------------------------ tryo: cmp ah,'O' je tryo_5 jmp short tryz tryo_5: push si push bp xor ax,ax mov bp,ax mov si,ax mov al,6 mov ah,setdpb int 21h pop bp pop si jmp coff ;------------------------------------------------------------------------ ; bogus command ;------------------------------------------------------------------------ tryz: cmp ah,0ffh je tryff dec chrptr inc count jmp short badop ;------------------------------------------------------------------------ ; null command ;------------------------------------------------------------------------ tryff: ;skip this command. jmp donothing doconf endp ;------------------------------------------------------------------------------ sysinit_parse proc ;set up registers for sysparse ;in) es:si -> command line in confbot ; di -> offset of the parse control defintion. ; ;out) calls sysparse. ; carry will set if parse error. ; *** the caller should check the eol condition by looking at ax ; *** after each call. ; *** if no parameters are found,then ax will contain a error code. ; *** if the caller needs to look at the synomym@ of the result, ; *** the caller should use cs:@ instead of es:@. ; cx register should be set to 0 at the first time the caller calls this ; procedure. ; ax - exit code ; bl - terminated delimeter code ; cx - new positional ordinal ; si - set to pase scanned operand ; dx - selected result buffer push es ;save es,ds push ds push es pop ds ;now ds:si -> command line push cs pop es ;now es:di -> control definition mov cs:badparm_seg,ds ;save the pointer to the parm mov cs:badparm_off,si ; we are about to parse for badparm msg. mov dx,0 call sysparse cmp ax,$p_no_error ;no error ;**cas note: when zero true after cmp, carry clear jz ll4 cmp ax,$p_rc_eol ;or the end of line? jnz if4 ll4: clc jmp short en4 if4: stc en4: pop ds pop es ret sysinit_parse endp ; ;---------------------------------------------------------------------------- ; ; procedure : badop_p ; ; same thing as badop,but will make sure to set ds register back ; to sysinitseg and return back to the caller. ; ;---------------------------------------------------------------------------- ; badop_p proc near push cs pop ds ;set ds to configsys seg. mov dx,offset badopm call print call error_line ret badop_p endp ; ;---------------------------------------------------------------------------- ; ; label : badop ; ;---------------------------------------------------------------------------- ; badop: mov dx,offset badopm ;want to print command error "unrecognized command..." call print call error_line ;show "error in config.sys ..." . jmp coff ; ;---------------------------------------------------------------------------- ; ; procedure : badparm_p ; ; show "bad command or parameters - xxxxxx" ; in badparm_seg,badparm_off -> xxxxx ; ;---------------------------------------------------------------------------- ; badparm_p proc near push ds push dx push si push cs pop ds mov dx,offset badparm call print ;"bad command or parameters - " lds si,badparm_ptr ; print "xxxx" until cr. do1: mov dl,byte ptr [si] ; get next character cmp dl,cr ; is a carriage return? jz en1 ; exit loop if so mov ah,std_con_output ; function 2 int 21h ; display character inc si ; next character jmp do1 en1: push cs pop ds mov dx,offset crlfm call print call error_line pop si pop dx pop ds badparmp_ret: ret badparm_p endp ; ;---------------------------------------------------------------------------- ; ; procedure : getchr ; ;---------------------------------------------------------------------------- ; getchr proc near push cx mov cx,count jcxz nochar mov si,chrptr mov al,es:[si] dec count inc chrptr clc get_ret: pop cx ret nochar: stc jmp short get_ret getchr endp ; ;---------------------------------------------------------------------------- ; ; procedure : incorrect_order ; ; show "incorrect order in config.sys ..." message. ; ;---------------------------------------------------------------------------- ; incorrect_order proc near mov dx,offset badorder call print call showlinenum ret incorrect_order endp ; ;---------------------------------------------------------------------------- ; ; procedure : error_line ; ; show "error in config.sys ..." message. ; ;---------------------------------------------------------------------------- ; public error_line error_line proc near push cs pop ds mov dx,offset errorcmd call print call showlinenum ret error_line endp ; ;---------------------------------------------------------------------------- ; ; procedure : showlinenum ; ; convert the binary linecount to decimal ascii string in showcount ;and display showcount at the current curser position. ;in.) linecount ; ;out) the number is printed. ; ;---------------------------------------------------------------------------- ; showlinenum proc near push es push ds push di push cs pop es ; es=cs push cs pop ds mov di,offset showcount+4 ; di -> the least significant decimal field. mov cx,10 ; decimal devide factor mov ax,cs:linecount sln_loop: cmp ax,10 ; < 10? jb sln_last xor dx,dx div cx or dl,30h ; add "0" (= 30h) to make it an ascii. mov [di],dl dec di jmp sln_loop sln_last: or al,30h mov [di],al mov dx,di call print ; show it. pop di pop ds pop es ret showlinenum endp comment ^ set_devmark proc near ;*************************************************************************** ; function: set a paragraph of informations infront of a device file or * ; an ifs file to be loaded for mem command. * ; the structure is: * ; devmark_id byte "d" for device,"i" for ifs * ; devmark_size size in para for the device loaded * ; devmark_filename 11 bytes. filename * ; * ; input : * ; [memhi] = address to set up devmark. * ; [memlo] = 0 * ; es:si -> pointer to [drive][path]filename,0 * ; [ifs_flag] = is_ifs bit set if ifs= command. * ; * ; output: devmark_id,devmark_filename set * ; cs:[devmark_addr] set. * ; ax,cx register destroyed. * ;*************************************************************************** push ds push si push es push di mov di,cs:[memhi] mov ds,di assume ds:nothing mov [devmark_addr],di ; save the devmark address for the future. mov ds:[devmark_id],devmark_device ; 'd' inc di mov ds:[devmark_seg],di xor al,al push si pop di ; now es:si = es:di = [path]filename,0 mov cx,128 ; maximum 128 char repnz scasb ; find 0 dec di ; now es:di-> 0 sdvmk_backward: ; find the pointer to the start of the filename. mov al,byte ptr es:[di] ; we do this by check es:di backward until cmp al,'\' ; di = si or di -> '\' or di -> ':'. je sdvmk_gotfile cmp al,':' je sdvmk_gotfile cmp di,si je sdvmk_fileptr dec di jmp sdvmk_backward sdvmk_gotfile: inc di sdvmk_fileptr: ; now es:di -> start of file name push di ; cas - holy sh*t!!! CODE! pop si ; save di to si. push ds ; switch es,ds push es pop ds pop es ; now,ds:si -> start of filename mov di,devmark_filename push di mov al,' ' mov cx,8 rep stosb ; clean up memory. pop di mov cx,8 ; max 8 char. only sdvmk_loop: lodsb cmp al,'.' je sdvmk_done cmp al,0 je sdvmk_done stosb loop sdvmk_loop sdvmk_done: pop di pop es pop si pop ds ret set_devmark endp ^ ; ========================================================================= ;reset_dos_version proc near ; ;;function: issue ax=122fh,dx=0,int 2fh to restore the dos version. ; ; push ax ; push dx ; mov ax,122fh ; mov dx,0 ; int 2fh ; pop dx ; pop ax ; ret ;reset_dos_version endp ; ; ; ========================================================================= IFDEF DONT_LOAD_OS2_DD ; M045 EXE_SIG EQU 5a4dh ; .EXE file signature OS2_SIG EQU 454eh ; OS2 .EXE file signature SIGNATURE_LEN EQU 2 ; Lenght of .EXE signature in bytes SIZE_DWORD EQU 4 SEG_SIG_OFFSET EQU 18h ; Offset of segmented .EXE signature SEG_EXE_SIG EQU 40h ; Signature of a segmented .EXE file SEG_HEADER_PTR EQU 3ch ; Offsets of ptr to segmented header ; ========================================================================= ; CheckForOS2 PROC ; ; Examines an open file to see if it is really an OS2 executable file. ; ; REGISTERS: AX - Open file handle ; RETURNS: Carry - Carry set if file is an OS2 executable or error. ; DESTROYS: NOTHING ; NOTE: The file ptr is assumed to be set to start of file ; on entry and is not reset to begining of the file ; on exit. ; ; Strategy: If word value at 00h == 454eh file is OS2 ; else if word value at 00h == 5a4dh and ; (word value at 18h == 40h and the dword ptr at 3ch ; points to word value of 454eh) file is OS2. ; ; ========================================================================= CheckForOS2 PROC NEAR push AX push BX push CX push DX push DS push BP push CS ; BUGBUG pop DS ; NOT ROM DOS COMPATIBLE mov BX,AX ; Put open file handle in BX mov BP,offset DS:Os2ChkBuf ; Save buff offset for latter ; First we need to read in the first 2 bytes of the file ; to see if it's an OS2 .EXE file and if not see if ; it is a DOS .EXE file. mov AX,(read shl 8) ; AH = DOS read function mov CX,SIGNATURE_LEN ; CX = size of word value mov DX,BP ; DS:DX --> tmp buffer int 21h jc OS2ChkExit ; Return carry on error dec AX ; Check number of byte read dec AX jnz NotOs2 ; Must be at end of file mov AX, WORD PTR DS:Os2ChkBuf cmp AX, OS2_SIG ; Check for 454eh je IsOS2 ; Return is OS2 if match cmp AX, EXE_SIG ; Now see if it's a DOS .EXE jne NotOS2 ; If no match can't be OS2 ; Here we know the file has a valid DOS .EXE signature so ; now we need to see if it's a segmented .EXE file by looking ; for the segmented .EXE signature at file offset 18h mov AX,(lseek shl 8) ; AX = Seek from begining xor CX,CX mov DX,SEG_SIG_OFFSET ; CX:DX = offset of segmented int 21h ; Seek to offset 18h jc OS2ChkExit ; Return carry on error mov AX,read shl 8 ; AX = Read file mov CX,SIGNATURE_LEN ; CX = size of word value mov DX,BP ; Restore buffer offset int 21h ; DS:DX -> buffer jc OS2ChkExit ; Return carry on error dec AX ; Check number of byte read dec AX jnz NotOs2 ; Must be at end of file cmp WORD PTR DS:Os2ChkBuf,SEG_EXE_SIG ; Chk for segmented .EXE file jne NotOS2 ; Can't be OS2 if no match ; Here we know we have a segmented .EXE file so we have ; to get the offset of the start of the segmented header ; from offset 3ch in the file. mov AX,(lseek shl 8) ; AX = Seek from begining xor CX,CX mov DX,SEG_HEADER_PTR ; CX:DX = offset of head ptr int 21h ; Seek to offset 3ch jc OS2ChkExit ; Return carry on error mov AX,(read shl 8) ; AX = Read file mov CX,SIZE_DWORD ; CX = size of dword (4 bytes) mov DX,BP ; Restore buffer offset int 21h ; Read in 4 byte offset jc OS2ChkExit ; Return carry on error cmp AX,SIZE_DWORD ; Check number of byte read jne NotOs2 ; Must be at end of file ; At this point OS2ChkBuf has a 4 byte offset into the file ; to the start of a segmented .EXE header so we need to read ; the 2 bytes at this location to see if they are 454eh mov DX,WORD PTR DS:Os2ChkBuf mov CX,WORD PTR DS:Os2ChkBuf[2] ; CX:DX = offset of new header mov AX,(lseek shl 8) ; AX = Seek from begining int 21h ; Seek to offset 3ch jc OS2ChkExit ; Return carry on error mov AX,(read shl 8) ; AX = Read file mov CX,SIGNATURE_LEN ; CX = size of word (2 bytes) mov DX,BP ; DS:DX --> Os2ChkBuf int 21h ; Read in 4 byte offset jc OS2ChkExit ; Return carry on error dec AX ; Check number of byte read dec AX jnz NotOs2 ; Must be at end of file ; We have the segmented .EXE header in OS2ChkBuf so all ; we have left to do is see if it's a .EXE signature. cmp WORD PTR DS:OS2ChkBuf,OS2_SIG ; Check for 454eh jne NotOs2 ; Not OS2 if it doesn't match IsOs2: stc ; Signal error or OS2 .EXE jmp SHORT OS2ChkExit NotOs2: clc ; Signal no err and not OS2 OS2ChkExit: pop BP pop DS pop DX pop CX pop BX pop AX ret CheckForOS2 ENDP ENDIF ; M045 ; ;---------------------------------------------------------------------------- ; ; procedure : ProcDOS ; ; Process the result of DOS= parsing ; ; result_val.$p_item_tag = 1 for DOS=HIGH ; = 2 for DOS=LOW ; = 3 for DOS=UMB ; = 4 for DOS=NOUMB ;---------------------------------------------------------------------------- ; ProcDOS proc near assume ds:nothing, es:nothing xor ah, ah mov al, result_val.$p_item_tag dec ax jz pd_hi dec ax jz pd_lo dec ax jz pd_umb mov DevUMB, 0 ret pd_umb: mov DevUMB, 0ffh ret pd_lo: mov runhigh, 0 ret pd_hi: mov runhigh, 0ffh ret ProcDOS endp ; ;---------------------------------------------------------------------------- ; ; procedure : LieInt12Mem ; ; Input : DevEntry points to Device Start address (offset == 0) ; alloclim set to the limit of low memory. ; ; Output : none ; ; Changes the ROM BIOS variable which stores the total low memory ; If a 3com device driver (any character device with name 'PROTMAN$') ; is being loaded alloclim is converted into Ks and stored in 40:13h ; Else if a device driver being loaded into UMB the DevLoadEnd is ; converted into Ks and stored in 40:13h ; ;---------------------------------------------------------------------------- ; LieInt12Mem proc near assume ds:nothing, es:nothing mov ax, alloclim ; lie INT 12 as alloclim ; assuming that it is 3Com call IsIt3Com? ; Is it 3Com driver? je lim_set ; yes, lie to him differently cmp DeviceHi, 0 ; Is the DD being loaded in UMB je limx ; no, don't lie mov ax, DevLoadEnd ; lie INT 12 as end of UMB lim_set: call SetInt12Mem limx: ret LieInt12Mem endp ; ;---------------------------------------------------------------------------- ; ; procedure : SetInt12Mem ; ; Input : AX = Memory size to be set (in paras) ; Output : none ; ; Sets the variable 40:13 to the memory size passed in AX ; It saves the old value in 40:13 in OldInt12Mem, ; It also sets a flag Int12Lied to 0ffh, which is checked before ; restoring the value of 40:13 ; ;---------------------------------------------------------------------------- ; SetInt12Mem proc near assume ds:nothing, es:nothing push ds mov bx, 40h mov ds, bx ; ROM BIOS Data Segment mov bx, word ptr ds:[13h] ; INT 12 memory variable mov OldInt12Mem, bx ; save it mov cl, 6 shr ax, cl ; convert paras into Ks mov word ptr ds:[13h], ax ; Lie mov Int12Lied, 0ffh ; mark that we are lying pop ds ret SetInt12Mem endp ; ;---------------------------------------------------------------------------- ; ; procedure : TrueInt12Mem ; ; Input : Int12Lied = 0 if we are not lying currently ; = 0ffh if we are lying ; OldInt12Mem = Saved value of 40:13h ; ; Output : none ; ; Resets the INT 12 Memory variable if we were lying about int 12 ; and resets the flag which indicates that we were lying ; ;---------------------------------------------------------------------------- ; TrueInt12Mem proc near assume ds:nothing, es:nothing cmp Int12Lied, 0 ; were we lying so far? mov Int12Lied, 0 ; reset it anyway je timx ; no, we weren't push ds mov ax, 40h mov ds, ax mov ax, OldInt12Mem mov word ptr ds:[13h], ax ; restore INT 12 memory pop ds timx: ret TrueInt12Mem endp ; ;---------------------------------------------------------------------------- ; ; procedure : IsIt3Com? ; ; Input : DevEntry = Seg:0 of device driver ; Output : Zero flag set if device name is 'PROTMAN$' ; else Zero flag is reset ; ;---------------------------------------------------------------------------- ; IsIt3Com? proc near assume ds:nothing, es:nothing, ss:nothing push ds push es push si lds si, DevEntry ; ptr to device header add si, sdevname ; ptr device name push cs pop es mov di, offset ThreeComName mov cx, 8 ; name length rep cmpsb pop si pop es pop ds ret IsIt3Com? endp ;M020 : BEGIN ; ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; UpdatePDB proc near assume ds:nothing push ds mov ah, 62h int 21h mov ds, bx mov bx, alloclim mov ds:[PDB_Block_Len], bx pop ds ret UpdatePDB endp ; ; M020 : END ; ;---------------------------------------------------------------------------- ; ; procedure : InitDevLoad ; ; Input : DeviceHi = 0 indicates load DD in low memory ; = 1 indicates load in UMB ; DevSize = Size of the device driver file in paras ; ; Output : none ; ; Initializes DevLoadAddr, DevLoadEnd & DevEntry. ; Also sets up a header for the Device driver entry for mem utility ; ;---------------------------------------------------------------------------- ; InitDevLoad proc near assume ds:nothing, es:nothing cmp DeviceHi, 0 ; Are we loading in UMB je InitForLo ; no, init for lo mem call SpaceInUMB? ; Do we have space left in the ; current UMB ? jnc InitForHi ; yes, we have call ShrinkUMB ; shrink the current UMB in use call GetUMBForDev ; else try to allocate new UMB jc InitForLo ; we didn't succeed, so load ; in low memory InitForHi: mov ax, DevUMBFree ; get Para addr of free mem mov dx, DevUMBAddr ; UMB start addr add dx, DevUMBSize ; DX = UMB End addr jmp short idl1 InitForLo: mov DeviceHi, 0 ; in case we failed to load ; into UMB indicate that we ; are loading low mov ax, memhi ; AX = start of Low memory mov dx, alloclim ; DX = End of Low memory idl1: call DevSetMark ; setup a sub-arena for DD mov DevLoadAddr, ax ; init the Device load address mov DevLoadEnd, dx ; init the limit of the block mov word ptr DevEntry, 0 ; init Entry point to DD mov word ptr DevEntry+2, ax ret InitDevLoad endp ;------------------------------------------------------------------ ; NTVDM 08-Dec-1992 Jonle ; ; AllocUMBLow- Allocates a chunk from memory from UMB area ; or from low memory area in case UMB memory ; is unavailable. ; ; The arena is marked as ; ; Input: es:di addr of arena name to copy ; cx size to allocate ; ; Output: es:di points to memory allocated ; ;------------------------------------------------------------------ AllocUMBLow proc near assume ds:nothing, es:nothing mov ax, cx ; convert size to paras add ax, 18 ; extra for dummy dev header for mem.exe call pararound mov DevSize, ax mov word ptr [bpb_addr], di ; fake cmd line for dev name mov word ptr [bpb_addr+2], es mov al, DevUMB ; we want UMB mov DeviceHi, al call InitDevLoad mov ax, word ptr DevEntry+2 ; mark arena for mem.exe dec ax mov es, ax mov byte ptr es:[devmark_id], devmark_spc inc ax ; mark final size add ax, DevSize mov word ptr DevBrkAddr+2,ax mov word ptr DevBrkAddr, 0 call DevBreak mov di, word ptr DevEntry ; es:di -> deventry mov ax, word ptr DevEntry+2 mov es, ax AllocUMBLow endp ; ;---------------------------------------------------------------------------- ; ; procedure : SpaceInUMB? ; ; Input : DevUMBAddr, DevUMBSize, DevUMBFree & DevSize ; Output : Carry set if no space in UMB ; Carry clear if Space is available for the device in ; current UMB ; ;---------------------------------------------------------------------------- ; SpaceInUMB? proc near assume ds:nothing, es:nothing mov ax, DevUMBSize add ax, DevUMBAddr ; End of UMB sub ax, DevUMBFree ; - Free = Remaining space or ax, ax ; Nospace ? jnz @f stc ret @@: dec ax ; space for sub-arena cmp ax, DevSize ; do we have space ? ret SpaceInUMB? endp ; ;---------------------------------------------------------------------------- ; ; procedure : GetUMBForDev ; ; Input : DevSize ; Output : Carry set if couldn't allocate a UMB to fit the ; the device. ; If success carry clear ; ; Allocates the biggest UMB for loading devices and updates ; DevUMBSize, DevUMBAddr & DevUMBFree if it succeeded in allocating ; UMB. ; ; This routine relies on the fact that all of the low memory ; is allocated, and any DOS alloc calls should return memory ; from the UMB pool. ; ;---------------------------------------------------------------------------- ; GetUMBForDev proc near assume ds:nothing, es:nothing if 0 ;; mov bx, 0ffffh mov ax, 4800h int 21h or bx, bx jz gufd_err dec bx cmp DevSize, bx ja gufd_err inc bx mov ax, 4800h int 21h jc gufd_err push ds dec ax mov ds, ax mov word ptr ds:[arena_owner], 8 mov word ptr ds:[arena_name], 'DS' inc ax pop ds mov DevUMBSize, bx ; update the UMB Variables mov DevUMBAddr, ax mov DevUMBFree, ax clc ; mark no error ret gufd_err: xor ax, ax mov DevUMBSize, ax ; erase the previous values mov DevUMBAddr, ax mov DevUMBFree, ax stc ret else ;; we changed the allocation strategy to best-fit for NT. This is because ;; we want to reserve bigger blocks for loadhigh command. In most case, ;; device drivers are smaller than TSR(ran from loadhigh). This change give ;; us a better chance to load the big tsr like DOSX.EXE to UMB and ;; give applications more free conventional memory. ;; The following implementation seems slow because every time we need an ;; UMB, we go through the chain. This is done because each request has ;; different size - We can grab all UMBs from the very beginning and put ;; them in a list, but we have to maintain the list. -williamh push cx push dx push es xor cx, cx ;; allocated count = 0 mov dx, DevSize inc dx ;; minimum size in paras ;; bios needs its sub-arena search_for_best_block: mov bx, 0ffffh ;; get largest block size mov ah, 48h ;; so far int 21h cmp bx, dx ;; will this satisfy ours? jb allocate_the_block ;; no, break mov ah, 48h ;; allocate this block int 21h jc allocate_the_block ;; failed, use the previous one inc cx ;; we have one more allocated push bx ;; save the size push ax ;; save the address jmp short search_for_best_block allocate_the_block: ;; the block saved on the top of the stack is the best fit one ;; grab it if there is one jcxz gufd_err ;; no block found, error pop ax ;; get the address pop DevUMBSize ;; and size mov DevUMBAddr, ax mov DevUMBFree, ax dec ax push ds mov ds, ax mov word ptr ds:[arena_owner], 8 mov word ptr ds:[arena_name], 'DS' pop ds dec cx ;; now free those unnecessary blocks jcxz allocate_done free_allocated_blocks: pop es ;; get the address add sp, 2 ;; discard the size mov ah, 49h ;; free it int 21h loop free_allocated_blocks allocate_done: clc ; mark no error jmp short GetUMBForDevExit gufd_err: xor ax, ax mov DevUMBSize, ax ; erase the previous values mov DevUMBAddr, ax mov DevUMBFree, ax stc GetUMBForDevExit: pop es pop dx pop cx ret endif GetUMBForDev endp ; ;---------------------------------------------------------------------------- ; ; procedure : DevSetMark ; ; Input : AX - Free segment were device is going to be loaded ; Output : AX - Segment at which device can be loaded (AX=AX+1) ; ; Creates a sub-arena for the device driver ; puts 'D' marker in the sub-arena ; Put the owner of the sub-arena as (AX+1) ; Copies the file name into sub-arena name field ; ; Size field of the sub-arena will be set only at succesful ; completion of Device load. ; ;---------------------------------------------------------------------------- ; DevSetMark proc near assume ds:nothing, es:nothing push es push di push ds push si mov es, ax mov byte ptr es:[devmark_id], devmark_device ; 'D' inc ax mov word ptr es:[devmark_seg], ax ; ;-------------- Copy file name ; push ax ; save load addr lds si, bpb_addr ; command line is still there ;M004 - BEGIN mov di, si cld dsm_again: lodsb cmp al, ':' jne isit_slash mov di, si jmp dsm_again isit_slash: cmp al, '\' jne isit_null mov di, si jmp dsm_again isit_null: ifdef DBCS call testkanj jz @f ; if this is not lead byte lodsb ; get tail byte @@: endif or al, al jnz dsm_again mov si, di ;M004 - END mov di, devmark_filename mov cx, 8 ; maximum 8 characters dsm_next_char: lodsb or al, al jz blankout cmp al, '.' jz blankout stosb loop dsm_next_char blankout: jcxz dsm_exit mov al, ' ' rep stosb ; blank out the rest dsm_exit: pop ax ; restore load addr pop si pop ds pop di pop es ret DevSetMark endp ; ;---------------------------------------------------------------------------- ; ; procedure : SizeDevice ; ; Input : ES:SI - points to device file to be sized ; ; Output : Carry set if file cannot be opened or if it is an OS2EXE file ; ; Calculates the size of the device file in paras and stores it ; in DevSize ; ;---------------------------------------------------------------------------- ; SizeDevice proc near assume ds:nothing, es:nothing push es pop ds mov dx, si ; ds:dx -> file name mov ax, 3d00h ; open int 21h jc sd_err ; open failed IFDEF DONT_LOAD_OS2_DD ; M045 call CheckForOS2 ; is it a OS2 EXE file ? jc sd_close ; yeah, we dont load them ENDIF ; M045 mov bx, ax ; BX - file handle mov ax, 4202h ; seek xor cx, cx mov dx, cx ; to end of file int 21h jc sd_close ; did seek fail (impossible) add ax, 15 ; para convert adc dx, 0 test dx, 0fff0h ; size > 0ffff paras ? jz @f ; no mov DevSize, 0ffffh ; invalid device size ; assuming that we fail later jmp short sd_close @@: mov cl, 4 ; conver it to paras shr ax, cl mov cl, 12 shl dx, cl or ax, dx ; cmp ax, DevSizeOption ja @f mov ax, DevSizeOption @@: mov DevSize, ax ; save file size clc sd_close: pushf ; let close not spoil our ; carry flag mov ax, 3e00h ; close int 21h ; we are not checking for err popf sd_err: ret SizeDevice endp ; ;---------------------------------------------------------------------------- ; ; procedure : ExecDev ; ; Input : ds:dx -> device to be executed ; DevLoadAddr - contains where device has to be loaded ; ; Output : Carry if error ; Carry clear if no error ; ; Loads a device driver using the 4b03h function call ; ;---------------------------------------------------------------------------- ; ExecDev proc near assume ds:nothing, es:nothing mov bx, DevLoadAddr mov DevExecAddr, bx ; Load the parameter block ; block for exec with ; Load address mov DevExecReloc, bx mov bx,cs mov es,bx mov bx,offset DevExecAddr ;es:bx points to parameters mov al,3 mov ah,exec int 21h ;load in the device driver ret ExecDev endp ; ;---------------------------------------------------------------------------- ; ; procedure : RemoveNull ; ; Input : ES:SI points to a null terminated string ; ; Output : none ; ; Replaces the null at the end of a string with blank ; ;---------------------------------------------------------------------------- ; RemoveNull proc near assume ds:nothing, es:nothing rn_next: mov bl, es:[si] or bl, bl ; null ? jz rn_gotnull inc si ; advance the pointer jmp rn_next rn_gotnull: mov bl, DevSavedDelim mov byte ptr es:[si], bl ; replace null with blank ret RemoveNull endp ; ;---------------------------------------------------------------------------- ; ; procedure : RoundBreakAddr ; ; Input : DevBrkAddr ; Output : DevBrkAddr ; ; Rounds DevBrkAddr to a para address so that it is of the form xxxx:0 ; ;---------------------------------------------------------------------------- ; RoundBreakAddr proc near assume ds:nothing, es:nothing mov ax, word ptr DevBrkAddr call pararound add word ptr DevBrkAddr+2, ax mov word ptr DevBrkAddr, 0 mov ax, DevLoadEnd cmp word ptr DevBrkAddr+2, ax jbe rba_ok jmp mem_err rba_ok: ret RoundBreakAddr endp ; ;---------------------------------------------------------------------------- ; ; procedure : DevSetBreak ; ; Input : DevBrkAddr ; Output : Carry set if Device returned Init failed ; Else carry clear ; ;---------------------------------------------------------------------------- ; DevSetBreak proc near assume ds:nothing, es:nothing push ax mov ax,word ptr [DevBrkAddr+2] ;remove the init code cmp multdeviceflag, 0 jne set_break_continue ;do not check it. cmp ax, DevLoadAddr jne set_break_continue ;if not same, then o.k. cmp word ptr [DevBrkAddr],0 je break_failed ;[DevBrkAddr+2]=[memhi] & [DevBrkAddr]=0 set_break_continue: call RoundBreakAddr pop ax clc ret break_failed: pop ax stc ret DevSetBreak endp ; ;---------------------------------------------------------------------------- ; ; procedure : DevBreak ; ; Input : DevLoadAddr & DevBrkAddr ; Output : none ; ; Marks a succesful install of a device driver ; Sets device size field in sub-arena & ; Updates Free ptr in UMB or adjusts memhi ; ;---------------------------------------------------------------------------- ; DevBreak proc near assume ds:nothing, es:nothing push ds mov ax, DevLoadAddr mov bx, word ptr [DevBrkAddr+2] dec ax ; seg of sub-arena mov ds, ax inc ax ; Back to Device segment sub ax, bx neg ax ; size of device in paras mov ds:[devmark_size], ax ; store it in sub-arena cmp DeviceHi, 0 je db_lo mov DevUMBFree, bx ; update Free ptr in UMB jmp short db_exit db_lo: mov memhi, bx mov memlo, 0 db_exit: pop ds ret DevBreak endp ; ;---------------------------------------------------------------------------- ; ; procedure : ParseSize ; ; Parses the command line for SIZE= command ; ; ES:SI = command line to parsed ; ; returns ptr to command line after SIZE= option in ES:SI ; updates the DevSizeOption variable with value supplied ; in SIZE=option ; Returns carry if the SIZE option was invalid ; ;---------------------------------------------------------------------------- ; ParseSize proc near assume ds:nothing, es:nothing mov DevSizeOption, 0 ; init the value mov word ptr DevCmdLine, si mov word ptr DevCmdLine+2, es call SkipDelim cmp word ptr es:[si], 'IS' jne ps_no_size cmp word ptr es:[si+2], 'EZ' jne ps_no_size mov al, es:[si+4] call delim jne ps_no_size add si, 5 call GetHexNum jc ps_err mov DevSizeOption, ax call SkipDelim ps_no_size: clc ret ps_err: stc ret ParseSize endp ; ;---------------------------------------------------------------------------- ; ; procedure : SkipDelim ; ; Skips delimiters in the string pointed to by ES:SI ; Returns ptr to first non-delimiter character in ES:SI ; ;---------------------------------------------------------------------------- ; SkipDelim proc near assume ds:nothing, es:nothing sd_next_char: mov al, es:[si] call delim jnz sd_ret inc si jmp sd_next_char sd_ret: ret SkipDelim endp ; ;---------------------------------------------------------------------------- ; ; procedure : GetHexNum ; ; Converts an ascii string terminated by a delimiter into binary. ; Assumes that the ES:SI points to a Hexadecimal string ; ; Returns in AX the number number of paras equivalent to the ; hex number of bytes specified by the hexadecimal string. ; ; Returns carry in case it encountered a non-hex character or ; if it encountered crlf ; ;---------------------------------------------------------------------------- ; GetHexNum proc near assume ds:nothing, es:nothing xor ax, ax xor dx, dx ghn_next: mov bl, es:[si] cmp bl, cr je ghn_err cmp bl, lf je ghn_err push ax mov al, bl call Delim pop ax jz ghn_into_paras call GetNibble jc ghn_err mov cx, 4 ghn_shift1: shl ax, 1 rcl dx, 1 loop ghn_shift1 or al, bl inc si jmp ghn_next ghn_into_paras: add ax, 15 adc dx, 0 test dx, 0fff0h jnz ghn_err mov cx, 4 ghn_shift2: clc rcr dx, 1 rcr ax, 1 loop ghn_shift2 clc ret ghn_err: stc ret GetHexNum endp ; ;---------------------------------------------------------------------------- ; ; procedure : GetNibble ; ; Convert one nibble (hex digit) in BL into binary ; ; Retruns binary value in BL ; ; Returns carry if BL contains non-hex digit ; ;---------------------------------------------------------------------------- ; GetNibble proc near cmp bl, '0' jb gnib_err cmp bl, '9' ja is_it_hex sub bl, '0' ; clc ret is_it_hex: cmp bl, 'A' jb gnib_err cmp bl, 'F' ja gnib_err sub bl, 'A'- 10 ; clc ret gnib_err: stc ret GetNibble endp ; ; ;============================================================================ ;============================================================================ ; ;---------------------------------------------------------------------------- ; ; procedure : AllocUMB ; ; Allocate all UMBs and link it to DOS arena chain ; ;---------------------------------------------------------------------------- ; AllocUMB proc near call InitAllocUMB ; link in the first UMB jc au_exit ; quit on error au_next: call umb_allocate ; allocate jc au_coalesce call umb_insert ; & insert till no UMBs jmp short au_next au_coalesce: call umb_coalesce ; coalesce all UMBs au_exit: ret AllocUMB endp ; ;---------------------------------------------------------------------------- ; ; procedure : InitAllocUMB ; ;---------------------------------------------------------------------------- ; InitAllocUMB proc near call IsXMSLoaded jnz iau_err ; quit on no XMS driver mov ah, 52h int 21h ; get DOS DATA seg mov DevDOSData, es ; & save it for later mov ax, 4310h int 2fh mov word ptr DevXMSAddr, bx ; get XMS driver address mov word ptr DevXMSAddr+2, es cmp FirstUMBLinked, 0 ; have we already linked a UMB? jne @f ; quit if we already did it call LinkFirstUMB ; else link the first UMB jc iau_err mov FirstUMBLinked, 0ffh ; mark that 1st UMB linked @@: clc ret iau_err: stc ret InitAllocUMB endp ;------------------------------------------------------------------------- ; ; Procedure Name : umb_allocate ; ; Inputs : DS = data ; ; Outputs : if UMB available ; Allocates the largest available UMB and ; BX = segment of allocated block ; DX = size of allocated block ; NC ; else ; CY ; ; Uses : BX, DX ; ;------------------------------------------------------------------------- umb_allocate proc near push ax mov ah, XMM_REQUEST_UMB mov dx, 0ffffh ; try to allocate largest ; possible call dword ptr DevXMSAddr ; dx now contains the size of ; the largest UMB or dx, dx jz ua_err mov ah, XMM_REQUEST_UMB call dword ptr DevXMSAddr cmp ax, 1 ; Q: was the reqst successful jne ua_err ; N: error clc ua_done: pop ax ret ua_err: stc jmp short ua_done umb_allocate endp ;--------------------------------------------------------------------------- ; ; Procedure Name : umb_insert ; ; Inputs : DOSDATA:UMB_HEAD = start of umb chain ; : BX = seg address of UMB to be linked in ; : DX = size of UMB to be linked in paras ; ; DS = data ; ; Outputs : links the UMB into the arena chain ; ; Uses : AX, CX, ES, DX, BX ; ;--------------------------------------------------------------------------- umb_insert proc near push ds mov ds, [DevDOSData] mov ds, ds:[UMB_ARENA] ; es = UMB_HEAD mov ax, ds mov es, ax ui_next: cmp ax, bx ; Q: is current block above ; new block ja ui_insert ; Y: insert it ; Q: is current block the ; last cmp es:[arena_signature], arena_signature_end jz ui_append ; Y: append new block to chain ; N: get next block mov ds, ax ; M005 call get_next ; ax = es = next block jmp short ui_next ui_insert: mov cx, ds ; ds = previous arena inc cx ; top of previous block sub cx, bx neg cx ; cx = size of used block mov ds:[arena_signature], arena_signature_normal mov ds:[arena_owner], 8 ; mark as system owned mov ds:[arena_size], cx mov word ptr ds:[arena_name], 'CS' ; prepare the arena at start of new block mov es, bx mov es:[arena_signature], arena_signature_normal mov es:[arena_owner], arena_owner_system ; mark as free sub dx, 2 ; make room for arena at ; start & end of new block mov es:[arena_size], dx ; prepare arena at end of new block add bx, dx inc bx mov es, bx ; es=arena at top of new block inc bx ; bx=top of new block ; ax contains arena just above ; this block sub ax, bx ; ax = size of used block mov es:[arena_signature], arena_signature_normal mov es:[arena_owner], 8 ; mark as system owned mov es:[arena_size], ax mov word ptr es:[arena_name], 'CS' jmp short ui_done ui_append: ; es = arena of last block add ax, es:[arena_size] ; ax=top of last block-1 para sub es:[arena_size], 1 ; reflect the space we are ; going to rsrv on top of this ; block for the next arena. mov es:[arena_signature], arena_signature_normal mov cx, ax ; cx=top of prev block-1 inc ax sub ax, bx ; ax=top of prev block - ; seg. address of new block neg ax mov es, cx ; ds = arena of unused block mov es:[arena_signature], arena_signature_normal mov es:[arena_owner], 8 ; mark as system owned mov es:[arena_size], ax mov word ptr es:[arena_name], 'CS' ; prepare the arena at start of new block mov es, bx mov es:[arena_signature], arena_signature_end mov es:[arena_owner], arena_owner_system ; mark as free dec dx ; make room for arena mov es:[arena_size], dx ui_done: pop ds ret umb_insert endp ; ;---------------------------------------------------------------------------- ; ;** umb_coalesce - Combine free blocks ahead with current block ; ; Coalesce adds the block following the argument to the argument block, ; iff it's free. Coalesce is usually used to join free blocks, but ; some callers (such as $setblock) use it to join a free block to it's ; preceeding allocated block. ; ; EXIT 'C' clear if OK ; (ds) unchanged, this block updated ; (ax) = address of next block, IFF not at end ; 'C' set if arena trashed ; USES cx, di, ds, es ; ;---------------------------------------------------------------------------- ; umb_coalesce proc near xor di, di mov es, [DevDOSData] mov es, es:[UMB_ARENA] ; es = UMB_HEAD uc_nextfree: mov ax, es mov ds, ax cmp es:[arena_owner], di ; Q: is current arena free jz uc_again ; Y: try to coalesce with next block ; N: get next arena call get_next ; es, ax = next arena jc uc_done jmp short uc_nextfree uc_again: call get_next ; ES, AX <- next block jc uc_done uc_check: cmp es:[arena_owner],di ; Q: is arena free jnz uc_nextfree ; N: get next free arena ; Y: coalesce mov cx,es:[arena_size] ; cx <- next block size inc cx ; cx <- cx + 1 (for header size) add ds:[arena_size],cx ; current size <- current size + cx mov cl,es:[di] ; move up signature mov ds:[di],cl jmp short uc_again ; try again uc_done: ret umb_coalesce endp ; ;---------------------------------------------------------------------------- ; ;** get_next - Find Next item in Arena ; ; ENTRY dS - pointer to block head ; EXIT AX,ES - pointers to next head ; 'C' set iff arena damaged ; ;---------------------------------------------------------------------------- ; get_next proc near cmp byte ptr ds:[0], arena_signature_end je gn_err mov ax,ds ; ax=current block add ax,ds:[arena_size] ; ax=ax + current block length inc ax ; remember that header! mov es, ax clc ret gn_err: stc ret get_next endp ; ;---------------------------------------------------------------------------- ; ; procedure : LinkFirstUMB ; ;---------------------------------------------------------------------------- ; LinkFirstUMB proc near call umb_allocate jc lfu_err ; bx = segment of allocated UMB ; dx = size of UMB int 12h ; ax = size of memory mov cl, 6 shl ax, cl ; ax = size in paragraphs mov cx, ax ; cx = size in paras sub ax, bx ; ax = - size of unused block neg ax sub cx, 1 ; cx = first umb_arena mov es, cx ; es = first umb_arena mov es:[arena_signature], arena_signature_normal mov es:[arena_owner], 8 ; mark as system owned mov es:[arena_size], ax mov word ptr es:[arena_name], 'CS' ; put in the arena for the first UMB mov es, bx ; es has first free umb seg mov es:[arena_signature], arena_signature_end mov es:[arena_owner], arena_owner_system ; mark as free dec dx ; make room for arena mov es:[arena_size], dx mov es, [DevDOSData] mov di, UMB_ARENA mov es:[di], cx ; initialize umb_head in DOS ; data segment with the arena ; just below Top of Mem ; we must now scan the arena chain and update the size of the last ; arena mov di, DOS_ARENA mov es, word ptr es:[di] ; es = start arena xor di, di scan_next: cmp byte ptr es:[di], arena_signature_end jz got_last mov ax, es add ax, es:[arena_size] inc ax mov es, ax jmp short scan_next got_last: ;; -williamh- we reserved the last paragraph for UMB_HEAD already. ;; refer to sysinit1.asm!goinit ;; The following instruction was commentted out for this reason. ;; sub es:[arena_size], 1 ;; mov es:[arena_signature], arena_signature_normal clc ret lfu_err: stc ret LinkFirstUMB endp ; ;---------------------------------------------------------------------------- ; ; procedure : ShrinkUMB ; ; Shrinks the current UMB in use, so that the unused portions ; of the UMB is given back to the DOS free mem pool ; ;---------------------------------------------------------------------------- ; public ShrinkUMB ShrinkUMB proc near cmp DevUMBAddr, 0 je su_exit push es push bx mov bx, DevUMBFree sub bx, DevUMBAddr mov es, DevUMBAddr mov ax, 4a00h int 21h mov ax, es dec ax mov es, ax mov word ptr es:[arena_owner], 8 pop bx pop es su_exit: ret ShrinkUMB endp ;M002 - BEGIN ; ;---------------------------------------------------------------------------- ; ; procedure : UnlinkUMB ; ; Unlinks the UMBs from the DOS arena chain ; ;---------------------------------------------------------------------------- ; public UnlinkUMB UnlinkUMB proc near push ds push es cmp FirstUMBLinked, 0 je ulu_x ; nothing to unlink mov es, DevDOSData ; get DOS data seg mov ds, es:[DOS_ARENA] mov di, es:[UMB_ARENA] ulu_next: call get_next jc ulu_x cmp di, ax ; is the next one UMB ? je ulu_found mov ds, ax jmp ulu_next ulu_found: mov ds:[arena_signature], 'Z' ulu_x: pop es pop ds ret UnlinkUMB endp ;M002 - END ; ========================================================================= ; sysinitseg ends end