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:
parent
0a271b206b
commit
7bcaf0ee8d
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user