From d4c0d5237292b1c562fc01bd3bc106bb6c281ed5 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Tue, 28 Mar 2017 08:18:17 +0100 Subject: [PATCH] Implement multiboot info structure tag scanner --- kernel/multiboot/multiboot.go | 115 +++++++++++++++++++++++++ kernel/multiboot/multiboot_test.go | 132 +++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100644 kernel/multiboot/multiboot.go create mode 100644 kernel/multiboot/multiboot_test.go diff --git a/kernel/multiboot/multiboot.go b/kernel/multiboot/multiboot.go new file mode 100644 index 0000000..84b84eb --- /dev/null +++ b/kernel/multiboot/multiboot.go @@ -0,0 +1,115 @@ +package multiboot + +import "unsafe" + +type tagType uint32 + +const ( + tagMbSectionEnd tagType = iota + tagBootCmdLine + tagBootLoaderName + tagModules + tagBasicMemoryInfo + tagBiosBootDevice + tagMemoryMap + tagVbeInfo + tagFramebufferInfo + tagElfSymbols + tagApmTable +) + +// info describes the multiboot info section header. +type info struct { + // Total size of multiboot info section. + totalSize uint32 + + // Always set to zero; reserved for future use + reserved uint32 +} + +// tagHeader describes the header the preceedes each tag. +type tagHeader struct { + // The type of the tag + tagType tagType + + // The size of the tag including the header but *not* including any + // padding. According to the spec, each tag starts at a 8-byte aligned + // address. + size uint32 +} + +// mmapHeader describes the header for a memory map specification. +type mmapHeader struct { + // The size of each entry. + entrySize uint32 + + // The version of the entries that follow. + entryVersion uint32 +} + +// MemoryEntryType defines the type of a MemoryMapEntry. +type MemoryEntryType uint32 + +const ( + // MemAvailable indicates that the memory region is available for use. + MemAvailable MemoryEntryType = iota + 1 + + // MemReserved indicates that the memory region is not available for use. + MemReserved + + // MemAcpiReclaimable indicates a memory region that holds ACPI info that + // can be reused by the OS. + MemAcpiReclaimable + + // MemNvs indicates memory that must be preserved when hibernating. + MemNvs + + // Any value >= memUnknown will be mapped to MemReserved. + memUnknown +) + +/// MemoryMapEntry describes a memory region entry, namely its physical address, +// its length and its type. +type MemoryMapEntry struct { + // The physical address for this memory region. + PhysAddress uint64 + + // The length of the memory region. + Length uint64 + + // The type of this entry. + Type MemoryEntryType +} + +var ( + infoData uintptr +) + +// 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. +func SetInfoPtr(ptr uintptr) { + infoData = ptr +} + +// 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. +// +// If the tag is not present in the multiboot info, findTagSection will return +// back (0,0). +func findTagByType(tagType tagType) (uintptr, uint32) { + var ptrTagHeader *tagHeader + + curPtr := infoData + 8 + for ptrTagHeader = (*tagHeader)(unsafe.Pointer(curPtr)); ptrTagHeader.tagType != tagMbSectionEnd; ptrTagHeader = (*tagHeader)(unsafe.Pointer(curPtr)) { + if ptrTagHeader.tagType == tagType { + return curPtr + 8, ptrTagHeader.size - 8 + } + + // Tags are aligned at 8-byte aligned addresses + curPtr += uintptr(int32(ptrTagHeader.size+7) & ^7) + } + + return 0, 0 +} diff --git a/kernel/multiboot/multiboot_test.go b/kernel/multiboot/multiboot_test.go new file mode 100644 index 0000000..f97991a --- /dev/null +++ b/kernel/multiboot/multiboot_test.go @@ -0,0 +1,132 @@ +package multiboot + +import ( + "testing" + "unsafe" +) + +func TestFindTagByType(t *testing.T) { + specs := []struct { + tagType tagType + expSize uint32 + }{ + {tagBootCmdLine, 1}, + {tagBootLoaderName, 27}, + {tagBasicMemoryInfo, 8}, + {tagBiosBootDevice, 12}, + {tagMemoryMap, 152}, + {tagFramebufferInfo, 24}, + {tagElfSymbols, 972}, + {tagApmTable, 20}, + } + + SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0]))) + + for specIndex, spec := range specs { + _, size := findTagByType(spec.tagType) + + if size != spec.expSize { + t.Errorf("[spec %d] expected tag size for tag type %d to be %d; got %d", specIndex, spec.tagType, spec.expSize, size) + + } + } +} + +func TestFindTagByTypeWithMissingTag(t *testing.T) { + SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0]))) + + if offset, size := findTagByType(tagModules); offset != 0 || size != 0 { + t.Fatalf("expected findTagByType to return (0,0) for missing tag; got (%d, %d)", offset, size) + } +} + +var ( + // 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, + 0, 171, 253, 7, 118, 119, 123, 0, 2, 0, 0, 0, 35, 0, 0, 0, + 71, 82, 85, 66, 32, 50, 46, 48, 50, 126, 98, 101, 116, 97, 50, 45, + 57, 117, 98, 117, 110, 116, 117, 49, 46, 54, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 0, 28, 0, 0, 0, 2, 1, 0, 240, 4, 213, 0, 0, + 0, 240, 0, 240, 3, 0, 240, 255, 240, 255, 240, 255, 0, 0, 0, 0, + 6, 0, 0, 0, 160, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 9, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 252, 9, 0, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, + 0, 0, 238, 7, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 254, 7, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 212, 3, 0, 0, 24, 0, 0, 0, 40, 0, 0, 0, + 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, + 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 38, 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, + 0, 16, 16, 0, 0, 32, 0, 0, 135, 26, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, + 1, 0, 0, 0, 2, 0, 0, 0, 0, 48, 20, 0, 0, 64, 4, 0, + 194, 167, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, + 0, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, + 224, 215, 21, 0, 224, 231, 5, 0, 176, 6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 1, 0, 0, 0, 2, 0, 0, 0, 144, 222, 21, 0, 144, 238, 5, 0, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 72, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, + 160, 222, 21, 0, 160, 238, 5, 0, 119, 23, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, + 7, 0, 0, 0, 2, 0, 0, 0, 32, 246, 23, 0, 32, 6, 8, 0, + 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 100, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 24, 0, 0, 16, 8, 0, 204, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 106, 0, 0, 0, + 1, 0, 0, 0, 3, 0, 0, 0, 224, 5, 24, 0, 224, 21, 8, 0, + 178, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 117, 0, 0, 0, 8, 0, 0, 0, 3, 4, 0, 0, + 148, 15, 24, 0, 146, 31, 8, 0, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 0, 0, 0, 16, 24, 0, 146, 31, 8, 0, + 176, 61, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, + 0, 0, 0, 0, 128, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, + 192, 77, 25, 0, 146, 31, 8, 0, 32, 56, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 224, 133, 25, 0, 146, 31, 8, 0, + 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 153, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 32, 134, 25, 0, 210, 31, 8, 0, 129, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 169, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 161, 160, 25, 0, 83, 58, 8, 0, + 2, 201, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 181, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 163, 105, 27, 0, 85, 3, 10, 0, 25, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 188, 106, 27, 0, 110, 4, 10, 0, + 67, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 207, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 28, 0, 184, 157, 10, 0, 252, 112, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 252, 116, 28, 0, 180, 14, 11, 0, + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 231, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 12, 117, 28, 0, 196, 14, 11, 0, 239, 79, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 251, 196, 28, 0, 179, 94, 11, 0, + 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 244, 197, 28, 0, 108, 99, 11, 0, 80, 77, 0, 0, 23, 0, 0, 0, + 210, 4, 0, 0, 4, 0, 0, 0, 16, 0, 0, 0, 9, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 68, 19, 29, 0, 188, 176, 11, 0, + 107, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 16, 0, 0, 0, + 127, 2, 0, 0, 128, 251, 1, 0, 5, 0, 0, 0, 20, 0, 0, 0, + 224, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 8, 0, 0, 0, 32, 0, 0, 0, 0, 128, 11, 0, 0, 0, 0, 0, + 160, 0, 0, 0, 80, 0, 0, 0, 25, 0, 0, 0, 16, 2, 0, 0, + 14, 0, 0, 0, 28, 0, 0, 0, 82, 83, 68, 32, 80, 84, 82, 32, + 89, 66, 79, 67, 72, 83, 32, 0, 220, 24, 254, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 0, 0, 0, + } +)