156 lines
3.8 KiB
NASM
156 lines
3.8 KiB
NASM
;----
|
|
; Example program switching to Protected and back to Real Mode
|
|
; Jerzy Tarasiuk 8-Jun-1995
|
|
;
|
|
code segment
|
|
assume cs:code
|
|
stk segment para stack 'stack'
|
|
dw 100h dup(?)
|
|
stk ends
|
|
assume cs:code,ss:stk,ds:Nothing,es:Nothing
|
|
.386P
|
|
|
|
;-
|
|
; GDT to be used in Protected Mode
|
|
;
|
|
mygdt dq 0 ; null descriptor
|
|
gdtcd dw -1,0,9A00h,0 ; 64kB code segment, base to be set
|
|
dw -1,0,9200h,008Fh ; 4GB R/W segment, base=0
|
|
dw -1,0,9200h,0 ; 64kB R/W segment, base=0
|
|
|
|
;---
|
|
; pm_mem - access memory (peek/poke a byte) in Protected Mode
|
|
;
|
|
; entry EBX=address, CX=0 for peek to CL or CX!=0 for poke CL
|
|
; changes EAX,EDX,GDTR,CL
|
|
;
|
|
; requires A20 to be enabled if to be used on a PC compatible
|
|
; (A20 is usually enabled if DOS is loaded into HMA)
|
|
;
|
|
pm_mem proc
|
|
pushf
|
|
push ds
|
|
mov ax,cs
|
|
movzx eax,ax
|
|
shl eax,4 ; eax=base for code segment
|
|
mov dword ptr gdtcd[2],eax
|
|
mov byte ptr gdtcd[5],9Ah ; set segment attribute
|
|
mov dx,offset mygdt
|
|
movzx edx,dx
|
|
add eax,edx ; eax=base for GDT
|
|
push eax
|
|
push 20h
|
|
movzx eax,sp
|
|
cli ; make sure no ISR will interfere now
|
|
lgdt fword ptr ss:[eax] ; LGDT is necessary before switch to PM
|
|
add sp,6
|
|
mov eax,cr0
|
|
or al,1
|
|
mov cr0,eax ; sets Protected Mode
|
|
db 0eah ; far jump to set CS & clear prefetch queue
|
|
dw pm_in
|
|
dw 8
|
|
|
|
pm_in: mov dx,10h
|
|
mov ds,dx ; load long segment descriptor from GDT into DS
|
|
jcxz pm_get
|
|
mov [ebx],cl
|
|
pm_get: mov cl,[ebx]
|
|
mov dl,18h
|
|
mov ds,dx ; load 64kB segment descriptor from GDT into DS
|
|
and al,not 1
|
|
mov cr0,eax ; sets Real Mode
|
|
db 0eah ; far jump to restore CS & clear prefetch queue
|
|
dd pm_out ; it MUST be jump - far return crashed!
|
|
pm_out: pop ds
|
|
popf
|
|
ret
|
|
pm_mem endp
|
|
|
|
;---
|
|
; vfycpu - make sure have proper CPU, in Real Mode, and A20 enabled
|
|
;
|
|
; changes AX,DX
|
|
; returns AL=error code if anything wrong
|
|
; error codes: 040h - not 32-bit CPU (PM,A20 not tested)
|
|
; 001h - already in PM (386+, A20 not tested)
|
|
; 0FFh - A20 disabled (32-bit CPU in RM)
|
|
;
|
|
vfycpu proc
|
|
pushf ; save flags
|
|
cli ; make sure no ISR will interfere now
|
|
;
|
|
pushf ; 1. make sure have at least 386
|
|
pop ax ; AX=flags
|
|
xor ah,40h ; toggle NT
|
|
push ax ; stack: modified_flags,original_flags
|
|
popf
|
|
pushf ; stack: modified_flags_from_cpu,original_flags
|
|
pop dx ; DX=flags passed via CPU
|
|
mov al,dh
|
|
xor al,ah
|
|
jnz vcfail ; improper CPU
|
|
;
|
|
smsw ax ; 2. make sure are in Real Mode
|
|
and al,1
|
|
jnz vcfail ; if already in PM (maybe VM86)
|
|
;
|
|
push ds ; 3. make sure A20 is enabled
|
|
push es
|
|
push bx
|
|
xor bx,bx
|
|
mov ds,bx
|
|
mov ax,-1
|
|
mov es,ax
|
|
xor [bx],ah ; change byte[000000h]
|
|
mov al,es:[bx+10h] ; get byte[100000h]
|
|
xor [bx],ah ; change byte[000000h]
|
|
xor al,es:[bx+10h] ; compare byte[100000h] with its previous value
|
|
; 0 if unchanged, -1 means [000000h]==[100000h]
|
|
pop bx
|
|
pop es
|
|
pop ds
|
|
;
|
|
vcfail: popf ; restore flags
|
|
test al,al ; test error code
|
|
ret
|
|
vfycpu endp
|
|
|
|
;---
|
|
; sample program
|
|
; - check if have proper CPU, exit with error message if bad
|
|
; - peek byte[0FFFFFFF0h] in PM
|
|
; - peek byte[0FFFEFFF0h] in PM
|
|
; - exit (status = byte obtatained)
|
|
;
|
|
badcpum db "Not 80386+ CPU!",0Dh,0Ah,'$'
|
|
inpmerm db "Already in Protected Mode!",0Dh,0Ah,'$'
|
|
bada20m db "Address line A20 disabled!",0Dh,0Ah,'$'
|
|
|
|
start: call vfycpu ; make sure having proper CPU and mode
|
|
add al,al
|
|
jz cpuok ; .. OK
|
|
lea dx,bada20m
|
|
jc error
|
|
lea dx,badcpum
|
|
js error
|
|
lea dx,inpmerm
|
|
error: push cs ; not proper - error message and exit
|
|
pop ds
|
|
mov ah,9
|
|
int 21h
|
|
mov ax,4cffh ; exit, status=-1
|
|
int 21h
|
|
|
|
cpuok: xor cx,cx ; peek a byte
|
|
mov ebx,-10h ; from 0FFFFFFF0h
|
|
call pm_mem
|
|
xor cx,cx ; peek a byte
|
|
mov ebx,-10010h ; from 0FFFEFFF0h
|
|
call pm_mem
|
|
exit: mov ah,4ch ; exit
|
|
mov al,cl ; status = the byte
|
|
int 21h
|
|
code ends
|
|
end start
|