236 lines
4.6 KiB
NASM
236 lines
4.6 KiB
NASM
|
|
%if 0
|
|
|
|
Example of using DPMI raw-mode switching
|
|
Public Domain
|
|
|
|
%endif
|
|
|
|
;%include "CMMACROS.MAC"
|
|
%define _4digitshex(h) ((((h)/1000h)% 10h)+'0' +(('A'-'9'-1)*((((h)/1000h)% 10h)/0Ah))), \
|
|
((((h)/100h)% 10h)+'0' +(('A'-'9'-1)*((((h)/100h)% 10h)/0Ah))), \
|
|
((((h)/10h)% 10h)+'0' +(('A'-'9'-1)*((((h)/10h)% 10h)/0Ah))), \
|
|
(((h)% 10h)+'0' +(('A'-'9'-1)*(((h)% 10h)/0Ah)))
|
|
; ASCIZ string
|
|
;
|
|
; %1+ = Optional string
|
|
%imacro asciz 0-1+.nolist
|
|
%if %0 >= 1
|
|
db %1
|
|
%endif
|
|
db 0
|
|
%endmacro
|
|
|
|
|
|
%assign _AUXBUFFSIZE 8192
|
|
|
|
cpu 386
|
|
org 100h
|
|
bits 16
|
|
start:
|
|
pop ax ; get word saved on stack for COM files
|
|
mov bx, sp
|
|
shr bx, 4
|
|
jnz .smallstack
|
|
mov bx, 1000h ; it was a full 64 KiB stack
|
|
.smallstack:
|
|
mov ah, 4Ah ; free unused memory
|
|
int 21h
|
|
xor ax, ax
|
|
xchg ax, word [2Ch]
|
|
mov es, ax
|
|
mov ah, 49h
|
|
int 21h ; free environment if any
|
|
|
|
mov word [pspdbg], cs
|
|
|
|
mov ax, 1687h
|
|
int 2Fh
|
|
or ax, ax ; DPMI host installed?
|
|
jnz nohost
|
|
push es ; save DPMI entry address
|
|
push di
|
|
or si, si ; host requires client-specific DOS memory?
|
|
jz .nomemneeded ; no -->
|
|
mov bx, si
|
|
mov ah, 48h
|
|
int 21h ; allocate memory
|
|
jc nomemory
|
|
mov es, ax
|
|
.nomemneeded:
|
|
mov si, msg.debuginfo
|
|
call printstring
|
|
int3
|
|
mov bp, sp
|
|
mov ax, 0001h ; start a 32-bit client
|
|
call far [bp] ; initial switch to protected-mode
|
|
jnc initsuccessful
|
|
initfailed:
|
|
mov si, msg.initfailed
|
|
jmp short rmerror
|
|
nohost:
|
|
mov si, msg.nohost
|
|
jmp short rmerror
|
|
nomemory:
|
|
mov si, msg.nomemory
|
|
rmerror:
|
|
call printstring
|
|
mov ax, 4CFFh
|
|
int 21h
|
|
|
|
initsuccessful:
|
|
initsuccessful_ofs equ (initsuccessful-$$+100h)
|
|
; now in protected mode
|
|
mov word [ data.pspsel ], es
|
|
push ds
|
|
pop es
|
|
|
|
mov si, msg.welcome
|
|
call printstring
|
|
|
|
mov word [code_sel], cs
|
|
mov word [dssel], ds
|
|
|
|
xor edi, edi
|
|
mov ax, 0305h ; get raw mode-switch save state addresses
|
|
int 31h
|
|
jc .cannotswitch
|
|
cmp ax, _AUXBUFFSIZE ; fits into auxbuff ?
|
|
ja .cannotswitch ; no -->
|
|
test ax, ax
|
|
jz .nobuffer
|
|
mov word [dpmi_rmsav+0], cx
|
|
mov word [dpmi_rmsav+2], bx
|
|
mov dword [dpmi_pmsav], edi
|
|
mov word [dpmi_pmsav+4], si
|
|
jmp .gotbuffer
|
|
|
|
.nobuffer:
|
|
mov word [dpmi_rmsav+0], ..@retf
|
|
push word [pspdbg]
|
|
pop word [dpmi_rmsav+2]
|
|
mov dword [dpmi_pmsav+0], ..@retf
|
|
mov word [dpmi_pmsav+4], cs
|
|
|
|
.gotbuffer:
|
|
xor edi, edi ; clear edih
|
|
mov ax, 0306h ; get raw mode-switch addresses
|
|
int 31h
|
|
jc .cannotswitch
|
|
mov word [dpmi_rm2pm+0], cx
|
|
mov word [dpmi_rm2pm+2], bx
|
|
mov dword [dpmi_pm2rm], edi
|
|
mov word [dpmi_pm2rm+4], si
|
|
|
|
mov al, 0
|
|
call sr_state_pm
|
|
call switchmode_pm2rm
|
|
|
|
mov si, msg.rm
|
|
call printstring
|
|
|
|
call switchmode_rm2pm
|
|
mov al, 1
|
|
call sr_state_pm
|
|
|
|
mov si, msg.pmagain
|
|
call printstring
|
|
|
|
.cannotswitch:
|
|
mov ax, 4C00h
|
|
int 21h ; normal client exit (terminates DOS process too)
|
|
|
|
..@retf:
|
|
retf
|
|
|
|
|
|
switchmode_pm2rm:
|
|
;--- raw switch:
|
|
;--- si:e/di: new cs:e/ip
|
|
;--- dx:e/bx: new ss:e/sp
|
|
;--- ax: new ds
|
|
;--- cx: new es
|
|
xor ebx, ebx ; clear ebxh
|
|
mov bx, sp
|
|
xor edi, edi ; clear edih
|
|
mov di, .back_after_switch
|
|
|
|
mov ax, [pspdbg] ; switch pm -> rm
|
|
mov si, ax
|
|
mov dx, ax
|
|
mov cx, ax
|
|
jmp far dword [dpmi_pm2rm]
|
|
|
|
.back_after_switch:
|
|
retn
|
|
|
|
|
|
switchmode_rm2pm:
|
|
xor ebx, ebx ; clear ebxh
|
|
mov bx, sp
|
|
xor edi, edi ; clear edih
|
|
mov di, .back_after_switch
|
|
|
|
mov ax, [dssel] ; switch rm -> pm
|
|
mov si, [code_sel]
|
|
mov dx, ax
|
|
mov cx, ax
|
|
jmp far [dpmi_rm2pm]
|
|
|
|
.back_after_switch:
|
|
retn
|
|
|
|
|
|
sr_state_rm:
|
|
mov edi, auxbuff
|
|
push ds
|
|
pop es
|
|
call far [dpmi_rmsav]
|
|
retn
|
|
|
|
|
|
sr_state_pm:
|
|
mov edi, auxbuff
|
|
push ds
|
|
pop es
|
|
call far dword [dpmi_pmsav]
|
|
retn
|
|
|
|
|
|
; Print a string with simple instructions. Don't use
|
|
; pointers or instructions depending on the default operation
|
|
; size, this is called in both 16- and 32-bit modes.
|
|
printstring.next:
|
|
mov dl, al
|
|
mov ah, 2
|
|
int 21h
|
|
printstring:
|
|
lodsb
|
|
or al, al
|
|
jnz .next
|
|
retn
|
|
|
|
align 4
|
|
data:
|
|
.pspsel: dw 0
|
|
dssel: dw 0
|
|
code_sel: dw 0
|
|
pspdbg: dw 0
|
|
dpmi_rm2pm: dd 0
|
|
dpmi_rmsav: dd 0
|
|
dpmi_pm2rm: times 3 dw 0
|
|
dpmi_pmsav: times 3 dw 0
|
|
|
|
align 16
|
|
auxbuff: times _AUXBUFFSIZE db 0
|
|
|
|
msg:
|
|
.nohost: asciz "No DPMI host installed.",13,10
|
|
.nomemory: asciz "Not enough DOS memory for child process creation or client initialization.",13,10
|
|
.initfailed: asciz "DPMI initialization failed.",13,10
|
|
.debuginfo: db "Protected mode breakpoint at ",_4digitshex(initsuccessful_ofs),"h.",13,10
|
|
asciz 13,10
|
|
.welcome: asciz "Welcome in protected mode.",13,10
|
|
.rm: asciz "Mode-switched to real mode.",13,10
|
|
.pmagain: asciz "In protected mode again.",13,10
|