Here's the code for resetting the segments:
global reloadSegments
section .text
reloadSegments:
; Reload the CS register with an offset of 0x08
jmp 0x08:.reload_CS
.reload_CS:
; Reload data segment registers
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
The jump itself is what crashes the os. Here's the code for loading the gdt:
void lgdt(void* gdt, uint16_t size) {
gdtr.base = (uint32_t)gdt;
gdtr.limit = size-1;
asm __volatile__("lgdt (%0)" : : "r" (&gdtr));
}
The base is 32 bit value while the limit is 16. Here's where I call both functions and fill the gdt:
void initGdt() {
create_descriptor(0, 0, 0, 0);
create_descriptor(1, 0, 0x000FFFFF, (GDT_CODE_PL0));
create_descriptor(2, 0, 0x000FFFFF, (GDT_DATA_PL0));
create_descriptor(3, 0, 0x000FFFFF, (GDT_CODE_PL3));
create_descriptor(4, 0, 0x000FFFFF, (GDT_DATA_PL3));
lgdt(&gdt, sizeof(gdt)-1);
extern void reloadSegments();
reloadSegments();
}
The functions and constants for creating descriptors are all from the gdt tutorial at osdev.org. I'm using the QEMU as a virtual machine with multiboot. Here's a link to the project's github: https://github.com/Wardence1/Basic_OS
I expected os to successfully jump to the reload_CS label and reload the cs register without problem. Thanks in advance for the help!
This answer is the culmination of everything the fine folks in the comments have said. First of all the gdt should be made up of 64 bit entries, not 16 bit. Second of all the limit should be placed in the struct for the gdtr before the base. Third of all I subtracted from gdt's size twice, once in the lgdt function args and once in the lgdt function itself. To make the code safer I switched the "r" with a "m" in the inline asm and passed a value into the gdtr. Thank you all again for the comments and support!