Page 1 of 1

Far jump in 64bit mode

Posted: Tue Jun 24, 2008 12:03 pm
by sngskunk
How come if I am using nasm in long mode and I change the GDT for example, and I want to set the cs, I cannot do a far jump.

Cannot do:

Code: Select all

[BITS 64]

jmp 0x08:next  ;<-- NASM complains

next:
   hlt

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 12:19 pm
by suthers
What kind of complaining, is it the standard 'invalid combination of opcode and operand', or something else?
Jules

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 12:41 pm
by jnc100
There's no 'jmp ptr16:64' instruction. The assumption is that you'd never want to change cs with a jmp in long mode as flat segments are expected anyway. You can encode the jmp ptr16:32 instruction from a [BITS 32] section to a [BITS 64] section in order to make the initial switch from compatibility mode to long mode.

An (untested) workaround is

Code: Select all

push 0x8
lea rax, [next]
push rax
retf
Regards,
John.

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 2:07 pm
by sngskunk
okay, i will give that a try, thank you.

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 3:43 pm
by sngskunk
Okay well it didn't work here is what bochs gave me:

Code: Select all

00009322702e[CPU0 ] LGDT64_Ms: loaded base64 address is not in canonical form!
00009322702e[CPU0 ] interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0
My code:

Code: Select all

gdtInit:
   lgdt              [gdtP]

	mov		ax, 0x10
	mov		ds, ax
	mov		es, ax
	mov		fs, ax
	mov		gs, ax
	mov		ss, ax	

	push	  0x8
	lea      rax, [gdtInitNext]
	push	  rax
	retf  ;<-- Fails here

gdtInitNext:
	ret

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 4:02 pm
by jnc100
I've just tried that technique (albeit assembled under yasm but it should produce the same code) in my bootloader and it seemed to work fine. Are you definitely in 64-bit long mode (not compatibility), cs.l = 1, cs.d = 0 and assembling in a section with the BITS 64 directive?

Regards,
John.

edit: I note you've just edited your post to change the error message that's produced. The new one seems to imply the error is with the lgdt instruction? If not, suggest you use bochs debugger and examine the value of rax after the lea instruction.

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 4:24 pm
by sngskunk
Here is my GDT:

Code: Select all

gdt[0] = (u64bit)0x0;
gdt[1] = (u64bit)0x390400;
gdt[2] = (u64bit)0x10000;
gdt[3] = (u64bit)0x3F0400;
Is this correct?

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 4:54 pm
by HJED
jnc100 wrote:I've just tried that technique (albeit assembled under yasm but it should produce the same code) in my bootloader and it seemed to work fine. Are you definitely in 64-bit long mode (not compatibility), cs.l = 1, cs.d = 0 and assembling in a section with the BITS 64 directive?

Regards,
John.

edit: I note you've just edited your post to change the error message that's produced. The new one seems to imply the error is with the lgdt instruction? If not, suggest you use bochs debugger and examine the value of rax after the lea instruction.
yasm implemnts 64-bit instructions and addresses difrently from NASM

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 8:22 pm
by sngskunk
okay well i can use yasm but I am have trouble with my make file

Here is what happens:

Code: Select all

build
 |
 |- Makefile
 |- kernel
 |- load.o   <-- is put in build directory when it should be in asm
kernel
 |
 |- asm
     |- load.s
     |- (load.o) <-- load.o should be here
 |- kMain.c
 |- kMain.o
Heres my make script:

Code: Select all

SOURCES=../kernel/asm/load.o ../kernel/kMain.o

CFLAGS=-I ../kernel/include -m64 -nostdlib -nostdinc -nodefaultlibs -fno-builtin -fno-stack-protector
LDFLAGS=-melf_x86_64 -Tlink.ld
ASFLAGS=-felf64

all: $(SOURCES) link 

clean:
	rm *.o ../kernel/asm/*.o ../kernel/*.o kernel

link:
	ld $(LDFLAGS) -o kernel $(SOURCES)

.s.o:
	yasm $(ASFLAGS) $<

Re: Far jump in 64bit mode

Posted: Tue Jun 24, 2008 11:41 pm
by jnc100
HJED wrote:yasm implemnts 64-bit instructions and addresses difrently from NASM
Please provide a bit more information. In what sense?
sngskunk wrote:Here is my GDT:

Code: Select all

gdt[0] = (u64bit)0x0;
gdt[1] = (u64bit)0x390400;
gdt[2] = (u64bit)0x10000;
gdt[3] = (u64bit)0x3F0400;
Is this correct?
Er, no. I don't think so. How did you manage to generate those values? I suggest you break it down field by field and decide exactly what you want to put in each field.

Regards,
John.

Re: Far jump in 64bit mode

Posted: Wed Jun 25, 2008 7:41 am
by sngskunk
Okay so I decided to go back an redo my GDT code but I am getting an error like this below:

Code: Select all

00009340690e[CPU0 ] return_protected: CS selector null
00009340690e[CPU0 ] interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0
My assembly code:

Code: Select all

[BITS 64]

%include "../kernel/include/asm/common.s"

[GLOBAL gdtInit]
[EXTERN gdtP]

gdtInit:
	lgdt	[gdtP]
	
	push	0x08
	lea		rax, [gdtInitFinish]
	push	rax
	retf    ;<--- Code stops here and returns error above

	gdtInitFinish:
		ret
Here is my gdt.c:

Code: Select all

/*
 * Global Descriptor Structure
 */
typedef struct {
	u16bit	limit;
	u16bit	baseLow;
	u08bit	baseMid;
	u08bit	type;
	u08bit	flags;
	u08bit	baseHigh;
} __attribute__((packed)) gdtEntry;

/*
 * Global Descriptor Pointer
 */
typedef struct {
	u16bit	limit;
	u64bit	base;
} __attribute__((packed)) gdtPointer;

/* Setup Table and Pointer */
gdtEntry gdt[4];
gdtPointer gdtP;

void gdtStart(void) {
	/* Create GDT entries */
	gdtSet(0, 0, 0);
	gdtSet(1, 0x9C, 0x20);
	gdtSet(2, 0x90, 0);
	gdtSet(3, 0xFC, 0x20);
	
	/* Create GDT Pointer */
	gdtP.limit = (sizeof(gdtEntry) * 4) - 1;
	gdtP.base = (u64bit)&gdt;
	
	gdtInit();
}

void gdtSet(u08bit number, u08bit type, u08bit flags) {
	/* Set Base and Limit Address */
	gdt[number].baseLow = 0;
	gdt[number].baseMid = 0;
	gdt[number].baseHigh = 0;
	gdt[number].limit = 0;
	
	/* Set Type and Flags */
	gdt[number].type = type;
	gdt[number].flags = flags;
}

Re: Far jump in 64bit mode

Posted: Wed Jun 25, 2008 9:57 am
by sngskunk
Am i creating my GDT correctly, or is in the gdtInit() function?

Any help would be great! Thanks!

Re: Far jump in 64bit mode

Posted: Sun Jul 13, 2008 7:12 pm
by HJED
yasm is different then nasm2 for 64-bit instructions see http://www.tortall.net/projects/yasm/wiki/AMD64

Re: Far jump in 64bit mode

Posted: Mon Jul 14, 2008 4:07 am
by AJ
Hi,

Firstly, have you done a CLI? If not, do you have a valid 64 bit IDT loaded (which handles exceptions and IRQ's at minimum)? If so, check that your IDT entries are really all valid 64 bit versions (even if you are in compatibility mode).

Secondly, the original error you had:
00009322702e[CPU0 ] LGDT64_Ms: loaded base64 address is not in canonical form!
00009322702e[CPU0 ] interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0
is because 64 bit modes require all pointers to be in canonical form. This means that the MSB's of the pointer must all be the same as the last valid MSB (this means bit 47 for the first long mode implementation).

Cheers,
Adam