Mail Archives: djgpp/1997/11/01/00:53:52
Greetings,
I am trying to understand the details of interrupt handling in
DJGPP. In this regard, I thought of writing a small program that would
install both, protected and real mode interrupt handlers for the different
kinds of interrupts (hardware and software) and trace the manner in which
control is transferred from one to the other and also the order in which
they are invoked. My protected mode handler writes a 'p' to an array
whenever it is called and my real mode handler writes 'r' to the same
array. The array is initialised with 'x'. I expect that the characters in
the array would describe the order in which things happen. Of course, I
did try to write 16 bit code for the real mode handler and copy it to
conventional memory but it wouldn't work (I'm new to assembly, but I'm
trying and hope to complete the 16 bit code soon) so I installed a real
mode callback instead which would be slower but would, I hope tell the
same story. I also plan to leave the handlers in different ways like iret,
chain and far calls so that each method of leaving the handler would teach
me the path of interrupt handling calls.
When I do this for the software interrupt (0x1c) I get a result
that to my **limited** understanding, is strange. It is always the real
mode interrupt that is called. My buffer is strewn with 'r's. This is the
same no matter which of the three DPMI hosts I use: cwsdpmi, cwsdpr0 or
pmode/dj. But when I run the same program in Windows 3.11, I get an
alternating string of 'p' and 'r' like: prprpr...., *even* when I do not
chain out of the protected mode handler. Obviously I am doing something
terribly WRONG! The DPMI specs say that int 0x1c is special in that, it is
always handled by the protected mode handler *even* when a real mode
handler is installed. Have I misunderstood something? Very likely! It
could also be that my inexperience with GAS has finally taken its toll.
However I did go through my code many times before I posted this. I am
appending my main c (test.c) program below and than the gas module
(my_isr.s) after that. My command line is simple:
gcc -Wall test.c my_isr.s -otest.exe
Would a kind Guru please help me understand this
-------------------test.c------------------------------------------
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <dpmi.h>
extern int init_handlers(void);
extern void reset_handlers(void);
unsigned long buff_size = 0x10000;
char *buffer;
int main(void)
{
unsigned long i;
int test;
char curr_char;
FILE *outfile;
buffer = (char *) malloc(buff_size);
if (!buffer)
{
printf("Unable to allocate buffer, Returning!\n");
return(1);
}
for(i = 0; i < buff_size; ++i)
buffer[i] = 'x';
outfile = fopen("history.dat", "w");
if(_go32_dpmi_lock_data(&buff_size, 4) == -1)
{
printf("Unable to lock data (buff_size)! Returning\n");
return(1);
}
if(_go32_dpmi_lock_data(buffer, buff_size) == -1)
{
printf("Unable to lock data (buffer)!, Returning\n");
return(1);
}
init_handlers();
getch();
for(i = 0; i < 200 * buff_size; ++i)
test = 2 * i - 4 * i;
for(i = 0; i < buff_size; ++i)
cprintf("%c\r", buffer[i]);
for(i = 0; i < buff_size; ++i)
{
curr_char = buffer[i];
if (curr_char != 'x')
fprintf(outfile, "Displaying buffer %lu .......%c\n", i, curr_char);
}
reset_handlers();
fclose(outfile);
return(0);
}
----------------------------my_isr.s-----------------------------
.file "my_isr.s"
.text
.globl _init_handlers
.globl _reset_handlers
begin_code_region:
pm_handler:
pushfl
.byte 0x2e
movw ___djgpp_ds_alias, %ds
movl index, %eax
cmpl %eax, _buff_size
jbe %cs:exit_pm_handler
incl index
addl _buffer, %eax
movb $'p, (%eax)
exit_pm_handler:
popfl
sti
iret
rm_handler:
# set up real mode return address from contents of real mode stack
movl (%esi), %eax
movl %eax, %es:0x2a(%edi)
movw 4(%esi), %ax
movw %ax, %es:0x20(%edi)
addw $6, %es:0x2e(%edi)
# increment index if within buffer bounds
pushw %ds
.byte 0x2e
movl ___djgpp_ds_alias, %ds
movl index, %eax
cmpl %eax, _buff_size
jbe %cs:exit_rm_handler
incl index
addl _buffer, %eax
movb $'r, (%eax)
exit_rm_handler:
popw %ds
sti
iret
end_code_region:
_init_handlers:
pushl %ebp
movl %esp, %ebp
pushfl
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
# lock code region
movl $begin_code_region, %ecx
movl $end_code_region, %edi
subl %ecx, %edi
addl ___djgpp_base_address, %ecx
shldl $0x10, %ecx, %ebx
shldl $0x10, %edi, %esi
movw $0x0600, %ax
int $0x31
movl $-1, %eax
jc cleanup
movl $1, %eax
# lock data region
movl $begin_data_region, %ecx
movl $end_data_region, %edi
subl %ecx, %edi
addl ___djgpp_base_address, %ecx
shldl $0x10, %ecx, %ebx
shldl $0x10, %edi, %esi
movw $0x0600, %ax
int $0x31
movl $-1, %eax
jc cleanup
movl $1, %eax
# save protected mode interrupt vector
movw $0x0204, %ax
movb $0x1c, %bl
int $0x31
movw %cx, sel_orig_pm_handler
movl %edx, off_orig_pm_handler
# this function always succeeds
# point protected mode handler to our own
movw $0x0205, %ax
pushw %cs
popw %cx
movl $pm_handler, %edx
movb $0x1c, %bl
int $0x31
movl $-1, %eax
jc cleanup
movl $1, %eax
# allocate real mode callback
movw $0x0303, %ax
pushw %ds
popw %es
movl $dpmi_regs, %edi
pushw %ds
pushw %cs
popw %ds
movl $rm_handler, %esi
int $0x31
popw %ds
movl $-1, %eax
jc cleanup
movl $1, %eax
movw %cx, seg_rmcb
movw %dx, off_rmcb
# save real mode interrupt vector
movw $0x0200, %ax
movb $0x1c, %bl
int $0x31
movw %cx, seg_orig_rm_handler
movw %dx, off_orig_rm_handler
# this function always succeeds
# point real mode interrupt vector to real mode callback
movw $0x0201, %ax
movb $0x1c, %bl
movw seg_rmcb, %cx
movw off_rmcb, %dx
int $0x31
# this function always succeeds
cleanup:
popl %edi
popl %esi
popl %edx
popl %ecx
popl %ebx
popfl
movl %ebp, %esp
popl %ebp
ret
_reset_handlers:
# reset protected mode interrupt vector
pushl %ebp
movl %esp, %ebp
pushfl
pushl %ebx
pushl %ecx
pushl %edx
movw $0x0205, %ax
movb $0x1c, %bl
movw sel_orig_pm_handler, %cx
movl off_orig_pm_handler, %edx
int $0x31
# reset real mode interrupt vector
movw $0x0201, %ax
movb $0x1c, %bl
movw seg_orig_rm_handler, %cx
movw off_orig_rm_handler, %dx
int $0x31
# free real mode callback wrapper
movw $0x0304, %ax
movw seg_rmcb, %cx
movw off_rmcb, %dx
int $0x31
popl %edx
popl %ecx
popl %ebx
popfl
movl %ebp, %esp
popl %ebp
ret
.data
begin_data_region:
index: .long 0
orig_pm_handler:
off_orig_pm_handler: .long 0
sel_orig_pm_handler: .short 0
seg_orig_rm_handler: .short 0
off_orig_rm_handler: .short 0
seg_rmcb: .short 0
off_rmcb: .short 0
dpmi_regs: .fill 50, 1, 0
end_data_region:
---------------------------------------------------------------------
- Raw text -