x86-64 内核在设置 IDT 时崩溃
x86-64 Kernel crashing on setting up the IDT
我目前正在尝试从头开始创建 x86-64 内核(使用 GRUB Multiboot2 作为引导加载程序)。我设置我的 GDT 很好,但是在设置我的 IDT 时,似乎有问题。我通过 hlt
在我的代码的大多数指令之前和之后将问题隔离为我对 lidt
的调用。这是定义我的 IDT 的 C 和 ASM 文件:
global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15
global load_idt
global remap_pic
global irq0_handler
global irq1_handler
global irq2_handler
global irq3_handler
global irq4_handler
global irq5_handler
global irq6_handler
global irq7_handler
global irq8_handler
global irq9_handler
global irq10_handler
global irq11_handler
global irq12_handler
global irq13_handler
global irq14_handler
global irq15_handler
extern handle_keyboard_in
%macro pushAll 0
push rax
push rcx
push rdx
push rbx
push rbp
push rsi
push rdi
%endmacro
%macro popAll 0
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
pop rax
%endmacro
section .text
bits 64
irq0:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq1:
pushAll
in al, 0x60
push ax
call handle_keyboard_in
mov al, 0x20
out 0x20, al
popAll
iret
irq2:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq3:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq4:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq5:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq6:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq7:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq8:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq9:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq10:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq11:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq12:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq13:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq14:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq15:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
load_idt:
mov edx, [esp + 4]
lidt [edx]
ret
remap_pic:
mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, 0x20
out 0x21, al
mov al, 0x40
out 0xA1, al
mov al, 0x04
out 0x21, al
mov al, 0x02
out 0xA1, al
mov al, 0x01
out 0x21, al
out 0xA1, al
mov al, 0x00
out 0x21, al
out 0xA1, al
ret
#include <stdint.h>
#include <stddef.h>
struct IDT_entry{
unsigned short int offset_lowerbits;
unsigned short int selector;
unsigned char zero;
unsigned char type_attr;
unsigned short int offset_higherbits;
};
struct IDT_entry IDT[256];
void idt_init() {
extern int load_idt();
extern int remap_pic();
extern int irq0();
extern int irq1();
extern int irq2();
extern int irq3();
extern int irq4();
extern int irq5();
extern int irq6();
extern int irq7();
extern int irq8();
extern int irq9();
extern int irq10();
extern int irq11();
extern int irq12();
extern int irq13();
extern int irq14();
extern int irq15();
unsigned long irq0_address;
unsigned long irq1_address;
unsigned long irq2_address;
unsigned long irq3_address;
unsigned long irq4_address;
unsigned long irq5_address;
unsigned long irq6_address;
unsigned long irq7_address;
unsigned long irq8_address;
unsigned long irq9_address;
unsigned long irq10_address;
unsigned long irq11_address;
unsigned long irq12_address;
unsigned long irq13_address;
unsigned long irq14_address;
unsigned long irq15_address;
unsigned long idt_address;
unsigned long idt_ptr[2];
remap_pic();
irq0_address = (unsigned long)irq0;
IDT[32].offset_lowerbits = irq0_address & 0xffff;
IDT[32].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[32].zero = 0;
IDT[32].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[32].offset_higherbits = (irq0_address & 0xffff0000) >> 16;
irq1_address = (unsigned long)irq1;
IDT[33].offset_lowerbits = irq1_address & 0xffff;
IDT[33].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[33].zero = 0;
IDT[33].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[33].offset_higherbits = (irq1_address & 0xffff0000) >> 16;
irq2_address = (unsigned long)irq2;
IDT[34].offset_lowerbits = irq2_address & 0xffff;
IDT[34].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[34].zero = 0;
IDT[34].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[34].offset_higherbits = (irq2_address & 0xffff0000) >> 16;
irq3_address = (unsigned long)irq3;
IDT[35].offset_lowerbits = irq3_address & 0xffff;
IDT[35].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[35].zero = 0;
IDT[35].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[35].offset_higherbits = (irq3_address & 0xffff0000) >> 16;
irq4_address = (unsigned long)irq4;
IDT[36].offset_lowerbits = irq4_address & 0xffff;
IDT[36].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[36].zero = 0;
IDT[36].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[36].offset_higherbits = (irq4_address & 0xffff0000) >> 16;
irq5_address = (unsigned long)irq5;
IDT[37].offset_lowerbits = irq5_address & 0xffff;
IDT[37].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[37].zero = 0;
IDT[37].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[37].offset_higherbits = (irq5_address & 0xffff0000) >> 16;
irq6_address = (unsigned long)irq6;
IDT[38].offset_lowerbits = irq6_address & 0xffff;
IDT[38].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[38].zero = 0;
IDT[38].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[38].offset_higherbits = (irq6_address & 0xffff0000) >> 16;
irq7_address = (unsigned long)irq7;
IDT[39].offset_lowerbits = irq7_address & 0xffff;
IDT[39].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[39].zero = 0;
IDT[39].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[39].offset_higherbits = (irq7_address & 0xffff0000) >> 16;
irq8_address = (unsigned long)irq8;
IDT[40].offset_lowerbits = irq8_address & 0xffff;
IDT[40].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[40].zero = 0;
IDT[40].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[40].offset_higherbits = (irq8_address & 0xffff0000) >> 16;
irq9_address = (unsigned long)irq9;
IDT[41].offset_lowerbits = irq9_address & 0xffff;
IDT[41].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[41].zero = 0;
IDT[41].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[41].offset_higherbits = (irq9_address & 0xffff0000) >> 16;
irq10_address = (unsigned long)irq10;
IDT[42].offset_lowerbits = irq10_address & 0xffff;
IDT[42].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[42].zero = 0;
IDT[42].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[42].offset_higherbits = (irq10_address & 0xffff0000) >> 16;
irq11_address = (unsigned long)irq11;
IDT[43].offset_lowerbits = irq11_address & 0xffff;
IDT[43].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[43].zero = 0;
IDT[43].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[43].offset_higherbits = (irq11_address & 0xffff0000) >> 16;
irq12_address = (unsigned long)irq12;
IDT[44].offset_lowerbits = irq12_address & 0xffff;
IDT[44].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[44].zero = 0;
IDT[44].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[44].offset_higherbits = (irq12_address & 0xffff0000) >> 16;
irq13_address = (unsigned long)irq13;
IDT[45].offset_lowerbits = irq13_address & 0xffff;
IDT[45].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[45].zero = 0;
IDT[45].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[45].offset_higherbits = (irq13_address & 0xffff0000) >> 16;
irq14_address = (unsigned long)irq14;
IDT[46].offset_lowerbits = irq14_address & 0xffff;
IDT[46].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[46].zero = 0;
IDT[46].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[46].offset_higherbits = (irq14_address & 0xffff0000) >> 16;
irq15_address = (unsigned long)irq15;
IDT[47].offset_lowerbits = irq15_address & 0xffff;
IDT[47].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[47].zero = 0;
IDT[47].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[47].offset_higherbits = (irq15_address & 0xffff0000) >> 16;
/* fill the IDT descriptor */
idt_address = (unsigned long)IDT ;
idt_ptr[0] = (sizeof (struct IDT_entry) * 256) + ((idt_address & 0xffff) << 16);
idt_ptr[1] = idt_address >> 16 ;
load_idt(idt_ptr);
}
我使用 OSDev wiki 作为源(该代码的很大一部分甚至是从那里复制和粘贴的)。
我使用 x86_64-elf-gcc 作为我的交叉编译器,NASM 作为我的汇编程序,x86_64-elf-ld 到 link 一切都在一起。我也使用 QEMU 作为我的模拟器
注意:我的代码在使用内联汇编时不想编译,这就是我将一些函数移植到 NASM 文件的原因。
您的 load_idt
函数被编写为 32 位函数,其中第一个参数在堆栈上传递。在 64-bit System V ABI 中,第一个参数在寄存器 RDI 中传递。改用这个:
load_idt:
lidt [rdi]
ret
我目前正在尝试从头开始创建 x86-64 内核(使用 GRUB Multiboot2 作为引导加载程序)。我设置我的 GDT 很好,但是在设置我的 IDT 时,似乎有问题。我通过 hlt
在我的代码的大多数指令之前和之后将问题隔离为我对 lidt
的调用。这是定义我的 IDT 的 C 和 ASM 文件:
global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15
global load_idt
global remap_pic
global irq0_handler
global irq1_handler
global irq2_handler
global irq3_handler
global irq4_handler
global irq5_handler
global irq6_handler
global irq7_handler
global irq8_handler
global irq9_handler
global irq10_handler
global irq11_handler
global irq12_handler
global irq13_handler
global irq14_handler
global irq15_handler
extern handle_keyboard_in
%macro pushAll 0
push rax
push rcx
push rdx
push rbx
push rbp
push rsi
push rdi
%endmacro
%macro popAll 0
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
pop rax
%endmacro
section .text
bits 64
irq0:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq1:
pushAll
in al, 0x60
push ax
call handle_keyboard_in
mov al, 0x20
out 0x20, al
popAll
iret
irq2:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq3:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq4:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq5:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq6:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq7:
pushAll
mov al, 0x20
out 0x20, al
popAll
iret
irq8:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq9:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq10:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq11:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq12:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq13:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq14:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
irq15:
pushAll
mov al, 0x20
out 0xa0, al
out 0x20, al
popAll
iret
load_idt:
mov edx, [esp + 4]
lidt [edx]
ret
remap_pic:
mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, 0x20
out 0x21, al
mov al, 0x40
out 0xA1, al
mov al, 0x04
out 0x21, al
mov al, 0x02
out 0xA1, al
mov al, 0x01
out 0x21, al
out 0xA1, al
mov al, 0x00
out 0x21, al
out 0xA1, al
ret
#include <stdint.h>
#include <stddef.h>
struct IDT_entry{
unsigned short int offset_lowerbits;
unsigned short int selector;
unsigned char zero;
unsigned char type_attr;
unsigned short int offset_higherbits;
};
struct IDT_entry IDT[256];
void idt_init() {
extern int load_idt();
extern int remap_pic();
extern int irq0();
extern int irq1();
extern int irq2();
extern int irq3();
extern int irq4();
extern int irq5();
extern int irq6();
extern int irq7();
extern int irq8();
extern int irq9();
extern int irq10();
extern int irq11();
extern int irq12();
extern int irq13();
extern int irq14();
extern int irq15();
unsigned long irq0_address;
unsigned long irq1_address;
unsigned long irq2_address;
unsigned long irq3_address;
unsigned long irq4_address;
unsigned long irq5_address;
unsigned long irq6_address;
unsigned long irq7_address;
unsigned long irq8_address;
unsigned long irq9_address;
unsigned long irq10_address;
unsigned long irq11_address;
unsigned long irq12_address;
unsigned long irq13_address;
unsigned long irq14_address;
unsigned long irq15_address;
unsigned long idt_address;
unsigned long idt_ptr[2];
remap_pic();
irq0_address = (unsigned long)irq0;
IDT[32].offset_lowerbits = irq0_address & 0xffff;
IDT[32].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[32].zero = 0;
IDT[32].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[32].offset_higherbits = (irq0_address & 0xffff0000) >> 16;
irq1_address = (unsigned long)irq1;
IDT[33].offset_lowerbits = irq1_address & 0xffff;
IDT[33].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[33].zero = 0;
IDT[33].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[33].offset_higherbits = (irq1_address & 0xffff0000) >> 16;
irq2_address = (unsigned long)irq2;
IDT[34].offset_lowerbits = irq2_address & 0xffff;
IDT[34].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[34].zero = 0;
IDT[34].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[34].offset_higherbits = (irq2_address & 0xffff0000) >> 16;
irq3_address = (unsigned long)irq3;
IDT[35].offset_lowerbits = irq3_address & 0xffff;
IDT[35].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[35].zero = 0;
IDT[35].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[35].offset_higherbits = (irq3_address & 0xffff0000) >> 16;
irq4_address = (unsigned long)irq4;
IDT[36].offset_lowerbits = irq4_address & 0xffff;
IDT[36].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[36].zero = 0;
IDT[36].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[36].offset_higherbits = (irq4_address & 0xffff0000) >> 16;
irq5_address = (unsigned long)irq5;
IDT[37].offset_lowerbits = irq5_address & 0xffff;
IDT[37].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[37].zero = 0;
IDT[37].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[37].offset_higherbits = (irq5_address & 0xffff0000) >> 16;
irq6_address = (unsigned long)irq6;
IDT[38].offset_lowerbits = irq6_address & 0xffff;
IDT[38].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[38].zero = 0;
IDT[38].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[38].offset_higherbits = (irq6_address & 0xffff0000) >> 16;
irq7_address = (unsigned long)irq7;
IDT[39].offset_lowerbits = irq7_address & 0xffff;
IDT[39].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[39].zero = 0;
IDT[39].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[39].offset_higherbits = (irq7_address & 0xffff0000) >> 16;
irq8_address = (unsigned long)irq8;
IDT[40].offset_lowerbits = irq8_address & 0xffff;
IDT[40].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[40].zero = 0;
IDT[40].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[40].offset_higherbits = (irq8_address & 0xffff0000) >> 16;
irq9_address = (unsigned long)irq9;
IDT[41].offset_lowerbits = irq9_address & 0xffff;
IDT[41].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[41].zero = 0;
IDT[41].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[41].offset_higherbits = (irq9_address & 0xffff0000) >> 16;
irq10_address = (unsigned long)irq10;
IDT[42].offset_lowerbits = irq10_address & 0xffff;
IDT[42].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[42].zero = 0;
IDT[42].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[42].offset_higherbits = (irq10_address & 0xffff0000) >> 16;
irq11_address = (unsigned long)irq11;
IDT[43].offset_lowerbits = irq11_address & 0xffff;
IDT[43].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[43].zero = 0;
IDT[43].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[43].offset_higherbits = (irq11_address & 0xffff0000) >> 16;
irq12_address = (unsigned long)irq12;
IDT[44].offset_lowerbits = irq12_address & 0xffff;
IDT[44].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[44].zero = 0;
IDT[44].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[44].offset_higherbits = (irq12_address & 0xffff0000) >> 16;
irq13_address = (unsigned long)irq13;
IDT[45].offset_lowerbits = irq13_address & 0xffff;
IDT[45].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[45].zero = 0;
IDT[45].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[45].offset_higherbits = (irq13_address & 0xffff0000) >> 16;
irq14_address = (unsigned long)irq14;
IDT[46].offset_lowerbits = irq14_address & 0xffff;
IDT[46].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[46].zero = 0;
IDT[46].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[46].offset_higherbits = (irq14_address & 0xffff0000) >> 16;
irq15_address = (unsigned long)irq15;
IDT[47].offset_lowerbits = irq15_address & 0xffff;
IDT[47].selector = 0x08; /* KERNEL_CODE_SEGMENT_OFFSET */
IDT[47].zero = 0;
IDT[47].type_attr = 0x8e; /* INTERRUPT_GATE */
IDT[47].offset_higherbits = (irq15_address & 0xffff0000) >> 16;
/* fill the IDT descriptor */
idt_address = (unsigned long)IDT ;
idt_ptr[0] = (sizeof (struct IDT_entry) * 256) + ((idt_address & 0xffff) << 16);
idt_ptr[1] = idt_address >> 16 ;
load_idt(idt_ptr);
}
我使用 OSDev wiki 作为源(该代码的很大一部分甚至是从那里复制和粘贴的)。
我使用 x86_64-elf-gcc 作为我的交叉编译器,NASM 作为我的汇编程序,x86_64-elf-ld 到 link 一切都在一起。我也使用 QEMU 作为我的模拟器
注意:我的代码在使用内联汇编时不想编译,这就是我将一些函数移植到 NASM 文件的原因。
您的 load_idt
函数被编写为 32 位函数,其中第一个参数在堆栈上传递。在 64-bit System V ABI 中,第一个参数在寄存器 RDI 中传递。改用这个:
load_idt:
lidt [rdi]
ret