Search code examples
cassemblyx86osdevirq

Crash when adding or removing data in code on an IRQ


I am developing an operating system as an hobby, and I'm having a strange issue when handling keyboard IRQ, I don't know why but I'm getting an Invalid Op Code ISR when too few string is presents in the code, and a breakpoint ISR when adding a little more string.

If I add a sufficient amount of string, the code works as excepted, and nothing goes wrong, but I can't just add string in the code and ignore the problem without understanding it...

Here is my ISR/IRQ handler (first argument of the macro is "isr" or "irq", second argument is the c handler, third argument is present only if handling irq)

%macro handler_macro 2-3
    handle_%+%1:
        pusha

        mov ax, ds
        push eax    ; save data segment
        mov esi, eax

        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov gs, ax
        mov fs, ax  ; set data segments

        push esp ; push the stack for the first arg of the c function
        call %2
        pop esp ; pop the pushed stack
        %if %0 = 3
            pop ebx
            mov ebx, esi
            mov ds, bx
            mov es, bx
            mov gs, bx
            mov fs, bx
        %else
            pop eax
            mov eax, esi
            mov ds, ax
            mov es, ax
            mov gs, ax
            mov fs, ax  ; restore data segments
        %endif

        popa

        add esp, 8  ; Remove the 2 params that's left in the stack
        sti          ; reenable interrupts
        iret
%endmacro

And there is the C handler for irq

/*
Structure in .h:
typedef struct reg_s {
    unsigned int eax_save;
    unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
    unsigned int code;
    unsigned int error;
    //unsigned int eip, cs, eflags, useresp, ss;
} reg_t;
*/

void irq_handler(reg_t *test)
    // Getting ISR 6 when all printfs are commented
    //printf("IRQ: %d\n", test->code); Uncommenting this one adds keeps on ISR 6
    //printf("");                      Same
    //printf("");                      Same
    //printf("");                      Uncommenting this one make the program works
    if (handler_fun[test->code] != NULL) {
        void (*fun)(void) = (void (*)(void)) handler_fun[test->code];
        //printf("Fun: %p\n", fun);
        fun();
    }
    pic_send_eio(test->code);
}

In case this could help the value of the fun pointer doesn't change from one test to another, and a difference that could (maybe?) change something is that by uncommenting the 4 printfs, the number of sector readed from disk switch from 45 to 46


Solution

  • In case anyone stumble on this, I found where this was comming from.

    This was a really poor error just based on where I loaded the kernel in memory.

    Basically, at some point when I added some bytes, gcc optimized the program to align the address of the functions correctly in memory, which caused the program to grow slightly more.

    This slight increase in the kernel size made the kernel overwrite the stack a bit, which caused a panic in the system.

    So for anyone who stumble on the same thing : Just check that your kernel and stack are correctly placed (and also that your kernel doesn't overwrite the bootloader by error before you perfom the far jump)

    And another advice that I would give to avoid this dumb kind of error : Just write a multi-stage bootloader, this way you will be able to unlock more memory, put your kernel above the 1MB bareer, and in addition to have a more advanced bootloader, you will not stumble into this kind of error.