4 ms·
This looks like a nice guide. I had a couple of questions. When reading the "entering protected mode" section I started to question my own understanding of som
by bogomipz 5y ago
This looks like a nice guide. I had a couple of questions.
When reading the "entering protected mode" section I started to question my own understanding of some the details. My first question is:
When a CPU starts up in real mode it's running in a kind of privileged state since there are none of the 4 protection rings that protected mode give us. We then build a GDT and switch the CPU to protected mode. In practical terms where does this code live GDT building and long mode jump code live? Is it in GRUB or whichever stage 2 bootloader is in use?
My second question was about the "chicken and egg" situation about how the kernel code inherits that privileged address space defined marked with ring 0 bits in the GDT. Is magic that once the GDT has been defined, when we subsequently decompresses the kernel into those memory addresses the kernel memory will have ring 0 bits in its descriptors?
This is how I've understood it but I've often found the texts about this a little murky and this part still feels a bit like magic to me I guess.
- afr0ck 5y agoFor 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.
- bogomipz 5y agoI 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?
- rep_lodsb 5y agoAs 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.
- bogomipz 5y agoThank 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?
- rep_lodsb 5y agoNo, how would that even work? 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. Hope that helps at least a little bit!
- bogomipz 5y agoSorry "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.