Page 1 of 1
please show me a code example to enable IRQ!
Posted: Mon Dec 11, 2006 6:38 pm
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.
Posted: Tue Dec 12, 2006 3:15 am
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
Posted: Tue Dec 12, 2006 7:15 pm
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.
Posted: Wed Dec 13, 2006 3:02 am
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
Posted: Wed Dec 13, 2006 4:47 pm
by R2_
hold on Im going to write the kernel from scratch following that tutorial to make sure I didn't miss anything.
Posted: Fri Dec 15, 2006 4:52 pm
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 ?
Posted: Fri Dec 15, 2006 6:05 pm
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
Posted: Fri Dec 15, 2006 6:18 pm
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
Posted: Fri Dec 15, 2006 6:24 pm
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.
Posted: Fri Dec 15, 2006 7:09 pm
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
Posted: Fri Dec 15, 2006 7:15 pm
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.
Posted: Fri Dec 15, 2006 8:31 pm
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
Posted: Sat Dec 16, 2006 3:44 pm
by R2_
thnx that did it
now I understand what I was doing wrong,