Ýòîò ïðèìåð äåìîíñòðèðóåò ðàáîòó ïðîöåññîðà â ðåæèìå V86.
 çàùèùåííîì ðåæèìå ñîçäàåòñÿ çàäà÷à âèðòóëüíîãî ðåæèìà, â êîòîðîé çàïóñêìåòñÿ êîìàíäíûé ïðîöåññîð command.com. «Ìîíèòîð âèðòóàëüíîé çàäà÷è» ïîñòîÿííî íàáëþäàåò çà ñîñòîÿíèåì çàäà÷è – î åãî ðàáîòå ñîîáùàåò ìèãàþùèé ñèìâîë «*».
Âíóòðè âèðòóàëüíîé çàäà÷è (ïîä óïðàâëåíèåì command.com) ìîæíî çàïóñòèòü ëþáóþ DOS-ïðîãðàììó, íî èñïîëüçóþùóþ òîëüêî êëàâèàòóðó è ìîíèòîð.
Íèæå ïðèâåäåí èñõîäíûé òåêñò ïðîãðàììû (ñíà÷àëà ãëàâíûé ìîäóëü, à çà íèì «âêëþ÷àåìûå» *.inc - ìîäóëè).
V86.asm
.MODEL
LARGE
INCLUDE MACROSES.INC ; MAIN DEFINITIONS
NESTED_INTS EQU
8 ; DEPTH OF NESTED
IRQS FOR RM/VM
SIZE_STACK EQU
1000H
;-----------------------------------------;
; 16-BIT
REAL/PROTECTED NODE CODE SEGMENT ;
;-----------------------------------------;
.8086
CODE16 SEGMENT PARA USE16
CODE16_BEGIN =
$
ASSUME CS:CODE16,DS:DATA,ES:DATA
START:
MOV
AX, DATA
MOV
DS, AX
MOV
ES, AX ;
LOAD DATA SEGMENTS
LEA
DX, MSG_STARTUP
MOV
AH, 9
INT
21H
CALL
DETECT
.386P
@ENABLE_A20
; ENABLE A20 LINE
IN
AL, PORT_INT_MASK_M
MOV
INT_MASK_M, AL ;
SAVE MASK OF HARDWARE INTS AT MASTER CNTRLR
IN
AL, PORT_INT_MASK_S
MOV
INT_MASK_S, AL ;
SAVE MASK OF HARDWARE INTS AT SLAVE CNTRLR
CLI ; DISABLE
MASKABLE INTS
@DISABLE_NMI ; DISABLE
NON-MASKABLE INTS
INCLUDE SETUPGDT.INC ; FILL GDT
INCLUDE SETUPIDT.INC ; FILL IDT
LGDT
FWORD PTR GDT_GDT ;
LOAD GDTR
LIDT
FWORD PTR IDTR ;
LOAD IDTR
MOV
EAX, CR0
AND
EAX, 01111111111111111111111111110000B
OR
EAX, 00000000000000000000000000000001B
MOV
CR0, EAX ;
SET UP PROTECTED MODE
@JUMP ; OVERLOAD
CODE SELECTOR
MOV
AX, DS_SEL
MOV
DS, AX ;
LOAD DS WITH DATA SELECTOR
MOV
ES, AX ;
LOAD ES WITH DATA SELECTOR
MOV
AX, SS_SEL
MOV
SS, AX ;
LOAD SS WITH STACK SELECTOR
XOR
AX, AX
MOV
FS, AX ;
LOAD FS WITH 0
MOV
GS, AX ;
LOAD GS WITH 0
LLDT
AX ;
LOAD LDTR WITH 0
MOVZX
ESP, SP ; EXPAND SP TO ESP
PUSH
CS ;
PREPARE FOR RETURNING BACK
PUSH
OFFSET START_BACK_TO_16 ;
TO 16-BIT PM CODE
MOV
DS:[ESP32], ESP
LEA
EDI, ENTER_32
MOV
EAX, CS32_SEL
PUSH
EAX
PUSH
EDI ;
PUSH 32-BIT CODE ADDRESS
INCLUDE SETUPTSS.INC ; FILL TSSs
MOV
AX, TSS_MAIN_SEL
LTR
AX ;
LOAD TR REGISTER
@SET_INT_CTRLR 20H, 28H ; REINITIALISE MASTER &
SLAVE INT CONTROLLERS
MOV
AL, 0 ;
MASK = 0
OUT
PORT_INT_MASK_M, AL ;
UNMASK INTS
OUT
PORT_INT_MASK_S, AL ;
UNMASK INTS
@ENABLE_NMI ; ENABLE
NON-MASKABLE INTS
STI ; ENABLE
MASKABLE INTS
@RETF ;
"RETURN" TO 32-BIT CODE
START_BACK_TO_16:
CLI ; DISABLE
MASKABLE INTS
@DISABLE_NMI ; DISABLE
NON-MASKABLE INTS
MOV
AX, DS_SEL
MOV
DS, AX ;
SAFETY IS WHAT WE NEED!!!
INCLUDE SET_RM1.INC ; BACK TO REAL MODE
MOV
AL, INT_MASK_M
OUT
PORT_INT_MASK_M, AL ;
RESTORE MASK OF HARDWARE INTS AT MASTER CNTRLR
MOV
AL, INT_MASK_S
OUT PORT_INT_MASK_S, AL ; RESTORE MASK OF HARDWARE INTS AT
SLAVE CNTRLR
@ENABLE_NMI ; ENABLE
NON-MASKABLE INTS
STI ; ENABLE
MASKABLE INTS
@DISABLE_A20 ; DISABLE A20 LINE
START_EXIT:
LEA
DX, MSG_CONTACT
MOV
AH, 9
INT
21H
MOV
AX, 4C00H
INT
21H ;
EXIT TO DOS
INCLUDE DETECT.INC ; HARDWARE DETECTION CODE
INCLUDE LCOMMAND.INC ; COMMAND.COM LAUNCHER
;-------------------------;
; V86 TASK CODE
GOES HERE ;
;-------------------------;
V86_START:
; LAUNCH
COMMAND.COM
CALL
LCOMMAND
MOV
AX, 0
DIV
AX
; "EXIT" ;)
SIZE_CSEG16 =
($ - CODE16_BEGIN)
CODE16 ENDS
;--------------------------------------;
; HELPFUL CODE
SEGMENT FOR V86 MONITOR ;
;--------------------------------------;
CODE_V86_IRET
SEGMENT PARA USE16
ASSUME CS:CODE_V86_IRET
V86_INT_X:
INT
0
CODE_V86_IRET ENDS
;------------------------------------;
; 32-BIT PROTECTED
MODE CODE SEGMENT ;
;------------------------------------;
CODE32 SEGMENT PARA USE32
CODE32_BEGIN =
$
ASSUME CS:CODE32,DS:DATA,ES:DATA
;--------------------;
; MAIN TASK (RING
0) ;
;--------------------;
ENTER_32:
MOV
AX, DS_SEL
MOV
DS, AX
MOV
WORD PTR DS:[TASK_ADDR+4], TSS_V86_SEL
JMP
FWORD PTR DS:[TASK_ADDR] ;
JUMP TO THE V86 TASK
@RETF ; BACK TO
16-BIT CODE
;----------------------------------------------;
; MAIN ROUTINES
AND HANDLERS ARE INCLUDED HERE ;
;----------------------------------------------;
INCLUDE SCREENIO.INC ; SCREEN I/O ROUTINES
INCLUDE EXC.INC ; EXCEPTION HANDLER
INCLUDE TIMER.INC ; KEYBOARD INTERRUPT
HANDLER
INCLUDE KEYBOARD.INC ; ROUTINE FOR DISPLAYING
TSS
INCLUDE IRQS.INC ; TRAPPINGS TO V86
INCLUDE SERVICE.INC ; SERVICE INTERRUPT
SIZE_CSEG32 = ($ - CODE32_BEGIN)
CODE32 ENDS
;-----------------------------------------;
; COMMON
REAL/PROTECTED MODE DATA SEGMENT ;
;-----------------------------------------;
DATA SEGMENT PARA USE16
DATA_BEGIN =
$
INCLUDE GDT.INC ; GDT TABLE
INCLUDE IDT.INC ; IDT TABLE
INCLUDE TSS.INC ; TSS TABLES
;----------------------------;
; LAUNCH-TIME
ERROR MESSAGES ;
;----------------------------;
MSG_STARTUP DB
"Example of V86 monitor by Alexei A. Frounze (C)
2000",13,10,"$"
MSG_CONTACT DB
"Contact information:",13,10
DB "E-mail : alexfru@chat.ru",13,10
DB "Homepage:
http://alexfru.chat.ru",13,10
DB "Mirror :
http://members.xoom.com/alexfru",13,10,"$"
MSG_NEEDED_386
DB "80386 OR BETTER PROCESSOR
IS NEEDED.",13,10,"$"
MSG_NEEDED_RM
DB "PROCESSOR IS ALREADY IN
PROTECTED MODE.",13,10
DB "PROBABLY WINDOWS OR
EMM386.EXE IS LOADED.",13,10
DB "LOAD PURE DOS IN REAL
MODE.",13,10,"$"
MSG_FOUND_HIMEM
DB "HIMEM.SYS IS INSTALLED.
DON'T LOAD IT PLEASE.",13,10,"$"
MSG_NEEDED_VGA
DB "VGA OR SVGA(VESA
COMPATIBLE) VIDEO ADAPTER IS NEEDED.",13,10,"$"
; HEXADECIMAL
TABLE FOR CONVERTING BCD TO TEXT
HEX_TAB DB "0123456789ABCDEF"
;------------------;
; SYSTEM VARIABLES
;
;------------------;
INT_MASK_M DB ?
INT_MASK_S DB ?
ESP32 DD ?
IDTR0 DF 0 ; DUMMY IDTR FOR SWITCHING TO
REAL MODE
IDTR1 DF 3FFH
EXT_MEMORY DD ?
TIMER_CNT DW 0
KEY_SCAN_CODE
DB 0
KBD_SEQ DB 0
;------------------;
; FLAGS AND TABLES
;
;------------------;
; FLAG TABLE FOR
EXCEPTIONS. 1 MEANS EXCEPTION HAS ERROR CODE, 0 - NO CODE.
EXC_ERR DB 0,0,0,0,0,0,0,0, 1,0,1,1,1,1,1,0,
0,1
; IRQ PASS TABLE
#1. 1 MEANS PASSING IRQ TO V86 IS ENABLED, 0 - DISABLED.
PASS_IRQ
LABEL BYTE
DB 1 ; IRQ0 (Timer)
DB 1 ; IRQ1 (Keyboard)
DB 1 ; IRQ2 (Cascade)
DB 1 ; IRQ3 (Com 2/4)
DB 1 ; IRQ4 (Com 1/3)
DB 1 ; IRQ5 (LPT 2)
DB 1 ; IRQ6 (FDD)
DB 1 ; IRQ7
(LPT 1)
DB 1 ; IRQ8 (CMOS)
DB 1 ; IRQ9 (Redirected IRQ2)
DB 1 ; IRQ10 (Free)
DB 1 ; IRQ11 (Free)
DB 1 ; IRQ12 (Free)
DB 1 ; IRQ13 (FPU)
DB 1 ; IRQ14 (HDD)
DB 1 ; IRQ15 (Free)
; IRQ PASS TABLE
#2. 0 MEANS NO PMODE IRQ HANDLER, 1 - PMODE HANDLER EXIST.
IRQ_ADDR
LABEL DWORD
XXX = OFFSET TIMER_HANDLER
DD XXX
XXX = OFFSET KEYBOARD_HANDLER
DD XXX
DD 14 DUP(0)
;--------------------;
; EXCEPTION
MESSAGES ;
;--------------------;
MSG_EXC DB "EXCEPTION: ",0
MSG_EXC_ERR
DB "ERROR CODE: ",0
MSG_CSEIP DB "CS=XXXXXXXX
EIP=XXXXXXXX",0
MSG_CR0 DB "CR0=XXXXXXXX",0
;-------------------------------;
; STACK VARS FOR
V86 INTERRUPTS ;
;-------------------------------;
NESTED_SP DD 0
NESTED_STACK LABEL
DWORD
DD NESTED_INTS*32 DUP(0)
INT_SP DW NESTED_INTS*1024
;------------------------------------;
; DATA FOR
LAUNCHING THE COMMAND.COM ;
;------------------------------------;
DTA_OFS DW ?
DTA_SEG DW ?
CMD_LINE LABEL
BYTE
CMD DB CMD_LEN
CMD_BEGIN = $
; DB "/C DIR|MORE"
CMD_LEN = $ - CMD_BEGIN
DB 0DH,0
FCB1 DB 37 DUP (0)
FCB2 DB 37 DUP (0)
R_EXEC S_EXEC <0, CMD,DATA, FCB1,DATA,
FCB2,DATA>
COMNAME DB 128 DUP (0) ;FULL NAME OF COMMAND.COM
COMSPEC DB "COMSPEC=" ;NAME OF SEARCHING VARIABLE
KEEP_SP DW ?
KEEP_SS DW ?
SIZE_DSEG =
($ - DATA_BEGIN)
DATA ENDS
;-----------------------------------;
; REAL/PROTECTED
MODE STACK SEGMENT ;
;-----------------------------------;
SSTACK SEGMENT PARA STACK
DB
SIZE_STACK DUP (?)
SSTACK ENDS
;----------------------------;
; STACK SEGMENT
FOR V86 INTS ;
;----------------------------;
STCK_INT_V86
SEGMENT PARA
DB
NESTED_INTS*1024 DUP (?)
STCK_INT_V86 ENDS
;------------------------;
; TASK V86 STACK
SEGMENT ;
;------------------------;
STCK_V86 SEGMENT
PARA
DB
SIZE_STACK DUP (?)
STCK_V86 ENDS
END START
gdt.inc (Îïèñàíèå GDT)
;-----------;
; GDT Table ;
;-----------;
GDT_BEGIN =
$
GDT LABEL WORD
GDT_0 S_DESC <0,0,0,0,0,0> ;
00
GDT_GDT S_DESC
<GDT_SIZE-1,,,ACS_DATA,0,> ; 08
GDT_CS16 S_DESC
<SIZE_CSEG16-1,,,ACS_CODE,0,> ; 10
GDT_DS S_DESC
<SIZE_DSEG-1,,,ACS_DATA+ACS_DPL_3,0,> ; 18
GDT_SS S_DESC
<SIZE_STACK-1,,,ACS_DATA,0,> ; 20
GDT_BIOS S_DESC
<SIZE_BIOS-1,LOW_BIOS,HIGH_BIOS,ACS_DATA+ACS_DPL_3,0,0> ; 28
GDT_TEXT S_DESC <SIZE_TEXT-1,LOW_TEXT,HIGH_TEXT,ACS_DATA+ACS_DPL_3,0,0> ; 30
GDT_GRAPH S_DESC
<SIZE_GRAPH-1,LOW_GRAPH,HIGH_GRAPH,ACS_DATA+ACS_DPL_3,0,0>;38
GDT_FLAT S_DESC
<0FFFFH,0,0,ACS_DATA,08FH,0> ; 4
GB SEGMENT ;)) ; 40
GDT_CS32 S_DESC <SIZE_CSEG32-1,,,ACS_CODE+ACS_READ,0,> ; 48
GDT_IDT S_DESC
<SIZE_IDT-1,,,ACS_IDT,0,> ; 50
GDT_TSS_MAIN S_DESC <SIZE_TSS-1,,,ACS_TSS,0,> ; 58
GDT_TSS_V86 S_DESC
<SIZE_TSS-1,,,ACS_TSS,0,> ; 60
GDT_SIZE =
($ - GDT_BEGIN)
CS16_SEL = (GDT_CS16 - GDT_0)
DS_SEL = (GDT_DS - GDT_0) + RPL_3
SS_SEL = (GDT_SS - GDT_0)
BIOS_SEL = (GDT_BIOS - GDT_0) + RPL_3
TEXT_SEL = (GDT_TEXT - GDT_0) + RPL_3
GRAPH_SEL = (GDT_GRAPH - GDT_0) + RPL_3
FLAT_SEL = (GDT_FLAT - GDT_0)
CS32_SEL = (GDT_CS32 - GDT_0)
IDT_SEL = (GDT_IDT - GDT_0)
TSS_MAIN_SEL = (GDT_TSS_MAIN - GDT_0)
TSS_V86_SEL = (GDT_TSS_V86 - GDT_0)
idt.inc (Îïèñàíèå IDT)
;-----------;
; IDT Table ;
;-----------;
IDTR R_IDTR
<SIZE_IDT,0,0>
IDT LABEL DWORD
IDT_BEGIN =
$
; EXCEPTIONS GO
HERE
IRPC N, 0123456789ABCDEF
IDT_0&N I_DESC <0, CS32_SEL, 0, ACS_TRAP,
0> ; 00...0F
ENDM
IRPC N, 0123456789ABCDEF
IDT_1&N I_DESC <0, CS32_SEL, 0, ACS_TRAP,
0> ; 10...1F
ENDM
; IRQs GO HERE
IRPC N, 0123456789ABCDEF
IDT_IRQ_0&N I_DESC <0, CS32_SEL, 0, ACS_INT,
0> ; 20...2F
ENDM
; INTs GO HERE
IDT_SERVICE I_DESC <0, CS32_SEL, 0,
ACS_TRAP+ACS_DPL_3, 0> ; 30
SIZE_IDT =
($ - IDT_BEGIN)
tss.inc (Îïèñàíèå TSS)
;---------------------------------------;
; TSSs of main and
few additional tasks ;
;---------------------------------------;
TSS_MAIN S_TSS
<>
TSS_V86 S_TSS
<>
; TASK LIST
TASK_LIST DW
TSS_MAIN_SEL, TSS_V86_SEL, 0
; THIS INDEX
VARIABLE IS USED TO CHOSE THE TASK TO SWITCH TO
TASK_INDEX DW
2
; THIS 6-BYTE PM
ADDRESS IS USED TO PERFORM FAR JUMP TO TSS
TASK_ADDR DF
0
setupgdt.inc
(Èíèöèàëèçàöèÿ GDT)
;-----------;
; Fills GDT ;
;-----------;
MOV
AX, DATA
MOV
DL, AH
XOR
DH, DH
SHL
AX, 4
SHR
DX, 4
MOV
SI, AX
MOV
DI, DX
; GDT GOES HERE
LEA
BX, GDT_GDT
MOV
AX, SI
MOV
DX, DI
ADD
AX, OFFSET GDT
ADC
DX, 0
@SET_GDT_ENTRY
; 16-BIT
REAL/PROTECTED MODE MAIN TASK CODE GOES HERE
LEA
BX, GDT_CS16
MOV
AX, CS
XOR
DH, DH
MOV
DL, AH
SHL
AX, 4
SHR
DX, 4
@SET_GDT_ENTRY
; COMMON DATA
SEGMENT GOES HERE
LEA
BX, GDT_DS
MOV
AX, SI
MOV
DX, DI
@SET_GDT_ENTRY
; STACK FOR 16/32
REAL/PROTECTED MODE MAIN TASK GOES HERE
LEA
BX, GDT_SS
MOV
AX, SS
XOR
DH, DH
MOV
DL, AH
SHL
AX, 4
SHR
DX, 4
@SET_GDT_ENTRY
; 32-BIT PROTECTED
MODE MAIN TASK CODE GOES HERE
LEA
BX, GDT_CS32
MOV
AX, CODE32
XOR
DH, DH
MOV
DL, AH
SHL
AX, 4
SHR
DX, 4
@SET_GDT_ENTRY
OR
[BX][S_DESC.ATTRIBS], 40H
; 32-BIT STUFF
; IDT GOES HERE
LEA
BX, GDT_IDT
MOV
AX, SI
MOV
DX, DI
ADD
AX, OFFSET IDT
ADC
DX, 0
@SET_GDT_ENTRY
MOV
IDTR.IDT_L, AX
MOV
IDTR.IDT_H, DX
; TSSs GO HERE
LEA
BX, GDT_TSS_MAIN
MOV
AX, SI
MOV
DX, DI
ADD
AX, OFFSET TSS_MAIN
ADC
DX, 0
@SET_GDT_ENTRY
LEA
BX, GDT_TSS_V86
MOV AX, SI
MOV
DX, DI
ADD
AX, OFFSET TSS_V86
ADC
DX, 0
@SET_GDT_ENTRY
setupidt.inc
(Èíèöèàëèçàöèÿ IDT)
;-----------;
; Fills IDT ;
;-----------;
; EXCEPTIONS GO
HERE
IRPC N, 0123456789ABCDEF ; 00...0F
LEA
EAX, EXC_0&N
MOV
IDT_0&N.OFFS_L, AX
SHR
EAX, 16
MOV
IDT_0&N.OFFS_H, AX
ENDM
IRPC N, 0123456789ABCDEF ; 10...1F
LEA
EAX, EXC_1&N
MOV
IDT_1&N.OFFS_L, AX
SHR
EAX, 16
MOV
IDT_1&N.OFFS_H, AX
ENDM
; IRQs GO HERE
IRPC N, 0123456789ABCDEF ; 20...2F
LEA
EAX, IRQ_0&N
MOV
IDT_IRQ_0&N.OFFS_L, AX
SHR
EAX, 16
MOV
IDT_IRQ_0&N.OFFS_H, AX
ENDM
; INTs GO HERE
LEA
EAX, SERVICE_INTERRUPT
; 30
MOV
IDT_SERVICE.OFFS_L, AX
SHR
EAX, 16
MOV
IDT_SERVICE.OFFS_H, AX
setuptss.inc
(Èíèöèàëèçàöèÿ TSS)
;---------------------------------------;
; TSSs of main and
few additional tasks ;
;---------------------------------------;
TSS_MAIN S_TSS
<>
TSS_V86 S_TSS
<>
; TASK LIST
TASK_LIST DW
TSS_MAIN_SEL, TSS_V86_SEL, 0
; THIS INDEX
VARIABLE IS USED TO CHOSE THE TASK TO SWITCH TO
TASK_INDEX DW
2
; THIS 6-BYTE PM
ADDRESS IS USED TO PERFORM FAR JUMP TO TSS
TASK_ADDR DF
0
detect.inc (Îïðåäåëåíèå
êîíôèãóðàöèè ñèñòåìû)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Detects Real
Mode and hardware ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.8086
DETECT PROC NEAR
;;;;;;;;;;;;;;;;;;;;;;;;
;; DETECTING CPU
TYPE ;;
;;;;;;;;;;;;;;;;;;;;;;;;
CALL
CPU_CHECK
CMP
AL, 3
JNC
DETECT_IS_386_PLUS ;
386+
LEA
DX, MSG_NEEDED_386
MOV
AH, 9
INT
21H
JMP
DETECT_FAILED
DETECT_IS_386_PLUS:
.386P
;;;;;;;;;;;;;;;;;;;;;;;;;
;; DETECTING REAL
MODE ;;
;;;;;;;;;;;;;;;;;;;;;;;;;
SMSW
AX ;
BUT THIS WORKS PERFECTLY :)
TEST
AL, 1 ;
IS PROTECTED MODE ACTIVE?
JZ
DETECT_IS_REAL_MODE ;
NO, IT ISN'T (REAL MODE)
LEA
DX, MSG_NEEDED_RM
MOV
AH, 9
INT
21H
JMP
DETECT_FAILED ;
YES, IT IS. EXITING...
DETECT_IS_REAL_MODE:
;;;;;;;;;;;;;;;;;;;;;;;;;
;; DETECTING
HIMEM.SYS ;;
;;;;;;;;;;;;;;;;;;;;;;;;;
MOV
AX, 4300H
INT
2FH
CMP
AL, 80H
JNE
DETECT_NO_HIMEM ;
HIMEM.SYS IS NOT INSTALLED
LEA
DX, MSG_FOUND_HIMEM
MOV
AH, 9
INT
21H
JMP
DETECT_FAILED ; YES, IT IS. EXITING...
DETECT_NO_HIMEM:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DETECTING VIDEO
SYSTEM ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MOV
AX,1A00H
INT
10H ; check if VGA
type display
CMP
AL,1AH
JNE DETECT_Not_VGA
CMP
BL,7 ; VGA with
Monochrome Display?
JE
DETECT_IS_VGA
CMP
BL,8 ; VGA with Color
Display?
JE
DETECT_IS_VGA
DETECT_NOT_VGA:
LEA
DX, MSG_NEEDED_VGA
MOV
AH, 9
INT
21H
JMP
DETECT_FAILED
DETECT_IS_VGA:
MOV
AX, 1003H
MOV
BL, 0
INT
10H ; DISABLE BLINKING
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COUNTING
EXTENDED MEMORY ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CALL
MEM_COUNT
MOV
DS:[EXT_MEMORY], EAX ; bytes
above 1MB+64KB
RET
DETECT_FAILED:
MOV AX, 4C00H
INT 21H
DETECT ENDP
.8086
CPU_CHECK PROC
NEAR
; 8086 CPU check
; Bits 12-15 are always set on the 8086
processor
;
CC_check_8086:
pushf ;save FLAGS
pop
bx ;store
FLAGS in BX
mov
ax, 0fffh ;clear
bits 12-15
and
ax, bx ; in FLAGS
push
ax ;store new
FLAGS calue on stack
popf ;replace current
FLAGS value
pushf ;set new flags
pop
ax ;store new
flags in AX
and
ax, 0f000h ;if bits
12-15 are set, then CPU
cmp
ax, 0f000h ; is an 8086/8088
mov
al, 0 ; save the
CPU type to AL
je
CC_end_cpuid
;
; Intel 286 CPU check
; Bits 12-15 are always clear on the Intel
processor.
;
check_80286:
.286
or
bx, 0f000h ;try to
set bits 12-15
push
bx
popf
pushf
pop
ax
and
ax, 0f000h ; if bits
12-15 are cleared,
; CPU=Intel 286
mov
al, 2 ; turn on
Intel 286 Cpu flag
jz
CC_end_cpuid ; if CPU
is intel 286, check
; for
Intel 287 math coprocessor
MOV
AL, 3 ; 386+
.8086
CC_END_CPUID:
RET
CPU_CHECK ENDP
.386P
MEM_COUNT PROC
NEAR
@ENABLE_A20
Xor
EAX, EAX
Mov
AX, CS
Shl
EAX, 4
LEA
EDX, MC_GDT
Add
EAX, EDX
Mov
DWord Ptr CS:MC_GDTR+2, EAX; Fill in GDTR with physical address
; of
Global Descriptor Table
@Push
<DS, ES>
CLI
LGDT
FWord Ptr CS:MC_GDTR ; Load
Global Descriptor Table
Mov
EAX, 1
Mov
CR0, EAX ; Set
Protected Mode
Mov
AX, 8
Mov
DS, AX
Mov
ES, AX
Mov
FS, AX
Mov
GS, AX ; All
segment registers are loaded
; with
4GB segment's selector
Xor
EAX, EAX
Mov
CR0, EAX ; Set Real
Mode
STI
Xor
ECX, ECX ; 0 bytes
Mov
DS, CX
Mov
ES, CX
Mov
ESI, 110000H ; 1MB +
64KB
Mov
EDI, ESI
MC_cycle:
Mov
EAX, DS:[ESI]
Not
EAX
Mov
ES:[EDI], EAX
Mov
EBX, DS:[ESI]
Cmp
EAX, EBX
JNE
MC_failed
Add
ESI, 4096;4
Mov
EDI, ESI
Add
ECX, 4096;4
Jmp
MC_cycle
MC_failed:
; And
CX, 0FC00H ; round to 1KB
Mov
EBX, ECX
; SHR
ECX, 2
; MOV
EDI, 110000H
; XOR
EAX, EAX
; MOV
ES, AX
; CLD
;MC_MEMCYC:
; MOV
ES:[EDI], EAX ; CLEAR
MEMORY
; ADD
EDI, 4
; DEC
ECX
; JNZ
MC_MEMCYC
@DISABLE_A20
MOV
EAX, EBX
@Pop
<ES, DS>
RET
MC_GDT DQ
0, 8F92000000FFFFh ;
"0" & "4GB" Descriptors
MC_GDTR DW
16, 0, 0
MEM_COUNT ENDP
exc.inc
;----------------------;
; Exception
handler(s) ;
;----------------------;
M =
0
IRPC N, 012345689ABCEF
EXC_0&N LABEL
DWORD
CLI
PUSH EBP
MOV EBP, ESP
PUSHAD
MOV EAX, M
M
= M+1
JMP EXC_HANDLER
ENDM
M =
010H
IRPC N, 0123456789ABCDEF
EXC_1&N LABEL
DWORD
CLI
PUSH EBP
MOV EBP, ESP
PUSHAD
MOV
EAX, M
M
= M+1
JMP EXC_HANDLER
ENDM
EXC_07 LABEL DWORD
CLTS
IRETD
EXC_0D PROC NEAR
CLI
; LET'S CHECK THE
"VM" FLAG AT THE "EFLAGS" REGISTER
TEST DWORD PTR SS:[ESP+3*4], 20000H ; IS IT A V86 TASK?
JZ EXC_0D_PM ; NO, IT ISN'T
;--------------------------------------------------------------------------;
; V86 MONITOR STARTS
HERE ;
;--------------------------------------------------------------------------;
; ESP CORRECTION
BECAUSE OF THE ERROR CODE
ADD ESP, 4 ; ESP = ^V86.EIP
; MAKING STACK
FRAME AND STORING REGISTERS ON THE STACK
PUSH EBP
MOV EBP, ESP ; EBP+4 = ^V86.EIP
@PUSH <DS, ES, EAX, EBX, ECX, EDX>
MOV AX, FLAT_SEL
MOV ES, AX
; LET'S CHECK THE
OPCODE AT THE ADDRESS WHERE INTERRUPT/EXCEPTION OCCURED
MOVZX EBX, WORD PTR SS:[EBP+2*4] ; EBX = V86.CS
CMP BX, CODE_V86_IRET ; EXIT FROM INT STUFF?
JNE EXC_0D_CONTINUE ; NO
; JMP RINT_EXIT ; YES
JMP IRQ_CONTINUE ; YES
EXC_0D_CONTINUE:
SHL EBX, 4 ; EBX = V86.CS*16
ADD EBX, SS:[EBP+4] ; EBX = CS*16+IP
MOV AH, ES:[EBX] ; AH = V86's OPCODE
MOV AL, 3 ; INT NUMBER = 3
CMP AH, 0CCH ; "INT 3"?
JE EXC_0D_PERFORM_V86_INT ; YES
MOV AL, 4 ; INT NUMBER = 4
CMP AH, 0CEH ; "INTO"?
JE EXC_0D_PERFORM_V86_INT ; YES
CMP AH, 0CDH ; "INT ?"?
JNE EXC_0D_DO_NOT_PERFORM_V86_INT ; NO
MOV AL, ES:[EBX+1] ; AL = INT NUMBER
INC WORD PTR SS:[EBP+4] ; CORRECT V86.IP
EXC_0D_PERFORM_V86_INT:
INC WORD PTR SS:[EBP+4] ; CORRECT V86.IP
CMP AL, 15H ; INT 15H?
JNE EXC_0D_NOT_15 ; NO
CMP BYTE PTR SS:[ESP+3*4+1], 87H ; FUNCTION 87H?
JNE EXC_0D_NOT_15
INCLUDE INT15F87.INC
@POP <EDX, ECX, EBX, EAX, ES, DS,
EBP>
IRETD
EXC_0D_NOT_15:
; PREPARING V86
STACK FOR RETURNING FROM THE INTERRUPT HANDLER
; LET'S MAKE SPACE
FOR IP, CS AND FLAGS
SUB WORD PTR SS:[EBP+4*4], 6 ; V86.SP -= 6
MOVZX EBX, WORD PTR SS:[EBP+5*4] ; EBX = V86.SS
SHL EBX, 4 ; EBX = V86.SS*16
ADD EBX, SS:[EBP+4*4] ; EBX = SS*16+SP
; LET'S PUT FLAGS
TO THE V86 STACK AND ALTER FLAGS FOR INTERRUPT HANDLER
MOV ECX, SS:[EBP+3*4] ; ECX = V86.EFLAGS
MOV ES:[EBX+4], CX ; FLAGS ARE PUT
AND CH, NOT 3 ; CLEAR "IF"
AND "TF"
MOV SS:[EBP+3*4], ECX ; ALTERED FLAGS
; LET'S PUT CS AND
IP TO THE V86's STACK (FOR IRET)
MOV CX, SS:[EBP+2*4] ; CS FOR IRET
MOV ES:[EBX+2], CX
MOV CX, SS:[EBP+4] ; IP FOR IRET
MOV ES:[EBX], CX
; LET'S PUT
INTERRUPT VECTOR ADDRESS
MOVZX EAX, AL ; AL = INT NUMBER
SHL EAX, 2
MOV EAX, ES:[EAX] ; EAX = RM INT VECTOR
MOV SS:[EBP+4], AX ; IP
SHR EAX, 16
MOV SS:[EBP+2*4], AX ; CS
; GO AHEAD! RUN
THE REAL MODE INTERRUPT HANDLER CODE!
@POP <EDX, ECX, EBX, EAX, ES, DS,
EBP>
IRETD
EXC_0D_DO_NOT_PERFORM_V86_INT:
@POP <EDX, ECX, EBX, EAX, ES, DS,
EBP>
SUB ESP, 4
MOV DWORD PTR SS:[ESP], 0
EXC_0D_PM:
PUSH EBP
MOV EBP, ESP
PUSHAD
MOV EAX, 0DH
JMP EXC_HANDLER
EXC_0D ENDP
; It's a common
part of all exception handlers
EXC_HANDLER PROC
NEAR
PUSH
DS
MOV
BX, DS_SEL
MOV
DS, BX
CALL
CLRSCR
LEA
ESI, MSG_EXC
MOV
EDI, 40*2
CALL
W_ASCIIZ ;
"EXCEPTION: "
ADD
EDI, 11*2
CALL
W_EAX ;
EXCEPTION NUMBER
SUB
EDI, 11*2
MOV
EBX, EBP
ADD
EBX, 4 ;
EBX = ^CS:EIP
MOVZX
EAX, BYTE PTR DS:[EXC_ERR+EAX]
OR
EAX, EAX
JZ
EXC_NO_ERR_CODE ;
THE EXCEPTION HAS NO ERROR CODE
ADD
EBX, 4 ; CORRECT EBX
LEA
ESI, MSG_EXC_ERR
ADD
EDI, 80*2
CALL
W_ASCIIZ ;
"ERROR CODE: "
MOV
EAX, SS:[EBP+4]
AND
EAX, 0FFFFH
ADD
EDI, 12*2
CALL
W_EAX
SUB
EDI, 12*2
SUB
EDI, 80*2
EXC_NO_ERR_CODE:
LEA
ESI, MSG_CSEIP
ADD
EDI, 2*80*2
CALL
W_ASCIIZ ;
"CS=XXXXXXXX EIP=XXXXXXXX"
ADD
EDI, 3*2
MOVZX
EAX, WORD PTR SS:[EBX+4]
CALL
W_EAX ;
CS
ADD
EDI, 13*2
MOV
EAX, SS:[EBX]
CALL
W_EAX ;
EIP
SUB
EDI, (3+13)*2
ADD
EDI, 80*2
LEA
ESI, MSG_CR0 ;
"CR0=XXXXXXXX"
CALL
W_ASCIIZ
ADD
EDI, 4*2
MOV
EAX, CR0
CALL
W_EAX ;
CR0
; jmp
$ ;
INFINITE LOOP
MOV AX, SS_SEL
MOV
SS, AX
MOV
ESP, DS:[ESP32]
@RETF
IRETD
EXC_HANDLER ENDP
macroses.inc
(Ñòðóêòóðû çàùèùåííîãî ðåæèìà)
;--------------------------------------------------------------------;
; Macroses that
define useful structures, constants and other things ;
;--------------------------------------------------------------------;
; Pushes several
registers to the stack
@PUSH MACRO
REGLIST
IRP
REG, <REGLIST>
PUSH REG
ENDM
ENDM
; Popes several
registers from the stack
@POP MACRO
REGLIST
IRP
REG, <REGLIST>
POP REG
ENDM
ENDM
; Sets up GDT
table entry
@SET_GDT_ENTRY MACRO
MOV [BX][S_DESC.BASE_L], AX
MOV [BX][S_DESC.BASE_M], DL
MOV [BX][S_DESC.BASE_H], DH
ENDM
; Segment
Descriptor structure
S_DESC STRUC
LIMIT DW 0
BASE_L DW 0
BASE_M DB
0
ACCESS DB 0
ATTRIBS DB
0
BASE_H DB 0
S_DESC ENDS
; Interrupt
Descriptor structure
I_DESC STRUC
OFFS_L DW 0
SEL DW 0
PARAM_CNT DB
0
ACCESS DB 0
OFFS_H DW 0
I_DESC ENDS
; IDTR register
structure
R_IDTR STRUC
LIMIT DW 0
IDT_L DW 0
IDT_H DW 0
R_IDTR ENDS
; Task State
Segment structure
S_TSS STRUC
LINK DW 0, 0
; 0
ESP0 DD 0
; 4
SS0 DW 0, 0
; 8
ESP1 DD 0
; 0C
SS1 DW 0,
0 ; 10
ESP2 DD 0
; 14
SS2 DW 0, 0
; 18
R_CR3 DD 0
; 1C
R_EIP DD 0
; 20
R_EFLAGS DD
0 ; 24
R_EAX
DD 0
; 28
R_ECX DD 0
; 2C
R_EDX DD 0
; 30
R_EBX DD 0
; 34
R_ESP DD 0
; 38
R_EBP DD 0
; 3C
R_ESI DD 0
; 40
R_EDI DD 0
; 44
R_ES DW 0, 0
; 48
R_CS DW 0, 0
; 4C
R_SS DW 0, 0
; 50
R_DS DW 0, 0
; 54
R_FS DW 0, 0
; 58
R_GS DW 0, 0
; 5C
R_LDTR DW 0, 0
; 60
TRACE DW 0
; 64
IO_MAP_ADDR DW
68H ; 66
IO_MAP DB
8192 DUP (0) ; 65536 PORTS AVAILABLE
S_TSS ENDS
; DIFFERENT
CONSTANTS AND FLAGS FOR PM
SIZE_TSS EQU
68H + 8192 ; 65536 PORTS
AVAILABLE
; Access byte's
flags
ACS_PRESENT EQU 10000000B
ACS_CSEG EQU 00011000B
ACS_DSEG EQU 00010000B
ACS_EXPDOWN EQU 00000100B
ACS_CONFORM EQU 00000100B
ACS_READ EQU 00000010B
ACS_WRITE EQU 00000010B
ACS_CODE =
ACS_PRESENT OR ACS_CSEG;
OR ACS_CONFORM
ACS_DATA = ACS_PRESENT OR ACS_DSEG OR
ACS_WRITE
ACS_STACK = ACS_PRESENT OR ACS_DSEG OR
ACS_WRITE
ACS_INT_GATE EQU 00001110B
ACS_TRAP_GATE EQU
00001111B
ACS_IDT EQU ACS_DATA
ACS_INT EQU ACS_PRESENT OR ACS_INT_GATE
ACS_TRAP EQU ACS_PRESENT OR ACS_TRAP_GATE
ACS_TSS EQU ACS_PRESENT OR 00001001B
ACS_DPL_0 EQU 00000000B
ACS_DPL_1 EQU 00100000B
ACS_DPL_2 EQU 01000000B
ACS_DPL_3 EQU 01100000B
RPL_0 EQU 0
RPL_1 EQU 1
RPL_2 EQU 2
RPL_3 EQU 3
; CONSTANTS FOR
BIOS DATA AREA
SEG_BIOS EQU 00040H
SIZE_BIOS EQU 00300H
LOW_BIOS EQU 00400H
HIGH_BIOS EQU 0
; CONSTANTS FOR
TEXT VIDEO MODES
SEG_TEXT EQU 0B800H
SIZE_TEXT EQU 02000H ; > 80*50*2
LOW_TEXT EQU 08000H
HIGH_TEXT EQU 0BH
; CONSTANTS FOR
GRAPHICS VIDEO MODES
SEG_GRAPH EQU 0A000H
SIZE_GRAPH EQU 10000H
LOW_GRAPH EQU 0
HIGH_GRAPH EQU 0AH
; DIFFERENT
CONSTANTS FOR PORT I/O
PORT_CMOS EQU 070H
PORT_6845 EQU 00063H
PORT_TEXT EQU 003D4H
PORT_STATUS EQU 064H
SHUT_DOWN EQU 0FEH
MODE_VIRTUAL EQU 00001H
PORT_A20 EQU 0D1H
A20_ON EQU 0DFH
A20_OFF EQU 0DDH
PORT_KBD_A EQU 060H
PORT_KBD_B EQU 061H
PORT_INT_MASK_M
EQU 021H
PORT_INT_MASK_S
EQU 0A1H
EOI EQU 020H
PORT_8259M EQU 020H
PORT_8259S EQU 0A0H
PORT_COM_REG EQU
043H
PORT_CHANNEL2 EQU 042H
; Enables A20 line
@ENABLE_A20 MACRO
MOV AL, PORT_A20
OUT PORT_STATUS, AL
MOV AL, A20_ON
OUT PORT_KBD_A, AL
ENDM
; Disables A20
line
@DISABLE_A20 MACRO
MOV AL, PORT_A20
OUT PORT_STATUS, AL
MOV AL, A20_OFF
OUT PORT_KBD_A, AL
ENDM
; Enables
non-maskable interrupts
@ENABLE_NMI MACRO
MOV AL, 0DH
OUT PORT_CMOS, AL
JMP $+2
ENDM
; Disables
non-maskable interrupts
@DISABLE_NMI MACRO
MOV AL, 8FH
OUT PORT_CMOS, AL
JMP $+2
ENDM
; This macro
reprograms PIC (master and slave) to other interrupt vectors
@SET_INT_CTRLR MACRO
INT_MASTER, INT_SLAVE
MOV
AL, 11H ; START
8259 INITIALIZATION
OUT
PORT_8259M, AL
OUT
PORT_8259S, AL
MOV
AL, INT_MASTER ; BASE
INTERRUPT VECTOR
OUT
PORT_8259M+1, AL
MOV
AL, INT_SLAVE
OUT
PORT_8259S+1, AL
MOV
AL, 1 SHL 2 ; BITMASK
FOR CASCADE ON IRQ 2
OUT
PORT_8259M+1, AL
MOV
AL, 2 ; CASCADE
ON IRQ 2
OUT
PORT_8259S+1, AL
MOV
AL, 1 ; FINISH
8259 INITIALIZATION
OUT
PORT_8259M+1, AL
OUT
PORT_8259S+1, AL
MOV
AL, 0FFH ; MASK ALL
INTERRUPTS
OUT
PORT_INT_MASK_M, AL
OUT
PORT_INT_MASK_S, AL
ENDM
@JUMP MACRO ; OVERLOADS CODE SELECTOR AFTER
CHANGING ITS DESCRIPTOR
DB
0EAH
DW
$+4
DW
CS16_SEL
ENDM
@JUMPR MACRO ; OVERLOADS CODE SEGMENT
DB
0EAH
DW
$+4
DW
CODE16
ENDM
@RETF MACRO ; FAR RETURN FROM 16-BIT TO 32-BIT
CODE & VICE VERSA
DB
66H
RETF
ENDM
S_EXEC STRUC
ENV_SEG DW ?
CMD_OFS DW ?
CMD_SEG DW ?
FCB1OFS DW ?
FCB1SEG DW ?
FCB2OFS DW ?
FCB2SEG DW ?
S_EXEC ENDS
service.inc (Ôîðìèðîâàíèå îáðàáîò÷èêà ïðåðûâàíèÿ)
;----------------------------------;
; SERVICE SOFTWARE
INTERRUPT (30H) ;
;----------------------------------;
SERVICE_INTERRUPT
PROC NEAR
PUSHAD
AND
EBX, 0FF00H ;
BH = FUNCTION CODE
SHR
EBX, 8
CMP
EBX, 3
JNC
SERV_INT_END ;
ONLY 3 FUNCTIONS AVAILABLE
SHL
EBX, 2 ;
ADDRESS OFFSET TABLE
CALL
DWORD PTR CS:[FUNC_TAB+EBX]
SERV_INT_END:
POPAD
IRETD
F_00 LABEL NEAR
JMP
CLRSCR ;
CLEAR SCREEN
F_01 LABEL NEAR
JMP
W_ASCIIZ ;
OUT ASCIIZ STRING
F_02 LABEL NEAR
JMP
W_EAX ; OUT 32-BIT EAX AS HEX
FUNC_TAB LABEL
DWORD
DD
F_00, F_01, F_02
SERVICE_INTERRUPT
ENDP
screenio.inc
(Ðàáîòà ñ âèäåîêàðòîé)
;---------------------------------;
; Subroutines for
screen text I/O ;
;---------------------------------;
; FUNCTION: CLEARS
THE SCREEN
; IN: NONE
; OUT: NONE, ALL
REGS ARE SAVED
CLRSCR PROC NEAR
PUSH
ES
PUSHAD
MOV
AX, TEXT_SEL
MOV
ES, AX
XOR
EDI, EDI
MOV
ECX, 80*25
MOV
AX, 700H;1B00H
REP
STOSW
POPAD
POP
ES
RET
CLRSCR ENDP
; FUNCTION: PRINTS
THE EAX VALUE TO THE SCREEN
; IN: EAX = 32-BIT VALUE, EDI = SCREEN OFFSET
; OUT: NONE, ALL
REGS ARE SAVED
W_EAX PROC NEAR
@PUSH
<DS,ES>
PUSHAD
MOV
DX, DS_SEL
MOV
DS, DX
MOV
DX, TEXT_SEL
MOV
ES, DX
MOV
ECX, 8
LEA
ESI, HEX_TAB
W_EAX_1:
ROL
EAX, 4
MOVZX
EBX, AL
AND
BL, 0FH
MOV
BL, DS:[ESI+EBX]
MOV
ES:[EDI], BL
ADD
EDI, 2
LOOP
W_EAX_1
POPAD
@POP
<ES,DS>
RET
W_EAX ENDP
; FUNCTION: PRINTS
ASCIIZ STRING TO THE SCREEN
; IN: DS:ESI -> STRING, EDI = SCREEN OFFSET
; OUT: NONE, ALL
REGS ARE SAVED
W_ASCIIZ PROC NEAR
PUSH
ES
PUSHAD
MOV
AX, TEXT_SEL
MOV
ES, AX
W_ASCIIZ_1:
LODSB
OR
AL, AL
JZ
W_ASCIIZ_2
STOSB
INC EDI
JMP
W_ASCIIZ_1
W_ASCIIZ_2:
POPAD
POP
ES
RET
W_ASCIIZ ENDP
keyboard.inc
(Îáðàáîò÷èê ïðåðûâàíèÿ îò êëàâèàòóðû)
;-------------------------------------;
; Keyboard
hardware interrupt handler ;
;-------------------------------------;
KEYBOARD_HANDLER
PROC NEAR
@PUSH
<DS, EAX>
MOV
AX, DS_SEL
MOV
DS, AX
IN
AL, PORT_KBD_A
MOV
AH, AL
AND
AL, 07FH
MOV
DS:[KEY_SCAN_CODE], AL
CMP
AH, 1DH ;
CTRL?
JNE
KEYBOARD_1
MOV
DS:[KBD_SEQ], 1
JMP
KEYBOARD_NEXT
KEYBOARD_1:
CMP
DS:[KBD_SEQ], 1
JNE
KEYBOARD_NEXT
CMP
AH, 1 ; ESC?
JE
KEYBOARD_ERROR ;
CTRL+ESC -> EXCEPTION #0
MOV
DS:[KBD_SEQ], 0
JMP
KEYBOARD_NEXT
KEYBOARD_ERROR:
MOV
EAX, 0
; DIV
EAX ; EMERGENCY "EXIT" ;)
KEYBOARD_NEXT:
@POP
<EAX, DS>
RET
KEYBOARD_HANDLER
ENDP
timer.inc (Îáðàáîò÷èê ïðåðûâàíèÿ
îò òàéìåðà)
;----------------------------------;
; Timer hardware
interrupt handler ;
;----------------------------------;
TIMER_HANDLER PROC
NEAR
@PUSH
<DS, ES>
PUSHAD
MOV
AX, DS_SEL
MOV
DS, AX
MOV
AX, BIOS_SEL
MOV
ES, AX
; INC
DWORD PTR ES:[06CH] ; UPDATE
BIOS TICK COUNTER
MOV
AX, DS:[TIMER_CNT] ;
INTERNAL TICK COUNTER
INC
AX
CMP
AX, 9 ;
IS TIME FOR "*" OR " "?
JNE
@@TIMER_END ;
NO, IT ISN'T
MOV AX, TEXT_SEL
MOV
ES, AX
MOV
AL, ES:[2*79]
MOV
BYTE PTR ES:[2*79], 0 ;
" " <-> "*"
CMP
AL, '*'
JE
@@TIMER_FLAG
MOV
BYTE PTR ES:[2*79], '*' ;
"*" <-> " "
@@TIMER_FLAG:
XOR
AX, AX
@@TIMER_END: ; UPDATE
INTERNAL TICK COUNTER
MOV
DS:[TIMER_CNT], AX
POPAD
@POP
<ES, DS>
RET
TIMER_HANDLER ENDP
set_rm1.inc (Âîçâðàò â RealMode – ñïîñîá 1)
;--------------------------------------------------------------------------;
; Sets Real Mode
using CR0, overloading segs and reprogramming PIC ;
; Ver 1:
Unfortunately, works quite buggy. I don't know why. :(( ;
; Ver 2: It seems
to be everything is OK after changing order of the ;
; @SET_INT_CTRLR 08H, 70H and ;
; LIDT FWORD PTR IDTR ;
; instructions ;
; Ver 3: unchanged
vesrsion 2, but it doesn't work again when the task ;
; switching is enabled ;
; Ver 4: added a
"CLTS" instructio. Every DPMI-based program, that I tried ;
; to run immediately after quitting from
this program, just hanged ;
; with nonzero "task switched"
flag. The solution is inside this ;
; simple instruction. Viola! it
works! ;
;--------------------------------------------------------------------------;
CLTS ; THE
SOLUTION!!! ;-)
@SET_INT_CTRLR 08H, 70H ; REINITIALISE MASTER &
SLAVE INT CONTROLLERS
MOV GDT_CS16.LIMIT, 0FFFFH ; CODE SEGMENT HAS 64KB LIMIT
MOV
GDT_DS.LIMIT, 0FFFFH ;
DATA SEGMENT HAS 64KB LIMIT
MOV
GDT_SS.LIMIT, 0FFFFH ;
STACK SEGMENT HAS 64KB LIMIT
; LGDT
FWORD PTR GDT_GDT ;
LOAD GDTR
@JUMP ; OVERLOAD
CODE SELECTOR
MOV
AX, DS_SEL
MOV
DS, AX ;
OVERLOAD DATA SELECTOR
MOV
ES, AX ;
OVERLOAD DATA SELECTOR
MOV
FS, AX ;
OVERLOAD DATA SELECTOR
MOV
GS, AX ;
OVERLOAD DATA SELECTOR
MOV
AX, SS_SEL
MOV
SS, AX ;
OVERLOAD STACK SELECTOR
MOV
EAX, CR0
AND
EAX, 01111111111111111111111111111110B
MOV
CR0, EAX ;
BACK TO THE REAL MODE
@JUMPR ; RESTORE RM
CODE SEGMENT
MOV
AX, SSTACK
MOV
SS, AX ;
RESTORE RM STACK SEGMENT
MOV
AX, DATA
MOV
DS, AX ;
RESTORE RM DATA SEGMENT
MOV
ES, AX
XOR
AX, AX
MOV
FS, AX
MOV
GS, AX
LIDT
FWORD PTR IDTR1 ;
LOAD REAL MODE INT TABLE
set_rm2.inc (Âîçâðàò â RealMode – ñïîñîá 2)
;--------------------------------;
; Sets Real Mode
using CPU reset ;
; Works perfectly.
:)) ;
;--------------------------------;
MOV
ESP32, ESP
MOV
AX, BIOS_SEL
MOV
ES, AX
MOV
WORD PTR ES:[067H], OFFSET SHUTDOWN_RET
MOV
WORD PTR ES:[069H], CODE16
MOV
AL, 5
OUT
PORT_CMOS+1, AL
; MOV
AL, SHUT_DOWN
; OUT
PORT_STATUS, AL
;START_RESET:
; HLT
; JMP
START_RESET
LIDT
[IDTR0]
INT
0
SHUTDOWN_RET LABEL FAR
MOV
AX, DATA
MOV
DS, AX
MOV
ES, AX
MOV
AX, SSTACK
MOV
SS, AX
MOV
ESP, ESP32
XOR
AX, AX
MOV
FS, AX
MOV
GS, AX
int15f87.inc (Ïåðåñûëêà äàííûõ âèðòóàëüíîé çàäà÷è)
@PUSH <ESI, EDI>
; jmp
err_1587
MOVZX ECX, CX
CMP ECX, 8000H
JA ERR_1587
MOVZX EBX, WORD PTR SS:[EBP+6*4] ; ES
SHL EBX, 4
MOVZX ESI, SI
ADD EBX, ESI ; EBX=ES*16+SI
MOV ESI, ES:[EBX+10H+2] ; 24-BIT SOURCE
AND ESI, 0FFFFFFH
MOVZX EAX, BYTE PTR ES:[EBX+10H+7]
SHL EAX, 24
ADD ESI, EAX
MOV EDI, ES:[EBX+18H+2] ; 24-BIT DESTINATION
AND EDI, 0FFFFFFH
MOVZX EAX, BYTE PTR ES:[EBX+18H+7]
SHL EAX, 24
ADD EDI, EAX
MOV BX, FLAT_SEL
MOV DS, BX
CLD
REP MOVSW
MOV BX, DS_SEL
MOV DS, BX
MOV BYTE PTR SS:[ESP+5*4+1], 0 ; AH=0 - NO ERROR
AND BYTE PTR SS:[EBP+3*4], NOT 1 ; CF=0 - NO ERROR
JMP EXIT_1587
ERR_1587:
MOV BYTE PTR SS:[ESP+5*4+1], 3 ; AH=3 - ERROR
OR BYTE PTR SS:[EBP+3*4], 1 ; CF=1 - ERROR
EXIT_1587:
@POP <EDI, ESI>
irqs.inc (Ïðåðûâàíèÿ
âèðòóàëüíîé ñðåäû)
;------;
; IRQs ;
;------;
M =
0
IRPC N, 0123456789ABCDEF ; 20...2F
IRQ_0&N LABEL
DWORD
PUSH EBP
MOV EBP, ESP
@PUSH <DS, ES, FS, GS, SS>
PUSHAD
MOV EAX, M
M
= M+1
JMP IRQ_HANDLER
ENDM
; It's a common
part of all IRQ handlers
IRQ_HANDLER PROC NEAR
XOR EDX, EDX ; IRQ HAS NO BEEN HANDLED YET
MOV BX, DS_SEL
MOV DS, BX
MOV EBX, DS:[IRQ_ADDR+EAX*4]
OR EBX, EBX
JZ IRQ_NO_PM_HANDLER ; NO PROTECTED MODE HANDLER
CALL DWORD PTR DS:[IRQ_ADDR+EAX*4]
OR EDX, 1 ; HANDLED IN PROTECTED MODE
IRQ_NO_PM_HANDLER:
MOVZX EBX, BYTE PTR DS:[PASS_IRQ+EAX]
OR EBX, EBX
JZ IRQ_NO_RM_HANDLER ; IRQ IS NOT PASSED TO REAL MODE HANDLER
; DETERMINING DATA
LENGTH IN STACK
TEST DWORD PTR SS:[EBP+3*4], 20000H ; WAS IT A V86 TASK?
JZ IRQ_PM_TEST0 ; NO, IT WASN'T
MOV ECX, 9 ; 9 EXTRA DWORDS ON STACK
JMP IRQ_LCONTINUE
IRQ_PM_TEST0:
TEST WORD PTR SS:[EBP+2*4], 3; WAS RPL
> 0 ?
JZ IRQ_PM_TEST1 ; NO, IT WASN'T
MOV ECX, 5 ; 5 EXTRA DWORDS ON STACK
JMP IRQ_LCONTINUE
IRQ_PM_TEST1:
MOV ECX, 3 ; 3 EXTRA DWORDS ON STACK
IRQ_LCONTINUE:
ADD ECX, 1+5+8 ; PUSHED EBP,SEGS,32-BIT REGS
LEA EDI, NESTED_STACK
ADD EDI, DS:[NESTED_SP]
ADD DS:[NESTED_SP], 32*4 ; ALTERING "STACK POINTER"
MOV
DS:[EDI], ECX ; STORING NUMBER OF DWORDS
ADD EDI, 4
MOV ESI, ESP
IRQ_CYCLE:
MOV EBX, SS:[ESI]
MOV DS:[EDI], EBX
ADD ESI, 4
ADD EDI, 4
LOOP IRQ_CYCLE
CMP EAX, 8
JNC IRQ_INT70
ADD EAX, 8
JMP IRQ_INT8
IRQ_INT70:
ADD EAX, 68H
IRQ_INT8:
MOV EDI, EAX ; EDI = INT NUMBER
; WORKING WITH V86
STACK
MOV AX, FLAT_SEL
MOV ES, AX
XOR EAX, EAX
@PUSH <EAX,EAX,EAX,EAX>
XOR EBX, EBX
MOV BX, STCK_INT_V86
PUSH EBX
SHL EBX, 4
MOVZX EAX, DS:[INT_SP]
SUB DS:[INT_SP], 1024
SUB EAX, 6
PUSH EAX
ADD
EBX, EAX
MOV WORD PTR ES:[EBX], OFFSET
V86_INT_X
MOV WORD PTR ES:[EBX+2], CODE_V86_IRET
PUSHFD
POP EAX
AND AH, NOT 42H ; CLEAR "NT" AND
"IF"
PUSH EAX
POPFD
MOV EAX, 23000H
MOV ES:[EBX+4], AX
PUSH EAX ; FLAGS
MOV EAX, EDI ; INT NUMBER
SHL EAX, 2
MOV EAX, ES:[EAX]
MOV EBX, EAX
SHR EAX, 16
PUSH EAX ; CS
AND EBX, 0FFFFH
PUSH EBX ; EIP
IRETD
IRQ_CONTINUE:
MOV AX, DS_SEL
MOV DS, AX
ADD DS:[INT_SP], 1024
SUB DS:[NESTED_SP], 32*4
LEA ESI, NESTED_STACK
ADD ESI, DS:[NESTED_SP]
MOV ECX, DS:[ESI]
ADD ESI, 4
MOV SS, DS:[ESI+8*4]
MOV ESP, DS:[ESI+3*4]
SUB ESP, 8*4
MOV EDI, ESP
IRQ_CYCLE2:
MOV EBX, DS:[ESI]
MOV SS:[EDI], EBX
ADD ESI, 4
ADD EDI, 4
LOOP IRQ_CYCLE2
OR EDX, 2 ; HANDLED IN REAL MODE
IRQ_NO_RM_HANDLER:
TEST EDX, 2
JNZ IRQ_EOI_SENT ; EOI HAS BEEN SENT BY RM IRQ
HANDLER
MOV AH, AL ; AH = IRQ NUMBER
MOV AL, EOI
OUT PORT_8259M, AL ; MASTER PIC
CMP AH, 8 ; IRQ0...IRQ7?
JC IRQ_EOI_SENT ; YES
OUT PORT_8259S, AL ; SLAVE PIC
IRQ_EOI_SENT:
POPAD
@POP <SS, GS, FS,
ES, DS, EBP>
IRETD
IRQ_HANDLER ENDP
lcommand.inc (Çàïóñê command.com)
;--------------------------------;
; Launches a
command interpreter ;
;--------------------------------;
LCOMMAND PROC NEAR
MOV
AX, DATA
MOV DS, AX
MOV AH, 51H
INT 21H
MOV ES, BX
MOV ES, ES:[02CH] ;ENVIRONMENT'S SEGMENT
XOR DI, DI
LEA
SI, COMSPEC
CLD
MOV DX, 32000 ;MAX SIZE OF ENVIRONMENT
LCOMMAND_FIND_COM:
PUSH SI
PUSH DI
MOV CX, 8
REPE CMPSB
JE LCOMMAND_FOUND_COM
POP DI
POP SI
INC DI
DEC DX
JNZ LCOMMAND_FIND_COM
JMP LCOMMAND_NOTFOUND_COM
LCOMMAND_FOUND_COM:
POP SI
POP SI
PUSH ES
POP DS
MOV SI, DI
MOV AX, DATA
MOV ES, AX
LEA DI, COMNAME
LCOMMAND_FILL_COM:
LODSB
STOSB
OR AL, AL
JZ LCOMMAND_FILL_END
JMP LCOMMAND_FILL_COM
LCOMMAND_FILL_END:
MOV AH, 02FH
INT 021H
MOV AX, DATA
MOV
DS, AX
MOV DS:DTA_OFS, BX
MOV DS:DTA_SEG, ES ;GET DTA
MOV DS:KEEP_SP, SP
MOV DS:KEEP_SS, SS
MOV AX, DS
MOV ES, AX
LEA DX, COMNAME
LEA BX, R_EXEC
MOV AX, 04B00H
INT 021H
MOV AX, DATA
MOV DS, AX
MOV ES, AX
CLI
MOV
SP, DS:KEEP_SP
MOV SS, DS:KEEP_SS
STI
MOV AH, 01AH
MOV DX, DS:DTA_OFS
MOV DS, DS:DTA_SEG
INT 021H ;SET DTA
LCOMMAND_NOTFOUND_COM:
MOV AX, DATA
MOV DS, AX
MOV ES, AX
RET
LCOMMAND ENDP