IDT invalid entry in long mode
Posted: Mon Sep 03, 2018 6:48 am
I am currently trying to get the interrupt handlers working in the kernel after I successfully entered long mode. However there are some errors when trying to trigger an interrupt via .
The current setup looks like this:
with __KERNEL_CS being 0x8 (GDT_SEGMENT_CS = 1, __KERNEL_CS = GDT_SEGMENT_CS * 8 ). When setting a breakpoint right before the int 0x0 instruction, the bochs GUI debugger shows the addresses of all __isrXX functions accordingly. But the problem is when the interrupt is triggered:
I added the Type, Valid and Segment output to the bochs code, which is simply printing the stats of the descriptor being checked:
Apparently the gate_descriptor.segment value is 1, which shouldn't be:
So apparently my code uses a data/code segment in the storage segment bit of the type_attr byte:
Even though the storage segment bit (bit 4 of type_attr, S) is set to 0, bochs seems to find a set bit at this place. Also, because my additional output says that the Type member of the bochs descriptor is 0xf, this also means that it is not using an interrupt gate but rather a trap gate. This would evaluate to a type_attr of 0x9f, but I'm setting the type_attr with 0x8e.
I am at loss of ideas how to move on here, because I'm very sure I checked the values in the type_attr member of my struct idt_entry above (0x8E).
Code: Select all
__asm__ volatile("int $0x0");
The current setup looks like this:
Code: Select all
// interrupt.h:
struct idt_entry {
uint16_t offset_low;
uint16_t selector;
uint8_t __r0;
uint8_t type;
uint16_t offset_middle;
uint32_t offset_high;
uint32_t __r1;
} __attribute((packed));
// isr.c:
void isr_init(void)
{
idt_set_gate(0, (uint64_t)__isr0, __KERNEL_CS, 0x8e);
idt_set_gate(1, (uint64_t)__isr1, __KERNEL_CS, 0x8e);
idt_set_gate(2, (uint64_t)__isr2, __KERNEL_CS, 0x8e);
idt_set_gate(3, (uint64_t)__isr3, __KERNEL_CS, 0x8e);
idt_set_gate(4, (uint64_t)__isr4, __KERNEL_CS, 0x8e);
idt_set_gate(5, (uint64_t)__isr5, __KERNEL_CS, 0x8e);
idt_set_gate(6, (uint64_t)__isr6, __KERNEL_CS, 0x8e);
idt_set_gate(7, (uint64_t)__isr7, __KERNEL_CS, 0x8e);
idt_set_gate(8, (uint64_t)__isr8, __KERNEL_CS, 0x8e);
idt_set_gate(9, (uint64_t)__isr9, __KERNEL_CS, 0x8e);
idt_set_gate(10, (uint64_t)__isr10, __KERNEL_CS, 0x8e);
idt_set_gate(11, (uint64_t)__isr11, __KERNEL_CS, 0x8e);
idt_set_gate(12, (uint64_t)__isr12, __KERNEL_CS, 0x8e);
idt_set_gate(13, (uint64_t)__isr13, __KERNEL_CS, 0x8e);
idt_set_gate(14, (uint64_t)__isr14, __KERNEL_CS, 0x8e);
idt_set_gate(15, (uint64_t)__isr15, __KERNEL_CS, 0x8e);
idt_set_gate(16, (uint64_t)__isr16, __KERNEL_CS, 0x8e);
idt_set_gate(17, (uint64_t)__isr17, __KERNEL_CS, 0x8e);
idt_set_gate(18, (uint64_t)__isr18, __KERNEL_CS, 0x8e);
idt_set_gate(19, (uint64_t)__isr19, __KERNEL_CS, 0x8e);
idt_set_gate(20, (uint64_t)__isr20, __KERNEL_CS, 0x8e);
}
- - When int 0x0 is triggered, the instruction pointer moves to the function located at the first entry (index 0) of the IDT. No problems so far.
- When stepping to the next instruction, the instruction pointer however moves to the next interrupt service routine, which is the page fault handler. In there, the instruction triggers itself multiple consecutive page fault, as the instruction pointer seems to only complete the cli instruction at the beginning of the isr stub. This goes on until I seemed to enter real mode again.
Code: Select all
Dump gate:
08894662103e[CPU0 ] Type : f
08894662103e[CPU0 ] Valid: 1
08894662103e[CPU0 ] Segm : 1
08894662103e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
08894662105e[CPU0 ] Dump gate:
08894662105e[CPU0 ] Type : f
08894662105e[CPU0 ] Valid: 1
08894662105e[CPU0 ] Segm : 1
08894662105e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
08894662107e[CPU0 ] Dump gate:
08894662107e[CPU0 ] Type : f
08894662107e[CPU0 ] Valid: 1
08894662107e[CPU0 ] Segm : 1
08894662107e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
08894662107e[CPU0 ] Dump gate:
08894662107e[CPU0 ] Type : f
08894662107e[CPU0 ] Valid: 1
08894662107e[CPU0 ] Segm : 1
08894662107e[CPU0 ] interrupt(long mode): gate descriptor is not valid sys seg
Code: Select all
// bochs/cpu/exception.cc:64
if ((gate_descriptor.valid==0) || gate_descriptor.segment)
{
BX_ERROR(("Dump gate:"));
BX_ERROR(("Type : %x", gate_descriptor.type));
BX_ERROR(("Valid: %x", gate_descriptor.valid ? 1 : 0));
BX_ERROR(("Segm : %x", gate_descriptor.segment ? 1 : 0));
BX_ERROR(("interrupt(long mode): gate descriptor is not valid sys seg"));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
Code: Select all
// bochs/cpu/descriptor.h:typedef struct bx_descriptor_t
// ...
bx_bool segment; /* 0 = system/gate, 1 = data/code segment */
// ...
Code: Select all
// From https://wiki.osdev.org/Interrupt_Descriptor_Table#Structure_IA-32
7 0
+---+---+---+---+---+---+---+---+
| P | DPL | S | GateType |
+---+---+---+---+---+---+---+---+
1 0 0 0 1 1 1 0 --> 0x8E
I am at loss of ideas how to move on here, because I'm very sure I checked the values in the type_attr member of my struct idt_entry above (0x8E).