zap8600 wrote:
I meant telling the CPU where the table is.
Create a GDTR descriptor (you can also use a struct) and then use the LGDT instruction to load the GDTR descriptor into GDTR. After you tell the CPU where your GDT is, you should load new selectors into the segment registers. Your code might look something like this, if you use a struct for the GDTR descriptor:
Code:
struct __attribute__((packed)) GDTR
{
uint16_t limit;
uint32_t base;
};
void example( uint32_t base, uint16_t limit )
{
struct GDTR gdtr = { limit, base };
asm( "lgdt %0" :: "m"(gdtr) );
asm( "ljmp %0,$1f\n1:" :: "i"(KERNEL_CODE_SEG) );
asm( "mov %0, %%ds" :: "r"(KERNEL_DATA_SEG) );
asm( "mov %0, %%es" :: "r"(KERNEL_DATA_SEG) );
asm( "mov %0, %%ss" :: "r"(KERNEL_DATA_SEG) );
//asm( "mov %0, %%fs" :: "r"(KERNEL_FS_SEG) );
//asm( "mov %0, %%gs" :: "r"(KERNEL_GS_SEG) );
}
Unlike the earlier example, this struct must be packed because the compiler would insert padding otherwise. Alignment is unnecessary.
zap8600 wrote:
Also, how would I find the values for base_low, mid and high?
Take your base address and put the low 16 bits into base_low, the next 8 bits into base_mid, and the top 8 bits into base_high.
zap8600 wrote:
Same question for limit_low and limit_high_and_flags.
Take your limit and put the low 16 bits into limit_low and the high four bits into limit_high_and_flags. The limit is only 20 bits; it indicates either bytes or pages according to the granularity flag.
zap8600 wrote:
Also, how would I add both limit_high and the flags to limit_high_and_flags?
The high four bits of the limit go into the low four bits of limit_high_and_flags. Four bits of flags go into the high four bits of limit_high_and_flags. You can use bitwise operations to place the values you want in the correct locations. The Intel and AMD manuals have excellent diagrams showing where everything goes.