; Flat real mode demonstration program
.386
code segment use16
assume cs:code
org 100h
example proc ; Example code
call FLAT_inst ; Enable 4Gb address space
mov ax,3 ; Colour text mode
int 10h
xor ax,ax ; Base ES <- 000[0000]0h
mov es,ax
mov ah,1fh ; Colour = White on blue
mov si,offset message
mov edi,000b8000h ; EDI <- top left screen address
mov cx,80 ; Write one line
l1: lodsb ; Get a char
stos word ptr es:[edi] ; Store char + attrib
loop l1
call FLAT_dest ; <- Very Important!!!
ret
message db ' Message written using direct screen writing'
db ' & 32-bit offsets in REAL-mode!! '
example endp
FLAT_inst proc ; Installs FLAT_tsr
.386p ; SMSW is a priviledged instruction
smsw ax ; Check for real mode
.386
test al,1
jnz short V86
pushf ; Save flags & DS register
push ds
cli
xor eax,eax ; Get IRQ5 vector & Set FLAT_tsr
mov ds,ax
mov ebx,ds:[34h]
mov cs:old_IRQ5,ebx
mov word ptr ds:[34h],offset FLAT_tsr
mov ax,cs
mov ds:[36h],ax
shl eax,4 ; Build Global Descriptor Table
add dword ptr cs:GDTR[2],eax
pop ds ; Restore DS register & flags
popf
ret
V86: mov ah,09h ; Write message
mov dx,offset V86_msg
push cs
pop ds
int 21h
mov ax,4C01h ; Terminate with error code 1
int 21h
V86_msg db 'Cannot run in a virtual environment!',10,'$'
FLAT_inst endp
FLAT_dest proc ; Destalls FLAT_tsr
push ds ; Save DS register
xor ax,ax ; Restore old IRQ5 vector
mov ds,ax
mov eax,cs:old_IRQ5
mov ds:[34h],eax
pop ds ; Restore DS register
ret
FLAT_dest endp
align 8
GDT dd 0,0 ; 1st entry needs to be 'null'
FLAT_desc dw 0ffffh ; Limit (bit 0..15)
db ?,?,? ; Base (bit 0..23)
db 92h ; Access rights
db 0cfh ; Page granularity + Limit(16..19)
db ? ; Base (bit 24..31)
FLAT_sel equ FLAT_desc - GDT
GDTR dw $ - GDT ; Limit (16 bytes)
dd offset GDT ; Offset within current segment...
dw 0
old_IRQ5 dd 0
last_Exc_13 dd 0
IRQ5_flag db 0
FLAT_tsr proc
test cs:IRQ5_flag,1 ; Exception within IRQ5 handler?
jnz short Exc_13
push ax ; Ask PIC if IRQ5 In_Service
mov al,0Bh
out 20h,al
jmp $+2
in al,20h
test al,20h
pop ax
jz short Exc_13
IRQ5: mov cs:IRQ5_flag,1 ; Call old IRQ5 handler
pushf
call dword ptr cs:old_IRQ5
mov cs:IRQ5_flag,0
iret
Exc_13: push eax ; Save accumulator
mov eax,ss:esp[4] ; Get address of SOE
cmp eax,cs:last_Exc_13 ; Same as last time?
je short SOE
mov cs:last_Exc_13,eax
.386p
lgdt qword ptr cs:GDTR ; Load GDT Register
push gs fs es ds bx ; Save registers
mov eax,CR0
or al,1 ; Enter Protected mode
mov CR0,eax
mov bx,FLAT_sel ; Load 4Gb limits
mov ds,bx
mov es,bx
mov fs,bx
mov gs,bx
and al,not 1 ; Back to Real mode
mov CR0,eax
.386
pop bx ds es fs gs ; Restore registers
pop eax ; Restore accumulator
iret ; Done
SOE: call FLAT_dest ; Remove FLAT_tsr
mov ah,0fh ; Clear screen
int 10h
mov ah,00h
int 10h
mov ah,09h ; Write message
mov dx,offset SOE_msg
push cs
pop ds
int 21h
mov ax,4C0Dh ; Terminate with error code 13
int 21h
SOE_msg db 'Segment Overrun Exception!',10,'$'
FLAT_tsr endp
code ends
end example