do not edit — generated by btf.
git.druid.rocksindexdruid520kaboomsrc/kernel/gdt.nsc

src/kernel/gdt.nsc


/*
 * kernel-owned gdt: null, kernel code, kernel data. boot.s's own gdt64
 * (in its .rodata, built entirely by hand in raw asm) only exists to
 * get the cpu into long mode at all -- this replaces it with one the
 * kernel actually manages, so a tss entry (needed once idt.nsc wants
 * a dedicated interrupt stack) or user-mode segments (needed once elf
 * programs run in ring 3) have somewhere real to go later.
 *
 * gdt entries can't be a `struct` (nsc struct fields are word
 * addressed, not byte-packed -- see the note in vga.nsc/kmain.nsc for
 * the general version of this constraint) so each entry is packed
 * into a u64 by hand, same technique proven while learning nsc's
 * pointer model, then stored with one 8-byte *ptr write.
 */
 
void load_gdt(ptr gdtr_addr);
 
global i8 gdt_table[24];
global i8 gdtr[10];
 
void
gdt_set_entry(i32 idx, u32 base, u32 limit, u8 access, u8 gran)
{
	ptr slot;
	u64 lo;
	u64 hi;
	u64 packed;
 
	lo = (u64)(limit & (u32)0xffff);
	lo = lo | ((u64)(base & (u32)0xffffff) << (u64)16);
	lo = lo | ((u64)access << (u64)40);
 
	hi = (u64)((limit >> (u32)16) & (u32)0x0f);
	hi = hi | (u64)gran;
	hi = hi | ((u64)((base >> (u32)24) & (u32)0xff) << (u64)8);
 
	packed = lo | (hi << (u64)48);
 
	slot = &gdt_table[0] + idx * 8;
	*slot = (i64)packed;
}
 
global void
gdt_init(void)
{
	ptr tbl;
	u64 addr;
	i32 limit;
	i32 i;
 
	gdt_set_entry(0, 0, 0, (u8)0, (u8)0);         /* null descriptor, required */
	gdt_set_entry(1, 0, 0, (u8)0x9a, (u8)0xa0);   /* 0x08: kernel code, 64-bit (L bit set in gran) */
	gdt_set_entry(2, 0, 0, (u8)0x92, (u8)0xa0);   /* 0x10: kernel data */
 
	limit = 23; /* 3 entries * 8 bytes - 1 */
	gdtr[0] = (i8)(limit & 0xff);
	gdtr[1] = (i8)((limit >> 8) & 0xff);
 
	tbl = &gdt_table[0];
	addr = (u64)tbl;
	i = 0;
	while(i < 8)
	{
		gdtr[2 + i] = (i8)((addr >> (u64)(i * 8)) & (u64)0xff);
		i = i + 1;
	}
 
	load_gdt(&gdtr[0]);
}
powered by btf.