delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/11/01/00:53:52

Date: Fri, 31 Oct 1997 02:02:08 +0000 ( )
From: "Gurunandan R. Bhat" <grbhat AT unigoa DOT ernet DOT in>
To: djgpp AT delorie DOT com
Subject: Tracing the path of Software Interrupts
Message-Id: <Pine.LNX.3.91.971031015324.237A-100000@aditya.unigoa.ernet.in>
Mime-Version: 1.0

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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019