mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Provide helper for setting the active frame allocator
This allows us to remove the allocFn argument from the vmm functions which causes the compiler's escape analysis to sometimes incorectly flag it as escaping to the heap.
This commit is contained in:
parent
1b88764676
commit
dbdf686d27
@ -23,14 +23,11 @@ var (
|
|||||||
errNoHugePageSupport = &kernel.Error{Module: "vmm", Message: "huge pages are not supported"}
|
errNoHugePageSupport = &kernel.Error{Module: "vmm", Message: "huge pages are not supported"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// FrameAllocatorFn is a function that can allocate physical frames.
|
|
||||||
type FrameAllocatorFn func() (pmm.Frame, *kernel.Error)
|
|
||||||
|
|
||||||
// Map establishes a mapping between a virtual page and a physical memory frame
|
// Map establishes a mapping between a virtual page and a physical memory frame
|
||||||
// using the currently active page directory table. Calls to Map will use the
|
// using the currently active page directory table. Calls to Map will use the
|
||||||
// supplied physical frame allocator to initialize missing page tables at each
|
// supplied physical frame allocator to initialize missing page tables at each
|
||||||
// paging level supported by the MMU.
|
// paging level supported by the MMU.
|
||||||
func Map(page Page, frame pmm.Frame, flags PageTableEntryFlag, allocFn FrameAllocatorFn) *kernel.Error {
|
func Map(page Page, frame pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
|
||||||
var err *kernel.Error
|
var err *kernel.Error
|
||||||
|
|
||||||
walk(page.Address(), func(pteLevel uint8, pte *pageTableEntry) bool {
|
walk(page.Address(), func(pteLevel uint8, pte *pageTableEntry) bool {
|
||||||
@ -53,7 +50,7 @@ func Map(page Page, frame pmm.Frame, flags PageTableEntryFlag, allocFn FrameAllo
|
|||||||
// physical frame for it map it and clear its contents.
|
// physical frame for it map it and clear its contents.
|
||||||
if !pte.HasFlags(FlagPresent) {
|
if !pte.HasFlags(FlagPresent) {
|
||||||
var newTableFrame pmm.Frame
|
var newTableFrame pmm.Frame
|
||||||
newTableFrame, err = allocFn()
|
newTableFrame, err = frameAllocator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -78,8 +75,8 @@ func Map(page Page, frame pmm.Frame, flags PageTableEntryFlag, allocFn FrameAllo
|
|||||||
// 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
|
||||||
// inactive page tables.
|
// inactive page tables.
|
||||||
func MapTemporary(frame pmm.Frame, allocFn FrameAllocatorFn) (Page, *kernel.Error) {
|
func MapTemporary(frame pmm.Frame) (Page, *kernel.Error) {
|
||||||
if err := Map(PageFromAddress(tempMappingAddr), frame, FlagRW, allocFn); err != nil {
|
if err := Map(PageFromAddress(tempMappingAddr), frame, FlagRW); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,17 +26,18 @@ func TestMapTemporaryAmd64(t *testing.T) {
|
|||||||
ptePtrFn = origPtePtr
|
ptePtrFn = origPtePtr
|
||||||
nextAddrFn = origNextAddrFn
|
nextAddrFn = origNextAddrFn
|
||||||
flushTLBEntryFn = origFlushTLBEntryFn
|
flushTLBEntryFn = origFlushTLBEntryFn
|
||||||
|
frameAllocator = nil
|
||||||
}(ptePtrFn, nextAddrFn, flushTLBEntryFn)
|
}(ptePtrFn, nextAddrFn, flushTLBEntryFn)
|
||||||
|
|
||||||
var physPages [pageLevels][mem.PageSize >> mem.PointerShift]pageTableEntry
|
var physPages [pageLevels][mem.PageSize >> mem.PointerShift]pageTableEntry
|
||||||
nextPhysPage := 0
|
nextPhysPage := 0
|
||||||
|
|
||||||
// allocFn returns pages from index 1; we keep index 0 for the P4 entry
|
// allocFn returns pages from index 1; we keep index 0 for the P4 entry
|
||||||
allocFn := func() (pmm.Frame, *kernel.Error) {
|
SetFrameAllocator(func() (pmm.Frame, *kernel.Error) {
|
||||||
nextPhysPage++
|
nextPhysPage++
|
||||||
pageAddr := unsafe.Pointer(&physPages[nextPhysPage][0])
|
pageAddr := unsafe.Pointer(&physPages[nextPhysPage][0])
|
||||||
return pmm.Frame(uintptr(pageAddr) >> mem.PageShift), nil
|
return pmm.Frame(uintptr(pageAddr) >> mem.PageShift), nil
|
||||||
}
|
})
|
||||||
|
|
||||||
pteCallCount := 0
|
pteCallCount := 0
|
||||||
ptePtrFn = func(entry uintptr) unsafe.Pointer {
|
ptePtrFn = func(entry uintptr) unsafe.Pointer {
|
||||||
@ -64,7 +65,7 @@ func TestMapTemporaryAmd64(t *testing.T) {
|
|||||||
frame := pmm.Frame(123)
|
frame := pmm.Frame(123)
|
||||||
levelIndices := []uint{510, 511, 511, 511}
|
levelIndices := []uint{510, 511, 511, 511}
|
||||||
|
|
||||||
page, err := MapTemporary(frame, allocFn)
|
page, err := MapTemporary(frame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -124,21 +125,22 @@ func TestMapTemporaryErrorsAmd64(t *testing.T) {
|
|||||||
return unsafe.Pointer(&physPages[0][pteIndex])
|
return unsafe.Pointer(&physPages[0][pteIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := MapTemporary(frame, nil); err != errNoHugePageSupport {
|
if _, err := MapTemporary(frame); err != errNoHugePageSupport {
|
||||||
t.Fatalf("expected to get errNoHugePageSupport; got %v", err)
|
t.Fatalf("expected to get errNoHugePageSupport; got %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("allocFn returns an error", func(t *testing.T) {
|
t.Run("allocFn returns an error", func(t *testing.T) {
|
||||||
|
defer func() { frameAllocator = nil }()
|
||||||
physPages[0][p4Index] = 0
|
physPages[0][p4Index] = 0
|
||||||
|
|
||||||
expErr := &kernel.Error{Module: "test", Message: "out of memory"}
|
expErr := &kernel.Error{Module: "test", Message: "out of memory"}
|
||||||
|
|
||||||
allocFn := func() (pmm.Frame, *kernel.Error) {
|
SetFrameAllocator(func() (pmm.Frame, *kernel.Error) {
|
||||||
return 0, expErr
|
return 0, expErr
|
||||||
}
|
})
|
||||||
|
|
||||||
if _, err := MapTemporary(frame, allocFn); err != expErr {
|
if _, err := MapTemporary(frame); err != expErr {
|
||||||
t.Fatalf("got unexpected error %v", err)
|
t.Fatalf("got unexpected error %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -39,7 +39,7 @@ type PageDirectoryTable struct {
|
|||||||
// Init can:
|
// Init can:
|
||||||
// - call mem.Memset to clear the frame contents
|
// - call mem.Memset to clear the frame contents
|
||||||
// - setup a recursive mapping for the last table entry to the page itself.
|
// - setup a recursive mapping for the last table entry to the page itself.
|
||||||
func (pdt *PageDirectoryTable) Init(pdtFrame pmm.Frame, allocFn FrameAllocatorFn) *kernel.Error {
|
func (pdt *PageDirectoryTable) Init(pdtFrame pmm.Frame) *kernel.Error {
|
||||||
pdt.pdtFrame = pdtFrame
|
pdt.pdtFrame = pdtFrame
|
||||||
|
|
||||||
// Check active PDT physical address. If it matches the input pdt then
|
// Check active PDT physical address. If it matches the input pdt then
|
||||||
@ -50,7 +50,7 @@ func (pdt *PageDirectoryTable) Init(pdtFrame pmm.Frame, allocFn FrameAllocatorFn
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a temporary mapping for the pdt frame so we can work on it
|
// Create a temporary mapping for the pdt frame so we can work on it
|
||||||
pdtPage, err := mapTemporaryFn(pdtFrame, allocFn)
|
pdtPage, err := mapTemporaryFn(pdtFrame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ func (pdt *PageDirectoryTable) Init(pdtFrame pmm.Frame, allocFn FrameAllocatorFn
|
|||||||
// function with the difference that it also supports inactive page PDTs by
|
// function with the difference that it also supports inactive page PDTs by
|
||||||
// establishing a temporary mapping so that Map() can access the inactive PDT
|
// establishing a temporary mapping so that Map() can access the inactive PDT
|
||||||
// entries.
|
// entries.
|
||||||
func (pdt PageDirectoryTable) Map(page Page, frame pmm.Frame, flags PageTableEntryFlag, allocFn FrameAllocatorFn) *kernel.Error {
|
func (pdt PageDirectoryTable) Map(page Page, frame pmm.Frame, flags PageTableEntryFlag) *kernel.Error {
|
||||||
var (
|
var (
|
||||||
activePdtFrame = pmm.Frame(activePDTFn() >> mem.PageShift)
|
activePdtFrame = pmm.Frame(activePDTFn() >> mem.PageShift)
|
||||||
lastPdtEntryAddr uintptr
|
lastPdtEntryAddr uintptr
|
||||||
@ -89,7 +89,7 @@ func (pdt PageDirectoryTable) Map(page Page, frame pmm.Frame, flags PageTableEnt
|
|||||||
flushTLBEntryFn(lastPdtEntryAddr)
|
flushTLBEntryFn(lastPdtEntryAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mapFn(page, frame, flags, allocFn)
|
err := mapFn(page, frame, flags)
|
||||||
|
|
||||||
if activePdtFrame != pdt.pdtFrame {
|
if activePdtFrame != pdt.pdtFrame {
|
||||||
lastPdtEntry.SetFrame(activePdtFrame)
|
lastPdtEntry.SetFrame(activePdtFrame)
|
||||||
|
@ -15,7 +15,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
t.Skip("test requires amd64 runtime; skipping")
|
t.Skip("test requires amd64 runtime; skipping")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(origFlushTLBEntry func(uintptr), origActivePDT func() uintptr, origMapTemporary func(pmm.Frame, FrameAllocatorFn) (Page, *kernel.Error), origUnmap func(Page) *kernel.Error) {
|
defer func(origFlushTLBEntry func(uintptr), origActivePDT func() uintptr, origMapTemporary func(pmm.Frame) (Page, *kernel.Error), origUnmap func(Page) *kernel.Error) {
|
||||||
flushTLBEntryFn = origFlushTLBEntry
|
flushTLBEntryFn = origFlushTLBEntry
|
||||||
activePDTFn = origActivePDT
|
activePDTFn = origActivePDT
|
||||||
mapTemporaryFn = origMapTemporary
|
mapTemporaryFn = origMapTemporary
|
||||||
@ -32,7 +32,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
return pdtFrame.Address()
|
return pdtFrame.Address()
|
||||||
}
|
}
|
||||||
|
|
||||||
mapTemporaryFn = func(_ pmm.Frame, _ FrameAllocatorFn) (Page, *kernel.Error) {
|
mapTemporaryFn = func(_ pmm.Frame) (Page, *kernel.Error) {
|
||||||
t.Fatal("unexpected call to MapTemporary")
|
t.Fatal("unexpected call to MapTemporary")
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pdt.Init(pdtFrame, nil); err != nil {
|
if err := pdt.Init(pdtFrame); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -61,7 +61,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
mapTemporaryFn = func(_ pmm.Frame, _ FrameAllocatorFn) (Page, *kernel.Error) {
|
mapTemporaryFn = func(_ pmm.Frame) (Page, *kernel.Error) {
|
||||||
return PageFromAddress(uintptr(unsafe.Pointer(&physPage[0]))), nil
|
return PageFromAddress(uintptr(unsafe.Pointer(&physPage[0]))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pdt.Init(pdtFrame, nil); err != nil {
|
if err := pdt.Init(pdtFrame); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
|
|
||||||
expErr := &kernel.Error{Module: "test", Message: "error mapping page"}
|
expErr := &kernel.Error{Module: "test", Message: "error mapping page"}
|
||||||
|
|
||||||
mapTemporaryFn = func(_ pmm.Frame, _ FrameAllocatorFn) (Page, *kernel.Error) {
|
mapTemporaryFn = func(_ pmm.Frame) (Page, *kernel.Error) {
|
||||||
return 0, expErr
|
return 0, expErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ func TestPageDirectoryTableInitAmd64(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pdt.Init(pdtFrame, nil); err != expErr {
|
if err := pdt.Init(pdtFrame); err != expErr {
|
||||||
t.Fatalf("expected to get error: %v; got %v", *expErr, err)
|
t.Fatalf("expected to get error: %v; got %v", *expErr, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -130,7 +130,7 @@ func TestPageDirectoryTableMapAmd64(t *testing.T) {
|
|||||||
t.Skip("test requires amd64 runtime; skipping")
|
t.Skip("test requires amd64 runtime; skipping")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(origFlushTLBEntry func(uintptr), origActivePDT func() uintptr, origMap func(Page, pmm.Frame, PageTableEntryFlag, FrameAllocatorFn) *kernel.Error) {
|
defer func(origFlushTLBEntry func(uintptr), origActivePDT func() uintptr, origMap func(Page, pmm.Frame, PageTableEntryFlag) *kernel.Error) {
|
||||||
flushTLBEntryFn = origFlushTLBEntry
|
flushTLBEntryFn = origFlushTLBEntry
|
||||||
activePDTFn = origActivePDT
|
activePDTFn = origActivePDT
|
||||||
mapFn = origMap
|
mapFn = origMap
|
||||||
@ -147,7 +147,7 @@ func TestPageDirectoryTableMapAmd64(t *testing.T) {
|
|||||||
return pdtFrame.Address()
|
return pdtFrame.Address()
|
||||||
}
|
}
|
||||||
|
|
||||||
mapFn = func(_ Page, _ pmm.Frame, _ PageTableEntryFlag, _ FrameAllocatorFn) *kernel.Error {
|
mapFn = func(_ Page, _ pmm.Frame, _ PageTableEntryFlag) *kernel.Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ func TestPageDirectoryTableMapAmd64(t *testing.T) {
|
|||||||
flushCallCount++
|
flushCallCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pdt.Map(page, pmm.Frame(321), FlagRW, nil); err != nil {
|
if err := pdt.Map(page, pmm.Frame(321), FlagRW); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ func TestPageDirectoryTableMapAmd64(t *testing.T) {
|
|||||||
return activePdtFrame.Address()
|
return activePdtFrame.Address()
|
||||||
}
|
}
|
||||||
|
|
||||||
mapFn = func(_ Page, _ pmm.Frame, _ PageTableEntryFlag, _ FrameAllocatorFn) *kernel.Error {
|
mapFn = func(_ Page, _ pmm.Frame, _ PageTableEntryFlag) *kernel.Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ func TestPageDirectoryTableMapAmd64(t *testing.T) {
|
|||||||
flushCallCount++
|
flushCallCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pdt.Map(page, pmm.Frame(321), FlagRW, nil); err != nil {
|
if err := pdt.Map(page, pmm.Frame(321), FlagRW); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
kernel/mem/vmm/vmm.go
Normal file
17
kernel/mem/vmm/vmm.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package vmm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/achilleasa/gopher-os/kernel"
|
||||||
|
"github.com/achilleasa/gopher-os/kernel/mem/pmm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var frameAllocator FrameAllocatorFn
|
||||||
|
|
||||||
|
// FrameAllocatorFn is a function that can allocate physical frames.
|
||||||
|
type FrameAllocatorFn func() (pmm.Frame, *kernel.Error)
|
||||||
|
|
||||||
|
// SetFrameAllocator registers a frame allocator function that will be used by
|
||||||
|
// the vmm code when new physical frames need to be allocated.
|
||||||
|
func SetFrameAllocator(allocFn FrameAllocatorFn) {
|
||||||
|
frameAllocator = allocFn
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user