Mixing 64 and 32-bit code

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
rdos
Member
Member
Posts: 3310
Joined: Wed Oct 01, 2008 1:55 pm

Mixing 64 and 32-bit code

Post by rdos »

From the Intel 64 and IA-32 Architectures Software Developpers Manual:
In IA-32e mode, bit 21 of the second doubleword of the segment
descriptor indicates whether a code segment contains native 64-bit
code. A value of 1 indicates instructions in this code segment are
executed in 64-bit mode. A value of 0 indicates the instructions in this
code segment are executed in compatibility mode. If L-bit is set, then
D-bit must be cleared. When not in IA-32e mode or for non-code
segments, bit 21 is reserved and should always be set to 0.
Does this mean that a 32-bit OS can execute "as-is" in long mode, just by avoiding ever setting the L bit in the code segment selector? Does it mean that if the OS sets up interrupt handlers in long-mode that have the L bit clear, they will work "as-is" in compability-mode? And would a page-fault handler with a clear L bit work regardless of the mode of the interrupted code? Is it that simple?

If it is, about the only piece of 64-bit software needed in the kernel would be some code that saves/loads 64-bit registers during task-switches. In a low end system, there would be no need to use more than 4G virtual address space, and so memory allocators for 64-bit applications could simply always give them a below 4G address, and then the whole kernel API would also work without translations (addresses usually passed in 32-bit registers would be equal to addresses passed in 64-bit registers).
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Re: Mixing 64 and 32-bit code

Post by JamesM »

rdos wrote:From the Intel 64 and IA-32 Architectures Software Developpers Manual:
In IA-32e mode, bit 21 of the second doubleword of the segment
descriptor indicates whether a code segment contains native 64-bit
code. A value of 1 indicates instructions in this code segment are
executed in 64-bit mode. A value of 0 indicates the instructions in this
code segment are executed in compatibility mode. If L-bit is set, then
D-bit must be cleared. When not in IA-32e mode or for non-code
segments, bit 21 is reserved and should always be set to 0.
Does this mean that a 32-bit OS can execute "as-is" in long mode, just by avoiding ever setting the L bit in the code segment selector? Does it mean that if the OS sets up interrupt handlers in long-mode that have the L bit clear, they will work "as-is" in compability-mode? And would a page-fault handler with a clear L bit work regardless of the mode of the interrupted code? Is it that simple?

If it is, about the only piece of 64-bit software needed in the kernel would be some code that saves/loads 64-bit registers during task-switches. In a low end system, there would be no need to use more than 4G virtual address space, and so memory allocators for 64-bit applications could simply always give them a below 4G address, and then the whole kernel API would also work without translations (addresses usually passed in 32-bit registers would be equal to addresses passed in 64-bit registers).
No - some instructions are not available in 64-bit mode that are available in 32-bit mode. I don't have my manuals with me here, but from memory instructions like INC EAX occupy the same block of instruction space as the REX prefixes, so are not available.
rdos
Member
Member
Posts: 3310
Joined: Wed Oct 01, 2008 1:55 pm

Re: Mixing 64 and 32-bit code

Post by rdos »

JamesM wrote:
rdos wrote:From the Intel 64 and IA-32 Architectures Software Developpers Manual:
In IA-32e mode, bit 21 of the second doubleword of the segment
descriptor indicates whether a code segment contains native 64-bit
code. A value of 1 indicates instructions in this code segment are
executed in 64-bit mode. A value of 0 indicates the instructions in this
code segment are executed in compatibility mode. If L-bit is set, then
D-bit must be cleared. When not in IA-32e mode or for non-code
segments, bit 21 is reserved and should always be set to 0.
Does this mean that a 32-bit OS can execute "as-is" in long mode, just by avoiding ever setting the L bit in the code segment selector? Does it mean that if the OS sets up interrupt handlers in long-mode that have the L bit clear, they will work "as-is" in compability-mode? And would a page-fault handler with a clear L bit work regardless of the mode of the interrupted code? Is it that simple?

If it is, about the only piece of 64-bit software needed in the kernel would be some code that saves/loads 64-bit registers during task-switches. In a low end system, there would be no need to use more than 4G virtual address space, and so memory allocators for 64-bit applications could simply always give them a below 4G address, and then the whole kernel API would also work without translations (addresses usually passed in 32-bit registers would be equal to addresses passed in 64-bit registers).
No - some instructions are not available in 64-bit mode that are available in 32-bit mode. I don't have my manuals with me here, but from memory instructions like INC EAX occupy the same block of instruction space as the REX prefixes, so are not available.
But if I have a register-level API for 32-bit mode, it should be possible to pass these same registers from a 64-bit application that only uses the lower 32-bits of addresses? Of course, 64-bit code cannot pass integer values larger than 32-bit either, but I don't find that too problematic either (there is no API function today that needs to use more than one 32-bit register except for time-stamps). As far as I understand it, EAX is lower 32-bits of RAX and so on?

Just found some other problem with the idea (also from the Intel manual):
In legacy mode, the size of an IDT entry (16 bits or 32 bits) determines the size of
interrupt-stack-frame pushes. SS:ESP is pushed only on a CPL change. In 64-bit
mode, the size of interrupt stack-frame pushes is fixed at eight bytes. This is because
only 64-bit mode gates can be referenced. 64-bit mode also pushes SS:RSP unconditionally,
rather than only on a CPL change.
IOW, long-mode requires a new IDT that only can reference 64-bit code segments. It does sound pretty fatal to the concept, but perhaps not. The worse thing though is related to mode-switches. The only way I can see of switching from 64-bit to 32-bit mode is to do an iret. This requires pushing lots of thing onto the 64-bit stack, and there is too much overhead for the idea to be useful. It is also not allowed for a 32-bit application to use a 32-bit callgate to enter kernel. This would mean fatally degraded performance for syscalls (I have no idea why they made this limitation, it seems totally ad-hoc). :cry:
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Mixing 64 and 32-bit code

Post by gerryg400 »

rdos wrote:Does this mean that a 32-bit OS can execute "as-is" in long mode, just by avoiding ever setting the L bit in the code segment selector? Does it mean that if the OS sets up interrupt handlers in long-mode that have the L bit clear, they will work "as-is" in compability-mode? And would a page-fault handler with a clear L bit work regardless of the mode of the interrupted code? Is it that simple?
No, interrupt handlers have to be 64 bit. However, I guess you could iret to a 32bit code segment to do the work.
rdos wrote:If it is, about the only piece of 64-bit software needed in the kernel would be some code that saves/loads 64-bit registers during task-switches. In a low end system, there would be no need to use more than 4G virtual address space, and so memory allocators for 64-bit applications could simply always give them a below 4G address, and then the whole kernel API would also work without translations (addresses usually passed in 32-bit registers would be equal to addresses passed in 64-bit registers).
Well yes, you would need 64bit isr stubs and 64bit, 4 level page-tables. Most everything else could be 32 bit.
If a trainstation is where trains stop, what is a workstation ?
Post Reply