中断描述符 Table 门
Interrupt Descriptor Table Gate
我编写了这段代码来创建一个示例 IDT 并将其加载到正确的寄存器中。我已经检查了英特尔系统编程指南的正确结构,但我无法让中断工作。在 Bochs 中 运行 内核代码,并触发中断(使用 __asm__ ("int ");
我得到一个日志说:
00135687199e[CPU0 ] interrupt(): gate not present
00135687199e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0b)
00135687199e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
当然这会导致 CPU 重置,因为中断未处理。要加载 IDT,我使用以下内容:
extern void _lidt(_IDT_PTR* idtPtr); //C code side
//Assembly
.global _lidt
_lidt:
push %ebp
mov %esp,%ebp
mov 8(%esp), %eax
lidt (%eax)
leave
ret
这是这样称呼的:
static struct __InteruptDescriptorTableEntry InteruptDescriptorTable[NUM_IDT_ENTRIES];
void zeroIDT()
{
unsigned i;
for(i=0;i<NUM_IDT_ENTRIES-1;++i)
{
IDTEntry nullIDTEntry = fillIDTEntry(0,0,0);
registerInterupt(nullIDTEntry, i);
}
}
void registerInterupt(const IDTEntry entry, const unsigned intNo)
{
if(intNo < NUM_IDT_ENTRIES)
InteruptDescriptorTable[intNo] = entry;
else
{
__asm__("mov [=13=]xDEADC0DE, %eax");
__asm__("hlt");
}
}
#define LOW_FUN_ADDR(fun) ( (uint32_t)fun & 0xFFFF )
#define UP_FUN_ADDR(fun) ( (uint32_t)fun >> 16) & 0xFFFF
IDTEntry fillIDTEntry(uint32_t intHandler,
uint16_t selector,
uint8_t type_attr)
{ IDTEntry newEntry;
newEntry.offset_low = LOW_FUN_ADDR(intHandler);
newEntry.selector = selector;
newEntry.zero = 0;
newEntry.type_attr = type_attr;
newEntry.offset_up = UP_FUN_ADDR(intHandler);
return newEntry;
}
extern void _lidt(_IDT_PTR* idtPtr);
void loadIDT()
{
zeroIDT();
_IDT_PTR idtPtr;
idtPtr.idtSize = sizeof(struct __InteruptDescriptorTableEntry)*256 - 1;
idtPtr.idtBaseAddr = (uint32_t) &InteruptDescriptorTable;
IDTEntry printOnScreenInt = fillIDTEntry((uint32_t)interupt_pritnOnScreen, 0x18, 0xe);
registerInterupt(printOnScreenInt, 32);
_lidt(&idtPtr);
}
数据结构:
struct __InteruptDescriptorTableEntry
{
uint16_t offset_low;
uint16_t selector;
uint8_t zero;
uint8_t type_attr;
uint16_t offset_up;
} __attribute__((packed));
typedef struct __InteruptDescriptorTableEntry IDTEntry;
struct _ITD_PTR
{
uint16_t idtSize;
uint32_t idtBaseAddr;
} __attribute__((packed));
typedef struct _ITD_PTR _IDT_PTR;
以及示例中断例程:
.global interupt_pritnOnScreen
interupt_pritnOnScreen:
mov [=15=]xf00ff00f, %eax
hlt
iret
我检查了IDT寄存器是否加载了ptr到quemu中的IDT,是的。我在 GRUB 启动后立即加载 IDT(设置了保护模式并且 GDT 选择器跨越整个 RAM)。我认为我错误地注册了中断例程,但我可以指出代码中的任何错误。
日志清楚地写着 not present
。您忘记设置 IDT 条目中的当前位。您应该使用 type_attr
of 0x8E
.
我编写了这段代码来创建一个示例 IDT 并将其加载到正确的寄存器中。我已经检查了英特尔系统编程指南的正确结构,但我无法让中断工作。在 Bochs 中 运行 内核代码,并触发中断(使用 __asm__ ("int ");
我得到一个日志说:
00135687199e[CPU0 ] interrupt(): gate not present
00135687199e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0b)
00135687199e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
当然这会导致 CPU 重置,因为中断未处理。要加载 IDT,我使用以下内容:
extern void _lidt(_IDT_PTR* idtPtr); //C code side
//Assembly
.global _lidt
_lidt:
push %ebp
mov %esp,%ebp
mov 8(%esp), %eax
lidt (%eax)
leave
ret
这是这样称呼的:
static struct __InteruptDescriptorTableEntry InteruptDescriptorTable[NUM_IDT_ENTRIES];
void zeroIDT()
{
unsigned i;
for(i=0;i<NUM_IDT_ENTRIES-1;++i)
{
IDTEntry nullIDTEntry = fillIDTEntry(0,0,0);
registerInterupt(nullIDTEntry, i);
}
}
void registerInterupt(const IDTEntry entry, const unsigned intNo)
{
if(intNo < NUM_IDT_ENTRIES)
InteruptDescriptorTable[intNo] = entry;
else
{
__asm__("mov [=13=]xDEADC0DE, %eax");
__asm__("hlt");
}
}
#define LOW_FUN_ADDR(fun) ( (uint32_t)fun & 0xFFFF )
#define UP_FUN_ADDR(fun) ( (uint32_t)fun >> 16) & 0xFFFF
IDTEntry fillIDTEntry(uint32_t intHandler,
uint16_t selector,
uint8_t type_attr)
{ IDTEntry newEntry;
newEntry.offset_low = LOW_FUN_ADDR(intHandler);
newEntry.selector = selector;
newEntry.zero = 0;
newEntry.type_attr = type_attr;
newEntry.offset_up = UP_FUN_ADDR(intHandler);
return newEntry;
}
extern void _lidt(_IDT_PTR* idtPtr);
void loadIDT()
{
zeroIDT();
_IDT_PTR idtPtr;
idtPtr.idtSize = sizeof(struct __InteruptDescriptorTableEntry)*256 - 1;
idtPtr.idtBaseAddr = (uint32_t) &InteruptDescriptorTable;
IDTEntry printOnScreenInt = fillIDTEntry((uint32_t)interupt_pritnOnScreen, 0x18, 0xe);
registerInterupt(printOnScreenInt, 32);
_lidt(&idtPtr);
}
数据结构:
struct __InteruptDescriptorTableEntry
{
uint16_t offset_low;
uint16_t selector;
uint8_t zero;
uint8_t type_attr;
uint16_t offset_up;
} __attribute__((packed));
typedef struct __InteruptDescriptorTableEntry IDTEntry;
struct _ITD_PTR
{
uint16_t idtSize;
uint32_t idtBaseAddr;
} __attribute__((packed));
typedef struct _ITD_PTR _IDT_PTR;
以及示例中断例程:
.global interupt_pritnOnScreen
interupt_pritnOnScreen:
mov [=15=]xf00ff00f, %eax
hlt
iret
我检查了IDT寄存器是否加载了ptr到quemu中的IDT,是的。我在 GRUB 启动后立即加载 IDT(设置了保护模式并且 GDT 选择器跨越整个 RAM)。我认为我错误地注册了中断例程,但我可以指出代码中的任何错误。
日志清楚地写着 not present
。您忘记设置 IDT 条目中的当前位。您应该使用 type_attr
of 0x8E
.