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