i am trying to setup GDT from my simple kernel that uses multiboot and i don't know what's happening (i think it's triple fault). when using the qemu monitor trying to debug it but i didn't success addressing the issue so i came here.
here is the code:
// boot.S
#ifndef __BOOT_S
#define __BOOT_S
#define ASM_FILE 1
#include <multiboot.h>
#ifdef ASM_HAS_USCORE
# define EXT(sym) _ ## sym // EXT(main) = _main
#else
# define EXT(sym) sym // EXT(main) = main
#endif
#ifdef __ELF__
# define AOUT_KLUDGE 0
#else
# define AOUT_KLUDGE MULTIBOOT_AOUT_KLUDGE
#endif
#define STACK_SIZE 0x4000
#define MULTIBOOT_HEADER_FLAGS MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | AOUT_KLUDGE
.text
.globl start, _start
.globl __lgdt // , __sgdt
// .globl __lidt, __sidt
__lgdt:
pushl %eax
pushl %ebp
mov %esp, %ebp
cli
pushl (%eax)
lgdt (%esp)
ljmp $0x08, $__flush_end
__flush_end:
popl %eax
popl %ebp
movl %ebp, %esp
start:
_start:
jmp mb_entry
.align MULTIBOOT_INFO_ALIGN
mb_header:
.long MULTIBOOT_HEADER_MAGIC
.long MULTIBOOT_HEADER_FLAGS
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
#ifndef __ELF__
/* header_addr */
.long mb_header
/* load_addr */
.long _start
/* load_end_addr */
.long _edata
/* bss_end_addr */
.long _end
/* entry_addr */
.long mb_entry
#else /* ! __ELF__ */
.long 0
.long 0
.long 0
.long 0
.long 0
#endif /* __ELF__ */
mb_entry:
movl $(stack + STACK_SIZE), %esp
pushl $0
popfl
pushl %ebx
pushl %eax
call EXT(main)
ret
loop:
hlt
jmp loop
.comm stack, STACK_SIZE
#endif
// gdt.h
#include <stdint.h>
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
#define SEG_PRES(x) ((x) << 0x07) // Present
#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
#define SEG_LONG(x) ((x) << 0x0D) // Long mode
#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)
#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3)
#define SEG_DATA_RD 0x00 // Read-Only
#define SEG_DATA_RDA 0x01 // Read-Only, accessed
#define SEG_DATA_RDWR 0x02 // Read/Write
#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed
#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down
#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed
#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down
#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
#define SEG_CODE_EX 0x08 // Execute-Only
#define SEG_CODE_EXA 0x09 // Execute-Only, accessed
#define SEG_CODE_EXRD 0x0A // Execute/Read
#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed
#define SEG_CODE_EXC 0x0C // Execute-Only, conforming
#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed
#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming
#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed
#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(0) | SEG_CODE_EXRD
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(0) | SEG_DATA_RDWR
#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(3) | SEG_CODE_EXRD
#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
SEG_PRIV(3) | SEG_DATA_RDWR
int64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) {
uint64_t descriptor;
// Create the high 32 bit segment
descriptor = limit & 0x000F0000; // set limit bits 19:16
descriptor |= (flag << 8) & 0x00F0FF00; // set type, p, dpl, s, g, d/b, l and avl fields
descriptor |= (base >> 16) & 0x000000FF; // set base bits 23:16
descriptor |= base & 0xFF000000; // set base bits 31:24
// Shift by 32 to allow for low part of segment
descriptor <<= 32;
// Create the low 32 bit segment
descriptor |= base << 16; // set base bits 15:0
descriptor |= limit & 0x0000FFFF; // set limit bits 15:0
return descriptor;
}
struct gdt_pointer_s {
uint16_t size;
uint32_t offset;
} __attribute__((packed));
#ifndef __DEBUG
extern void __lgdt(void* gdtp);
#endif
#ifdef __DEBUG
# define printf __builtin_printf
#endif
int setup_gdt(void) {
uint64_t gdt[5];
gdt[0] = create_descriptor(0, 0, 0);
gdt[1] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL0));
gdt[2] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL0));
gdt[3] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3));
gdt[4] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3));
#ifdef __DEBUG
for (int i = 0; i <= 2; i += 1) {
printf("%lx\n", gdt[i]);
}
#endif
struct gdt_pointer_s gdtp;
gdtp.size = sizeof(gdt) - 1;
gdtp.offset = (uint32_t)&gdt[0];
#ifndef __DEBUG
__lgdt(&gdtp);
#endif
return 0;
}
i did some modifications to the setup_gdt
function where it's know setting the gdt entries to 0xfafafafa
x/64x $esp
00007f9c: 0x0000185b 0x00007fc2 0x00000000 0x00001846
00007fac: 0x00007fc8 0x00000000 0x00000000 0x00000000
00007fbc: 0x2badb002 0x00020000 0x00007fc8 0xfafafafa
00007fcc: 0x00000000 0xfafafafa 0x00000000 0xfafafafa
00007fdc: 0x00000000 0x00000000 0x00000000 0x00008008
00007fec: 0x00010000 0x00000000 0x00000000 0x00000000
....
i was playing around from last night until now also i've searched about it. i searched for it across the internet and found this post on osdev forums but it didn't help.
Thank God Solved.
boot.S:
gdt.h: NOTE: the __lgdt accepts a value not referance and this value must be the gdt decriptor pointer. Thanks to Michael Petch.