GDT: Jumps to wrong memory after reloading registers

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
Luca1
Posts: 15
Joined: Tue Apr 11, 2017 11:18 am

GDT: Jumps to wrong memory after reloading registers

Post 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
Last edited by Luca1 on Sat Nov 18, 2017 4:29 pm, edited 1 time in total.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: GDT: Jumps to wrong memory after reloading registers

Post 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.
Luca1
Posts: 15
Joined: Tue Apr 11, 2017 11:18 am

Re: GDT: Jumps to wrong memory after reloading registers

Post 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)
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: GDT: Jumps to wrong memory after reloading registers

Post 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.
Luca1
Posts: 15
Joined: Tue Apr 11, 2017 11:18 am

Re: GDT: Jumps to wrong memory after reloading registers

Post 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!
Post Reply