Triple fault on setting CR0 in with 64-bit

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Triple fault on setting CR0 in with 64-bit

Post by bluemoon »

requimrar wrote:
bluemoon wrote:

Code: Select all

PML4T[0] = (uint64_t)&PageDirectoryPointerTable | 3;         // Present, R/W
PageDirectoryPointerTable[0] = (uint64_t)&PageDirectory | 3;   // Present, R/W
PageDirectory[0] = (uint64_t)&PageTable | 3;               // Present, R/W
Hint #1: &PageDirectoryPointerTable
Hint #2: This whole thing will not work if logical(as view by linker) address(PageDirectoryPointerTable) != physical address

1. What am I supposed to use then?
PageDirectoryPointerTable, instead of &PageDirectoryPointerTable; I suppose you knew the difference and just merely a mistake.
requimrar wrote:2. ...? How then, would I ensure that the physical address matches the logical address?
A simplified way is:

Code: Select all

PML4T[0] = physical_address( PDPT ) | 3;
PDPT[0] = physical_address( PDT ) | 3;
...

#define physical_address(p)  ( (uint64_t)(p) - KERNEL_VADDR + KERNEL_PADDR )
KERNEL_VADDR = your kernel logical address as specified in linker script (e.g. 0xFFFFFFFF80100000)
KERNEL_PADDR = the physical address of the point of KERNEL_VADDR (e.g. 0x00100000 mark)

PS. I do this step in assembly.
User avatar
SparrowOS
Member
Member
Posts: 72
Joined: Wed Nov 14, 2012 5:22 pm
Location: Vegas
Contact:

Re: Triple fault on setting CR0 in with 64-bit

Post by SparrowOS »

I identity map everything.

I did my page tables in ASM because they must be done in 32-bit and my compiler only does 64-bit.

I identity map with my page tables at 0x100000
http://www.sparrowos.com/Wb/OSMain/Memory.html

My compiler has different operator precidence rules
http://www.sparrowos.com/Wb/Doc/Differences.html

ALSO, YOU MUST PUT AN "&" FOR A FUNCTION ADDRESS.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Triple fault on setting CR0 in with 64-bit

Post by bluemoon »

SparrowOS wrote:ALSO, YOU MUST PUT AN "&" FOR A FUNCTION ADDRESS.
This might be true for your so-called compiler, but every other C and C++ compiler accept bare function pointer (no de-reference) without issue.

Can you be more kind and do some positive contribution? You are wasting your own time to make foo of yourself.
User avatar
SparrowOS
Member
Member
Posts: 72
Joined: Wed Nov 14, 2012 5:22 pm
Location: Vegas
Contact:

Re: Triple fault on setting CR0 in with 64-bit

Post by SparrowOS »

bluemoon wrote:
SparrowOS wrote:ALSO, YOU MUST PUT AN "&" FOR A FUNCTION ADDRESS.
This might be true for your so-called compiler, but every other C and C++ compiler accept bare function pointer (no de-reference) without issue.

Can you be more kind and do some positive contribution? You are wasting your own time to make foo of yourself.
Dear children, don't be so close-minded making another Linux.

DOS and UNIX have a command-line where you run files.

Apple II and Commodore 64 have a command-line where you execute BASIC statements.
If you type a line number in front of a statement, it adds it to the stored BASIC program in memory. You type "Run" to run that program.

I have a command-line that is a dialect of C/C++.

I did not want to have to type

>Dir("*.*");

So, I added default args from C++.

>Dir();

I looked at it and said, "I don't need parens, do I?"

>Dir;

The side effect is I had to change the syntax on address of functions to include an "&".

Just remember a C64 ROM was 20K. That was a BASIC interpretor and DISK I/O and everything. ASM instructions are 1-3 bytes so 20K is 10,000 LOC.
sounds
Member
Member
Posts: 112
Joined: Sat Feb 04, 2012 5:03 pm

Re: Triple fault on setting CR0 in with 64-bit

Post by sounds »

Requimrar, here's an example of switching from Real to Long mode - if you put the code in the first 64K of memory you can use it both for your bootloader and later for a trampoline when you init more cores:

Code: Select all

	lidt [IDTR]	; load IDTR to an empty IDT - any interrupt will triple-fault
	jmp far 0:set_cr3	; CS must be 0 so use a far jmp to do that
set_cr3:
	mov ax, ds:PML4_ADDRESS	; PML4 must map the first 1MB of physical addresses to the first 1MB of virtual addresses
	mov cr3, eax
	mov ecx, 0xC0000080
	rdmsr	; read EFER (selected with ECX)
	or ax, 0x0100	; 0x0100 = Long Mode Enable (LME)
	wrmsr	; write EFER

	mov  eax, cr0
	;
	; TODO: you need to review the cr0 bits and set more if appropriate
	;
	or eax,0x80000001	; set cr0.PG and cr0.PE: go straight from 16-bit real mode to 64-bit long mode
	mov cr0, eax
	;
	; now in 64-bit compatibility mode with CS = 0 (as a 16-bit selector)
	;
	lgdt [GDTR]	; load GDT using the GDTR values - using 16-bit addressing
	jmp far segment_from_your_GDT:address_of_next_instruction	; switch to 64-bit mode (not compatibility) by loading a 64-bit selector from the GDT
	; remember to re-load DS, ES, SS, FS, GS, and set the GDTR using the PML4
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: Triple fault on setting CR0 in with 64-bit

Post by zhiayang »

Thanks guys for all the help. I'm not able to test this right now, but I'll get back here once I implement your suggestions.
mich
Posts: 18
Joined: Sun Nov 11, 2012 5:36 pm

Re: Triple fault on setting CR0 in with 64-bit

Post by mich »

Let me throw in some of my code. It uses a NASM macro to set up a static PML4 that identity maps the 1st X GiB. (Warning/note: The page table will be placed into the data section so the resulting image might get quite big!)
It was/is used to quickly bootstrap a 64bit system.

Code: Select all

[SECTION .text]
[BITS 32]
	[...] ; coming out of a state as specified by the Multiboot specification (pmode, flat 0 base 4GiB segments, ints disabled, etc..)
	cli
; enable PAE
	mov eax, cr4
	or  eax, 1<<5 ; PAE is bit 5
	mov cr4, eax
; load pml4
	mov eax, pml4
	mov cr3, eax
; enable ia-32e mode
	mov ecx, 0xC0000080
	rdmsr
	or eax, 1<<8 ; LME (i.e. IA-32e Mode Enable) is bit 8
	wrmsr
; enable paging
	mov eax, cr0
	or eax, 1<<31 ; PG is bit 31
	mov cr0, eax

; now load 64-bit GDT and jump into real 64-bit code
	lgdt [gdt_desc_global]
	jmp gdt.code:real64

[BITS 64]
real64:
	cli
	mov ax,gdt.data
	mov ds,ax
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov ss,ax
	mov rsp, init_stack+4096
	[...] ; call 64bit C/C++-code

[SECTION .bss]

init_stack:
	resb 4096

[SECTION .data align=4096]

align	4 
gdt:
.null equ $ - gdt
	dw 0,0,0,0 ; NULL Deskriptor
.code equ $ - gdt
	dw 0                         ; Limit (low)
	dw 0                         ; Base (low)
	db 0                         ; Base (middle)
	db 10011010b                 ; Access
	db 00100000b                 ; Granularity with 64-bit flag set
	db 0                         ; Base (high)
.data equ $ - gdt
	dw 0                         ; Limit (low)
	dw 0                         ; Base (low)
	db 0                         ; Base (middle)
	db 10010010b                 ; Access
	db 00000000b                 ; Granularity
	db 0                         ; Base (high)
gdt_desc_global:
	dw $ - gdt - 1               ; Limit
	dq gdt                       ; Base

align 4096
%define MAXMEM 64 ; in GB (must be < 512)
; setup paging for id map of the first MAXMEM GB
; use 2MiB pages
pdes:
	%assign i 0
	%rep 512 * MAXMEM
		dq 10000011b | i*2*1024*1024
	%assign i i+1
	%endrep
pdpte:
	%assign i 0
	%rep MAXMEM
		dq 11b + pdes + 512*8*i
	%assign i i+1
	%endrep
	times 512-MAXMEM dq 0
pml4:
	dq 11b + pdpte
	times 511 dq 0
Post Reply