diff --git a/src/gopheros/kernel/mem/pmm/frame.go b/src/gopheros/kernel/mem/pmm/frame.go index 10d5df7..0189013 100644 --- a/src/gopheros/kernel/mem/pmm/frame.go +++ b/src/gopheros/kernel/mem/pmm/frame.go @@ -24,3 +24,12 @@ func (f Frame) Valid() bool { func (f Frame) Address() uintptr { return uintptr(f << mem.PageShift) } + +// FrameFromAddress returns a Frame that corresponds to +// the given physical address. This function can handle +// both page-aligned and not aligned addresses. in the +// latter case, the input address will be rounded down +// to the frame that contains it. +func FrameFromAddress(physAddr uintptr) Frame { + return Frame((physAddr & ^(uintptr(mem.PageSize - 1))) >> mem.PageShift) +} diff --git a/src/gopheros/kernel/mem/pmm/frame_test.go b/src/gopheros/kernel/mem/pmm/frame_test.go index f05968f..59c1988 100644 --- a/src/gopheros/kernel/mem/pmm/frame_test.go +++ b/src/gopheros/kernel/mem/pmm/frame_test.go @@ -23,3 +23,21 @@ func TestFrameMethods(t *testing.T) { t.Error("expected InvalidFrame.Valid() to return false") } } + +func TestFrameFromAddress(t *testing.T) { + specs := []struct { + input uintptr + expFrame Frame + }{ + {0, Frame(0)}, + {4095, Frame(0)}, + {4096, Frame(1)}, + {4123, Frame(1)}, + } + + for specIndex, spec := range specs { + if got := FrameFromAddress(spec.input); got != spec.expFrame { + t.Errorf("[spec %d] expected returned frame to be %v; got %v", specIndex, spec.expFrame, got) + } + } +}