-
Notifications
You must be signed in to change notification settings - Fork 157
Description
The following test program causes FreeDOS and current Enhanced DR-DOS to differ from MS-DOS and lDOS. As usual the test requires lmacros to build with NASM.
What this does:
- Squirrel away the original Parent Return Address and Parent fields of our PSP.
- Set us up as self-parented and point the Parent Return Address into our code section.
- Find NUL device header.
- Insert a new character device what lives in our code section.
- Read from the device.
- Device causes an error (device return code 8103h "unknown command") on the first attempt to read from it (device function 04h).
- Interrupt 24h handler says "Abort" (return code 02h).
- Expected: Process is aborted, so that our hooked Parent Return Address code runs.
- Not expected: Int 21h DOS call returns an error return with CY and ax = error code.
- Even less expected: Int 21h DOS call returns success.
- In the unexpected cases, explicitly terminate.
- In the PRA handler, restore the parent and PRA and undo the insertion of our character device, then terminate the application for good.
; Public Domain
%include "lmacros3.mac"
cpu 386
org 256
start:
mov eax, dword [0Ah] ; PRA
mov dword [origpra], eax
mov ax, word [16h] ; parent
mov word [origparent], ax
mov word [16h], ds
push ds
push word i22
pop dword [0Ah]
mov dx, i24
mov ax, 2524h
int 21h
mov ah, 52h
int 21h
cmp dword [es:bx + 22h + 10], "NUL "
jne error
push dword [es:bx + 22h]
pop dword [deviceheader.link]
mov word [list], bx
mov word [list + 2], es
push cs
push word deviceheader
pop dword [es:bx + 22h]
mov dx, i23
mov ax, 2523h
int 21h
mov ax, 3D00h
mov dx, name
int 21h
jc error
xchg bx, ax
mov dx, buffer
mov cx, 1
mov ah, 3Fh
not byte [isabortflag]
int 21h
jnc .success
.fail:
not byte [isabortflag]
push cs
pop es
mov di, msg.fail.code
call hexword
mov ah, 09h
mov dx, msg.fail
int 21h
mov ax, 4C00h
int 21h
.success:
not byte [isabortflag]
mov ah, 09h
mov dx, msg.success
int 21h
mov ax, 4C00h
int 21h
error:
mov ah, 09h
mov dx, msg.error
int 21h
mov ax, 4CFFh
int 21h
mismatch:
je .ret
mov ah, 09h
int 21h
.ret:
retn
i22:
push cs
pop ds
mov eax, dword [origpra]
mov dword [0Ah], eax
mov ax, word [origparent]
mov word [16h], ax
rol byte [isabortflag], 1
jnc .notabort
push cs
pop es
mov di, msg.abort.code
mov ah, 4Dh
int 21h
call hexword
mov dx, msg.abort
mov ah, 09h
int 21h
.notabort:
les bx, [list]
push dword [deviceheader.link]
pop dword [es:bx + 22h]
mov ax, 4C26h
int 21h
i24:
mov al, 02h ; abort
iret
i23:
stc
retf
hexword:
xchg al, ah
call hexbyte
xchg al, ah
hexbyte:
rol al, 4
call hexnybble
rol al, 4
hexnybble:
push ax
and al, 15
add al, '0'
cmp al, '9'
jbe .got
add al, -'9'-1+'A'
.got:
stosb
pop ax
retn
isabortflag: db 0
msg:
.error: ascic "Error!",13,10
.abort: db "Process aborted from i24, term code="
.abort.code: ascic "----h.",13,10
.fail: db "DOS call returned failure, error code="
.fail.code: ascic "----h.",13,10
.success: ascic "DOS call returned success. How?!",13,10
name:
asciz "TEST$$"
align 2, nop
buffer:
.size equ 64
times .size db 0
align 4, nop
list: dd 0
origpra: dd 0
origparent: dw 0
deviceheader:
.link: dd -1
.attr: dw 8000h
.strat: dw deviceentry
.int: dw retf_instruction
.name: fill 8, 32, db "TEST$$"
deviceentry:
push ax
push bx
push cx
push dx
push ds
push si
push es
push di
xor ax, ax
mov al, [es:bx + 2]
add ax, ax
mov si, ax
mov dx, deviceerror
cmp si, devicetable.end - devicetable
jae .dispatch
mov dx, [cs:devicetable + si]
.dispatch:
call dx
pop di
pop es
pop si
pop ds
pop dx
pop cx
pop bx
pop ax
retf_instruction:
retf
align 2
devicetable:
dw deviceinit
dw devicemediacheck
dw devicegetbpb
dw devicereadioctl
dw deviceread
dw devicereadnd
dw deviceinputstatus
dw deviceinputflush
dw devicewrite
dw devicewritev
dw deviceoutputstatus
dw deviceoutputflush
dw devicewriteioctl
dw deviceopen
dw deviceclose
dw deviceremovable
.end:
data:
.: db "Hello world!",13,10
db "123"
.end:
.size equ .end - .
deviceinit:
devicemediacheck:
devicegetbpb:
devicereadioctl:
deviceinputstatus:
deviceinputflush:
devicewrite:
devicewritev:
deviceoutputstatus:
deviceoutputflush:
devicewriteioctl:
deviceopen:
deviceclose:
deviceremovable:
deviceerror:
mov word [es:bx + 3], 8103h
retn
deviceread:
push cs
pop ds
rol byte [flag], 1
jc .read
not byte [flag]
jmp deviceerror
.read:
push es
mov cx, [es:bx + 12h]
les di, [es:bx + 0Eh]
mov si, word [pointer]
mov ax, data.end
sub ax, si
cmp cx, ax
jb @F
mov cx, ax
@@:
mov ax, cx
rep movsb
mov word [pointer], si
pop es
mov word [es:bx + 12h], ax
deviceok:
mov word [es:bx + 3], 0100h
retn
align 2, nop
pointer: dw data
flag: db 0
devicereadnd:
mov si, word [cs:pointer]
cmp si, data.end
jae .busy
cs lodsb
mov byte [es:bx + 0Dh], al
jmp deviceok
.busy:
mov word [es:bx + 3], 0300h
retn
Results:
MS-DOS v7, MS-DOS v5, lDOS 2025 August:
C:\>testabrt
Process aborted from i24, term code=0200h.
FreeDOS:
C:\>testabrt
DOS call returned failure, error code=000Ch.
Enhanced DR-DOS:
C:\>testabrt
DOS call returned failure, error code=0053h.
The FreeDOS code is in
Lines 723 to 731 in 032523a
; | |
; Abort processing. | |
; | |
CritErrAbort: | |
mov ax,[_cu_psp] | |
mov es,ax | |
cmp ax,[es:PSP_PARENT] | |
mov al,FAIL | |
jz CritErrExit |
The EDR-DOS code is very similar: https://hg.pushbx.org/ecm/edrdos/file/6c174e5361fb/drdos/pcmif.nas#l806
di24_abort: ; Abort this Process
mov ax,[current_psp] ; check not root application because
mov es,ax ; it must not be terminated so force
cmp ax,[es:PSP_PARENT] ; Is this the root Process
mov al,ERR_FAIL ; convert the error to FAIL
je di24_40 ; if not we terminate
It's essentially unchanged (modulo the RASM-86 to JWasm to NASM port) from the OpenDOS v7.01 code in https://hg.pushbx.org/ecm/edrdos/file/d4aed5f1b3e6/ibmdos/pcmif.a86#l778
Additional oddity: EDR-DOS returns error code 53h which means "fail on INT 24h". FreeDOS instead returns the error code 0Ch meaning "access code invalid".