1
我在GDT,IDT和ISR上關注Bran's tutorial。我寫了異常處理程序,但是當我通過除零來測試它時,它發生了三重故障。我不確定我做錯了什麼。這裏是descriptor_table.h
:異常處理問題
#ifndef VOS_DESCRIPTOR_TABLE_H
#define VOS_DESCRIPTOR_TABLE__H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define SEGMENT_BASE 0
#define SEGMENT_LIMIT 0xFFFFF
#define CODE_RX_TYPE 0xA
#define DATA_RW_TYPE 0x2
#define GDT_NUM_ENTRIES 6
#define TSS_SEGSEL (5*8)
struct gdt_entry
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed));
typedef struct gdt_entry gdt_entry_t;
struct gdt_ptr
{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
typedef struct gdt_ptr gdt_ptr_t;
struct idt_entry
{
uint16_t base_low;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_high;
} __attribute__((packed));
typedef struct idt_entry idt_entry_t;
struct idt_ptr
{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
typedef struct idt_ptr idt_ptr_t;
struct regs
{
uint32_t gs, fs, es, ds;
uint32_t edi, esi, ebp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss;
};
typedef struct regs regs_t;
void gdt_set_gate(int, unsigned long, unsigned long, unsigned char, unsigned char);
void idt_set_gate(uint8_t, uint32_t, uint16_t, uint8_t);
int gdt_init();
int idt_init();
int isrs_init();
int descriptors_init();
#endif
這裏是descriptor_table.c
:
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <kernel/system.h>
#include <kernel/descriptor_table.h>
gdt_entry_t gdt[3];
gdt_ptr_t gp;
idt_entry_t idt[256];
idt_ptr_t idtp;
extern void gdt_flush();
extern void idt_load();
void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
gdt[num].base_low = (base & 0xFFFF);
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
gdt[num].limit_low = (limit & 0xFFFF);
gdt[num].granularity = ((limit >> 16) & 0x0F);
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access = access;
}
int gdt_init()
{
gp.limit = (sizeof(gdt_entry_t) * 3) - 1;
gp.base = (uint32_t)&gdt;
// Null descriptor
gdt_set_gate(0, 0, 0, 0, 0);
// Code segment
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
// Data segment
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
gdt_flush();
return 1;
}
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
{
idt[num].base_low = base & 0x0000FFFF;
idt[num].base_high = (base >> 16) & 0x0000FFFF;
idt[num].sel = sel;
idt[num].always0 = 0;
idt[num].flags = flags;
}
int idt_init()
{
// IDT pointer
idtp.limit = (sizeof(idt_entry_t) * 256) - 1;
idtp.base = (uint32_t)&idt;
// Clear out IDT
memset(&idt, 0, sizeof(idt_entry_t) * 256);
// Add ISRs
// TODO
idt_load();
return 1;
}
int descriptors_init()
{
kernel_log("Initializing GDT...");
gdt_init();
kernel_log("GDT initialized.");
kernel_log("Initializing IDT...");
idt_init();
kernel_log("IDT initialized.");
return 1;
}
這裏是isrc.c
:
#include <stddef.h>
#include <stdint.h>
#include <kernel/descriptor_table.h>
#include <kernel/serial.h>
#include <kernel/system.h>
#include <kernel/tty.h>
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
int isrs_init()
{
idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E);
idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E);
idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E);
idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E);
idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E);
idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E);
idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E);
idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E);
idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E);
idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E);
idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E);
idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E);
idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E);
idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E);
idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E);
idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E);
idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E);
idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E);
idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E);
idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E);
idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E);
idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E);
idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E);
idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E);
idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E);
idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E);
idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E);
idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E);
idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E);
idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E);
idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E);
idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E);
return 1;
}
char* exception_messages[] =
{
"Division by Zero",
"Debug",
"Non-maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved", // 19
"Reserved", // 20
"Reserved", // 21
"Reserved", // 22
"Reserved", // 23
"Reserved", // 24
"Reserved", // 25
"Reserved", // 26
"Reserved", // 27
"Reserved", // 28
"Reserved", // 29
"Reserved", // 30
"Reserved", // 31
};
void fault_handler(regs_t *r)
{
if(r->int_no < 32)
{
kernel_log_partA("Exception Detected: ");
//kernel_log_partB(exception_messages[r->int_no]);
//kernel_log("System Halted.");
// terminal_writeline("Exception Detected: ");
// terminal_reset();
// terminal_write(exception_messages[r->int_no]);
// terminal_writeline("System Halted!");
// Halting system
// TODO: Reboot the system to halt
for(;;);
}
}
這是gdt.S
:
.intel_syntax noprefix
.global gdt_flush
.extern gp
gdt_flush:
lgdt [gp]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:flush2
flush2:
ret
這裏是idt.S
:
.intel_syntax noprefix
.global idt_load
.extern idtp
idt_load:
lidt [idtp]
ret
這裏是isr.S
:
.intel_syntax noprefix
.global isr0
.global isr1
.global isr2
.global isr3
.global isr4
.global isr5
.global isr6
.global isr7
.global isr8
.global isr9
.global isr10
.global isr11
.global isr12
.global isr13
.global isr14
.global isr15
.global isr16
.global isr17
.global isr18
.global isr19
.global isr20
.global isr21
.global isr22
.global isr23
.global isr24
.global isr25
.global isr26
.global isr27
.global isr28
.global isr29
.global isr30
.global isr31
# Divide by zero exception
isr0:
cli
push 0x0
push 0x0
jmp isr_common_stub
# Debug exception
isr1:
cli
push 0x0
push 0x1
jmp isr_common_stub
isr2:
cli
push 0x0
push 0x2
jmp isr_common_stub
isr3:
cli
push 0x0
push 0x3
jmp isr_common_stub
isr4:
cli
push 0x0
push 0x4
jmp isr_common_stub
isr5:
cli
push 0x0
push 0x5
jmp isr_common_stub
isr6:
cli
push 0x0
push 0x6
jmp isr_common_stub
isr7:
cli
push 0x0
push 0x7
jmp isr_common_stub
isr8:
cli
push 0x8
jmp isr_common_stub
isr9:
cli
push 0x0
push 0x9
jmp isr_common_stub
isr10:
cli
push 0x10
jmp isr_common_stub
isr11:
cli
push 0x11
jmp isr_common_stub
isr12:
cli
push 0x12
jmp isr_common_stub
isr13:
cli
push 0x13
jmp isr_common_stub
isr14:
cli
push 0x14
jmp isr_common_stub
isr15:
cli
push 0x0
push 0x15
jmp isr_common_stub
isr16:
cli
push 0x0
push 0x16
jmp isr_common_stub
isr17:
cli
push 0x0
push 0x17
jmp isr_common_stub
isr18:
cli
push 0x0
push 0x18
jmp isr_common_stub
isr19:
cli
push 0x0
push 0x19
jmp isr_common_stub
isr20:
cli
push 0x0
push 0x20
jmp isr_common_stub
isr21:
cli
push 0x0
push 0x21
jmp isr_common_stub
isr22:
cli
push 0x0
push 0x22
jmp isr_common_stub
isr23:
cli
push 0x0
push 0x23
jmp isr_common_stub
isr24:
cli
push 0x0
push 0x24
jmp isr_common_stub
isr25:
cli
push 0x0
push 0x25
jmp isr_common_stub
isr26:
cli
push 0x0
push 0x26
jmp isr_common_stub
isr27:
cli
push 0x0
push 0x27
jmp isr_common_stub
isr28:
cli
push 0x0
push 0x28
jmp isr_common_stub
isr29:
cli
push 0x0
push 0x29
jmp isr_common_stub
isr30:
cli
push 0x0
push 0x30
jmp isr_common_stub
isr31:
cli
push 0x0
push 0x31
jmp isr_common_stub
.extern fault_handler
isr_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push eax
mov eax, fault_handler
call eax
pop eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
這裏是QEMU調試後的結果:
EAX=8b0cec83 EBX=00010000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00106824
EIP=8b0cec83 EFL=00200002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00105030 00000017
IDT= 00105060 000007ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=00106868 CCO=ADDL
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
qemu: fatal: Trying to execute code outside RAM or ROM at 0x8b0cec83
什麼我錯在這裏做什麼?有關如何解決此問題的任何建議?
只需使用gdb調試QEMU。我不記得確切的命令,但我記得它非常簡單。 – Downvoter
@cad將'-s -S'添加到QEMU的命令行選項,並在localhost端口1234上執行遠程GDB調試。 –