1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00
Achilleas Anagnostopoulos 319f868a14 Implement page table entry walker
The page table walker provides a mechanism for accessing the individual
page table entries that correspond to a particular virtual memory
address. This implementation will serve as the basis for implementing
page mapping/unmapping and virtual to physical address translation.
2017-06-06 07:30:13 +01:00

57 lines
2.2 KiB
Go

package vmm
import (
"unsafe"
"github.com/achilleasa/gopher-os/kernel/mem"
)
var (
// ptePointerFn returns a pointer to the supplied entry address. It is
// used by tests to override the generated page table entry pointers so
// walk() can be properly tested. When compiling the kernel this function
// will be automatically inlined.
ptePtrFn = func(entryAddr uintptr) unsafe.Pointer {
return unsafe.Pointer(entryAddr)
}
)
// pageTableWalker is a function that can be passed to the walk method. The
// function receives the current page level and page table entry as its
// arguments. If the function returns false, then the page walk is aborted.
type pageTableWalker func(pteLevel uint8, pte *pageTableEntry) bool
// walk performs a page table walk for the given virtual address. It calls the
// suppplied walkFn with the page table entry that corresponds to each page
// table level. If walkFn returns an error then the walk is aborted and the
// error is returned to the caller.
func walk(virtAddr uintptr, walkFn pageTableWalker) {
var (
level uint8
tableAddr, entryAddr, entryIndex uintptr
ok bool
)
// tableAddr is initially set to the recursively mapped virtual address for the
// last entry in the top-most page table. Dereferencing a pointer to this address
// will allow us to access
for level, tableAddr = uint8(0), pdtVirtualAddr; level < pageLevels; level, tableAddr = level+1, entryAddr {
// Extract the bits from virtual address that correspond to the
// index in this level's page table
entryIndex = (virtAddr >> pageLevelShifts[level]) & ((1 << pageLevelBits[level]) - 1)
// By shifting the table virtual address left by pageLevelShifts[level] we add
// a new level of indirection to our recursive mapping allowing us to access
// the table pointed to by the page entry
entryAddr = tableAddr + (entryIndex << mem.PointerShift)
if ok = walkFn(level, (*pageTableEntry)(ptePtrFn(entryAddr))); !ok {
return
}
// Shift left by the number of bits for this paging level to get
// the virtual address of the table pointed to by entryAddr
entryAddr <<= pageLevelBits[level]
}
}