Ziessel
Ziessel

Reputation: 57

INT 21h is not working with AH = 09h

I'm trying to program a driver to provide services in 55h. I'm making some tries to be sure everything works but I've found that when I call INT 21h with AH = 09h to print a string, it doesn't print anything, even with the right offset in DX, and I don't have any idea how this can be. In other sections of the code, it works fine. Here's my code:

codigo SEGMENT
ASSUME CS :codigo
ORG 256

inicio:
    MOV AL, DS:[83H] ;Parameters: when call with '/I' installs driver
    CMP AL, 49H
    JE inst
    CMP AL, 44H ;Parameters: when call with '/D', uninstalls
    JE desinstalar_55h
    JE rsi

    PRUEBA DB "THIS IS A TEST",0AH,'$'

rsi PROC FAR
    STI
    CMP AH, 00
    JE firm ;used to check if driver is install
    MOV CX, 0
    CMP AH, 11H
    JE codificar
volver:
    IRET
desinst:
    JE desinstalar_55h
inst: 
    CALL instalador
firm:
    CALL firma
rsi ENDP


firma PROC NEAR
    MOV AX, 0F0F0H
    RET
firma ENDP

desinstalar_55h PROC
    PUSH AX
    PUSH BX
    PUSH CX
    PUSH DS
    PUSH ES
    CALL check_driver
    CMP AX, 1
    JE no_instalado
    MOV CX, 0
    MOV DS, CX
    MOV ES, DS:[55H*4+2]
    MOV BX, ES:[2CH]
    MOV AH, 49H
    INT 21H
    MOV ES, BX
    INT 21H
    CLI
    MOV DS:[55H*4], CX
    MOV DS:[55H*4+2], CX
    STI
no_instalado:
    POP ES
    POP DS
    POP CX
    POP BX
    POP AX
    RET
desinstalar_55h ENDP


instalador PROC
    CALL check_driver
    CMP AX, 1
    JNE ya_instalado
    MOV DX, OFFSET PRUEBA
    MOV AH, 09H
    INT 21H ;here it works fine
    MOV AX, 0
    MOV ES, AX
    MOV AX, OFFSET rsi
    MOV BX, CS
    CLI
    MOV ES:[55h*4], AX
    MOV ES:[55h*4+2], BX
    STI
    MOV DX, OFFSET instalador
ya_instalado:
    INT 27H
instalador ENDP

codificar PROC
    CLD
    MOV DX, OFFSET PRUEBA
    MOV AH, 09H
    INT 21H ;here it doens't print anything
    RET
codificar ENDP

check_driver PROC
    MOV AX, 0
    MOV ES, AX
    MOV AX, OFFSET rsi
    CMP WORD PTR ES:[55H*4], 0
    JNE detectar_mi_driver
    CMP WORD PTR ES:[55H*4 + 2], 0
    JE no_driver
detectar_mi_driver:
    MOV AH, 0
    INT 55H
    CMP AX, 0F0F0H
    JE fin_check
no_driver: 
    MOV AX, 1
fin_check: RET
ENDP check_driver

codigo ENDS
END inicio

For example, inside 'instalador' rutine, which install the driver, I make a call to INT 21h and it works fine, printing the string. But when I call the interruption 55h with AH = 11h from another .EXE program, it should execute rsi process and jump to 'codificar' rutine, which calls INT 21h, but in this case, it doens't print anything, although it has the same offset in DX. Anyone knows why this can be? Thanks in advance for your help.

EDIT: I've tried to debugged it with TD and works fine, prints the string. However, when I call the interruption 55h with AH = 11h from another program, it doesn't print anything or just got stuck and never returns.

Upvotes: 2

Views: 1289

Answers (1)

Sep Roland
Sep Roland

Reputation: 39676

Several problems exist in this program.

inicio:
 MOV AL, DS:[83H] ;Parameters: when call with '/I' installs driver
 CMP AL, 49H
 JE inst
 CMP AL, 44H ;Parameters: when call with '/D', uninstalls
 JE desinstalar_55h
 JE rsi

 PRUEBA DB "THIS IS A TEST",0AH,'$'

In the previous code snippet the JE rsi is useless and should be replaced by a program termination. You can use RET because the program is a .COM

rsi PROC FAR
 STI
 CMP AH, 00
 JE firm ;used to check if driver is install
 MOV CX, 0
 CMP AH, 11H
 JNE volver      <------------ codificar is a routine that ends with
 CALL codificar  <------------ a mere RET so call it (don't jump to it!)
volver:          <------------ and fall through in the IRET.
 IRET
;;;;desinst:              \
;;;; JE desinstalar_55h   |  Move this code outside the proc!!!
;;;;inst:                 |  Here it has no sense.
;;;; CALL instalador      /
firm:
 CALL firma
 IRET         <-- Add this because the RETF provided by ENDP is not enough!
rsi ENDP

The rsi procedure has the most problems. You have declared it to be a FAR PROC but in fact it is an interrupt handler and thus all of its exits should use the IRET instruction.

instalador PROC
 CALL check_driver
 CMP AX, 1
 JNE ya_instalado

At the label ya_instalado you have a terminate and stay resident call BUT the check made it clear that you are already installed! Solve this via

 int 27h
ya_instalado:
 int 20h

The last but most visible problem sits in the printing routine. When called from the executing .COM the DS register is setup by DOS. When called from within the interrupt handler 55h you have to setup DS manually. Just copy it from CS. Also you don't need the CLD instruction. And since this is after all an interrupt handler you are supposed to preserve registers.

codificar PROC
 ;;;;CLD
 PUSH AX
 PUSH DX
 PUSH DS
 PUSH CS
 POP DS
 MOV DX, OFFSET PRUEBA
 MOV AH, 09H
 INT 21H
 POP DS
 POP DX
 POP AX
 RET
codificar ENDP

Upvotes: 2

Related Questions