Page 1 of 2

General Protection Fault upon return from Intterupt handler

Posted: Wed Mar 26, 2014 1:58 pm
by kemosparc
Hi,

I have a problem with my interrupt handlers.

As soon as I load the IDT and enable the PIC and the Key board I keep on getting GPF.

My irq stub handler looks like this

Code: Select all

irq_common_stub:

    pushAll                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
    mov ax, ds               ; Lower 16-bits of eax = ds.
    push rax                 ; 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 rbx        ; reload the original data segment descriptor
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx

    popAll                     ; Pops edi,esi,ebp..
    add rsp, 16      ; Cleans up the pushed error code and pushed ISR number
    sti
    iretq           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
When I insert a halt before the "iretq", the GPF does not appear, but eventually the VM crashes as I guess the stack explode.

Any ideas what could be my problem.

Thanks

Karim

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 2:20 pm
by Combuster
Did you read the logs?

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 4:30 pm
by theesemtheesem
Hi,

Shouldn't You also push esp just before the call so Your function can know where to pick up the registers from? (i. e. where the stack is?)

EDIT: also the sti before irteq is not needed - iretq enables interrupts on its own.

Cheers,
Theesem

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 5:26 pm
by Gigasoft
No. What business would an IRQ handler have randomly messing with the saved registers?

By the way, IRQs do not have error codes as they are not errors. I'd also look at pushAll and popAll. Are they really pushing and popping "edi,esi,ebp,esp,ebx,edx,ecx,eax"? Why are you setting FS and GS to the same value as DS? What's the purpose?

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 7:04 pm
by theesemtheesem
Hi,

It looks like he followed a tutorial, and all of these set all segment registers to the same value.
Also unless his irq handler function takes no parameters than it will mess up his stack, becouse
it will pop his saved ds value. And I suspect, since it looks like he did follow a some tutorial, that his
irq handler function does take one parameter, a pointer to a struct holding all the registers. But he does not
push that. So his stack gets messed up and iret just jumps to some random value. And he probably pushes a zero
to the stack as a dummy error code, hence he increments esp by 2 stack "slots".

Even if his IRQ handler does not "mess with the saved registers" he still has to either push esp before call
so his function can pop it as it's parameter, or modify his irq handler not to take any parameters, and obtain
the IRQ number from the PIC.

Cheers,
Andrew

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 7:57 pm
by sortie
Someone please link him the JamesM known bugs tutorial.

OP: Please upload your full source code somewhere, I think a closer look is in order when I wake up tomorrow.

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 8:02 pm
by Bender
Seeing that you're able to use RAX, it looks like you're in 64bit mode, but I'm confused since you're pushing the 32bit counterparts.
????

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 8:05 pm
by kemosparc
Thank you all for replying,

Yes, you are right, I followed James Molloy's tutorial, and my objective is to make it work with 64-bit and C++ implementation.

In my case I cannot push esp (32 bits), the compiler refuses to compile, rather I can push rsp, but this did not solve the problem.

Here is the code after adding the "push rsp". Is that what you meant I should do ?

Code: Select all

irq_common_stub:

    pushAll                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
    mov ax, ds               ; Lower 16-bits of eax = ds.
    push rax                 ; 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
    push rsp
    call irq_handler

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

    popAll                     ; Pops edi,esi,ebp..
    add rsp, 16      ; Cleans up the pushed error code and pushed ISR number
    sti
    iretq           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
You are also right, my handler function takes one parameter which is the following structure:

Code: Select all

typedef struct {
    uint64_t ds;
    uint64_t r15,r14,r13,r12,r11,r10,r9,r8,rsp,rdi, rsi, rbp , rdx, rcx, rbx, rax;
    uint8_t intNo, errCode;
    uint64_t rip, cs, eflags, useresp, ss;
} registers;
Also here is the irq macro that I use which jmps to the code in my first post:

Code: Select all

%macro IRQ 2
  global irq%1
  irq%1:
    cli
    push byte 0
    push byte %2
    jmp irq_common_stub
%endmacro
I don't really understand why should I push the esp ?

Thanks

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 8:42 pm
by kemosparc
Okay,

Thanks for refering me to the tutorial problems, I looked at the tutorial and updated my code to have my handler parameter as a pointer rahter than passing it by value

Code: Select all

irq_common_stub:

    pushAll                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
    mov ax, ds               ; Lower 16-bits of eax = ds.
    push rax                 ; 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

    push rsp      ; pushing rsp as the structure pointer -----------> new addition
    call irq_handler

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

    popAll                     ; Pops edi,esi,ebp..
    add rsp, 16      ; Cleans up the pushed error code and pushed ISR number
    iretq           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP


%macro IRQ 2
  global irq%1
  irq%1:
    cli
    push byte 0
    push byte %2
    jmp irq_common_stub
%endmacro


and my handler function is

Code: Select all

void irq_handler(registers * regs)
{
    if (interrupt_handlers[regs->intNo] != 0)
    {
        isr_t handler = interrupt_handlers[regs->intNo];
        handler(regs);
    }


    // Send an EOI (end of interrupt) signal to the PICs.
    // If this interrupt involved the slave.
        if (regs->intNo >= 40)
        {
            // Send reset signal to slave.
            Ports::outportb(PIC2_COMMAND, 0x20);
        }
        // Send reset signal to master. (As well as slave, if necessary).
        Ports::outportb(PIC1_COMMAND, 0x20);
}


But know the VM reboots as soon as the first PIC fires !!!

Any suggestions?

Thanks
Karim

Re: General Protection Fault upon return from Intterupt hand

Posted: Wed Mar 26, 2014 10:24 pm
by kemosparc
Okay, I did some updates and it now does not reboot and does not generate GPF.

here is the code for my handler

Code: Select all

void irq_handler(struct registers * regs)
{
        uint8_t oldx = video.getPositionX();
        uint8_t oldy = video.getPositionY();
        video.setPosition(45,2);
        video.putString("Got Interrupt: ",COLOR_BLUE,COLOR_WHITE);
        video.putDecimal(regs->intNo,COLOR_BLUE,COLOR_WHITE);
        video.setPosition(oldx,oldy);
}
here is the code for my irq stub

Code: Select all

irq_common_stub:

    pushAll                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
    mov ax, ds               ; Lower 16-bits of eax = ds.
    push rax                 ; 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
    mov rax,rsp
    push rax
    call irq_handler
    pop rax
    pop rbx        ; reload the original data segment descriptor
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx

    popAll                     ; Pops edi,esi,ebp..
    add rsp, 16      ; Cleans up the pushed error code and pushed ISR number
    iretq           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP


The problem now is that my handler prints the IRQ number as zeor while it should be PIC (32) to zero.

All the values inside the registers structure pointed to by reg has the values zeros !!!


any suggestions?

Thanks
Karim

Re: General Protection Fault upon return from Intterupt hand

Posted: Thu Mar 27, 2014 6:25 am
by theesemtheesem
Hi,

Can You also post what Your pushall and popall is? As far as I understand in long mode one has to manually push/pop all regs
since pusha/popa do not exist. So i gather it's a macro that You've defined.

Cheers,
Andrew

Re: General Protection Fault upon return from Intterupt hand

Posted: Thu Mar 27, 2014 9:44 am
by kemosparc
Hi,

Here is the whole file

Code: Select all

[BITS 64]
%macro pushAll 0
      push   rax
      push   rbx
      push   rcx
      push   rdx
      push   rbp
      push   rsi
      push   rdi
      push   rsp
      push   r8
      push   r9
      push   r10
      push   r11
      push   r12
      push   r13
      push   r14
      push   r15
%endmacro

%macro popAll 0
      pop       r15
      pop       r14
      pop       r13
      pop       r12
      pop       r11
      pop       r10
      pop       r9
      pop       r8
      pop       rsp
      pop       rdi
      pop       rsi
      pop       rbp
      pop       rdx
      pop       rcx
      pop       rbx
      pop       rax
%endmacro


global idtInit
extern idtP
idtInit:
   lidt [idtP]
   ret

;/*
; * Interrupt Handler
; */
extern isrHandler

isrCommon:
    pushAll
    mov     ax, ds
    push    rax

    mov     ax, 0x10
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax
    mov rax,rsp
    push rax

    call isrHandler
    pop rax
    pop      rbx
    mov      ds, bx
    mov      es, bx
    mov      fs, bx
    mov      gs, bx


    popAll
    add rsp,16
    ;sti
    iretq

extern irq_handler
extern irq_handler1

; 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:

    pushAll                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
    mov ax, ds               ; Lower 16-bits of eax = ds.
    push rax                 ; 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
    mov rax,rsp
    push rax
    xor rax,rax
    mov al,0x20
    out 0x20,al
;    call irq_handler1
    pop rax
    pop rbx        ; reload the original data segment descriptor
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx

    popAll                     ; Pops edi,esi,ebp..
    add rsp, 16      ; Cleans up the pushed error code and pushed ISR number
;    sti
hlt
    iretq           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

%macro ISR_NOERRCODE 1
  [GLOBAL isr%1]
  isr%1:
    cli
    push byte 0
    push byte %1
    jmp isrCommon
%endmacro

%macro ISR_ERRCODE 1
  [GLOBAL isr%1]
  isr%1:
    cli
    push byte %1
    jmp isrCommon
%endmacro

%macro IRQ 2
  global irq%1
  irq%1:
    cli
    push byte 0
    push byte %2
    jmp irq_common_stub
%endmacro

ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE   8
ISR_NOERRCODE 9
ISR_ERRCODE   10
ISR_ERRCODE   11
ISR_ERRCODE   12
ISR_ERRCODE   13
ISR_ERRCODE   14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
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

And here is my main kernel file

Code: Select all

#include "icxxabi.h"
#include "Video.h"
#include "Disk.h"
#include "PageManager.h"
#include "MemoryManager.h"
#include "HeapIndexItem.h"
#include "PCIConfigHeaderManager.h"
#include "new.h"
#include "E1000.h"
#include "rtl8139.h"

/*
* Interrupt Descriptor Structure
*/
#define IDT_SIZE    256

#define MAIN_FILE
#include "globals.h"
char exception_messages[32][64] =
{
    "Division By Zero",
    "Debug",
    "Non Maskable Interrupt",
    "Breakpoint Exception",
    "Into Detected Overflow Exception",
    "Out of Bounds Exception",
    "Invalid Opcode Exception",
    "No Coprocessor Exception",
    "Double Fault Exception",
    "Coprocessor Segment Overrun Exception",
    "Bad TSS Exception",
    "Segment Not Present Exception",
    "Stack Fault Exception",
    "General Protection Fault Exception",
    "Page Fault Exception",
    "Unknown Interrupt Exception",
    "Coprocessor Fault Exception",
    "Alignment Check Exception (486+)",
    "Machine Check Exception (Pentium/586+)",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions",
    "Reserved Exceptions"
};

char kbdus[128] =
{
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8',	/* 9 */
  '9', '0', '-', '=', '\b',	/* Backspace */
  '\t',			/* Tab */
  'q', 'w', 'e', 'r',	/* 19 */
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',	/* Enter key */
    0,			/* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',	/* 39 */
 '\'', '`',   0,		/* Left shift */
 '\\', 'z', 'x', 'c', 'v', 'b', 'n',			/* 49 */
  'm', ',', '.', '/',   0,				/* Right shift */
  '*',
    0,	/* Alt */
  ' ',	/* Space bar */
    0,	/* Caps lock */
    0,	/* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,	/* < ... F10 */
    0,	/* 69 - Num lock*/
    0,	/* Scroll Lock */
    0,	/* Home key */
    0,	/* Up Arrow */
    0,	/* Page Up */
  '-',
    0,	/* Left Arrow */
    0,
    0,	/* Right Arrow */
  '+',
    0,	/* 79 - End key*/
    0,	/* Down Arrow */
    0,	/* Page Down */
    0,	/* Insert Key */
    0,	/* Delete Key */
    0,   0,   0,
    0,	/* F11 Key */
    0,	/* F12 Key */
    0,	/* All other keys are undefined */
};



/*
* Prototypes
*/
void idtStart(void);
void idtSet(uint8_t, uint64_t, uint16_t, uint8_t);

static void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran);
static void init_gdt();

#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#else
extern
#endif
void isrHandler(struct registers *);

#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#else
extern
#endif
void gdtInit(uint64_t p);


#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#else
extern
#endif
void idtInit();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr0();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr1();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr2();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr3();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr4();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr5();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr6();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr7();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr8();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr9();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr10();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr11();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr12();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr13();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr14();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr15();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr16();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr17();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr18();
#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr19();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr20();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr21();


#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr22();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr23();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr24();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr25();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr26();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr27();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr28();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr29();

#if defined(__cplusplus)
extern "C"
#else
extern
#endif
void isr30();

#if defined(__cplusplus)
extern "C"
#endif
void isr31();

#if defined(__cplusplus)
extern "C"
#endif
void irq0 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq1 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq2 ();


#if defined(__cplusplus)
extern "C"
#endif
void irq3 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq4 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq5 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq6 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq7 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq8 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq9 ();

#if defined(__cplusplus)
extern "C"
#endif
void irq10();

#if defined(__cplusplus)
extern "C"
#endif
void irq11();

#if defined(__cplusplus)
extern "C"
#endif
void irq12();

#if defined(__cplusplus)
extern "C"
#endif
void irq13();

#if defined(__cplusplus)
extern "C"
#endif
void irq14();

#if defined(__cplusplus)
extern "C"
#endif
void irq15();


/* Setup Table and Pointer */

idtEntry idt[IDT_SIZE];
idtPointer idtP;



void IRQ_set_mask(unsigned char IRQline) {
    uint16_t port;
    uint8_t value;

    if(IRQline < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        IRQline -= 8;
    }
    value = Ports::inportb(port) | (1 << IRQline);
    Ports::outportb(port, value);
}

void IRQ_clear_mask(unsigned char IRQline) {
    uint16_t port;
    uint8_t value;

    if(IRQline < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        IRQline -= 8;
    }
    value = Ports::inportb(port) & ~(1 << IRQline);
    Ports::outportb(port, value);
}
void register_interrupt_handler(uint8_t n, isr_t handler)
{
    interrupt_handlers[n] = handler;
    if ( n >= IRQ0)
        IRQ_clear_mask(n-IRQ0);
}

void idtStart(void) {
   /* Set IDT Pointer */
   idtP.limit = (sizeof(idtEntry) * IDT_SIZE) - 1;
   idtP.base = (uint64_t)&idt;
   /* Clear Memory for IDT's */
   Utils::memset((uint8_t *)&idt, 0, sizeof(idtEntry) * IDT_SIZE);

   Utils::memset((uint8_t *)&interrupt_handlers, 0, sizeof(isr_t)*256);

    Ports::outportb(0x20, 0x11);
    Ports::outportb(0xA0, 0x11);
    Ports::outportb(0x21, 0x20);
    Ports::outportb(0xA1, 0x28);
    Ports::outportb(0x21, 0x04);
    Ports::outportb(0xA1, 0x02);
    Ports::outportb(0x21, 0x01);
    Ports::outportb(0xA1, 0x01);
    Ports::outportb(0x21, 0x0);
    Ports::outportb(0xA1, 0x0);
    for ( unsigned char c = 0 ; c < 16 ; c++)
        IRQ_set_mask(c);

   /* Set IDT Gates */
   idtSet(0, (uint64_t)isr0, 0x08, 0x8E);
   idtSet(1, (uint64_t)isr1, 0x08, 0x8E);
   idtSet(2, (uint64_t)isr2, 0x08, 0x8E);
   idtSet(3, (uint64_t)isr3, 0x08, 0x8E);
   idtSet(4, (uint64_t)isr4, 0x08, 0x8E);
   idtSet(5, (uint64_t)isr5, 0x08, 0x8E);
   idtSet(6, (uint64_t)isr6, 0x08, 0x8E);
   idtSet(7, (uint64_t)isr7, 0x08, 0x8E);
   idtSet(8, (uint64_t)isr8, 0x08, 0x8E);
   idtSet(9, (uint64_t)isr9, 0x08, 0x8E);
   idtSet(10, (uint64_t)isr10, 0x08, 0x8E);
   idtSet(11, (uint64_t)isr11, 0x08, 0x8E);
   idtSet(12, (uint64_t)isr12, 0x08, 0x8E);
   idtSet(13, (uint64_t)isr13, 0x08, 0x8E);
   idtSet(14, (uint64_t)isr14, 0x08, 0x8E);
   idtSet(15, (uint64_t)isr15, 0x08, 0x8E);
   idtSet(16, (uint64_t)isr16, 0x08, 0x8E);
   idtSet(17, (uint64_t)isr17, 0x08, 0x8E);
   idtSet(18, (uint64_t)isr18, 0x08, 0x8E);
   idtSet(19, (uint64_t)isr19, 0x08, 0x8E);
   idtSet(20, (uint64_t)isr20, 0x08, 0x8E);
   idtSet(21, (uint64_t)isr21, 0x08, 0x8E);
   idtSet(22, (uint64_t)isr22, 0x08, 0x8E);
   idtSet(23, (uint64_t)isr23, 0x08, 0x8E);
   idtSet(24, (uint64_t)isr24, 0x08, 0x8E);
   idtSet(25, (uint64_t)isr25, 0x08, 0x8E);
   idtSet(26, (uint64_t)isr26, 0x08, 0x8E);
   idtSet(27, (uint64_t)isr27, 0x08, 0x8E);
   idtSet(28, (uint64_t)isr28, 0x08, 0x8E);
   idtSet(29, (uint64_t)isr29, 0x08, 0x8E);
   idtSet(30, (uint64_t)isr30, 0x08, 0x8E);
   idtSet(31, (uint64_t)isr31, 0x08, 0x8E);

    idtSet(32, (uint64_t)irq0, 0x08, 0x8E);
    idtSet(33, (uint64_t)irq1, 0x08, 0x8E);
    idtSet(34, (uint64_t)irq2, 0x08, 0x8E);
    idtSet(35, (uint64_t)irq3, 0x08, 0x8E);
    idtSet(36, (uint64_t)irq4, 0x08, 0x8E);
    idtSet(37, (uint64_t)irq5, 0x08, 0x8E);
    idtSet(38, (uint64_t)irq6, 0x08, 0x8E);
    idtSet(39, (uint64_t)irq7, 0x08, 0x8E);
    idtSet(40, (uint64_t)irq8, 0x08, 0x8E);
    idtSet(41, (uint64_t)irq9, 0x08, 0x8E);
    idtSet(42, (uint64_t)irq10, 0x08, 0x8E);
    idtSet(43, (uint64_t)irq11, 0x08, 0x8E);
    idtSet(44, (uint64_t)irq12, 0x08, 0x8E);
    idtSet(45, (uint64_t)irq13, 0x08, 0x8E);
    idtSet(46, (uint64_t)irq14, 0x08, 0x8E);
    idtSet(47, (uint64_t)irq15, 0x08, 0x8E);
   /* Load IDT Table */
   idtInit();
}

void idtSet(uint8_t number, uint64_t base, uint16_t selector, uint8_t flags) {
   /* Set Base Address */
   idt[number].baseLow = base & 0xFFFF;
   idt[number].baseMid = (base >> 16) & 0xFFFF;
   idt[number].baseHigh = (base >> 32) & 0xFFFFFFFF;

   /* Set Selector */
   idt[number].selector = selector;
   idt[number].flags = flags;

   /* Set Reserved Areas to Zero */
   idt[number].reservedIst = 0;
   idt[number].reserved = 0;
}



#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#endif

void isrHandler(struct registers * regs) {

//    Video video;
    if ( regs->intNo == 14)
    {
        video.setPosition(10,10);
        uint64_t faulting_address;
        asm volatile("mov %%cr2, %0" : "=r" (faulting_address));

        // The error code gives us details of what happened.
        int present   = !(regs->errCode & 0x1); // Page not present
        int rw = regs->errCode & 0x2;           // Write operation?
        int us = regs->errCode & 0x4;           // Processor was in user-mode?
        int reserved = regs->errCode & 0x8;     // Overwritten CPU-reserved bits of page entry?
        int id = regs->errCode & 0x10;          // Caused by an instruction fetch?

       video.putString("Page fault! ( ",COLOR_BLUE,COLOR_WHITE);
       video.putHexa(regs->errCode,COLOR_BLUE,COLOR_WHITE);
       video.putString(", ",COLOR_BLUE,COLOR_WHITE);
       if (present) {video.putString("present ",COLOR_BLUE,COLOR_WHITE);}
       if (rw) {video.putString("read-only ",COLOR_BLUE,COLOR_WHITE);}
       if (us) {video.putString("user-mode ",COLOR_BLUE,COLOR_WHITE);}
       if (id) {video.putString("Inst. fetch ",COLOR_BLUE,COLOR_WHITE);}
       if (reserved) {video.putString("reserved ",COLOR_BLUE,COLOR_WHITE);}
       video.putString(") at 0x",COLOR_BLUE,COLOR_WHITE);
       video.putHexa(faulting_address,COLOR_BLUE,COLOR_WHITE);
       video.putString("\n",COLOR_BLUE,COLOR_WHITE);
    }
    else
    {
//	This is  where the GPF Message get displayed
        video.setPosition(10,10);
        video.putString("Error Code: ",COLOR_BLUE,COLOR_WHITE);
        video.putHexa(regs->errCode,COLOR_BLUE,COLOR_WHITE);
        video.putString("\n",COLOR_BLUE,COLOR_WHITE);
    }
    return;
}


#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#endif


void irq_handler(registers * regs)
{
    if ( regs->intNo == 42)
    {
        uint8_t oldx = video.getPositionX();
        uint8_t oldy = video.getPositionY();
        video.setPosition(45,2);
        video.putString("I am here 1",COLOR_BLUE,COLOR_WHITE);
        video.setPosition(oldx,oldy);
    }
    else if (interrupt_handlers[regs->intNo] == 0)
    {

        uint8_t oldx = video.getPositionX();
        uint8_t oldy = video.getPositionY();
        video.setPosition(45,3);
        video.putString("Got Interrupt",COLOR_BLUE,COLOR_WHITE);
        video.putDecimal(regs->intNo,COLOR_BLUE,COLOR_WHITE);
        video.setPosition(oldx,oldy);
    }
    if (interrupt_handlers[regs->intNo] != 0)
    {
        isr_t handler = interrupt_handlers[regs->intNo];
        handler(regs);
    }


    // Send an EOI (end of interrupt) signal to the PICs.
    // If this interrupt involved the slave.
        if (regs->intNo >= 40)
        {
            // Send reset signal to slave.
            Ports::outportb(PIC2_COMMAND, 0x20);
        }
        // Send reset signal to master. (As well as slave, if necessary).
        Ports::outportb(PIC1_COMMAND, 0x20);


    if ( regs->intNo == 42)
    {
        uint8_t oldx = video.getPositionX();
        uint8_t oldy = video.getPositionY();
        video.setPosition(45,2);
        video.putString("I am here 2",COLOR_BLUE,COLOR_WHITE);
        video.setPosition(oldx,oldy);
    }

}

static void timer_callback(registers * regs)
{
    tick++;
//    Video video;
    video.setPosition(50,12);
    if ( regs->intNo == 32)
    {
        video.putString("Tick: ",COLOR_BLUE,COLOR_WHITE);
        video.putDecimal(tick,COLOR_BLUE,COLOR_WHITE);
        video.putString("\n",COLOR_BLUE,COLOR_WHITE);
    }
}

static void keyboard_callback(struct registers * regs)
{

    unsigned char status = Ports::inportb(0x64);
    unsigned char sc = Ports::inportb(0x60);
//    Video video;
    if ( sc&0x80)
    {
    }
    else
    {
        video.setPosition(40,15);
        video.putString("IRQ: ",COLOR_BLUE,COLOR_WHITE);
        video.putHexa(regs->intNo,COLOR_BLUE,COLOR_WHITE);
        video.putString(", Status: ",COLOR_BLUE,COLOR_WHITE);
        video.putHexa(status,COLOR_BLUE,COLOR_WHITE);
        video.putString("\n",COLOR_BLUE,COLOR_WHITE);
        video.setPosition(40,16);
        char mychar = kbdus[sc];
        video.putString("Got Character: ",COLOR_BLUE,COLOR_WHITE);
        video.putCharacter((char)mychar,COLOR_BLUE,COLOR_WHITE);
        video.putString("\n",COLOR_BLUE,COLOR_WHITE);
    }
}


void init_timer(uint32_t frequency)
{
    // Firstly, register our timer callback.
    register_interrupt_handler(IRQ0, &timer_callback);
    register_interrupt_handler(IRQ1, &keyboard_callback);


    // The value we send to the PIT is the value to divide it's input clock
    // (1193180 Hz) by, to get our required frequency. Important to note is
    // that the divisor must be small enough to fit into 16-bits.
    uint32_t divisor = 1193180 / frequency;

    // Send the command byte.
    Ports::outportb(0x43, 0x34);

    // Divisor has to be sent byte-wise, so split here into upper/lower bytes.
    uint8_t l = (uint8_t)(divisor & 0xFF);
    uint8_t h = (uint8_t)( (divisor>>8) & 0xFF );

    // Send the frequency divisor.
    Ports::outportb(0x40, l);
    Ports::outportb(0x40, h);
}


unsigned int createMask(unsigned a, unsigned b)
{
   unsigned r = 0;
   for (unsigned i=a; i<=b; i++)
       r |= 1 << i;

   return r;
}

#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#endif


void kernel_main()
{
	video.initialize();
	video.clearScreen(COLOR_BLACK);
	idtStart();
	init_timer(50);
	asm volatile ("sti");
}


Thanks a lot,

Karim

Re: General Protection Fault upon return from Intterupt hand

Posted: Thu Mar 27, 2014 10:08 am
by iansjack
Why do you push and pop register rsp?

Re: General Protection Fault upon return from Intterupt hand

Posted: Thu Mar 27, 2014 10:12 am
by Combuster
And everything that's not a #PF is a #GPF - including interrupts...?

Re: General Protection Fault upon return from Intterupt hand

Posted: Thu Mar 27, 2014 10:33 am
by sortie
Okay, here's a bunch of stuff I see that other people might or might not already have mentioned:

Since no one linked it yet, please have a very close look at http://wiki.osdev.org/James_Molloy%27s_Known_Bugs. You are making a lot of stupid mistakes that you got from that tutorial. Please step back and reconsider everything it does, it's well-known to be buggy. In particular, your interrupt stuff here is really bad and you don't understand it well enough to debug this simple stuff yourself.

You clear interrupts when you enter the interrupt handler, but as described in my above link, that's stupid and you should just decide whether you want interrupts on when you set the IDT entries.

You are pushing the general purpose registers onto the kernel stack before you have changed the the data segment. You don't need to change the stack segment, since the CPU does that for you. I forgot if any of this is even needed on x86_64.

Don't push and pop rsp! This might or might not be a bug. There is absolutely no reason to do so. There is no need to do that, it was saved by the CPU when you entered the interrupt handler. There is no real need for pushAll and popAll macros, I recommend you simply inline those where they are needed. It makes it simpler to reason about your interrupt handlers.

Don't move rsp into rax and then push rax. You can just push rsp directly.

There is no need to pop rax after calling your interrupt handler. You don't actually care about its value. Just add 8 to rsp and that's equivalent to removing one 64-bit general purpose register from the stack.

Your isrCommon and irq_common_stub routines should be identical in purpose. You should combine them into a single routine that passes control to C. You can then check the interrupt number when in C to detect if it was an ISR or IRQ. Having two functions just asks for bugs where you forgot to update one place. Indeed, they are not identical right now!

(What's up with irq_common_stub doing port IO? Perhaps that's left behind debug stuff. I recommend you remove such debug stuff when asking for help.)

(Your assembly indention seems slight off. Also you can't entirely seem to decide on what naming convention to use.)

Code: Select all

char exception_messages[32][64]
That should probably just be something like:

Code: Select all

const char* exception_messages[32]/code]

[code]
#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#else
extern
#endif
What the **** are you doing? Is this C or C++? You already know the answer, so delete the preprocessor conditionals and just leave the extern magic for your particular language. That is, extern "C" for C++, and nothing for C (extern is implied for C functions that are not static). Also, the comment says that this is for kernel_main, but this isn't for kernel_main. (I originally wrote that processor block for Bare Bones and the intention was that you just removed it if you didn't work in C++.)

Your code is generally fairly bad and you have inherited a bunch of the bad style from the tutorial you followed. I recommend you try cleaning it up considerably and really think through the stuff you are doing. I get the feeling you are trying to do things `your way' and try to be different (such as putting memset in a C++ namespace), but you are not good enough at designing kernels yet, so your design is really not better than doing things more conventionally. I advise you to not trying to to be clever, but correct. (My original kernel looked a lot like what you are doing right now, and I've spent way too much time cleaning up my early design mistakes, many of which I got from the tutorial you are following.)