IDT problems
- bellezzasolo
- Member
- Posts: 110
- Joined: Sun Feb 20, 2011 2:01 pm
Re: IDT problems
As for WIN32 it is for 32 bit and 64 bit, not compiler porting
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS
https://github.com/ChaiSoft/ChaiOS
Re: IDT problems
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
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"
gdt.c
idt.c
int_stub.S
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
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
-
- Member
- Posts: 190
- Joined: Tue Aug 26, 2008 11:24 am
- GitHub: https://github.com/sebihepp
Re: IDT problems
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));
Re: IDT problems
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.
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
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.
-
- Member
- Posts: 190
- Joined: Tue Aug 26, 2008 11:24 am
- GitHub: https://github.com/sebihepp
Re: IDT problems
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.
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
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.
Re: IDT problems
I'm not using bochs. What is it?Techel wrote:enable breakpoints in your bochs config.
Everything I use is gcc, make, nano and qemu.
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?
Last edited by cklie97 on Tue Apr 19, 2016 1:25 pm, edited 1 time in total.
Re: IDT problems
Then use gdb to debug it.cklie97 wrote: Everything I use is gcc, make, nano and qemu.
Re: IDT problems
For the debugging I modified the int_stub.S, so I can set breakpoints.
int_stub.S
The content of the registers at "begin32"(IRQ0)
where
while the content of the registers at "end" where
and the Stack's content is
I don't get what the reason for the appearance of the General Protection Fault is.
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
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
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
-
- Member
- Posts: 5586
- Joined: Mon Mar 25, 2013 7:01 pm
Re: IDT problems
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
Re: IDT problems
What do you mean?Octocontrabass wrote: It's also not aligned correctly.
-
- Member
- Posts: 5586
- Joined: Mon Mar 25, 2013 7:01 pm
Re: IDT problems
ESP points to an address that is not a multiple of 4. Here's more information about alignment.
Re: IDT problems
Now I stepped through the code.
Until the interrupt $sp%4==0.
But then, something mystery happens.
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
Code: Select all
(gdb) step
Breakpoint 2, 0x00100070 in intr_stub_32 ()
(gdb) print $sp
$7 = (void *) 0x1067ea