Saved LOADALL-related files

This commit is contained in:
Jeff Parsons 2016-02-16 13:09:00 -08:00
commit 926d9e7c4e
14 changed files with 4487 additions and 9 deletions

View file

@ -1,6 +1,3 @@
;
; Saved on February 16, 2015 from http://www.rcollins.org/ftp/source/aad/aad.asm
;
.386p
;-----------------------------------------------------------------------------
;
@ -201,4 +198,4 @@ Test_AAD endp
end

View file

@ -43,4 +43,6 @@ From [http://www.rcollins.org/secrets/opcodes/AAD.html](http://www.rcollins.org/
This instruction exists in this form on all Intel x86 processors.
See the file [AAD.ASM](AAD.ASM) for diagnostic source code for this instruction.
The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/):
* [AAD.ASM](AAD.ASM)

View file

@ -1,6 +1,3 @@
;
; Saved on February 16, 2015 from http://www.rcollins.org/ftp/source/aam/aam.asm
;
.386p
;-----------------------------------------------------------------------------
;

View file

@ -59,4 +59,6 @@ From [http://www.rcollins.org/secrets/opcodes/AAM.html](http://www.rcollins.org/
This instruction exists in this form on all Intel x86 processors.
See the file [AAM.ASM](AAM.ASM) for diagnostic source code for this instruction.
The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/):
* [AAM.ASM](AAM.ASM)

View file

@ -0,0 +1,625 @@
Page 60,132
;-----------------------------------------------------------------------------
; BEGIN LISTING 1
;-----------------------------------------------------------------------------
;
; 286LOAD.ASM
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;
; This program demonstrates various aspects of CPU
; behavior that become apparent when using LOADALL.
;
; Test 1: Checks that LOADALL loads all the general-
; purpose registers; loads the segment registers
; with values that are inconsistant to their
; respective descriptor cache registers.
;
; Test 2: Access extended memory in real mode.
;
; Test 3: Tests that the Present bit in a descriptor
; table can be loaded using LOADALL without
; generating exception 11. But when the segment
; is accessed, exception 13 is generated.
; NOTE: This test should be done in protected
; mode, but can be done in real mode. 1) In real
; mode, no error code is pushed on the stack
; (possibly due to a bug in the CPU). 2) Also
; in real mode, when this program is emulated on
; a '386, the '386 fails to set the Present bit
; when any subsequent segment in loaded. This
; latter condition is clearly a bug in the '386.
;
; This program was written for Microsoft MASM 5.1, and
; MS DOS 3.3. This program contains compiler directives
; and branching techniques that might not be available
; on previous versions of the Macro Assembler, nor in
; competitive products. If this program is executed on
; any version of DOS prior to 3.3, it will most certainaly
; cause the system to crash. No attempt is made in this
; program to be compatible with previous versions of DOS,
; but compatibility can be done, and is left as an
; exercise to the reader.
;
;---------------------------------------------------------------
;---------------------------------------------------------------
; Compiler directives
;---------------------------------------------------------------
Title LOADALL_286
.radix 16
.8086
;---------------------------------------------------------------
; Interrupt vector segment
;---------------------------------------------------------------
ABS0 segment at 0
org 06h*4 ; INT 06h vector
INT_6 dd ?
org 0467h ; PM Return address
PM_Ret_off dw ? ; Offset
PM_Ret_seg dw ? ; Segment
org 800h ; LOADALL table loc'n.
Loadall_Locn label word
ABS0 ends
;---------------------------------------------------------------
; Structure definitions
;---------------------------------------------------------------
Desc_cache STRUC ;; Hidden descriptor cache
A15_A00 dw ? ;; format.
A23_A16 db ?
_Type db ?
_Limit dw ?
Desc_cache ENDS
Loadall_struc STRUC ;; LOADALL memory image format
dw 3 dup (0)
_Msw dw 0
dw 7 dup (0)
_Tr dw 0
_Flags dw 2
_Ip dw 0
_Ldt dw 0
_Ds dw 2222h
_Ss dw 4444h
_Cs dw 1111h
_Es dw 3333h
_Di dw 6666h
_Si dw 7777h
_Bp dw 5555h
_Sp dw 8888h
_Bx dw 2222h
_Dx dw 4444h
_Cx dw 3333h
_Ax dw 1111h
ES_Desc db 00,00,03,93h,0ffh,0ffh
CS_Desc db 00,00,00,9bh,0ffh,0ffh
SS_Desc db 00,00,04,93h,0ffh,0ffh
DS_Desc db 00,00,02,93h,0ffh,0ffh
Gdt_Desc db 00,00,00,00h,000h,000h
Ldt_Desc db 00,00,06,82h,088h,000h
Idt_Desc db 00,00,00,00h,0ffh,003h
TSS_Desc db 00,00,05,89h,000h,008h
Loadall_Struc ENDS
Descriptor STRUC
Seg_limit dw ? ; Segment limit
Base_A15_A00 dw ? ; A00..A15 of base address
Base_A23_A16 db ? ; A16..A23 of base address
Access_rights db ? ; Segment access rights
Limit_A19_A16 db ? ; Granularity, Op-size,
; Limit A16..A19
Base_A31_A24 db ? ; A24..A31 of base address
Descriptor ENDS
INT_Desc STRUC
IGate_Offset dw ? ; Offset of handler
CSEG_Sel dw ? ; Code segment selector
db 0
db 86h ; 286 interrupt gate=16bit
; CS:IP, FLAGS
Resvd dw 0 ; Reserved=0
INT_Desc ENDS
;---------------------------------------------------------------
; Macro definitions in MACROS.286:
; MFARJMP: Far JUMP since MASM doesn't assemble it.
; IO_DELAY: Put your favorite I/O delay macro here.
; LOADALL: Copy the LOADALL memory image down to
; 0:800 and execute a '286 LOADALL.
; PRINT_STRING: Given a variable name, use the DOS
; print string command to send it to the
; screen.
;---------------------------------------------------------------
Include MACROS.286
_DATA SEGMENT PARA PUBLIC 'DATA'
;---------------------------------------------------------------
; Equates & local variables
;---------------------------------------------------------------
; Protected mode access rights
;---------------------------------------------------------------
CS_access equ 10011011b
DS_access equ 10010011b
;---------------------------------------------------------------
; Text equates
;---------------------------------------------------------------
CRLF equ <0dh,0ah>
CRLF$ equ <CRLF,'$'>
INT6 equ [bp-4]
;---------------------------------------------------------------
; Conditional compilation. Set USE_386=1 if you plan to execute
; this program on a '386 using EMULOAD.
;---------------------------------------------------------------
USE_386 equ 0
;---------------------------------------------------------------
; Loadall table(s)
;---------------------------------------------------------------
Loadall_tbl Loadall_struc <>
Machine_State Loadall_struc <>
;---------------------------------------------------------------
; Global Descriptor Table
;---------------------------------------------------------------
GDT_286 Descriptor <Gdt2_len-1,,,DS_access>
CSEG2 Descriptor <0ffffh,,,CS_access> ; CS
DSEG2 Descriptor <0ffffh,,,DS_access> ; DS
Gdt2_len equ $-Gdt_286
;---------------------------------------------------------------
; Interrupt Descriptor Table
;---------------------------------------------------------------
IDT_286 INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT00
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT01
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT02
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT03
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT04
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT05
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT06
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT07
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT08
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT09
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0a
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0b
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0c
INT_Desc <Offset INT13,CSEG2-GDT_286> ; INT0d
IDT2_Len equ $-IDT_286
;---------------------------------------------------------------
; Misc. local variables
;---------------------------------------------------------------
Mem_buffer db 400h dup (0)
Results dw 0
i8259_1 db ? ; Status for master device
i8259_2 db ? ; Status of slave device
;---------------------------------------------------------------
; String Messages
;---------------------------------------------------------------
Passed db " PASSED.",CRLF$
Failed db "--> FAILED <--",CRLF$
Not_286 db "Not 80286 class computer.",CRLF$
Rmvd db "LOADALL removed from 80286 mask.",CRLF$
RFail db "Registers weren't loaded correctly."
LF db CRLF$
;---------------------------------------------------------------
; I'm doing this wierd string definition technique to limit the
; page width to 64 characters.
;---------------------------------------------------------------
Test_1 label word
db "Test 1: Testing 286 LOADALL instruction: ",24
Test_2 label word
db "Test 2: Testing extended memory in real mode: ",24
Test_3 label word
db "Test 3: Testing Present BIT in descriptor: ",24
_DATA ends
_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK
.286p
;---------------------------------------------------------------
; A little CS-relative data for the stack pointer. This is
; to avoid using other kludge techniques, caused by using
; LOADALL, that make using the data segment undesirable.
;---------------------------------------------------------------
Stack_ptr dw 0
dw 0
;---------------------------------------------------------------
LOADALL_286 proc far
;---------------------------------------------------------------
PUSH DS ; Setup the stack to
XOR AX,AX ; return to DOS
PUSH AX
MOV AX,_Data
MOV DS,AX
MOV ES,AX
;---------------------------------------------------------------
; Check CPU type, and set up a minimal invalid opcode handler
; in case LOADALL has been removed from the CPU mask.
;---------------------------------------------------------------
IFE USE_386
Call CPU_Type ; 286, 386?
cmp ax,2 ; 286?
je short @F ; yep
Print_String LF
Print_String Not_286
retf ; go split
@@: enter 4,0 ; create stack frame
mov word ptr INT6,offset INT6_handler
mov INT6[2],cs
call set_INT6_vector ; set our INT6 handler
ENDIF
cli
Call Save_State ; Save the current CPU
Print_String LF ; state
Print_String Test_1
;---------------------------------------------------------------
;
; TEST1: Real mode
; Test general purpose registers
; Test Segment registers
; Test Descriptor cache base address
;
; (1) Setup LOADALL structures, and pointers
; (2) Execute LOADALL
; (3) Verify results of the test
;
;---------------------------------------------------------------
mov ax,cs ; Prepare 24-bit
mov es,ax ; physical address that
mov si,0 ; is put in the LOADALL
call Calc_pm_address ; descriptor cache
mov Loadall_tbl.CS_Desc.A15_A00,ax ; entry.
mov Loadall_tbl.CS_Desc.A23_A16,dl
smsw ax
mov Loadall_tbl._Msw,ax
mov Loadall_tbl._Ip,offset Verify_State
mov word ptr cs:stack_ptr,sp ; save SS:SP
mov word ptr cs:stack_ptr[2],ss
LOADALL ; If LOADALL is removed
nop ; from the CPU mask,
Print_String failed ; then fall through
Print_String Rmvd ; to here.
Loadall_RET:
call Restore_state
IFE USE_386
call set_INT6_vector ; set our INT6 handler
leave
ENDIF
retf
;---------------------------------------------------------------
Verify_State: ; Verify that LOADALL worked
;---------------------------------------------------------------
; This is where we land for the first test of '286 LOADALL.
; The purpose of this test is to verify that all the general
; purpose registers get loaded correctly. Specifically, we are
; testing to verify that all segment registers contain values
; that don't correspond to the memory addresses they appear to
; be pointing to. In other words, we are checking that the
; that the segment registers have one value, while their
; associated hidden descriptor cache registers have different
; values.
;---------------------------------------------------------------
cmp ax,1111h ; Test AX
jne @F
cmp bx,2222h ; Test BX
jne @F
cmp cx,3333h ; Test CX
jne @F
cmp dx,4444h ; Test DX
jne @F
cmp bp,5555h ; Test BP
jne @F
cmp di,6666h ; Test DI
jne @F
cmp si,7777h ; Test SI
jne @F
cmp sp,8888h ; Test SP
jne short @F
mov ax,cs ; Test CS
cmp ax,1111h
jne short @F
mov ax,ds ; Test DS
cmp ax,2222h
jne short @F
mov ax,es ; Test ES
cmp ax,3333h
jne short @F
mov ax,ss ; Test SS
cmp ax,4444h
jne short @F
cmp word ptr ds:[0],0202h ; Test DS Desc Cache
jne short @F
cmp word ptr es:[0],0303h ; Test ES Desc Cache
jne short @F
cmp word ptr ss:[0],0404h ; Test SS Desc Cache
jne short @F
mov ax,_Data
mov ds,ax
mov es,ax
mov ax,cs:stack_ptr[2]
mov ss,ax
mov sp,cs:stack_ptr
FARJMP <@Test1_Pass>,<seg _Text>
;---------------------------------------------------------------
; Loadall failed the REGISTERs test.
;---------------------------------------------------------------
@@: mov ax,_Data
mov ds,ax
mov es,ax
mov ax,cs:stack_ptr[2]
mov ss,ax
mov sp,cs:stack_ptr
FARJMP <@F>,<seg _Text>
@@: Print_String failed
Print_String RFail
jmp loadall_ret
;---------------------------------------------------------------
; LOADALL passed
;---------------------------------------------------------------
@Test1_Pass:
Print_String passed
;---------------------------------------------------------------
;
; TEST2: Access extended memory while in real mode.
;
; (1) Enable A20
; (2) Save contents of extended memory
; (3) Write data pattern in extended memory
; (4) Set IP & ES descriptor cache pointing to extended memory
; (5) LOADALL
; (6) Verify results
; (7) Restore original data in extended memory
;
;----------------------------------------------------------------
Print_String Test_2
Call Enable_Gate20 ; Enable extended memory
mov bx,0ffffh ; Point to extended mem.
mov ds,bx ; as FFFF:0010
mov si,10h
mov di,offset Mem_buffer
mov cx,400h / 2 ; 1k data block to test
rep movsw ; save extended memory
mov ax,5aa5h ; test pattern
mov es,bx ; point to extended mem.
mov cx,400h / 2
mov di,10h
rep stosw ; store pattern in mem.
mov ax,_data
mov ds,ax
mov Loadall_tbl._AX,5aa5h
mov Loadall_tbl._CX,400h / 2
mov Loadall_tbl._DI,0h
mov Loadall_tbl._SP,sp ; save SP
mov Loadall_tbl._IP,offset @F
mov Loadall_tbl.ES_Desc.A15_A00,00
mov Loadall_tbl.ES_Desc.A23_A16,10
LOADALL
@@: repz scasw ; data match?
lahf ; get flags
mov bx,_Data
mov ds,bx
mov cx,0ffffh
mov es,cx
mov cx,400h / 2
mov si,offset Mem_buffer
mov di,10h
rep movsw ; restore data
mov es,bx
mov cx,cs:stack_ptr[2]
mov ss,cx
FARJMP <@F>,<seg _Text>
@@: sahf ; restore flags
jz @Test2_Pass
PRINT_STRING failed
jmp Loadall_RET
@Test2_Pass:
PRINT_STRING passed
;---------------------------------------------------------------
;
; TEST3: Test that the Present bit gets loaded w/out exception,
; but when a segment is accessed INT13 get generated.
;
; If LOADALL works even remotely like we think it does,
; then this test will work in REAL MODE! And as this
; test was originally programmed, it did! However, I
; was doing my testing by emulating '286 LOADALL with
; '386 LOADALL, where I could use an ICE for debug
; purposes. The code worked on a '286, but failed on a
; '386! I found that the '386 fails to clear the
; Present bit in the descriptor cache register when a
; segment register is loaded in real mode. This is
; obviously a bug in the '386. Since the CPU is in a
; state that can never be duplicated under any program
; control, except by using LOADALL (Present=0), the bug
; will never be manifested in any production code. As a
; result, I reprogramed this example to use protected
; mode so it would work on both the '286 and '386.
;
; (1) Prepare GDT & IDT descriptor cache registers and
; descriptor tables, & segment selectors
; (2) Set protected mode bit, clear Present bit, set IP
; (3) Save the 8259 masks, set the PM return address, and set
; CMOS shutdown=5
; (4) LOADALL
; (5) Generate the exception
; (6) Reset ES to a valid segment selector & save results of
; test.
; (7) Reset the CPU, restore 8259 masks, inhibit A20 from the
; CPU bus, restore segment registers to real mode values.
; (8) Verify the results
;
;---------------------------------------------------------------
; Test Present bit: verify that P=0 in a descriptor cache
; register will, even in REAL MODE, will generate an exception
; 13 when trying to access memory
;---------------------------------------------------------------
Test3: Print_String Test_3
mov ax,_Data
mov es,ax
mov si,0
call Calc_pm_address
mov DSEG2.Base_A15_A00,ax
mov DSEG2.Base_A23_A16,dl
add ax,offset GDT_286
adc dl,0
mov Loadall_tbl.GDT_Desc.A15_A00,ax
mov Loadall_tbl.GDT_Desc.A23_A16,dl
mov Loadall_tbl.GDT_Desc._Limit,GDT2_Len-1
mov si,offset IDT_286
call Calc_pm_address
mov Loadall_tbl.IDT_Desc.A15_A00,ax
mov Loadall_tbl.IDT_Desc.A23_A16,dl
mov Loadall_tbl.IDT_Desc._Limit,IDT2_Len-1
mov ax,_TEXT
mov es,ax
mov si,0
call Calc_pm_address
mov CSEG2.Base_A15_A00,ax
mov CSEG2.Base_A23_A16,dl
mov Loadall_tbl._CS,CSEG2-GDT_286
or Loadall_tbl._MSW,1
and Loadall_tbl.ES_Desc._Type,7fh ; Clear P bit
mov Loadall_tbl._IP,offset @PM_286 ; Set IP
Call Get_INT_Status ; save PIC masks
mov ax,offset @RM_286 ; save real mode return
Call SetPM_RET_addr ; address
Call Set_shutdown_type ; set shutdown in CMOS
LOADALL
@PM_286:mov al,es:[di][2]
mov ax,DSEG2-GDT_286
mov es,ax
mov ES:Results,di
jmp RESET_CPU
@RM_286:mov ax,cs:stack_ptr[2]
mov ss,ax
mov sp,cs:stack_ptr
mov ax,_Data
mov ds,ax
mov es,ax
call Set_INT_Status
call Shut_A20
mov di,Results ; If an exception 13 was
test di,1 ; generated, then the
jnz @F ; low bit of DI is set
Print_String failed ; Test failed
jmp Loadall_RET
@@: Print_String passed ; Test passed
jmp Loadall_RET
LOADALL_286 endp
;---------------------------------------------------------------
; Minimal exception 13 handler that points past a 4-byte opcode,
; and sets the lowest bit in DI before returning.
;---------------------------------------------------------------
INT13 label word
push bp
mov bp,sp
add word ptr [bp][4],4
or di,1
pop bp
add sp,2
iret
;---------------------------------------------------------------
; Include all the protected mode functions:
; RESET_CPU: Reset the CPU back to real mode
; SETPM_RET_ADDR: Put the PM return address @ 40:67
; GET_INT_STATUS: Save the 8259 (PIC) masks.
; SET_INT_STATUS: Restore the 8259 (PIC) masks.
; SET_SHUTDOWN_TYPE: Set CMOS shutdown type 5
; ENABLE_GATE20: Enable A20 to CPU bus
; SHUT_A20: Disable A20 from the CPU bus
; CALC_PM_ADDRESS: Calculate a 24-bit physical address
; SAVE_STATE: Save machine state before LOADALL
; RESTORE_STATE: Restore machine state after LOADALL
;---------------------------------------------------------------
Include LOADFNS.286
IFE USE_386
;---------------------------------------------------------------
; Include the CPU_TYPE procedure & LOADALL test
;---------------------------------------------------------------
Include CPU_TYPE.ASM
ENDIF
_text ends
stack segment para stack 'stack'
db 400h dup (0)
stack ends
end LOADALL_286
;---------------------------------------------------------------
; END LISTING 1
;---------------------------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -226,3 +226,15 @@ From [http://www.rcollins.org/secrets/opcodes/LOADALL.html](http://www.rcollins.
; the access rights as a Read/Write/Data segment. This will
; even work in protected mode.
;---------------------------------------------------------------------
The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/):
* [The LOADALL Instruction](tspec_a3_doc.html)
* [286LOAD.ASM](286load.asm)
* [386LOAD.ASM](386load.asm)
* [CPU_TYPE.ASM](cpu_type.asm)
* [EMULOAD.ASM](emuload.asm)
* [LOADFNS.286](loadfns.286.asm)
* [LOADFNS.386](loadfns.386.asm)
* [MACROS.286](macros.286.asm)
* [MACROS.386](macros.386.asm)

View file

@ -0,0 +1,203 @@
.386p
;-----------------------------------------------------------------------------
;
; CPU_TYPE.ASM
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;---------------------------------------------------------------;
; CPU_Type determines the CPU type in the system. ;
;---------------------------------------------------------------;
; Written by: ;
; Robert Collins ;
;---------------------------------------------------------------;
; Input: None ;
; Output: AX = CPU type ;
; 0 = 8086/8088 ;
; 1 = 80186/80188 ;
; 2 = 80286 ;
; 3 = 80386 ;
; 4 = 80486 ;
; FFFF = Unknown CPU type ;
; Register(s) modified: AX, BX, CX, EDX ;
;---------------------------------------------------------------;
; Macro definitions ;
;---------------------------------------------------------------;
; 80486 instruction macro -- because MASM 5.1 doesn't support ;
; the 80486! ;
;---------------------------------------------------------------;
XADD macro ;
db 0fh,0C0h,0D2h ; 80486 instruction macro ;
ENDM ;
;
;
;---------------------------------------------------------------;
CPU_Type proc near ;
;---------------------------------------------------------------;
; Determine the CPU type by testing for differences in the CPU ;
; in the system. ;
;---------------------------------------------------------------;
; To determine if we are a 8086/8088, or 80186/80188, test the
; value of SP after it is placed on the stack. The algorithm
; for "PUSH SP" differs from 8086/80186 to 80286+. The
; algorithm difference is as follows:
;
; 8086/80186 80286+
; { {
; SP = SP - 2 TEMP = SP
; SS:SP = SP SP = SP - 2
; } SS:SP = TEMP
; }
;
; Thus for the 8086/80186, the value of SP that gets pushed on
; the stack is the value after SP is decremented. Hence, the
; value on the stack does not reflect the value of SP before the
; "PUSH" instruction. Therefore, all we have to do to
; categorize the CPU as 8086/8088 or 80186/80188 is to "PUSH SP"
; and compare the value on the stack image to the value in SP.
;---------------------------------------------------------------
xor ax,ax ; clear CPU type return register
push sp ; save SP on stack to look at
pop bx ; get SP saved on stack
cmp bx,sp ; if 8086/8088 these values will
; differ
jz short @Not_8086 ; nope, must be other CPU type
;---------------------------------------------------------------
; If this test passes, then we need some other means to differ-
; entiate between 8088/8088 and 80186/80188. This method I will
; use comes from "80186/188, 80C186/C188 Hardware Reference
; Manual" from Intel, PN# 270788, page A-2: "When a word write
; is performed at offset FFFFh in a segment, the 8086 will write
; one byte at offset FFFFh, and the other at offset 0, while an
; 80186 family processor will write one byte at offset FFFFh,
; and the other at offset 10000h (one byte beyond the end of the
; segment).
;---------------------------------------------------------------
; Before we can blast a value out to FFFFh, we must save
; anything there, so we don't crash anybody else's data.
;---------------------------------------------------------------
push es
mov bx,ds ; get original DS
inc bx
mov es,bx
mov bl,ds:[0] ; get byte @ 0
mov bh,es:[0fff0h] ; get byte @ 10000h
mov ds:[0ffffh],0aaaah ; write signature at
; test location
cmp byte ptr ds:[0],0aah ; 8086?
mov ds:[0],bl ; restore original value
mov es:[0fff0h],bh
pop es
je short CPU_8086_Exit
inc ax
jmp short CPU_8086_Exit
;---------------------------------------------------------------
; When we get here, we know that we aren't a 8086/80186. And
; since all subsequent processors will trap invalid opcodes via
; INT6, we will determine which CPU we are by trapping an
; invalid opcode.
; We are an 80486 if: XADD DX,DX executes correctly
; 80386 if: MOV EDX,CR0 executes correctly
; 80286 if: SMSW DX executes correctly
;---------------------------------------------------------------
; Setup INT6 handler
;---------------------------------------------------------------
@Not_8086:
enter 4,0 ; create stack frame
mov word ptr INT6,offset INT6_handler
mov INT6+2,cs
call set_INT6_vector ; set pointer for INT6 handler
mov ax,4 ; initialize CPU flag=4 (80486)
xor cx,cx ; initialize semaphore
;---------------------------------------------------------------
; Now, try and determine which CPU we are by executing invalid
; opcodes. The instructions I chose to invoke invalid opcodes,
; are themselves rather benign. In each case, the chosen
; instruction modifies the DX register, and nothing else. No
; system parameters are changed, e.g. protected mode, or other
; CPU dependant features.
;---------------------------------------------------------------
; The 80486 instruction 'XADD' xchanges the registers, then adds
; them. The exact syntax for a '486 compiler would be:
; XADD DX,DX.
;---------------------------------------------------------------
XADD ;DX,DX ; 80486
jcxz CPU_exit
dec ax ; set 80386 semaphore
inc cx ; CX=0
;---------------------------------------------------------------
; For a description on the effects of the following instructions,
; look in the Intel Programmers Reference Manual's for the 80186,
; 80286, or 80386.
;---------------------------------------------------------------
mov edx,cr0 ; 80386
jcxz CPU_exit
dec ax ; set 80286 semaphore
inc cx ; CX=0
smsw dx ; 80286
jcxz CPU_exit
sub ax,3 ; set UNKNOWN_CPU semaphore
CPU_exit:
call set_INT6_vector
leave
CPU_8086_exit:
ret
;---------------------------------------------------------------
; Set the INT6 vector by exchanging it with the one currently on
; the stack.
;---------------------------------------------------------------
set_INT6_vector:
push ds
push ABS0 ; save interrupt vector segment
pop ds ; make DS=INT vector segment
ASSUME DS:ABS0
mov dx,word ptr ds:INT_6 ; get offset of INT6
xchg INT6,dx ; set new INT6 offset
mov word ptr ds:INT_6,dx
mov dx,word ptr ds:INT_6[2] ; get segment of INT6
xchg INT6+2,dx ; set new INT6 segment
mov word ptr ds:INT_6[2],dx
pop ds ; restore register
ret ; split
ASSUME DS:_TEXT
;---------------------------------------------------------------
; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return
; address to point past the invalid opcode.
; [BP]
;---------------------------------------------------------------
INT6_handler:
enter 0,0 ; create new stack frame
dec cx ; make CX=FFFF
add word ptr ss:[bp][2],3 ; point past invalid
; opcode
leave
iret
CPU_Type endp

View file

@ -0,0 +1,648 @@
Page 60,132
;-----------------------------------------------------------------------------
; BEGIN LISTING 3
;-----------------------------------------------------------------------------
;
; EMULOAD.ASM
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;
; 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
;---------------------------------------------------------------

View file

@ -0,0 +1,382 @@
;-----------------------------------------------------------------------------
;
; LOADFNS.286
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;---------------------------------------------------------------
; Equates & local variables
;---------------------------------------------------------------
; I/O Ports
;---------------------------------------------------------------
Mstrmsk equ 021h ; 8259 master mask addr
KBC_CTL equ 060h ; 8042 control port
KBC_STAT equ 064h ; 8042 status port
Cmos_index equ 070h ; CMOS address port
Cmos_data equ 071h ; CMOS data port
Slv_msk equ 0a1h ; 8259 slave mask addr
;---------------------------------------------------------------
; CMOS RAM
;---------------------------------------------------------------
Shut_down equ 00fh ; CMOS index for shutdwn
Type5 equ 5 ; Shutdown type-5
;---------------------------------------------------------------
; Keyboard Controller
;---------------------------------------------------------------
inpt_buf_full equ 2 ; Input buffer full
Shutdown_CMD equ 0feh ; Shutdown CMD for KBC
enable_bit20 equ 0dfh ; enable A20 command
disable_bit20 equ 0ddh ; disable A20 command
;---------------------------------------------------------------;
RESET_CPU:; Resets the CPU by sending a shutdown command to
; the keyboard controller.
;---------------------------------------------------------------
; Input: None
; Output: None
; Register(s) modified: Doesn't matter, the CPU is reset
;---------------------------------------------------------------
mov al,Shutdown_CMD ; get shutdown command
out KBC_STAT,al ; send command to shutdown CPU
cli ; disable interrupts so that
; an INT can't come through
; before the CPU resets
hlt ;
;---------------------------------------------------------------;
; SETPM_RET_ADDR: Save the real-mode return address @ 40:67
; from protected mode.
;---------------------------------------------------------------
; Input: CS:AX = Return address from PM.
; DS = Better darn well have a PM segment selector!
; (Or else Kablooie!)
; Output: None
; Register(s) modified: None
;---------------------------------------------------------------
Setpm_ret_addr proc near
;---------------------------------------------------------------
push dx ; save it
push ds
mov dx,ABS0 ;
mov ds,dx
ASSUME DS:ABS0
mov DS:PM_Ret_off,ax
mov DS:PM_Ret_seg,cs
ASSUME DS:_DATA
pop ds
pop dx
ret
Setpm_ret_addr endp
;---------------------------------------------------------------
; Get_INT_status: Saves the master and slave mask register
; contents from the 8259 interrupt controller.
;---------------------------------------------------------------
; Input: DS = _DATA SEGMENT
; Output: i8259_1 = Status of master device
; i8259_2 = Status of slave device
; Register(s) modified: None
;---------------------------------------------------------------
Get_int_status proc near
;---------------------------------------------------------------
push ax
in al,mstrmsk ; get master PIC mask
mov i8259_1,al
IO_Delay ; I/O delay
in al,slv_msk ; get slave PIC mask
mov i8259_2,al
pop ax
ret ; exit
Get_int_status endp
;---------------------------------------------------------------;
; Set_INT_status: Restores the interrupt status of the 8259A
; programmable interrupt controller (PIC).
;---------------------------------------------------------------
; Input: i8259_1 = Status of master device
; i8259_2 = Status of slave device
; DS = _DATA SEGMENT
; Output: None
; Register(s) modified: None
;---------------------------------------------------------------
Set_int_status proc near
;---------------------------------------------------------------
pushf ; save interrupt flag
cli ; we REALLY don't want an int
; to come through while we are
push ax ; reprogramming the PIC masks
mov al,i8259_1
out mstrmsk,al ; restore master PIC mask
IO_Delay ; I/O delay
mov al,i8259_2
out slv_msk,al ; restore slave PIC mask
pop ax
popf ; restore interrupt flag
ret ; exit
Set_int_status endp
;---------------------------------------------------------------
; SET_SHUTDOWN_TYPE: Set the processor shutdown type-5 in CMOS.
;---------------------------------------------------------------
; Input: None
; Output: None
; Register(s) modified: None
;---------------------------------------------------------------
Set_shutdown_type proc near
;---------------------------------------------------------------
pushf ; save interrupt status
cli ; disable ints so somebody else
; doesn't do this right now
push ax
mov al,shut_down ; Set shutdown byte
out cmos_index,al ; to shut down x05.
IO_Delay ; I/O delay
mov al,Type5 ;
out cmos_data,al ; CMOS data port
pop ax
popf
ret
set_shutdown_type endp
;---------------------------------------------------------------
; Enable_gate20: Turn on A20, and check for errors.
;---------------------------------------------------------------
; Input: None
; Output: CY=ERROR
; Register(s) modified: None
;---------------------------------------------------------------
Enable_gate20 proc near
;---------------------------------------------------------------
push ax
mov ah,enable_bit20 ; gate address bit 20 on
Call Gate_A20
or al,al ; command accepted?
jz A20_OK ; go if yes
stc ; set error flag
A20_OK: pop ax
ret ; exit
Enable_gate20 endp
;---------------------------------------------------------------
; SHUT_A20: Disable A20 from CPU address BUS.
;---------------------------------------------------------------
; Input: None
; Output: CY=ERROR
; Register(s) modified: None
;---------------------------------------------------------------
Shut_a20 proc near
;---------------------------------------------------------------
push ax
mov ah,disable_bit20 ; gate address bit 20 on
Call Gate_A20
or al,al ; was command accepted?
jz A20_Shut ; go if yes
stc ; set error flag
A20_Shut:
pop ax
ret ; exit
Shut_a20 endp
;---------------------------------------------------------------
; GATE_A20: This routine controls a signal which gates address
; line 20 (A20). The gate A20 signal is an output of
; of the 8042 slave processor (keyboard controller).
; A20 should be gated on before entering protected
; mode, to allow addressing of the entire 16M address
; space of the 80286, or 4G address space of the
; 80386 & 80486. It should be gated off after
; entering real mode -- from protected mode.
;---------------------------------------------------------------
; Input: AH = DD ==> A20 gated off (A20 always 0)
; AH = DF ==> A20 gated on (CPU controls A20)
; Output: AL = 0 ==> Operation successful
; AL = 2 ==> Operation failed, 8042 can't accept cmd
; Register(s) modified: AX
;---------------------------------------------------------------
Gate_a20 proc near
;---------------------------------------------------------------
pushf ; save interrupt status
cli ; disable ints while using 8042
Call Empty_8042 ; insure 8042 input buffer empty
jnz A20_Fail ; ret: 8042 unable to accept cmd
IO_Delay ; I/O Delay
mov al,0D1h ; 8042 cmd to write output port
out KBC_STAT,al ; output cmd to 8042
Call Empty_8042 ; wait for 8042 to accept cmd
jnz A20_Fail ; ret: 8042 unable to accept cmd
mov al,ah ; 8042 port data
out KBC_CTL,al ; output port data to 8042
Call Empty_8042 ; wait for 8042 to port data
push cx ; save it
mov cx,14h ;
@DLY: IO_Delay ; Wait for KBC to execute the
loop @DLY ; command. (about 25uS)
pop cx ; restore it
A20_Fail:
popf ; restore flags
ret
Gate_a20 endp
;---------------------------------------------------------------
; EMPTY_8042: This routine waits for the 8042 buffer to empty.
;---------------------------------------------------------------
; Input: None
; Output: AL = 0, 8042 input buffer empty: ZF
; AL = 2, Time out; 8042 buffer full: NZ
; Register(s) modified: AX
;---------------------------------------------------------------
Empty_8042 proc near
;---------------------------------------------------------------
push cx ; save CX
xor cx,cx ; CX=0: timeout value
Try_KBC:
IO_Delay ;
in al,KBC_STAT ; read 8042 status port
and al,inpt_buf_full; input buffer full flag (D1)
loopnz Try_KBC ; loop until input buffer empty
; or timeout
pop cx ; restore CX
ret
Empty_8042 endp
;---------------------------------------------------------------
; CALC_PM_ADDRESS: Calculate 32-bit protected mode address.
; Used for building descriptor tables.
;---------------------------------------------------------------
; Input: ES:SI = Real mode address
; Output: DX:AX = 32-bit linear address
; Register(s) modified: AX, DX
;---------------------------------------------------------------
Calc_pm_address proc near
;---------------------------------------------------------------
mov ax,es ; point to control block
xor dh,dh ; clear upper register
mov dl,ah ; build high byte of 32-bit addr
shr dl,4 ; use only high nibble from (AX)
shl ax,4 ; strip high nibble from segment
add ax,si ; add GDT offset for low word
adc dx,0 ; adj high byte if CY from low
ret ; back to calling program
calc_pm_address endp
;---------------------------------------------------------------
Save_state proc near ; Save the machine state before
; ; LOADALL
;---------------------------------------------------------------
push ax
push ds
mov si,0
mov di,offset Machine_State.ES_Desc
mov ax,3000h ; ES descriptor
mov ds,ax
mov bx,0303h
movsw
mov word ptr [si-2],bx
add ax,1000h ; SS descriptor
add bx,0101h
mov si,0
add di,0ah
mov ds,ax
movsw
mov word ptr [si-2],bx
sub ax,2000h ; DS descriptor
sub bx,0202h
mov si,0
add di,4
mov ds,ax
movsw
mov word ptr [si-2],bx
pop ds
smsw ax
mov Machine_State._Msw,ax
pushf
pop ax
mov Machine_State._Flags,ax
pop ax
mov Machine_State._DI,di
mov Machine_State._SI,si
mov Machine_State._BP,bp
mov Machine_State._BX,bx
mov Machine_State._DX,dx
mov Machine_State._CX,cx
mov Machine_State._AX,ax
mov ax,ds
mov Machine_State._DS,ax
mov ax,es
mov Machine_State._ES,ax
ret
Save_state endp
;---------------------------------------------------------------
Restore_state proc near ; Restore the machine state
; ; after LOADALL
;---------------------------------------------------------------
mov ax,_data
mov ds,ax
mov ax,3000h ; ES
mov es,ax
mov si,offset Machine_State.DS_Desc
mov di,0
movsw
add ax,1000h ; SS
add si,0ah
mov di,0
mov es,ax
movsw
sub ax,2000h ; DS
add si,4
mov di,0
mov es,ax
movsw
mov ax,Machine_State._ES
mov es,ax
mov ax,Machine_State._DS
mov ds,ax
mov ax,Machine_State._Flags
push ax
popf
mov ax,Machine_State._Msw
lmsw ax
mov ax,Machine_State._AX
mov cx,Machine_State._CX
mov dx,Machine_State._DX
mov bx,Machine_State._BX
mov bp,Machine_State._BP
mov si,Machine_State._SI
mov di,Machine_State._DI
ret
Restore_State endp

View file

@ -0,0 +1,205 @@
;-----------------------------------------------------------------------------
;
; LOADFNS.386
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
INT01: ; Int1 trap routine
;-----------------------------------------------------------------------------
; Interprets breakpoint type, and sets a flag
;-----------------------------------------------------------------------------
inc dx
push bp
mov bp,sp
mov buffer2[bx],cx
add bx,2
push eax
push ebx
push ecx
mov eax,dr6
mov ecx,eax
mov ebx,dr7
shr ebx,10h ; get length encodings
test ah,20h ; debug register access attempt?
jnz @DR_Attempt ; yep
shr al,1 ; DR0?
jc @DR0
shr al,1 ; DR1?
jc @DR1
shr al,1 ; DR2?
jc @DR2
@DR3: or si,8
and cl,not 8
test bh,30h ; code, or data?
jz @Fault
jmp short @Trap
@DR2: or si,4
and cl,not 4
test bh,03h ; code, or data?
jz @Fault
jmp short @Trap
@DR1: or si,2
and cl,not 2
test bl,30h ; code, or data?
jz @Fault
jmp short @Trap
@DR0: or si,1
and cl,not 1
test bl,03h ; code, or data?
jz @Fault
jmp short @Trap
@Fault: add word ptr [bp][2],1
mov dr6,ecx
@Trap: pop ecx
pop ebx
pop eax
pop bp
iret
@Dr_Attempt:
push bp
add word ptr [bp][2],3
pop bp
iret
;-----------------------------------------------------------------------------
Save_state proc near ; Save the machine state before LOADALL
;-----------------------------------------------------------------------------
push eax
push ds
mov si,0
mov di,offset Machine_State.GS_Desc
mov ax,5000h ; GS descriptor
mov ds,ax
mov ebx,05050505h
movsd
mov dword ptr [si-4],ebx
sub ax,1000h ; FS descriptor
sub ebx,01010101h
mov si,0
add di,8
mov ds,ax
movsd
mov dword ptr [si-4],ebx
sub ax,2000h ; DS descriptor
sub ebx,02020202h
mov si,0
add di,8
mov ds,ax
movsd
mov dword ptr [si-4],ebx
add ax,4000h ; SS descriptor
add ebx,04040404h
mov si,0
add di,8
mov ds,ax
movsd
mov dword ptr [si-4],ebx
sub ax,3000h ; ES descriptor
sub ebx,03030303h
mov si,0
add di,14h
mov ds,ax
movsd
mov dword ptr [si-4],ebx
pop ds
mov eax,cr0
mov Machine_State._CR0,eax
pushfd
pop eax
mov Machine_State._Eflags,eax
pop eax
mov Machine_State._EDI,edi
mov Machine_State._ESI,esi
mov Machine_State._EBP,ebp
mov Machine_State._EBX,ebx
mov Machine_State._EDX,edx
mov Machine_State._ECX,ecx
mov Machine_State._EAX,eax
mov ax,gs
movzx eax,ax
mov Machine_State._GS,eax
mov ax,fs
mov Machine_State._FS,eax
mov ax,ds
mov Machine_State._DS,eax
mov ax,es
mov Machine_State._ES,eax
ret
Save_state endp
;-----------------------------------------------------------------------------
Restore_state proc near ; Restore the machine state after LOADALL
;-----------------------------------------------------------------------------
mov ax,_data
mov ds,ax
mov ax,5000h ; GS
mov es,ax
mov si,offset Machine_State.GS_Desc
mov di,0
movsd
sub ax,1000h ; FS
add si,8
mov di,0
mov es,ax
movsd
sub ax,2000h ; DS
add si,8
mov di,0
mov es,ax
movsd
add ax,4000h ; SS
add si,8
mov di,0
mov es,ax
movsd
sub ax,3000h ; ES
add si,14h
mov di,0
mov es,ax
movsd
mov eax,Machine_State._ES
mov es,ax
mov eax,Machine_State._DS
mov ds,ax
mov eax,Machine_State._FS
mov fs,ax
mov eax,Machine_State._GS
mov gs,ax
mov eax,Machine_State._Eflags
push eax
popfd
mov eax,Machine_State._CR0
mov cr0,eax
mov eax,Machine_State._EAX
mov ecx,Machine_State._ECX
mov edx,Machine_State._EDX
mov ebx,Machine_State._EBX
mov ebp,Machine_State._EBP
mov esi,Machine_State._ESI
mov edi,Machine_State._EDI
ret
Restore_State endp

View file

@ -0,0 +1,51 @@
;-----------------------------------------------------------------------------
;
; MACROS.286
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;---------------------------------------------------------------
; Macro definitions
;---------------------------------------------------------------
FARJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF
db 0eah ;; jmp instruction
dw offset destination ;; offset word
dw selector ;; segment selector word
endm
IO_DELAY MACRO
out 0edh,ax
endm
LOADALL MACRO
mov cx,ABS0
mov es,cx
mov cx,(size Loadall_struc) / 2
mov si,offset Loadall_tbl
mov di,800h
rep movsw
db 0fh,05
ENDM
PRINT_STRING MACRO MSG_NAME
mov ah,9
mov dx,offset MSG_NAME
int 21h
ENDM

View file

@ -0,0 +1,78 @@
;-----------------------------------------------------------------------------
;
; MACROS.386
;
; Copyright (c) 1991, 1995-Present Robert Collins
;
; You have my permission to copy and distribute this software for
; non-commercial purposes. Any commercial use of this software or
; source code is allowed, so long as the appropriate copyright
; attributions (to me) are intact, *AND* my email address is properly
; displayed.
;
; Basically, give me credit, where credit is due, and show my email
; address.
;
;-----------------------------------------------------------------------------
;
; Robert R. Collins email: rcollins@x86.org
;
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; Macro definitions
;-----------------------------------------------------------------------------
Init_descriptor macro segment,offset,desc_name
push ax
push dx
push si
push es
mov ax,&segment ;; get segment name
mov es,ax ;; to form 24 bit address
mov si,&offset ;;
mov ax,es ; point to control block
xor dh,dh ; clear upper register
mov dl,ah ; build high byte of 32-bit address
shr dl,4 ; use only high nibble from (AX)
shl ax,4 ; strip high nibble from segment
add ax,si ; add the GDT offset to develop low word
adc dx,0 ; adjust high byte if carry from low
mov &desc_name.Base_A15_A00,ax ;; low word of address
mov &desc_name.Base_A23_A16,dl ;; high byte of address
mov &desc_name.Base_A31_A24,dh ;; high byte of linear address
pop es
pop si
pop dx
pop ax
endm
FARJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF
db 0eah ;; jmp instruction
dw offset destination ;; offset word
dw selector ;; segment selector word
endm
LONGJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF
db 0eah ;; jmp instruction
dd offset destination ;; offset word
dw selector ;; segment selector word
endm
IO_DELAY MACRO
out 0edh,ax
endm
LOADALL MACRO
db 0fh,07h
ENDM
PRINT_STRING MACRO MSG_NAME
mov ah,9
mov dx,offset MSG_NAME
int 21h
ENDM

File diff suppressed because it is too large Load diff