delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2000/01/08/23:09:02

From: NoEmailAds AT execpc DOT com (Chris Giese)
Newsgroups: alt.os.development,alt.os.assembly,comp.os.msdos.djgpp,alt.lang.asm
Subject: Re: ISR with DJGPP in a kernel.
Date: Sun, 09 Jan 2000 02:43:47 GMT
Organization: Church of the SubGenius - Propulsion Group
References: <s7dr49t5oj886 AT corp DOT supernews DOT com>
X-Newsreader: Forte Free Agent 1.11/32.235
Lines: 151
Message-ID: <3877f58e$0$1379@news.execpc.com>
NNTP-Posting-Host: 6b640537.news.execpc.com
X-Trace: 0RW8S?BXNaRI5[332>a9Y[bfNiaEHUgJWRYcgIRLSUE]>VTjIHLkV<WfXg\jTb[AT]lO<3E9iRX4W6=oZ8VFQiOQ
X-Complaints-To: abuse AT execpc DOT com
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

Mind-control rays from black helicopters made Groman
<groman AT thehelm DOT com> write:

>I am writing a small kernel using DJGPP and NASM, and I bumped into several
>problems(again).
>
>Ok...here are my steps.
>
>1) I create the IDT and load the register.
>2) I reprogram the PIC to shift the IRQs so they do not overlap with the
>exceptions.
>3) I disable all IRQs beside 2 and 0.
>Now I want to create a handler for 0(the timer) in C...
>now, how exactly do I do that... I mean it jumps out of the code right in
>the middle of the function...and starts another one?

Yes, that's how interrupts work.

>shoud I do the handler in assembly that calls C functions then? or is there
>a way to turn an ordinary DJGPP function
>into a handler...

Using DPMI (DJGPP + CWSDPMI or Win95 + DOS):

#include <sys/farptr.h>	/* _farpokeb(), _farpeekb() */
#include <conio.h>	/* kbhit(), getch() */
#include <dos.h>	/* outportb() */
#include <go32.h>	/* _my_cs() */
#include <dpmi.h>	/* _go32_dpmi_... */
/*****************************************************************************
*****************************************************************************/
void irq8(void)
{/* increment char at upper left corner of screen */
	_farpokeb(_dos_ds, 0xB8000L,
		_farpeekb(_dos_ds, 0xB8000L) + 1);
/* reset 8259-compatible interrupt controller */
	outportb(0x20, 0x20); }
/*****************************************************************************
	name:	main
*****************************************************************************/
int main(void)
{	_go32_dpmi_seginfo OldVector, NewVector;

/* save the old vector */
	_go32_dpmi_get_protected_mode_interrupt_vector(8, &OldVector);
/* install new interrupt handler */
	NewVector.pm_selector=_my_cs();
	NewVector.pm_offset=(unsigned long)irq8;
	_go32_dpmi_allocate_iret_wrapper(&NewVector);
	_go32_dpmi_set_protected_mode_interrupt_vector(8, &NewVector);
/* main loop */
	getch();
/* restore old vector */
	_go32_dpmi_set_protected_mode_interrupt_vector(9, &OldVector);
	return(0); }

If you're writing an interrupt handler for your own OS, you need code
to replace the _go32_dpmi...() functions above. The main concern is
saving the values of the CPU registers when the interrupt occurs.
This has to be done in assembler. Maybe something like this:

[SECTION .text]
[BITS 32]

isr0:	push byte 0	; push error code
	push byte 0	; push interrupt #
	jmp short fault1
isr1:	push byte 0
	push byte 1
	jmp short fault1
;
; ...
;
isr8:	nop	; interrupt 8 is Double Fault
	nop	; It pushes an error code, so we don't have to
	push byte 8
	jmp short fault1
;
; ...
;
isr0D:	nop	; general protection fault
	nop
	push byte 0x0D
	jmp short fault1
;
; ...
;
isr20:	nop	; timer tick
	nop
	push byte 0x20
	jmp short fault1
;
; ...
;
isr30:	nop	; syscall!
	nop
	push byte 0x30
	jmp short fault1
;
; ...
;
fault1:	push gs
	push fs
	push es
	push ds
; save the 7 general-purpose registers
	pusha
; hopefully, the interrupt set SS automatically
; if the data and stack are in the same segment, we can do this:
; copy SS to DS, ES, FS, and GS
		mov ax,ss
		mov ds,ax
		mov es,ax
		mov fs,ax
		mov gs,ax
[EXTERN _my_isr]
		call _my_isr
	popa
	pop ds
	pop es
	pop fs
	pop gs
; drop exception # and error code
	add esp,8
	iret

The C language handler looks like this:

void fault(volatile long EDI, volatile long ESI, volatile long EBP,
	volatile long ESP, volatile long EBX, volatile long ECX,
	volatile long EAX, volatile long DS, volatile long ES,
	volatile long FS, volatile long GS, volatile long WhichInt,
	volatile long ErrCode, volatile long EIP, volatile long CS,
	volatile long EFLAGS, volatile long UserESP,
	volatile long UserSS)
{
// look at WhichInt, figure out if this is a fault,
// hardware interrupt, or syscall
}

If this is a system call interrupt (interrupt 0x30 in this case), you
can fiddle with the user-mode register values on the stack. The
assembly-language code will pop those values back into the registers
when you return. This is NOT something you want to do with a hardware
interrupt (timer, keyboard, etc.)

-- 
geezer@    | Sales rushes in where
execpc.com | Engineering fears to tread
pmode tutorial, homebrew OS: http://www.execpc.com/~geezer/os

- Raw text -


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