Ok i've got a few questions around paging and also a funny issue I'm not quite sure what's causing it.. first off questions:
1) Assuming I have a machine with 2gig of memory installed, let's say running 32bit... Some devices may still map memory into a higher range than is physically available.. IE: video mem buffer at 3gig.. I've noticed this with Vesa LFB. So my assumption is .. that when setting up paging I need to map the full address space (NOT just what is physically available) to allow these mem-mapped devices/areas to be accessable correct?
2) Following on from 1... I assume that no device / bios setup etc can make assumptions as to the OS being 32bit or 64bit... in which case ALL devices and mem-mapped io and config space and so on (for the near future) MUST all be below 4gig to allow a 32bit OS to correctly setup paging? - IE It is safe to assume that over 4gig is 100% free available and the OS could do with as it pleases?
3) To s tart things off in my 64bit kernel I did the following:
boot loader identity maps first 2Mb, just enough to switch to the kernel stub in 64bit long mode so that it can setup full paging and handle re-mapping itself to higher-half VMA etc. I'm fairly happy with that model, so to start off with I've setup the paging in the kernel to be 100% identity mapped, just so i can start testing a few other bits of code/support stuff until I do the higher-half setup.. first issue is related to the questions above, if I have less than 4gig of physical mem, I should still go ahead and MAP the FULL 4gig address space? (to support devices/mem-mapped etc higher than 2gig).. obviously if the machine has more than 4gig physical I just map it all?
4) For some reason the above seems to work perfectly in QEMU, but in bochs it dies and reboots (i assume triple fault). I've narrowed the problem down to the following:
The boot loader maps 2Mb, switches to Kernel stub which maps the full 4gig space.. As a test I try to write a byte to say 3gig and read it back.. in QEMU perfect, in bochs ANY read/write over exactly 2Mb dies.. so it seems as if the reload of CR3 with the updated paging structures isn't taking affect.. here are the various code bits (initial stuff from the higher-half tutorial):
Do i need to perhaps somehow force TLBs to reload? (I didn't think it was needed.. even though I've enabled the Global pages option because none of the pages are yet present/created.. and the 1 and only 2Mb page which has a G flag set doesn't change):
Code: Select all
.. in the boot loader.....
;--------------------------------------------------------------------------------
; Basic Identity Map Paging for 1st 2Meg, just enough to get us there.
;--------------------------------------------------------------------------------
xor bx,bx
mov es,bx
cld
mov di,0c000h ;c000 = PML4
mov ax,0d00fh
stosw
xor ax,ax
mov cx,07ffh
rep stosw
mov ax,0e00fh ;d000 = PDPT
stosw
xor ax,ax
mov cx,07ffh
rep stosw
mov ax,018fh ;e000 = PDE
stosw
xor ax,ax
mov cx,07ffh
rep stosw
;--------------------------------------------------------------------------------
; Switch To 64bit Long Mode and Jump To Kernel Stub.
;--------------------------------------------------------------------------------
mov dl,7 ; Display progress.
mov si,offset ker_str3
call print_str
; Enable physical-address extensions (PAE)
mov eax,cr4
or eax,0a0h ; Enable PAE and PGE bits.
mov cr4,eax
; Point CR3 at PML4
mov eax,0000c008h ; Bit 3 set for write-thru caching.
mov cr3,eax
; Enable long mode (set EFER.LME=1)
mov ecx,0c0000080h ; EFER MSR number.
RDMSR
or eax,00000101h ; LME amd SYSCALL/SYSRET.
WRMSR
; Enable paging AND protected mode to activate long mode (set CR0.PG=1)
mov eax,cr0 ; Read CR0
or eax,80000001h ; Enable Paging and Protection.
mov cr0,eax ; Write CR0
dw 0ea66h ; Far jump to 64bit kernel stub, reload CS and
dd 100000h ; flush instruction cache.
db 08h,00h
; In the kernel stub code..
; Configure Paging.
mov edi,0000e000h
xor rax,rax
mov ecx,512*4
xor rdx,rdx
fillPDE0:
mov rax,rdx
or rax,18fh
mov [edi],rax
add rdx,(1024*2000)
add edi,8
dec ecx
jnz short fillPDE0
mov edi,0000d000h
mov eax,0e00fh
mov [edi],eax
mov eax,0f00fh
mov [edi+8],eax
mov eax,1000fh
mov [edi+16],eax
mov eax,1100fh
mov [edi+24],eax
; Point CR3 at PML4
mov rax,0000c008h ; Bit 3 set for write-thru caching.
mov cr3,rax
mov edi,(1024*1024)*2 ;DIES in bochs.. works in QEMU ... -1 byte and it works (so its the 2Mb barrier from initial paging setup?)
mov al,'F'
mov [edi],al
xor eax,eax
mov al,[edi]