my interrupt handler cause a general protection fault (using Jamesmolloy Tutorial)

0

i'm getting a general protection fault and i don't know why, i send a interrupt $0 and i get the message : Divide error 0 so it's good but then i got a loop of general protection fault and then it segfault.

here my code : init_tables.c

#include <k/types.h>
#include "io.h"
#include "init_tables.h"


extern void gdt_flush(u32 gdt_ptr);
extern void idt_flush(u32 idt_p);


/* 1. SERIAL PORT */
void init_uart(void)                //Initialize uart 16550 for 38400 bps
{
    u8 ier = inb(SERIAL_PORT + 1);
    u8 fcr = inb(SERIAL_PORT + 2);
    u8 lcr = inb(SERIAL_PORT + 3);
    u16 rate = 38400;

    outb(SERIAL_PORT + 3, lcr | 1 << 7);
    outb(SERIAL_PORT + 0, (115200 / rate) & 255); // = 0x3
    outb(SERIAL_PORT + 1, (115200 / rate) >> 8);  // = 0x0
    outb(SERIAL_PORT + 3, lcr & ~(1 << 7));

    outb(SERIAL_PORT + 2, fcr | 1 << 1);
    outb(SERIAL_PORT + 2, fcr | 1 << 2);
    outb(SERIAL_PORT + 2, fcr | 1 << 6);
    outb(SERIAL_PORT + 2, fcr | 1 << 7);
    outb(SERIAL_PORT + 1, ier | 1 << 1);
}

/* 2. MEMORY MANAGER */

static struct gdt_entry gdt[5];
static struct gdt_r gdt_r;

static struct idt_entry idt_e[256];
static struct idt_r idt_r;

static void set_gdt_entry(unsigned index, u32 base, u32 limit, u16 access, u16 flags)/* Function to initialize an index of the gtd_entry structure */
{
    if (index >= SIZE_ARRAY(gdt))
        printf("ARRAY SIZE INCORRECT\n");


    gdt[index].base_15_00 = (base & 0xFFFF);   // set segment limit of 00-15
    gdt[index].base_23_16 = (base >> 16) & 0xFF; //set up base 16-23 bit
    gdt[index].base_31_24 = (base >> 24) & 0xFF; //set up base 24-31 bit*/

    gdt[index].seg_lim_15_00    = (limit & 0xFFFF); //set up base 00-15 bit
    gdt[index].granularity = (limit >> 16) & 0x0F;   //set segment of 16-19 

    gdt[index].granularity |= flags & 0xF0;  // granularity, operand size, zero and avl  -> flags
    gdt[index].access_byte = access; //set up type, s, dpl, p 

}


static void init_gdt(void)
{
    gdt_r.limit = sizeof(gdt) - 1;
    gdt_r.base  = (u32)&gdt;

    set_gdt_entry(0, 0, 0, 0, 0);                /* Null segment */
    set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
    set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
    //set_gdt_entry(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); /* User mode code segment */ 
    //set_gdt_entry(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); /* User mode data segment */

    gdt_flush((u32)&gdt_r);
}

void init_kernel(void)
{
    init_uart();
    init_gdt();
    init_idt();

}

static int idt_set_gate(u32 n, u32 base, u16 sel, u8 flags)
{
    if (n >= SIZE_ARRAY(idt_e))
        return -1;
    idt_e[n].base_15_00 = base & 0xFFFF;
    idt_e[n].base_16_31 = (base >> 16) & 0xFFFF;

    idt_e[n].segment_sel= sel;
    idt_e[n].zero = 0;
    /* We must uncomment the OR below when we get to using user-mode. It
      sets the interrupt gate's privilege level to 3. */
    idt_e[n].flags   = flags /* | 0x60 */;
    return 0;
}




void init_idt()
{
    idt_r.limit = sizeof(idt_e) - 1;
    idt_r.base  = (u32)&idt_e;

    (void)memset(&idt_e, 0, sizeof(idt_e));

    /*outb(0x20, 0x11); // remap irq table
    outb(0xA0, 0x11);
    outb(0x21, 0x20);
    outb(0xA1, 0x28);
    outb(0x21, 0x04);
    outb(0xA1, 0x02);
    outb(0x21, 0x01);
    outb(0xA1, 0x01);
    outb(0x21, 0x0);
    outb(0xA1, 0x0);*/
    idt_set_gate( 0,  (u32)isr0, 0x08, 0x8E);
    idt_set_gate( 1,  (u32)isr1, 0x08, 0x8E);
    idt_set_gate( 2,  (u32)isr2, 0x08, 0x8E);
    idt_set_gate( 3,  (u32)isr3, 0x08, 0x8E);
    idt_set_gate( 4,  (u32)isr4, 0x08, 0x8E);
    idt_set_gate( 5,  (u32)isr5, 0x08, 0x8E);
    idt_set_gate( 6,  (u32)isr6, 0x08, 0x8E);
    idt_set_gate( 7,  (u32)isr7, 0x08, 0x8E);
    idt_set_gate( 8,  (u32)isr8, 0x08, 0x8E);
    idt_set_gate( 9,  (u32)isr9, 0x08, 0x8E);
    idt_set_gate(10, (u32)isr10, 0x08, 0x8E);
    idt_set_gate(11, (u32)isr11, 0x08, 0x8E);
    idt_set_gate(12, (u32)isr12, 0x08, 0x8E);
    idt_set_gate(13, (u32)isr13, 0x08, 0x8E);
    idt_set_gate(14, (u32)isr14, 0x08, 0x8E);
    idt_set_gate(15, (u32)isr15, 0x08, 0x8E);
    idt_set_gate(16, (u32)isr16, 0x08, 0x8E);
    idt_set_gate(17, (u32)isr17, 0x08, 0x8E);
    idt_set_gate(18, (u32)isr18, 0x08, 0x8E);
    idt_set_gate(19, (u32)isr19, 0x08, 0x8E);
    idt_set_gate(20, (u32)isr20, 0x08, 0x8E);
    idt_set_gate(21, (u32)isr21, 0x08, 0x8E);
    idt_set_gate(22, (u32)isr22, 0x08, 0x8E);
    idt_set_gate(23, (u32)isr23, 0x08, 0x8E);
    idt_set_gate(24, (u32)isr24, 0x08, 0x8E);
    idt_set_gate(25, (u32)isr25, 0x08, 0x8E);
    idt_set_gate(26, (u32)isr26, 0x08, 0x8E);
    idt_set_gate(27, (u32)isr27, 0x08, 0x8E);
    idt_set_gate(28, (u32)isr28, 0x08, 0x8E);
    idt_set_gate(29, (u32)isr29, 0x08, 0x8E);
    idt_set_gate(30, (u32)isr30, 0x08, 0x8E);
    idt_set_gate(31, (u32)isr31, 0x08, 0x8E);
    /*idt_set_gate(32,  (u32)irq0, 0x08, 0x8E);
    idt_set_gate(33,  (u32)irq1, 0x08, 0x8E);
    idt_set_gate(34,  (u32)irq2, 0x08, 0x8E);
    idt_set_gate(35,  (u32)irq3, 0x08, 0x8E);
    idt_set_gate(36,  (u32)irq4, 0x08, 0x8E);
    idt_set_gate(37,  (u32)irq5, 0x08, 0x8E);
    idt_set_gate(38,  (u32)irq6, 0x08, 0x8E);
    idt_set_gate(39,  (u32)irq7, 0x08, 0x8E);
    idt_set_gate(40,  (u32)irq8, 0x08, 0x8E);
    idt_set_gate(41,  (u32)irq9, 0x08, 0x8E);
    idt_set_gate(42, (u32)irq10, 0x08, 0x8E);
    idt_set_gate(43, (u32)irq11, 0x08, 0x8E);
    idt_set_gate(44, (u32)irq12, 0x08, 0x8E);
    idt_set_gate(45, (u32)irq13, 0x08, 0x8E);
    idt_set_gate(46, (u32)irq14, 0x08, 0x8E);
    idt_set_gate(47, (u32)irq15, 0x08, 0x8E);*/

    idt_flush((u32)&idt_r);
   
}






Then i got my asm file : init_tab.asm

[GLOBAL gdt_flush] ; allow in C to call these functions

gdt_flush:
    mov eax, [esp+4]  ; Get the pointer to the GDT, passed as a parameter.
    lgdt [eax]        ; Load the new GDT pointer
    mov eax, cr0       ; Activate protected mode
    or eax, 1
    mov cr0, eax
    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax        ; Load all data segment selectors
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:.flush   ; 0x08 is the offset to our code segment: Far jump!
.flush:
    ret



[GLOBAL idt_flush]

idt_flush:
    mov eax, [esp+4]  ; Get the pointer to the IDT, passed as a parameter.
    lidt [eax]        ; Load the IDT pointer.
    ret

and then i got my interrupt common stub : interrupt_conf.asm :

%macro ISR_NO_ERROR 1  ; define a macro, taking one parameter
    [GLOBAL isr%1]        ; %1 accesses the first parameter.
    isr%1:
        ;cli
        push byte 0
        push byte %1
        jmp isr_common_stub
%endmacro

%macro ISR_ERROR 1
    [GLOBAL isr%1]
    isr%1:
        ;cli
        push byte %1
        jmp isr_common_stub
%endmacro



ISR_NO_ERROR  0
ISR_NO_ERROR  1
ISR_NO_ERROR  2
ISR_NO_ERROR  3
ISR_NO_ERROR  4
ISR_NO_ERROR  5
ISR_NO_ERROR  6
ISR_NO_ERROR  7
ISR_ERROR    8
ISR_NO_ERROR  9
ISR_ERROR   10
ISR_ERROR   11
ISR_ERROR   12
ISR_ERROR   13
ISR_ERROR   14
ISR_NO_ERROR 15
ISR_NO_ERROR 16
ISR_NO_ERROR 17
ISR_NO_ERROR 18
ISR_NO_ERROR 19
ISR_NO_ERROR 20
ISR_NO_ERROR 21
ISR_NO_ERROR 22
ISR_NO_ERROR 23
ISR_NO_ERROR 24
ISR_NO_ERROR 25
ISR_NO_ERROR 26
ISR_NO_ERROR 27
ISR_NO_ERROR 28
ISR_NO_ERROR 29
ISR_NO_ERROR 30
ISR_NO_ERROR 31




; In isr.c
[EXTERN isr_handler]
; This is our common ISR stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame.
isr_common_stub:
    pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

    mov eax, ds               ; Lower 16-bits of eax = ds.
    push eax                 ; save the data segment descriptor

    mov eax, 0x10  ; load the kernel data segment descriptor
    mov ds, eax
    mov es, eax
    mov fs, eax
    mov gs, eax

    call isr_handler

    pop eax        ; reload the original data segment descriptor
    mov ds, eax
    mov es, eax
    mov fs, eax
    mov gs, eax

    popa                     ; Pops edi,esi,ebp...
    add esp, 8     ; Cleans up the pushed error code and pushed ISR number
    ;sti
    iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP


; This macro creates a stub for an IRQ - the first parameter is
; the IRQ number, the second is the ISR number it is remapped to.
%macro IRQ 2
[GLOBAL irq%1]
    irq%1:
        cli
        push byte 0
        push byte %2
        jmp irq_common_stub
%endmacro

;IRQ  0, 32
;IRQ  1, 33
;IRQ  2, 34
;IRQ  3, 35
;IRQ  4, 36
;IRQ  5, 37
;IRQ  6, 38
;IRQ  7, 39
;IRQ  8, 40
;IRQ  9, 41
;IRQ 10, 42
;IRQ 11, 43
;IRQ 12, 44
;IRQ 13, 45
;IRQ 14, 46
;IRQ 15, 47


; In isr.c
[EXTERN irq_handler]
; This is our common IRQ stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame. 
irq_common_stub:
   pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

   mov ax, ds               ; Lower 16-bits of eax = ds.
   push eax                 ; save the data segment descriptor

   mov ax, 0x10  ; load the kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call irq_handler

   pop ebx        ; reload the original data segment descriptor
   mov ds, bx
   mov es, bx
   mov fs, bx
   mov gs, bx

   popa                     ; Pops edi,esi,ebp...
   add esp, 8     ; Cleans up the pushed error code and pushed ISR number
   sti
   iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

my main look like this :

void k_main(unsigned long magic, multiboot_info_t *info)
{
    init_kernel();
    printf("perfect toto\n");
    asm volatile("int $0");
}

After that i got this on my terminal :

enter image description here

enter image description here

and here my file where k_main is launch :

#include "multiboot.h"

#define HEADER_FLAGS (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO)
#define STACK_SIZE  8192

    .section .multiboot
    .type multiboot_header, @object
multiboot_header:
    .align      MULTIBOOT_HEADER_ALIGN
    .long       MULTIBOOT_HEADER_MAGIC
    .long       HEADER_FLAGS
    .long       -(MULTIBOOT_HEADER_MAGIC + HEADER_FLAGS)
    .size multiboot_header, . - multiboot_header

    .section .text
    .global k_entry
    .type k_entry, @function
k_entry:
    lea end_stack, %esp
    push %ebx   /* multiboot info */
    push %eax   /* magic */
    call k_main /* kernel entry point */
.Lend:
    jmp .Lend
    .size k_entry, . - k_entry

.section .bss
stack:
    .space STACK_SIZE
    .align 16
end_stack:
.global end_stack

here is my handlers function:

static const char *exceptions[32] = {
    [0] = "Divide Error",
    [1] = "Debug Exception",
    [2] = "NMI Interrupt",
    [3] = "Breakpoint",
    [4] = "Overflow",
    [5] = "Bound Range Exceeded",
    [6] = "Invalid Opcode",
    [7] = "Device Not Available",
    [8] = "Double Fault",
    [9] = "Coprocessor Segment Overrum",
    [10] = "Invalid TSS",
    [11] = "Segment Not Present",
    [12] = "Stack Segment Fault",
    [13] = "General Protection Fault",
    [14] = "Page Fault",
    [15] = "Unknown interrupt exception",
    [16] = "x87 FPU Fault",
    [17] = "Alignment Check",
    [18] = "Machine Check",
    [19] = "SIMD Floating Point Exception",
    [20] = "Virtualization Exception",
};

isrhdl_t interrupt_handlers[256];

/* This gets called from our ASM interrupt handler stub. */
void
isr_handler(struct cpu_regs regs)
{

    if (interrupt_handlers[regs.int_no] != NULL) {
        isrhdl_t handler = interrupt_handlers[regs.int_no];
        handler(regs);
    } else {
        printf("unhandled interrupt: %s\n", exceptions[regs.int_no]);
    }
}

/* This gets called from our ASM interrupt handler stub. */
void
irq_handler(struct cpu_regs regs) {
    /* Send an EOI (end of interrupt) signal to the PICs. If this interrupt
       involved the slave. */
    if (regs.int_no >= 40) {
        /* Send reset signal to slave.*/
        outb(0xA0, 0x20);
    }
    /* Send reset signal to master. */
    outb(0x20, 0x20);

    if (interrupt_handlers[regs.int_no] != 0) {
        isrhdl_t handler = interrupt_handlers[regs.int_no];
        handler(regs);
    }
}

void
register_interrupt_handler(u32 n, isrhdl_t handler)
{

    if (n >= SIZE_ARRAY(interrupt_handlers))
        printf("Bad interrupt handler index.");
    interrupt_handlers[n] = handler;
}




i've been stuck 1 week on that i'm terribly tired of that ... Can somebody help me please thank you very much for help !

EDIT SOLUTION : Cannot modify data segment register. When tried General Protection Error is thrown

assembly
gcc
x86
interrupt
osdev
asked on Stack Overflow Oct 28, 2020 by YoloSama • edited Oct 28, 2020 by YoloSama

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0