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: 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 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 /* _farpokeb(), _farpeekb() */ #include /* kbhit(), getch() */ #include /* outportb() */ #include /* _my_cs() */ #include /* _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