If you want to be able to remap stuff around in your paging structures without page faults in the easiest way, you can do this:
Create a 4096-byte aligned variable called
kernel_visor_page_table set to all zeroes on startup, also 4096-byte sized. It has to point to 4096 bytes.
Your page directory has 1024 entries. Your kernel will take a certain number of those.
If it just takes the first Megabyte and a few Kilobytes, it will only take 1 page directory entry.In your kernel, you can make that first page directory entry point to your 4096-byte-aligned
kernel_visor_page_table so that it becomes a page table.
If you modify its entries, you can modify any unmapped pages.
But in this case, it will have a certain number of entries taken by
the kernel.
You have to ensure that some of those entries are always free (for example the very last 16 entries of the page table) because you will need them as pointers to any other pages, specially page directories and page tables that now you no longer need to map anywhere else.Think that now, with just that kernel-accessible page table:
- Your base page table is within the kernel.
- You have the last 16 entries.
- Your kernel contents must skip them for being able to be bigger than 4 Megabytes.
- With those 16 same pointers, you can remap them to access anything.
In NASM, it could be (skip 4096 for the page directory, and the next 4096 will be our mapped page table):
Code:
;With this label variable we can freely
;manage the rest of memory without
;disabling paging if we reserve the last
;few page table entries as special visor pages,
;but then we also need labels for static
;pointers to those page table entries for
;immediate access to them from the kernel.
;More than 1 entry will only be useful for
;a proper multitasking environment that
;can modify page tables from several processes
;without disabling interrups (it's probably
;always unstable to do as seen by OSes
;like Windows, Linux...).
;;
align 4096
kernel_visor_page_table times 4096 db 0 ;Base address of page table
kernel_visor_pagetable0 equ kernel_visor_page_table+(4096-4) ;Pointer to mapped page table entry to remap
kernel_visor_page0_ptr equ (0000000000b<<22)|(1111111111b<<12)|(000000000000b) ;const virtual base address of our remappeable physical page
Then to write the otherwise unmapped 4K physical page:
Code:
;Point to last entry of the visor page table
;via visor page #0 const pointer
;(in C it should be kernel_visor_pagetable[0]):
;;
mov widesi,kernel_visor_pagetable0
;Set it up mapping to test Megabyte #200:
;;
mov dword[widesi],(1048576*120)|_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE|_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite|_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel
;Write the start of Megabyte #200
;through this visor page (if you
;examine the emulator memory
;it will contain the string "TEST"
;at physical address 209715200):
;;
mov dword[kernel_visor_page0_ptr],"TSET" ;FINAL