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
|
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
|
// MapTemporary establishes a temporary RW mapping of a physical memory frame
|
||||||
// to a fixed virtual address overwriting any previous mapping. The temporary
|
// to a fixed virtual address overwriting any previous mapping. The temporary
|
||||||
// mapping mechanism is primarily used by the kernel to access and initialize
|
// 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) {
|
func TestMapTemporaryErrorsAmd64(t *testing.T) {
|
||||||
if runtime.GOARCH != "amd64" {
|
if runtime.GOARCH != "amd64" {
|
||||||
t.Skip("test requires amd64 runtime; skipping")
|
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
|
// Calculate the physical address by taking the physical frame address and
|
||||||
// appending the offset from the virtual address
|
// 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
|
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