I have mapped the first Megabyte and up to the size of my kernel.
When I try to add a new page table, right after my kernel, and add addresses to it, a page fault occurs.
It seems that page directory and page table structures themselves need to be page-mapped, before mapping data pages themselves. If I try to build a page table at 32 Megabytes but I have only mapped 1.5 Megabytes, a page fault occurs when I set entries of this new page table at 32MB. The CPU doesn't seem to allow access not even to paging structures that aren't mapped themselves inside virtual addresses.
Is paging supposed to be fault-driven to add protection by indirect events?
Does the CPU disable the paging bit for being able to directly access physical addresses while the page fault doesn't execute IRET to return control?
How can I add new page tables if I no longer have free available memory that is in the already mapped pages once I map addresses 0-kernel_end? Anything new I do will simply trigger a page fault.
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
The solution I've implemented so far is including a static empty page in the kernel used solely for things like adding new page tables and data pages in currently unmapped memory, and a function to change the physical address of that page (or others). That page will always exist with a valid static virtual address in ring 0 and an ever-changing physical address so no page faults will occur while I set up physical addresses with that function. I just manipulate any physical page through that special page as if it was a data view to any other physical address:
Code: Select all
;Inputs:
; WIDEDX -- CR3 array offset address
; WIDESI -- Virtual address to modify
; WIDEDI -- New physical address to point to
;;
align wideword_sz
OPCODE__CPU_x86_32_remap_physical_page_address:
pushfwide
push widebx
push widecx
push widedx
push widesi
;Get the base address of the specified
;page directory in WIDEDX:
;;
mov widedx,[widedx*wideword_sz+CR3_array]
;Convert bits 22-31 to page directory entry index offset:
;;
mov widebx,widesi ;Put virtual address in WIDEBX
shr widebx,22 ;Only get page directory index bits
shl widebx,2 ;Multiply index by 4
add widebx,widedx ;Go to page directory base address
;Read the physical address in the entry
;in WIDEBX:
;;
mov widebx,[widebx] ;Get page directory entry value
and widebx,11111111111111111111000000000000b ;Get rid of attribute bits
;Convert bits 12-21 to page table base address:
;;
mov widecx,widesi ;Load virtual address in DX
shl widecx,10 ;Get rid of bits 22-31
shr widecx,10+12 ;Get only page table index bits
shl widecx,2 ;Multiply by 4 to go to the actual entry
add widecx,widebx ;Go to the page table base address
;Read the physical address of the virtual page table
;and only preserve type/attribu bits:
;;
mov widesi,[widecx]
shl widesi,20
shr widesi,20
;Place the new address instead:
;;
or widesi,widedi
mov [widecx],widesi
pop widesi
pop widedx
pop widecx
pop widebx
popfwide
retwide