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