I have the following scenario in my code:
.code16
// NOTE: current CS:IP address is 0x8000:0000
lgdt kernel_gdt_descriptor
// Enable PE bit in cr0 register
mov %cr0, %eax
or %eax, $0x1
mov %eax, %cr0
ljmp 0x8, _pmode_entry
_pmode_entry:
jmp _pmode_entry
I understand that performing a long jump to CS=0x8 will select the first segment descriptor entry, which in my case spans all addressable 32 bit memory, and execution jumps to the location (0x00000000 + _pmode_entry).
This is of course not the actual location of _pmode_entry
, but only the offset. The real, 32 bit location of _pmode_entry is (0x8000 * 16 + 0x0), but I have no idea how to perform a jump to this location, as the CS register is now used to select descriptors, and my following attempt does not compile.
According to an excerpt I found from the Intel developers manual, page 616:
When executing a far jump in real-address or virtual-8086 mode, the processor jumps to the code segment and offset specified with the target operand. Here the target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location (m16:16 or m16:32)
Thus, I understand that the following instruction is legal:
ljump $0x8, $0x0080000
This, in my mind, selects the first segment descriptor, and jumps to the memory location 0x00800000 within that segment. However, GNU AS fails with the message
Error: 16 bit jump out of range
.