How to make a GDT?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: How to make a GDT?

Post by nullplan »

zap8600 wrote:So do I need to make a USB controller driver? If I only need to initialize them, then do I use the 1.0, 2.0, or 3.0 controller(s)?
Since USB HCI initialization contains hand-off from BIOS to OS, yes, you really only need to initialize them. And you need to initialize all of the ones you find. Thankfully, for the most part, these days you only have to initialize XHCI, since no other HCIs exist in modern PCs.
Carpe diem!
zap8600
Member
Member
Posts: 195
Joined: Tue Nov 02, 2021 11:26 am
Libera.chat IRC: zap8600

Re: How to make a GDT?

Post by zap8600 »

nullplan wrote: Since USB HCI initialization contains hand-off from BIOS to OS, yes, you really only need to initialize them. And you need to initialize all of the ones you find. Thankfully, for the most part, these days you only have to initialize XHCI, since no other HCIs exist in modern PCs.
Thanks. I'll try to figure out how to initialize XHCI.

I plan on changing my OS to a x86_64 OS. I will use the BOOTBOOT protocol because it has support for booting the kernel from an initial ramdisk, and it can work with multiple platforms (I would like to have my OS run on x86_64 PCs (UEFI & BIOS) and aarch64 (Raspberry Pi 4)). How would I set up the GDT from x86_64, and what is the equivalent of the GDT and IDT in aarch64 (Raspberry Pi 4). How would I enable paging in x86_64 and aarch64?
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: How to make a GDT?

Post by nullplan »

zap8600 wrote:I plan on changing my OS to a x86_64 OS
That is a good idea. Changing from x86 to x86_64 is a change of architecture, and that can be difficult as you start out. So if you start at x86_64, you have less changeover pain.
zap8600 wrote:How would I set up the GDT from x86_64, and what is the equivalent of the GDT and IDT in aarch64 (Raspberry Pi 4). How would I enable paging in x86_64 and aarch64?
The AMD64 GDT is basically the same structure as the i386 one. The only differences are that the system call instructions prescribe a certain order of segments, and that you need two segments wherever you actually specify a nonzero base address (the upper segment containing only the high 32-bits of the base address). But I've only ever needed that for the TSS. The TSS looks different in 64-bit mode, and yes, you still need one if you ever plan to switch to user mode. Consult the Intel SDM vol. 3A or AMD APM vol. 2 for more information (depending on taste, really, they basically contain the same information).

You enable paging on AMD64 the same way you do on i386. In fact, you have no choice but to enable paging, since the instruction that enables paging is the instruction that switches to long mode. The page table format is the same as the PAE format (please consult the SDM or APM for details). Only now the third layer is actually a full layer, not just four entries, and there is a fourth layer of page tables. Otherwise, it is pretty similar, just a nice, hierarchical page table system. Switching CR3 requires the page that the instruction is on to be on the same physical page before and after the switch, so that requirement hasn't changed. Most OSes achieve that by mapping the kernel the same way in all address spaces.

As for AArch64, GDT and IDT are entirely x86-specific concepts and simply don't exist on any other architectures. They are an outgrowth of the 8086's interrupt handling mechanism and the 80286's overloading of the segment registers, respectively, and no other architecture has these chips in its lineage. I am unfamiliar with AArch64 specifically, but I do know ARM8 had its interrupt table at a fixed address in memory (no idea if that was virtual or physical memory, and there were ARM8 chips that didn't have paging at all, making the distinction moot). I do know that most RISC CPUs have only a single exception for "external interrupt", and if you want to know more specifically what interrupt occurred, you need to ask the interrupt controller. In any case, I suggest you get some documentation on AArch64 interrupt handling if the topic interests you. But I would counsel against putting two architectures on your plate from the start. Get your OS going on one arch, then the other.
Carpe diem!
zap8600
Member
Member
Posts: 195
Joined: Tue Nov 02, 2021 11:26 am
Libera.chat IRC: zap8600

Re: How to make a GDT?

Post by zap8600 »

nullplan wrote: That is a good idea. Changing from x86 to x86_64 is a change of architecture, and that can be difficult as you start out. So if you start at x86_64, you have less changeover pain.
That is good to know.
nullplan wrote: The AMD64 GDT is basically the same structure as the i386 one. The only differences are that the system call instructions prescribe a certain order of segments, and that you need two segments wherever you actually specify a nonzero base address (the upper segment containing only the high 32-bits of the base address). But I've only ever needed that for the TSS. The TSS looks different in 64-bit mode, and yes, you still need one if you ever plan to switch to user mode. Consult the Intel SDM vol. 3A or AMD APM vol. 2 for more information (depending on taste, really, they basically contain the same information).
So if I understood correctly, I don't need to learn something new (which usually takes me from a couple of months to a year or two).
nullplan wrote: You enable paging on AMD64 the same way you do on i386. In fact, you have no choice but to enable paging, since the instruction that enables paging is the instruction that switches to long mode. The page table format is the same as the PAE format (please consult the SDM or APM for details). Only now the third layer is actually a full layer, not just four entries, and there is a fourth layer of page tables. Otherwise, it is pretty similar, just a nice, hierarchical page table system. Switching CR3 requires the page that the instruction is on to be on the same physical page before and after the switch, so that requirement hasn't changed. Most OSes achieve that by mapping the kernel the same way in all address spaces.
I don't think I need to do this since I'm using BOOTBOOT, which automatically loads the kernel into higher half and supports x86_64 kernels. I'm not sure how BOOTBOOT sets up paging though (if it even does).
nullplan wrote: As for AArch64, GDT and IDT are entirely x86-specific concepts and simply don't exist on any other architectures. They are an outgrowth of the 8086's interrupt handling mechanism and the 80286's overloading of the segment registers, respectively, and no other architecture has these chips in its lineage. I am unfamiliar with AArch64 specifically, but I do know ARM8 had its interrupt table at a fixed address in memory (no idea if that was virtual or physical memory, and there were ARM8 chips that didn't have paging at all, making the distinction moot). I do know that most RISC CPUs have only a single exception for "external interrupt", and if you want to know more specifically what interrupt occurred, you need to ask the interrupt controller. In any case, I suggest you get some documentation on AArch64 interrupt handling if the topic interests you. But I would counsel against putting two architectures on your plate from the start. Get your OS going on one arch, then the other.
Will do. Thanks.
devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

Re: How to make a GDT?

Post by devc1 »

Just to mention, X64 GDT **must** have base and limit fields set to 0, otherwise it will triple fault on real hardware and Hypervisors.
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: How to make a GDT?

Post by nexos »

devc1 wrote:Just to mention, X64 GDT **must** have base and limit fields set to 0, otherwise it will triple fault on real hardware and Hypervisors.
Citation needed. According to the Intel SDM, base is treated as if it is 0 See below:
Intel SDM wrote:The processor treats the segment base of CS, DS, ES, SS as zero
The limit is treated as infinity. Note that FS and GS are exceptions; the base of their descriptors is used by the CPU. Note that it also provides MSRs so that we can set all 64 bits of the hidden GS.base and FS.base, instead of the 32 bit window the descriptor exposes. But even for FS and GS, the limit is ignored.

EDIT: fix error about limit being treated as 0, clarify about FS and GS.
Last edited by nexos on Wed Oct 12, 2022 4:03 pm, edited 1 time in total.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: How to make a GDT?

Post by nullplan »

nexos wrote:Citation needed. According to the Intel SDM, base and limit are treated as if they are 0.
Yes, Intel SDM and AMD APM both say that the base and limit fields are ignored, the base is treated as zero and the limit as infinity (since it is impossible to give more than a 4GB limit). However, a later extensions allows specifying a segment limit within the highest 4GB of address space, which e.g. the Xen hypervisor uses to hide their code at the top of address space. Since it is also possible that some emulator may be less than perfect, you should specify the base as zero and the limit as 4GB for the normal segments. It doesn't really cost you anything, anyway.

All of this only holds for normal segments, and system segments, like the TSS, must have nonzero base and weird limit, anyway, in order to be useful.
Carpe diem!
linguofreak
Member
Member
Posts: 510
Joined: Wed Mar 09, 2011 3:55 am

Re: How to make a GDT?

Post by linguofreak »

nullplan wrote:
As for AArch64, GDT and IDT are entirely x86-specific concepts and simply don't exist on any other architectures. They are an outgrowth of the 8086's interrupt handling mechanism and the 80286's overloading of the segment registers, respectively, and no other architecture has these chips in its lineage. I am unfamiliar with AArch64 specifically, but I do know ARM8 had its interrupt table at a fixed address in memory (no idea if that was virtual or physical memory, and there were ARM8 chips that didn't have paging at all, making the distinction moot). I do know that most RISC CPUs have only a single exception for "external interrupt", and if you want to know more specifically what interrupt occurred, you need to ask the interrupt controller. In any case, I suggest you get some documentation on AArch64 interrupt handling if the topic interests you. But I would counsel against putting two architectures on your plate from the start. Get your OS going on one arch, then the other.
With respect to the IDT specifically, I'd argue that that's not so much of an outgrowth of Intel segmentation: the 8086 had segments, but a fixed IVT. The VAX was entirely a flat-address-space machine, but had a register that set the base address for a System Control Block, which contained interrupt and exception vectors. And I'd say it's generally good practice in designing a CPU architecture to expose things like that in registers so the OS can put them where it wants them, rather than baking addresses into the microcode.
zap8600
Member
Member
Posts: 195
Joined: Tue Nov 02, 2021 11:26 am
Libera.chat IRC: zap8600

Re: How to make a GDT?

Post by zap8600 »

Does anyone know if the BOOTBOOT protocol allows you to setup the GDT and paging by yourself?
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to make a GDT?

Post by iansjack »

Any boot loader lets you set up your own GDT, IDT, and paging tables.
zap8600
Member
Member
Posts: 195
Joined: Tue Nov 02, 2021 11:26 am
Libera.chat IRC: zap8600

Re: How to make a GDT?

Post by zap8600 »

iansjack wrote: Any boot loader lets you set up your own GDT, IDT, and paging tables.
Can you setup the GDT, the IDT, and paging after the x86_64 kernel starts running?
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to make a GDT?

Post by iansjack »

You need a GDT and paging to be in long mode. But there’s nothing to stop you then creating new ones to your own specification. It’s highly unlikely that you would permanently use those provided by the boot loader.
zap8600
Member
Member
Posts: 195
Joined: Tue Nov 02, 2021 11:26 am
Libera.chat IRC: zap8600

Re: How to make a GDT?

Post by zap8600 »

iansjack wrote: You need a GDT and paging to be in long mode. But there’s nothing to stop you then creating new ones to your own specification. It’s highly unlikely that you would permanently use those provided by the boot loader.
So I can setup paging and the GDT from the kernel? How would I do that?
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to make a GDT?

Post by iansjack »

Exactly the same way that you would in a boot loader. Create the tables, load the appropriate registers, and do a long jump.
zap8600
Member
Member
Posts: 195
Joined: Tue Nov 02, 2021 11:26 am
Libera.chat IRC: zap8600

Re: How to make a GDT?

Post by zap8600 »

iansjack wrote: Exactly the same way that you would in a boot loader. Create the tables, load the appropriate registers, and do a long jump.
Can BOOTBOOT load x86 code? If I understand correctly, BOOTBOOT will need to load the x86 part of the kernel, then the GDT and paging will be setup. Then everything needed to enter long mode will be setup. Once the code enters long mode, the main kernel code can be ran. Or should I just make my own bootloader? If I should, then I would like it to boot from UEFI.
Post Reply