Page 1 of 1
Setting segment registers in long mode illegal?
Posted: Sun Oct 31, 2021 5:50 pm
by angods
Is it illegal? When I try to do it, it triple faults immediately.
Do segment registers serve any purpose in long mode?
Re: Setting segment registers in long mode illegal?
Posted: Sun Oct 31, 2021 6:38 pm
by Octocontrabass
angods wrote:Is it illegal? When I try to do it, it triple faults immediately.
Most instructions to set segment registers work the same in 64-bit long mode as they do in protected mode, including the part where they load a segment descriptor into the hidden descriptor part of the segment register. A triple fault indicates an issue with your GDT, your LDT, your choice of selector, or your choice of instruction.
angods wrote:Do segment registers serve any purpose in long mode?
In compatibility mode, segment registers behave the same way they do in protected mode.
In 64-bit mode, most functions of segmentation go away, but some of them still work. CS still determines the current privilege level. FS and GS still have base addresses. SS is given a new function as a flag to indicate privilege level changes.
Re: Setting segment registers in long mode illegal?
Posted: Sun Oct 31, 2021 6:59 pm
by angods
Octocontrabass wrote:angods wrote:Is it illegal? When I try to do it, it triple faults immediately.
Most instructions to set segment registers work the same in 64-bit long mode as they do in protected mode, including the part where they load a segment descriptor into the hidden descriptor part of the segment register. A triple fault indicates an issue with your GDT, your LDT, your choice of selector, or your choice of instruction.
angods wrote:Do segment registers serve any purpose in long mode?
In compatibility mode, segment registers behave the same way they do in protected mode.
In 64-bit mode, most functions of segmentation go away, but some of them still work. CS still determines the current privilege level. FS and GS still have base addresses. SS is given a new function as a flag to indicate privilege level changes.
My GDT is exactly the same as in
https://wiki.osdev.org/Setting_Up_Long_Mode, so I'm sure it's valid.
But I just realised it only causes a triple fault when modifying ss.
Re: Setting segment registers in long mode illegal?
Posted: Sun Oct 31, 2021 9:35 pm
by deadmutex
The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 4:49 am
by angods
deadmutex wrote:The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
It didn't change anything. I found a 'solution' though. Apparently, ss can be set to 0x0 (null segment). I'm not sure if it's ok to do that though.
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 5:18 am
by iansjack
deadmutex wrote:The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
I don't think it makes any difference, does it? Isn't that bit just ignored for data segment descriptors?
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 5:23 am
by iansjack
angods wrote:deadmutex wrote:The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
It didn't change anything. I found a 'solution' though. Apparently, ss can be set to 0x0 (null segment). I'm not sure if it's ok to do that though.
I'm pretty sure that only the system should set SS to 0 (during interrupts). In any case, you are just masking the problem.
What value are you trying to use for SS, are you in kernel or user mode, and are you sure it refers to a valid data selector?
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 5:29 am
by angods
angods wrote:deadmutex wrote:The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
It didn't change anything. I found a 'solution' though. Apparently, ss can be set to 0x0 (null segment). I'm not sure if it's ok to do that though.
It can't be '0' though, because IRETQ throws #GP when it's 0. I must find a different solution.
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 5:32 am
by iansjack
angods wrote:It can't be '0' though, because IRETQ throws #GP when it's 0. I must find a different solution.
Yes it can be 0. It's the way that the processor marks nested interrupts in long mode.
I get the impression that you are just trying things at random that you have seen on the Internet (including this forum). Have you actually read the manufacturer's Programmer's Manual on the subject?
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 5:48 am
by angods
iansjack wrote:angods wrote:deadmutex wrote:The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
It didn't change anything. I found a 'solution' though. Apparently, ss can be set to 0x0 (null segment). I'm not sure if it's ok to do that though.
I'm pretty sure that only the system should set SS to 0 (during interrupts). In any case, you are just masking the problem.
What value are you trying to use for SS, are you in kernel or user mode, and are you sure it refers to a valid data selector?
Code: Select all
PRESENT equ 1 << 7
NOT_SYS equ 1 << 4
EXEC equ 1 << 3
DC equ 1 << 2
RW equ 1 << 1
ACCESSED equ 1 << 0
GRAN_4K equ 1 << 7
SZ_32 equ 1 << 6
LONG_MODE equ 1 << 5
GlobalDescriptorTable64:
dw GDTEnd64 - GDTStart64 - 1
dq GDTStart64
GDTStart64:
GDTEntry64_0: dd 0, 0 ;NULL
GDTEntry64_1:
dd 0xFFFF
db 0
db PRESENT | NOT_SYS | EXEC | RW | 0xF
db GRAN_4K | LONG_MODE
db 0
GDTEntry64_2:
dd 0xFFFF
db 0
db PRESENT | NOT_SYS | RW | 0xF
db GRAN_4K
db 0
GDTEnd64:
I can never be 100% sure, but this is the code.
Code: Select all
lgdt [GlobalDescriptorTable64]
jmp 0x8:LongModeMain ;Where 0x8 is code segment
Code: Select all
LongModeMain:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
xor ax, ax ;If I don't xor it, it crashes
mov ss, ax
I'm in kernel mode. I mean.. I don't even know. I didn't do anything with permission level yet..
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 6:08 am
by angods
iansjack wrote:angods wrote:It can't be '0' though, because IRETQ throws #GP when it's 0. I must find a different solution.
Yes it can be 0. It's the way that the processor marks nested interrupts in long mode.
I get the impression that you are just trying things at random that you have seen on the Internet (including this forum). Have you actually read the manufacturer's Programmer's Manual on the subject?
I try to reference intel's manual(s) whenever I can, but finding some information is hard.
And the Intel ISA manual mentions that 'If the stack segment selector is NULL going back to compatibility mode,' #GP is thrown.
https://www.felixcloutier.com/x86/iret:iretd
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 8:44 am
by Doctor5555
You are currently using
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
The '| 0xF' on the Access byte of that data segment descriptor may be setting a bit that should be zero - the AMD manual suggests that bit 11 in the upper dword should be 0 and bit 12 should be 1, and my code triple faults when I have bit 11 set. Bit 12 is set correctly by NOT_SYS.
You may also want to remove the '| 0xF' from your code segment descriptor to make the code cleaner, although it will probably have no effect on the outcome.
'0x0000920000000000' works for me as the full data segment entry, and you seem to be using '0x00A09
F000000FFFF', while removing the '| 0xF' should give you '0x00A09
2000000FFFF', which should at least work. Please correct me if I've mis-counted the bytes somewhere there.
You can view the full AMD manual
here, and the relevant section is Volume 2 Chapter 4 sections 7 (legacy) and 8 (long mode). I'd recommend bookmarking that link, and I've found the AMD manuals to be easier to navigate than Intel's, although that is probably just personal preference.
If this works for you, the wiki page should probably be updated.
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 9:26 am
by nexos
One thing I want to add is that I used to ask questions about basic x86 stuff here. I soon realized that the only way to truly understand x86 is to look at the manuals. I have to thank @iansjack for pointing me to the manuals instead of just giving me the answer here. Trust, me it works!
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 9:32 am
by deadmutex
iansjack wrote:deadmutex wrote:The 'LONG_MODE' flag should not be set for data segment descriptors. It's only used to indicate a 64-bit code segment:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | 0xF ; Access
db GRAN_4K | LONG_MODE ; Flags
db 0 ; Base (high)
Try removing it and see if it changes anything.
I don't think it makes any difference, does it? Isn't that bit just ignored for data segment descriptors?
For the L bit, the manual specifically says:
When not in IA-32e mode or for non-code segments, bit 21 is reserved and should always be set to 0.
Also, the access and flag bits for the data segment are wrong. It should be:
Code: Select all
.Data: equ $ - GDT
dd 0xFFFF ; Limit & Base (low)
db 0 ; Base (mid)
db PRESENT | NOT_SYS | RW | DC ; Access
db GRAN_4K | SZ_32 ; Flags
db 0 ; Base (high)
EDIT: Fixed formatting
Re: Setting segment registers in long mode illegal?
Posted: Mon Nov 01, 2021 11:12 am
by Octocontrabass
Doctor5555 wrote:The '| 0xF' on the Access byte of that data segment descriptor may be setting a bit that should be zero - the AMD manual suggests that bit 11 in the upper dword should be 0 and bit 12 should be 1, and my code triple faults when I have bit 11 set. [...] If this works for you, the wiki page should probably be updated.
The wiki page needs to be updated either way. The 0xF is supposed to be the upper 4 bits of the limit, which is part of the flags byte, not the access byte.
The AMD manual gives the impression that only the present bit matters for data segments, but I can't say the same for Intel. However, both manuals do say that system calls require particular descriptors for SS, so you should match your descriptor for SS with the descriptor used by SYSCALL/SYSENTER.