diff --git a/kernel/multiboot/multiboot.go b/kernel/multiboot/multiboot.go index 977a40a..a7336fb 100644 --- a/kernel/multiboot/multiboot.go +++ b/kernel/multiboot/multiboot.go @@ -47,6 +47,38 @@ type mmapHeader struct { entryVersion uint32 } +// FramebufferType defines the type of the initialized framebuffer. +type FramebufferType uint8 + +const ( + // FrameBufferTypeIndexed specifies a 256-color palette. + FrameBufferTypeIndexed FramebufferType = iota + + // FramebufferTypeRGB specifies direct RGB mode. + FramebufferTypeRGB + + // FramebufferTypeEGA specifies EGA text mode. + FramebufferTypeEGA +) + +// FramebufferInfo provides information about the initialized framebuffer. +type FramebufferInfo struct { + // The framebuffer physical address. + PhysAddr uint64 + + // Row pitch in bytes. + Pitch uint32 + + // Width and height in pixels (or characters if Type = FramebufferTypeEGA) + Width, Height uint32 + + // Bits per pixel (non EGA modes only). + Bpp uint8 + + // Framebuffer type. + Type FramebufferType +} + // MemoryEntryType defines the type of a MemoryMapEntry. type MemoryEntryType uint32 @@ -86,7 +118,7 @@ var ( ) // MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions -// for each memory region defined by the boot loader +// for each memory region provided by the boot loader. type MemRegionVisitor func(entry *MemoryMapEntry) // SetInfoPtr updates the internal multiboot information pointer to the given @@ -124,6 +156,19 @@ func VisitMemRegions(visitor MemRegionVisitor) { } } +// GetFramebufferInfo returns information about the framebuffer initialized by the +// bootloader. This function returns nil if no framebuffer info is available. +func GetFramebufferInfo() *FramebufferInfo { + var info *FramebufferInfo + + curPtr, size := findTagByType(tagFramebufferInfo) + if size != 0 { + info = (*FramebufferInfo)(unsafe.Pointer(curPtr)) + } + + return info +} + // 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. diff --git a/kernel/multiboot/multiboot_test.go b/kernel/multiboot/multiboot_test.go index 7607e1c..62193b3 100644 --- a/kernel/multiboot/multiboot_test.go +++ b/kernel/multiboot/multiboot_test.go @@ -89,6 +89,33 @@ func TestVisitMemRegion(t *testing.T) { } } +func TestGetFramebufferInfo(t *testing.T) { + SetInfoPtr(uintptr(unsafe.Pointer(&emptyInfoData[0]))) + + if GetFramebufferInfo() != nil { + t.Fatalf("expected GetFramebufferInfo() to return nil when no framebuffer tag is present") + } + + SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0]))) + fbInfo := GetFramebufferInfo() + + if fbInfo.Type != FramebufferTypeEGA { + t.Errorf("expected framebuffer type to be %d; got %d", FramebufferTypeEGA, fbInfo.Type) + } + + if fbInfo.PhysAddr != 0xB8000 { + t.Errorf("expected physical address for EGA text mode to be 0xB8000; got %x", fbInfo.PhysAddr) + } + + if fbInfo.Width != 80 || fbInfo.Height != 25 { + t.Errorf("expected framebuffer dimensions to be 80x25; got %dx%d", fbInfo.Width, fbInfo.Height) + } + + if fbInfo.Pitch != 160 { + t.Errorf("expected pitch to be 160; got %x", fbInfo.Pitch) + } +} + var ( emptyInfoData = []byte{ 0, 0, 0, 0, // size