1
0
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:
Achilleas Anagnostopoulos 2017-03-28 08:22:46 +01:00
parent d4c0d52372
commit 558cbf5f17
2 changed files with 88 additions and 0 deletions

View File

@ -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.

View File

@ -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,