Consolidated /docs into /pubs
This commit is contained in:
parent
9d356c582b
commit
71d117fa02
106 changed files with 350 additions and 317 deletions
9
pubs/x86/README.md
Normal file
9
pubs/x86/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
layout: page
|
||||
title: x86 Documentation
|
||||
permalink: /pubs/x86/
|
||||
---
|
||||
|
||||
Placeholder for future x86 documentation.
|
||||
|
||||
* [x86 Instructions](ops/)
|
||||
86
pubs/x86/ops/AAA/README.md
Normal file
86
pubs/x86/ops/AAA/README.md
Normal 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 %}
|
||||
26
pubs/x86/ops/AAA/pcjs/opAAA.js
Normal file
26
pubs/x86/ops/AAA/pcjs/opAAA.js
Normal 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
201
pubs/x86/ops/AAD/AAD.ASM
Normal 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
|
||||
|
||||
|
||||
48
pubs/x86/ops/AAD/README.md
Normal file
48
pubs/x86/ops/AAD/README.md
Normal 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
218
pubs/x86/ops/AAM/AAM.ASM
Normal 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
|
||||
|
||||
|
||||
64
pubs/x86/ops/AAM/README.md
Normal file
64
pubs/x86/ops/AAM/README.md
Normal 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)
|
||||
84
pubs/x86/ops/ICEBP/README.md
Normal file
84
pubs/x86/ops/ICEBP/README.md
Normal 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).
|
||||
625
pubs/x86/ops/LOADALL/286load.asm
Normal file
625
pubs/x86/ops/LOADALL/286load.asm
Normal 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
|
||||
;---------------------------------------------------------------
|
||||
1000
pubs/x86/ops/LOADALL/386load.asm
Normal file
1000
pubs/x86/ops/LOADALL/386load.asm
Normal file
File diff suppressed because it is too large
Load diff
240
pubs/x86/ops/LOADALL/README.md
Normal file
240
pubs/x86/ops/LOADALL/README.md
Normal 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)
|
||||
203
pubs/x86/ops/LOADALL/cpu_type.asm
Normal file
203
pubs/x86/ops/LOADALL/cpu_type.asm
Normal 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
|
||||
648
pubs/x86/ops/LOADALL/emuload.asm
Normal file
648
pubs/x86/ops/LOADALL/emuload.asm
Normal 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
|
||||
;---------------------------------------------------------------
|
||||
382
pubs/x86/ops/LOADALL/loadfns.286.asm
Normal file
382
pubs/x86/ops/LOADALL/loadfns.286.asm
Normal 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
|
||||
205
pubs/x86/ops/LOADALL/loadfns.386.asm
Normal file
205
pubs/x86/ops/LOADALL/loadfns.386.asm
Normal 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
|
||||
51
pubs/x86/ops/LOADALL/macros.286.asm
Normal file
51
pubs/x86/ops/LOADALL/macros.286.asm
Normal 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
|
||||
78
pubs/x86/ops/LOADALL/macros.386.asm
Normal file
78
pubs/x86/ops/LOADALL/macros.386.asm
Normal 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
|
||||
1276
pubs/x86/ops/LOADALL/tspec_a3_doc.html
Normal file
1276
pubs/x86/ops/LOADALL/tspec_a3_doc.html
Normal file
File diff suppressed because it is too large
Load diff
93
pubs/x86/ops/README.md
Normal file
93
pubs/x86/ops/README.md
Normal 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
|
||||
51
pubs/x86/ops/SALC/README.md
Normal file
51
pubs/x86/ops/SALC/README.md
Normal 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.
|
||||
51
pubs/x86/ops/UMOV/README.md
Normal file
51
pubs/x86/ops/UMOV/README.md
Normal 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.
|
||||
Loading…
Reference in a new issue