mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Implement visitor for examining reported memory map entries
Since the actual size of each memory entry is not known in advance (bootloaders may append additional information to it) but needs to be queried off the memory map tag header we cannot reserve space for it as no memory allocation is yet available. Instead, a visitor pattern was implemented to allow the memory manager initialization block to easily mark the appropriate pages as reserved
This commit is contained in:
parent
d4c0d52372
commit
558cbf5f17
@ -85,6 +85,10 @@ var (
|
||||
infoData uintptr
|
||||
)
|
||||
|
||||
// MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions
|
||||
// for each memory region defined by the boot loader
|
||||
type MemRegionVisitor func(entry *MemoryMapEntry)
|
||||
|
||||
// SetInfoPtr updates the internal multiboot information pointer to the given
|
||||
// value. This function must be invoked before invoking any other function
|
||||
// exported by this package.
|
||||
@ -92,6 +96,34 @@ func SetInfoPtr(ptr uintptr) {
|
||||
infoData = ptr
|
||||
}
|
||||
|
||||
// VisitMemRegions will invoke the supplied visitor for each memory region that
|
||||
// is defined by the multiboot info data that we received from the bootloader.
|
||||
func VisitMemRegions(visitor MemRegionVisitor) {
|
||||
curPtr, size := findTagByType(tagMemoryMap)
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// curPtr points to the memory map header (2 dwords long)
|
||||
ptrMapHeader := (*mmapHeader)(unsafe.Pointer(curPtr))
|
||||
endPtr := curPtr + uintptr(size)
|
||||
curPtr += 8
|
||||
|
||||
var entry *MemoryMapEntry
|
||||
for curPtr != endPtr {
|
||||
entry = (*MemoryMapEntry)(unsafe.Pointer(curPtr))
|
||||
|
||||
// Mark unknown entry types as reserved
|
||||
if entry.Type == 0 || entry.Type > memUnknown {
|
||||
entry.Type = MemReserved
|
||||
}
|
||||
|
||||
visitor(entry)
|
||||
|
||||
curPtr += uintptr(ptrMapHeader.entrySize)
|
||||
}
|
||||
}
|
||||
|
||||
// findTagByType scans the multiboot info data looking for the start of of the
|
||||
// specified type. It returns a pointer to the tag contents start offset and
|
||||
// the content length exluding the tag header.
|
||||
|
@ -40,7 +40,63 @@ func TestFindTagByTypeWithMissingTag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestVisitMemRegion(t *testing.T) {
|
||||
specs := []struct {
|
||||
expPhys uint64
|
||||
expLen uint64
|
||||
expType MemoryEntryType
|
||||
}{
|
||||
// This region type is actually MemAvailable but we patch it to
|
||||
// a bogus value to test whether it gets flagged as reserved
|
||||
{0, 654336, MemReserved},
|
||||
{654336, 1024, MemReserved},
|
||||
{983040, 65536, MemReserved},
|
||||
{1048576, 133038080, MemAvailable},
|
||||
{134086656, 131072, MemReserved},
|
||||
{4294705152, 262144, MemReserved},
|
||||
}
|
||||
|
||||
var visitCount int
|
||||
|
||||
SetInfoPtr(uintptr(unsafe.Pointer(&emptyInfoData[0])))
|
||||
VisitMemRegions(func(_ *MemoryMapEntry) {
|
||||
visitCount++
|
||||
})
|
||||
|
||||
if visitCount != 0 {
|
||||
t.Fatal("expected visitor not to be invoked when no memory map tag is present")
|
||||
}
|
||||
|
||||
// Set a bogus type for the first entry in the map
|
||||
SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0])))
|
||||
multibootInfoTestData[128] = 0xFF
|
||||
|
||||
VisitMemRegions(func(entry *MemoryMapEntry) {
|
||||
if entry.PhysAddress != specs[visitCount].expPhys {
|
||||
t.Errorf("[visit %d] expected physical address to be %x; got %x", visitCount, specs[visitCount].expPhys, entry.PhysAddress)
|
||||
}
|
||||
if entry.Length != specs[visitCount].expLen {
|
||||
t.Errorf("[visit %d] expected region len to be %x; got %x", visitCount, specs[visitCount].expLen, entry.Length)
|
||||
}
|
||||
if entry.Type != specs[visitCount].expType {
|
||||
t.Errorf("[visit %d] expected region type to be %d; got %d", visitCount, specs[visitCount].expType, entry.Type)
|
||||
}
|
||||
visitCount++
|
||||
})
|
||||
|
||||
if visitCount != len(specs) {
|
||||
t.Errorf("expected the visitor func to be invoked %d times; got %d", len(specs), visitCount)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
emptyInfoData = []byte{
|
||||
0, 0, 0, 0, // size
|
||||
0, 0, 0, 0, // reserved
|
||||
0, 0, 0, 0, // tag with type zero and length zero
|
||||
0, 0, 0, 0,
|
||||
}
|
||||
|
||||
// A dump of multiboot data when running under qemu.
|
||||
multibootInfoTestData = []byte{
|
||||
72, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9, 0, 0, 0,
|
||||
|
Loading…
x
Reference in New Issue
Block a user