Page 1 of 1
IRQ not fired on real hardware
Posted: Wed Feb 16, 2011 2:48 am
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
Re: IRQ not fired on real hardware
Posted: Wed Feb 16, 2011 3:38 am
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.
Re: IRQ not fired on real hardware
Posted: Wed Feb 16, 2011 5:44 am
by Combuster
Or rather, what you intended for it to happen
Re: IRQ not fired on real hardware
Posted: Wed Feb 16, 2011 6:33 am
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.
Re: IRQ not fired on real hardware
Posted: Wed Feb 16, 2011 8:19 am
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)
Re: IRQ not fired on real hardware
Posted: Wed Feb 16, 2011 11:38 am
by Combuster
You just confirmed the stereotypical "Vous parler l'Anglais? Oui!" and continue in French. And no, that's not a compliment.
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?
Re: IRQ not fired on real hardware
Posted: Thu Feb 17, 2011 2:36 am
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 ?
Re: IRQ not fired on real hardware
Posted: Thu Feb 17, 2011 4:33 pm
by Combuster
Try using rate generator instead of square wave.
Re: IRQ not fired on real hardware
Posted: Fri Feb 18, 2011 12:04 am
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.
Re: IRQ not fired on real hardware
Posted: Tue Feb 22, 2011 2:02 am
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
Re: IRQ not fired on real hardware
Posted: Thu Feb 24, 2011 2:13 am
by poupougne
I've done some debugs and i found something interesting : it's not an IRQ firing bug
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
Re: IRQ not fired on real hardware
Posted: Thu Feb 24, 2011 2:23 pm
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.
Re: IRQ not fired on real hardware
Posted: Mon Feb 28, 2011 3:42 am
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.
Re: IRQ not fired on real hardware
Posted: Wed Mar 09, 2011 6:11 am
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
Re: IRQ not fired on real hardware
Posted: Wed Mar 09, 2011 8:27 am
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.