0

I have my own OS that I am working on, and I have asked a few questions on before. Currently, the OS works perfectly fine on QEMU, but on real hardware (Tested on an old AMD athlon64 system with IDE drives, and on an intel core i5 system), it fails to handle any keyboard interrupts, and instead, it receives a [#GP0] exception.

I have tried printing the error code received by the interrupt handler, and it is set to 0, which means it is not a segment error. I have tested it on two different machines, both with the same results.

Here is some relevant code:

; Common ISR code
isr_common_stub:
    ; 1. Save CPU state
    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  ; kernel data segment descriptor
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push esp

    ; 2. Call C handler
    call isr_handler
    pop eax

    ; 3. Restore state
    pop eax 
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    popa
    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

; Common IRQ code. Identical to ISR code except for the 'call' 
; and the 'pop ebx'
irq_common_stub:
    pusha
    mov ax, ds
    push eax
    mov ax, 0x10 ;0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push esp                 ; At this point ESP is a pointer to where DS (and the rest
                             ; of the interrupt handler state resides)
                             ; Push ESP as 1st parameter as it's a 
                             ; pointer to a registers_t  
    call irq_handler
    pop ebx                  ; Remove the saved ESP on the stack. Efficient to just pop it 
                             ; into any register. You could have done: add esp, 4 as well
    pop ebx
    mov ds, bx
    mov es, bx
    mov fs, bx
    mov gs, bx
    popa
    add esp, 8
    sti
    iret
static void keyboard_callback(registers_t regs) {
    /* The PIC leaves us the scancode in port 0x60 */
    uint8_t scancode = port_byte_in(0x60);

    //kprint_int(scancode);

    bool iskeyup = false;
    if (scancode >= KEYUPOFFSET) {
        iskeyup = true;
        scancode -= KEYUPOFFSET;
    }

    key_handler(scancode, iskeyup);
    UNUSED(regs);
}
void isr_handler(registers_t *r) {
    kprint("received interrupt: ");
    char s[3];
    int_to_ascii(r->int_no, s);
    kprint(s);
    kprint("\n");
    kprint("error code: ");
    char e[3];
    int_to_ascii(r->err_code, s);
    kprint(s);
    kprint("\n");
    kprint(exception_messages[r->int_no]);
    kprint("\n");
}

void irq_handler(registers_t *r) {
    /* After every interrupt we need to send an EOI to the PICs
     * or they will not send another interrupt again */
    if (r->int_no >= 40) port_byte_out(0xA0, 0x20); /* slave */
    port_byte_out(0x20, 0x20); /* master */

    /* Handle the interrupt in a more modular way */
    if (interrupt_handlers[r->int_no] != 0) {
        isr_t handler = interrupt_handlers[r->int_no];
        handler(r);
    } 
    else {
        if (loaded == 1) {
            kprint("Error! Unhandled interrupt!");
        }
    }
}

And the repo for building: https://github.com/Menotdan/DripOS/tree/dev

I expect that keyboard input should work on the real hardware, not really sure why it doesn't. The emulator is running as x86_64, as is the hardware. But instead of working the OS just receives [GP#0] as fast as it can handle interrupts.

EDIT: Sorry about the link spacing, for some reason StackOverflow thought it was code so I had to add lines between them so it wouldn't complain :/

Menotdan
  • 130
  • 1
  • 11
  • 4
    The question needs to contain the most essential information in the question text ([mre]), not behind external links – Antti Haapala -- Слава Україні Sep 06 '19 at 14:41
  • Well, there is a lot of code, and I'm not entirely sure where the problem is. What parts should I include? (You kind of need the whole OS to test it) but that would also probably be a lot of work if you were to test on real hardware, since that is where the problem is – Menotdan Sep 06 '19 at 14:42
  • 2
    Stack Overflow questions need to be self contained. Remove everything from your code that is not needed to reproduce the problem and then put the reduced code into your question. Your question must be answerable without following any links. – fuz Sep 06 '19 at 14:45
  • Try testing in bochs as that has better low level debug info. – Jester Sep 06 '19 at 14:45
  • 1
    You should not assume that someone here will dig through your whole code to find your bug. The Stackoverflow community does not get paid for answering questions. Try to find your bug yourself, or at least strip down the code so it fits into the question. See also [how to ask](https://stackoverflow.com/help/how-to-ask) – Qw3ry Sep 06 '19 at 15:02
  • @Qw3ry well I guess I am going to link the repo for the reproducible bit, then I can include important parts of the linked files? Also I think the problem is only on real hardware when booting from a USB or something with the ISO written to it – Menotdan Sep 06 '19 at 15:09
  • 1
    Aside: the `cli` and `sti` instructions used are irrelevant in the file `interrupt.asm`. When an interrupt occurs the `IF` control bit is cleared anyway, and `iret` pops the flags register, immediately overwiting whatever you set that flag to. For the problem I suggest making a small test code that explores the keyboard handler specifically. – Weather Vane Sep 06 '19 at 15:10
  • I believe I have edited the question sufficiently. Also, I have a guess at what the problem might be, if that is the problem, then I might just delete the question. The problem that it might be is that ```keyboard_callback``` isn't taking a pointer, so to much of the stack might be read, and then it might cause problems loading other stack values. – Menotdan Sep 06 '19 at 15:19
  • 1
    Note: you are assuming at `rti` that the segment registers all contained the same value, which may not be the case. Also, should you be using `pushad` and `popad` instead of `pusha` and `popa`? – Weather Vane Sep 06 '19 at 15:29
  • @WeatherVane ```pushad``` and ```popad``` is probably correct. This OS is based partly off a tutorial which was based off the James Molloy Tutorial, which does have well-known bugs, which is why I mentioned the ```register_t``` pointer bug – Menotdan Sep 06 '19 at 15:36
  • Im gonna do some more testing soon to see what i can find – Menotdan Sep 06 '19 at 16:05

1 Answers1

0

There were a few problems with the code that I have fixed, and now the OS boots just fine. First problem was that the keyboard driver wasn't taking a pointer as a parameter. The next problem was the use of pusha and popa in interrupt.asm, instead of pushad and popad.

After changing those two things, the OS boots on real hardware.

Menotdan
  • 130
  • 1
  • 11
  • 1
    In 32-bit code `pusha` and `pushad` are the same thing `popa` and `popad` are the same in 32-bit code. – Michael Petch Sep 06 '19 at 17:54
  • Oh well, I guess it was just the ```keyboard_callback``` not taking a pointer. Does that mean that when a parameter is taken in C, the part of the stack that it took up is removed? I guess that because the keyboard function does not do anything with the argument, so I don't think it would be a problem otherwise. – Menotdan Sep 06 '19 at 17:56