Hi all,
If you've ever tried using hdpmi32 with a djgpp program, you may have
noticed some strange behavior. The program first fails to run with
"Load error: no DPMI", but on the second try, it suddenly works. Then
a third invocation fails again, the fourth runs fine, etc.
When you rename 'hdpmi32.exe' to 'cwsdpmi.exe', your program seems to
run consistently. But this is only because there is a second (real)
cwsdpmi in your PATH somewhere. What really happens, is that your
program alternates between running under hdpmi and cwsdpmi.
I finally figured out why this happens, and it's very simple: hdpmi uses
the exit status to indicate if it was loaded via xms, vcpi, or int15.
And the djgpp stub considers any non-zero exit status to be a failure,
so it keeps searching PATH until cwsdpmi is found, which always returns
zero.
For a possible solution, I would suggest to ignore the return status
from the host, and just check int 2f/1687 after every exec. As an added bonus, this saves 13 bytes of stub space.
On 2022-11-23 20:47, J.W. Jagersma wrote:
Hi all,
If you've ever tried using hdpmi32 with a djgpp program, you may have
noticed some strange behavior. The program first fails to run with
"Load error: no DPMI", but on the second try, it suddenly works. Then
a third invocation fails again, the fourth runs fine, etc.
When you rename 'hdpmi32.exe' to 'cwsdpmi.exe', your program seems to
run consistently. But this is only because there is a second (real)
cwsdpmi in your PATH somewhere. What really happens, is that your
program alternates between running under hdpmi and cwsdpmi.
I finally figured out why this happens, and it's very simple: hdpmi uses
the exit status to indicate if it was loaded via xms, vcpi, or int15.
And the djgpp stub considers any non-zero exit status to be a failure,
so it keeps searching PATH until cwsdpmi is found, which always returns
zero.
For a possible solution, I would suggest to ignore the return status
from the host, and just check int 2f/1687 after every exec. As an added
bonus, this saves 13 bytes of stub space.
Amended patch follows - it no longer skips the last iteration (exec
with no path).
It's a bit larger, but still saves 6 bytes in total.
--- a/src/stub/stub.asm
+++ b/src/stub/stub.asm
@@ -199,38 +199,49 @@ not_path:
;-----------------------------------------------------------------------------
; Get DPMI information before doing anything 386-specific
- push es
push di
- xor cx, cx ; flag for load attempt set cx = 0
- jz @f2 ; We always jump, shorter than jmp
+ ; Set up loadname in case of no DPMI.
+ ; First try current dir.
+ xor ah, ah ; Copy until this character (=0)
+ call store_env_string ; copy stub image to "loadname"
+ mov si, bx ; remove name so we can add DPMI name
+ mov di, [path_off] ; Pointer to path contents (next try)
@b1:
+ xor cx, cx ; flag to signal end of loop
+@b2:
+ call check_dpmi ; int 2f, ax=1687
+ jz @f3
+ call do_exec ; copy our name to string and try load + jcxz @f1 ; cx=0 while we have more paths to try + call check_dpmi ; last chance...
+ jz @f3
mov al, 110
mov dx, msg_no_dpmi
jmpl error
-@b2:
- or cx, cx
- jnz @b1 ; we already tried load once before
- inc cx
- call load_dpmi
- jc @b1
+@f1:
+ ; Set up loadname for next attempt.
+ mov ah, ';' ; Copy until this character
+ call store_env_string ; to "loadname"
+ or al, al ; Check terminating character
+ jne @f2 ; If ';', continue
+ dec di ; else point at null for next pass.
@f2:
- mov ax, 0x1687 ; get DPMI entry point
- int 0x2f
- or ax, ax
- jnz @b2 ; if 0 then it's there
- and bl, 1 ; 32 bit capable?
- jz @b2
+ inc cx
+ cmp si, loadname ; anything there?
+ je @b2 ; final try (no path)
+ mov al, [si-1]
+ call test_delim ; is final character a path delimiter
+ je @b1
+ movb [si], '\\' ; no, add separator between path & name + inc si
+ jmp @b1
@f3:
- mov [modesw], di ; store the DPMI entry point
- mov [modesw+2], es
- mov [modesw_mem], si
pop di
- pop es
;-----------------------------------------------------------------------------
; Now, find the name of the program file we are supposed to load.
-; xor ah, ah ; termination character (set above!)
+; xor ah, ah ; termination char (set by check_dpmi)
call store_env_string ; copy it to loadname, set bx
mov [stubinfo_env_size], di
@@ -700,36 +711,29 @@ pm_dos:
ret
;-----------------------------------------------------------------------------
-; load DPMI server if not present
-; First check directory from which stub is loaded, then path, then default -; On entry di points to image name
+; Check for presence of a DPMI host, and save the mode switch address.
+; Zero flag is clear on success. Clobbers ax/bx/dx.
-path_off:
- .dw 0 ; If stays zero, no path
-
-load_dpmi:
- xor ah, ah ; Copy until this character (=0)
- call store_env_string ; copy stub image to "loadname"
- mov si, bx ; remove name so we can add DPMI name
- mov di, [path_off] ; Pointer to path contents (next try)
- jmp @f2
-loadloop:
- mov ah, ';' ; Copy until this character
- call store_env_string ; to "loadname"
- or al,al ; Check terminating character
- jne @f1 ; If ';', continue
- dec di ; else point at null for next pass. -@f1:
- cmp si, loadname ; anything there?
- je do_exec ; final try (no path) let it return
- mov al, [si-1]
- call test_delim ; is final character a path delimiter
- je @f2
- movb [si], '\\' ; no, add separator between path & name - inc si
-@f2:
- call do_exec ; copy our name to string and try load - jc loadloop
+check_dpmi:
+ push es
+ push cx
+ push di
+ push si
+ mov ax, 0x1687 ; get DPMI entry point
+ int 0x2f
+ mov dx, bx
+ or dl, 1 ; bx bit 0: 32-bit capable
+ xor bx, dx
+ or ax, bx ; DPMI present if ax = 0
+ jnz @f1
+ mov [modesw], di ; store the DPMI entry point
+ mov [modesw+2], es
+ mov [modesw_mem], si
+@f1:
+ pop si
+ pop di
+ pop cx
+ pop es
ret
;-----------------------------------------------------------------------------
@@ -766,13 +770,6 @@ do_exec:
int 0x21
pop di
pop es
- jc @f1 ;carry set if exec failed
-
- mov ah, 0x4d ;get return code
- int 0x21
- sub ax, 0x300 ;ah=3 TSR, al=code (success)
- neg ax ;CY, if not originally 0x300
-@f1:
jmp restore_umb ;called func. return for us.
;-----------------------------------------------------------------------------
@@ -796,10 +793,9 @@ include_umb:
@f1:
ret
-; Restore upper memory status. All registers and flags preserved.
+; Restore upper memory status. All registers preserved.
restore_umb:
- pushf
cmpb [dos_major], 5 ; Won't work before dos 5
jb @f1
push ax
@@ -815,7 +811,6 @@ restore_umb:
pop bx
pop ax
@f1:
- popf
ret
;-----------------------------------------------------------------------------
@@ -840,6 +835,8 @@ msg_no_selectors:
.db "no DPMI selectors$"
msg_no_dpmi_memory:
.db "no DPMI memory$"
+path_off:
+ .dw 0 ; Points to PATH, stays zero if none.
;-----------------------------------------------------------------------------
; Unstored Data, available during and after mode switch
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 251 |
Nodes: | 16 (0 / 16) |
Uptime: | 30:09:13 |
Calls: | 5,571 |
Calls today: | 1 |
Files: | 11,685 |
Messages: | 5,128,450 |