; snoop.asm ; ; Written By Ray Smith ; Bix Name: rjsmith ; Copyright (c) 1987, Smith, Brittain & Associates. All rights reserved. ; ; ;***************************************************************************** ; Usage: snoop [/d] [/e] [/i] [/m] [/a] [/x] [/n] ; ; where d = resident and installed device drivers ; e = system equipment and configuration ; i = Invars Table ; m = Memory Control Blocks ; a = all of the above ; x = all of the above except /e ; n = do Not pause the display, allowing the output to be ; redirected to a file in a continuous stream. ; ;***************************************************************************** ; ; .8087 cseg segment para public 'code' org 100h ; this will be a .com file assume cs:cseg,ds:cseg ; all seg regs point to start of PSP main proc far ; begin: jmp entry ; go around the data ; ;*********************************************************************** ;* Explanation of bit settings in byte "config_flag" ;*********************************************************************** ; ; Value 8 4 2 1 8 4 2 1 ; +-----------------+-----------------+ ; Bit | | | ; Number | 07 06 05 04 | 03 02 01 00 | ; | | | ; +-----------------+----------------------------------------+ ; 01 | | | | | | | | 1 = PC/AT Class Machine | ; 02 | | | | | | | 1 = Enhanced BIOS Present | ; 04 | | | | | | 1 = Enhanced Keyboard Attached | ; 08 | | | | | 1 = Compaq DeskPro 386 or klone | ; 10 | | | | 1 = PC/XT Class Machine | ; 20 | | | 1 = PC Class Machine | ; 40 | | 1 = PC Convertible | ; 80 | 1 = PC/XT 089 | ; +----------------------------------------------------------+ ; ; display_flag db 0h config_flag db 0h equ_flag db 0h inv_flag db 0h drv_flag db 0h pse_flag db 0h mem_flag db 0h cpu_flag db 0h ps2_flag db 0h sys_flag db 0h env_flag db 0h psp_flag db 0h tsr_flag db 0h mt_flag db 0h data_flag db 0h switchar db 2Fh ; "/" for command line switches pathchar db 5Ch ; "\" for path name delimiter switch_err db 0h scan_code db 44h loop_count dw 0h arg_cnt dw 0h argc db 0h optcnt db 0h portcnt db 0h total_pages dw 0h avail_pages dw 0h firstenv db 01h firstpsp db 01h firstmcb db 01h firstsys db 01h one db 01h linecnt db 0h de_allocmsg db 'Deallocated$' systype db 'DOS $' psptype db 'PSP $' envtype db 'ENV $' datatype db 'DATA$' mttype db 'Unkn$' lastdpb db 'Chain Ends$' notread db 'nr$' ; drive was not read dos_vers dw 0h emm_vers db 0h rom_flag db 0FFh get_key db 0h ; default BIOS Int 16h function to read a key avail_c db 01h ; default BIOS Int 16h function to check avail char get_sts db 02h ; default BIOS Int 16h function to check shift status control dw 0h ; save 80x87 control word sav_code db 0h sav_addr dw 0h sav_off dw 0h invar_seg dw 0h invar_off dw 0h dpb_seg dw 0h dpb_off dw 0h sav_name db ' ' db '$' type_drv dw 0h devh_seg dw 0h ; segment address NUL device driver devh_off dw 0h ; offset address NUL device driver next_seg dw 0h ; next seg addr next_off dw 0h ; next off addr colon db ':' emm_name db 'EMMXXXX0' ; Guaranteed emm device driver file name blank db 20h ourcopy db 0Dh,0Ah,' Copyright (c) 1987 Smith, Brittain & Associates. ' db 'All Rights Reserved.$' mcbseg dw 0h filename db ' $' dataname db ' $' db 'Written By Raymond J. Smith' msg1 db 0Dh,0Ah,' Machine is an IBM PC/AT or AT klone $' msg1A db 0Dh,0Ah,' Machine is an IBM PC/AT Model 339 $' msg1B db 0Dh,0Ah,' Machine is an IBM PC/AT Model 239 $' msg1C db 0Dh,0Ah,' Machine is an IBM PC/AT Model 099 $' msg1D db 0Dh,0Ah,' Machine is a Compaq Dekspro 386 or compatible$' msg1E db 0Dh,0Ah,' Machine is an IBM Personal System/2 Model 30$' msg1F db 0Dh,0Ah,' Machine is an IBM Personal System/2 Model 50$' msg1G db 0Dh,0Ah,' Machine is an IBM Personal System/2 Model 60$' msg1H db 0Dh,0Ah,' Machine is an IBM Personal System/2 Model 80$' msg2 db 0Dh,0Ah,' Enhanced BIOS is present $' msg3 db 0Dh,0Ah,' Enhanced Keyboard is attached $' msg4 db 0Dh,0Ah,' Machine ID byte contains code ==> $' msg5 db 0Dh,0Ah,' No Enhanced BIOS is present $' msg6 db 0Dh,0Ah,' No Enhanced Keyboard is attached $' msg7 db 0Dh,0Ah,' Press any key to continue... $' msg9 db 0Dh,0Ah,' EGA is active adapter $' msg10 db 0Dh,0Ah,' EGA is active and is monochrome $' msg11 db 0Dh,0Ah,' EGA is not active, a MDA or Hercules card is active $' msg12 db 0Dh,0Ah,' EGA is not active, a CGA is active $' msg14 db 0Dh,0Ah,' EGA has 64kb graphics memory installed $' msg15 db 0Dh,0Ah,' EGA has 128kb graphics memory installed $' msg16 db 0Dh,0Ah,' EGA has 192kb graphics memory installed $' msg17 db 0Dh,0Ah,' EGA has 256kb graphics memory installed $' msg18 db 0Dh,0Ah,' Enhanced Color Display is attached $' msg18A db 0Dh,0Ah,' Enhanced Color Display in Color Graphics mode is attached $' msg19 db 0Dh,0Ah,' Normal Color Display is attached $' msg19A db 0Dh,0Ah,' CGA is active$' msg20 db 0Dh,0Ah,' Monochrome Display is active$' msg21 db 0Dh,0Ah,' Machine is an IBM PC/XT or XT klone $' msg22 db 0Dh,0Ah,' Machine is an IBM PC or PC klone $' msg23 db 0Dh,0Ah,' Machine is an IBM PC convertible $' msg24 db 0Dh,0Ah,' Machine is a PC/XT Model 089 $' msg25 db 0Dh,0Ah,' Machine is a PC/XT Model 286 $' msg26 db 0Dh,0Ah,' EGA switches improperly set $' msg27 db 0Dh,0Ah,' 8087 is installed $' msg28 db 0Dh,0Ah,' 80287 is installed $' msg29 db 0Dh,0Ah,' no NDP is installed$' msg30 db ' exTEnded memory installed$',0Dh,0Ah msg31 db ' exPAnded memory installed$' msg31A db ' total EMS pages$' msg31B db ' available EMS pages$' msg31C db 0Dh,0Ah,' EMM Version: $' msg32 db 0Dh,0Ah,' no$' msg33 db 0Dh,0Ah,' System is operating under DOS Version $' msg33A db 0Dh,0Ah,' Switch character currently in effect is $' msg33B db 0Dh,0Ah,' DOS Int 21h Function 37h not responding$' msg34 db ' is installed$' msg35 db '3.00$' msg36 db '3.10$' msg37 db '3.20$' msg37A db '3.30$' msg37B db '3.40$' msg38 db '2.00$' msg39 db '2.10$' msg40 db 'is unknown$' msg41 db 'kb$' msg42 db ' base memory installed$',0Dh,0Ah msg43 db ' OR the EMM is not installed$' msg44 db 'LPT1: $' msg45 db 'LPT2: $' msg46 db 'LPT3: $' msg47 db 'COM1: $' msg48 db 'COM2: $' msg48A db 'COM3: $' msg48B db 'COM4: $' msg49 db 'No Parallel Ports active$' msg50 db 'No Serial Ports active$' msg98 db '2.x$' msg99 db '3.x$' copyrite db 'ROM BIOS Copyright ==> $' biosdate db 'ROM BIOS dated $' egacopy db 'EGA BIOS Copyright ==> $' egadate db 'EGA BIOS dated $' baddrv db 'Corrupted EMM Driver $' badbrd db 'Malfunction in exPAnded memory hardware$' romid db 'Adapter ROM signature found at segment $' noroms db 'No adapter ROMs detected $' newline db 0Dh,0Ah,'$' indent db ' $' rom_sig dw 0AA55h tbuff db 255 dup('$') char_dev db 'Char $' blk_dev db 'Block $' clk_dev db 'Clock $' cmndmsg db 'COMMAND $' sysmsg db 'System $' freemsg db 'Free $' mtblkmsg db ' $' unknmsg db 'Unknown $' envmsg db 'Process Env $' mastenv db 'Master Env $' tsrmsg db 'TSR $' resdmsg db 'Resident part$' datamsg db 'Process Data $' thismsg db 'Transient $' drvmsg db 'Dev Drvs, etc$' space1 db ' $' space2 db ' $' space3 db ' $' space4 db ' $' space5 db ' $' space6 db ' $' space7 db ' $' space8 db ' $' space9 db ' $' space10 db ' $' space11 db ' $' space12 db ' $' space13 db ' $' space14 db ' $' scr1 db 0Dh,0Ah,' Partial Contents of DOS "Invar" Table' db 0Dh,0Ah,' ' db 0Dh,0Ah,' Invar First 1st Dir Size of Drive/Directory DOS "Busy"' db 0Dh,0Ah,' Table DPB Table Buffer 1 Cache Table Flag' db 0Dh,0Ah,' Seg : Off Seg : Off Seg : Off Buffer Seg : Off Seg : Off' db 0Dh,0Ah,' --------- --------- --------- ------- --------- --------- $' scr1A db 0Dh,0Ah,' Contents of DPB Table By Drive' db 0Dh,0Ah,' Dev Drvr Next DPB' db 0Dh,0Ah,'Drv DU BPC SPC RS CF MDE FUS TCC SIF FDS Hdr Addr MD Address' db 0Dh,0Ah,'-- -- ---- --- ---- -- ---- ---- ---- --- ---- --------- -- ---------$' scr2 db 0Dh,0Ah,' Installed Device Drivers' db 0Dh,0Ah,' Name or Header Address Entry Points DOS' db 0Dh,0Ah,'Type # Units Seg : Off Strat Interpt Attrib Version' db 0Dh,0Ah,'----------------------------------------------------------------------------$' scr3 db 0Dh,0Ah,' Memory Allocation ' db 0Dh,0Ah,' ' db 0Dh,0Ah,'MCB Points Paras Hooked' db 0Dh,0Ah,'Addr To Blk Alloc Type Owner Comment Cmnd Line Vectors' db 0Dh,0Ah,'---- ---- ---- ---- -------- ----------- --------- -------------------$' cnt dw 00h vectcnt dw 00h blk_beg dw 00h blk_end dw 00h usemsg db 0Dh,0Ah,' Usage: snoop [/d] [/e] [/i] [/m] [/a] [/n]',0Dh,0Ah db 0Dh,0Ah db 0Dh,0Ah,' where d = list device drivers' db 0Dh,0Ah,' e = list equipment' db 0Dh,0Ah,' i = list Invars Table and DPBs' db 0Dh,0Ah,' m = list Memory Control Blocks' db 0Dh,0Ah,' a = list all of the above' db 0Dh,0Ah,' n = do Not pause the display' db 0Dh,0Ah,' x = list all of the above except e' db 0Dh,0Ah,' (for non-IBM BIOS compatible machines)$' ; ;*********************************************************************** ;* Beginning of Code Seg ;*********************************************************************** entry: call switch_char ; go see what they're using for paths mov switch_err,al ; check for error and store for later call chk_switch ; get our command line switches mov ah,30h ; get dos ver num int 21h ; go do it xchg ah,al ; turn it around mov dos_vers,ax ; need for NUL device driver location cmp ax,0200h ; 2.00 or greater? jae oz_ok bad_oz: jmp quit ; need 2.0 or greater oz_ok: mov dx,offset ourcopy ; display our copyright message call dostty mov dx,offset newline call dostty cmp equ_flag,0FFh ; switch set for equipment list? je equip_tests ; yes jmp invar_chk ; no - bypass equipment list equip_tests: clc ; clear the carry flag for error rtn mov ah,0C0h ; get configuration parameters int 15h ; avaialable on AT class machines only sti ; int 15h does not reenable interrupts jc is_old ; it's a PC cmp ah,80h ; return value if original PC je is_old ; 86h is returned on all PS/2 models cmp ah,86h ; return value if not new machine jne is_new ; 86h is returned on all PS/2 models is_old: jmp test_more ; it's either a PS/2 or PC PC/XT class is_new: ; determine machine type cmp ax,00FFh ; return value if PS/2 jne not_new_mod ; call chk_ps2 cmp ps2_flag,0h je not_new_mod ; jmp at_tests not_new_mod: cmp byte ptr es:[bx+2],0FCh ; AT class machine ID je chk_339 jmp test_more chk_339: cmp byte ptr es:[bx+3],01h ; check sub-model type byte je is_339 ; 1 means IBM AT/339 or Compaq 386 cmp byte ptr es:[bx+3],02h ; check sub-model type byte jne next_one jmp xt_286 ; a 2 means it's an IBM XT/286 next_one: cmp byte ptr es:[bx+3],0h ; check sub-model type byte je is_239 ; 0 means it's an IBM AT/239 or 099 jmp test_more ; (note:AT/239 has rom 06/10/85) is_339: ; mach id byte is FCh - means little call chk_cpu ; see if 386 or 286 cpu cmp byte ptr cs:cpu_flag,03h ; is it a 386 cpu? je is_386 ; is_286: ; it's a 286 cpu or byte ptr cs:config_flag,01h ; indicate PC/AT mov dx,offset msg1A ; AT class message call dostty jmp at_tests is_386: or byte ptr cs:config_flag,09h ; indicate PC/AT class & 386 class mov dx,offset msg1D ; Compaq DeskPro 386 Class message call dostty jmp at_tests is_239: or byte ptr cs:config_flag,01h ; indicate PC/AT cmp byte ptr es:[bx+4],0h ; check bios level byte je is_099 ; 0 means it's an IBM AT/099 cmp byte ptr es:[bx+4],01 ; check bios level byte jne test_more ; 1 means it's an IBM AT/239 mov dx,offset msg1B ; Einen Klonen Machinen message call dostty ; if all tests fail, assume klone jmp at_tests ; test for AT type stuff is_099: mov dx,offset msg1C ; original 6 mHz AT call dostty jmp at_tests ;*********************************************************************** ;* Determine Machine Type for non_AT type machines. * ;*********************************************************************** test_more: mov ax,0F000h ; seg address of rom bios mov es,ax ; establish addressibility mov ax,word ptr es:[0FFFEh] ; offset of rom bios machine id byte call chk_mod30 ; see if PS/2 Model 30 first cmp ps2_flag,30h ; is it a PS/2 model 30? jne not_a_30 ; if greater, is model 50/60/80 jmp chk_mem not_a_30: cmp al,0FCh ; not PS/2: PC/AT? Compaq 386? XT/286? je at_ok ; jmp not_at ; it's not PS/2 or AT class at_ok: or byte ptr cs:config_flag,01h ; indicate PC/AT mov dx,offset msg1 ; call dostty jmp at_tests xt_286: or byte ptr cs:config_flag,01h ; indicate PC/AT class machine mov dx,offset msg25 ; call dostty ;*********************************************************************** ;* These tests are applicable to AT class machines only. * ;*********************************************************************** ; at_tests: ; test for base memory int 12h ; BIOS int 12h returns memory size push ax ; this is safe on an AT mov dx,offset newline call dostty mov dx,offset indent call dostty pop dx call dec16out mov dx,offset msg41 ; kb call dostty mov dx,offset msg42 ; bytes call dostty ; ;**************************************************************************** ;* Test for presence and amount of exTEnded memory (AT class machines only) * ;**************************************************************************** mov ax,8800h int 15h cmp ax,0h je noexten push ax mov dx,offset newline call dostty mov dx,offset indent call dostty pop dx call dec16out ; convert binary to decimal & display mov dx,offset msg41 ; kb call dostty jmp extend noexten: mov dx,offset msg32 ; no exTEnded memory installed call dostty mov dx,offset msg30 call dostty jmp chk_emm ; go see if exPAnded memory installed extend: mov dx,offset msg30 ; exTEnded memory is installed call dostty jmp chk_emm ; go see if exPAnded memory installed ; ;*********************************************************************** ;* Test for machine type if not AT class. * ;*********************************************************************** not_at: cmp ps2_flag,30h ; is this a PS/2 Model 30? je chk_mem ; if yes, go right to mem chk cmp al,0FEh ; is this a PC/XT ? jne not_xt ; set flag if it is, branch if not or byte ptr cs:config_flag,10h ; indicate PC/XT mov dx,offset msg21 ; call dostty jmp chk_mem not_xt: cmp al,0FFh ; is this a PC ? jne not_pc ; set flag if it is, branch if not or byte ptr cs:config_flag,20h ; indicate PC mov dx,offset msg22 ; call dostty jmp chk_mem not_pc: cmp al,0F9h ; is this a PC Convertible? jne xt_089 ; set flag if it is, branch if not or byte ptr cs:config_flag,40h ; indicate PC Convertible mov dx,offset msg23 ; call dostty jmp chk_mem xt_089: cmp al,0FBh ; is this a new PC/XT-089? jne unk_id ; set flag if it is, branch if not or byte ptr cs:config_flag,80h ; indicate PC/XT-089 mov dx,offset msg24 ; call dostty jmp chk_mem unk_id: mov dx,offset msg4 ; don't recognize this Klone call dostty mov sav_code,al ; display the actual machine ID byte mov cx,1 ; count of bytes to display lea bx,[sav_code] call show_bytes ; ;*********************************************************************** ; Test for amount of conventional memory. * ;*********************************************************************** chk_mem: ; test for main memory if not AT class ; machine int 12h ; BIOS int 12h returns memory size push ax ; risky: only returns switch settings mov dx,offset newline call dostty mov dx,offset indent call dostty pop dx call dec16out mov dx,offset msg41 ; kb call dostty mov dx,offset msg42 ; bytes call dostty ; ;*********************************************************************** ;* Test for presence and amount of LIM/EMS (exPAnded) memory ;*********************************************************************** ; chk_emm: mov ah,35h mov al,67h int 21h mov di,0Ah push cs pop ds mov si,offset emm_name ; guaranteed device driver name mov cx,8 ; length of file name cld repz cmpsb jz chk_ems_hardware jmp no_emm ;*********************************************************************** ;* Find out if hardware is functional using Int 67h fcn 40h ;*********************************************************************** chk_ems_hardware: mov ah,40h ; int 67h cmp ah,0h ; zero return code means all ok je emm_ok cmp ah,80h ; je bad_drv bad_hard: mov dx,offset newline ; call dostty mov dx,offset indent call dostty mov dx,offset badbrd ; bad emm hardware call dostty jmp chk_bios bad_drv: mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset baddrv ; bad emm driver image call dostty jmp chk_bios ; ;*********************************************************************** ;* Find out how many pages present/available using Int 67h fcn 03h ;*********************************************************************** emm_ok: mov dx,offset newline call dostty mov dx,offset indent call dostty mov ah,42h ; get number of pages int 67h or ah,ah jz no_err ; put error messages here jmp chk_bios no_err: mov word ptr total_pages,dx ; dx holds total number of 16kb pages mov word ptr avail_pages,bx ; bx holds number of available pages call dec16out ; display it mov dx,offset msg31A ; call dostty mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,word ptr avail_pages call dec16out ; display it mov dx,offset msg31B ; call dostty ; ;*********************************************************************** ;* Find out the EMS version using Int 67h fcn 07h ;*********************************************************************** ; mov ah,46h ; get emm version int 67h ; al = version # in BCD mov byte ptr emm_vers,al ; Major revision in upper 4 bits ; Minor revision in lower 4 bits mov dx,offset msg31C ; call dostty mov al,byte ptr emm_vers and ax,00F0h ; isolate major ver # mov cl,4 ; shift to low bits shr ax,cl add al,30h ; make it ascii mov dl,al ; set it up for stdout call stdout ; display major version # mov dl,2Eh call stdout ; display a period mov al,byte ptr emm_vers ; get emm version and ax,000Fh ; isolate minor version add al,30h ; make it ascii mov dl,al ; set it up for stdout call stdout ; display minor version # jmp chk_bios no_emm: mov dx,offset msg32 ; no exPAnded memory found... call dostty mov dx,offset msg31 call dostty mov dx,offset msg43 ; ...or the emm not installed call dostty ; ;*********************************************************************** ;* display copyright and rom release date and test for enhanced BIOS * ;*********************************************************************** chk_bios: ; display copyright slug mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset copyrite ; copyright header string call dostty cld push es push ds push ds pop es ; destination string address in es:di mov ax,0F000h ; source string address in ds:si mov ds,ax ; ...location of IBM AT copyright xor ax,ax mov cx,10h ; count of words in copyright test byte ptr cs:config_flag,10h ; is this an older PC/XT? jz getcopy mov ax,0E000h ; IBM XT copyright is higher up in rom mov cx,0Bh ; count of words (XT is shorter) getcopy: mov bx,cx ; shl bx,1 ; multiply by 2 to get offset of mov si,ax ; terminator character in dest string mov di,offset es:tbuff rep movsw pop ds pop es mov byte ptr tbuff+[bx],'$' ; insert terminator mov bx, offset tbuff scan: cmp byte ptr[bx],'$' ; are we done? je end_scan ; go display it cmp byte ptr[bx],' ' ; less than a space? jb hide_it ; cmp byte ptr[bx],'~' ; greater than a tilde jna bump_bx ; if not it's printable hide_it: mov byte ptr[bx],20h ; make nonsense characters a space bump_bx: inc bx ; increment the address jmp scan ; go do it again end_scan: mov dx,offset tbuff ; call dostty push es push ds push ds pop es ; destination string address in es:di mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset biosdate ; date header call dostty mov ax,0F000h ; source string address in ds:si mov ds,ax mov ax,0FFF5h ;offset of rom release date mov si,ax mov di,offset es:tbuff mov cx,04h ; count of words rep movsw pop ds pop es mov byte ptr tbuff[08h],'$' ; insert string terminator mov dx,offset tbuff call dostty ; check for enhanced bios mov ah,2 ; get shift status (old function) int 16h ; mov bl,al ; Save shift status not al ; change al (invert all bits) mov ah,12h ; new BIOS extended shift status int 16h ; cmp al,bl ; is result the same from both calls? jne next1 ; if not, this is not enhanced BIOS or byte ptr cs:config_flag,02h ; indicate enhanced BIOS present mov ax,40h ; seg address of BIOS data area mov es,ax ; establish addressibility mov al,byte ptr es:[96h] ; offset of BIOS @KB_FLAG_3 byte test al,10h ; is enhanced keyboard attached? jz next1 ; set flag if it is, branch if not or byte ptr cs:config_flag,04h ; indicate enhanced keyboard attached test byte ptr cs:config_flag,06h ; could be new XTs with enhanced BIOS jz next1 ; branch if not add get_key,10h ; if new bios... add avail_c,10h ; ...and new keyboard... add get_sts,10h ; ...add 10h to get extended functions next1: test byte ptr cs:config_flag,02h ; is enhanced BIOS present? jz old_bios ; branch if not mov dx,offset msg2 call dostty jmp new_bios old_bios: mov dx,offset msg5 call dostty new_bios: test byte ptr cs:config_flag,04h ; is enhanced keyboard present? jz not_enhanced ; branch if not mov dx,offset msg3 ; call dostty mov scan_code,86h ; ascii code for F12 jmp scan_rom not_enhanced: mov dx,offset msg6 call dostty ;*********************************************************************** ;* Scan ROM for BIOS IDs... ;*********************************************************************** scan_rom: mov dx,0C000h ; start point for rom signature scan mov di,word ptr rom_sig ; rom signature is 55 AA hex scan_loop: mov es,dx xor bx,bx ; offset zero mov ax,es:[bx] ; cmp ax,di ; equal to 55 AA ? jnz next_blk ; if no, go increment block address mov ax,es ; get segment address for display push dx mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset romid ; ROM detected message call dostty call disp_hex mov al,'h' call stdout mov rom_flag,0h ; indicate an adapter ROM was found pop dx next_blk: add dx,80h ; point to next 2k address chk_addr: cmp dx,0F600h ; end of addresses where ROMs can be? jl scan_loop ; search for more if not no_roms: cmp rom_flag,0h ; was an adapter ROM found? je end_rom ; yes? bypass message mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset noroms ; no ROMs detected call dostty end_rom: ; ;*********************************************************************** ;* Check active display and adapter ;*********************************************************************** ; chkdisp: ; check for presence of an EGA first mov bx, 0FF10h ; see if EGA responds mov ah, 12h int 10h test bh, 0FEh ; bl has mem size jnz notega ; cl has switch settings jmp IsEga notega: ; see if MDA or CGA or HGC mov ax,40h ; seg address of BIOS data area mov es,ax ; establish addressibility mov al,byte ptr es:[10h] ; offset of video status byte and al,00110000b ; isolate bits 4 & 5 cmp al,30h ; is it monochrome card? je is_mono ; assume color if not mono mov dx,offset msg19A ; CGA is active adapter call dostty jmp chk_ndp is_mono: mov dx,offset msg20 ; MDA is active adapter call dostty jmp chk_ndp IsEga: call ega_copy ; bl and cl get clobbered mov al,byte ptr es:[87h] ; offset of EGA BIOS data byte INFO shl al,1 shl al,1 shl al,1 shl al,1 test al,0h ; look for EGA with color jnz nocolor ; if not, see if mono attached mov dx,offset msg9 ; EGA is active adapter call dostty mov al,byte ptr es:[88h] ; offset of EGA BIOS data byte INFO_3 shl al,1 shl al,1 shl al,1 shl al,1 test al,09h ; EGA with ECD in hi res mode jnz nothires ; set flag if it is, branch if not mov dx,offset msg18 ; call dostty jmp chkmem nothires: test al,01h ; EGA with ECD, EGA in CGA mode jnz noecd ; set flag if it is, branch if not mov dx,offset msg18A ; ECD is in CGD emulation mode call dostty jmp chkmem noecd: test al,0Eh ; EGA with Normal Color Display jnz nocolor ; set flag if it is, branch if not mov dx,offset msg19 ; call dostty jmp chkmem nocolor: test al,0Dh ; look for EGA with monochrome display jnz mono2 ; set flag if it is, branch if not mov dx,offset msg20 ; call dostty jmp chkmem mono2: test al,05h ; look for EGA with monochrome display jnz badswitch ; set flag if it is, branch if not mov dx,offset msg20 ; call dostty jmp chkmem badswitch: ; switches must be set incorrectly mov dx,offset msg25 ; call dostty ; ;*********************************************************************** ;* Test for amount of graphics memory on EGA ;*********************************************************************** ; chkmem: mov ax,40h mov es,ax mov al,byte ptr es:[87h] ; offset of EGA BIOS data byte INFO and al,60h ; get rid of unwanted bits cmp al,60h ; is 256kb onboard? jne not256 ; no - check for 192kb mov dx,offset msg17 ; call dostty jmp chk_ndp not256: cmp al,40h ; is 192kb onboard? (is IBM EGA) jne not192 ; no - check for 128kb mov dx,offset msg16 ; call dostty jmp chk_ndp not192: cmp al,20h ; is 128kb onboard? (is IBM EGA) jne not128 ; no - check for 64kb mov dx,offset msg15 ; call dostty jmp chk_ndp not128: ; *must* be 64kb memory (is IBM EGA) mov dx,offset msg14 ; call dostty jmp chk_ndp ; ;*********************************************************************** ;* Test for presence of 80x87. * ;*********************************************************************** ; chk_ndp: fninit ; finit - see if 8087 installed sub ax,ax ; fn means no wait in case no ndp mov word ptr control,ax ; move two zeros to cntrl reg save area fnstcw control ; get 8087 control word - no wait mov ax,word ptr control ; put control word in ax and ax,037Fh ; default initialization state cmp ax,037Fh ; equal to 8087 here? jne no_ndp ; no - go around cmp ps2_flag,30h ; is it a PS/2 model 50 or above? ja is_80287 ; if so it's an 80287 test byte ptr config_flag,01h ; is this an 80286 class machine ? jz is_8087 ; if not, NDP is 8087 is_80287: mov dx,offset msg28 ; else it's an 80287 call dostty jmp getvers is_8087: mov dx,offset msg27 call dostty jmp getvers no_ndp: mov dx,offset msg29 call dostty ; ;*********************************************************************** ;* Display DOS Version ;*********************************************************************** ; getvers: mov dx,offset msg33 call dostty mov ax,dos_vers cmp ax,0200h ; 2.00 or greater? ja isver3 mov dx,offset msg38 ; it's 2.00 call dostty jmp endvers isver3: cmp ax,0300h ; 3.00 or greater? jae which3 mov dx,offset msg39 ; no, must be 2.10 call dostty jmp endvers which3: cmp al,0Ah ; 3.10 ? jne mustbe32 mov dx,offset msg36 call dostty jmp endvers mustbe32: cmp al,14h ; 3.20 ? jne mustbe33 mov dx,offset msg37 ; 3.20 call dostty jmp endvers mustbe33: cmp al,1Eh ; 3.30 ? jne unk_dos mov dx,offset msg37A ; 3.30 call dostty jmp endvers unk_dos: mov dx,offset msg40 ; unknown version number call dostty jmp quit endvers: ; ;*********************************************************************** ;* Display the active switch character ;*********************************************************************** cmp switch_err,0h ; was there a switchar error? je fcn_37_ok mov dx,offset msg33B call dostty fcn_37_ok: mov dx,offset msg33A call dostty mov al,switchar ; display the *current* switchar call stdout ; ;*********************************************************************** ;* Display the active Lpt: ports ;*********************************************************************** ; chklpt: mov ax,40h ; ROM BIOS data area segment address mov es,ax mov ax,word ptr es:[8h] ; offset of lpt I/O addresses cmp ax,0h je no_lpt1 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg44 ; lpt1: call dostty call disp_hex mov al,'h' call stdout no_lpt1: mov ax,word ptr es:[0Ah] cmp ax,0h je no_lpt2 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg45 ; lpt2: call dostty call disp_hex mov al,'h' call stdout no_lpt2: mov ax,word ptr es:[0Ch] cmp ax,0h je no_lpt3 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg46 ; lpt3: call dostty call disp_hex mov al,'h' call stdout no_lpt3: cmp portcnt,0h je no_prns jmp chkcom no_prns: mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg49 ; no lpt ports found call dostty ; ;*********************************************************************** ;* Display the active Com: ports ;*********************************************************************** ; chkcom: and portcnt,0h mov ax,word ptr es:[0h] ; offset of com I/O addresses cmp ax,0h je no_com1 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg47 ; com1: call dostty call disp_hex mov al,'h' call stdout no_com1: mov ax,word ptr es:[02h] cmp ax,0h je no_com2 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg48 ; com2: call dostty call disp_hex mov al,'h' call stdout no_com2: mov ax,word ptr es:[04h] cmp ax,0h je no_com3 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg48A ; com3: call dostty call disp_hex mov al,'h' call stdout no_com3: mov ax,word ptr es:[06h] cmp ax,0h je no_com4 inc portcnt mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg48B ; com4: call dostty call disp_hex mov al,'h' call stdout no_com4: cmp portcnt,0h je no_coms jmp next_chk no_coms: mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset msg50 ; no com ports found call dostty next_chk: dec optcnt call pause ;*********************************************************************** ;* Display DOS Invar Table Contents. * ;*********************************************************************** invar_chk: cmp inv_flag,0FFh ; switch set for invar list? je disp_invar ; yes jmp chk_dev_drv ; no - bypass it. disp_invar: ; list "Invars" table contents mov dx,offset newline call dostty mov dx,offset scr1 call dostty mov dx,offset newline call dostty mov dx,offset space1 call dostty mov ah,52h ; undocumented function DOS 2.x or... int 21h ; ...greater. Returns pointer to a... push es ; ... DOS internal structure in es:bx push bx ; save for later push bx ; pop sav_off ; mov ax,es ; get Invars seg address for display call disp_hex ; display it. call split ; print the colon. mov bx,sav_off ; restore offset mov ax,bx ; get Invars off address for display call disp_hex mov dx,offset space4 call dostty mov bx,sav_off ; restore offset mov ax,es:[bx+2] ; get DPB segment address for display mov dpb_seg,ax call disp_hex call split mov bx,sav_off ; restore offset mov ax,es:[bx] ; get DPB offset address for display mov dpb_off,ax call disp_hex mov dx,offset space4 call dostty mov bx,sav_off ; restore offset mov ax,es:[bx+6] ; get cache buffer seg addr call disp_hex call split mov bx,sav_off ; restore offset mov ax,es:[bx+4] ; get cache buffer offset addr call disp_hex mov dx,offset space6 call dostty mov bx,sav_off ; restore offset mov ax,es:[bx+10h] ; get cache buffer size for display add ax,10h ; add in size of overhead bytes (16) call disp_hex mov dx,offset space8 call dostty mov bx,sav_off ; restore offset mov ax,es:[bx+18h] ; get drive/directory table seg addr call disp_hex call split mov bx,sav_off ; restore offset mov ax,es:[bx+16h] ; get drive/directory table off addr call disp_hex mov dx,offset space5 call dostty mov ah,34h ; svc 34h = get DOS "Busy" flag addr int 21h push bx pop sav_off mov ax,es ; get DOS busy seg address for display call disp_hex call split mov bx,sav_off ; restore offset mov ax,bx ; get DOS busy off address for display call disp_hex ; ;*********************************************************************** ;* Display Disk Paramter Blocks. ;*********************************************************************** dpb: mov dx,offset newline call dostty mov dx,offset scr1A call dostty mov ax,dpb_seg mov es,ax mov bx,dpb_off dpb_loop: mov dx,offset newline call dostty mov al,byte ptr es:[bx] ; get drive id add al,41h ; convert to ascii letter call stdout call split mov dx,offset space2 call dostty mov al,byte ptr es:[bx+01h] ; get unit number (watch VDISKs) ; media descriptor FEh indicates vdisk? add al,31h ; convert to ascii numeral call stdout mov dx,offset space2 call dostty mov ax,word ptr es:[bx+02h] ; bytes per sector mov cx,word ptr es:[bx+05h] ; num of bits to shift BPS to get BPC shl ax,cl ; multiply it call disp_hex mov dx,offset space2 ; call dostty mov al,byte ptr es:[bx+04h] ; get Sectors Per Cluster minus 1 cmp al,0FEh ; this value indicates that ... je not_read ; ... the drive was never accessed jmp was_read not_read: mov dx,offset notread call dostty mov dx,offset space2 call dostty jmp res_sect was_read: inc al ; make SPC-1 SPC add al,30h ; make ascii char call stdout mov dx,offset space3 call dostty res_sect: mov ax,word ptr es:[bx+06h] ; Reserved Sectors call disp_hex mov dx,offset space2 call dostty mov al,byte ptr es:[bx+08h] ; get Copies of FAT add al,30h ; make ascii char call stdout mov dx,offset space2 call dostty mov ax,word ptr es:[bx+09h] ; Maximum Directory Entries call disp_hex mov dx,offset space2 call dostty mov ax,word ptr es:[bx+0Bh] ; First Usable Sector call disp_hex mov dx,offset space2 call dostty mov ax,word ptr es:[bx+0Dh] ; Total Cluster Count plus 1 dec ax ; make it TCC call disp_hex mov dx,offset space3 call dostty mov al,byte ptr es:[bx+0Fh] ; get Sectors in FAT mov sav_code,al ; display low order byte mov cx,1 ; count of bytes to display push bx lea bx,[sav_code] call show_bytes pop bx mov dx,offset space2 call dostty mov ax,word ptr es:[bx+10h] ; get First Directory Sector call disp_hex mov dx,offset space2 call dostty mov ax,word ptr es:[bx+14h] ; get dev drv seg addr call disp_hex call split mov ax,word ptr es:[bx+12h] ; get dev drv off addr call disp_hex mov dx,offset space2 call dostty mov ax,word ptr es:[bx+16h] ; get Media Descriptor cmp al,00h ; if zero, drive was never accessed jne good_md mov dx,offset notread call dostty mov dx,offset space2 call dostty jmp next_link good_md: mov sav_code,al ; display low order byte mov cx,1 ; count of bytes to display push bx lea bx,[sav_code] call show_bytes pop bx mov dx,offset space2 call dostty next_link: mov dx,word ptr es:[bx+18h] ; get off of next dpb cmp dx,0FFFFh ; last dpb in chain? jne next_dpb jmp end_dpb next_dpb: mov ax,word ptr es:[bx+1Ah] ; get next DPB seg addr call disp_hex call split mov ax,word ptr es:[bx+18h] ; get next DPB off addr call disp_hex mov ax,word ptr es:[bx+1Ah] ; get seg of next dpb mov dx,word ptr es:[bx+18h] ; get off of next dpb mov es,ax ; establish addressibility mov bx,dx jmp dpb_loop end_dpb: mov dx,offset lastdpb call dostty mov dx,offset newline call dostty dec optcnt call pause pop bx pop es ; ;*********************************************************************** ;* Display Device Driver Info. ;*********************************************************************** chk_dev_drv: cmp drv_flag,0FFh ; switch set for device driver list? je nul_dev ; yes jmp chk_tsr ; no - bypass driver list nul_dev: ; list device driver section mov ah,52h ; undocumented function DOS 2.x or... int 21h ; ...greater. Returns pointer to a... push es ; ... DOS internal structure in es:bx push bx ; save for later mov dx,offset newline call dostty mov dx,offset scr2 call dostty pop bx pop es cmp dos_vers+1,03h ; Version dependent... je add_34 ; add bx,17h ; add 23 byte offset if DOS 2.x jmp is_two add_34: add bx,22h ; add 34 byte offset if DOS 3.x is_two: mov devh_seg,es ; segment of device header chain in es mov devh_off,bx ; offset of NUL device now in bx mov ax,es:[bx+2] ; get seg of next driver in chain mov next_seg,ax ; save it mov ax,es:[bx] ; get offset of next driver in chain mov next_off,ax ; save it drv_loop: cmp ax,0FFFFh ; end of chain? jne more_drv jmp end_drv more_drv: mov ax,es:[bx+2] ; get seg of next driver in chain mov next_seg,ax ; save it mov ax,es:[bx] ; get off of next driver in chain mov next_off,ax ; save it mov dx,offset newline call dostty mov sav_off,bx ; save offset mov ax,es:[bx+04h] ; attribute word mov type_drv,ax ; put it where I can get it test ax,8000h ; what kind of device: blk or char? jz is_block mov dx,offset char_dev ; is character device call dostty ; display the word "Char" jmp is_char is_block: mov dx,offset blk_dev ; is block device call dostty ; display the word "Block" call blk_name ; format the block device name jmp clean_up_name is_char: mov ax,word ptr es:[bx+0Ah] ; move name to my buffer mov word ptr sav_name+0,ax mov ax,word ptr es:[bx+0Ch] mov word ptr sav_name+2,ax mov ax,word ptr es:[bx+0Eh] mov word ptr sav_name+4,ax mov ax,word ptr es:[bx+10h] mov word ptr sav_name+6,ax mov ax,2020h ; pad name to 12 chars mov word ptr sav_name+8,ax mov word ptr sav_name+10,ax mov word ptr sav_name+12,ax mov byte ptr sav_name+13,0FFh ; the field termination character clean_up_name: push bx mov bx, offset sav_name scan2: cmp byte ptr[bx],0FFh ; are we done? je end_scan2 ; go display it cmp byte ptr[bx],20h ; less than a space? jb hide_it2 cmp byte ptr[bx],'z' ; greater than lower case z? jna bump_bx2 ; if not it's printable hide_it2: mov byte ptr[bx],20h ; make nonsense characters a space bump_bx2: inc bx ; increment the address jmp scan2 ; go do it again end_scan2: pop bx mov dx,offset sav_name ; print dev name even if block dev call disp_dev_drv mov dx,offset space2 call dostty mov ax,es ; get this driver's seg addr call disp_hex call split mov bx,sav_off ; restore offset mov ax,bx ; get this driver's off addr call disp_hex mov dx,offset space7 ; call dostty ; strategy offset mov bx,sav_off ; restore offset mov ax,es:[bx+06h] ; get strategy offset call disp_hex mov dx,offset space3 ; call dostty ; interrupt offset mov bx,sav_off ; restore offset mov ax,word ptr es:[bx+08h] ; get interrupt offset call disp_hex mov dx,offset space6 ; call dostty mov bx,sav_off ; restore offset mov ax,word ptr es:[bx+04h] ; get device attribute word call disp_hex mov dx,offset space5 ; call dostty mov ax,type_drv ; check DOS version this driver and ah,08h ; ...requires cmp ah,08h ; jne not_rm ; OCREM not supported - a 2.x driver mov dx,offset msg99 ; OCREM is supported - a 3.x driver jmp is_rm not_rm: mov dx,offset msg98 is_rm: call dostty mov bx,sav_off ; restore offset mov es,next_seg ; get seg of next driver in chain mov bx,next_off ; get off of next driver in chain mov ax,bx ; set up check for end of chain jmp drv_loop end_drv: dec optcnt call pause ;*********************************************************************** ;* Display Memory Control Blocks ;*********************************************************************** chk_tsr: ; list MCBs cmp mem_flag,0FFh ; switch set for MCB list? je mem_alloc ; yes - go do it jmp quit ; no - quit mem_alloc: mov dx,offset newline call dostty mov dx,offset scr3 ; Memory Allocation Screen call dostty mov ah,52h int 21h mov ax,es:[bx-2] ; contains seg address of 1st MCB mov es,ax ; establish addressibility xor bx,bx ; offset will always be zero mcb_loop: and env_flag,0h ; set environment found flag "off" and psp_flag,0h ; set PSP found flag "off" and sys_flag,0h ; set system block found flag "off" and tsr_flag,0h ; set TSR flag "off" and mt_flag,0h ; set empty block found flag "off" cmp byte ptr es:[bx],5Ah ; hex 5A is last MCB jne mcb_2 jmp last_mcb ; process last one differently mcb_2: mov mcbseg,ax ; save for later mov dx,offset newline call dostty xor bx,bx ; offset will always be zero call disp_hex mov dx, offset space2 ; will change as logic is inserted call dostty xor bx,bx chk_sys: mov ax,word ptr es:[bx+1] ; get seg addr this MCB allocates for cmp ax,0008h ; DOS block always has 0008h here jne chk_dealloc or sys_flag,0FFh and firstsys,0h chk_dealloc: ; was this block deallocated? push ax mov ax,word ptr es:[bx+1] ; get seg addr this MCB allocates for call disp_hex mov dx, offset space3 call dostty xor bx,bx ; offset will always be zero pop ax cmp ax,0000h ; is block begin zero? jne paras ; if yes, this is empty block or mt_flag,0FFh ; set flag (block was deallocated) paras: mov ax,word ptr es:[bx+3] ; get number of paragraphs allocated call disp_hex mov dx, offset space2 call dostty xor bx,bx ; search_for_env: ; does this MCB allocate for an Env? and env_flag,0h ; clear flag cmp byte ptr es:[bx+10h],43h ; looking for "C" in "COMSPEC=" jne no_autoexec ; yes = last MCB controls environment cmp byte ptr es:[bx+11h],4Fh ; looking for "O" in "COMSPEC=" jne no_autoexec ; if not, maybe no autoexec.bat jmp env_found no_autoexec: ; if no autoexec, 1st string is PATH= cmp byte ptr es:[bx+10h],50h ; looking for "P" in "PATH=" jne search_for_psp ; yes = last MCB controls environment cmp byte ptr es:[bx+11h],41h ; looking for "A" in "PATH=" jne search_for_psp ; if not, no environment env_found: cmp firstenv,01h ; first environment? je first_env call get_name ; get the name of the process or tsr_flag,0FFh first_env: and psp_flag,0h ; can't be both or env_flag,0FFh ; set flag jmp type_blk search_for_psp: ; does this MCB allocate for a PSP? and psp_flag,0h ; clear flag cmp byte ptr es:[bx+10h],0CDh ; looking for an Int 20h in PSP jne type_blk cmp byte ptr es:[bx+11h],20h ; jne type_blk and env_flag,0h ; can't be both or psp_flag,0FFh ; set flag for others xor bx,bx cmp firstpsp,01h je type_blk or tsr_flag,0FFh type_blk: cmp psp_flag,0FFh ; PSP? jne type2 mov dx,offset psptype jmp end_type type2: cmp env_flag,0FFh ; environment? jne type3 mov dx,offset envtype jmp end_type type3: cmp mt_flag,0FFh ; empty block? jne type4 mov dx,offset mttype jmp end_type type4: cmp sys_flag,0FFh ; system block? jne type5 mov dx,offset systype jmp end_type type5: call data_name ; save the filename if any mov dx,offset datatype ; it's a data block end_type: call dostty xor bx,bx owner: mov dx,offset space1 call dostty cmp sys_flag,0FFh ; is this THE DOS block? jne owner1 mov dx,offset sysmsg ; assume system block jmp end_owner owner1: ; cmp psp_flag,0FFh ; if it's a psp and... jne owner2 ; cmp firstpsp,01h ; ...not the first PSP... jne is_tsr ; mov dx,offset cmndmsg ; it's command.com jmp end_owner owner2: cmp env_flag,0FFh ; is it an environment block? jne owner3 cmp firstenv,01h ; is it the DOS environment block? jne is_tsr mov dx,offset cmndmsg ; yes, it belongs to COMMAND.COM jmp end_owner owner3: cmp mt_flag,0FFh ; is this block empty? jne owner4 mov dx,offset mtblkmsg ; assume that this block is empty jmp end_owner owner4: ; must assume this is a data block mov dx,offset dataname ; display last env name jmp end_owner is_tsr: ; this block is a TSR mov dx,offset filename end_owner: call dostty ; xor bx,bx comments: mov dx,offset space2 call dostty comment1: cmp env_flag,0FFh ; environment? jne comment2 cmp firstenv,01h ; first environment? je comment4 mov dx,offset envmsg ; process environment jmp end_comment comment2: cmp sys_flag,0FFh ; is this a system owned block? jne comment3 mov dx,offset drvmsg ; dev drvs, etc. jmp end_comment comment3: cmp mt_flag,0FFh ; is this block empty? jne comment5 mov dx,offset de_allocmsg ; assume that this block is empty jmp end_comment comment4: mov dx,offset mastenv ; this is the DOS master environment and firstenv,0h ; there can be only one jmp end_comment comment5: cmp psp_flag,0FFh ; is this a tsr? jne comment7 cmp firstpsp,01h ; first PSP? je comment6 mov dx,offset tsrmsg ; TSR jmp end_comment comment6: mov dx,offset resdmsg ; resident part of command.com and firstpsp,0h ; there can be only one jmp end_comment comment7: mov dx,offset datamsg ; must assume process data jmp end_comment end_comment: call dostty xor bx,bx ;*********************************************************************** ;* Display the command line arguments for this TSR ;*********************************************************************** args: call chk_args ;*********************************************************************** ;* Find and display any interrupt vectors hooked by this TSR. * ;*********************************************************************** chk_vec: ; print hooked vectors here mov dx,word ptr es:[bx+3] ; get number of paragraphs allocated mov ax,es ; get mcb seg inc ax ; account for length of mcb mov blk_beg,ax ; this is where the blk begins add ax,dx ; add the length of the blk mov blk_end,ax ; this is where the blk ends push es mov ax,0h mov es,ax and vectcnt,0h mov dx,vectcnt mov cl,4 mov cnt,0h vect_loop: shl dx,1 ; multiply the interrupt number... shl dx,1 ; ...by 4 to get offset of vector... mov bx,dx ; .....in table. mov ax,word ptr es:[bx+2] ; get the vector segment mov dx,word ptr es:[bx] ; get the vector offset shr dx,cl ; divide by 16 to get paragraphs add ax,dx ; add them to get seg addr of entry cmp ax,blk_beg ; compare the mcb seg and int seg jnb chk_end ; int seg is greater...chk end seg jmp not_hooked chk_end: cmp ax,blk_end ; compare the ending seg and int seg jna is_hooked ; if int seg less, vector is hooked jmp not_hooked ; ...otherwise it's not. is_hooked: mov ax,vectcnt ; print the interrupt number mov sav_addr,ax ; put it where display routine wants mov cx,1 ; count of bytes to display lea bx,[sav_addr] call show_bytes mov dx, offset space1 call dostty inc cnt cmp cnt,05h jbe not_hooked ; see if we have to wrap the line and cnt,0h mov dx,offset newline call dostty call chk_screen mov dx,offset space12 call dostty ; align the wrap line mov dx,offset space12 call dostty mov dx,offset space12 call dostty mov dx,offset space12 call dostty mov dx,offset space11 call dostty not_hooked: mov cl,4 inc vectcnt ; increment interrupt type number cmp vectcnt,078h ; not interested in types > 78h ja done_vect mov dx,vectcnt jmp vect_loop done_vect: call chk_screen pop es end_mcb_loop: xor bx,bx ; offset will always be zero mov ax,mcbseg ; seg addr of MCB mov dx,word ptr es:[bx+3] ; get number of paragraphs allocated add ax,dx ; add paragraphs allocated to seg addr inc ax ; +16 to account for the MCB length mov es,ax ; this is the new seg addr jmp mcb_loop ;*********************************************************************** ;* This is the MCB for snoop.com * ;*********************************************************************** last_mcb: or psp_flag,0FFh mov dx,offset newline call dostty xor bx,bx call disp_hex mov dx, offset space2 call dostty xor bx,bx mov ax,word ptr es:[bx+1] ; get seg addr this MCB allocates for call disp_hex mov dx, offset space3 call dostty xor bx,bx mov ax,word ptr es:[bx+3] ; get number of paragraphs allocated call disp_hex mov dx, offset space2 call dostty mov dx, offset psptype call dostty mov dx,offset space1 call dostty mov dx,offset filename call dostty mov dx,offset space2 call dostty mov dx,offset thismsg ; assume that this block is free call dostty call chk_args mov dx,offset newline call dostty ;*********************************************************************** ;* End of Job. * ;*********************************************************************** quit: mov ax,4C00h ; Return code for normal completion int 21h ; return to DOS main endp ; ; ;*********************************************************************** ; ; Called procedures (Near) ; ;*********************************************************************** ; ;*********************************************************************** ;* DOS TTY Write ;*********************************************************************** dostty proc near push ax mov ah,09h ; ah=09h: display string at ds:dx int 21h pop ax ret dostty endp ;*********************************************************************** ;* DOS Display Single Character ;*********************************************************************** dos_char proc near push ax mov ah,2 ; ah=02h: display char in dl int 21h pop ax ret dos_char endp ;*********************************************************************** ;* Prints a colon between seg and offset addresses ;*********************************************************************** split proc near push ax mov al,colon call show_ascii pop ax ret split endp ;*********************************************************************** ;* Prints a single space ;*********************************************************************** space proc near push ax mov al,blank call show_ascii pop ax ret space endp ;*********************************************************************** ;* Converts Hex numbers for display. ;*********************************************************************** show_bytes proc near push ax push bx push cx sbs_loop: mov al,[bx] call show_byte inc bx loop sbs_loop pop cx pop bx pop ax ret show_bytes endp ;*********************************************************************** ;* Convert the hex character. ;*********************************************************************** show_byte proc near pushf push cx push ax mov cl,4h ;shift rt 4 bits shr al,cl ;to isolate m.s. nybble call test ;display hex contents pop ax ;retrieve al and al,0fh ;isolate l.s. nybble call test ;display hex contents pop cx popf ret show_byte endp ;*********************************************************************** ;* Determines if hex digit is a letter. ;*********************************************************************** test proc near cmp al,9h ;is nybble letter? ja letter ;if so convert to letter or al,30h ;if not add '30' code jmp display letter: sub al,9h ;reduce letter nybble by 9 or al,40h ;add '40' code display: call show_ascii ret test endp ;*********************************************************************** ;* Displays ASCII characters. ;*********************************************************************** show_ascii proc near push ax push dx mov dl,al mov ah,02h ;ah=02: display char in dl int 21h pop dx pop ax ret show_ascii endp ; ;************************************************************************* ;* dec16out - Routine to convert internal 16 bit binary to ASCII decimal * ;************************************************************************* dec16out proc near dec16out0: push ds push di push dx push cx push ax mov ax,cs mov ds,ax ; a binary number is in dx ; put the digits in a temporary buffer mov cx,0 mov di, offset cs:tbuff ; point to buffer dec16out1: push cx mov ax,dx ; ax has numerator mov dx,0 mov cx,10d ; divisor of 10 div cx xchg ax,dx ; get quotient add al,30h mov [di],al ; put in buffer inc di ; point to next byte pop cx inc cx ; count the digit cmp dx,0 ; done? jnz dec16out1 ; dump the buffer out dec16out2: dec di ; back up through the buffer mov al,[di] call stdout loop dec16out2 pop ax pop cx pop dx pop di pop ds ret dec16out endp ; ;*********************************************************************** ;* Display device driver names so embedded "$" while display. ;*********************************************************************** disp_dev_drv proc near push bx push si ; save the count xor si,si mov bx,dx disp_drv_loop: cmp byte ptr ds:[bx+si],0FFh ; the field termination character je end_drv_loop mov al,byte ptr ds:[bx+si] ; set it up for stdout call stdout inc si cmp si,0Dh ; paranoia: are we done yet? je end_drv_loop jmp disp_drv_loop end_drv_loop: pop si pop bx ret disp_dev_drv endp ; ;*********************************************************************** ;* Sends a character to the std ouput device. ;*********************************************************************** stdout proc near push dx mov dl,al ;in dl for DOS call mov ah,2 ;send character to std output int 21h pop dx ret stdout endp ;*********************************************************************** ;* Finds EGA Copyright String. ;*********************************************************************** ega_copy proc near cmp ps2_flag,0h ; PS/2 series has onboard VGA je not_vga ; and therefore no EGA copyright jmp vga_exit not_vga: mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset egacopy ; copyright header call dostty push es push ds push ds pop es ; destination string address in es:di mov ax,0C000h ; source string address in ds:si mov ds,ax ; ...location of IBM EGA copyright mov ax,05h ; mov cx,11h ; count of words in copyright mov bx,cx ; shl bx,1 ; multiply by 2 then subtract 1... dec bx ; ... to get offset of... mov si,ax ; terminator character in dest string mov di,offset es:tbuff rep movsw pop ds pop es mov byte ptr tbuff+[bx],'$' ; insert terminator mov bx, offset tbuff scan_copy: cmp byte ptr[bx],'$' ; are we done? je done_copy ; go display it cmp byte ptr[bx],' ' ; less than a space? jb mask_it ; cmp byte ptr[bx],'~' ; greater than a tilde jna inc_bx ; if not it's printable mask_it: mov byte ptr[bx],20h ; make nonsense characters a space inc_bx: inc bx ; increment the address jmp scan_copy ; go do it again done_copy: mov dx,offset tbuff ; call dostty push es push ds push ds pop es ; destination string address in es:di mov dx,offset newline call dostty mov dx,offset indent call dostty mov dx,offset egadate ; date header call dostty mov ax,0C000h ; source string address in ds:si mov ds,ax mov ax,26h ; offset of EGA rom release date mov si,ax mov di,offset es:tbuff mov cx,04h ; count of words rep movsw pop ds pop es mov byte ptr tbuff[07h],'$' mov dx,offset tbuff ; call dostty vga_exit: ret ega_copy endp ;*********************************************************************** ;* Division Routine. ;*********************************************************************** divide proc near mov ax,bx xor dx,dx div cx mov bx,dx mov dl,al cmp al,0 jz chk_flag or display_flag,al chk_flag: cmp display_flag,0 ja display_it ret display_it: add dl,30h call dos_char ret divide endp ;*********************************************************************** ; Pause the scrolling display. ;*********************************************************************** pause proc near cmp byte ptr pse_flag,0h ; are we to pause the display? jne no_pause ; if pause is zero we will cmp byte ptr optcnt,0h ; last option? jbe no_pause ; if so don't pause push dx mov dx,offset msg7 ; call dostty mov ah,get_key ; function number int 16h ; ascii code for key pressed in ah pop dx no_pause: ret ; yes - return to caller pause endp ;*********************************************************************** ;* Get a block device driver's name into a buffer for display. ;*********************************************************************** blk_name proc near mov al,byte ptr es:[bx+0Ah] ; first byte is number of units add al,30h ; make it ascii mov ah,20h ; add a space mov word ptr sav_name,ax ; store it mov ax,es:[bx+12h] ; remainder of name... mov word ptr sav_name+2,ax mov ax,es:[bx+14h] ; ...if any, follows units... mov word ptr sav_name+4,ax mov ax,es:[bx+16h] ; ...and may include... mov word ptr sav_name+6,ax mov ax,es:[bx+18h] ; ....some garbage characters... mov word ptr sav_name+8,ax mov ax,es:[bx+1Ah] ; ...whic is unavoidable... mov word ptr sav_name+10,ax mov ax,es:[bx+1Ch] ; ...because I want to see the name. mov word ptr sav_name+12,ax mov byte ptr sav_name+13,0FFh ; the field termination character ret blk_name endp ; ;*********************************************************************** ;* Search for Task Name in Command Line in Environment. ;*********************************************************************** get_name proc near cmp dos_vers+1,02h ; name not available in DOS 2.x ja vers_ok mov arg_cnt,0h ; ignore switches jmp quick_x ; display spaces for owner name vers_ok: mov dx,0000h mov bx,10h mov cx,532h ; env can't be longer than this look_for: dec cx cmp cx,0h ; have we checked 1,330 chars? jne not_1330 ; no, continue the search mov arg_cnt,0h ; yes, ignore switches jmp quick_x ; display spaces for owner name not_1330: inc bx ; a byte at a time..... cmp word ptr es:[bx],dx ; ...look for back to back ascii nuls jne look_for add bx,2 ; found them... mov ax,word ptr es:[bx] ; ... get count of command line args mov arg_cnt,ax add bx,3 cmp byte ptr es:[bx],':' ; ...looking for :\ je not_netware mov arg_cnt,0h ; ignore switches jmp quick_x ; display spaces for owner name not_netware: inc bx ; step over ":" cmp byte ptr es:[bx],5Ch ; ...looking for "\" path delimiter je not_novelle cmp byte ptr es:[bx],2Fh ; ...looking for "/" path delimiter je not_novelle ; Novelle Netware does not use either mov arg_cnt,0h ; won't find task name so ignore jmp quick_x ; display spaces for owner name not_novelle: inc bx ; step over the "\" or "/" mov di,offset filename mov si,bx ; si is offset of beginning of name xor cx,cx mov_name: cmp byte ptr es:[si],5Ch ; looking for embedded '\' in path je restart_scan cmp byte ptr es:[si],2Fh ; looking for embedded '/' in path jne no_path restart_scan: mov di,offset filename ; reset dest offset to beginning inc si ; bump si past '\' or '/' xor cx,cx jmp mov_name ; go back and start again no_path: cmp byte ptr es:[si],2Eh ; looking for '.' to exclude extension je end_name cmp cx,8h ; filename is 8 chars long max je fini mov al,byte ptr es:[si] mov byte ptr ds:[di],al inc si inc di inc cx jmp mov_name end_name: cmp cx,8h ; filename is 8 chars long jnb fini mov byte ptr ds:[di],20h inc di inc cx jmp end_name fini: mov byte ptr ds:[di],'$' quick_x: xor bx,bx ; offset will always be zero ret get_name endp ;*********************************************************************** ;* Save the filename for data blocks ;*********************************************************************** ; data_name proc near cmp byte ptr filename,20h ; will be a space first time around jne not_first call get_owner ; find the owning task name not_first: cmp data_flag,0FFh ; if set, name is already in place je data_exit ; exit if it is push es ; save MCB seg addr push ds ; establish addressibility pop es ; destination string address in es:di mov ax,offset filename ; offset of filename mov si,ax ; set up source index mov di,offset es:dataname ; set up destination index mov cx,04h ; count of words (8 bytes) rep movsw ; do the move mov byte ptr dataname[08h],'$' ; string terminator for DOS or data_flag,0FFh ; set it for next time pop es ; restore MCB seg addr data_exit: ret data_name endp ; ;*********************************************************************** ;* Get name of task that owns this data block. ;*********************************************************************** get_owner proc near push es push bx xor bx,bx mov ax,word ptr es:[bx+1] ; get seg addr of blk this MCB controls mov es,ax ; es now points to PSP of owner mov ax,word ptr es:[bx+2Ch] ; get seg addr of environment mov es,ax ; es now points to Env of owner call get_name ; call the normal get name routine pop bx pop es ret get_owner endp ; ;*********************************************************************** ;* Display Hex Numbers. ;*********************************************************************** disp_hex proc near push bx xchg ah,al ; get it turned around mov sav_addr,ax ; mov cx,2 ; count of bytes to display lea bx,[sav_addr] call show_bytes pop bx ret disp_hex endp ; ;*********************************************************************** ;* Check for command line switches in the TSR's PSP. * ;*********************************************************************** chk_args proc near push bx cmp psp_flag,0FFh ; is this a PSP? jne no_args cmp arg_cnt,0h ; any command line switches? je no_args mov bx,90h ; offset of count (including MCB) mov ax,es:[bx] ; PSP arg cnt cmp ax,0h ; any args? je end_args inc bx ; point to tail arg_loop: cmp byte ptr es:[bx],0Dh ; CR ends tail je end_args mov al,es:[bx] call stdout inc bx ; bump offset cmp bx,9Bh ; only room for 9 characters jb arg_loop end_args: sub bx,91h ; get number of spaces to print cmp bx,0h jbe no_args ; if negative, no args mov cx,0Ch sub cx,bx fill_loop: mov al,20h call stdout loop fill_loop jmp exit_args no_args: mov dx,offset space12 ; change # of spaces for args print call dostty ; exit_args: pop bx ret chk_args endp ;*********************************************************************** ;* See if 80286 or 80386 CPU using Intel approved method ;*********************************************************************** chk_cpu proc near push ax mov cpu_flag,0h ; clear it pushf ; save original flags pushf ; make extra copy of flags register.. pop ax ; bits 12-14 can be set on a 386 only or ax,0111000000000000b ; turn on bits 12-14 push ax ; popf ; pop this value back into flags reg pushf ; pop ax ; look at results and ax,0111000000000000b ; see if bits 12-14 are set jnz is_32_bit ; if they're set, it's a 386 cpu is_16_bit: popf ; restore flags or byte ptr cs:cpu_flag,02h ; indicate 286 cpu jmp cpu_exit is_32_bit: popf ; restore flags or byte ptr cs:cpu_flag,03h ; indicate 386 cpu jmp cpu_exit cpu_exit: pop ax ret chk_cpu endp ; ;*********************************************************************** ;* Check to see if this is an IBM Personal System/2 Machine * ;*********************************************************************** ; Model Id Byte values and meanings: ; ; IBM Personal System/2 Model 30 ; at address F000:FFFE FA ; ; IBM Personal System/2 Model 50 ; at address E000:7AF9 FC 04 <====Rom Revision Level 4. ; ; IBM Personal System/2 Model 60 ; at address E000:7B03 FC 05 <====Rom Revision Level 5. ; ; IBM Personal System/2 Model 80 ; at address E000:xxxx F8 00 F8 is an educated guess ; chk_ps2 proc near and ps2_flag,0h cmp word ptr es:[bx+2],04FCh je model_50 cmp word ptr es:[bx+2],05FCh je model_60 cmp byte ptr es:[bx+2],0F8h je need_386 jmp unkn_model need_386: call chk_cpu cmp byte ptr cs:cpu_flag,03h ; is it a 386 cpu? je model_80 jmp unkn_model ; it's an 80286, 8088, or 8086 model_50: or ps2_flag,50h mov dx,offset msg1F call dostty jmp end_ps2 model_60: or ps2_flag,60h mov dx,offset msg1G call dostty jmp end_ps2 model_80: or ps2_flag,80h mov dx,offset msg1H call dostty jmp end_ps2 unkn_model: ; probably a PC Convertible end_ps2: ret chk_ps2 endp ; ;*********************************************************************** ;* chk_mod30 - Check if this is a PS/2 Model 30. ;*********************************************************************** chk_mod30 proc near cmp al,0FAh ; PS/2 Model 30? je model_30 jmp end_30 model_30: or ps2_flag,30h mov dx,offset msg1E call dostty end_30: ret chk_mod30 endp ; ;*********************************************************************** ;* chk_switch - Check command line switches for options requested. * * ;*********************************************************************** chk_switch proc near mov cl,ds:[0080h] ; command line arg count in PSP cmp cl,0h ; any args? ja swt_set jmp end_swt swt_set: mov bx,80h ; offset-1 of command tail in PSP swt_char: inc bx cmp byte ptr ds:[bx],0Dh ; CR ends command tail jne more_swt jmp end_swt more_swt: cmp byte ptr ds:[bx],'/' je fnd_swt cmp byte ptr ds:[bx],'\' je fnd_swt cmp byte ptr ds:[bx],' ' je fnd_swt cmp byte ptr ds:[bx],'-' je fnd_swt jmp swt_char fnd_swt: inc bx or byte ptr ds:[bx],20h cmp byte ptr ds:[bx],'n' jne chk_equ or pse_flag,0FFh and byte ptr one,0h ; value to add to the line counter jmp swt_char chk_equ: cmp byte ptr ds:[bx],'e' jne chk_inv or equ_flag,0FFh inc optcnt jmp swt_char chk_inv: cmp byte ptr ds:[bx],'i' jne chk_drv or inv_flag,0FFh inc optcnt jmp swt_char chk_drv: cmp byte ptr ds:[bx],'d' jne chk_mcb or drv_flag,0FFh inc optcnt jmp swt_char chk_mcb: cmp byte ptr ds:[bx],'m' jne all_chk or mem_flag,0FFh inc optcnt jmp swt_char all_chk: cmp byte ptr ds:[bx],'a' jne klone_chk or equ_flag,0FFh or inv_flag,0FFh or drv_flag,0FFh or mem_flag,0FFh or argc,0FFh jmp swt_char klone_chk: ; option for MS-DOS boxes cmp byte ptr ds:[bx],'x' ; which are not IBM ROM... jne last_chk and equ_flag,0h ; ... BIOS compatible. or inv_flag,0FFh or drv_flag,0FFh or mem_flag,0FFh or argc,0FFh jmp swt_char last_chk: dec bx jmp swt_char end_swt: cmp argc,0FFh jne not_all mov optcnt,4 not_all: cmp optcnt,1 ; must specify one switch at least jnb lv_swt mov dx,offset usemsg call dostty mov ax,4C01h ; Return code for abnormal completion int 21h ; return to DOS lv_swt: ret chk_switch endp ; ;*********************************************************************** ;* Check the switch char for path names - is it "/" or "\"? ;*********************************************************************** switch_char proc near mov ax,3700h ; request switchar be returned in dl int 21h cmp dl,5CH ; are they using "\" for switches? jne not_unix_lover ; no, "/" for switches, "\" for paths cmp dl,2FH ; are they using "/" for switches? jne func_not_working ; if no, the function is not working mov switchar,5Ch ; change it around for unix lovers mov pathchar,2Fh ; least they be troubled... :-) jmp func_works not_unix_lover: cmp dl,2FH ; are they using "/" for switches? je func_works ; the undocumented function works func_not_working: mov al,0FFh ; if no, the function is not working ; leave defaults in place, signal err func_works: ret switch_char endp ; ;*********************************************************************** ;* Check to see if screen is full during MCB display. ;*********************************************************************** chk_screen proc near push ax push dx xor ax,ax mov al,byte ptr linecnt add al,one ; will be 0 if pause, 1 if not cmp al,14h ; 20 lines per screen jb not_full mov dx,offset newline call dostty mov dx,offset msg7 ; press any key message call dostty mov ah,get_key ; function number (0h or 10h) int 16h ; ascii code for key pressed in ah xor al,al not_full: mov byte ptr linecnt,al ; store the updated counter pop dx pop ax ret chk_screen endp ; cseg ends end begin ;***************************************************************************** ;* End Of Source Code. ;*****************************************************************************