Consolidated /docs into /pubs

This commit is contained in:
Jeff Parsons 2017-09-12 11:28:18 -07:00 committed by Jeff Parsons
commit 71d117fa02
106 changed files with 350 additions and 317 deletions

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

@ -0,0 +1,240 @@
---
layout: page
title: "x86 Instructions: LOADALL"
permalink: /pubs/x86/ops/LOADALL/
---
LOADALL386 (0x070F)
---
### Description
Excerpt from [http://www.rcollins.org/secrets/opcodes/LOADALL.html](http://www.rcollins.org/secrets/opcodes/LOADALL.html):
(LOADALL) An undocumented op code used by ICE host software and
diagnostics software to test CPU functionality. This instruction
has the ability to bypass the entire protection checking mechanism
in the CPU, and therefore can be used to test many aspects of CPU
behavior that can't be duplicated by any other software means.
Read LOADALL magazine article and download LOADALL demo source code.
Undocumented: Available on all 80386 processors.
Useful for diagnostics purposes on production
CPU's.
Useful for ICE BONDOUT CPU's to return the
processor to EMUlation state.
LOADALL
Flags: Loads the entire CPU state
All flags set according to +----------+----------+
the LOADALL flags image. | 00001111 | 00000111 |
+----------+----------+
| 0F | 07 |
+----------+----------+
Input: ES:EDI points to the Clocks: 122
LOADALL register image. Bus Cycles: 51
LOADALL loads the entire CPU state from a table pointed to by
ES:EDI. At the completion of LOADALL, the CPU state is defined
according to this table. No protection checks are performed
against values in the table, and LOADALL can generate no
exceptions in real mode, or in protected mode at IOPL 0.
Attempting to execute LOADALL at any other privilege level will
generate an exception 13.
There are three types of structures in the LOADALL image:
1) 32-bit CPU registers entries;
2) 16-bit segment registers (zero-extended to 32-bits);
3) 96-bit segment descriptor cache entries.
The segment register entries have the following format:
SREG STRUC
REG_VAL DW ? ; low 16-bits defined
DW 0 ; high 16-bits=0
ENDS
The segment descriptor cache entires have the following format:
DESC_CACHE STRUC
DB 0 ; b[00-07] not used
S_USE DB ? ; b[14] operand size
S_Access DB ? ; b[16-23] Access Rights
DB 0 ; b[24-31] not used
S_Addr DD ? ; Segment Address in memory
S_Limit DD ? ; Segment size limit
ENDS
The LOADALL tables is organized as follows:
;----------------------------------------------------------------
; LOADALL table pointed to by ES:EDI
;----------------------------------------------------------------
Offset Description Size Value
====== =========== ==== =====
[00] CR0 DD ?
[04] EFLAGS DD ?
[08] EIP DD ?
[0C] EDI DD ?
[10] ESI DD ?
[14] EBP DD ?
[18] ESP DD ?
[1C] EBX DD ?
[20] EDX DD ?
[24] ECX DD ?
[28] EAX DD ?
[2C] DR6 DD ?
[30] DR7 DD ?
[34] TR_REG SREG <?>
[38] LDT_REG SREG <?>
[3C] GS_REG SREG <?>
[40] FS_REG SREG <?>
[44] DS_REG SREG <?>
[48] SS_REG SREG <?>
[4C] CS_REG SREG <?>
[50] ES_REG SREG <?>
[54] TSS_DESC DESC_CACHE <?,?,?>
[60] IDT_DESC DESC_CACHE <0,?,?>
[6C] GDT_DESC DESC_CACHE <0,?,?>
[78] LDT_DESC DESC_CACHE <?,?,?>
[84] GS_DESC DESC_CACHE <?,?,?>
[90] FS_DESC DESC_CACHE <?,?,?>
[9C] DS_DESC DESC_CACHE <?,?,?>
[A8] SS_DESC DESC_CACHE <?,?,?>
[B4] CS_DESC DESC_CACHE <?,?,?>
[C0] ES_DESC DESC_CACHE <?,?,?>
[CC] LENGTH OF TABLE
The following two diagrams take a closer look at fields within
the LOADALL table:
1) the descriptor cache register;
2) the access rights within the descriptor cache register.
;---------------------------------------------------------------------
; Segment descriptor cache register
;
; 9 6 3 2 1 1 0 0
; 5 3 1 3 5 3 7 0
; +--------------+---------------------+---+---------------+---+---+
; | 32-bit limit | 32-bit base address | 0 | Access Rights | 0 | 0 |
; +--------------+---------------------+---+---------------+---+---+
;
;---------------------------------------------------------------------
; 386 Descriptor Cache Access Rights
;
; ++++++++----------------------------- 0=Undefined
; |||||||| +--------------------------- Present 0=No 1=Yes
; |||||||| |++------------------------- Descriptor privelege level
; |||||||| |||+------------------------ System Desc. 0=Sys 1=Code/Data
; |||||||| ||||+++--------------------- Type(*)
; |||||||| ||||||+-----------------------Read/Write 0=R/O 1=R/W
; |||||||| |||||+|-----------------------Expansion 0=Up 1=Dwn
; |||||||| ||||+||-----------------------Executable 0=No 1=Yes*
; |||||||| ||||||| 000=Read Only
; |||||||| ||||||| 001=Read/Write
; |||||||| ||||||| 010=Read Only, Expand down
; |||||||| ||||||| 011=Read/Write, Expand down
; |||||||| ||||||| 100=Execute only
; |||||||| ||||||| 101=Execute/Read
; |||||||| ||||||| 110=Execute only, conforming
; |||||||| ||||||| 111=Execute/Read, conforming
; |||||||| |||||||+-------------------- Accessed
; |||||||| |||||||| +------------------ 0=Undefined (was G bit)
; |||||||| |||||||| |+----------------- Default operand size(+)
; |||||||| |||||||| || 0=16-bit operands
; |||||||| |||||||| || 1=32-bit operands
; |||||||| |||||||| ||
; |||||||| |||||||| ||++++++-++++++++-- 0=Undefined
; |||||||| |||||||| |||||||| ||||||||
; |||||||| |||||||| |||||||| ||||||||
; 3||||||||2||||||||1||||||||0||||||||0 Bit
; 1||||||||3||||||||5||||||||7||||||||0 Offset
; +++++++++++++++++++++++++++++++++++++
; | Intel |22221111|11|Intel| Intel | (*) = CS can be marked as a R/W
; |Reserved|32109876|54|Rsvd.|Reserved| data segment if LOADALL
; +++++++++++++++++++++++++++++++++++++ is used to load register.
; (+) = Only applicable for CS
;
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; A closer look at the access rights field definitions:
;
; 2 2 2 2 1 1 1 1 1 1 1 Bit 2 2 2 2 1 1 1 1 1 1
; 3 2 1 0 9 8 7 6 5 4 3 Offset 3 2 1 0 9 8 7 6 5 4
; +-+---+-+-----+-+-+-+-+ +-+---+-+-----+-+-+-+
; |P|DPL|S|Type |A|0|G|D| |P|DPL|S| Type |G|D|
; | | | |0| | | | | | | | | | | |1| | | | | | |
; +-+---+-+-----+-+-+-+-+ +-+---+-+-----+-+-+-+
; Bit:
; P Present bit. 1=Present, 0=Not present.
; This bit signals the CPU if the segment addressed by the
; segment base address is actually present in memory.
; DPL Descriptor Privilege Level: 0=highest, 3=lowest
; S System descriptor: 0=Code, Data; 1=System descriptor
; Type Segment Type: (S=0)
; +-+-+-+
; |X|Y|Z|
; +-+-+-+
; | | |
; | | +-- Read/Write 0=Read-only 1=Read/Write
; | +---- Expansion direction. 0=Expand up 1=Expand down
; +------ Executable 0=Data Seg 1=Code Seg
; Type Segment Type: (S=1)
; 0000 = Reserved
; 0001 = Available 286 TSS
; 0010 = LDT
; 0011 = Busy 286 TSS
; 0100 = 286 Call Gate
; 0101 = Task Gate
; 0110 = 286 Interrupt Gate
; 0111 = 286 Trap Gate
; 1000 = Reserved
; 1001 = Available 386, 486 TSS
; 1010 = Reserved
; 1011 = Busy 386, 486 TSS
; 1100 = 386, 486 Call Gate
; 1101 = Reserved
; 1110 = 386, 486 Interrupt Gate
; 1111 = 386, 486 Trap Gate
; A Accessed (S=0) 0=Not Accessed 1=Accessed
; The processor sets this bit when the descriptor is
; accessed.
; G Granularity 0=Byte 1=4k
; When set, upon loading the limit field of the descriptor
; cache register, the CPU shifts the limit by 12, and fills
; in the 1st 12 bits with 1's as follows:
; SHL LIMIT,12
; OR LIMIT,0FFFh
; D Default operand size 0=16-bit 1=32-bit
; When set, the CPU interprets all operands, and effective
; addresses as 32-bit values. When clear, all operands
; and effective addresses are 16-bit values. This bit
; is only applicable to the CS descriptor cache.
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; The definition of these bits is exactly as that of the access
; rights in the descriptor table, with the following exceptions:
; 1) The "PRESENT" bit becomes a valid bit. Using LOADALL, you
; may load a descriptor cache register whose P bit is marked
; not present (P=0). During normal CPU operaion, simply
; loading the segment selector with a descriptor table entry
; whose P=0 will cause an exception-11. This is different
; that operating with LOADALL. LOADALL will let you load the
; descriptor cache register with P=0. But any memory
; reference using that segment selector will cause exception-
; 13.
; 2) The DPL field for SS & CS descriptors determine the CPL.
; 3) The DPL field for DS, ES, FS, & GS should be 3.
; 4) The Granularity (G) bit has no effect on the limit field
; in the descriptor cache register
; 5) A Code segment (CS) may be Read/Write/Executable by setting
; 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