Page 1 of 1

HELP ! Paging problems switching to long mode

Posted: Sat Feb 18, 2006 11:32 am
by BigBadBen
Greetings all,

I am writting a small boot loader to enable long mode and jump to some 64 bit code.

However I've hit a problem when enabling paging, I am getting the following messages from bochs:

00119797160i[CPU0 ] compatibility mode
00119797160i[CPU0 ] CS.d_b = 32 bit
00119797160i[CPU0 ] SS.d_b = 32 bit
00119797160i[CPU0 ] EFER = 0x00000500
00119797160i[CPU0 ] | RAX=0000000080000011 RBX=0000000000000000
00119797160i[CPU0 ] | RCX=00000000c0000080 RDX=0000000000000000
00119797160i[CPU0 ] | RSP=0000000000067ed4 RBP=0000000000067ee4
00119797160i[CPU0 ] | RSI=000000000002cb3f RDI=000000000002cb40
00119797160i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00119797160i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00119797160i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00119797160i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00119797160i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00119797160i[CPU0 ] | SEG selector base limit G D
00119797160i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00119797160i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00119797160i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00119797160i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00119797160i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00119797160i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00119797160i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00119797160i[CPU0 ] | MSR_FS_BASE:0000000000000000
00119797160i[CPU0 ] | MSR_GS_BASE:0000000000000000
00119797160i[CPU0 ] | RIP=00000000001000b8 (00000000001000b8)
00119797160i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000080
00119797160i[CPU0 ] | CR3=0x0000000000101010 CR4=0x00000020
00119797160i[CPU0 ] (instruction unavailable) page not present

I have attached my bootloader code. I suspect the page table setup I doing in loader_pae.c is wrong, but I've tried quite a few things :(

Re:HELP ! Paging problems switching to long mode

Posted: Sat Feb 18, 2006 3:26 pm
by JoeKayzA
Hmm, just a moment, you are doing:

Code: Select all

...
   pae_pde[3] = (uint64)(0x600000) << 21;
    pae_pde[3] |= (FIELD_P | FIELD_RW | FIELD_PS);

   pae_pdp[0]  = (uint64)(pae_pde) << 12;
    pae_pdp[0]  |= (FIELD_P | FIELD_RW);
...
AFAICS, pae_pde is in global memory, and I assume it is correctly aligned. Then you put a pointer to pae_pde into the first entry of pae_pdp, right so far. But while you do so, you are shifting the pointer 12 bits to the left, this is wrong, The pointer will go to a completely wrong location then.

Since the pointer to the page directory is aligned on a 4kb boundary, the least significant 12 bits are zero anyway, therefore they are used to put your flags (FIELD_P, FIELD_RW) in there. I guess it's the same with the above values (which you are shifting 21 bits to the left). Just remove the shifting operations, and it *should* work.

cheers Joe

Re:HELP ! Paging problems switching to long mode

Posted: Sun Feb 19, 2006 11:50 am
by BigBadBen
Thanks!, the note about alignment was the real cause of my problems. I orginally did not have the bit shifts in there.

In the end I gave up using C code. I was strugling to get the linker to have the memory as part of the kernel image and have it 4k alligned.

So just I used some ASM code :) and put the page tables after the end of the kernel image.

Code: Select all

PAE_PML4 equ (kernel_end)
PAE_PDP  equ (PAE_PML4 + 0x1000)
PAE_PDE  equ (PAE_PDP +  0x1000)

; setup first pml4 entry.
   mov eax, dword PAE_PDP ; address of first pdp entry.
   or  eax, 3 ; set presnt, r/w, u/s bits
   mov [PAE_PML4], eax
   mov [PAE_PML4 + 4], dword 0x0

; setup first PDP entry.
   mov eax, dword PAE_PDE ; address of first pde entry.
   or  eax, 3 ; set presnt, r/w, u/s bits
   mov [PAE_PDP], eax
   mov [PAE_PDP + 4], dword 0x0

; setup first PDE entry - size flag set, so maps first 2mb of memory
   mov eax, dword 0x0 ; base address of PDE entry.
   or  eax, 131 ; set size, presnt, r/w, u/s bits
   mov [PAE_PDE], eax
   mov [PAE_PDE + 4], dword 0x0

; set CR3 to point to PML4 table (PT4)
   mov   eax, PAE_PML4         ; Pointer to PML4 table (<4GB).
   mov   cr3, eax               ; Initialize CR3 with PML4 base.
kernel_end comes from my linker script:

Code: Select all

{
..... .text, .data, .bss sections go here  ....

    /* symbols to mark end of kernel */
    kernel_end = .; _end = .;
}
Now I get into compatibilty mode, little more work and I should be able to get into long mode.

Re:HELP ! Paging problems switching to long mode

Posted: Sun Feb 19, 2006 12:26 pm
by JoeKayzA
Great!

I'd like to ask you something different however: Do you have any good links about OS development in long mode, besides some threads here in the forum and the MT OSFAQ? I've only seen the AMD docs so far, not much more...

cheers Joe

Re:HELP ! Paging problems switching to long mode

Posted: Mon Feb 20, 2006 12:49 pm
by JAAman
there is a developers message board over at AMD website (cannot remember the URL atm, but search this board for a thread by brandon (i think) where he talks about skipping PMode on LMode initialization and he had a link to it there

and there is of course the Intel docs also (though they arn't much different from the info you have in the AMD docs, sometimes it helps to have multiple references, because they say it a little differently, it may give a different POV, increasing your understanding)

Re:HELP ! Paging problems switching to long mode

Posted: Tue Feb 21, 2006 3:35 pm
by BigBadBen
Anoher document I find useful is the overview document, titled "AMD 64-Bit Technology" "The AMD x86-64 Architecture Overview" doc no. 24108C.

It gets the nitty gritty stuff about long mode & compatiabily mode without all the stuff about the older modes.

The only problem is it assumes in some places pior knowledge of Pmode, but theres pretty of non-reference material & example source code around the web to look .

I still haven't had a chance at getting into long mode proper, my aim is at least to be able to get into some 64bit C code and print "hello world!" :)