GDT generates Triple Fault
Posted: Sat Nov 17, 2018 3:11 pm
Hello, this is my first topic at this forum so forgive me if I make a mistake.
I started developing a kernel to learn more about how OSes work, when I realized, I was implementing the GDT to leave real mode and enter protected mode. For my surprise, when I had my kernel built and running on QEMU I was able to see how the kernel generates a triple fault and how it is rebooting endlessly.
Before you ask, all my structures are properly packed.
My loader.asm:
My kernel.c:
My gdt.h:
I'm not a native english speaker, sorry if there are mistakes. Thank all of you in advance.
I started developing a kernel to learn more about how OSes work, when I realized, I was implementing the GDT to leave real mode and enter protected mode. For my surprise, when I had my kernel built and running on QEMU I was able to see how the kernel generates a triple fault and how it is rebooting endlessly.
Before you ask, all my structures are properly packed.
My loader.asm:
Code: Select all
bits 32
section .text
align 4
dd 0x1BADB002
dd 0x00
dd - (0x1BADB002+0X00)
global start
extern kmain
start:
cli
call kmain
hlt
Code: Select all
#include "include/headers/screen.h"
#include "include/headers/string.h"
#include "include/headers/keyboard.h"
#include "include/headers/system.h"
#include "include/headers/idt.h"
#include "include/headers/interrupts.h"
#include "include/headers/gdt.h"
#include "include/headers/shell.h"
#include "include/headers/memory.h"
#include "tests.h"
void run_tests(){
//MEMORY TESTS
//test_memcccpy();
test_memchr();
//test_memcmove();
//test_memcmp();
test_memcpy();
//test_memset();
//STRING TESTS
}
kmain() {
clearScreen();
print("Running lib tests....");
run_tests();
gdt_init();
print("Global Descriptor Table initialized\n");
shell_main();
outportb(0xf4, 0x00);
}
Code: Select all
#ifndef OSFROMSCRATCH_GDT_H
#define OSFROMSCRATCH_GDT_H
#include "types.h"
#define KERNEL_CS 0X08
#define KERNEL_DS 0x10
#define GDT_ENTRIES 4
typedef struct {
//pointer is 32 bits long
//limit is 20 bits long
uint16 limit_low;//16 bits
uint16 pointer_low;//16 bits low pointer
uint8 pointer_middle;//1byte high of low pointer
uint8 access;//1 byte of access or type
uint8 granularity;//high 4 bits for flags, low 4 bits for limit
uint8 pointer_high;//1 byte left for the pointer
}__attribute__((packed)) gdt_entry_t;
/**
* Pointer with limit and base
*/
typedef struct{
uint16 limit;
uint32 base;
}__attribute__((packed)) gdt_limit_ptr_t;
//0-> null entry
//1-> reserved entry
//2-> CS entry
//3-> DS entry
//4-> TSS entry
//5-> USER entry
//6-> LDT entry
//7-> second TSS entry(only if we need it)
//8,9-> reserved for future entries
gdt_entry_t gdt_entry[GDT_ENTRIES];
gdt_limit_ptr_t gdt_limit_ptr;
/**
* Function to flush or init
*/
void gdt_set();
/**
* It prepares the structs for being used
*/
void gdt_init();
void gdt_set_gate(int n, uint32 base,uint32 limit, uint8 access, uint8 granularity);
//not implemented yet
//TODO Mean to return the actual offset of DS and CS
uint16 code_segment_offset();
uint16 data_segment_offset();
#endif //OSFROMSCRATCH_GDT_H
Code: Select all
void gdt_init(){
//see gdt.h for index
gdt_limit_ptr.limit =(sizeof(gdt_entry_t)*GDT_ENTRIES)-1;
gdt_limit_ptr.base=(uint32)&gdt_entry;
//null entry
gdt_set_gate(0,0,0,0,0);
//reserved entry
gdt_set_gate(1,0,0,0,0);
//code segment entry
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x9A, 0xCF);
//data segment entry
gdt_set_gate(3, 0, 0xFFFFFFFF, 0x92, 0xCF);
//tss entry is called from another file
//user entry
gdt_set();
}
void gdt_set_gate(int n, uint32 base,uint32 limit, uint8 access, uint8 granularity){
gdt_entry[n].pointer_low = (base & 0xFFFF);
gdt_entry[n].pointer_middle = (base >> 16) & 0xFF;
gdt_entry[n].pointer_high = (base >>24) & 0xFF;
gdt_entry[n].limit_low = (limit & 0xFFFF);
gdt_entry[n].granularity=((limit >> 16)&0x0F);
gdt_entry[n].granularity |= (granularity & 0xF0);
gdt_entry[n].access = access;//type
}
void gdt_set(){
__asm__ __volatile__("lgdtl (gdt_limit_ptr)");
__asm__ __volatile__(
"cli\n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movw %ax, %ss \n"
"ljmp $0x08, $next \n"
"next: \n"
);
}