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

9
pubs/x86/README.md Normal file
View file

@ -0,0 +1,9 @@
---
layout: page
title: x86 Documentation
permalink: /pubs/x86/
---
Placeholder for future x86 documentation.
* [x86 Instructions](ops/)

View file

@ -0,0 +1,86 @@
---
layout: page
title: "x86 Instructions: AAA"
permalink: /pubs/x86/ops/AAA/
---
AAA (0x37)
---
### Description
AAA converts the result of the addition of two valid unpacked BCD digits to a valid 2-digit BCD number and
takes the AL register as its implicit operand.
For the previous addition to have had any meaning, each of the two operands of the addition must have had its
lower 4 bits contain a number in the range from 0 to 9. The AAA instruction then adjusts AL so that it contains
a correct BCD digit. If the addition produced a decimal carry (AF=1), the AH register is incremented and the carry
(CF) and auxiliary carry (AF) flags are set to 1. If the addition did not produce a decimal carry, CF and AF are
cleared to 0 and AH is not altered. In both cases, the high-order 4 bits of AL are cleared to 0.
Traditionally, this instruction is labeled as ASCII Adjust After Addition. And AAA will adjust the result of the
addition of two ASCII characters that were in the range from 30h ("0") to 39h ("9"). This is because the lower 4 bits
of those characters fall in the range from 0 to 9. The result of the addition, however, is not an ASCII character;
it is a BCD digit.
The following example shows how to add BCD numbers then adjust the result:
MOV AH,0 ; Clear AH for most significant digit
MOV AL,6 ; BCD 6 in AL
ADD AL,5 ; Add BCD 5 to digit in AL
AAA ; AH=1, AL=1 representing BCD 11.
### Algorithm
IF ((AL AND 0Fh)>9 OR (AF=1) THEN
IF (8086 OR 8088) THEN ;See note 1
AL=AL+6
ELSE ;80286 or later
AX=AX+6
ENDIF
AH=AH+1
AF=1
CF=1
ELSE
AF=0
CF=0
ENDIF
AL=AL AND 0FH
### Notes
1. The 8086 and 8088 implement AAA differently than later processors. On the 80286 and later processors,
the first addition is performed on AX instead of AL, incrementing the AH register if a carry is generated out
of AL. If AX contains OOFFh, executing AAA on an 8088 will leave AX=0105h. On an 80386, the same operation
will leave AX=0205h. Despite the different implementation, this instruction does operate as intended for all
valid operands.
2. The upper 4 bits of the AL register are always cleared to 0. This is not noted correctly in Intel's
documentation for the 80386 and 80486.
### Flags
**O** | **D** | **I** | **T** | **S** | **Z** | **A** | **P** | **C**
:---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---:
- | | | | - | - | * | - | *
### Timing
Operands | **x** | **8088** | **8086** | **80286** | **80386** | **80486**
---------- | :---: | :------: | :------: | :-------: | :-------: | :-------:
none | 0 | 8 | 8 | 3 | 4 | 3
(x is the number of memory transfers)
---
Source: PC Magazine "Programmer's Technical Reference: The Processor and Coprocessor," by Robert L. Hummel.
---
### PCjs Code
{% highlight javascript linenos %}
{% include_relative pcjs/opAAA.js %}
{% endhighlight %}

View file

@ -0,0 +1,26 @@
/**
* op=0x37 (AAA)
*
* @this {X86CPU}
*/
X86.opAAA = function()
{
var CF, AF;
var AL = this.regEAX & 0xff;
var AH = (this.regEAX >> 8) & 0xff;
if ((AL & 0xf) > 9 || this.getAF()) {
AL += 6;
/*
* Simulate the fact that the 80286 and higher add 6 to AX rather than AL.
*/
if (this.model >= X86.MODEL_80286 && AL > 0xff) AH++;
AH++;
CF = AF = 1;
} else {
CF = AF = 0;
}
this.regEAX = (this.regEAX & ~0xffff) | (((AH << 8) | AL) & 0xff0f);
if (CF) this.setCF(); else this.clearCF();
if (AF) this.setAF(); else this.clearAF();
this.nStepCycles -= this.cycleCounts.nOpCyclesAAA;
};

201
pubs/x86/ops/AAD/AAD.ASM Normal file
View file

@ -0,0 +1,201 @@
.386p
;-----------------------------------------------------------------------------
;
; AAD.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
;
;-----------------------------------------------------------------------------
.model small
.code
.286
;-----------------------------------------------------------------------------
; Interrupt vector segment
;-----------------------------------------------------------------------------
ABS0 segment at 0
org 0*4
Orig_INT0 label word
ABS0 ends
;-----------------------------------------------------------------------------
; Local stack frame variable(s)
;-----------------------------------------------------------------------------
INT0 equ [bp-4]
;-----------------------------------------------------------------------------
; Instruction macro definition
;-----------------------------------------------------------------------------
AADI MACRO VALUE
db 0d5h,VALUE
ENDM
;-----------------------------------------------------------------------------
TEST_AAD proc near ; Test AAD IMMED08 instruction functionality.
;-----------------------------------------------------------------------------
; AAD:
; {
; AL = AH*IMMED08 + AL
; AH = 0
; CF = AL[b7] Overflow?
; OF = AL[b7] set, but not overflow? or AL[b7] overflow, but not set?
; AF = AL[b3] overflow, or AL[b3] borrow?
; SF = AL[b7]=1?
; ZF = AL==0?
; PF = Even/Odd parity
; }
; Input: None
; Output: BX = Bit mask of results (3FFF if all tests passed)
; [b13] = 1, NS flag test passed
; [b12] = 1, SF flag test passed
; [b11] = 1, NZ flag test passed
; [b10] = 1, ZF flag test passed
; [b09] = 1, PO flag test passed
; [b08] = 1, PE flag test passed
; [b07] = 1, AF (test 2) flag test passed
; [b06] = 1, AF (test 1) flag test passed
; [b05] = 1, NA flag test passed
; [b04] = 1, OF (test 2) flag test passed
; [b03] = 1, NO flag test passed
; [b02] = 1, OF (test 1) flag test passed
; [b01] = 1, CY flag test passed
; [b00] = 1, NC flag test passed
; Register(s) modified: AX, BX, CX
;-----------------------------------------------------------------------------
xor bx,bx ; clear result flags
xor cx,cx
;-----------------------------------------------------------------------------
; Test Carry Flag set. According to Intel, CF is undefined after AAD, but
; should be set according to the results. Since this is an arithmatic
; operation, CF should be set according to the results. Let's find out!
;-----------------------------------------------------------------------------
mov ax,3300h ; set AH=51, AL=0 and perform 51*5.
AADI 5 ; result should not produce a CF
jc @F ; oops
or bl,1 ; set NC passed
@@: mov ax,3301h ; set AH=51, AL=1 and perform
AADI 5 ; (55*5)+1 should set CF
jnc @F ; oops, didn't work
or bl,2 ; set CF passed
;-----------------------------------------------------------------------------
; Test Overflow Flag set. There are two ways the OF can be set:
; 1) If AL[b7] is set, but doesn't overflow into CF;
; 2) If AL[b7] overflows, but doesn't get set.
;-----------------------------------------------------------------------------
; 1) If AL[b7] is set, but doesn't overflow into CF;
;-----------------------------------------------------------------------------
mov ax,2a02h ; perform (42*3)+2 = 128, should set
AADI 3 ; OF.
jno @F ; oops, didn't work
or bl,4 ; set OF passed
@@: mov ax,8080h ; perform (128*2)+128, should not set
AADI 2 ; OF because it sets CF, & AL[b7]
jo @F ; oops, didn't work
or bl,8 ; set NO passed
;-----------------------------------------------------------------------------
; 2) If AL[b7] overflows, but doesn't get set.
;-----------------------------------------------------------------------------
@@: mov ax,8080h ; perform (128*2)+128, should not set
AADI 1 ; OF because it sets CF, & AL[b7]
jno @F ; oops, didn't work
or bl,10h
;-----------------------------------------------------------------------------
; Test Auxiliary carry Flag (AF) set. AF is set in two ways:
; 1) If there is a carry out of bit3;
; 2) If there is a borrow out of bit3.
;-----------------------------------------------------------------------------
@@: mov ax,2200h ; perform (34*5)+0, should not set
AADI 5 ; AM because no carry from bit3
lahf ; get flags
test ah,10h ; AF set?
jnz @F ; yes, must have been a mistake
or bl,20h ; set NA flag passed
;-----------------------------------------------------------------------------
; 1) If there is a carry out of bit3;
;-----------------------------------------------------------------------------
@@: mov ax,2208h ; perform (34*5)+8, should set AF
AADI 5 ; because a bit3 will carry
lahf ; get flags
test ah,10h ; AF set?
jz @F ; nope, oops
or bl,40h ; set AF flag passed
;-----------------------------------------------------------------------------
; 2) If there is a borrow out of bit3.
; (This may not be an accurate test of borrowing out of bit 3, because
; this test adds a -8 to the result of the multplication. In other
; words, the addition algorithm is still used, not the subtraction
; algorithm -- if they are even different in the first place.)
;-----------------------------------------------------------------------------
@@: mov ax,22f8h ; perform (34*5)-8, should set AF
AADI 5 ; because a bit3 will borrow
lahf ; get flags
test ah,10h ; AF set?
jz @F ; nope, oops
or bl,80h ; set AF flag passed
;-----------------------------------------------------------------------------
; Test EVEN and ODD parity by generating results in the low byte that
; contain even and odd parity respectively.
;-----------------------------------------------------------------------------
@@: mov ax,0a00h ; 10*17+0 which is EVEN parity
AADI 11h
jpo @F ; didn't generate even parity
or bh,1 ; set even parity flag passed
@@: mov ax,0a01h ; 10*17+1 which is ODD parity
AADI 11h
jpe @F ; didn't generate odd parity
or bh,2 ; set odd parity flag passed
;-----------------------------------------------------------------------------
; Test ZERO FLAG by generating results that produce a zero, and non-zero.
;-----------------------------------------------------------------------------
@@: mov ax,0880h ; 8*16+128 will generate a zero result
AADI 10h ; This should force ZF=1
jnz @F ; didn't work as expected
or bh,4
@@: mov ax,0881h ; 8*16+129 will be non-zero
AADI 10h ; This should force ZF=0,
jz @F ; didn't work as expected
or bh,8
;-----------------------------------------------------------------------------
; Test Sign Flag by generating results whose highest bit is on.
; I'll try and do this in a manner that doesn't set OF.
;-----------------------------------------------------------------------------
mov ax,80c0h ; (128*128)+192 will generate SF
AADI 80h ; without generating OF.
jns @F ; oops
or bh,10h ; set SF flag passed
@@: mov ax,8040h ;
AADI 80h
js @F
or bh,20h
@@: ret
Test_AAD endp
end

View file

@ -0,0 +1,48 @@
---
layout: page
title: "x86 Instructions: AAD"
permalink: /pubs/x86/ops/AAD/
---
AAD (0xD5)
---
### Description
Excerpt from [http://www.rcollins.org/secrets/opcodes/AAD.html](http://www.rcollins.org/secrets/opcodes/AAD.html):
Undocumented: Available to all Intel x86 processors
Useful in production source code.
AAD
Flags: ASCII Adjust before Division
+-+-+-+-+-+-+-+-+-+ +----------+----------+
|O|D|I|T|S|Z|A|P|C| | 11010101 | DATA |
+-+-+-+-+-+-+-+-+-+ +----------+----------+
|+| | | |+|+|+|+|+| | D5 | IMM8 |
+-+-+-+-+-+-+-+-+-+ +----------+----------+
This instruction is the multiplication counterpart to AAM. As is the
case with AAM, AAD uses the second byte as an operand. This operand is
the multiplicand for AAD. Like AAM, AAD provides a way to execute a
MUL IMM8 that is unavailable through any other means in the CPU.
Unlike MUL, or IMUL, AAD sets all of the CPU status flags according
to the result. Intel states that the Overflow Flag (OF), Auxiliary carry
Flag (AF), and Carry Flag (CF) are undefined. This assertion is incorrect.
These flags are fully defined, and are set consistently with respect to
any other integer operations.
And again, like AMM, beginning with the Pentium, Intel has finally
acknowledged the existence of the second byte of this instruction as its
operand. Intel says:
Note: imm8 has the value of the instruction's second byte. The
second byte under normally assembly [sic] of this instruction will
be 0A, however, explicit modification of this byte will result in
the operation described above and may alter results.
This instruction exists in this form on all Intel x86 processors.
The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/):
* [AAD.ASM](AAD.ASM)

218
pubs/x86/ops/AAM/AAM.ASM Normal file
View file

@ -0,0 +1,218 @@
.386p
;-----------------------------------------------------------------------------
;
; AAM.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
;
;-----------------------------------------------------------------------------
.model small
.code
.286
;-----------------------------------------------------------------------------
; Interrupt vector segment
;-----------------------------------------------------------------------------
ABS0 segment at 0
org 0*4
Orig_INT0 label word
ABS0 ends
;-----------------------------------------------------------------------------
; Local stack frame variable(s)
;-----------------------------------------------------------------------------
INT0 equ [bp-4]
;-----------------------------------------------------------------------------
; Instruction macro definition
;-----------------------------------------------------------------------------
AAMI MACRO VALUE
db 0d4h,VALUE
ENDM
;-----------------------------------------------------------------------------
TEST_AAM proc near ; Test AAM IMMED08 instruction functionality.
;-----------------------------------------------------------------------------
; Input: None
; Output: BX = Bit mask of results (3FF if all tests passed)
; [b15..b10] = Unused
; [b9] = 1, Carry Flag test passed
; [b8] = 1, Overflow Flag test passed
; [b7] = 1, Auxiliary carry Flag test passed
; [b6] = 1, INT0 exception passed
; [b5] = 1, ZF flag test passed
; [b4] = 1, NZ flag test passed
; [b3] = 1, NS flag test passed
; [b2] = 1, SF flag test passed
; [b1] = 1, PE flag test passed
; [b0] = 1, PO flag test passed
; Register(s) modified: AX, BX, CX, SI
;-----------------------------------------------------------------------------
xor bx,bx ; clear result flags
xor cx,cx
;-----------------------------------------------------------------------------
; Test EVEN and ODD parity by generating results in the low byte that
; contain even and odd parity respectively.
;-----------------------------------------------------------------------------
mov al,0fbh ; 251/252 leave remainder=251, whose
; parity=ODD.
AAMI 0FCh ; generate odd parity
jpe @F ; oops odd parity not set
or bl,1 ; set even parity flag
@@: AAMI 0F1h ; 251/241 leaves remainder=10, whose
; parity=EVEN
jpo @F ; oops even parity
or bl,2 ; set odd parity flag
;-----------------------------------------------------------------------------
; Test Sign flag by generating results in the low byte whose bit7=1. This
; is easily done by putting 80h in AL, and dividing by a number larger than
; 80h. The remainder will always be 80h, and therefore the sign flag is set.
;-----------------------------------------------------------------------------
@@: mov al,080h ; 128/255 leaves remainder=128, whose
AAMI 0ffh ; Sign flag=1 (bit7=1)
jns @F ; oops no SF!
or bl,4 ; set SF flag
@@: AAMI 80h ; 128/128 leaves remainder=0, whose
js @F ; sign flag=0 (bit7=0)
or bl,8 ; set NS flag
;-----------------------------------------------------------------------------
; Test ZERO flag by generating results in the low byte as ZERO, and NON-ZERO.
;-----------------------------------------------------------------------------
@@: mov al,0f0h ; 240/127 leaves remainder=113, which
AAMI 7Fh ; is obviously not 0.
jz @F ; oops, ZF!
or bl,10h ; set NF flag
@@: AAMI 113d ; 113/113 leaves remainder=0, which is
jnz @F ; obviously 0!
or bl,20h ; set ZF flag
;-----------------------------------------------------------------------------
; Test that AAM 0 (divide by 0) will generate the appropriate CPU exception
; (exception 0). This can be tested by setting up a simple INT0 handler, and
; try to divide by 0. If the execption occured, then success.
;-----------------------------------------------------------------------------
@@: enter 4,0 ; create stack frame
mov word ptr INT0,offset INT0_handler
mov INT0[2],cs ; save current CS to restore later
call set_INT0_vector ; set pointer to our INT6 handler
AAMI 0 ; generate INT0 exception
jcxz @F ; if CX=0, then an error occurred
or bl,40h ; set success flag
@@: call set_INT0_vector ; restore original INT0 vector
leave ; restore stack frame
;-----------------------------------------------------------------------------
; Test unaffected flags will cycle through every possible combination of
; AAM, and test that none of the "unaffected" flags are changed. For
; brevity of source code, I'm going to do one of the biggest no-no's in
; programming...I'm going to write self modifying code.
;-----------------------------------------------------------------------------
; First test the Auxiliary carry Flag (AF). If AF gets set, then the test
; fails.
;-----------------------------------------------------------------------------
mov si,offset @AF[1] ; get address of operand to AAM
mov cx,1 ; start with AAM 01
@@: mov al,ch
mov cs:[si],cl ; modify op code
jmp short @AF ; go
@AF: AAMI 00 ; starting sequence
lahf ; get flags register
test ah,10h ; auxiliary flag set?
jnz short @F ; yes
add ch,1 ; try next dividend
adc cl,0 ; try next divisor
jnc @B ; continue
or bl,80h ; set success flag
;-----------------------------------------------------------------------------
; Second, test the Overflow Flag (OF). If OF gets set, then the test fails.
;-----------------------------------------------------------------------------
@@: mov si,offset @OF[1] ; get address of operand to AAM
mov cx,1 ; start with AAM 01
@@: mov al,ch
mov cs:[si],cl ; modify op code
jmp short @OF ; go
@OF: AAMI 00 ; starting sequence
jo short @F ; test failed
add ch,1 ; try next dividend
adc cl,0 ; try next divisor
jnc @B ; continue
or bh,01h ; set success flag
;-----------------------------------------------------------------------------
; Finally, test the Carry Flag (CF). If CF gets set, then the test fails.
;-----------------------------------------------------------------------------
@@: mov si,offset @CF[1] ; get address of operand to AAM
mov cx,1 ; start with AAM 01
@@: mov al,ch
mov cs:[si],cl ; modify op code
jmp short @CF ; go
@CF: AAMI 00 ; starting sequence
jc short @F ; test failed
add ch,1 ; try next dividend
adc cl,0 ; try next divisor
jnc @B ; continue
or bh,02h ; set success flag
@@: ret ; split
Test_AAM endp
;-----------------------------------------------------------------------------
; Set the INT6 vector by exchanging it with the one currently on the stack.
;-----------------------------------------------------------------------------
set_INT0_vector:
push ds
push ABS0 ; save interrupt vector segment
pop ds ; make DS=INT vector segment
ASSUME DS:ABS0
mov dx,Orig_INT0; ; get offset if INT0 handler
xchg INT0,dx ; set new INT0 offset
mov Orig_INT0,dx
mov dx,Orig_INT0[2] ; get segment of INT0 handler
xchg INT0[2],dx ; set new INT0 segment
mov Orig_INT0[2],dx
pop ds ; restore segment register
ret ; split
ASSUME DS:NOTHING
;-----------------------------------------------------------------------------
; INT0 handler sets a semaphore (CX=FFFF) and adjusts the return address to
; point past the invalid opcode.
;-----------------------------------------------------------------------------
INT0_handler:
enter 0,0 ; create new stack frame
dec cx ; make CX=FFFF
add word ptr ss:[bp][2],2 ; point past invalid opcode
leave
iret
end

View file

@ -0,0 +1,64 @@
---
layout: page
title: "x86 Instructions: AAM"
permalink: /pubs/x86/ops/AAM/
---
AAM (0xD4)
---
### Description
Excerpt from [http://www.rcollins.org/secrets/opcodes/AAM.html](http://www.rcollins.org/secrets/opcodes/AAM.html):
Undocumented: Available to all Intel x86 processors.
Useful in production source code.
AAM
Flags: ASCII Adjust after Multiply
+-+-+-+-+-+-+-+-+-+ +----------+----------+
|O|D|I|T|S|Z|A|P|C| | 11010100 | DATA |
+-+-+-+-+-+-+-+-+-+ +----------+----------+
|0| | | |+|+|0|+|0| | D4 | IMM8 |
+-+-+-+-+-+-+-+-+-+ +----------+----------+
AAM is shown as a two byte encoding used to divide AL by 10, putting
the quotient in AH, and the remainder in AL. However, AAM is listed in
the op code map as a single byte instruction. This leads one to wonder
why a two-byte opcode is listed in the single-byte opcode map.
In reality, the second byte is an undocumented operand to AAM. The operand
is the divisor. In its documented incarnation, AAM is encoded as D4 0A.
The operand 0A is the divisor. This divisor can be changed to any value
between 0 and FF. Using AAM in this manner is useful -- as it extends the
CPU instruction set to include a DIV IMM8 instruction that is not available
from any other form of the DIV instruction.
The extended form of the AAM instruction is also useful because it sets the
flags register according to the results, unlike the DIV or IDIV instruction.
According to Intel documentation, SF, ZF, and PF flags are set according
to the result, while OF, AF, and CF are undefined. However, if AAM were used
strictly as documented, then the Sign Flag (SF) could not be set under any
circumstances, since anything divided by 10 will leave a remainder between
0 and 9. Obviously the remainder could never be between 128 and 255 (or -1
and -128 if you prefer) if used only as documented. Since AAM divides an
8-bit number by another 8-bit number, a carry or overflow could never occur.
Therefore CF and OF always=0. Intel claims they are undefined, but my
observations are consistent with my theory.
Contrary to documentation, AAM will generate exceptions in real mode,
protected mode, and V86 mode. AAM can only generate Exception 0 -- divide
by 0.
Finally, in the Pentium User's Manual, this heretofore undocumented form of
AMM is described. Intel says:
Note: imm8 has the value of the instruction's second byte. The
second byte under normally assembly [sic] of this instruction will
be 0A, however, explicit modification of this byte will result in
the operation described above and may alter results.
This instruction exists in this form on all Intel x86 processors.
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,84 @@
---
layout: page
title: "x86 Instructions: ICEBP"
permalink: /pubs/x86/ops/ICEBP/
---
ICEBP (0xF1)
---
### Description
Excerpt from [http://www.rcollins.org/secrets/opcodes/ICEBP.html](http://www.rcollins.org/secrets/opcodes/ICEBP.html):
An undocumented op code that will make debugging run-time code
on an ICE easier. Normally, to set an arbitrary breakpoint in a
program which was loaded by an operating system, you must perform
a laborious task of figuring out where your program was loaded
in memory. Follow that process with an equally laborious task of
calculating the offset in memory which corresponds to the desired
breakpoint.
This process is exacerbated by programs which use many segments,
especially many code segments. Now for one final complication,
consider that your program switches from real mode, to protected mode,
with paging enabled, and you are not using a 1-to-1 mapping of physical
to virtual memory. You want to talk about a nightmare just to figure
out where to set a breakpoint?
All of these problems are eliminated, simply by using this instruction
-- provided you know its caveats.
Undocumented: Available to all 80386-class (and above)
processors as described herein.
May be available to 80286 processors, but
implemented in a different manner.
Useful to BONDOUT (ICE) processors.
Especially useful during ICE debugging.
Useful in production source code.
ICEBP
Flags: ICE Break Point
+-+-+-+-+-+-+-+-+-+ +----------+
|O|D|I|T|S|Z|A|P|C| | 11110001 |
+-+-+-+-+-+-+-+-+-+ +----------+
| | | | | | | | | | | F1 |
+-+-+-+-+-+-+-+-+-+ +----------+
The name ICEBP was given by a pre-production Intel ICE that had the
ability to disassemble undocumented op codes. The name ICEBP is a
misnomer because the instruction is actually a single byte single-step
exception (INT-01).
How you use ICEBP depends upon whether or not you are using an 80386
ICE, Intel486 ICE, or Pentium ICE. For the purposes of this article,
usage of ICEBP on 80386 and Intel486 are identical. Pentium enables
ICEBP a little differently than its predecessors.
Two effects of ICEBP -- 80386 and Intel486
ICEBP has two operational effects: When Interrupt Redirection (IR) is
disabled, ICEBP acts as a single byte INT 01. When this instruction occurs,
it invokes the standard INT 01 handler. Unlike the single step exception
(Trap Flag=1), this instruction does not set the trap flag on the stack
image, nor modifies the trap flag on the stack image. Therefore, upon
termination of the INT 01 handler, execution continues without further
occurrences of the single step breakpoints.
When Interrupt Redirection is enabled, ICEBP will attempt to invoke the
hardware breakpoint handler associated with an In Circuit Emulator (ICE).
If the processor is a production CPU, the processor will hang. If the
processor is a BONDOUT CPU attached to an ICE, ICEBP will cause the ICE
to break from emulation. On an Intel ICE, the message "Unknown Breakpoint
at address xxxx:xxxx:xxxxxxxx" appears on the screen.
There are two ways to enable Interrupt Redirection. It can be done by
directly programming DR7 (see "Undocumented Bits in DR7"), or this bit
can be set (indirectly) using an ICE. To set this bit using an ICE, you
must first be in HALT mode. Any "go til" command that uses the debug
registers will enable Interrupt Redirection. For example, "go til 1234:5678
execute," "go til 1025:3245 write," or simply "go til 0 p" will enable
Interrupt Redirection. This work because the ICE actually uses the debug
registers to trap debug exceptions. Of course, this directly implies that
any time the ICE uses the debug registers to signify break points, and
emulation halts, it does so following an INT 01 to the ICE break point
handler (since interrupt redirection is enabled).

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

93
pubs/x86/ops/README.md Normal file
View file

@ -0,0 +1,93 @@
---
layout: page
title: x86 Instructions
permalink: /pubs/x86/ops/
---
Placeholder for future x86 documentation.
x86 Instructions
----------------
[AAA](AAA/)
[AAD](AAD/)
[AAM](AAM/)
AAS
ADC
ADD
AND
CALL
CBW
CLC
CLD
CLI
CMC
CMP
CMPS
CWD
DAA
DAS
DEC
DIV
ESC
HLT
[ICEBP](ICEBP/)
IDIV
IMUL
IN
INC
INT 3
INT
INTO
IRET
Jcc
JMP
LAHF
LDS
LEA
LES
[LOADALL](LOADALL/)
LOCK
LODS
LOOP
LOOPZ
LOOPNZ
MOV
MOVS
MUL
NEG
NOP
NOT
OR
OUT
POP
POPF
PUSH
PUSHF
RCL
RCR
REP
REPZ
REPNZ
RET
ROL
ROR
SAHF
SAL
[SALC](SALC/)
SAR
SBB
SCAS
SHL
SHR
STC
STD
STI
STOS
SUB
TEST
[UMOV](UMOV/)
WAIT
XCHG
XLAT
XOR

View file

@ -0,0 +1,51 @@
---
layout: page
title: "x86 Instructions: SALC"
permalink: /pubs/x86/ops/SALC/
---
SALC (0xD6)
---
### Description
Excerpt from [http://www.rcollins.org/secrets/opcodes/SALC.html](http://www.rcollins.org/secrets/opcodes/SALC.html):
An undocumented op code that performs an operation common to
every Assembly language subroutine to C and many other higher
level languages. This instruction is a C programmers 'dream'
instruction for interfacing to assembly language.
Undocumented: Available to all Intel x86 processors
Useful in production source code.
SALC
Flags: SET Carry flag to AL
+-+-+-+-+-+-+-+-+-+ +----------+
|O|D|I|T|S|Z|A|P|C| | 11010110 |
+-+-+-+-+-+-+-+-+-+ +----------+
| | | | | | | | | | | D6 |
+-+-+-+-+-+-+-+-+-+ +----------+
The name SALC simply stands for SET the Carry flag in AL. This
instruction is categorized as an undocumented single-byte proprietary
instruction. Intel claims it can be emulated as a NOP. Hardly a NOP,
this instruction sets AL=FF if the Carry Flag is set (CF=1), or resets
AL=00 if the Carry Flag is clear (CF=0). It can best be emulated as
SBB AL,AL. SALC doesn't change any flags, where SBB AL,AL does.
This instruction is most useful to high-level language programmers
whose programs call assembly language, and expect AL to indicate success
or failure. Since it is convenient for assembly language programs to
return status in the CF, this instruction will convert that status to a
form compatible with high level languages.
Over the years, this instruction has been given many names by various
discoverers. I originally gave it the name SETCAL, but the most common
name I've seen in print is SETALC. The name given above, SALC is an
official Intel name.
While perusing the P6 opcode map, I always check for known, undocumented
opcodes. After weeding through the map for many minutes, my patience and
perseverance paid off. I found the opcode, and its name. Intel's name for
this opcode is SALC. This would indicate that Intel plans to officially
document this instruction, beginning with the P6.

View file

@ -0,0 +1,51 @@
---
layout: page
title: "x86 Instructions: UMOV"
permalink: /pubs/x86/ops/UMOV/
---
UMOV (0x100F,0x110F,0x120F,0x130F)
---
### Description
Excerpt from [http://www.rcollins.org/secrets/opcodes/UMOV.html](http://www.rcollins.org/secrets/opcodes/UMOV.html):
An undocumented op code used by ICE host software to perform
memory cycles to the target system during HALT mode.
Undocumented: Available on all 80386/80486 processors.
Useful only to BONDOUT (ICE) processors.
UMOV
Flags: User MOVE data
+-+-+-+-+-+-+-+-+-+ +----------+----------+-------------+
|O|D|I|T|S|Z|A|P|C| | 00001111 | 000100dw | mod,reg,r/m |
+-+-+-+-+-+-+-+-+-+ +----------+----------+-------------+
| | | | | | | | | | | 0F | 1x | xx |
+-+-+-+-+-+-+-+-+-+ +----------+----------+-------------+
UMOV is an acronym for User-MOVe. When the In-Circuit Emulator
(ICE) is in HALT mode, the CPU performs no recognizable bus
cycles. Since the '386 is a dynamic device, it must be executing
some instructions during HALT, but it is not doing it in a way
recognizable to a logic analyzer with a '386 probe attached.
During HALT mode, the ICE differentiates between USER space and
HOST space. The ICE is fetching, and performing all bus cycles
to HOST memory space during HALT, and not USER space. Since the
ICE differentiates between these two memory spaces, it needs a
mechanism to access user memory space. That mechanism is UMOV.
When a user request to view memory, or disassemble memory, the
ICE executes UMOV instructions to get data from User space.
If UMOV is executed by a user program, it will appear it is a
alias for MOV.
The field operands to UMOV are exactly the same as the MOV
instruction. For example:
d Direction. If set (d=1), do memory to register, or register
to register; the reg field is the destination. If cleared
(d=0), do register to memory; the reg field is the source.
w Width. Selects the default data width. W=1 selects
word width, according to the appropriate CPU operating mode,
and/or size prefix override. W=0 selects 8-bit operands.