Why does enabling INTs triple faults in 1 PC?

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
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Why does enabling INTs triple faults in 1 PC?

Post by ~ »

Maybe I'm missing something, the A20 has been enabled already seemingly, or this wouldn't run, but most tutorials use GRUB to boot and set up the machine, which is a bad option if you want to know every single required bit for a stable booting.

Even the Alexei Frounze tutorials end with GPF whenever they use interrupts in that machine. And have tried fast A20, BIOS A20 and keyboard controller A20 in one of my boot sectors, and it doesn't work yet.

I made a small test kernel and have debugged it as far as I know, and have isolated the problem to the moment I enable interrupts with STI. But it only happens in 1 machine.

I don't think it's a stack alignment problem, but can be some other similar problem.

http://126.sytes.net/tmp/kern_int_err0000.zip

At the end I have put the most relevant "RealC" source (asm-C-like) in the most accurate order so you can evaluate it more easily.

It contains the full source code in Assembly. If you want to understand it clearly you can see the CSM files of the same names as those as the ASM files. These contain C-like source code which is easier to understand yet with assembly level.

What is that could be wrong here, judging from what it's doing, what details are lacking in the configuration process?

Code: Select all

The whole skeleton with PIT, keyboard and a
dummy inactive PS/2 mouse IRQs.

Files:
_____
bootf.zip        -- The floppy boot sources by John Fine
floppy_image.img -- The whole floppy image
BOOTSECT.BIN     -- Only th floppy bootsector
kernel.bin       -- The kernel described below


The floppy boot sources have been modified. The
ONLY changes have been to both load the
kernel directly at 0x100000 and leave Paging
disabled in CR0. Everything else is intact and
unchanged.


It does the following, in order:

- Program resides at 0x100000
- Disables interrupts (CLI)
- Sets SS, DS, ES, FS, GS to data selector 16
- Sets ESP to 0x100000*3-1
- Sets PIC1 to INTs 28h-2Fh and PIC2 to 70h-77h
- Leaves keyboard and PS/2 mouse IRQs active at PIC1
- IDT resides at 0x100000*2
- Zeroes IDT up to INT 77h
- Builds keyboard, PS/2 mouse and PIT vectors
- Sets the first default onscreen text DWORD to "1234"
- Loads IDT with LIDT[IDTR]
- Enables Interrupts with STI (it Bombs in 1 PC)
- Loops forever incrementing onscreen text DWORD at [0xB8000+41]

Description of Bombing:
_____________________

When the program bombs, it has already been
loaded and configured. Just when interrupts are
enabled, it resets in a 2010 Asrock Intel E6500
Dual Core machine, model N73V-S. The A20 gate is enabled in the
boot code, because if the STI instruction to
enable interrupts is removed, it works fine
but without interrupts.
_________________________________________
_________________________________________
_________________________________________
_________________________________________
_________________________________________
_________________________________________

Main:

Code: Select all

bits 32
org 1048576


asm cli
asm mov ax,16
asm mov ss,ax
asm mov ds,ax
asm mov es,ax
asm mov fs,ax
asm mov gs,ax
asm mov esp,1048576*3-1


#include "pmode_pic_reprogramming.asm"
#include "idt_builder.asm"


dword[0xB8000+160]="1234";



asm{
lidt[IDTR]

asm sti
are:
 inc dword[0xB8000+41]
jmp are
}



#include "idtr.asm"


#include "ps2_keyb_isr.asm"
#include "ps2_mouse_isr.asm"
#include "pit_isr.asm"
_________________________________________
_________________________________________
_________________________________________
_________________________________________
_________________________________________
_________________________________________


ISR sample:

Code: Select all

function pit_isr()
{
 asm push eax

  dword[0xB8002+60]++;  //Print something



 //Send EOI to PIC 1
 ///
  $AL=20h;
  asm out 20h,al


 asm pop eax
 asm iretd
}

PIC reprogramming:

Code: Select all

/*
 Port 20h and A0h -- Write-only (supposedly)
                        After PIC initialization, used more commonly
                        for sending EOI (End Of Interrupt).

 Port 21h and A1h -- Read/Write
                        After PIC initialization, used more commonly
                        to read/write/enable/disable specific IRQs
                        from 0 to 15 (0-7 in PIC_1_Master and 8-15
                        in PIC_2_Slave).

*/


;//Initialization Command Word 1
;//Initialization Command Word 1
;//Initialization Command Word 1
;//Send ICW1:
;;;
;//ICW1 bitset:
;// Bits:
;//   bit 0 -- ICW4 needed          (1) or ICW4 not needed          (0)
;//   bit 1 -- cascade mode         (0) or single mode              (1)
;//   bit 2 -- IDT entry is 8 bytes (0) or 4 bytes                  (1)
;//   bit 3 -- edge triggered mode  (0) or level triggered mode     (1)
;//   bit 4 -- ICW1 is being issued (1) or ICW1 is not being issued (0)
;//  bits 5-7 are only used if bit 2 is 0 (000)
;
$AL=00010001b;
asm out 0x20,al; ;//PIC1

$AL=00010001b;
asm out 0xA0,al; ;//PIC2




;//Initialization Command Word 2
;//Initialization Command Word 2
;//Initialization Command Word 2
;//Send ICW2:
;;;
;//ICW2 bitset:
;// Bits:
;//  bit  0-2 -- reserved (00)
;//  bits 3-7 -- first INT number to be handled by each PIC
;
$AL=0x28;
asm out 0x21,al; ;//PIC1: INT28h-2Fh (like in Real Mode but now it's INT (08h+20h))

$AL=0x70;
asm out 0xA1,al; ;//PIC2: INT70h-77h (like in Real Mode)




;//Initialization Command Word 3
;//Initialization Command Word 3
;//Initialization Command Word 3
;//Send ICW3:
;;;
;//ICW3 bitset:
;// Bits:
;//  bit 0 -- PIC attached, "IRQ 0 to PIC2" for PIC1 and "IRQ  8" for PIC2  (1)
;//        or cascaded disabled for "IRQ 0" for PIC1 and "IRQ  8" for PIC2  (0)
;//
;//  bit 1 -- PIC attached, "IRQ 1 to PIC2" for PIC1 and "IRQ  9" for PIC2  (1)
;//        or cascaded disabled for "IRQ 1" for PIC1 and "IRQ  9" for PIC2  (0)
;//
;//  bit 2 -- PIC attached, "IRQ 2 to PIC2" for PIC1 and "IRQ 10" for PIC2  (1)
;//        or cascaded disabled for "IRQ 2" for PIC1 and "IRQ 10" for PIC2  (0)
;//
;//  bit 3 -- PIC attached, "IRQ 3 to PIC2" for PIC1 and "IRQ 11" for PIC2  (1)
;//        or cascaded disabled for "IRQ 3" for PIC1 and "IRQ 11" for PIC2  (0)
;//
;//  bit 4 -- PIC attached, "IRQ 4 to PIC2" for PIC1 and "IRQ 12" for PIC2  (1)
;//        or cascaded disabled for "IRQ 4" for PIC1 and "IRQ 12" for PIC2  (0)
;//
;//  bit 5 -- PIC attached, "IRQ 5 to PIC2" for PIC1 and "IRQ 13" for PIC2  (1)
;//        or cascaded disabled for "IRQ 5" for PIC1 and "IRQ 13" for PIC2  (0)
;//
;//  bit 6 -- PIC attached, "IRQ 6 to PIC2" for PIC1 and "IRQ 14" for PIC2  (1)
;//        or cascaded disabled for "IRQ 6" for PIC1 and "IRQ 14" for PIC2  (0)
;//
;//  bit 7 -- PIC attached, "IRQ 7 to PIC2" for PIC1 and "IRQ 15" for PIC2  (1)
;//        or cascaded disabled for "IRQ 7" for PIC1 and "IRQ 15" for PIC2  (0)
;//
;
$AL=00000100b;
asm 0x21,al; ;//PIC1: connection to slave in IRQ2

$AL=00000010b;
asm out 0xA1,al; ;//PIC2: this is the hook from IRQ9 to the IRQ2 in PIC2




;//Initialization Command Word 4
;//Initialization Command Word 4
;//Initialization Command Word 4
;//Send ICW4:
;;;
;//ICW4 bitset:
;// Bits:
;//   bit 0   -- 8086/8088 mode (1) or 8085 mode                 (0)
;//   bit 1   -- manual EOI     (0) or auto EOI                  (1) Interrupt Acknowledge
;//  bits 2-3 --               [00] == nonbuffered mode      == [00]
;//                            (01) == nonbuffered mode      == (01)
;//                            (10) == buffered mode/slave   == (10)
;//                            (11) == buffered mode/master  == (11)
;//   bit 4   -- normal mode    (0) or special fully-nested mode (1)
;//  bits 5-7 -- reserved     (000)
;
$AL=00000001b;
asm out 0x21,al; ;//PIC1

$AL=00000001b;
asm out 0xA1,al; ;//PIC2




;//Output Control Word 1
;//Output Control Word 1
;//Output Control Word 1
;//Send OCW1:
;;;
;//OCW1 bitset:
;// Bits:
;//  bit 0 -- disable IRQ0 in PIC1 or IRQ8  in PIC2 (1) or enable it (0)
;//  bit 1 -- disable IRQ1 in PIC1 or IRQ9  in PIC2 (1) or enable it (0)
;//  bit 2 -- disable IRQ2 in PIC1 or IRQ10 in PIC2 (1) or enable it (0)
;//  bit 3 -- disable IRQ3 in PIC1 or IRQ11 in PIC2 (1) or enable it (0)
;//  bit 4 -- disable IRQ4 in PIC1 or IRQ12 in PIC2 (1) or enable it (0)
;//  bit 5 -- disable IRQ5 in PIC1 or IRQ13 in PIC2 (1) or enable it (0)
;//  bit 6 -- disable IRQ6 in PIC1 or IRQ14 in PIC2 (1) or enable it (0)
;//  bit 7 -- disable IRQ7 in PIC1 or IRQ15 in PIC2 (1) or enable it (0)
;
$AL=11111100b;  //Enable keyboard and PIT IRQs
asm out 0x21,al; ;//PIC1, disables also the IRQ2 slave line response

$AL=11111111b;
asm out 0xA1,al; ;//PIC2

_________________________________________
_________________________________________
_________________________________________
_________________________________________


IDT building:

Code: Select all

IDT equ 1048576*2

///INIT: Zero-clear the IDT memory
///INIT: Zero-clear the IDT memory
///INIT: Zero-clear the IDT memory
//  $ECX=(78h*8)/4;  //Number of vectors times Size of INT vector
                     //divided by DWORD size

  $ECX=240;  //240 DWORDs!!!


  $EDI=IDT;        //Destination for the IDT
  asm xor eax,eax  ;Zero value
  asm rep stosd    ;Zero out!


///END:  Zero-clear the IDT memory
///END:  Zero-clear the IDT memory
///END:  Zero-clear the IDT memory





///INIT: Setup the keyboard ISR
///INIT: Setup the keyboard ISR
///INIT: Setup the keyboard ISR
///INIT: Setup the keyboard ISR

  $EDI=IDT;   //Take IDT base address
  $EDI+=328;  //Go to 29h*8, or vector 29h


   asm {
        mov eax,ps2_keyb_isr  ;take base address


       ;dw 00000h       ; (Bytes 0-1) ISR Handler Low Word, bits 0-15
        mov word[edi],ax

       ;dw 00008h       ; (Bytes 2-3) Segment Selector
        mov word[edi+2],8

       ;db 000h         ; (Byte 4)    bits 0-4 Reserved (00000b)
                        ;             bits 5-7 000b
        mov byte[edi+4],0
                         
       ;db 10001110b    ; (Byte 5)    bit 0 -- 0
                        ;             bit 1 -- 1
                        ;             bit 2 -- 1
                        ;             bit 3 -- Default Operand Size (D)
                        ;                 0b -- 16 bits
                        ;                 1b -- 32 bits
                        ;
                        ;             bit 4 -- 0
                        ;             bit 5-6 -- Descriptor Privilege Level (DPL)
                        ;                 00b -- Ring 0
                        ;                 01b -- Ring 1
                        ;                 10b -- Ring 2
                        ;                 11b -- Ring 3
                        ;
                        ;             bit 7 -- Present (P)
                        ;                 0b -- No
                        ;                 1b -- Yes
        mov byte[edi+5],10001110b                        


       ;dw 00000h       ; (Bytes 6-7) ISR Handler High Word, bits 16-31
        ror eax,16
        mov word[edi+6],ax
    }  


///END:  Setup the keyboard ISR
///END:  Setup the keyboard ISR
///END:  Setup the keyboard ISR




























///INIT: Setup the PS/2 mouse ISR
///INIT: Setup the PS/2 mouse ISR
///INIT: Setup the PS/2 mouse ISR
///INIT: Setup the PS/2 mouse ISR

  $EDI=IDT;   //Take IDT base address
  $EDI+=928;  //Go to 74h*8, or vector 74h


   asm {
        mov eax,ps2_mouse_isr  ;take base address


       ;dw 00000h       ; (Bytes 0-1) ISR Handler Low Word, bits 0-15
        mov word[edi],ax

       ;dw 00008h       ; (Bytes 2-3) Segment Selector
        mov word[edi+2],8

       ;db 000h         ; (Byte 4)    bits 0-4 Reserved (00000b)
                        ;             bits 5-7 000b
        mov byte[edi+4],0
                         
       ;db 10001110b    ; (Byte 5)    bit 0 -- 0
                        ;             bit 1 -- 1
                        ;             bit 2 -- 1
                        ;             bit 3 -- Default Operand Size (D)
                        ;                 0b -- 16 bits
                        ;                 1b -- 32 bits
                        ;
                        ;             bit 4 -- 0
                        ;             bit 5-6 -- Descriptor Privilege Level (DPL)
                        ;                 00b -- Ring 0
                        ;                 01b -- Ring 1
                        ;                 10b -- Ring 2
                        ;                 11b -- Ring 3
                        ;
                        ;             bit 7 -- Present (P)
                        ;                 0b -- No
                        ;                 1b -- Yes
        mov byte[edi+5],10001110b                        


       ;dw 00000h       ; (Bytes 6-7) ISR Handler High Word, bits 16-31
        ror eax,16
        mov word[edi+6],ax
    }  


///END:  Setup the PS/2 mouse ISR
///END:  Setup the PS/2 mouse ISR
///END:  Setup the PS/2 mouse ISR




























///INIT: Setup the PIT ISR
///INIT: Setup the PIT ISR
///INIT: Setup the PIT ISR
///INIT: Setup the PIT ISR

  $EDI=IDT;   //Take IDT base address
  $EDI+=320;  //Go to 28h*8, or vector 28h


   asm {
        mov eax,pit_isr  ;take base address


       ;dw 00000h       ; (Bytes 0-1) ISR Handler Low Word, bits 0-15
        mov word[edi],ax

       ;dw 00008h       ; (Bytes 2-3) Segment Selector
        mov word[edi+2],8

       ;db 000h         ; (Byte 4)    bits 0-4 Reserved (00000b)
                        ;             bits 5-7 000b
        mov byte[edi+4],0
                         
       ;db 10001110b    ; (Byte 5)    bit 0 -- 0
                        ;             bit 1 -- 1
                        ;             bit 2 -- 1
                        ;             bit 3 -- Default Operand Size (D)
                        ;                 0b -- 16 bits
                        ;                 1b -- 32 bits
                        ;
                        ;             bit 4 -- 0
                        ;             bit 5-6 -- Descriptor Privilege Level (DPL)
                        ;                 00b -- Ring 0
                        ;                 01b -- Ring 1
                        ;                 10b -- Ring 2
                        ;                 11b -- Ring 3
                        ;
                        ;             bit 7 -- Present (P)
                        ;                 0b -- No
                        ;                 1b -- Yes
        mov byte[edi+5],10001110b                        


       ;dw 00000h       ; (Bytes 6-7) ISR Handler High Word, bits 16-31
        ror eax,16
        mov word[edi+6],ax
    }  


///END:  Setup the PIT ISR
///END:  Setup the PIT ISR
///END:  Setup the PIT ISR
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: Why does enabling INTs triple faults in 1 PC?

Post by Casm »

"Builds keyboard, PS/2 mouse and PIT vectors"

What about the real time clock? Until you are ready to install something more permanent you should have all the interrupts pointed at stub handlers (one for hardware interrupts, and one for all other interrupts), otherwise you are asking for trouble.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: Why does enabling INTs triple faults in 1 PC?

Post by ~ »

Yes, what you say solved the triple fault and now works well.

http://126.sytes.net/tmp/kern_int_err_0000_solved.zip

Here is the README.txt description:

Code: Select all

This is the corrected version. The solution
was to first clear all of the IDT to 0.

Then, set all existing interrupt vectors
to dummy ISRs.

Then, set the IRQ interrupt routines for both
the ones that acknowledge the PIC 1 (IRQs
0 to 7) and the ones that acknowledge
the PIC 2 and the PIC 1 (IRQs 8 to 15).

Then set the actual "working" IRQ interrupt routines.

The strange thing is that only the PIT (bit 1 of PIC 1) and the keyboard interrupts (bit 0 of PIC 1) are being enabled. The rest shouldn't interfere because they are disabled at the PIC level (BUT THEY DO APPARENTLY). And I don't think that the RTC IRQ (IRQ 8, managed by PIC 2) belongs to a Non Maskable Interrupt. Then it would still triple fault with interrupts disabled but with the NMI unmasked (bit 7 of port 70h cleared to 0). The PIC 2 is also disabled.

But then how can those ISRs be triggered or any other interrupt?

Code: Select all

$AL=11111100b;  //Enable keyboard and PIT IRQs
asm out 0x21,al; ;//PIC1, disables also the IRQ2 slave line response

$AL=11111111b;
asm out 0xA1,al; ;//PIC2
What do you think? Does it have to do with the APIC? I don't think so, but don't know. Without an answer to this, this same problem could cause other errors in the future for not properly understanding what happens.
Last edited by ~ on Fri Oct 22, 2010 10:06 pm, edited 1 time in total.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Why does enabling INTs triple faults in 1 PC?

Post by gerryg400 »

Maybe it's an interrupt pending from before you disable the PICs.
If a trainstation is where trains stop, what is a workstation ?
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: Why does enabling INTs triple faults in 1 PC?

Post by ~ »

gerryg400 wrote:Maybe it's an interrupt pending from before you disable the PICs.
Yes I suspected that, and also suspected that a pending interrupt for something like the mouse or the keyboard could lock them if the interrupt is acknowledged by a dummy ISR and the data ports aren't read. Maybe the case is that some devices keep signaling IRQs in some machines even after full PIC reprogramming, and somehow once signaled when still not reprogrammed, those particular PICs still pass the IRQs even after full reprogramming. It is still strange that disabled IRQs at the PIC can interfere like this. But basically I think I see how this situation shall be handled.

This must be the spurious IRQ that has been discussed somewhere, isn't it?
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: Why does enabling INTs triple faults in 1 PC?

Post by Casm »

Maybe it is a message signaled interrupt from a PCI Express card.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: Why does enabling INTs triple faults in 1 PC?

Post by ~ »

Casm wrote:Maybe it is a message signaled interrupt from a PCI Express card.
Could you please tell me what documents should I read to have a clear understanding of this?
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: Why does enabling INTs triple faults in 1 PC?

Post by Combuster »

MSIs are not quite backwards compatible and shouldn't occur until you have your own drivers to make them. (if you do get one, you'd get a random int or a GPF with the interrupt number). Instead, the devices configured by the bios are more likely to use a SMI instead, which are completely transparent to your OS (you'd only see lost clock cycles)

The spurious interrupt on the other hand, is an interrupt caused by ignoring other interrupts, and as such it can't be masked. If you have stub handlers for all IRQs, this can't cause you problems.

Bottom line: get exception handlers so you can actually see what is happening.
"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 ]
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: Why does enabling INTs triple faults in 1 PC?

Post by Casm »

~ wrote:
Casm wrote:Maybe it is a message signaled interrupt from a PCI Express card.
Could you please tell me what documents should I read to have a clear understanding of this?
Googling it doesn't seem to turn up anything useful, so the only account I know of is in a book called "PCI System Architecture" published by Mindshare. Whereas MSIs were optional in the PCI specification, they are the only way in which a PCI Express card can generate an interrupt.

The advantage of Messaged Signalled Interrupt is that you are not limited to the four interrupt lines available to PCI cards. Only having four lines inevitably means that interrupts have to be shared, and then the OS has to try and figure out where the interrupt came from. MSI's are generated by writing to a reserved are of memory, but instead of actually arriving in memory, the MSI is intercepted by the host-PCI bridge, which uses it to raise an interrupt on one of the processor's interrupt pins.
Post Reply