mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
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.
77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package vmm
|
|
|
|
import (
|
|
"runtime"
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"github.com/achilleasa/gopher-os/kernel/mem"
|
|
)
|
|
|
|
func TestPtePtrFn(t *testing.T) {
|
|
// Dummy test to keep coverage happy
|
|
if exp, got := unsafe.Pointer(uintptr(123)), ptePtrFn(uintptr(123)); exp != got {
|
|
t.Fatalf("expected ptePtrFn to return %v; got %v", exp, got)
|
|
}
|
|
}
|
|
|
|
func TestWalkAmd64(t *testing.T) {
|
|
if runtime.GOARCH != "amd64" {
|
|
t.Skip("test requires amd64 runtime; skipping")
|
|
}
|
|
|
|
defer func(origPtePtr func(uintptr) unsafe.Pointer) {
|
|
ptePtrFn = origPtePtr
|
|
}(ptePtrFn)
|
|
|
|
// This address breaks down to:
|
|
// p4 index: 1
|
|
// p3 index: 2
|
|
// p2 index: 3
|
|
// p1 index: 4
|
|
// offset : 1024
|
|
targetAddr := uintptr(0x8080604400)
|
|
|
|
sizeofPteEntry := uintptr(unsafe.Sizeof(pageTableEntry(0)))
|
|
expEntryAddrBits := [pageLevels][pageLevels + 1]uintptr{
|
|
{511, 511, 511, 511, 1 * sizeofPteEntry},
|
|
{511, 511, 511, 1, 2 * sizeofPteEntry},
|
|
{511, 511, 1, 2, 3 * sizeofPteEntry},
|
|
{511, 1, 2, 3, 4 * sizeofPteEntry},
|
|
}
|
|
|
|
pteCallCount := 0
|
|
ptePtrFn = func(entry uintptr) unsafe.Pointer {
|
|
if pteCallCount >= pageLevels {
|
|
t.Fatalf("unexpected call to ptePtrFn; already called %d times", pageLevels)
|
|
}
|
|
|
|
for i := 0; i < pageLevels; i++ {
|
|
pteIndex := (entry >> pageLevelShifts[i]) & ((1 << pageLevelBits[i]) - 1)
|
|
if pteIndex != expEntryAddrBits[pteCallCount][i] {
|
|
t.Errorf("[ptePtrFn call %d] expected pte entry for level %d to use offset %d; got %d", pteCallCount, i, expEntryAddrBits[pteCallCount][i], pteIndex)
|
|
}
|
|
}
|
|
|
|
// Check the page offset
|
|
pteIndex := entry & ((1 << mem.PageShift) - 1)
|
|
if pteIndex != expEntryAddrBits[pteCallCount][pageLevels] {
|
|
t.Errorf("[ptePtrFn call %d] expected pte offset to be %d; got %d", pteCallCount, expEntryAddrBits[pteCallCount][pageLevels], pteIndex)
|
|
}
|
|
|
|
pteCallCount++
|
|
|
|
return unsafe.Pointer(uintptr(0xf00))
|
|
}
|
|
|
|
walkFnCallCount := 0
|
|
walk(targetAddr, func(level uint8, entry *pageTableEntry) bool {
|
|
walkFnCallCount++
|
|
return walkFnCallCount != pageLevels
|
|
})
|
|
|
|
if pteCallCount != pageLevels {
|
|
t.Errorf("expected ptePtrFn to be called %d times; got %d", pageLevels, pteCallCount)
|
|
}
|
|
}
|