Category : Files from Magazines
Archive   : OCT91.ZIP
Filename : 2N10046A
;---------------------------------------------------------------
; BEGIN LISTING 3
;---------------------------------------------------------------
;
; EMULOAD.ASM Copyright (c) 1991 Robert Collins
;
; This utility uses '386 LOADALL to emulate '286 LOADALL.
; All 16-bit registers are zero-extended to 32-bit
; registers. All 24-bit physical addresses are zero-
; extended to 32-bit registers. '386-specific registers
; not used in '286 LOADALL are either set to the current
; values (Debug registers), or zeroed (segment registers).
;
;---------------------------------------------------------------
;
; This program assumes that you have run the '386 LOADALL
; test prior to installing this TSR. Obviously if LOADALL
; has been removed from the '386 mask, then this program
; will never work. Likewise, it is easier for me to
; document the need to run the LOADALL test program, than
; to incorporate it into this code.
;
;---------------------------------------------------------------
;
; EMULOAD returns ERROR codes to DOS that can be
; intecepted by the batch file command 'IF ERRORLEVEL'.
; The following ERRORLEVEL codes are generated by this
; program:
; 0 = EMULOAD driver now installed in memory
; 1 = Attempted removal of the EMULOAD driver from
; memory failed because EMULOAD was not in already
; in memory.
; 2 = The EMULOAD driver was already in memory when an
; attempt was made to install it again.
; 3 = Bogus command line argument(s).
; 4 = Help requested.
; 5 = The EMULOAD driver was sucessfully removed from
; memory.
; 6 = Can't install the EMULOAD driver because this
; computer isn't an 80386.
;
;---------------------------------------------------------------
;
; Compilation instructions:
; MASM EMULOAD; (MASM 5.1)
; LINK EMULOAD;
; EXE2BIN EMULOAD EMULOAD.COM
; DEL EMULOAD.EXE
;
; The resultant EMULOAD.COM file is 1473 bytes, while the
; TSR portion is 1072 bytes.
;
;---------------------------------------------------------------
; Compiler directives
;---------------------------------------------------------------
Title EMULOAD
.radix 16
.8086
;---------------------------------------------------------------
; Interrupt vector segment
;---------------------------------------------------------------
ABS0 segment at 0
org 6*4
INT_6 dd ?
org 800h
Loadall_286 dd ?
ABS0 ends
;---------------------------------------------------------------
; Structure definitions
;---------------------------------------------------------------
Desc_cache2 STRUC ; 80286 Descriptor cache
A15_A00 dw ? ; register layout.
A23_A16 db ?
_Type2 db ?
_Limit2 dw ?
Desc_cache2 ENDS
Desc_cache3 STRUC ; 80386 Descriptor cache
_Access db 0 ; register layout
_Type db ?
_CS32 db 0
db 0
_Addr dd ?
_Limit dd ?
Desc_cache3 ENDS
Loadall_struc2 STRUC ; 80286 LOADALL table
dw 3 dup (?) ; RESERVED
_286Msw dw ? ; MSW
dw 7 dup (?) ; RESERVED
_286Tr dw ? ; TR
_Flags dw ? ; FLAGS
_286Ip dw ? ; IP
_286Ldt dw ? ; LDT
_286Ds dw ? ; DS
_286Ss dw ? ; SS
_286Cs dw ? ; CS
_286Es dw ? ; ES
_286Di dw ? ; DI
_286Si dw ? ; SI
_286Bp dw ? ; BP
_286Sp dw ? ; SP
_286Bx dw ? ; BX
_286Dx dw ? ; DX
_286Cx dw ? ; CX
_286Ax dw ? ; AX
ES_Desc286 dw 3 dup (?) ; ES Desc. Cache
CS_Desc286 dw 3 dup (?) ; CS Desc. Cache
SS_Desc286 dw 3 dup (?) ; SS Desc. Cache
DS_Desc286 dw 3 dup (?) ; DS Desc. Cache
Gdt_Desc286 dw 3 dup (?) ; GDTR
Ldt_Desc286 dw 3 dup (?) ; LDTR
Idt_Desc286 dw 3 dup (?) ; IDTR
TSS_Desc286 dw 3 dup (?) ; TSSR
Loadall_Struc2 ENDS
Loadall_struc3 STRUC
_Cr0 dd ? ; EAX
_Eflags dd ? ; EFLAGS
_Eip dd ? ; EIP
_Edi dd ? ; EDI
_Esi dd ? ; ESI
_Ebp dd ? ; EBP
_Esp dd ? ; ESP
_Ebx dd ? ; EBX
_Edx dd ? ; EDX
_Ecx dd ? ; ECX
_Eax dd ? ; EAX
_Dr6 dd ? ; DR6
_Dr7 dd ? ; DR7
_Tr dd ? ; TR
_Ldt dd ? ; LDT
_Gs dd ? ; GS
_Fs dd ? ; FS
_Ds dd ? ; DS
_Ss dd ? ; SS
_Cs dd ? ; CS
_Es dd ? ; ES
TSS_Desc dd 3 dup (?) ; TSSR
IDT_Desc dd 3 dup (?) ; IDTR
Gdt_Desc dd 3 dup (?) ; GDTR
Ldt_Desc dd 3 dup (?) ; LDTR
GS_Desc dd 3 dup (?) ; GS Desc. Cache
FS_Desc dd 3 dup (?) ; FS Desc. Cache
DS_Desc dd 3 dup (?) ; DS Desc. Cache
SS_Desc dd 3 dup (?) ; SS Desc. Cache
CS_Desc dd 3 dup (?) ; CS Desc. Cache
ES_Desc dd 3 dup (?) ; ES Desc. Cache
dd 0ah dup (?) ; RESERVED
Loadall_Struc3 ENDS
INT_VEC STRUC
int_offset dw ?
int_segment dw ?
INT_VEC ENDS
;---------------------------------------------------------------
; Equate definitions
;---------------------------------------------------------------
LOADALL286 equ 050fh
CRLF equ <0dh,0ah>
CRLF$ equ <0dh,0ah,'$'>
INT6 equ [bp-4]
;---------------------------------------------------------------
; Macro definitions
;---------------------------------------------------------------
LOADALL_386 MACRO
db 0fh,07h
ENDM
PRINT_STRING MACRO MSG_NAME
mov ah,9
mov dx,offset MSG_NAME
int 21h
ENDM
_TEXT SEGMENT PARA PUBLIC 'CODE'
Assume CS:_TEXT, DS:_TEXT, ES:_TEXT, SS:_TEXT
Org 100h
.386p
;---------------------------------------------------------------
Emulate_286_Loadall Proc Far
;---------------------------------------------------------------
jmp EMULOAD ; goto beginning instruction
Align 4
;---------------------------------------------------------------
; Local Data
;---------------------------------------------------------------
Loadall_tbl Loadall_Struc3 <>
emuload_msg db "80286 LOADALL EMULATOR utility.",CRLF
db "Version 1.0 Only for 80386 computers."
db CRLF
db "Copyright (c) 1991 Robert Collins."
db CRLF$
emu_msg_len equ $-emuload_msg
align 4
;---------------------------------------------------------------
; TSR Code begins here as an INT06 replacement.
;---------------------------------------------------------------
Int06: push bp
mov bp,sp
push si
push ds
lds si,[bp][2] ; get CS:IP of bogus
; opcode
cmp word ptr [si],LOADALL286; was it LOADALL?
jne @Not_LOADALL ; nope
mov di,0
mov ds,di
mov di,cs
mov es,di
mov edi,offset Loadall_tbl
Assume DS:ABS0, ES:_TEXT, SS:NOTHING
;---------------------------------------------------------------
; Convert 80286 registers to 80386 counterparts. The sequencing
; order follows the 80386 LOADALL table.
;---------------------------------------------------------------
; While mapping MSW to CR0, bit5 in CR0 is documented as
; RESERVED on the '386 DX, and '1' on the '386 SX. Bit6 is
; defined as 'NE' (Numeric Exception) on the '486. If we wanted
; this code to work on the '486, then we should mask the lower
; nibble of MSW with CR0. But the '486 doesn't have LOADALL,
; so this isn't necesary. Next consider the Reserved bit5 on
; the '386 DX. Since LOADALL completely redefines the CPU
; state, it is safe to clear this reserved bit instead of
; masking it with MSW.
;---------------------------------------------------------------
mov eax,cr0 ; MSW --> CR0
mov ax,Loadall_286._286Msw
mov Loadall_tbl._CR0,eax
movzx eax,Loadall_286._Flags ; FLAGS --> EFLAGS
mov Loadall_tbl._EFLAGS,eax
;---------------------------------------------------------------
; Hereafter MOVZX isn't needed because the upper 16-bits are
; guaranteed to be 0.
;---------------------------------------------------------------
mov ax,Loadall_286._286IP ; IP --> EIP
mov Loadall_tbl._EIP,eax
mov ax,Loadall_286._286DI ; DI --> EDI
mov Loadall_tbl._EDI,eax
mov ax,Loadall_286._286SI ; SI --> ESI
mov Loadall_tbl._ESI,eax
mov ax,Loadall_286._286BP ; BP --> EBP
mov Loadall_tbl._EBP,eax
mov ax,Loadall_286._286SP ; SP --> ESP
mov Loadall_tbl._ESP,eax
mov ax,Loadall_286._286BX ; BX --> EBX
mov Loadall_tbl._EBX,eax
mov ax,Loadall_286._286DX ; DX --> EDX
mov Loadall_tbl._EDX,eax
mov ax,Loadall_286._286CX ; CX --> ECX
mov Loadall_tbl._ECX,eax
mov ax,Loadall_286._286AX ; AX --> EAX
mov Loadall_tbl._EAX,eax
;---------------------------------------------------------------
; DR6 & DR7 aren't in the '286, so let's use the current values.
; By keeping the current values, guarantees that any ICE
; breakpoints, or debug register breakpoints are preserved.
; (ICE breakpoints use (at least) the upper two of the
; 'RESERVED' bits in DR7.
;---------------------------------------------------------------
mov eax,dr6 ; Keep DR6
mov Loadall_tbl._DR6,eax
mov eax,dr7 ; Keep DR7
mov Loadall_tbl._DR7,eax
movzx eax,Loadall_286._286TR ; TR --> TR
mov Loadall_tbl._TR,eax
mov ax,Loadall_286._286LDT ; LDT --> LDT
mov Loadall_tbl._LDT,eax
;---------------------------------------------------------------
; FS & GS aren't in the '286, so let's zero them out.
;---------------------------------------------------------------
xor ax,ax
mov Loadall_tbl._GS,eax ; Clear GS
mov Loadall_tbl._FS,eax ; Clear FS
mov ax,Loadall_286._286DS ; DS --> DS
mov Loadall_tbl._DS,eax
mov ax,Loadall_286._286SS ; SS --> SS
mov Loadall_tbl._SS,eax
mov ax,Loadall_286._286CS ; CS --> CS
mov Loadall_tbl._CS,eax
mov ax,Loadall_286._286ES ; ES --> ES
mov Loadall_tbl._ES,eax
;-----------------------------------------------------------
; Convert '286 descriptor cache register entries to '386
; format.
;-----------------------------------------------------------
mov esi,offset Loadall_286.TSS_Desc286
mov edi,offset Loadall_tbl.TSS_Desc
call CVT_Desc
mov esi,offset Loadall_286.IDT_Desc286
mov edi,offset Loadall_tbl.IDT_Desc
call CVT_Desc
mov esi,offset Loadall_286.GDT_Desc286
mov edi,offset Loadall_tbl.GDT_Desc
call CVT_Desc
mov esi,offset Loadall_286.LDT_Desc286
mov edi,offset Loadall_tbl.LDT_Desc
call CVT_Desc
;-----------------------------------------------------------
; Fill in FS & GS descriptor cache entires with 0.
;-----------------------------------------------------------
mov Loadall_tbl.GS_Desc._Type,93h
mov Loadall_tbl.GS_Desc._Addr,0
mov Loadall_tbl.GS_Desc._Limit,0ffffh
mov Loadall_tbl.FS_Desc._Type,93h
mov Loadall_tbl.FS_Desc._Addr,0
mov Loadall_tbl.FS_Desc._Limit,0ffffh
;-----------------------------------------------------------
; Convert '286 descriptor cache register entries to '386
; format.
;-----------------------------------------------------------
mov esi,offset Loadall_286.DS_Desc286
mov edi,offset Loadall_tbl.DS_Desc
call CVT_Desc
mov esi,offset Loadall_286.SS_Desc286
mov edi,offset Loadall_tbl.SS_Desc
call CVT_Desc
mov esi,offset Loadall_286.CS_Desc286
mov edi,offset Loadall_tbl.CS_Desc
call CVT_Desc
mov esi,offset Loadall_286.ES_Desc286
mov edi,offset Loadall_tbl.ES_Desc
call CVT_Desc
mov edi,offset Loadall_tbl
LOADALL_386
HLT ; This instruction never
; gets executed
@Not_LOADALL:
pop ds
pop si
pop bp
Orig_int06:
jmp far ptr INT_6
Emulate_286_Loadall endp
;---------------------------------------------------------------
CVT_Desc proc near ; Convert '286 descriptor table
; ; cache register format to '386
; ; format.
;---------------------------------------------------------------
; Input: DS:ESI = Pointer to '286 descriptor cache entry
; DS:EDI = Pointer to '386 descriptor cache entry
; Output: None
; Register(s) modified: EAX, EBX, ECX
;---------------------------------------------------------------
mov eax,[esi] ; get 24-bit base &
; access rights
mov ebx,eax ; make a copy
movzx ecx,[esi]._Limit2 ; get 16-bit limit
rol eax,8 ; put access in AL
and ebx,00ffffffh ; make 24-bit address
mov ES:[edi]._Type,al ; store Access
mov ES:[edi]._Addr,ebx ; store Address
mov ES:[edi]._Limit,ecx ; store Limit
ret
CVT_Desc endp
TSR_End label word
;---------------------------------------------------------------
; End of TSR program
;---------------------------------------------------------------
;---------------------------------------------------------------
; Local DATA used for initialization code only.
;---------------------------------------------------------------
bogus_msg1 db "Unrecognized command line argument."
db CRLF$
bogus_msg2 db "Not 80386 computer.",7,CRLF$
driver_msg1 db "Resident driver installed."
db CRLF$
driver_msg2 db "Resident driver already installed."
db 7,CRLF$
driver_msg3 db "Resident driver removed from memory."
db CRLF$
driver_msg4 db "Resident driver was not already "
db "installed",7,CRLF$
help_msg db CRLF
db "Syntax: EMULOAD",CRLF
db " EMULOAD -R (to remove from "
db "memory)",CRLF$
ASSUME DS:_TEXT
;---------------------------------------------------------------
EMULOAD proc near ; Beginning of initialization
; ; code as the NON-TSR part of
; ; the program.
;---------------------------------------------------------------
cld ; clear direction flag
Print_String emuload_msg ; Print initialization
; message.
;---------------------------------------------------------------
; Check CPU type
;---------------------------------------------------------------
call CPU_TYPE ; Get CPU type
and al,0fh ; mask out CPU sub-type
cmp al,3 ; 80386?
jz short @F ; yes
Print_String Bogus_msg2 ; Not 80386 computer
mov ax,4c06h ; set function to DOS
int 21h ; exit to DOS
;---------------------------------------------------------------
; Check command line argument
;---------------------------------------------------------------
@@: xor ax,ax ; clear AX
mov si,80h ; get start of PSP
lodsb ; get command line len.
or ax,ax ; Any command line args?
jz short Installed? ; nope
mov cx,ax ; put into counter
mov di,si ;
mov al,' ' ; skip past superfluous
repz scasb ; blank characters
cmp byte ptr [di],0dh ; are we at the end?
jz short Installed? ; yep
cmp byte ptr [di-1],'-' ; check if it's a switch
jnz short @F ; if not, then error
mov si,di ; get pointer
lodsb ; get cmd line switch
cmp al,'r' ; remove driver?
jz short remove_driver ; yep
cmp al,'R' ; remove driver?
jz short remove_driver ; go remove driver
cmp al,'?' ; help?
jnz short @F ; nope
Print_String help_msg ; Print help message
mov ax,4c04h ; set return code
int 21h ; exit to DOS
;---------------------------------------------------------------
; Bogus command line argument
;---------------------------------------------------------------
@@: Print_String bogus_msg1 ; Invalid command line
mov ax,4c03h ; set function code
int 21h ; exit to DOS
;---------------------------------------------------------------
; Remove driver from memory
;---------------------------------------------------------------
remove_driver:
call check_installed ; Driver installed?
jnz short @F ; driver not installed
mov bp,sp ; create stack frame
push ds ; save (DS)
mov dx,ABS0 ; get bottom of memory
mov ds,dx ; make segment register
ASSUME DS:ABS0, ES:_TEXT
;---------------------------------------------------------------
; Restore original INT6 vector
;---------------------------------------------------------------
; We can restore the original INT6 by getting the vector from
; our current memory resident driver -- not the DS from the
; code now executing. The original DS is the same as the code
; segment for our EMULOAD driver. Hence we only need to get
; the original segment value from the memory resident image.
; And we get this by looking at the segment for INT6!
;---------------------------------------------------------------
mov es,int_6.int_segment ; Original DS
mov ax,es:orig_int06[1].int_offset ; Original INT6
mov bx,es:orig_int06[1].int_segment ; " "
mov int_6.int_offset,ax ; Restore orig.
mov int_6.int_segment,bx ; INT6
;---------------------------------------------------------------
; Free memory pointed to by ES
;---------------------------------------------------------------
mov ah,49h ; DOS FREE_MEM function
int 21h ; free allocated memory
mov ds,[bp-2] ; get original (DS)
ASSUME DS:_TEXT
;---------------------------------------------------------------
; Now split with TSR removed from memory.
;---------------------------------------------------------------
Print_String driver_msg3 ; Driver removed
mov ax,4c05h ; set function to DOS
int 21h ; exit to DOS
;---------------------------------------------------------------
; If EMULOAD was not in memory, then come here and split with
; the error code.
;---------------------------------------------------------------
@@: Print_String driver_msg4 ; Driver not installed
mov ax,4c01h ; set function to DOS
int 21h ; exit to DOS
;---------------------------------------------------------------
; Check for driver already installed
;---------------------------------------------------------------
Installed?:
call check_installed ; check if driver is
jnz short @F ; already installed?
;---------------------------------------------------------------
; Driver already installed
;---------------------------------------------------------------
Print_String driver_msg2 ; Driver already inst.
mov ax,4c02h ; set function to DOS
int 21h ; exit to DOS
;---------------------------------------------------------------
; Driver not yet installed
;---------------------------------------------------------------
@@: Print_String driver_msg1 ; Driver now installed
;---------------------------------------------------------------
; Install driver into memory
;---------------------------------------------------------------
xor dx,dx ; Point to INT. vectors
mov ds,dx ; complete the move
ASSUME ds:ABS0
;---------------------------------------------------------------
; Chain to INT6 by replacing and saving the original INT6
; vector.
;---------------------------------------------------------------
mov ax,int_6.int_offset ; Orig. offset
mov bx,int_6.int_segment ; Orig. segment
mov orig_int06[1].int_offset,ax ; save old INT6
mov orig_int06[1].int_segment,bx ; vector.
;---------------------------------------------------------------
; Now replace the original INT6 vector.
;---------------------------------------------------------------
mov dx,offset cs:int06 ; Get new INT6 vector
mov int_6.int_offset,dx ; as CS:INT6
mov int_6.int_segment,cs ;
ASSUME DS:_TEXT
;---------------------------------------------------------------
; Terminate and Stay Resident
;---------------------------------------------------------------
mov dx,cs ; make DS=CS
mov ds,dx
mov es,ds:[2ch] ; get DOS env. segment
mov ah,49h ; release memory func.
int 21h ; release memory
mov dx,offset tsr_end ; get ending address
shr dx,4 ; divide by 16
adc dx,1 ; check for remainder;
; add 1
mov ax,3100h ; set return code to DOS
int 21h
EMULOAD endp
ASSUME ES:ABS0
;---------------------------------------------------------------
; Check to see if the EMULOAD driver is installed in memory.
; It is possible to check if a TSR program is already installed
; in memory by looking for a semaphore in the memory image.
; Luckily we can locate the memory image of our TSR by looking
; at the current INT6 vector. The INT6 code segment is the
; segment of the TSR! So this routine looks in this segment
; for the inital banner message:
;
; 80286 LOADALL EMULATOR utility.
; Version 1.0 Only for 80386 computers.
; Copyright (c) 1991 Robert Collins.
;
; If this message is found, then the TSR is in memory. If
; another TSR has chained to the same INT6 vector, this
; technique will fail to find EMULOAD, as it very well should!
;---------------------------------------------------------------
Check_installed proc near
;---------------------------------------------------------------
; Input: None
; Output: NZ if NOT installed
; ZF if ALREADY installed
; Register(s) modified: CX, SI, DI
;---------------------------------------------------------------
push es ; save (ES)
mov cx,ABS0 ; get bios data segment
mov es,cx ; put in (ES)
mov cx,emu_msg_len ; # of bytes to compare
mov si,offset emuload_msg ; get address of message
les di,ES:INT_6 ; get INT6 vector
sub di,int06-emuload_msg ; point to theoretical
; start of message
repz cmpsb ; check data
pop es ; restore (ES)
ret ; split
Check_installed endp
;---------------------------------------------------------------
; Include the CPU_TYPE procedure & LOADALL test
;---------------------------------------------------------------
Include CPU_TYPE.ASM
_TEXT ends
end Emulate_286_LOADALL
;---------------------------------------------------------------
; END LISTING 3
;---------------------------------------------------------------
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/