Page 2 of 2
Re: Triple fault on setting CR0 in with 64-bit
Posted: Wed Nov 21, 2012 1:18 pm
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.
Re: Triple fault on setting CR0 in with 64-bit
Posted: Wed Nov 21, 2012 1:34 pm
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.
Re: Triple fault on setting CR0 in with 64-bit
Posted: Wed Nov 21, 2012 1:45 pm
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.
Re: Triple fault on setting CR0 in with 64-bit
Posted: Wed Nov 21, 2012 2:28 pm
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.
Re: Triple fault on setting CR0 in with 64-bit
Posted: Wed Nov 21, 2012 10:46 pm
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
Re: Triple fault on setting CR0 in with 64-bit
Posted: Thu Nov 22, 2012 12:25 am
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.
Re: Triple fault on setting CR0 in with 64-bit
Posted: Thu Nov 22, 2012 3:40 pm
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