为什么中断在此内核代码中不起作用?
Why interrupts not working in this kernel code?
尝试使中断在 64 位高半内核中工作。
github 回购:
https://github.com/JustVic/kernel_interrupts
这三个文件中的所有中断代码:
trap.h、trap.c、trap.S
trap.h:
#ifndef _TRAP_H_
#define _TRAP_H_
#include "stdint.h"
struct IdtEntry{
uint16_t low;
uint16_t selector;
uint8_t res0;
uint8_t attr;
uint16_t mid;
uint32_t high;
uint32_t res1;
} __attribute__((packed));
struct IdtPtr {
uint16_t limit;
uint64_t addr;
} __attribute__((packed));
struct TrapFrame {
int64_t r15;
int64_t r14;
int64_t r13;
int64_t r12;
int64_t r11;
int64_t r10;
int64_t r9;
int64_t r8;
int64_t rbp;
int64_t rdi;
int64_t rsi;
int64_t rdx;
int64_t rcx;
int64_t rbx;
int64_t rax;
int64_t trapno;
int64_t errorcode;
int64_t rip;
int64_t cs;
int64_t rflags;
int64_t rsp;
int64_t ss;
};
void vector0(void);
void vector1(void);
void vector2(void);
void vector3(void);
void vector4(void);
void vector5(void);
void vector6(void);
void vector7(void);
void vector8(void);
void vector10(void);
void vector11(void);
void vector12(void);
void vector13(void);
void vector14(void);
void vector16(void);
void vector17(void);
void vector18(void);
void vector19(void);
void vector32(void);
void vector39(void);
void init_idt(void);
void eoi(void);
void load_idt(struct IdtPtr *ptr);
unsigned char read_isr(void);
#endif
trap.c:
#include "trap.h"
struct IdtPtr idt_pointer;
struct IdtEntry vectors[256];
void init_idt_entry(struct IdtEntry *entry, uint64_t addr, uint8_t attribute)
{
entry->low = (uint16_t)addr;
entry->selector = 0x08;
entry->attr = attribute;
entry->mid = (uint16_t)(addr>>16);
entry->high = (uint32_t)(addr>>32);
}
void init_idt(void)
{
init_idt_entry(&vectors[0],(uint64_t)vector0,0x8e);
init_idt_entry(&vectors[1],(uint64_t)vector1,0x8e);
init_idt_entry(&vectors[2],(uint64_t)vector2,0x8e);
init_idt_entry(&vectors[3],(uint64_t)vector3,0x8e);
init_idt_entry(&vectors[4],(uint64_t)vector4,0x8e);
init_idt_entry(&vectors[5],(uint64_t)vector5,0x8e);
init_idt_entry(&vectors[6],(uint64_t)vector6,0x8e);
init_idt_entry(&vectors[7],(uint64_t)vector7,0x8e);
init_idt_entry(&vectors[8],(uint64_t)vector8,0x8e);
init_idt_entry(&vectors[10],(uint64_t)vector10,0x8e);
init_idt_entry(&vectors[11],(uint64_t)vector11,0x8e);
init_idt_entry(&vectors[12],(uint64_t)vector12,0x8e);
init_idt_entry(&vectors[13],(uint64_t)vector13,0x8e);
init_idt_entry(&vectors[14],(uint64_t)vector14,0x8e);
init_idt_entry(&vectors[16],(uint64_t)vector16,0x8e);
init_idt_entry(&vectors[17],(uint64_t)vector17,0x8e);
init_idt_entry(&vectors[18],(uint64_t)vector18,0x8e);
init_idt_entry(&vectors[19],(uint64_t)vector19,0x8e);
init_idt_entry(&vectors[32],(uint64_t)vector32,0x8e);
init_idt_entry(&vectors[39],(uint64_t)vector39,0x8e);
idt_pointer.limit = sizeof(vectors)-1;
idt_pointer.addr = (uint64_t)vectors;
load_idt(&idt_pointer);
}
void handler(struct TrapFrame *tf)
{
unsigned char isr_value;
printk("received interupt:");
printk(" %d\n", tf->trapno);
switch (tf->trapno) {
case 32:
eoi();
break;
case 39:
isr_value = read_isr();
if ((isr_value&(1<<7)) != 0) {
eoi();
}
break;
default:
while (1) { }
}
}
trap.S:
.text
.extern handler
.global vector0
.global vector1
.global vector2
.global vector3
.global vector4
.global vector5
.global vector6
.global vector7
.global vector8
.global vector10
.global vector11
.global vector12
.global vector13
.global vector14
.global vector16
.global vector17
.global vector18
.global vector19
.global vector32
.global vector39
.global eoi
.global read_isr
.global load_idt
Trap:
push %rax
push %rbx
push %rcx
push %rdx
push %rsi
push %rdi
push %rbp
push %r8
push %r9
push %r10
push %r11
push %r12
push %r13
push %r14
push %r15
mov %rsp,%rdi
call handler
TrapReturn:
pop %r15
pop %r14
pop %r13
pop %r12
pop %r11
pop %r10
pop %r9
pop %r8
pop %rbp
pop %rdi
pop %rsi
pop %rdx
pop %rcx
pop %rbx
pop %rax
add ,%rsp
iretq
vector0:
push [=12=]
push [=12=]
jmp Trap
vector1:
push [=12=]
push
jmp Trap
vector2:
push [=12=]
push
jmp Trap
vector3:
push [=12=]
push
jmp Trap
vector4:
push [=12=]
push
jmp Trap
vector5:
push [=12=]
push
jmp Trap
vector6:
push [=12=]
push
jmp Trap
vector7:
push [=12=]
push
jmp Trap
vector8:
push
jmp Trap
vector10:
push
jmp Trap
vector11:
push
jmp Trap
vector12:
push
jmp Trap
vector13:
push
jmp Trap
vector14:
push
jmp Trap
vector16:
push [=12=]
push
jmp Trap
vector17:
push
jmp Trap
vector18:
push [=12=]
push
jmp Trap
vector19:
push [=12=]
push
jmp Trap
vector32:
push [=12=]
push
jmp Trap
vector39:
push [=12=]
push
jmp Trap
eoi:
mov [=12=]x20,%al
out %al, [=12=]x20
ret
read_isr:
mov ,%al
out %al, [=12=]x20
in [=12=]x20,%al
ret
load_idt:
lidt (%rdi)
ret
GDT setup in boot32.S in the entry function _start:
...
lgdt (init_gdt64_ptr)
...
在数据部分:
.section .data
.align 16
gdt64:
.quad 0x0000000000000000 // 0x00 NULL
.quad 0x0020980000000000 // 0x08 KCODE64
gdt64_end:
.align 16
init_gdt64_ptr:
.word gdt64_end - gdt64 - 1
.long gdt64
如果我 运行 这个 Qemu 重新启动。我怀疑这是三重错误。
帮我理解为什么它不起作用?
据我在您的代码中看到的情况,一旦您进入长模式,您将在执行此操作时删除恒等映射:
movq [=10=]x0, p4_table
invlpg 0
问题是,从现在开始,您在 32 位代码中拥有的所有数据结构和变量都无法再访问,其中包括一件非常重要的东西 - GDT。在删除标识映射之前,您应该修复 GDT 指针并根据高端内存地址映射使用 LGDT
重新加载它。您必须将 KERNEL_VMA
添加到 GDT 指针内的基地址,并且必须使用 LGDT
.
加载相对于 KERNEL_VMA
的 GDT
在 boot32.S
中,我将在 init_gdt64_ptr
中为基地址添加一个标签,并使其全局可见,以便我们可以在 boot64.S
中访问它
.global init_gdt64_ptr_baseaddr
init_gdt64_ptr:
.word gdt64_end - gdt64 - 1
init_gdt64_ptr_baseaddr:
.quad gdt64 # Change to QUAD from LONG
我也将init_gdt64_ptr
中的基地址大小从.long
扩展到.quad
,这样这个GDT指针就可以在任何32中用LGDT
加载-位保护模式或长模式(64 位)。
在boot64.s
中我们可以将KERNEL_VMA
添加到基地址,也可以加载相对于高端内存的init_gdt64_ptr
,就像这样:
mov $KERNEL_VMA, %rax
add %rax, init_gdt64_ptr_baseaddr # Adjust the base pointer to high memory address
lgdt init_gdt64_ptr(%rax) # Reload the GDT relative to its high memory address
add %rax, %rsp # You were already adjusting the stack, I just moved it
// Setup segment selectors # Load the segment registers
movw [=12=], %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
movq [=12=]x0, p4_table
invlpg 0
现在我们有一个驻留在高端内存中的 GDT。我相信您遇到的问题与以下事实有关:当您在内核中执行 int [=27=]x3
时,试图通过 [=43] 重新加载 CS 寄存器=] 但它失败了,因为您在较低内存中的 GDT 不再被映射,因此发生故障,最终导致三重故障。
尝试使中断在 64 位高半内核中工作。 github 回购: https://github.com/JustVic/kernel_interrupts
这三个文件中的所有中断代码: trap.h、trap.c、trap.S
trap.h:
#ifndef _TRAP_H_
#define _TRAP_H_
#include "stdint.h"
struct IdtEntry{
uint16_t low;
uint16_t selector;
uint8_t res0;
uint8_t attr;
uint16_t mid;
uint32_t high;
uint32_t res1;
} __attribute__((packed));
struct IdtPtr {
uint16_t limit;
uint64_t addr;
} __attribute__((packed));
struct TrapFrame {
int64_t r15;
int64_t r14;
int64_t r13;
int64_t r12;
int64_t r11;
int64_t r10;
int64_t r9;
int64_t r8;
int64_t rbp;
int64_t rdi;
int64_t rsi;
int64_t rdx;
int64_t rcx;
int64_t rbx;
int64_t rax;
int64_t trapno;
int64_t errorcode;
int64_t rip;
int64_t cs;
int64_t rflags;
int64_t rsp;
int64_t ss;
};
void vector0(void);
void vector1(void);
void vector2(void);
void vector3(void);
void vector4(void);
void vector5(void);
void vector6(void);
void vector7(void);
void vector8(void);
void vector10(void);
void vector11(void);
void vector12(void);
void vector13(void);
void vector14(void);
void vector16(void);
void vector17(void);
void vector18(void);
void vector19(void);
void vector32(void);
void vector39(void);
void init_idt(void);
void eoi(void);
void load_idt(struct IdtPtr *ptr);
unsigned char read_isr(void);
#endif
trap.c:
#include "trap.h"
struct IdtPtr idt_pointer;
struct IdtEntry vectors[256];
void init_idt_entry(struct IdtEntry *entry, uint64_t addr, uint8_t attribute)
{
entry->low = (uint16_t)addr;
entry->selector = 0x08;
entry->attr = attribute;
entry->mid = (uint16_t)(addr>>16);
entry->high = (uint32_t)(addr>>32);
}
void init_idt(void)
{
init_idt_entry(&vectors[0],(uint64_t)vector0,0x8e);
init_idt_entry(&vectors[1],(uint64_t)vector1,0x8e);
init_idt_entry(&vectors[2],(uint64_t)vector2,0x8e);
init_idt_entry(&vectors[3],(uint64_t)vector3,0x8e);
init_idt_entry(&vectors[4],(uint64_t)vector4,0x8e);
init_idt_entry(&vectors[5],(uint64_t)vector5,0x8e);
init_idt_entry(&vectors[6],(uint64_t)vector6,0x8e);
init_idt_entry(&vectors[7],(uint64_t)vector7,0x8e);
init_idt_entry(&vectors[8],(uint64_t)vector8,0x8e);
init_idt_entry(&vectors[10],(uint64_t)vector10,0x8e);
init_idt_entry(&vectors[11],(uint64_t)vector11,0x8e);
init_idt_entry(&vectors[12],(uint64_t)vector12,0x8e);
init_idt_entry(&vectors[13],(uint64_t)vector13,0x8e);
init_idt_entry(&vectors[14],(uint64_t)vector14,0x8e);
init_idt_entry(&vectors[16],(uint64_t)vector16,0x8e);
init_idt_entry(&vectors[17],(uint64_t)vector17,0x8e);
init_idt_entry(&vectors[18],(uint64_t)vector18,0x8e);
init_idt_entry(&vectors[19],(uint64_t)vector19,0x8e);
init_idt_entry(&vectors[32],(uint64_t)vector32,0x8e);
init_idt_entry(&vectors[39],(uint64_t)vector39,0x8e);
idt_pointer.limit = sizeof(vectors)-1;
idt_pointer.addr = (uint64_t)vectors;
load_idt(&idt_pointer);
}
void handler(struct TrapFrame *tf)
{
unsigned char isr_value;
printk("received interupt:");
printk(" %d\n", tf->trapno);
switch (tf->trapno) {
case 32:
eoi();
break;
case 39:
isr_value = read_isr();
if ((isr_value&(1<<7)) != 0) {
eoi();
}
break;
default:
while (1) { }
}
}
trap.S:
.text
.extern handler
.global vector0
.global vector1
.global vector2
.global vector3
.global vector4
.global vector5
.global vector6
.global vector7
.global vector8
.global vector10
.global vector11
.global vector12
.global vector13
.global vector14
.global vector16
.global vector17
.global vector18
.global vector19
.global vector32
.global vector39
.global eoi
.global read_isr
.global load_idt
Trap:
push %rax
push %rbx
push %rcx
push %rdx
push %rsi
push %rdi
push %rbp
push %r8
push %r9
push %r10
push %r11
push %r12
push %r13
push %r14
push %r15
mov %rsp,%rdi
call handler
TrapReturn:
pop %r15
pop %r14
pop %r13
pop %r12
pop %r11
pop %r10
pop %r9
pop %r8
pop %rbp
pop %rdi
pop %rsi
pop %rdx
pop %rcx
pop %rbx
pop %rax
add ,%rsp
iretq
vector0:
push [=12=]
push [=12=]
jmp Trap
vector1:
push [=12=]
push
jmp Trap
vector2:
push [=12=]
push
jmp Trap
vector3:
push [=12=]
push
jmp Trap
vector4:
push [=12=]
push
jmp Trap
vector5:
push [=12=]
push
jmp Trap
vector6:
push [=12=]
push
jmp Trap
vector7:
push [=12=]
push
jmp Trap
vector8:
push
jmp Trap
vector10:
push
jmp Trap
vector11:
push
jmp Trap
vector12:
push
jmp Trap
vector13:
push
jmp Trap
vector14:
push
jmp Trap
vector16:
push [=12=]
push
jmp Trap
vector17:
push
jmp Trap
vector18:
push [=12=]
push
jmp Trap
vector19:
push [=12=]
push
jmp Trap
vector32:
push [=12=]
push
jmp Trap
vector39:
push [=12=]
push
jmp Trap
eoi:
mov [=12=]x20,%al
out %al, [=12=]x20
ret
read_isr:
mov ,%al
out %al, [=12=]x20
in [=12=]x20,%al
ret
load_idt:
lidt (%rdi)
ret
GDT setup in boot32.S in the entry function _start:
...
lgdt (init_gdt64_ptr)
...
在数据部分:
.section .data
.align 16
gdt64:
.quad 0x0000000000000000 // 0x00 NULL
.quad 0x0020980000000000 // 0x08 KCODE64
gdt64_end:
.align 16
init_gdt64_ptr:
.word gdt64_end - gdt64 - 1
.long gdt64
如果我 运行 这个 Qemu 重新启动。我怀疑这是三重错误。 帮我理解为什么它不起作用?
据我在您的代码中看到的情况,一旦您进入长模式,您将在执行此操作时删除恒等映射:
movq [=10=]x0, p4_table
invlpg 0
问题是,从现在开始,您在 32 位代码中拥有的所有数据结构和变量都无法再访问,其中包括一件非常重要的东西 - GDT。在删除标识映射之前,您应该修复 GDT 指针并根据高端内存地址映射使用 LGDT
重新加载它。您必须将 KERNEL_VMA
添加到 GDT 指针内的基地址,并且必须使用 LGDT
.
KERNEL_VMA
的 GDT
在 boot32.S
中,我将在 init_gdt64_ptr
中为基地址添加一个标签,并使其全局可见,以便我们可以在 boot64.S
.global init_gdt64_ptr_baseaddr
init_gdt64_ptr:
.word gdt64_end - gdt64 - 1
init_gdt64_ptr_baseaddr:
.quad gdt64 # Change to QUAD from LONG
我也将init_gdt64_ptr
中的基地址大小从.long
扩展到.quad
,这样这个GDT指针就可以在任何32中用LGDT
加载-位保护模式或长模式(64 位)。
在boot64.s
中我们可以将KERNEL_VMA
添加到基地址,也可以加载相对于高端内存的init_gdt64_ptr
,就像这样:
mov $KERNEL_VMA, %rax
add %rax, init_gdt64_ptr_baseaddr # Adjust the base pointer to high memory address
lgdt init_gdt64_ptr(%rax) # Reload the GDT relative to its high memory address
add %rax, %rsp # You were already adjusting the stack, I just moved it
// Setup segment selectors # Load the segment registers
movw [=12=], %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
movq [=12=]x0, p4_table
invlpg 0
现在我们有一个驻留在高端内存中的 GDT。我相信您遇到的问题与以下事实有关:当您在内核中执行 int [=27=]x3
时,试图通过 [=43] 重新加载 CS 寄存器=] 但它失败了,因为您在较低内存中的 GDT 不再被映射,因此发生故障,最终导致三重故障。