Files
oldlinux-files/study/sabre/os/files/ProtectedMode/SIMPL_PM.asm
2024-02-19 00:25:23 -05:00

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