1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

vmm: implement identity mapping function for contiguous physical mem regions

vmm.IdentityMapRegion can be used by device drivers that want to
establish an identity mapping for a contiguous physical memory block in
order to access some hardware or table.
This commit is contained in:
Achilleas Anagnostopoulos 2017-08-28 07:27:35 +01:00
parent 0a271b206b
commit 7bcaf0ee8d
3 changed files with 59 additions and 2 deletions

View File

@ -130,6 +130,24 @@ func MapRegion(frame pmm.Frame, size mem.Size, flags PageTableEntryFlag) (Page,
return PageFromAddress(startPage), nil
}
// IdentityMapRegion establishes an identity mapping to the physical memory
// region which starts at the given frame and ends at frame + pages(size). The
// size argument is always rounded up to the nearest page boundary.
// IdentityMapRegion returns back the Page that corresponds to the region
// start.
func IdentityMapRegion(startFrame pmm.Frame, size mem.Size, flags PageTableEntryFlag) (Page, *kernel.Error) {
startPage := Page(startFrame)
pageCount := Page(((size + (mem.PageSize - 1)) & ^(mem.PageSize - 1)) >> mem.PageShift)
for curPage := startPage; curPage < startPage+pageCount; curPage++ {
if err := mapFn(curPage, pmm.Frame(curPage), flags); err != nil {
return 0, err
}
}
return startPage, nil
}
// MapTemporary establishes a temporary RW mapping of a physical memory frame
// to a fixed virtual address overwriting any previous mapping. The temporary
// mapping mechanism is primarily used by the kernel to access and initialize

View File

@ -164,6 +164,40 @@ func TestMapRegion(t *testing.T) {
})
}
func TestIdentityMapRegion(t *testing.T) {
defer func() {
mapFn = Map
}()
t.Run("success", func(t *testing.T) {
mapCallCount := 0
mapFn = func(_ Page, _ pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
mapCallCount++
return nil
}
if _, err := IdentityMapRegion(pmm.Frame(0xdf0000), 4097, FlagPresent|FlagRW); err != nil {
t.Fatal(err)
}
if exp := 2; mapCallCount != exp {
t.Errorf("expected Map to be called %d time(s); got %d", exp, mapCallCount)
}
})
t.Run("Map fails", func(t *testing.T) {
expErr := &kernel.Error{Module: "test", Message: "map failed"}
mapFn = func(_ Page, _ pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
return expErr
}
if _, err := IdentityMapRegion(pmm.Frame(0xdf0000), 128000, FlagPresent|FlagRW); err != expErr {
t.Fatalf("expected error: %v; got %v", expErr, err)
}
})
}
func TestMapTemporaryErrorsAmd64(t *testing.T) {
if runtime.GOARCH != "amd64" {
t.Skip("test requires amd64 runtime; skipping")

View File

@ -13,7 +13,12 @@ func Translate(virtAddr uintptr) (uintptr, *kernel.Error) {
// Calculate the physical address by taking the physical frame address and
// appending the offset from the virtual address
physAddr := pte.Frame().Address() + (virtAddr & ((1 << pageLevelShifts[pageLevels-1]) - 1))
physAddr := pte.Frame().Address() + PageOffset(virtAddr)
return physAddr, nil
}
// PageOffset returns the offset within the page specified by a virtual
// address.
func PageOffset(virtAddr uintptr) uintptr {
return (virtAddr & ((1 << pageLevelShifts[pageLevels-1]) - 1))
}