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

Implement function for mapping a contiguous physical memory region

The MapRegion function can be used by device drivers to ensure that they
can access memory mapped by the various devices.
This commit is contained in:
Achilleas Anagnostopoulos 2017-07-08 16:04:39 +01:00
parent 42e6802323
commit 8ac2ba82cc
2 changed files with 92 additions and 0 deletions

View File

@ -47,6 +47,8 @@ var (
// which will cause a fault if called in user-mode. // which will cause a fault if called in user-mode.
flushTLBEntryFn = cpu.FlushTLBEntry flushTLBEntryFn = cpu.FlushTLBEntry
earlyReserveRegionFn = EarlyReserveRegion
errNoHugePageSupport = &kernel.Error{Module: "vmm", Message: "huge pages are not supported"} errNoHugePageSupport = &kernel.Error{Module: "vmm", Message: "huge pages are not supported"}
errAttemptToRWMapReservedFrame = &kernel.Error{Module: "vmm", Message: "reserved blank frame cannot be mapped with a RW flag"} errAttemptToRWMapReservedFrame = &kernel.Error{Module: "vmm", Message: "reserved blank frame cannot be mapped with a RW flag"}
) )
@ -105,6 +107,29 @@ func Map(page Page, frame pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
return err return err
} }
// MapRegion establishes a 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. MapRegion reserves the next
// available region in the active virtual address space, establishes the
// mapping and returns back the Page that corresponds to the region start.
func MapRegion(frame pmm.Frame, size mem.Size, flags PageTableEntryFlag) (Page, *kernel.Error) {
// Reserve next free block in the address space
size = (size + (mem.PageSize - 1)) & ^(mem.PageSize - 1)
startPage, err := earlyReserveRegionFn(size)
if err != nil {
return 0, err
}
pageCount := size >> mem.PageShift
for page := PageFromAddress(startPage); pageCount > 0; pageCount, page, frame = pageCount-1, page+1, frame+1 {
if err := mapFn(page, frame, flags); err != nil {
return 0, err
}
}
return PageFromAddress(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

View File

@ -97,6 +97,73 @@ func TestMapTemporaryAmd64(t *testing.T) {
} }
} }
func TestMapRegion(t *testing.T) {
defer func() {
mapFn = Map
earlyReserveRegionFn = EarlyReserveRegion
}()
t.Run("success", func(t *testing.T) {
mapCallCount := 0
mapFn = func(_ Page, _ pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
mapCallCount++
return nil
}
earlyReserveRegionCallCount := 0
earlyReserveRegionFn = func(_ mem.Size) (uintptr, *kernel.Error) {
earlyReserveRegionCallCount++
return 0xf00, nil
}
if _, err := MapRegion(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)
}
if exp := 1; earlyReserveRegionCallCount != exp {
t.Errorf("expected EarlyReserveRegion to be called %d time(s); got %d", exp, earlyReserveRegionCallCount)
}
})
t.Run("EarlyReserveRegion fails", func(t *testing.T) {
expErr := &kernel.Error{Module: "test", Message: "out of address space"}
earlyReserveRegionFn = func(_ mem.Size) (uintptr, *kernel.Error) {
return 0, expErr
}
if _, err := MapRegion(pmm.Frame(0xdf0000), 128000, FlagPresent|FlagRW); err != expErr {
t.Fatalf("expected error: %v; got %v", expErr, err)
}
})
t.Run("Map fails", func(t *testing.T) {
expErr := &kernel.Error{Module: "test", Message: "map failed"}
earlyReserveRegionCallCount := 0
earlyReserveRegionFn = func(_ mem.Size) (uintptr, *kernel.Error) {
earlyReserveRegionCallCount++
return 0xf00, nil
}
mapFn = func(_ Page, _ pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
return expErr
}
if _, err := MapRegion(pmm.Frame(0xdf0000), 128000, FlagPresent|FlagRW); err != expErr {
t.Fatalf("expected error: %v; got %v", expErr, err)
}
if exp := 1; earlyReserveRegionCallCount != exp {
t.Errorf("expected EarlyReserveRegion to be called %d time(s); got %d", exp, earlyReserveRegionCallCount)
}
})
}
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")