OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Apr 16, 2024 3:46 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Long mode sign extending bit 31?
PostPosted: Fri Oct 03, 2014 8:50 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 21, 2011 9:47 pm
Posts: 286
Location: Tustin, CA USA
Hi,

I have run into an issue that I cannot figure out and I have been fighting for about a week now. It's time to ask for a push in the right direction.

From what I can tell from Bochs and QEMU, it appears that addresses are being sign-extended from bit 31, rather than from bit 47. My final GDT is located at address 0xc0102000. I would expect that canonical address to be 0x00000000_c0102000. However, Bochs and QEMU both report it as 0xffffffff_c0102000.

The following is the log from Bochs:
Code:
00018229330i[BIOS  ] Booting from 07c0:0000
00089457289e[CPU0  ] interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x0
00089457289e[CPU0  ] interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x0
00089457289i[CPU0  ] CPU is in long mode (active)
00089457289i[CPU0  ] CS.mode = 64 bit
00089457289i[CPU0  ] SS.mode = 64 bit
00089457289i[CPU0  ] EFER   = 0x00000500
00089457289i[CPU0  ] | RAX=00000000c0101000  RBX=00000000000b8000
00089457289i[CPU0  ] | RCX=00000000e0000011  RDX=0000000000000000
00089457289i[CPU0  ] | RSP=00000000c0103000  RBP=0000000000000000
00089457289i[CPU0  ] | RSI=0000000000000000  RDI=0000000000007000
00089457289i[CPU0  ] |  R8=0000000000000000   R9=0000000000000000
00089457289i[CPU0  ] | R10=0000000000000000  R11=0000000000000000
00089457289i[CPU0  ] | R12=0000000000000000  R13=0000000000000000
00089457289i[CPU0  ] | R14=0000000000000000  R15=0000000000000000
00089457289i[CPU0  ] | IOPL=0 ID vip vif ac vm RF nt of df if tf sf ZF af PF cf
00089457289i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
00089457289i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 00000fff 1 0
00089457289i[CPU0  ] |  DS:0010( 0002| 0|  0) 00000000 00000fff 1 0
00089457289i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 00000fff 1 0
00089457289i[CPU0  ] |  ES:0010( 0002| 0|  0) 00000000 00000fff 1 0
00089457289i[CPU0  ] |  FS:0010( 0002| 0|  0) 00000000 00000fff 1 0
00089457289i[CPU0  ] |  GS:0010( 0002| 0|  0) 00000000 00000fff 1 0
00089457289i[CPU0  ] |  MSR_FS_BASE:0000000000000000
00089457289i[CPU0  ] |  MSR_GS_BASE:0000000000000000
00089457289i[CPU0  ] | RIP=00000000c010100b (00000000c010100b)
00089457289i[CPU0  ] | CR0=0xe0000011 CR2=0xffffffffc0102002
00089457289i[CPU0  ] | CR3=0x00001000 CR4=0x00000020
(0).[89457289] [0x00000010100b] 0008:00000000c010100b (unk. ctxt): lgdt ds:0xffffffffc0102000 ; 0f011425002010c0
00089457289e[CPU0  ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00089457289i[SYS   ] bx_pc_system_c::Reset(HARDWARE) called


I believe this telling me that I am in long mode (not compatibility mode). Paging is on and I have my virtual addresses properly mapped (virtual 0xc0102000 it at physical 0x00102000). The instruction causing me the issue is "lgdt" and it is causing a #PF at 0xffffffff_c0102000. I have no interrupt table, so it leads to a triple fault.

I found a similar issue with the jump from compatibility mode to full long mode and I overcame the issue with the following code:
Code:
         xor         rax,rax
         lea         eax,[StartHigherHalf]
         push      rax
         ret


I am basically forcing the upper dword to be 0 (faking a sign extension from bit 47). I was happy to have this working, but now I really believe I was covering up the real problem.

NOTE: The code says higher-half, but it is not really higher half -- I know there is a discrepancy and I don't believe it is relevant to my question. But I want to call it out anyway.

On one hand, I have been staring at my GDT descriptors for a while thinking that something in there is my problem. I'm losing confidence that that is really where my issue lies. I also wonder if I managed to get a flag wrong in a control register.

In short, can someone please shove me in the right direction to look in order to get the sign extension from bit 47 rather than at 31? Please let me know if there is anything in particular you would like to see.


Thanks if advance for the assistance!

_________________
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber


Top
 Profile  
 
 Post subject: Re: Long mode sign extending bit 31?
PostPosted: Fri Oct 03, 2014 9:33 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

eryjus wrote:
In short, can someone please shove me in the right direction to look in order to get the sign extension from bit 47 rather than at 31? Please let me know if there is anything in particular you would like to see.


The instruction encodings were designed for 32-bit and then recycled for 64-bit. This means that 64-bit immediate operands almost don't exist (but not quite, there's a special "mov" instruction), and for most cases the CPU will only sign extend 32-bit immediate operands.

Some assemblers aren't very good at detecting things like "constant too large", and will only check if (e.g.) the constant 0x89ABCDEF will fit in 32 bits and won't care about the difference between "unsigned 32-bit" and "signed 32-bit" or complain that 0x89ABCDEF is too large for signed 32-bit.

The combination of both these things mean that (for assembly) you need to be extremely careful when working with 64-bit values in the range 0x0000000080000000 to 0x00000000FFFFFFFF. I can almost guarantee that this is the problem (e.g. some instruction/s somewhere that's used an "impossible to encode" 64-bit immediate value that the assembler accepted because it fits in 32-bits).

Also note that (due to the way instructions are encoded), it's much more efficient for 64-bit code to use virtual addresses in the range 0x0000000000000000 to 0x000000007FFFFFFF and in the range 0xFFFFFFFF80000000 to 0xFFFFFFFFFFFFFFFF. For virtual addresses outside this range code ends up slower because it has to work around the "32-bit only for most immediate operands" limitation.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Long mode sign extending bit 31?
PostPosted: Fri Oct 03, 2014 10:59 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 21, 2011 9:47 pm
Posts: 286
Location: Tustin, CA USA
Brendan wrote:
I can almost guarantee that this is the problem (e.g. some instruction/s somewhere that's used an "impossible to encode" 64-bit immediate value...


Bloody hell!!

LGDTappears to be one of those instructions. I changed the virtual address to be 0x40000000 and everything worked fine. I need to try the other end of the virtual address space, but that is not going to happen tonight.

Brendan wrote:
it's much more efficient for 64-bit code to use virtual addresses in the range 0x0000000000000000 to 0x000000007FFFFFFF and in the range 0xFFFFFFFF80000000 to 0xFFFFFFFFFFFFFFFF


So if I understand correctly, (in assembly) unless I want to jump through the hoops of bit-twiddling all immediate values and memory references in long mode I'm better off keeping my virtual memory map to 4GB, split into 2 X 2GB contiguous memory pools? I assume that higher level languages take care of this automatically and it would be invisible to me as a developer, in the end providing a greater memory pool.

If this is the case, then I am honestly trying to figure out the benefit of long mode.... The only thing I can come up with is that there is more physical memory available which will result in much less swapping virtual memory pages to disk.


Anyway, Brendan, you were spot-on as always. Thanks for the help!

_________________
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber


Top
 Profile  
 
 Post subject: Re: Long mode sign extending bit 31?
PostPosted: Fri Oct 03, 2014 11:32 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

eryjus wrote:
Brendan wrote:
I can almost guarantee that this is the problem (e.g. some instruction/s somewhere that's used an "impossible to encode" 64-bit immediate value...


Bloody hell!!

LGDTappears to be one of those instructions. I changed the virtual address to be 0x40000000 and everything worked fine. I need to try the other end of the virtual address space, but that is not going to happen tonight.


:)

eryjus wrote:
Brendan wrote:
it's much more efficient for 64-bit code to use virtual addresses in the range 0x0000000000000000 to 0x000000007FFFFFFF and in the range 0xFFFFFFFF80000000 to 0xFFFFFFFFFFFFFFFF


So if I understand correctly, (in assembly) unless I want to jump through the hoops of bit-twiddling all immediate values and memory references in long mode I'm better off keeping my virtual memory map to 4GB, split into 2 X 2GB contiguous memory pools? I assume that higher level languages take care of this automatically and it would be invisible to me as a developer, in the end providing a greater memory pool.


For higher level languages, the compiler takes care of it and you just end up with less efficient code. For assembly you need to take care of it yourself, and still end up with less efficient code.

Note that the "32-bit immediates" problem only applies to immediates. For things like dynamically allocated memory (where you can't hard-code the address into the instruction to begin with) there is no problem.

Basically (for efficiency); for processes you want ".text", ".data" and ".bss" to be in the first 2 GiB of the virtual address space, with dynamically allocated stuff (heap, stack) anywhere you like; and for the kernel you want ".text", ".data" and ".bss" to be in the last 2 GiB of the virtual address space, with dynamically allocated stuff (heap, stack) anywhere you like. You'll find that almost all 64-bit OSs do this (Windows, Linux, etc).

eryjus wrote:
If this is the case, then I am honestly trying to figure out the benefit of long mode.... The only thing I can come up with is that there is more physical memory available which will result in much less swapping virtual memory pages to disk.


Erm, no. You can use PAE (e.g. in 32-bit protected mode) to access the same amount of physical memory as you can in long mode.

The benefits of long mode are:
  • Much larger virtual address spaces (256 TiB per virtual address space, instead of 4 GiB)
  • Support for 64-bit code
  • Less "historical baggage" to worry about (e.g. you don't need to check if the CPU supports FPU, MMX, SSE, etc because all CPUs that support long mode support a minimum set of features)
The benefits of 64-bit code are:
  • Twice as many registers, which can improve performance (less "spilling" to/from stack)
  • Twice as wide registers, which can improve performance (especially when working with 64-bit integers)
  • The ability to use the much larger virtual address spaces that long mode provides (64-bit pointers)

Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 57 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group