IRQ not fired on real hardware

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

IRQ not fired on real hardware

Post by poupougne »

Hello,
I've been working for a long time on my own OS, an it works fine within emulator such as Bochs & Qemu. But it fails on real hardware : i have tested with 3 real PC, it's ok until it reaches "STI" and so, no IRQ is fired and OS loops in "idle" task. I've been searching for days an days (forums, doc) but found nothing significant.
Do you have any idea ?

Samples of code :
A20 gate

Code: Select all

        ; activation ligne A20 
        ; masquer les irg 
        mov     al,0xFF 
        out     0xA1,al 
        out     0x21,al 
        ; si ko, essayer de desactiver le kbd avant (out 0x64,0xAD) et de le  
        ; reactiver apres (cmd out 0x64,0xAE), ou de lire le Ouput Port avant d'y 
        ; ecrire la meme valeur OR 2 (bit du A20 : bit 1 - a mettre a 1 pour activer A20) 
        ; 
        ;mov    al,0xAD 
        ;out    clavier_port_command,al ; ecriture Output Port du 8042 
        ; 
attente_8042_1: 
        jmp     $+2 
        in      al,clavier_port_command 
        test    al,2 
        jnz     attente_8042_1          ; attend que le buffer soit dispo (bit 1 à 0) 
        ; 
        mov     al,0xD1 
        out     clavier_port_command,al ; ecriture Output Port du 8042 
        ; 
attente_8042_2: 
        jmp     $+2 
        in      al,clavier_port_command 
        test    al,2 
        jnz     attente_8042_2          ; on attend que le buffer soit dispo (bit 1 a 0) 
        ; 
        mov     al,0xDF                 ; A20 + activation IRQ souris et clavier (0xCF a l'origine, 0xDF menuet32+bochs)
        out     clavier_port_data,al    ; autoriser la ligne A20 (envoi controleur 8042) 
        ; 
attente_8042_3: 
        jmp     $+2 
        in      al,clavier_port_command 
        test    al,2 
        jnz     attente_8042_3          ; on attend que le buffer soit dispo (bit 1 a 0) 
        ; 
        ;mov    al,0xAE 
        ;out    clavier_port_command,al ; ecriture Output Port du 8042 
        ; 
attente_8042_4: 
        ;jmp    $+2 
        ;in     al,clavier_port_command 
        ;test   al,2 
        ;jnz    attente_8042_4          ; on attend que le buffer soit dispo (bit 1 a 0) 
remap of 8259

Code: Select all

        ; mise en place des IRQ, programmation 8259 
        ; sauvegarde des masques 
        ;in     al,0x21 
        ;mov    bh,al 
        ;in     al,0xA1 
        ;mov    bl,al 
        ; iowait a mettre apres chaque out, pour laisser le temps au PIC de travailler 
        ;mov    al,0xFF         ; Masquage de toutes les interruptions avant travaux 
        ;out    0xA1,al 
        ;call   pic_iowait 
        ;out    0x21,al 
        ;call   pic_iowait 
        ; 
        mov     al,0x11         ; Initialisation 
        out     0x20,al 
        out     0xA0,al 
        ;call   pic_iowait 
        mov     al,0x20         ; Initialisation - Master - 1ere IRQ = 0x20 
        out     0x21,al 
        mov     al,0x28         ; Initialisation - Slave - 1ere IRQ = 0x28 
        out     0xA1,al 
        ;call   pic_iowait       
        mov     al,0x04         ; Initialisation - Master - lien master/slave 
        out     0x21,al 
        mov     al,0x02         ; Initialisation - Slave - lien master/slave 
        out     0xA1,al 
        ;call   pic_iowait 
        mov     al,0x01         ; Initialisation - Master - divers (8086) 
        out     0x21,al 
        mov     al,0x01         ; Initialisation - Slave - divers (8086) 
        out     0xA1,al 
        ;call   pic_iowait 
        ; 
        ; attente plus longue avant de remettre les masques 
        mov     ecx,0xFFFF 
pic_att: 
        nop 
        loop    pic_att 
        ; remise des masques sauvegardes 
        ;mov    al,bh 
        mov     al,0 
        out     0x21,al 
        out     0xA1,al 
        call    pic_iowait 
        ;mov    al,bl 
        ; envoi EOI aux 2 pics 
        mov     al,0x20 
        out     0x20,al 
        out     0xA0,al 
        jmp     pic_fin 
pic_iowait: 
        nop 
        ret 
pic_fin: 
Perhaps the order in which system initializations are done is important : A20 gate then entering pmode then remap irq then etc. !? If so, what is the correct order ?

Thanks to all by advance
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: IRQ not fired on real hardware

Post by Chandra »

poupougne wrote:Hello,
I've been working for a long time on my own OS, an it works fine within emulator such as Bochs & Qemu. But it fails on real hardware : i have tested with 3 real PC, it's ok until it reaches "STI" and so, no IRQ is fired and OS loops in "idle" task. I've been searching for days an days (forums, doc) but found nothing significant.
Do you have any idea ?

Samples of code :
A20 gate

Code: Select all

        ; activation ligne A20 
        ; masquer les irg 
        mov     al,0xFF 
        out     0xA1,al 
        out     0x21,al 
        ; si ko, essayer de desactiver le kbd avant (out 0x64,0xAD) et de le  
        ; reactiver apres (cmd out 0x64,0xAE), ou de lire le Ouput Port avant d'y 
        ; ecrire la meme valeur OR 2 (bit du A20 : bit 1 - a mettre a 1 pour activer A20) 
        ; 
        ;mov    al,0xAD 
        ;out    clavier_port_command,al ; ecriture Output Port du 8042 
        ; 
attente_8042_1: 
        jmp     $+2 
        in      al,clavier_port_command 
        test    al,2 
        jnz     attente_8042_1          ; attend que le buffer soit dispo (bit 1 à 0) 
        ; 
        mov     al,0xD1 
        out     clavier_port_command,al ; ecriture Output Port du 8042 
        ; 
attente_8042_2: 
        jmp     $+2 
        in      al,clavier_port_command 
        test    al,2 
        jnz     attente_8042_2          ; on attend que le buffer soit dispo (bit 1 a 0) 
        ; 
        mov     al,0xDF                 ; A20 + activation IRQ souris et clavier (0xCF a l'origine, 0xDF menuet32+bochs)
        out     clavier_port_data,al    ; autoriser la ligne A20 (envoi controleur 8042) 
        ; 
attente_8042_3: 
        jmp     $+2 
        in      al,clavier_port_command 
        test    al,2 
        jnz     attente_8042_3          ; on attend que le buffer soit dispo (bit 1 a 0) 
        ; 
        ;mov    al,0xAE 
        ;out    clavier_port_command,al ; ecriture Output Port du 8042 
        ; 
attente_8042_4: 
        ;jmp    $+2 
        ;in     al,clavier_port_command 
        ;test   al,2 
        ;jnz    attente_8042_4          ; on attend que le buffer soit dispo (bit 1 a 0) 
remap of 8259

Code: Select all

        ; mise en place des IRQ, programmation 8259 
        ; sauvegarde des masques 
        ;in     al,0x21 
        ;mov    bh,al 
        ;in     al,0xA1 
        ;mov    bl,al 
        ; iowait a mettre apres chaque out, pour laisser le temps au PIC de travailler 
        ;mov    al,0xFF         ; Masquage de toutes les interruptions avant travaux 
        ;out    0xA1,al 
        ;call   pic_iowait 
        ;out    0x21,al 
        ;call   pic_iowait 
        ; 
        mov     al,0x11         ; Initialisation 
        out     0x20,al 
        out     0xA0,al 
        ;call   pic_iowait 
        mov     al,0x20         ; Initialisation - Master - 1ere IRQ = 0x20 
        out     0x21,al 
        mov     al,0x28         ; Initialisation - Slave - 1ere IRQ = 0x28 
        out     0xA1,al 
        ;call   pic_iowait       
        mov     al,0x04         ; Initialisation - Master - lien master/slave 
        out     0x21,al 
        mov     al,0x02         ; Initialisation - Slave - lien master/slave 
        out     0xA1,al 
        ;call   pic_iowait 
        mov     al,0x01         ; Initialisation - Master - divers (8086) 
        out     0x21,al 
        mov     al,0x01         ; Initialisation - Slave - divers (8086) 
        out     0xA1,al 
        ;call   pic_iowait 
        ; 
        ; attente plus longue avant de remettre les masques 
        mov     ecx,0xFFFF 
pic_att: 
        nop 
        loop    pic_att 
        ; remise des masques sauvegardes 
        ;mov    al,bh 
        mov     al,0 
        out     0x21,al 
        out     0xA1,al 
        call    pic_iowait 
        ;mov    al,bl 
        ; envoi EOI aux 2 pics 
        mov     al,0x20 
        out     0x20,al 
        out     0xA0,al 
        jmp     pic_fin 
pic_iowait: 
        nop 
        ret 
pic_fin: 
Perhaps the order in which system initializations are done is important : A20 gate then entering pmode then remap irq then etc. !? If so, what is the correct order ?

Thanks to all by advance
I hope you dont mind replacing those french lines with English so that it would be little more easier to figure out what is happening.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: IRQ not fired on real hardware

Post by Combuster »

Or rather, what you intended for it to happen :wink:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: IRQ not fired on real hardware

Post by bewing »

I'm willing to try to read it in french, but the code you posted contains no STI -- so the description of the problem is incomplete. There is no particular order that you need to do things in, except by simple logic -- you need to enable A20 before you can access memory at 1M, for example.
Your PIC masking and IRQ mapping looks fine.

1) Why do you expect that there is a pending IRQ1 to fire? Did you hit a key?
2) What mode was the system in, when you think the scancode was generated? Pmode? Real mode?
3) If a scancode was generated while you had interrupts turned off, did you read it out of the buffer? Did some other piece of code read it out of the buffer (that is, the BIOS IRQ1 handler)?
4) Did another interrupt fire first (IRQ0?), and not get handled properly?

Basically, the causes for never getting an IRQ1 are: the bytes have all been read out of the keyboard buffer already, multiple bytes were put into the keyboard buffer and you've only read out one of them, EOI (0x20) has not been sent to the PIC (8259) after the last IRQ, or interrupts are still masked at the PIC.
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

Re: IRQ not fired on real hardware

Post by poupougne »

Thanks bewing for responding.

1) in fact, i expect IRQ0 to fire regularly, in order to activate the 4 processes that should be running
2) when STI is done, the system is in pmode, with PIT timer programmed, IRQ remapped and unmasked, and processes ready to run (IRQ handler are ok)
3) BIOS is no longer used at this point
4) in the IRQ0 handler, EOI is done at the beginning, before task swap ; i've put it at the end of the handler, but it doesn't change anything

Code: Select all

intirq0: 		; interruption materielle 0 : TIMER (scheduler)
	cli					; utile ??
	pushad					; mode 32b
	mov		[ebp+proc_save_esp],esp	; sauvegarde ESP pour les "POP"
	inc dword	[ebp+proc_nb_quantum]	; incremente le nb de quantum du process en cours
	mov		al,0x20			; envoi EOI
	out		0x20,al
	inc dword	[timer_systick]		; +1 au nb d'appels de l'IRQ0 !
	;
sched_manuel:
	mov	ebx,[proc_encours]
	movzx	ecx,byte[proc_prioriteec]	; cl / bit31=0 : 1er passage
	mov	ch,[proc_prio_max]
	test	ebx,ebx			; test si 0
	jnz	sched_proc_suivant
	; c'est le process "idle" qui tourne : recherche depuis priorite 0
	mov	ecx,0x80000700		; priorites : max=7, ec=0 ; bit31=1 : 2eme passage
	lea	ebx,[proc_tableec_p0]	; ad process a rechercher
	mov	[proc_debtable_p],ebx
	sub	ebx,4
sched_proc_suivant:
	add	ebx,4
sched_proc_suivant2:
	mov	ebp,[ebx]
	test	ebp,ebp				; test si 0
	jz	sched_suite_prio		
	mov	esi,[ebp+proc_att_mutex_adr]	; prochain process trouve - verif si en attente
	mov	edx,[ebp+proc_att_buffer_adr]
	mov	edi,[ebp+proc_att_systick]
	mov	eax,esi
	or	eax,edx
	or	eax,edi
	jz	sched_retour			; process trouve car pas en attente de ressource
	test	esi,esi
	jz	sched_pas_mutex			
	movzx	eax,byte[ebp+proc_att_mutex_bit]	; en attente mutex : libre ?
	bts	[esi],eax
	jnc	sched_retour			; en attente et mutex libre : ok
	jmp	sched_proc_suivant
sched_pas_mutex:
	test	edx,edx
	jz	sched_pas_buffer		; proc pas en attente POPW
	mov	eax,[edx+buffer_read]
	xor	eax,[edx+buffer_write]
	jnz	sched_retour			; en attente POPW et buffer plus vide : ok (read <> write)
	test	edi,edi
	jz	sched_proc_suivant		; pas en attente temporisee : process suivant
sched_pas_buffer:
	cmp	edi,[timer_systick]
	jbe	sched_retour			; en attente POPWT et delai depasse ou attente time-out et delai expire ou pas time-out : ok
	jmp	sched_proc_suivant
sched_suite_prio:
	; passage a la priorite suivante jusqu'a depasse priomax
	mov	ebx,[proc_debtable_p]
	add	ebx,1024
	mov	[proc_debtable_p],ebx
	inc	cl
	cmp	cl,ch
	jbe	sched_proc_suivant2
	; test si 1er passage ou non
	test	ecx,0x80000000
	jnz	sched_2eme_passage
sched_1er_passage:
	or	ecx,0x80000000		; bit31=1 si 2eme passage
	lea	ebx,[proc_tableec_p0]
	mov	[proc_debtable_p],ebx
	xor	cl,cl			; recommencer depuis priorite 0 (au 1er passage uniquement)
	inc	ch			; on fait tourner la prio max egalement
	and	ch,7
	jmp	sched_proc_suivant2
sched_2eme_passage:
	inc	ch			; a partir du 2eme passage, on cherche les priorite suivantes, sans revenir a la priorite 0
	and	ch,7
	jnz	sched_proc_suivant2
	; lancer idle car aucun process pret !
	xor	ebx,ebx
	lea	ebp,[proc_idle]
sched_retour:
	mov	[proc_prioriteec],cl
	mov	[proc_prio_max],ch
	mov	[proc_encours],ebx
	mov	[proc_encours_sav],ebx
	xor	eax,eax
	; ebp = adresse debut process en memoire
	mov	[ebp+proc_att_mutex_adr],eax	; proc actif : pas de mutex en attente !!
	mov	[ebp+proc_att_buffer_adr],eax	; ni de POPW en attente !
	mov	[ebp+proc_att_systick],eax	; ni de time-out en attente !
	mov	esp,[ebp+proc_save_esp]		; restaure ESP pour les "POP"
	popad					; mode 32b
	iret
I attach a floppy image, that you can try with Qemu : it should be working !
(press key 0/1/2 to choose screen mode and for VESA, then type key 1 to 9 to choose a mode)
Attachments
os.zip
contain floppy image usable with qemu/bochs
(43.73 KiB) Downloaded 32 times
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: IRQ not fired on real hardware

Post by Combuster »

You just confirmed the stereotypical "Vous parler l'Anglais? Oui!" and continue in French. And no, that's not a compliment. :evil:

Anyways, I can't see the relevant code, but did you actually configure the PIT to be in interval mode rather than one-shot mode like BIOSes tend to do, or did you only set the interval?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

Re: IRQ not fired on real hardware

Post by poupougne »

Thanks Combuster,
No, i'm not "continuing" in french. The source code of my os is more than 22,000 lines, written in french (i began in 2002).
I have only done copy/paste ! The time will come to translate it when the assembly part is finished.
I think that the source code i post is understandable.

Then, here is the sample of code the pit is setup, in interval mode i think (with no french sentences...)

Code: Select all

   ; timer IRQ0
	mov	al,0x36		; setup 8254 - count 0, periodic rect, 16 bits
	out	0x43,al
	xor	edx,edx
	mov	eax,0x001234DE		; (1193182 Hz)
	div dword [kernel_freq_sched]
	out	0x40,al		 	; LSB
	mov	al,ah			   ; MSB
	out	0x40,al
	mov	[kernel_freq_valeur],ax
While testing some issues, something strange happens.
After booting the os and "working" for a while (with qemu and bochs), i did a reset using emulator console, and at reboot, the same bug occurs : system halt and no irq fired ! No timer pulse neither keyboard response.
Can it help ?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: IRQ not fired on real hardware

Post by Combuster »

Try using rate generator instead of square wave.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: IRQ not fired on real hardware

Post by bewing »

Also, I think you should try sending an extra EOI to the PIC just before you enter your idle task -- just to make sure. If that changes the behavior, then you will know what the problem is.
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

Re: IRQ not fired on real hardware

Post by poupougne »

I got it about the reset bug !
There was a bug in the CREATE PROCESS function that zero'ed the first kb of memory, instead of process header ; that's why the os halted at reset (very strange behaviour indeed).
But it's still ko on real hardware... i continue debugging
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

Re: IRQ not fired on real hardware

Post by poupougne »

I've done some debugs and i found something interesting : it's not an IRQ firing bug :oops:
I misunderstood the problem, because on real hardware, the os boot from USB pendrive (i've no more floppy...). And the boot loader fail when it reaches sector # 64 : it's translated in CHS to sector 1 and head 1. But the loaded sector is not the one expected.
I copy the os with the "dd" utility, and my USB pendrive is set to 63 sectors and 255 heads.
Is there something special to do when there are "255" heads ?

Here is the part of code that loads sectors :

Code: Select all

secteur_suivant: 
        push    cx 
        mov     cx,[boot_piste_sect]   ; current sector - begins at 2 
        mov     dh,[boot_tete]          ; current head - begins at 0 
        mov     dl,[boot_device] 
        ; 
        push    es 
        xor     bx,bx 
        mov     ah,2            ; read sector
        mov     al,1            ; nb sectors to read
        int     0x13 
        jc      load_kernel_error       ; error
        mov     ax,0x0E2E               ; display point
        int     0x10 
        pop     es 
        mov     ax,es 
        add     ax,0x20
        mov     es,ax 
        ; calcul secteur suivant CHS (secteur++ puis head++ puis cylindre++) 
        mov     cx,[boot_piste_sect] 
        mov     dh,[boot_tete] 
        inc     cl              ; sect + 1 
        cmp     cl,[disk_nbsect] 
        jbe     secteur_fincalc 
        mov     cl,1 
        inc     dh              ; head + 1 
        cmp     dh,[mask_tete]  ; max head reaches 
        jbe     secteur_fincalc 
        ; come back to head 0 and cylinder ++
        inc     ch 
secteur_fincalc: 
        and     dh,[mask_tete] 
        mov     [boot_piste_sect],cx 
        mov     [boot_tete],dh 
        pop     cx 
        xor     si,si 
        loop    secteur_suivant 
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: IRQ not fired on real hardware

Post by bewing »

Use INT0x13/ah=8 to get the drive geometry, so you can calculate your CHS addresses at runtime. I think that should always work.

If that doesn't work then the answer is no -- you're screwed. Keep your bootloader under 64 sectors, transition to pmode, and use actual drivers.
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

Re: IRQ not fired on real hardware

Post by poupougne »

It's booting fine using extended int 13h.
It's ok when bios treat usb pen as HDD emulation.
But with another computer, it's recognized as FDD emulation and extended int 13h returns an error !
In this case, as you suggest it Bewing, i will try to get drive geometry ans use CHS int 13h.
When it's ok, i will share the code.
Thanks all.
poupougne
Posts: 7
Joined: Wed May 05, 2010 6:23 am
Location: Lyon, France

Re: IRQ not fired on real hardware

Post by poupougne »

Hi,

After lots of tests, when extended int 13h is ko, getting drive geometry and using CHS int 13h manage to load kernel (32 Mo fob).
But there's still (but now i'm not so sure) an IRQ bug. After loading kernel, doing some initializations, sending extra EOI to PIC and then doing STI, nothing happens !
The CPU is a Sempron 64 : does 64 bits capability make a difference, while running in PM legacy 32bits mode, with 32 bits "native" CPU ? I saw nothing of it in Intel's doc.

On the another computer, DELL laptop with Pentium M, it loads correctly and os runs correctly too, with IRQ 0/1/12 firing normally (it's loaded using extended int 13h, fob being treated as HDD emulation). It's also correct with Qemu and Bochs 2.4.5

Thanks
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: IRQ not fired on real hardware

Post by bewing »

It's not supposed to make any difference, but clearly you have found something. One possibility is that some hardware on the new system uses level-triggered interrupts. The old PIC is not built to handle those, and they do cause issues on real systems -- but nothing should really be different until you enable the APICs.

But the real point is that you have now crossed the border from finding generic bugs in your kernel that would happen on all systems, to finding very specific hardware bugs on only specific systems. We will all be interested in hearing what the bug is, but we can only offer small suggestions on what kinds of things may be causing it.
Post Reply