Page 1 of 2
64 bit long mode cr0 issue
Posted: Tue Mar 21, 2017 12:04 pm
by Bipman
Hi all
I'm using the code from the 'Setting Up Long Mode' tutorial on this website and all going well so far except when I reach the following code
Code: Select all
mov eax, cr0 ; Set the A-register to control register 0.
or eax, 1 << 31 | 1 << 0 ; Set the PG-bit, which is the 31nd bit, and the PM-bit, which is the 0th bit.
mov cr0, eax ; Set control register 0 to the A-register.
When the code gets to the mov cr0,eax line, it faults the VM i am running it in with a 'Page Table Not Present' error. I've moved the address of the tables (1GB mode so two tables) into the CR3 register so not sure why it's faulting. Any ideas?
Bipman
Re: 64 bit long mode cr0 issue
Posted: Tue Mar 21, 2017 1:28 pm
by bzt
You have to enable big page feature for 1G pages. Run it in bochs, and use "page (address)" in debugger to see where the translation fails.
Re: 64 bit long mode cr0 issue
Posted: Tue Mar 21, 2017 1:34 pm
by Bipman
I'll give it a go thanks!
Re: 64 bit long mode cr0 issue
Posted: Thu Mar 23, 2017 3:05 am
by Bipman
OK, there was an issue with the flags in the PDPE table being wrong (thanks goodness for the Bochs debugger) but I've now sorted that. Trouble is, it triple faults still after I set paging active (no interrupts set up yet) :-
Code: Select all
Next at t=0
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
<bochs:1> c
(0).[92902891] ??? (physical address not available)
Next at t=92902892
(0).[92902892] ??? (physical address not available)
<bochs:2> r
rax: 00000000_e0000011 rcx: 00000000_c0000080
rdx: 00000000_00000000 rbx: 00000000_0000933d
rsp: 00000000_0009ffff rbp: 00000000_00008000
rsi: 00000000_000e0000 rdi: 00000000_00021020
r8 : 00000000_00000000 r9 : 00000000_00000000
r10: 00000000_00000000 r11: 00000000_00000000
r12: 00000000_00000000 r13: 00000000_00000000
r14: 00000000_00000000 r15: 00000000_00000000
rip: 00000000_00009436
eflags 0x00010012: id vip vif ac vm RF nt IOPL=0 of df if tf sf zf AF pf cf
<bochs:3> page 1
PML4: 0x000000000002100b ps a pcd PWT S W P
PDPE: 0x0000000000000081 PS g pat d a pcd pwt S R P
physical address not available for linear 0x0000000000000000
<bochs:4> quit
(0).[92902892] ??? (physical address not available)
The (messy) code for the tables is :-
Code: Select all
mov ax,ds ;start of 64 bit page translation tables
mov es,ax ;
mov edi,PML4E ;
xor ax,ax ;mov 0 to al for storing in tables
mov ecx,0x2000 ;8k for both tables
rep stosb ;store al 8k times
mov eax,PDPE
add eax,0xb ;flags for the first entry in PM4LE
mov [PML4E],eax ;
mov edi,PDPE ;Next the three entries for the 3 gigs of code and memory
mov eax,0x81 ;Flags 0b00000010000001
mov [edi],eax ;store flags+0 base address
;next part of address will be 0 too
mov [edi+4],dword 0 ;store 0 for the next part of the address + 0 in NX bit
add edi,dword 8 ;Next table
mov eax,dword 0x81 ;
bts eax,30 ;set 2GB start
mov [edi],eax ;
xor eax,eax
bts eax,31 ;set 'no eecute' bit as it's data
mov [edi+4],eax
add edi,dword 8 ;next table
mov eax,dword 0x81 ;
bts eax,31 ;3GB
mov [edi],eax
xor eax,eax
bts eax,31 ;no execute bit set as this is data
mov [edi+4],eax
add edi,dword 8
mov eax,0xc0000000 ;4GB
add eax,dword 0x81 ;
mov [edi],eax
xor eax,eax
bts eax,31 ;no execute bit set as this is data
mov [edi+4],eax
add edi,dword 8
mov eax, PML4E ; Pointer to PML4 table (<4GB).
mov cr3, eax ; Initialize CR3 with PML4 base.
It must be an issue with my paging table, I wanted the first 1GB from 0:0 up to 1GB to be a code page and I've set it R/W for now. Can I not use 0:0 as the first address in the table? I'm basically wanting to set the first 1GB to code and the rest to data as there will only be one process running.
Bipman
Re: 64 bit long mode cr0 issue
Posted: Fri Mar 24, 2017 2:57 am
by Bipman
I'm now running in Virtualbox under a 64 bit OS as I discovered the 'other' OS i was using was not 64 bit. Anyway, the same still occurs and a view of the tables shows:-
Code: Select all
VBoxDbg> dptg 0x21000
%%0000000000021000 (index 0x0):
000 %0000000000000000: 0000000000000081 big phys=0000000000000000 p r s na nd avl=00
001 %0000000000200000: 8000000040000081 big phys=0000000040000000 p r s na nd avl=00 NX
002 %0000000000400000: 8000000080000081 big phys=0000000080000000 p r s na nd avl=00 NX
003 %0000000000600000: 80000000c0000081 big phys=00000000c0000000 p r s na nd avl=00 NX
Which looks OK to me. But when I run the following code:-
Code: Select all
mov eax, cr0 ; Read CR0.
bts eax, 31 ; Set PG=1.
mov cr0, eax ; Write CR0.
I get a triple fault with
Code: Select all
eax=80000011 ebx=00000000 ecx=c0000080 edx=00000000 esi=000094d8 edi=00021018
eip=000094b2 esp=0009ffff ebp=00008000 iopl=0 rf nv up di pl zr na po nc
cs=0008 ds=0010 es=0010 fs=0010 gs=0010 ss=0010 eflags=00010046
u: error: DBGCCmdHlpVarToDbgfAddr failed on '0008:000094b2 L 0': VERR_PAGE_TABLE_NOT_PRESENT
If I try and display the tables I get
Code: Select all
dptg 0
%%0000ff53f000f000 (base %0000000000000000 / index 0x0):
error: VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS: Reading PTE memory at %%0000ff53f000f000.
I'm so nearly there but cannot work out what the issue is, any ideas?
Bipman
Re: 64 bit long mode cr0 issue
Posted: Fri Mar 24, 2017 3:49 am
by MDenham
Honestly, it'd help if you'd dump CR0~CR4 after the triple fault also.
Re: 64 bit long mode cr0 issue
Posted: Fri Mar 24, 2017 5:29 am
by Bipman
OK, here they are
Code: Select all
cr0=0000000080000011
cr2=0000000000000080
cr3=0000000000020000
cr4=0000000000000020
cr8=0000000000000000
Bipman
Re: 64 bit long mode cr0 issue
Posted: Fri Mar 24, 2017 11:18 am
by Bipman
Before the Page Fault the table looks OK
Code: Select all
VBoxDbg> dpd
%%0000000000021000 (index 0x0):
000 %0000000000000000: 0000000000000083 big phys=0000000000000000 p w s na nd avl=00
001 %0000000000200000: 8000000040000083 big phys=0000000040000000 p w s na nd avl=00 NX
002 %0000000000400000: 8000000080000083 big phys=0000000080000000 p w s na nd avl=00 NX
003 %0000000000600000: 80000000c0000083 big phys=00000000c0000000 p w s na nd avl=00 NX
004 %0000000000800000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
005 %0000000000a00000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
006 %0000000000c00000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
007 %0000000000e00000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
008 %0000000001000000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
009 %0000000001200000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
00a %0000000001400000: 0000000000000000 4kb phys=0000000000000000 np r s na avl=00
Although I'm not sure where items 4+ come from as the table is 0's past 3. Once I set the cr0 register for PG=1 this table is just full of rubbish.
CR registers before the fault are
Code: Select all
cr0=00000011 cr2=00000000
cr3=00020000 cr4=00000020
Does it look OK?
Bipman
Re: 64 bit long mode cr0 issue
Posted: Fri Mar 24, 2017 9:40 pm
by MDenham
The CR registers all look okay for the most part; on the other hand, I'm not sure why in that last one you're doing "dptg 0" instead of "dptg 0x21000" to see the current tables. (See a couple of lines down about where your IDT currently is for why that'd give entirely wrong information for debugging - IDT entries have basically no resemblance to page-table entries.)
Well, let's narrow down what could still be going wrong here.
Do you have an IDT set up yet? (It looks like the answer is "yes", but the entries appear to be trash or at least of the wrong size, leading to the page fault at 00000080 as CR2 says, which would be where the double-fault IDT entry is if the IDT base is 00000000.)
Do you have the timer interrupt disabled or remapped at this point? (If you don't, that's going to immediately make the CPU think you've double-faulted.)
Re: 64 bit long mode cr0 issue
Posted: Sat Mar 25, 2017 3:03 am
by Bipman
Hi
Interrupts are cleared and so there is no IDT table for now. I was going to do this once I had managed to get into 64 bit long mode. The dptg 0x2100 shows (although I'm not sure what the 0,200000,400000,600000 are) :-
Code: Select all
VBoxDbg> dptg 0x21000
%%0000000000021000 (index 0x0):
000 %0000000000000000: 0000000000000083 big phys=0000000000000000 p w s na nd avl=00
001 %0000000000200000: 8000000040000083 big phys=0000000040000000 p w s na nd avl=00 NX
002 %0000000000400000: 8000000080000083 big phys=0000000080000000 p w s na nd avl=00 NX
003 %0000000000600000: 80000000c0000083 big phys=00000000c0000000 p w s na nd avl=00 NX
VBoxDbg>
Unless you have to have an IDT even if interrupots are disabled I can't see the problem. I must be missing something really simple.
Bipman
Re: 64 bit long mode cr0 issue
Posted: Sat Mar 25, 2017 5:14 am
by LtG
In the last piece of code you've posted you only enable paging, not protected mode? Have you changed your code from the original so that those are now done separately? It's a bit difficult to follow when there's only bits and pieces. Also debug info from Bochs might be a bit more descriptive.
If you can show the relevant code, Bochs error message and dump relevant registers and memory regions + paging info it might be more useful. I'd suggest always including the relevant pieces as none of us can know what changes from post to post: you might have changed some code, some of the registers might now be different.. It's really difficult trying to guess which posts of yours are "in sync"..
Re: 64 bit long mode cr0 issue
Posted: Sat Mar 25, 2017 6:11 am
by Bipman
OK, here goes. It goes into 32 bit protected mode first, and then tried to go to the 64 bit mode. To save using up space with the code the link to the asm file is here:-
https://www.dropbox.com/s/rnhhraab0efvc ... S.asm?dl=0
Below is the debug output from Virtualbox as I am using that now due to memory usage of over 2GB :-
Code: Select all
eax=80000011 ebx=00000000 ecx=c0000080 edx=00000000 esi=0000f4a0 edi=00021018
eip=0000949b esp=0009ffff ebp=00008000 iopl=0 rf nv up di pl zr na po nc
cs={0008 base=00000000 limit=ffffffff flags=c09b} dr0=00000000 dr1=00000000
ds={0010 base=00000000 limit=ffffffff flags=c093} dr2=00000000 dr3=00000000
es={0010 base=00000000 limit=ffffffff flags=c093} dr6=ffff0ff0 dr7=00000400
fs={0010 base=00000000 limit=ffffffff flags=c093} cr0=80000011 cr2=00000080
gs={0010 base=00000000 limit=ffffffff flags=c093} cr3=00020000 cr4=00000020
ss={0010 base=00000000 limit=ffffffff flags=c093} cr8=00000000
gdtr=000094b9:0017 idtr=00000000:ffff eflags=00010046
ldtr={0000 base=00000000 limit=0000ffff flags=0082}
tr ={0000 base=00000000 limit=0000ffff flags=008b}
sysenter={cs=0000 eip=00000000 esp=00000000}
fcw=0000 fsw=042b ftw=ffff mxcsr=ffffffff mxcsr_mask=ffffffff
u: error: DBGCCmdHlpVarToDbgfAddr failed on '0008:0000949b L 0': VERR_PAGE_TABLE_NOT_PRESENT
The memory areas and tables don't print as the below error shows :-
Code: Select all
dptg 0x21000
%%0000ff53f000f108 (base %0000000000021000 / index 0x21):
error: VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS: Reading PTE memory at %%0000ff53f000f108.
The tables before the fault are shown in a reply above. Let me know if you need anything else
Bipman
Re: 64 bit long mode cr0 issue
Posted: Sat Mar 25, 2017 9:59 am
by LtG
Is there a reason you don't want to/can't use Bochs? It might be able to provide more useful information.
How do you know at which instruction your code breaks? Single-stepping, using loops, etc?
Is the first "debug output from virtualbox" in your latest post after what? Right after enabling paging?
In your code:
Code: Select all
mov edi,40000000
mov [edi],byte 0xeb
mov [edi+1],byte 0xfe
jmp $
mov eax, cr0 ; Read CR0.
bts eax, 31 ; Set PG=1.
mov cr0, eax ; Write CR0.
What's the first part until the CR0 part intended to do? Is the 40000000 supposed to be hex?
Then:
Code: Select all
db 066h
db 0eah
dd 0x80000000
dw CODE_SEG64
What's that intended to be? There's no comment for those _lines_, though there's a comment above.. That's supposed to be a far jump? You are using CODE_SEG64, though it's not yet loaded (with lgdt), since it seems you have two GDT's. Note, I didn't check, but the GDT64 might coincide with GDT32 in descriptor numbers so in that case you would still be using the CODE32 descriptor, however your code changes to 64-bit...
Re: 64 bit long mode cr0 issue
Posted: Sat Mar 25, 2017 10:32 am
by Bipman
Hi
Apologies but that version was an older one which I have now replaced with the current one. I'm not using bochs because it can't use more than 2GB memory and the virtualbox has it's own debugger and trace output which can be found in the link
https://www.dropbox.com/s/qv1d9h3qcz7cl ... t.txt?dl=0 .
1.) The program halts at the mov cr0, eax and know this as I have paused it before and after and this is the line that faults. It does the same if I singe step.
2.) The debug output from VirtualBox was right after the paging enable i.e. mov cr0, eax
3.) Ignore that bit of code as it has been removed.
4.) I see what you mean about the CODE_SEG64; my mistake ! It was indeed a long jump to go into long mode. Be nice to get ths far though!
5.) There are two GDT tables, one for 32 bit and the simple 64 bit one.
Hope that helps and apologies again for sharing the wrong asm file.
Bipman
Re: 64 bit long mode cr0 issue
Posted: Sat Mar 25, 2017 11:10 am
by LtG
Can you elaborate on the issues with Bochs, I'm not an expert on it but I would think you can use more Guest than Host memory, or is there some other limitation your experiencing?
The trace you provided is not available, size 0 bytes.
Can you dump from virtual box the guest's _physical_ address for the paging stuff, I think it was 0x20000 and 0x21000. You should be able to do that before and after the offending instruction, since it shouldn't be dependent on the translation on the guest.
If you want to use VBox and there's no clear error, then you probably should implement IDT and see what exception gets raised and what's on the stack at that point, if anything relevant.
I usually use Qemu and gdb to debug it, being able to single step thru it all and check relevant registers, etc is pretty almost enough. Though I think Bochs might be a bit friendlier at generating useful error messages.