2016-03-11 126 views
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 

什麼我錯在這裏做什麼?有關如何解決此問題的任何建議?

+0

只需使用gdb調試QEMU。我不記得確切的命令,但我記得它非常簡單。 – Downvoter

+1

@cad將'-s -S'添加到QEMU的命令行選項,並在localhost端口1234上執行遠程GDB調試。 –

回答

2

這個問題是NASM(您鏈接的教程中使用的彙編程序)和GAS(又名GNU彙編程序,我假設您正在使用)之間的細微區別。具體來說,也就是這條線在isr.S

mov eax, fault_handler 

在NASM,一切都將被視爲一個標籤/值。所以,上面的語句彙編爲

mov eax, <address of fault_handler> 

即「移動32位立即進入eax」。然而,在GAS,它把此作爲一個變量,並自動解除引用它,因此它的作用就像

mov eax, dword ptr [address of fault_handler] 

即它拉在函數fault_handler前4個字節,並將它們分配到eax,導致垃圾eip所示在QEMU轉儲。

這有一些修正:

  1. 使用lea代替mov(即lea eax, fault_handler
  2. 使用offset關鍵字(mov eax, offset fault_handler
  3. 只需直接調用函數(call fault_handler