Page 13 of 20

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 8:23 am
by zap8600
Octocontrabass wrote:Limine provides a GDT you can use temporarily. You'll need to set up your own GDT at some point, though.
The subject of making the GDT is very confusing to me. Thankfully, I've been looking at some existing code, so I have a (somewhat) good idea about what I need to do. I'll be back, but I'm going to give it a good try before I do.

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 2:37 pm
by zap8600
I don't think I setup my GDT correctly. When booting, the system halts because Limine wasn't able to start the terminal. In the Limine protocol documentation, it says that specific segments are required, but I'm not sure how to set them up. Here is my GDT.

Code: Select all

FullGDT gdt[32] __attribute__((used)) = {{ 
         { 
                 {0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00}, 
                 {0xFFFF, 0x0000, 0x00, 0x9A, (1 << 5) | (1 << 7) | 0x0F, 0x00}, 
                 {0xFFFF, 0x0000, 0x00, 0x92, (1 << 5) | (1 << 7) | 0x0F, 0x00}, 
                 {0xFFFF, 0x0000, 0x00, 0xFA, (1 << 5) | (1 << 7) | 0x0F, 0x00}, 
                 {0xFFFF, 0x0000, 0x00, 0xF2, (1 << 5) | (1 << 7) | 0x0F, 0x00}, 
                 {0x0067, 0x0000, 0x00, 0xE9, 0x00, 0x00}, 
         }, 
         {0x00000000, 0x00000000}, 
         {0x0000, 0x0000000000000000}, 
         {0,{0,0,0},0,{0,0,0,0,0,0,0},0,0,0}, 
 }};
How would I properly setup the GDT?

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 2:52 pm
by Octocontrabass

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 2:57 pm
by zap8600
So then how would I set up the seven descriptors I need? How would I set up 16-bit and 32-bit descriptors?

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 3:17 pm
by Octocontrabass
You can find more information about segment descriptors in the wiki, the Intel manuals, and the AMD manuals.

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 3:47 pm
by zap8600
Octocontrabass wrote:You can find more information about segment descriptors in the wiki, the Intel manuals, and the AMD manuals.
Would this be a 16-bit kernel mode code segment? If not, then what would one look like?

Code: Select all

{0xFFFF, 0x0000, 0x00, 0x9A, (1 << 5) | (0 << 7) | 0x00, 0x00},

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 4:54 pm
by Octocontrabass
zap8600 wrote:Would this be a 16-bit kernel mode code segment?
That's a 64-bit kernel mode code segment.
zap8600 wrote:If not, then what would one look like?
The L and D/B bits determine whether a segment is 16-bit, 32-bit, or 64-bit. Both of those bits need to be clear for a 16-bit code segment.

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 5:13 pm
by zap8600
Octocontrabass wrote: The L and D/B bits determine whether a segment is 16-bit, 32-bit, or 64-bit. Both of those bits need to be clear for a 16-bit code segment.
My bad. Bits are a bit confusing for me, so I'm not exactly sure how to do this. Some help on bits would be great.

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 5:48 pm
by kzinti
zap8600 wrote:My bad. Bits are a bit confusing for me, so I'm not exactly sure how to do this. Some help on bits would be great.
https://www.rapidtables.com/convert/num ... o-hex.html

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 6:09 pm
by zap8600
That's really helpful. Thanks.
I think I might have all the segments done. Does this look right?

Code: Select all

FullGDT gdt[32] __attribute__((used)) = {{
	{
		{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00},
		{0xFFFF, 0x0000, 0x00, 0x9A, 0x08, 0x00},
		{0xFFFF, 0x0000, 0x00, 0x92, 0x08, 0x00},
		{0xFFFFFFFF, 0x0000, 0x00, 0x9A, 0x08, 0x00},
		{0xFFFFFFFF, 0x0000, 0x00, 0x92, 0x08, 0x00},
		{0xFFFF, 0x0000, 0x00, 0x9A, 0x0A, 0x00},
		{0xFFFF, 0x0000, 0x00, 0x92, 0x0A, 0x00},
		{0x0067, 0x0000, 0x00, 0xE9, 0x00, 0x00},
	},
	{0x00000000, 0x00000000},
	{0x0000, 0x0000000000000000},
	{0,{0,0,0},0,{0,0,0,0,0,0,0},0,0,0},
}};
If it is, then I got this warning.

Code: Select all

arch/x86_64/gdt.c:49:18: warning: conversion from 'unsigned int' to 'short unsigned int' changes value from '4294967295' to '65535' [-Woverflow]
   49 |                 {0xFFFFFFFF, 0x0000, 0x00, 0x9A, 0x08, 0x00},
      |                  ^~~~~~~~~~
arch/x86_64/gdt.c:50:18: warning: conversion from 'unsigned int' to 'short unsigned int' changes value from '4294967295' to '65535' [-Woverflow]
   50 |                 {0xFFFFFFFF, 0x0000, 0x00, 0x92, 0x08, 0x00},
      |                  ^~~~~~~~~~
If it isn't, then I don't know what I'm doing wrong.

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 6:24 pm
by Octocontrabass
zap8600 wrote:Does this look right?
No. You're trying to put 32 bits in a space that can only hold 16 bits, and it looks like the G, D/B, and L bits are shifted by 4 bits.

The G, D/B, and L bits all go in the same byte as the upper four bits of the limit.

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 6:51 pm
by zap8600
Octocontrabass wrote: No. You're trying to put 32 bits in a space that can only hold 16 bits, and it looks like the G, D/B, and L bits are shifted by 4 bits.

The G, D/B, and L bits all go in the same byte as the upper four bits of the limit.
So how do I fix the limit because the Limine protocol says that the 32-bit limit has to be 0xffffffff. And can I "un-shift" the bits?

Re: How to make a GDT?

Posted: Fri Oct 28, 2022 11:14 pm
by Octocontrabass
zap8600 wrote:So how do I fix the limit because the Limine protocol says that the 32-bit limit has to be 0xffffffff.
The limit is split into two parts in the GDT. Refer to the data structure to see where all the bits for the limit go.

You'll notice that there are only 20 bits for the limit, which means 0xFFFFFFFF doesn't fit. However, 0xFFFFFFFF bytes is equal to 0xFFFFF pages, and when G=1 the limit is measured in pages instead of bytes. So, you can set the limit to 0xFFFFF and G=1 in your descriptor to meet Limine's requirement for a limit of 0xFFFFFFFF bytes.
zap8600 wrote:And can I "un-shift" the bits?
Yes.

Re: How to make a GDT?

Posted: Sat Oct 29, 2022 2:54 pm
by zap8600
Octocontrabass wrote: The limit is split into two parts in the GDT. Refer to the data structure to see where all the bits for the limit go.

You'll notice that there are only 20 bits for the limit, which means 0xFFFFFFFF doesn't fit. However, 0xFFFFFFFF bytes is equal to 0xFFFFF pages, and when G=1 the limit is measured in pages instead of bytes. So, you can set the limit to 0xFFFFF and G=1 in your descriptor to meet Limine's requirement for a limit of 0xFFFFFFFF bytes.
So does the 0xFFFF limit need to be changed for the 16-bit (and maybe 64-bit) segments?
Octocontrabass wrote: Yes.
So how would I do that? would I do something similar to this?

Code: Select all

(1 << 5) | (1 << 7) | 0x0F

Re: How to make a GDT?

Posted: Sat Oct 29, 2022 3:08 pm
by Octocontrabass
zap8600 wrote:So does the 0xFFFF limit need to be changed for the 16-bit (and maybe 64-bit) segments?
The 16-bit segments are supposed to have a limit of 0xFFFF bytes, so you need to either set the limit to 0xFFFF with G=0 or set the limit to 0xF with G=1. The limit is ignored for 64-bit segments, but it's a good idea to set it to 0xFFFFF with G=1 to ensure compatibility.
zap8600 wrote:So how would I do that? would I do something similar to this?
Yes. That specific example sets G=1, D/B=0, L=1, and the upper four bits of the limit to 0xF.