For the first question, it can be done in various ways. It can be done by the firmware or the bootloader for you, or you can do it by yourself once the platform jumps to your kernel code upon machine startup.
For the second question, you just build your GDT entries with the highest privelege, then you switch to protected mode.
I understand about that you build your GDT entries and mark them all with privilege bit set to 0. However at that point your kernel is still sitting as a compressed image on disk. This is the disconnect I seem to have. We have an in memory data structure that's the GDT and we have kernel image that still on disk. How are those GDT entries allocated to the kernel?
As you observed before, real mode is also privileged. Both before and immediately after enabling protected mode, the code segment you are running from is already "ring 0" (even if it wasn't loaded from a GDT descriptor), and so it is allowed to transfer control to the "proper" kernel code segment.
Thank you. For clarification is that same code segment from real mode sort of automatically "remapped" then to a descriptor in the GDT after CPU transitions into protected mode? Is that correct mental model?
The OS (or loader) is responsible for setting up descriptors and managing memory. In 64-bit and most 32-bit kernels, segmentation is basically not used anymore, and the descriptors are just flat address spaces (all start at 0, no limit) with different privilege levels.
Example of 32 bit flat GDT:
0000 (null descriptor; reserved by hardware and can't be used)
0008 kernel code (ring 0)
0010 kernel data (ring 0)
0018 user code (ring 3)
0020 user data (ring 3)
0028 TSS (hardware defined structure)
Isolation between processes would then be done through the page mapping mechanism. This is kind of hard to wrap your head around at first, but makes it much easier to allocate memory. One big problem with using segments instead of fixed-size pages is that when you need to free them in some random order, memory becomes fragmented.
But you can also have segments in addition to paging, which is helpful for transitioning from/to 16-bit mode.
Sorry "remapping" was a poor choice of words on my part.
What I meant was the code segment register gets reloaded to some offset in that GDT that has those protection bits set to 0. According to your flat address space map above that would be at offsets 0008 and 0010. That makes a lot of sense, thanks.
For the second question, you just build your GDT entries with the highest privelege, then you switch to protected mode.