2016-03-11 3 views
1

Я следил за Bran's tutorial по GDT, IDT и ISR. Я написал обработчик исключений, но когда я проверил его, разделив на ноль, он поменялся тройной ошибкой. Я не уверен, что я сделал не так. Вот 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

Просто отлаживать QEMU с помощью gdb. Я не помню точных команд, но я помню, что это довольно просто. – Downvoter

+1

@cad добавить '-s -S' в параметры командной строки QEMU и выполнить отладку удаленного GDB на localhost port 1234. –

ответ

2

Проблема заключается в тонкой разнице между NASM (ассемблером, используемым в учебном пособии, который вы связали) и GAS (ака-сборщик GNU, который, как я полагаю, вы используете). В частности, он с этой линии в isr.S:

mov eax, fault_handler 

В NASM, все рассматривается как метка/значение. Таким образом, приведенное выше утверждение компонует в

mov eax, <address of fault_handler> 

т.е. "MOVE 32-битный немедленной в eax". Однако в ГАС, он рассматривает это как переменную и автоматически разыменовывает, поэтому он действует как

mov eax, dword ptr [address of fault_handler] 

т.е. тянет первые 4 байта в функции fault_handler и присваивает их eax, в результате чего мусор eip показано в дампе QEMU.

Есть несколько исправлений для этого:

  1. использование lea вместо mov (т.е. lea eax, fault_handler)
  2. использовать offset ключевое слово (mov eax, offset fault_handler)
  3. просто вызовите функцию непосредственно (call fault_handler)
Смежные вопросы