Page 1 of 1

Kernel reboot after keybord IRQ1

Posted: Sat May 17, 2008 11:40 pm
by Sill
Hi!

After many hours of work and many drops of sudor... i stick.

I have a bootloader loads kernel from raw-data floppy, unblock A20, setts primitives stack and GDT and jump to C coded kernel.

There I set new GDT and IDT tables, reroute hardware ISR (in source generated by nasm macor) for IRQs, set IRQ1 and enable it (and disabling IRQ0 and IRQs 2-15).
After that I 'sti' and for( ; ; ) ;

To this point all seems to be OK.

But when I press any key, the kernel is rebooting, with bochs log listed below.

I try all things i could invent or find over the Inet.
I googled all Internet, i think (-;

What am I doing wrong??

If someone could look up my code it's all in attachment. It is prepared to compile on FreeBSD by typing 'sh make.sh'.

I just can’t look anymore at Vi with asm/c mash (-;
Help! (-:


The Bochs reboot log:

Code: Select all

00091058500i[CPU0 ] CPU is in protected mode (active)
00091058500i[CPU0 ] CS.d_b = 32 bit
00091058500i[CPU0 ] SS.d_b = 32 bit
00091058500i[CPU0 ] EFER   = 0x00000000
00091058500i[CPU0 ] | RAX=0000000000000000  RBX=0000000000000010
00091058500i[CPU0 ] | RCX=0000000000000008  RDX=0000000000000007
00091058500i[CPU0 ] | RSP=0000000000007fd0  RBP=0000000000000000
00091058500i[CPU0 ] | RSI=00000000ffff88ca  RDI=0000000000080001
00091058500i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00091058500i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00091058500i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00091058500i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00091058500i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf zf af pf cf
00091058500i[CPU0 ] | SEG selector     base    limit G D
00091058500i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00091058500i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00091058500i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00091058500i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00091058500i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00091058500i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00091058500i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00091058500i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00091058500i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00091058500i[CPU0 ] | RIP=0000000000011130 (0000000000011130)
00091058500i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000
00091058500i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00091058500i[CPU0 ] >> jmp .+0xfffffffe (0x00011130) : EBFE
00091058500e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00091058500i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00091058500i[CPU0 ] cpu software reset

Posted: Sun May 18, 2008 4:47 pm
by Combuster
What are the messages bochs prints before giving the CPU dump?

Posted: Sun May 18, 2008 8:02 pm
by edfed
it looks like a double general protection faillure.

something is not correctlly done in the IRQ and IDT assignements.

Posted: Sun May 18, 2008 10:17 pm
by Sill
@Combuster: Nothing. Only somthing like "booting form 7C00h";
If I don't load IDT, there is message about this. But actually, there is nothing.


@edfed:
(sorry for big parts of code but i have not idea how to avid this)

In entry.asm (the 'header' linked to the kernel.c) i have:

Code: Select all

cli
lgdt [gdt_descr]
lidt [idt_descr]
jmp .1
.1:
...
call reroute_irqs
...
[EXTERN __main]
call __main
...
idt_descr:
 dw 256*8-1
 dd idt
[GLOBAL idt]
idt:
 times 256 dd 0,0
...
 [GLOBAL _irq1]
 _irq1:
 (ISR code, I`ve even tried hlt for test purposes)
...
Then in C code I set IDT table entry by code like this:

Code: Select all

#define __byte(x,y)     (((unsigned char *)&(y))[x])
#define cached_21       (__byte(0,cached_irq_mask))
#define cached_A1       (__byte(1,cached_irq_mask))

static unsigned int cached_irq_mask = 0xffff;

typedef struct {
        unsigned short offset_0;
        unsigned short selector;
        unsigned short type;
        unsigned short offset_16;
} gate_desc[256];

extern gate_desc idt;

void set_gate(int n, unsigned long irq_handle, unsigned short type) {
        idt[n].offset_0  = irq_handle;
        idt[n].selector  = 0x08;
        idt[n].type      = type;
        idt[n].offset_16 = (irq_handle >> 16);
}
void disable_irq(unsigned int irq) {
        unsigned int mask = (1 << irq);
        cached_irq_mask |= mask;
        if (irq & 8) {
                outb(cached_A1,0xA1);
        } else {
                outb(cached_21,0x21);
        }
}

void enable_irq(unsigned int irq) {
        unsigned int mask = ~(1 << irq);
        cached_irq_mask &= mask;
        if (irq & 8) {
                outb(cached_A1,0xA1);
        } else {
                outb(cached_21,0x21);
        }
}

// entry point of kernel
void __main() {
        int i = 0;
        for( i = 0; i < 16; i ++ ) {
                disable_irq(i);
        }
        enable_irq(1);
        set_gate(0x21, (unsigned long)&_irq1, 0x8E00);
        sti();
        for( ; ; );
}
What can be wrong?
I really have no idea...

Posted: Sun May 18, 2008 11:07 pm
by edfed
| troll just below :evil:
V ](*,)

Posted: Mon May 19, 2008 1:37 am
by JamesM
edfed wrote:i invite you to not code in C.

asm is enough to make what you want.
seting the IDT in C is hazardous when you know you can set it in asm.
I invite you not to code in assembly.

C is enough to make what you want.
doing anything in assembly is hazardous when you know you can set it in C.


The moral of the story? He's programming in C, so give him an answer in C. Just because you cannot program well enough in C to do what he wants, does not mean he or anyone else can't.

EDIT:

@OP: I notice a couple of things wrong - firstly you don't reload the code segment after your lgdt.

Code: Select all

cli
lgdt [gdt_descr]
lidt [idt_descr]
jmp .1
.1: 
Should be

Code: Select all

cli
lgdt [gdt_descr]
lidt [idt_descr]
jmp 0x08:.1
.1: 
Note the segment selector - this is a FAR jump, and reloads CS.

Also, I notice that you're not masking your base offsets properly:

Code: Select all

void set_gate(int n, unsigned long irq_handle, unsigned short type) {
        idt[n].offset_0  = irq_handle;
        idt[n].selector  = 0x08;
        idt[n].type      = type;
        idt[n].offset_16 = (irq_handle >> 16);
} 
Should be

Code: Select all

void set_gate(int n, unsigned long irq_handle, unsigned short type) {
        idt[n].offset_0  = irq_handle&0xFFFF;
        idt[n].selector  = 0x08;
        idt[n].type      = type;
        idt[n].offset_16 = (irq_handle >> 16) & 0xFFFF;
} 
Now, you'd hope that the compiler would do those masks for you, but I've run into problems before where some versions of GCC didn't and funky things started happening because of it!

HTH,

James

Posted: Mon May 19, 2008 4:23 am
by Sill
@JamesM:
Well. There was problem with GTD in fact. I`ve fixed it and it is not the case of rebooting.

I was mistrustful to the structure, becous it gave strange outputs , and tried (in set_gate) something like that:

Code: Select all

        unsigned short* idtn;
        idtn = &idt[n];
        idtn[0] = irq_handle & 0xFFFF;
        idtn[1] = 0x08;
        idtn[2] = type;
        idtn[3] = (irq_handle >> 16) & 0xFFFF;
... and still the same ...

Posted: Mon May 19, 2008 4:30 am
by AJ
Hi,

Code: Select all

typedef struct {
   unsigned short offset_0;
   unsigned short selector;
   unsigned short type;
   unsigned short offset_16;
} gate_desc[256];
I suggest you declare this with __attribute__((packed)) (before the gate_desc[256]). This will prevent GCC padding the fields to 32 bits each.

Cheers,
Adam