dosemu2/test/ecm/dpmitest/dpmialoc.asm
geos_one 91736529d5
Some checks failed
Master / Scheduled (FULL) (push) Has been cancelled
Master / Triggered (push) Has been cancelled
Master / Triggered (ASAN) (push) Has been cancelled
Master / Triggered (FULL) (push) Has been cancelled
New upstream version 2.0pre9.2
2025-08-10 12:35:43 +02:00

596 lines
12 KiB
NASM

%if 0
Example of an application running in DPMI-allocated memory
Public Domain
%endif
%include "lmacros3.mac"
cpu 386
org 100h
addsection R86M_MEM_SECTION, start=100h
addsection DPMI_MEM_SECTION, vstart=0 follows=R86M_MEM_SECTION align=16
usesection R86M_MEM_SECTION
bits 16
r86m_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 bx, 80h >> 4
mov ah, 48h
int 21h ; allocate memory for child process
jc nomemory
; ax:0-> DOS memory allocated for child process
mov es, ax
xor di, di ; es:di->
xor si, si ; cs:si = ds:si -> our PSP
mov cx, 128 >> 1 ; PSP size
rep movsw ; copy process segment prefix into newly allocated block
dec ax
mov ds, ax ; ds = MCB of allocated block
inc ax ; ax = allocated block!
mov word [ 8 ], "DP"
mov word [ 8+2 ], "MI"
mov word [ 8+4 ], "PS"
mov word [ 8+6 ], "PC" ; Force MCB string to "DPMIPSPC"
; mov word [ 1 ], ax ; Set owner to itself
; (leave owner as us)
mov es, ax ; es = new PSP
mov dx, cs
mov ds, dx ; ds = old PSP
mov di, 18h
mov cx, 20
mov word [ es:32h ], cx
mov word [ es:34h ], di
mov word [ es:34h+2 ], ax ; fix the new PSP's PHT pointer
mov word [ es:0Ah ], childterminated
mov word [ es:0Ah+2 ], dx ; set termination address
mov word [ es:16h ], dx ; set parent PSP to current one
; The stack address set on the child's termination
; is that of the last Int21 call to a usual function
; (such as Int21.48 or .45) from the parent process.
; All registers will be lost though, because we don't
; build a fake stack frame.
push di
mov al, -1
rep stosb ; initialize new PHT with empty entries
pop di
mov cx, word [ 32h ] ; = number of current process handles
jcxz .phtdone ; (weird, but handle this correctly)
cmp cx, 20
jbe .normalpht
mov cx, 20
.normalpht:
lds si, [ 34h ] ; -> current process handle table
xor bx, bx
.phtloop:
mov dl, -1
cmp byte [si+bx], dl ; source PHT handle used?
je .phtnext ; no -->
mov ah, 45h
int 21h ; DUP
jc nohandle
xchg ax, bx
xchg dl, byte [si+bx] ; get DUPed handle and kill PHT entry
xchg ax, bx
mov byte [es:di+bx], dl ; write into PHT of new process
.phtnext:
inc bx ; next handle
loop .phtloop
.phtdone:
push cs
pop ds
mov bx, es
mov ah, 50h
int 21h ; set current PSP to new
; mov ah, 1Ah
; mov ds,
; mov dx, 80h
; int 21h ; set DTA
; Now executing in the child process's environment.
; Terminating will return to label childterminated.
mov ax, cs
mov word [rmcallstruc0.cs], ax
mov word [rmcallstruc0.ds], ax
mov word [rmcallstruc0.es], ax
mov word [rmcallstruc0.ss], ax
pushf
pop word [rmcallstruc0.flags] ; setup with RM values
mov ax, 1687h
int 2Fh
test ax, ax ; DPMI host installed?
jnz nohost
push es ; save DPMI entry address
push di
test si, si ; host requires client-specific DOS memory?
jz .nomemneeded ; no -->
mov bx, si
mov ah, 48h ; alloc DOS memory
int 21h
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
nohandle:
cmp cx, 20
je .no_handles_duplicated_yet
; In this case, there may be some already duplicated
; file handles. Switch to the child process and then
; terminate it, in order to close the handles.
mov word [ es:0Ah ], .half_initialised_child_terminated
; set Parent Return Address to ours
mov bx, es
mov ah, 50h
int 21h
mov ax, 4C00h
int 21h
.half_initialised_child_terminated:
cld
.no_handles_duplicated_yet:
push cs
pop ds
mov si, msg.nohandle
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 bx, cs
mov cx, cs
lar cx, cx
shr cx, 8
or ch, 40h ; make a 32-bit cs
mov ax, 9
int 31h
; now in 32-bit PM
bits 32
now32bit:
now32bit_ofs equ (now32bit-$$+100h)
mov word [ data.pspsel ], es
push ds
pop es
mov esi, msg.welcome
call printstring
mov [r86m_end + dpmi_to_r86m_code_sel - dpmi_start], cs
mov [r86m_end + dpmi_to_r86m_data_sel - dpmi_start], ds
xor eax, eax
mov cx, 2
int 31h ; allocate 2 selectors
jc @F
xchg eax, ebx
mov eax, 3
int 31h
jc @F
mov dword [r86m_end + dpmi_dpmi_code_sel - dpmi_start], ebx
push ebx
add ebx, eax
mov dword [r86m_end + dpmi_dpmi_data_sel - dpmi_start], ebx
mov ax, 8
or ecx, -1
mov edx, ecx
int 31h ; set limit to -1
pop ebx
jc @F
mov ax, 8
int 31h ; set limit to -1
jc @F
mov ax, 9
mov cx, 1100_1111_1_11_1_1011b
int 31h ; set to 32-bit readable code segment
jc @F
mov ax, 0501h
mov bx, (dpmi_end - dpmi_start) >> 16
mov cx, (dpmi_end - dpmi_start) & 0FFFFh
int 31h
jc @F
push bx
push cx
pop dword [data.dpmi_block_address]
push si
push di
pop dword [data.dpmi_block_handle]
mov ebx, dword [r86m_end + dpmi_dpmi_data_sel - dpmi_start]
mov edx, dword [data.dpmi_block_address]
mov ecx, dword [data.dpmi_block_address + 2]
mov ax, 7
int 31h
jc @F
push ecx
mov es, ebx
xor edi, edi
mov esi, r86m_end
mov ecx, dwords(dpmi_end - dpmi_start)
rep movsd
pop ecx
mov ebx, dword [r86m_end + dpmi_dpmi_code_sel - dpmi_start]
mov ax, 7
int 31h
jc @F
mov esi, msg.info2.1
call printstring
mov eax, dword [data.dpmi_block_address]
call disp_eax_hex
mov esi, msg.info2.2
call printstring
mov eax, ebx
call disp_ax_hex
mov esi, msg.info2.3
call printstring
mov eax, ebx
call disp_ax_hex
mov esi, msg.info2.4
call printstring
mov eax, ebx
call disp_ax_hex
mov esi, msg.info2.5
call printstring
int3
push ebx
push dpmi_start
retf
@@:
push ss
pop ds
mov esi, msg.error
call printstring
or eax, -1
pmend:
push ss
pop ds
push eax
mov ebx, dword [r86m_end + dpmi_dpmi_code_sel - dpmi_start]
mov ax, 1
int 31h
mov ebx, dword [r86m_end + dpmi_dpmi_data_sel - dpmi_start]
mov ax, 1
int 31h
mov edi, dword [data.dpmi_block_handle]
mov esi, dword [data.dpmi_block_handle + 2]
cmp edi, -1
je @F
mov ax, 0502h
int 31h
@@:
pop eax
mov ah, 4Ch ; normal client exit
int 21h
disp_eax_hex:
rol eax, 16
call disp_ax_hex
rol eax, 16
disp_ax_hex:
xchg al, ah
call disp_al_hex
xchg al, ah
disp_al_hex:
rol al, 4
call disp_al_nybble_hex
rol al, 4
disp_al_nybble_hex:
push eax
and al, 0Fh
add al, '0'
cmp al, '9'
jbe @F
add al, -'9' -1 +'A'
@@:
call disp_al
pop eax
retn
disp_al:
push edx
push eax
mov dl, al
mov ah, 2
int 21h
pop eax
pop edx
retn
bits 16
callrm:
; int3 ; int 03h or int3 traps (in real or V86 mode) don't cause any problems.
int strict byte 03h
xor ax, ax
push ax
push ax
call -1:-1
.callback equ $-4
pop ax
pop ax
; int3
int strict byte 03h
iret
; 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
test al, al
jnz .next
retn
; The (DPMIed) child process has terminated.
childterminated:
childterminated_ofs equ (childterminated-$$+100h)
cld
push cs
pop ds
mov ah, 4Dh
int 21h
mov si, msg.backsuccess
test al, al
jz .success
mov si, msg.backerror
.success:
call printstring
mov ax, 4C00h
int 21h ; terminate DOS process
align 4
data:
.dpmi_block_address: dd 0
.dpmi_block_handle: dd -1
.pspsel: dw 0
align 4
; This one is used to call down to our RM part
; from the 32-bit PM code. All values are filled
; in either here or in our RM initialization.
rmcallstruc0:
.edi: dd 0
.esi: dd 0
.ebp: dd 0
dd 0
.ebx: dd 0
.edx: dd 0
.ecx: dd 0
.eax: dd 0
.flags: dw 0
.es: dw 0
.ds: dw 0
.fs: dw 0
.gs: dw 0
.ip: dw callrm
.cs: dw 0
.sp: dw rmcallsp
.ss: dw 0
align 4
; This one is utilized by the DPMI host and
; our RM callback when called from RM. All
; values are filled in by the DPMI host.
rmcallstruc1:
.edi: dd 0
.esi: dd 0
.ebp: dd 0
dd 0
.ebx: dd 0
.edx: dd 0
.ecx: dd 0
.eax: dd 0
.flags: dw 0
.es: dw 0
.ds: dw 0
.fs: dw 0
.gs: dw 0
.ip: dw 0
.cs: dw 0
.sp: dw 0
.ss: dw 0
msg:
.backsuccess: asciz "Child process terminated okay, back in real mode.",13,10
.backerror: asciz "Child process terminated with error, back in real mode.",13,10
.error: asciz "Error during allocation setup.",13,10
.info2.1: asciz "DPMI allocation at "
.info2.2: asciz "h.",13,10,"DPMI allocation entrypoint at "
.info2.3: db "h:00000000h.",13,10
asciz "Real mode procedure called at "
.info2.4: db "h:",_8digitshex(dpmi_start.callingrm - dpmi_start),"h.",13,10
asciz "DPMI allocation exit at "
.info2.5: asciz "h:",_8digitshex(dpmi_start.return - dpmi_start),"h.",13,10
.nohost: asciz "No DPMI host installed.",13,10
.nohandle: asciz "No free DOS file handle for child process creation.",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
db "32-bit code segment breakpoint at ",_4digitshex(now32bit_ofs),"h.",13,10
db "Return from child process at ",_4digitshex(childterminated_ofs),"h.",13,10
asciz 13,10
.welcome: asciz "Welcome in 32-bit protected mode.",13,10
align 16
times 256 db 26h
align 2
rmcallsp:
align 16
r86m_end:
usesection DPMI_MEM_SECTION
bits 32
dpmi_start:
nop
mov ds, [cs:dpmi_dpmi_data_sel]
mov esi, dpmi_msg.hello
call dpmi_printstring
mov ax, 0303h
push cs
pop ds
mov esi, dpmi_callback ; ds:esi-> called procedure
push ss
pop es
mov edi, rmcallstruc1 ; es:edi-> (inreentrant) real mode call structure
int 31h ; allocate RM callback
push ss
pop ds
jc .nocallback
mov dword [callrm.callback], edx
mov word [callrm.callback+2], cx
mov ax, 0302h
xor ebx, ebx
xor ecx, ecx
mov edi, rmcallstruc0
.callingrm:
int 31h ; call RM procedure with interrupt stack
nop
jc .callrmfailed
mov ecx, dword [callrm.callback+2]
mov edx, dword [callrm.callback]
mov ax, 0304h
int 31h ; free RM callback
mov ds, [cs:dpmi_dpmi_data_sel]
mov esi, dpmi_msg.bye
call dpmi_printstring
.return:
nop
xor eax, eax
.ret_al:
jmp far [cs:dpmi_return_address]
.callrmfailed:
mov esi, dpmi_msg.callrmfailed
jmp short @F
.nocallback:
mov esi, dpmi_msg.nocallback
@@:
push cs
pop ds
call dpmi_printstring
push ss
pop ds
movzx ecx, word [callrm.callback+2]
movzx edx, word [callrm.callback]
mov eax, edx
and eax, ecx
inc ax
jnz @F
mov ax, 0304h
int 31h ; free RM callback
@@:
or eax, -1
jmp .ret_al
; This is a RM callback. Called from RM, executed in PM.
;
; INP: es:edi-> RM call structure
; ds:esi-> RM stack
; ss:esp-> DPMI host internal stack
; CHG: all (?) except es:edi
; read/write RM call structure to communicate with RM code
dpmi_callback:
push dword [esi]
pop dword [es:edi+2Ah] ; set RM cs:ip
add word [es:edi+2Eh], byte 4 ; pop 4 byte from the stack
int strict byte 03h
nop
int3
nop
iret
; Print a string with simple instructions.
dpmi_printstring.next:
mov dl, al
mov ah, 2
int 21h
dpmi_printstring:
lodsb
test al, al
jnz .next
retn
dpmi_msg:
.hello: asciz "Hello from DPMI memory section!",13,10
.nocallback: asciz "Could not allocate real mode callback.",13,10
.callrmfailed: asciz "Calling real mode procedure failed.",13,10
.bye: asciz "Calling real mode procedure which called callback successful.",13,10
align 4
dpmi_return_address: dd pmend
dpmi_to_r86m_code_sel: dd 0
dpmi_to_r86m_data_sel: dd 0
dpmi_dpmi_code_sel: dd 0
dpmi_dpmi_data_sel: dd 0
align 16
dpmi_end: