Re: IDT problems
Posted: Thu Feb 09, 2012 11:14 am
As for WIN32 it is for 32 bit and 64 bit, not compiler porting
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
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:"
);
}
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);
}
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
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));
}
Code: Select all
#define IDT_SELECTOR_GDT 0x0
(...)build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
No. The NULL Selector would be another instruction.sebihepp wrote:And here you set the GDT Selector to the NULL Selector, instead of the code ring 0 selector.Code: Select all
#define IDT_SELECTOR_GDT 0x0 (...)build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 1));
Code: Select all
build_selector(IDT_SELECTOR_RING0 | IDT_SELECTOR_GDT, 0));
Thanks for this hint, but after I rearranged my code, the problem still appears.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.
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));
}
(...)
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.sebihepp wrote:so we can see, if everything is right there.
I'm not using bochs. What is it?Techel wrote:enable breakpoints in your bochs config.
No after "iret" there is a General Protection Faultsebihepp wrote:Does it really Triple Fault when you iret? Or does it Triple Fault when the interrupt gets fired?
It happens in both cases.sebihepp wrote:f this happens everytime or only when PIC fires an interrupt? Or only when Syscall interrupt?
Then use gdb to debug it.cklie97 wrote: Everything I use is gcc, make, nano and qemu.
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
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
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
Code: Select all
0x10676a: 0x000810b9 0x67a70297 0x00000010 0x87e70000
0x10677a: 0x8747000b 0x007c000b 0x8f000008 0x67b8000b
0x10678a: 0x10080010 0x00200010 0x00000000 0xffff0000
0x10679a: 0x000a0000 0x0ce60000 0x33300000 0x31440034
That looks like a very nasty bug waiting to happen.cklie97 wrote:Code: Select all
pop %esp
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.cklie97 wrote:and the Stack's content is
What do you mean?Octocontrabass wrote: It's also not aligned correctly.
Code: Select all
(gdb) print $sp
$5 = (void *) 0x1067f0
(gdb) step
36 asm volatile("int $0x20");
(gdb) print $sp
$6 = (void *) 0x1067f0
Code: Select all
(gdb) step
Breakpoint 2, 0x00100070 in intr_stub_32 ()
(gdb) print $sp
$7 = (void *) 0x1067ea