I'm a newbie in x86 architecture. Have read several tutorials for setting the GDT, also on this site.
Get always a General Protection Fault (Error code 0), when I try to set the Kernel code segment at the start of the .text section
and Kernel data segment to .data, .bss., etc. No issues when I use 0 for base and 0xFFFFF for limit
Here is my function for setting the entries:
Code: Select all
static void gdt_set_entry(struct gdt_entry *entry,
uint32_t base,
uint32_t limit,
uint8_t access,
uint8_t flags)
{
if (!entry)
return;
entry->lo = (limit & 0xFFFF);
entry->lo |= ((base & 0xFFFF) << 16);
entry->hi = ((base & 0xFF0000) >> 16);
entry->hi |= ((uint32_t) access << 8);
entry->hi |= (limit & 0xF0000);
entry->hi |= (((uint32_t) flags & 0xF) << 20);
entry->hi |= (base & 0xFF000000);
}
Code: Select all
#define GDT_ACCESS_RW 0x02
#define GDT_ACCESS_DIRECTION 0x04
#define GDT_ACCESS_EXEC 0x08
#define GDT_ACCESS_SEGMENT 0x10
#define GDT_ACCESS_RING0 0x00
#define GDT_ACCESS_RING1 0x20
#define GDT_ACCESS_RING2 0x40
#define GDT_ACCESS_RING3 0x60
#define GDT_ACCESS_PRESENT 0x80
#define GDT_FLAG_SIZE 0x04
#define GDT_FLAG_GRAN 0x08
#define GDT_ENTRIES 5
Code: Select all
struct gdt_entry {
uint32_t lo;
uint32_t hi;
};
struct gdt_ptr {
uint16_t limit;
uint32_t ptr;
} __attribute__((packed));
Code: Select all
static void gdt_init(void)
{
/* NULL entry */
gdt_set_entry(&gdt[0], 0, 0, 0, 0);
/* Kernel Code */
gdt_set_entry(&gdt[1], 0, 0xFFFFF, GDT_ACCESS_EXEC |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING0 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
/* Kernel Data */
gdt_set_entry(&gdt[2], 0, 0xFFFFF, GDT_ACCESS_RW |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING0 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
/* User Code */
gdt_set_entry(&gdt[3], 0, 0xFFFFF, GDT_ACCESS_EXEC |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING3 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
/* User Data */
gdt_set_entry(&gdt[4], 0, 0xFFFFF, GDT_ACCESS_RW |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING3 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
gdt_p.ptr = (uint32_t) &gdt[0];
gdt_p.limit = ((sizeof(struct gdt_entry) * GDT_ENTRIES) - 1);
_cpu_gdt_flush((uint32_t) &gdt_p, ((uint32_t )&gdt[2].lo - (uint32_t)&gdt[0].lo));
}
Code: Select all
FUNCTION(_cpu_gdt_flush)
pushl %ebp
movl %esp, %ebp
movl 8(%esp), %eax
lgdt (%eax)
movl 12(%esp), %eax
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
ljmp $0x8, $.1
.1:
leave
ret
Kernel Sections:
.text 0x100000 Size 0x5274
.rodata 0x106000 Size 0x42e
.bss 0x107000 Size 0xcbec
.stack 0x115000 Size 0x4000
Tried it with the following values:
Base 0x100000 Limit: 5 for the code segment
Base 0x106000 Limit: 18 for the data segment
Can somebody explain me please, what I'm doing wrong? Maybe I have misunderstood something.
Edit:
Corrected some typos.