In x86 processors, the Global Descriptor Table is a data structure that stores characteristics of regions of memory known as “segments”. Example characteristics are the start address of the segment, the size of the segment, and access flags, such as whether the segment is writable or executable. Back in the days of 16-bit addresses, the ability to dynamically switch the current segment allowed programmers to effectively address more 64k.
Nowadays, in 64-bit mode, a Global Descriptor Table must still be set up, largely for legacy reasons it seems. Certain instructions, notably those which move control between distant virtual address (such as returning from a system call), take a segment index as an argument, and change the current segment in addition to the current instruction pointer address.
Typically the GDT has at least 2 entries (in addition to the mandatory null entry at index 0) - one for code, and a second for data. I’m not sure whether it’s necessary to have one such pair for the kernel, and a second pair of segments for user-mode. My current goal is to get the kernel-to-user-mode switch to happen at all, then go over everything I’m doing and make sure I’m doing it “right”. Once I have a basic user-mode “thread” running, I’ll do a longer write-up explaining how to get from zero to this point.
A page that turned out to be of great practical use: Builing a UEFI x64 kernel from scratch: A long trip to userspace