C Kernel - Runs fine in Qemu but not in VM -
i developing kernel scratch in c. having problem keyboard. in qemu, when press key on keyboard, keypress handled normally. when run in virtualbox or on actual computer, works fine until press key. in virtualbox, when crashes, gives me error code vinf_em_triple_fault. here (important parts) of code:
assembly:
bits 32 section .text ;multiboot spec align 4 dd 0x1badb002 ;magic dd 0x00 ;flags dd - (0x1badb002 + 0x00) global start global keyboard_handler global read_port global write_port global load_idt extern main ;this defined in c file extern keyboard_handler_main read_port: mov edx, [esp + 4] ;al lower 8 bits of eax in al, dx ;dx lower 16 bits of edx ret write_port: mov edx, [esp + 4] mov al, [esp + 4 + 4] out dx, al ret load_idt: mov edx, [esp + 4] lidt [edx] sti ;turn on interrupts ret keyboard_handler: call keyboard_handler_main iretd start: cli ;block interrupts mov esp, stack_space call main hlt ;halt cpu section .bss resb 8192; 8kb stack stack_space:
c (the important parts, omitted parts don't involve keyboard):
struct idt_entry{ unsigned short int offset_lowerbits; unsigned short int selector; unsigned char zero; unsigned char type_attr; unsigned short int offset_higherbits; }; struct idt_entry idt[idt_size]; void idt_init(void) { unsigned long keyboard_address; unsigned long idt_address; unsigned long idt_ptr[2]; /* populate idt entry of keyboard's interrupt */ keyboard_address = (unsigned long)keyboard_handler; idt[0x21].offset_lowerbits = keyboard_address & 0xffff; idt[0x21].selector = kernel_code_segment_offset; idt[0x21].zero = 0; idt[0x21].type_attr = interrupt_gate; idt[0x21].offset_higherbits = (keyboard_address & 0xffff0000) >> 16; /* ports * pic1 pic2 *command 0x20 0xa0 *data 0x21 0xa1 */ /* icw1 - begin initialization */ write_port(0x20 , 0x11); write_port(0xa0 , 0x11); /* icw2 - remap offset address of idt */ /* * in x86 protected mode, have remap pics beyond 0x20 because * intel have designated first 32 interrupts "reserved" cpu exceptions */ write_port(0x21 , 0x20); write_port(0xa1 , 0x28); /* icw3 - setup cascading */ write_port(0x21 , 0x00); write_port(0xa1 , 0x00); /* icw4 - environment info */ write_port(0x21 , 0x01); write_port(0xa1 , 0x01); /* initialization finished */ /* mask interrupts */ write_port(0x21 , 0xff); write_port(0xa1 , 0xff); /* fill idt descriptor */ idt_address = (unsigned long)idt ; idt_ptr[0] = (sizeof (struct idt_entry) * idt_size) + ((idt_address & 0xffff) << 16); idt_ptr[1] = idt_address >> 16 ; load_idt(idt_ptr); } void kb_init(void) { /* 0xfd 11111101 - enables irq1 (keyboard)*/ write_port(0x21 , 0xfd); } void keyboard_handler_main(void) { unsigned char status; char keycode; /* write eoi */ write_port(0x20, 0x20); status = read_port(keyboard_status_port); /* lowest bit of status set if buffer not empty */ if (status & 0x01) { keycode = read_port(keyboard_data_port); if(keycode < 0){ return; } char c = keyboard_map[(unsigned char) keycode]; //keyboard_map converts key codes ascii (prints char) } } } void main(void) { idt_init(); kb_init(); while(1); print("welcome code os"); }
and of course compiled linker. why working in qemu not actual computer? (on actual computer works fine until press key.)
Comments
Post a Comment