Page 1 of 1

GDT: Jumps to wrong memory after reloading registers

Posted: Sat Nov 18, 2017 3:45 pm
by Luca1
Hello everyone,

after reading through a lot of the wiki pages/tutorials I decided to setup my own GDT, however as soon as I reload any of the registers ds, ss and cs there's a jump to a completely wrong address for some reason and that causes a crash.

To store the address and size used when executing "lgdt" i used this struct:

Code: Select all

struct gdt_info {
	unsigned int address;
	unsigned short size;
} __attribute__((packed));
And to store a single gdt entry I used this struct:

Code: Select all

struct gdt_entry {
	unsigned char upperBase; // Bits 24 to 31 of base address
	unsigned char config; //Flags in the upper 4 bits and Limit from 16-19 in the lower four
	unsigned char access; //Access byte
	unsigned char middleBase; // Bits 16 to 23 of base address
	unsigned short lowerBase; //Bits 0 to 15 of base address
	unsigned short limit; //Lower limit(Bits 0 to 15)
} __attribute__((packed));
Then I define an array of 3 of the structs containing the null descriptor, the kernel data segment and the kernel code segment:

Code: Select all

struct gdt_entry nullDescriptor = {
		.upperBase = 0,
		.config = 0,
		.access = 0,
		.middleBase = 0,
		.lowerBase = 0,
		.limit = 0
	};
	gdt_entries[0] = nullDescriptor;
	/* 0x9A = 10011010 0xC=1100 */
	gdt_entries[1] = gdt_makeEntry(0, 0xFFFFF, 0x9A, 0xC);
	/* 0x92 = 10010010 */
	gdt_entries[2] = gdt_makeEntry(0, 0xFFFFF, 0x92, 0xC);
With make_entry doing this:

Code: Select all

struct gdt_entry gdt_makeEntry(unsigned int base, unsigned int limit, unsigned char access, unsigned char flags){
	struct gdt_entry newEntry = {
		.upperBase = (base & 0xFF000000) >> 24,
		.config = ((flags & 0x0F) << 4) | ((limit & 0xF0000) >> 16),
		.access = access,
		.middleBase = (base & 0x00FF0000) >> 16,
		.lowerBase = (base & 0x0000FFFF),
		.limit = (limit & 0x0FFFF)
	};
	return newEntry;
}
I'm using following assembler functions to lgdt:

Code: Select all

global load_gdt
;load_gdt Loads a GDT, with the first argument being the address to a gdt_info struct
;Stack: [esp+4] Address to gdt_info struct
;	[esp] Return address
load_gdt:
	mov eax, [esp+4]
	lgdt [eax]
	ret
When stepping through this with GDB I checked if eax contained the correct address and it did, and the size and address of the GDT were also correct.
Now here comes the problematic code:

Code: Select all

global gdt_setRegisters
;gdt_setRegisters Sets the required cs, ss and ds registers
;Stack:
;	[esp] Return address
gdt_setRegisters:
	jmp 0x08:flush_cs ;And then flush it

flush_cs:
	; And we are with cs = [esp+2]
	mov ax, 0x10
	mov ds, ax
	mov ss, ax
	ret
As soon as the jmp is executed the executions jumps to a seemingly random address in memory resulting, sooner or later, in a crash. I also tried swapping around the flushing of the CS register and the setting of ds and ss, but I still get the same Problem it jumps to a bogus address once reaching the first instructions that modifies any of cs, ds and ss.

While single stepping through GDB I also noticed that the "disassemble" command doesn't recognise the far jump, but instead displays (BAD).

I hope you can help me.

Regards,
Luca

Re: GDT: Jumps to wrong memory after reloading registers

Posted: Sat Nov 18, 2017 3:58 pm
by iansjack
The only reason I can think of for the code to jump to a seemingly random location is that you are getting an exception, but haven't set up the IDT and exception handlers.

Re: GDT: Jumps to wrong memory after reloading registers

Posted: Sat Nov 18, 2017 4:01 pm
by Luca1
iansjack wrote:The only reason I can think of for the code to jump to a seemingly random location is that you are getting an exception, but haven't set up the IDT and exception handlers.
I didn't, but from my last understanding this should Triple fault my CPU, shouldn't it?
And even then something is still wrong if I'm getting an exception and I'm quite confused why considering my GDT is seemingly correct(According to GDB, if you want I can post the path I followed)

Re: GDT: Jumps to wrong memory after reloading registers

Posted: Sat Nov 18, 2017 9:17 pm
by MichaelPetch
Luca1 wrote:

Code: Select all

struct gdt_info {
	unsigned int address;
	unsigned short size;
} __attribute__((packed));
First thing I see here is that the size and address are reversed. Should be:

Code: Select all

struct gdt_info {
	unsigned short size;
	unsigned int address;
} __attribute__((packed));
This is a known bug in the Little OS Book tutorial. I assume that you got this definition from that tutorial or someone who relied on that tutorial.

Re: GDT: Jumps to wrong memory after reloading registers

Posted: Sun Nov 19, 2017 1:06 am
by Luca1
MichaelPetch wrote:
Luca1 wrote:

Code: Select all

struct gdt_info {
	unsigned int address;
	unsigned short size;
} __attribute__((packed));
First thing I see here is that the size and address are reversed. Should be:

Code: Select all

struct gdt_info {
	unsigned short size;
	unsigned int address;
} __attribute__((packed));
This is a known bug in the Little OS Book tutorial. I assume that you got this definition from that tutorial or someone who relied on that tutorial.
Yeah I kinda followed along this tutorial. I turned around the order of the gdt_info and gdt_entry structs and now it works perfectly!
Thank you very much!