0

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.

Maxim Blinov
  • 886
  • 9
  • 33
  • 2
    Try forcing it to a 32-bit operand using `ljmpl $0x8, $0x80000` . In AT&T syntax `ljmp` will assume 16 bit-operand (16:16ptr) when using `.code16` where as `ljmpl` will assume ptr16:32. – Michael Petch Sep 05 '16 at 03:09
  • @MichaelPetch: For code that will run after switching to 32-bit protected mode, shouldn't you use a `.code32` directive so the assembler makes the right choice about prefixes to override the operand-size and address-size? Oh, actually I think http://wiki.osdev.org/Protected_Mode implies that the far-jump is decoded in 16-bit mode, and executing it is what switches to a 32-bit code segment. The OP's `[enable protected mode]` made it sound like that was already done, since it wasn't just a comment describing the jump. – Peter Cordes Sep 05 '16 at 08:24
  • @MichaelPetch `ljmpl $0x8, $0x80000` does indeed work! – Maxim Blinov Sep 05 '16 at 13:22
  • 1
    @PeterCordes : Yes, I assumed from the code comments that prior to the `ljmp` he had flipped on the protected mode bit in _CR0_. Although one is in protected mode at that point you are still using 16-bit operands and addresses and the _CS_ being used is still the real mode segment in the CPUs descriptor cache. Until you do a far JMP or CALL via a 32-bit selector you won't be using 32-bit addresses and operands so `.code16` still applies. You need to force it to a 32-bit operand with the 0x66 32-bit operand prefix. – Michael Petch Sep 05 '16 at 13:49

0 Answers0