I try to create my first os from 0 using different tutorials. Now I have a simple kernel with simple paging, GDT for 64 bit, and entering to long mode. But there is a problem with keyboard interrupts. I read lots of topics about that and I think its a double-fault when start typing. Please, help me to understand and fix this problem. Here is repository with my code https://github.com/alexanderian76/TestOS So, the problem is if I type anything, QEMU resets system instead showing symbols on display. Each interrupt resets it, as I understand. This is my gdt64 and enter to long-mode
gdt64:
dq 0 ; zero entry
.code: equ $ - gdt64 ; new
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
.pointer:
dw $ - gdt64 - 1
dq gdt64
This is enter to long mode.
start:
mov esp, stack_top
call check_multiboot
call check_cpuid
call check_long_mode
call set_up_page_tables ; new
call enable_paging ; new
; print `OK` to screen
mov dword [0xb8000], 0x2f4b2f4f
lgdt [gdt64.pointer]
jmp gdt64.code:long_mode_start
hlt
long_mode_start:
; print `OKAY` to screen
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov rax, 0x2f592f412f4b2f4f
mov qword [0xb8000], rax
call main
hlt
And this is IDT
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define ICW1_INIT 0x10
#define ICW1_ICW4 0x01
#define ICW4_8086 0x01
struct IDT_entry {
unsigned short offset_lowerbits;
unsigned short selector;
unsigned char ist;
unsigned short offset_mid;
unsigned int zero;
unsigned char type_attr;
unsigned int offset_higherbits;
};
//*********************************
extern struct IDT_entry IDT[IDT_SIZE];
void load_idt_entry()
{
for(unsigned long long int t = 0; t < 256; t++) {
IDT[t].offset_lowerbits = (unsigned short)(((unsigned long long int)&isr1 & 0x000000000000ffff));
IDT[t].offset_mid = (unsigned short)(((unsigned long long int)&isr1 & 0x00000000ffff0000) >> 16);
IDT[t].offset_higherbits = (unsigned int)(((unsigned long long int)&isr1 & 0xffffffff00000000) >> 32);
IDT[t].selector = 0x08;
IDT[t].type_attr = 0x8e;
IDT[t].zero = 0;
IDT[t].ist = 0;
RemapPic();
outb(0x21, 0xfd);
outb(0xa1, 0xff);
LoadIDT();
}
}
void outb(unsigned short port, unsigned char val){
asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}
unsigned char inb(unsigned short port){
unsigned char returnVal;
asm volatile ("inb %1, %0"
: "=a"(returnVal)
: "Nd"(port));
return returnVal;
}
void RemapPic(){
unsigned char a1, a2;
a1 = inb(PIC1_DATA);
a2 = inb(PIC2_DATA);
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
outb(PIC1_DATA, 0);
outb(PIC2_DATA, 8);
outb(PIC1_DATA, 4);
outb(PIC2_DATA, 2);
outb(PIC1_DATA, ICW4_8086);
outb(PIC2_DATA, ICW4_8086);
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
}
Sorry, this the first time I ask something here, but I cant solve this problem by myself. Thank you so much!
Your IDT_entry
seems to have the fields in the wrong order. type_attr
should be after the ist
and the zero
should be at the end. Also your POPALL
macro actually has pushes not pops.
diff --git a/long_mode_init.asm b/long_mode_init.asm
index cd64e24..926afae 100644
--- a/long_mode_init.asm
+++ b/long_mode_init.asm
@@ -19,13 +19,13 @@ extern IDT
%endmacro
%macro POPALL 0
- push r11
- push r10
- push r9
- push r8
- push rdx
- push rcx
- push rax
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ pop rax
%endmacro
diff --git a/main.c b/main.c
index b1bfa1c..22ef2fe 100644
--- a/main.c
+++ b/main.c
@@ -41,10 +41,10 @@ struct IDT_entry {
unsigned short offset_lowerbits;
unsigned short selector;
unsigned char ist;
- unsigned short offset_mid;
- unsigned int zero;
unsigned char type_attr;
+ unsigned short offset_mid;
unsigned int offset_higherbits;
+ unsigned int zero;
};
//*********************************
With these changes it does no longer crash.