Ïðèìåð ¹5 – «Ïðèìåð ðåàëèçàöèè ìîíèòîðà ðåæèìà V86»

 

          Ýòîò ïðèìåð äåìîíñòðèðóåò ðàáîòó ïðîöåññîðà â ðåæèìå 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