Getting GDT to work on AT&T asm

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
solidwarea
Posts: 1
Joined: Mon Feb 03, 2025 3:23 pm

Getting GDT to work on AT&T asm

Post by solidwarea »

Hello all. I'm quite new to this so please do bare with me.
I'm trying to set up GDT and GDT reload for my kernel written in C. The example code in the osdev wiki is written in NASM i believe, I've been trying to convert it to AT&T but I keep getting triple faults. Any advice would be appreciated.

Relevant section in boot.S

Code: Select all

.section .data
gdtr:
	.word 0
	.long 0x00000000

.section .text
.global setGDT
setGDT:
	movw 8(%esp), %ax
	movw %ax, gdtr
	movl 12(%esp), %eax
	movl %eax, gdtr + 2
	lgdt gdtr
	ret

.section .text
.global reloadSegments
reloadSegments:
   ljmp $0x08, $.reload_CS

.reload_CS:
   movw $0x10, %ax
   movw %ax, %ds
   movw %ax, %es
   movw %ax, %fs
   movw %ax, %gs
   movw %ax, %ss
   ret



Relevant code in kernel.c

Code: Select all

struct GDT {
    uint32_t base;
    uint32_t limit;
    uint8_t access;
    uint8_t flags;
};

void encodeGdtEntry(uint8_t *target, struct GDT source)
	{
    
    	target[0] = source.limit & 0xFF;
    	target[1] = (source.limit >> 8) & 0xFF;
    	target[6] = (source.limit >> 16) & 0x0F;
    
    	target[2] = source.base & 0xFF;
    	target[3] = (source.base >> 8) & 0xFF;
    	target[4] = (source.base >> 16) & 0xFF;
    	target[7] = (source.base >> 24) & 0xFF;
    
    	target[5] = source.access;
    
    	target[6] |= (source.flags << 4);
	}

extern void setGDT(uint16_t limit, uint32_t base);
extern void reloadSegments(void);

void GdtSetup() {
	
	uint32_t gdt[3 * 8];


	struct GDT segmnt_null = {0, 0x00000000, 0x00, 0x0};
	struct GDT segmnt_code = {0, 0xFFFFF, 0x9A, 0xC};
	struct GDT segmnt_data = {0, 0xFFFFF, 0x92, 0xC};


	encodeGdtEntry((uint8_t*)&gdt[0], segmnt_null);
	encodeGdtEntry((uint8_t*)&gdt[1], segmnt_code); 
	encodeGdtEntry((uint8_t*)&gdt[2], segmnt_data);

	uint16_t limit = (sizeof(gdt) - 1);
	uint32_t base = (uint32_t)&gdt;

	setGDT(limit, base);
}

Octocontrabass
Member
Member
Posts: 5695
Joined: Mon Mar 25, 2013 7:01 pm

Re: Getting GDT to work on AT&T asm

Post by Octocontrabass »

solidwarea wrote: Mon Feb 03, 2025 3:43 pmI keep getting triple faults. Any advice would be appreciated.
Use your virtual machine's debugging functionality to examine the CPU state at the time the triple fault occurs. For example, QEMU has a "-d int" option that will log the CPU state every time an interrupt occurs, including when that interrupt is an exception. (QEMU has some other options to stop it from rebooting each time there's a triple fault, too.)

For example, when the exception occurs, you might see that the GDTR is incorrect, and then you'd examine your code to set the GDTR and see if you could spot a bug that might cause the GDTR to contain the wrong values. Like, perhaps, setGDT reading its arguments from the wrong location on the stack.
MichaelPetch
Member
Member
Posts: 813
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Getting GDT to work on AT&T asm

Post by MichaelPetch »

One problem I notice is:

Code: Select all

void GdtSetup() {
	
	uint32_t gdt[3 * 8];
You can't place the GDT on the stack. Once the function goes out of scope then the stack space where the GDT was can me changed by future pushes and pops corrupting the GDT. Move the gdt array outside of GdtSetup to global scope or make it static.
Post Reply