From 13ef4cd08d450f13101352f3d64a5a79fa41fce1 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Sat, 8 Jul 2017 20:38:14 +0100 Subject: [PATCH] Map physical address of the vga text console framebuffer in DriverInit Currently, the kernel can write to 0xb80000 because this is part of the initial identify mapping set up by the rt0 code. When we establish new mappings for the kernel using its real VMA address then writes to the framebuffer will cause a page fault unless we explicitly map it. --- src/gopheros/device/video/console/probe.go | 10 +++- src/gopheros/device/video/console/vga_text.go | 47 +++++++++++++------ .../device/video/console/vga_text_test.go | 35 ++++++++++++-- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/gopheros/device/video/console/probe.go b/src/gopheros/device/video/console/probe.go index 1981378..1937343 100644 --- a/src/gopheros/device/video/console/probe.go +++ b/src/gopheros/device/video/console/probe.go @@ -1,9 +1,15 @@ package console -import "gopheros/device" -import "gopheros/kernel/hal/multiboot" +import ( + "gopheros/device" + "gopheros/kernel/cpu" + "gopheros/kernel/hal/multiboot" + "gopheros/kernel/mem/vmm" +) var ( + mapRegionFn = vmm.MapRegion + portWriteByteFn = cpu.PortWriteByte getFramebufferInfoFn = multiboot.GetFramebufferInfo // ProbeFuncs is a slice of device probe functions that is used by diff --git a/src/gopheros/device/video/console/vga_text.go b/src/gopheros/device/video/console/vga_text.go index f5be66b..0215363 100644 --- a/src/gopheros/device/video/console/vga_text.go +++ b/src/gopheros/device/video/console/vga_text.go @@ -3,16 +3,17 @@ package console import ( "gopheros/device" "gopheros/kernel" - "gopheros/kernel/cpu" "gopheros/kernel/hal/multiboot" + "gopheros/kernel/kfmt" + "gopheros/kernel/mem" + "gopheros/kernel/mem/pmm" + "gopheros/kernel/mem/vmm" "image/color" "io" "reflect" "unsafe" ) -var portWriteByteFn = cpu.PortWriteByte - // VgaTextConsole implements an EGA-compatible 80x25 text console using VGA // mode 0x3. The console supports the default 16 EGA colors which can be // overridden using the SetPaletteColor method. @@ -28,7 +29,8 @@ type VgaTextConsole struct { width uint32 height uint32 - fb []uint16 + fbPhysAddr uintptr + fb []uint16 palette color.Palette defaultFg uint8 @@ -40,15 +42,10 @@ type VgaTextConsole struct { // framebuffer mapped to fbPhysAddr. func NewVgaTextConsole(columns, rows uint32, fbPhysAddr uintptr) *VgaTextConsole { return &VgaTextConsole{ - width: columns, - height: rows, - clearChar: uint16(' '), - // overlay a 16bit slice over the fbPhysAddr - fb: *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{ - Len: int(columns * rows), - Cap: int(columns * rows), - Data: fbPhysAddr, - })), + width: columns, + height: rows, + fbPhysAddr: fbPhysAddr, + clearChar: uint16(' '), palette: color.Palette{ color.RGBA{R: 0, G: 0, B: 1}, /* black */ color.RGBA{R: 0, G: 0, B: 128}, /* blue */ @@ -198,7 +195,29 @@ func (cons *VgaTextConsole) DriverVersion() (uint16, uint16, uint16) { } // DriverInit initializes this driver. -func (cons *VgaTextConsole) DriverInit(_ io.Writer) *kernel.Error { return nil } +func (cons *VgaTextConsole) DriverInit(w io.Writer) *kernel.Error { + // Map the framebuffer so we can write to it + fbSize := mem.Size(cons.width * cons.height * 2) + fbPage, err := mapRegionFn( + pmm.Frame(cons.fbPhysAddr>>mem.PageShift), + fbSize, + vmm.FlagPresent|vmm.FlagRW, + ) + + if err != nil { + return err + } + + cons.fb = *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{ + Len: int(fbSize >> 1), + Cap: int(fbSize >> 1), + Data: fbPage.Address(), + })) + + kfmt.Fprintf(w, "mapped framebuffer to 0x%x\n", fbPage.Address()) + + return nil +} // probeForVgaTextConsole checks for the presence of a vga text console. func probeForVgaTextConsole() device.Driver { diff --git a/src/gopheros/device/video/console/vga_text_test.go b/src/gopheros/device/video/console/vga_text_test.go index 3d5cb25..d18b9be 100644 --- a/src/gopheros/device/video/console/vga_text_test.go +++ b/src/gopheros/device/video/console/vga_text_test.go @@ -2,8 +2,12 @@ package console import ( "gopheros/device" + "gopheros/kernel" "gopheros/kernel/cpu" "gopheros/kernel/hal/multiboot" + "gopheros/kernel/mem" + "gopheros/kernel/mem/pmm" + "gopheros/kernel/mem/vmm" "image/color" "testing" "unsafe" @@ -63,6 +67,7 @@ func TestVgaTextFill(t *testing.T) { fb := make([]uint16, 80*25) cons := NewVgaTextConsole(80, 25, uintptr(unsafe.Pointer(&fb[0]))) + cons.fb = fb cw, ch := cons.Dimensions() testPat := uint16(0xDEAD) @@ -101,6 +106,7 @@ nextSpec: func TestVgaTextScroll(t *testing.T) { fb := make([]uint16, 80*25) cons := NewVgaTextConsole(80, 25, uintptr(unsafe.Pointer(&fb[0]))) + cons.fb = fb cw, ch := cons.Dimensions() t.Run("up", func(t *testing.T) { @@ -176,6 +182,7 @@ func TestVgaTextScroll(t *testing.T) { func TestVgaTextWrite(t *testing.T) { fb := make([]uint16, 80*25) cons := NewVgaTextConsole(80, 25, uintptr(unsafe.Pointer(&fb[0]))) + cons.fb = fb defaultFg, defaultBg := cons.DefaultColors() t.Run("off-screen", func(t *testing.T) { @@ -309,12 +316,11 @@ func TestVgaTextSetPaletteColor(t *testing.T) { } func TestVgaTextDriverInterface(t *testing.T) { + defer func() { + mapRegionFn = vmm.MapRegion + }() var dev device.Driver = NewVgaTextConsole(80, 25, 0) - if err := dev.DriverInit(nil); err != nil { - t.Fatal(err) - } - if dev.DriverName() == "" { t.Fatal("DriverName() returned an empty string") } @@ -322,6 +328,27 @@ func TestVgaTextDriverInterface(t *testing.T) { if major, minor, patch := dev.DriverVersion(); major+minor+patch == 0 { t.Fatal("DriverVersion() returned an invalid version number") } + + t.Run("init success", func(t *testing.T) { + mapRegionFn = func(_ pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + return 0xb8000, nil + } + + if err := dev.DriverInit(nil); err != nil { + t.Fatal(err) + } + }) + + t.Run("init fail", func(t *testing.T) { + expErr := &kernel.Error{Module: "test", Message: "something went wrong"} + mapRegionFn = func(_ pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + return 0, expErr + } + + if err := dev.DriverInit(nil); err != expErr { + t.Fatalf("expected error: %v; got %v", expErr, err) + } + }) } func TestVgaTextProbe(t *testing.T) {