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.