Page 1 of 2

Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 7:34 am
by chris13524
I'm trying to setup my GDT table, however, when I try to assemble it, I get this error:

Code: Select all

src/kernel/gdtasm.s:28: error: instruction not supported in 64-bit mode
Here is my asm code for that section:

Code: Select all

[GLOBAL gdt_flush]
gdt_flush:
   mov eax, [esp+4]
   lgdt [eax]

   mov ax, 0x10
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax
   mov ss, ax
   jmp 0x08:.flush ; this is line 28
.flush:
   ret
I am using nasm, and running it with this flag: '-f elf64'. I do not have any BITS 64 flags at the top of my asm file. UEFI is landing me in 64-bit mode, I am trying to change the GDT.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 7:36 am
by Ycep
Which emulator? QEMU?

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 7:37 am
by chris13524
Lukand wrote:Which emulator? QEMU?
Yes, I am using QEMU, but I don't see how this is related.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 7:41 am
by Octacone
64 bit mode requires 64 bit instructions. Also put "BITS 64" at the top of your 64 bit section.
For example:

Code: Select all

EAX -> RAX
EBX -> RBX
Etc...

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 7:48 am
by jnc100
There is no jmp ptr16:64 instruction, and jmp ptr16:32 is not supported in 64 bit mode.

You probably want to do a far return, e.g.:

Code: Select all

push 0x08
push .flush
retf
Regards,
John.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 7:52 am
by chris13524
jnc100 wrote:There is no jmp ptr16:64 instruction, and jmp ptr16:32 is not supported in 64 bit mode.

You probably want to do a far return, e.g.:

Code: Select all

push 0x08
push .flush
retf
Regards,
John.
My understanding is I need to set the CS register with 0x8, I'm not sure that this does that.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:01 am
by Ycep
octacone wrote:64 bit mode requires 64 bit instructions. Also put "BITS 64" at the top of your 64 bit section.
For example:

Code: Select all

EAX -> RAX
EBX -> RBX
Etc...
Hmmm... this is not correct, since 64 bit archiceture supports RAX, EAX and AX, RBX, EBX and BX, RCX, ECX, CX, ...

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:02 am
by Octacone
chris13524 wrote:
jnc100 wrote:There is no jmp ptr16:64 instruction, and jmp ptr16:32 is not supported in 64 bit mode.

You probably want to do a far return, e.g.:

Code: Select all

push 0x08
push .flush
retf
Regards,
John.
My understanding is I need to set the CS register with 0x8, I'm not sure that this does that.
That is just a blank far jump. You basically jump to a specific far address and return from it.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:14 am
by chris13524
When I replace:

Code: Select all

   jmp 0x08:.flush ; this is line 28
.flush:
   ret
with:

Code: Select all

   push 0x08
   push .flush
   retf
It can't find the .flush symbol:

Code: Select all

src/kernel/gdtasm.s:32: error: symbol `gdt_flush.flush' undefined
I understand why this is happening, but I don't know what you expected me to do. Where should I put the flush symbol?

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:21 am
by jnc100
Keep it wherever it was before. Replace the jmp 0x08:.flush with these three lines and keep the .flush and ret afterwards.

Regards,
John.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:33 am
by chris13524
jnc100 wrote:Keep it wherever it was before. Replace the jmp 0x08:.flush with these three lines and keep the .flush and ret afterwards.

Regards,
John.
I did this, but now it won't link:

Code: Select all

ld: build/kernel/gdtasm.o: relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC
I'm assuming this is because I'm pushing a label, so that would be it's absolute address, rather than a relative one. I tried adding the 'DEFAULT REL' modifier (before and after 'BITS 64'), but it didn't help.

I'm building a shared object so UEFI can run it.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:44 am
by iansjack
The question is, why are you wanting to do such a jump?

64-bit long mode uses a flat address space, so the only real point of changing the CS register is to change to privilege level. A far jump would not be the appropriate way to do this; normally you would do so via a syscall instruction or an interrupt. The sysret, or iret, instruction would then change the privilege level back again - manipulating these instructions can be done to put the processor into user mode initially; after that you shouldn't need to manipulate CS.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 8:53 am
by chris13524
iansjack wrote:The question is, why are you wanting to do such a jump?

64-bit long mode uses a flat address space, so the only real point of changing the CS register is to change to privilege level. A far jump would not be the appropriate way to do this; normally you would do so via a syscall instruction or an interrupt. The sysret, or iret, instruction would then change the privilege level back again - manipulating these instructions can be done to put the processor into user mode initially; after that you shouldn't need to manipulate CS.
I posted here: http://forum.osdev.org/viewtopic.php?f= ... 27#p264327. They told me to setup a GDT. I am now trying to port my previous GDT code from 32 to 64-bits.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 9:09 am
by iansjack
I'd say that the reason that you were given there "to make sure you actually have access to all of the memory space" is invalid (in 64-bit mode). It is certainly true that you will want to create a valid IDT (I've no idea what UEFI sets up) and you may need to modify the GDT that UEFI has provided. But IMO you shouldn't need to do the sort of far jump that you propose.

Re: Long jump in 64-bits: instruction not supported

Posted: Thu Aug 25, 2016 9:37 am
by Octocontrabass
chris13524 wrote:I'm assuming this is because I'm pushing a label, so that would be it's absolute address, rather than a relative one. I tried adding the 'DEFAULT REL' modifier (before and after 'BITS 64'), but it didn't help.
That's because "push .flush" isn't calculating an effective address, it only pushes a fixed value. You need to use an instruction that calculates an effective address, for example:

Code: Select all

    lea rax, [rel .flush]
    push 0x08
    push rax
    retf
.flush:
iansjack wrote:It is certainly true that you will want to create a valid IDT (I've no idea what UEFI sets up) and you may need to modify the GDT that UEFI has provided. But IMO you shouldn't need to do the sort of far jump that you propose.
It's necessary to ensure that CS has a reasonable value so interrupts can return properly. Otherwise, the CS pushed to the stack when an interrupt occurs may not refer to a valid code selector.