Page 2 of 3

Re: IDT problems

Posted: Thu Feb 09, 2012 11:14 am
by bellezzasolo
As for WIN32 it is for 32 bit and 64 bit, not compiler porting

Re: IDT problems

Posted: Thu Feb 09, 2012 11:31 am
by bluemoon
IIRC On VC the WIN32 is defined even for Win64 projects. I suggest to introduce your own directive and configure it in the project option.

Re: IDT problems

Posted: Tue Apr 19, 2016 2:40 am
by cklie97
I have a problem by setting up the IDT.
In fact every time I get an interrupt everything do just fine until the end of my handling routine.
When I call "iret", I get everytime an GPF. I loked for hours through the code, but I didn't found the problem.

"descriptor_tables.h"

Code: Select all

#ifndef _DESCRIPTOR_TABLES_H_
#define _DESCRIPTOR_TABLES_H_

struct cpu_state
{
    uint32_t   eax;
    uint32_t   ebx;
    uint32_t   ecx;
    uint32_t   edx;
    uint32_t   esi;
    uint32_t   edi;
    uint32_t   ebp;

    uint32_t   interrupt_number;
    uint32_t   error;

    uint32_t   eip;
    uint32_t   cs;
    uint32_t   eflags;
    uint32_t   esp;
    uint32_t   ss;
};

void init_gdt(void);
void init_idt(void);

void handle_interrupt(struct cpu_state *cpu);

#endif
gdt.c

Code: Select all

#include "descriptor_tables.h"

#define GDT_FLAG_DATASEG 0x02
#define GDT_FLAG_CODESEG 0x0a
#define GDT_FLAG_TSS     0x09

#define GDT_FLAG_SEGMENT 0x10
#define GDT_FLAG_RING0   0x00
#define GDT_FLAG_RING3   0x60
#define GDT_FLAG_PRESENT 0x80

#define GDT_FLAG_4K      0x800
#define GDT_FLAG_32_BIT  0x400

#define GDT_ENTRIES 5
static uint64_t gdt[GDT_ENTRIES];

static void gdt_set_entry(uint16_t i, uint32_t base, uint32_t limit, uint16_t flags);
static void load_gdt(void);

void init_gdt(void)
{
    gdt_set_entry(0, 0, 0, 0);
    gdt_set_entry(1, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_CODESEG | GDT_FLAG_4K | GDT_FLAG_PRESENT | GDT_FLAG_RING0);
    gdt_set_entry(2, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_DATASEG | GDT_FLAG_4K | GDT_FLAG_PRESENT | GDT_FLAG_RING0);
    gdt_set_entry(3, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_CODESEG | GDT_FLAG_4K | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
    gdt_set_entry(4, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_DATASEG | GDT_FLAG_4K | GDT_FLAG_PRESENT | GDT_FLAG_RING3);

    load_gdt();
}

static void gdt_set_entry(uint16_t i, uint32_t base, uint32_t limit, uint16_t flags)
{
    if(i>=GDT_ENTRIES)
        return;
    uint64_t *gdt_cp;
    gdt_cp = (gdt + i);
    *gdt_cp = limit & 0xffffLL;
    *gdt_cp |= (base & 0xffffffLL) << 16;
    *gdt_cp |= (flags & 0xffLL) << 40;
    *gdt_cp |= ((limit & 0xf0000LL) >> 16) << 48;
    *gdt_cp |= ((flags & 0xf00LL) >> 8) << 52;
    *gdt_cp |= ((base & 0xff000000LL) >> 24) << 56;
}


static void load_gdt(void)
{
    struct
    {
        uint16_t limit;
        void *pointer;
    }
    __attribute__((packed)) gdtp =
    {
        .limit = GDT_ENTRIES * 8 - 1,
        .pointer = gdt,
    };

    // GDT neu laden
    asm volatile("lgdt %0" : : "m" (gdtp));

    // Segmentregister neu laden, damit die neuen GDT-Eintraege auch wirklich
    // benutzt werden
    asm volatile(
        "mov $0x10, %ax;"
        "mov %ax, %ds;"
        "mov %ax, %es;"
        "mov %ax, %ss;"
        "ljmp $0x8, $.1;"
        ".1:"
    );
}
idt.c

Code: Select all

#include "descriptor_tables.h"

extern void intr_stub_0(void);
extern void intr_stub_1(void);
extern void intr_stub_2(void);
extern void intr_stub_3(void);
extern void intr_stub_4(void);
extern void intr_stub_5(void);
extern void intr_stub_6(void);
extern void intr_stub_7(void);
extern void intr_stub_8(void);
extern void intr_stub_9(void);
extern void intr_stub_10(void);
extern void intr_stub_11(void);
extern void intr_stub_12(void);
extern void intr_stub_13(void);
extern void intr_stub_14(void);
extern void intr_stub_15(void);
extern void intr_stub_16(void);
extern void intr_stub_17(void);
extern void intr_stub_18(void);

extern void intr_stub_32(void);
extern void intr_stub_33(void);

extern void intr_stub_48(void);

#define IDT_FLAG_PRESENT 0x80
#define IDT_FLAG_RING0 0x00
#define IDT_FLAG_RING3 0x60
#define IDT_FLAG_32BIT 0x8
#define IDT_FLAG_INTERRUPT_GATE 0x6
#define IDT_FLAG_TRAP_GATE 0x7
#define IDT_FLAG_TASK_GATE 0x5

#define IDT_SELECTOR_RING0 0x0
#define IDT_SELECTOR_RING3 0x3
#define IDT_SELECTOR_GDT 0x0
#define IDT_SELECTOR_LDT 0x4

#define IDT_ENTRIES 256
static uint64_t idt[IDT_ENTRIES];

#define PIC_IRQ0 0x20

static uint16_t build_selector(uint8_t flags, uint16_t table_entry);
static void idt_set_entry(uint16_t i, void (*function)(), uint8_t flags, uint16_t selector);
static void load_idt(void);
static inline void outb(uint16_t port, uint8_t data);
static void init_pic(void);
static void pic_send_eoi(uint8_t irq);

void init_idt(void)
{
    init_pic();

    idt_set_entry(0, intr_stub_0, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(1, intr_stub_1, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(2, intr_stub_2, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(3, intr_stub_3, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(4, intr_stub_4, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(5, intr_stub_5, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(6, intr_stub_6, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(7, intr_stub_7, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(8, intr_stub_8, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(9, intr_stub_9, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(10, intr_stub_10, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(11, intr_stub_11, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(12, intr_stub_12, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(13, intr_stub_13, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(14, intr_stub_14, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(15, intr_stub_15, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(16, intr_stub_16, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(17, intr_stub_17, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(18, intr_stub_18, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));

    idt_set_entry(32, intr_stub_32, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
    idt_set_entry(33, intr_stub_33, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING0 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));

    idt_set_entry(48, intr_stub_48, IDT_FLAG_INTERRUPT_GATE | IDT_FLAG_RING3 | IDT_FLAG_PRESENT, build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));

    load_idt();
    asm volatile("sti");
}

void handle_interrupt(struct cpu_state *cpu)
{
    if(!isBeginOfLine())
        kprintf("\n\r");
    if (cpu->interrupt_number <= 0x1f)
    {
        kprintf("exception %d, kernel stopped!\n\r", cpu->interrupt_number);
        // TODO Care about the exception
        while(1)
        {
            asm volatile("cli; hlt");
            // Prozessor anhalten
        }
    }
    else
        if (cpu->interrupt_number >= PIC_IRQ0 && cpu->interrupt_number <= PIC_IRQ0 + 0xf)
        {
            kprintf("IRQ %d.\n\r", cpu->interrupt_number - PIC_IRQ0);
            pic_send_eoi(cpu->interrupt_number - PIC_IRQ0);
        }
        else
        {
            kprintf("Unbekannter Interrupt oder Syscall. Nummer: %d\n\rKernel angehalten!\n\r", cpu->interrupt_number);
            while(1)
            {
                // Prozessor anhalten
                asm volatile("cli; hlt");
            }
        }
}

static uint16_t build_selector(uint8_t flags, uint16_t table_entry)
{
    uint16_t selector;
    selector = (flags & 0x7LL);
    selector |= ((table_entry & 0x1fffLL) << 3);
    return selector;
}

static void idt_set_entry(uint16_t i, void (*function)(void), uint8_t flags, uint16_t selector)
{
    if (i>=IDT_ENTRIES)
        return;
    uint32_t handler = (uint32_t) function;
    uint64_t *idt_cp;
    idt_cp = (idt + i);
    *idt_cp = (handler & 0xffffLL);
    *idt_cp |= ((selector & 0xffffLL) << 16);
    *idt_cp |= ((uint64_t)(flags & 0xffLL) << 40);
    *idt_cp |= (((uint64_t)(handler & 0xffff0000LL) >> 16) << 48);
}

static void load_idt(void)
{
    struct
    {
        uint16_t limit;
        void *pointer;
    }
    __attribute__((packed)) idtp =
    {
        .limit = IDT_ENTRIES * 8 - 1,
        .pointer = idt,
    };
    asm volatile("lidt %0" : : "m" (idtp));
}

static inline void outb(uint16_t port, uint8_t data)
{
    asm volatile ("outb %0, %1" : : "a" (data), "Nd" (port));
}

#define PIC_MASTER_COMMAND 0x20
#define PIC_MASTER_DATA 0x21
#define PIC_MASTER_IMR 0x21
#define PIC_SLAVE_COMMAND 0xA0
#define PIC_SLAVE_DATA 0xA1
#define PIC_SLAVE_IMR 0xA1
#define END_OF_INTERRUPT 0x20

static void init_pic(void)
{
    outb(PIC_MASTER_COMMAND, 0x11);
    outb(PIC_SLAVE_COMMAND, 0x11);
    outb(PIC_MASTER_DATA, PIC_IRQ0);
    outb(PIC_SLAVE_DATA, PIC_IRQ0 + 0x8);
    outb(PIC_MASTER_DATA, 0x04);
    outb(PIC_SLAVE_DATA, 0x02);
    outb(PIC_MASTER_DATA, 0x01);
    outb(PIC_SLAVE_DATA, 0x01);

    outb(PIC_MASTER_IMR, 0x0);
    outb(PIC_SLAVE_IMR, 0x0);
}

static void pic_send_eoi(uint8_t irq)
{
    if (irq >= 0x8)
    {
        outb(PIC_SLAVE_COMMAND, END_OF_INTERRUPT);
    }
    outb(PIC_MASTER_COMMAND, END_OF_INTERRUPT);
}
int_stub.S

Code: Select all

.macro intr_stub nr
.global intr_stub_\nr
intr_stub_\nr:
    pushl $0
    pushl $\nr
    jmp intr_common_handler
.endm

.macro intr_stub_error_code nr
.global intr_stub_\nr
intr_stub_\nr:
    pushl $\nr
    jmp intr_common_handler
.endm

// Exceptions
intr_stub 0
intr_stub 1
intr_stub 2
intr_stub 3
intr_stub 4
intr_stub 5
intr_stub 6
intr_stub 7
intr_stub_error_code 8
intr_stub 9
intr_stub_error_code 10
intr_stub_error_code 11
intr_stub_error_code 12
intr_stub_error_code 13
intr_stub_error_code 14
intr_stub 15
intr_stub 16
intr_stub_error_code 17
intr_stub 18

// IRQs
intr_stub 32
intr_stub 33
// etc. until 47

// Syscall
intr_stub 48

.extern handle_interrupt
intr_common_handler:
    push %ebp
    push %edi
    push %esi
    push %edx
    push %ecx
    push %ebx
    push %eax

    push %esp
    call handle_interrupt
    add $4, %esp

    pop %eax
    pop %ebx
    pop %ecx
    pop %edx
    pop %esi
    pop %edi
    pop %ebp

    add $8, %esp
    iret

Re: IDT problems

Posted: Tue Apr 19, 2016 3:34 am
by sebihepp

Code: Select all

static void load_idt(void)
{
    struct
    {
        uint16_t limit;
        void *pointer;
    }
    __attribute__((packed)) idtp =
    {
        .limit = IDT_ENTRIES * 8 - 1,
        .pointer = idt,
    };
    asm volatile("lidt %0" : : "m" (idtp));
}
You define the idtp inside the function so it will be on the stack. But the stack will be overwritten by other functions and so your idtp contains random data.

Code: Select all

#define IDT_SELECTOR_GDT 0x0
(...)build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
And here you set the GDT Selector to the NULL Selector, instead of the code ring 0 selector.

Re: IDT problems

Posted: Tue Apr 19, 2016 7:55 am
by cklie97
sebihepp wrote:

Code: Select all

#define IDT_SELECTOR_GDT 0x0
(...)build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
And here you set the GDT Selector to the NULL Selector, instead of the code ring 0 selector.
No. The NULL Selector would be another instruction.

Code: Select all

build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 0));
sebihepp wrote: You define the idtp inside the function so it will be on the stack. But the stack will be overwritten by other functions and so your idtp contains random data.
Thanks for this hint, but after I rearranged my code, the problem still appears.

idt.c

Code: Select all

(...)
struct idt_ptr
{
    uint16_t limit;
    void *pointer;
} __attribute__((packed));

struct idt_ptr idtp;
(...)
static void load_idt(void)
{
    idtp.limit = IDT_ENTRIES * 8 - 1;
    idtp.pointer = idt;
    asm volatile("lidt %0" : : "m" (idtp));
}
(...)

Re: IDT problems

Posted: Tue Apr 19, 2016 8:56 am
by Techel
After using lidt you may inspect the idt using 'info gdt' in bochs debugger. Place a 'xchg bx, bx' after it and enable breakpoints in your bochs config.

Re: IDT problems

Posted: Tue Apr 19, 2016 10:17 am
by sebihepp
Does it really Triple Fault when you iret? Or does it Triple Fault when the interrupt gets fired?
If it is really the first thing, then you could test, if this happens everytime or only when PIC fires an interrupt? Or only when Syscall interrupt? etc.
The Stack would be also very helpful, so we can see, if everything is right there, especially with the values in cpu_state.

Re: IDT problems

Posted: Tue Apr 19, 2016 11:09 am
by Techel
sebihepp wrote:so we can see, if everything is right there.
I recommend getting a debugger and inspect your code. Finding needles in a haystack is a thing you should learn, especially when deving an os.

Re: IDT problems

Posted: Tue Apr 19, 2016 1:17 pm
by cklie97
Techel wrote:enable breakpoints in your bochs config.
I'm not using bochs. What is it?
Everything I use is gcc, make, nano and qemu.
sebihepp wrote:Does it really Triple Fault when you iret? Or does it Triple Fault when the interrupt gets fired?
No after "iret" there is a General Protection Fault
sebihepp wrote:f this happens everytime or only when PIC fires an interrupt? Or only when Syscall interrupt?
It happens in both cases.

Re: IDT problems

Posted: Tue Apr 19, 2016 2:10 pm
by iansjack
cklie97 wrote: Everything I use is gcc, make, nano and qemu.
Then use gdb to debug it.

Re: IDT problems

Posted: Sat Apr 23, 2016 2:52 am
by cklie97
For the debugging I modified the int_stub.S, so I can set breakpoints.

int_stub.S

Code: Select all

.macro intr_stub nr
.global intr_stub_\nr
intr_stub_\nr:
begin\nr:
    pushl $0
    pushl $\nr
    jmp intr_common_handler
.endm

(...)
.extern handle_interrupt
intr_common_handler:
    // CPU-Zustand sichern
    push %ebp
    push %edi
    push %esi
    push %edx
    push %ecx
    push %ebx
    push %eax

    // Handler aufrufen
    push %esp
    call handle_interrupt
    pop %esp

    // CPU-Zustand wiederherstellen
    pop %eax
    pop %ebx
    pop %ecx
    pop %edx
    pop %esi
    pop %edi
    pop %ebp

    // Fehlercode und Interruptnummer vom Stack nehmen
    add $8, %esp
    // Ruecksprung zum unterbrochenen Code
end:
    iret
The content of the registers at "begin32"(IRQ0)
where

Code: Select all

eax		0xb8746	 755526
ecx		0xa		  10
edx		0x0		  0
ebx		0x9500	  38144
esp		0x10676a	0x10676a
ebp		0x106788	0x106788
esi		0x0		  0
edi		0x108000	1081344
eip		0x100070	0x100070 <intr_stub_32>
eflags   0x97		 [ CF PF AF SF ]
cs		 0x8		  8
ss		 0x10		 16
ds		 0x10		 16
es		 0x10		 16
fs		 0x10		 16
gs		 0x10		 16
while the content of the registers at "end" where

Code: Select all

eax		0xb8746	 755526
ecx		0xa		  10
edx		0x0		  0
ebx		0x9500	  38144
esp		0x10676a	0x10676a
ebp		0x106788	0x106788
esi		0x0		  0
edi		0x108000	1081344
eip		0x10009a	0x10009a <end>
eflags   0x6		  [ PF ]
cs		 0x8		  8
ss		 0x10		 16
ds		 0x10		 16
es		 0x10		 16
fs		 0x10		 16
gs		 0x10		 16
and the Stack's content is

Code: Select all

0x10676a:	0x000810b9		0x67a70297		0x00000010		0x87e70000
0x10677a:	0x8747000b		0x007c000b		0x8f000008		0x67b8000b
0x10678a:	0x10080010		0x00200010		0x00000000		0xffff0000
0x10679a:	0x000a0000		0x0ce60000		0x33300000		0x31440034
I don't get what the reason for the appearance of the General Protection Fault is.

Re: IDT problems

Posted: Sat Apr 23, 2016 3:38 am
by Octocontrabass
cklie97 wrote:

Code: Select all

    pop %esp
That looks like a very nasty bug waiting to happen.
cklie97 wrote:and the Stack's content is
The stack contents look like nonsense to me. It's also not aligned correctly. Try setting the breakpoint somewhere earlier and see if you can find where the stack is getting corrupted.

Re: IDT problems

Posted: Sat Apr 23, 2016 4:52 am
by cklie97
Octocontrabass wrote: It's also not aligned correctly.
What do you mean?

Re: IDT problems

Posted: Sat Apr 23, 2016 5:38 am
by Octocontrabass
ESP points to an address that is not a multiple of 4. Here's more information about alignment.

Re: IDT problems

Posted: Sat Apr 23, 2016 7:43 am
by cklie97
Now I stepped through the code.
Until the interrupt $sp%4==0.

Code: Select all

(gdb) print $sp
$5 = (void *) 0x1067f0
(gdb) step
36	            asm volatile("int $0x20");
(gdb) print $sp
$6 = (void *) 0x1067f0
But then, something mystery happens.

Code: Select all

(gdb) step
Breakpoint 2, 0x00100070 in intr_stub_32 ()
(gdb) print $sp
$7 = (void *) 0x1067ea