please show me a code example to enable IRQ!

Programming, for all ages and all languages.
Post Reply
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

please show me a code example to enable IRQ!

Post by R2_ »

I been looking for 2 weeks how to enable IRQ but I still can't find how. Please someone post a link to a tutorial on doing this or post code.
Thnx in advanced.

I looked at the osdev wiki but nothing there worked.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Hi,

I had a headache with this initially too. Have a look at http://www.osdever.net/bkerndev/index.php?the_id=90, which has sections on the IDT, ISR's, IRQ's and the PIC's.

You will need to ensure that you follow all the sections before enabling interrupts, because otherwise you will find that the timer interrupt tries to call it's (non-existant) handler resulting ultimately in a triple-fault exception (depending on the rest of your OS environment).

Hope this helps,
Adam
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

O so thats why when I enable interrupts it crashes ? (well my VM at least)

I tried that but I must be doing something wrong because it still crashing when I call asm("sti"); any source code to a kernel with basic I/O will be appreciated.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Hi,

The link given in my previous post should get you on track. Basically, it will take you through the following steps, which you will need before using sti:

* Set up descriptors in the IDT for at least interrupts 0-31 (exceptions) and 32-47 (irq's). The irq_set_gate() function of the above example will vastly simplify this.

* Set up an information structure containing the base and limit of the IDT. Load this structure via the LIDT instruction.

* Remap the PIC so that the correct IRQ's are calling the expected irq handlers.

* Call ("sti"). You will at least need 'placeholder' Interrupt Service Routines to display the nature of the interrupt on screen (or send them to a COM port for easier debugging!).

If you enable interrupts ("sti") and find that you get a divide by zero exception (int 0) immediately, chances are that you have not set up an interrupt handler for int 32 (IRQ 0). This means that every time the timer fires, it will fire up the code for int 0 (or a random point in memory).

Of course, I have assumed that at this point you have a valid GDT and if you are using paging, you have correctly paged in your entire kernel... :)

If none of this helps and you have interrupt handlers or are using an emulator, can you at least give me some idea which interrupt seems to be firing?

Cheers,
Adam
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

hold on Im going to write the kernel from scratch following that tutorial to make sure I didn't miss anything.
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

will

IDTptr DW 7FFh
DD 0000h

GDTptr DW 17FFh
DD 0800h

and then

LIDT FWORD PTR IDTptr
LGDT FWORD PTR GDTptr


set up GDT and IDT ?
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

Code: Select all

%include "grub.inc" ; needed for the multiboot header

[BITS 32]

[global start]
[extern _k_main] ; this is in the c file

gdtr dw 0   ; for limit storage
     dd 0   ; for base storage

setGdt:
   mov eax,[esp+4]
   mov [gdtr+2],eax
   mov ax,[esp+8]
   mov [gdtr],ax
   lgdt [gdtr]
   ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; the IDT with it's descriptors
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
start_of_idt:
;interrupt 0
dw 0x0000
dw 0x10
dw 0x8E00
dw 0x20

;interrupt 1
dw 0x0000
dw 0x10
dw 0x8E00
dw 0x20

;interrupt 2, intel reserved, we set the 'present' bit to 0 on this one
dw 0x0000
dw 0x10
dw 0xE00
dw 0x20

;interrupts 3-14 now, since we are making the descriptors
;identical, we are going to loop to get them all(12 total)
%rep 0xC
  dw 0x0000
  dw 0x10
  dw 0x8E00
  dw 0x20
%endrep

;interrupt 15, intel reserved, we set the 'present' bit to 0 on this one
dw 0x0000
dw 0x10
dw 0xE00
dw 0x20

;interrupt 16
dw 0x0000
dw 0x10
dw 0x8E00
dw 0x20
end_of_idt:

idt_pointer:
dw end_of_idt - start_of_idt - 1
dd start_of_idt

start:
 ; stop using bootloader GDT, and load new GDT
lgdt [gdtr]
lidt [idt_pointer]
 push es
 pop ds
 push ds
STI
 xor   eax,eax 
         in    al,0x60
  call _k_main

  jmp $ ; crash
  hlt ; halt the CPU




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Multiboot header for GRUB bootloader. This must be in the first 8K
; of the kernel file. We use the aout kludge so it works with ELF,
; DJGPP COFF, Win32 PE, or other formats.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; these are in the linker script file
EXTERN code, bss, end

ALIGN 4
mboot:
	dd MULTIBOOT_HEADER_MAGIC
	dd MULTIBOOT_HEADER_FLAGS
	dd MULTIBOOT_CHECKSUM
; aout kludge. These must be PHYSICAL addresses
	dd mboot
	dd code
	dd bss
	dd end
	dd start
I've setup IDT and GDT tables and it still doesn't work.. when I call STI it crashes the VM. Is there anything im missing in my above code ? the VM works well with other OSs
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
R2_ wrote:I've setup IDT and GDT tables and it still doesn't work.. when I call STI it crashes the VM. Is there anything im missing in my above code ? the VM works well with other OSs
I'm not sure how much you didn't post, but for the code you did post I didn't see any IRQ handlers, any code to set the address of each IRQ handler or any code to remap the PICs....


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

Thnx that must be what im missing, I been having a lot of trouble getting keyboard input to work as I am a newbie at OSDev for the intel architecture. OSdever.net IDT tutorials don't work either.

I still think STI should work, yet for some reason it crashes the VM.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
R2_ wrote:Thnx that must be what im missing, I been having a lot of trouble getting keyboard input to work as I am a newbie at OSDev for the intel architecture. OSdever.net IDT tutorials don't work either.

I still think STI should work, yet for some reason it crashes the VM.
The problem is that STI does work.... ;)

As far as I can tell, when any IRQ occurs (after the STI) the CPU will look at the IDT, find the entry for that IRQ, and then either crash or try to execute an interrupt handler with CS:EIP set to 0x0010:0x00200000 (from the IDT entry). Because there's no code at 0x0010:0x00200000 this would cause it to crash too.

When the CPU does crash it'd generate an exception, which would make it crash again and generate a double fault exception. The double fault exception would crash too, causing a triple fault (CPU reset).

So that it doesn't crash you need to either mask all IRQs in the PIC, or write valid IRQ handlers and put the addresses of the IRQ handlers into the IDT (so that the CPU can find them when an IRQ occurs).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

So my IDT table is correct just I need to add an entry for devices such as the system clock ?
sorry for wasting your time, I just really want my kernel to support input and I been trying for 3 books, bought the book MMURTL but the code there is not explained at all.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
R2_ wrote:So my IDT table is correct just I need to add an entry for devices such as the system clock ?
sorry for wasting your time, I just really want my kernel to support input and I been trying for 3 books, bought the book MMURTL but the code there is not explained at all.
For every interrupt that could be generated (either exceptions generated by the CPU or IRQs sent to the CPU by the PIC chips) you need a corresponding IDT entry pointing to valid code to handle that interrupt.

At the moment all of your IDT entries point to 0x10:0x00200000 and don't point to valid code to handle the interrupt. In addition, the first (master) PIC chip is probably generating interrupts 0x08 to 0x0F which conflict with the CPU exceptions (so you won't be able to easily tell what caused these interrupts) and the second (slave) PIC chip is probably generating interupts 0x70 to 0x77 which don't have any IDT entries.

Lastly, your IDT limit only allows IDT entries for interrupts 0x00 to 0x11, so any higher interrupts (e.g. from the slave PIC) will cause a general protection fault.

For now, try doing something like this:

Code: Select all

start:
 ; stop using bootloader GDT, and load new GDT
    lgdt [gdtr]
    lidt [idt_pointer]

;Setup segment registers and stack

    mov ax, <what is the correct GDT entry for data segments???>
    mov ss,ax
    mov ds,ax
    mov es,ax
    mov fs,ax
    mov gs,ax
    jmp far <what is the correct GDT entry for the code segment???>:.here
.here:
    mov esp, <where is your stack meant to be???>

;Mask all IRQs in the PIC, except the timer IRQ

    mov al,11111110b
    out 0x20+1,al
    mov al,11111111b
    out 0x21+1,al

;Set the IDT entry for the timer IRQ

    mov eax, timerIRQhandler
    mov cx, <what is the correct GDT entry for the code segments???>
    mov [start_of_idt + 0x08 * 8], ax
    shr eax,16
    mov [start_of_idt + 0x08 * 8 + 6], ax
    mov [start_of_idt + 0x08 * 8 + 2], cx
    mov word [start_of_idt + 0x08 * 8+4], 0x8E00

;Enable IRQs and stop

    sti
.wait:
    hlt
    jmp .wait



;Timer IRQ handler

timerIRQhandler:
    push eax
    inc dword [0x000B8000]     ;Increase a dword that is (hopefully) in video display memory
    mov al,0x20
    out 0x20,al                           ;Send "end of interrupt" to the PIC chip
    pop eax
    iret
If this works (and if you're in text mode) you should see a pair of flashing characters at the top left corner of the screen....

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
R2_
Member
Member
Posts: 50
Joined: Sat Dec 02, 2006 3:27 pm

Post by R2_ »

thnx that did it :D now I understand what I was doing wrong,
Post Reply