1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

vmm: switch exception handling to use the new gate package

This commit is contained in:
Achilleas Anagnostopoulos 2018-05-31 21:22:29 +01:00
parent 7b12fbd940
commit 7deeab3cbc
4 changed files with 59 additions and 53 deletions

View File

@ -2,12 +2,24 @@ package vmm
import ( import (
"gopheros/kernel" "gopheros/kernel"
"gopheros/kernel/irq" "gopheros/kernel/gate"
"gopheros/kernel/kfmt" "gopheros/kernel/kfmt"
"gopheros/kernel/mm" "gopheros/kernel/mm"
) )
func pageFaultHandler(errorCode uint64, frame *irq.Frame, regs *irq.Regs) { var (
// handleInterruptFn is used by tests.
handleInterruptFn = gate.HandleInterrupt
)
func installFaultHandlers() {
handleInterruptFn(gate.PageFaultException, 0, pageFaultHandler)
handleInterruptFn(gate.GPFException, 0, generalProtectionFaultHandler)
}
// pageFaultHandler is invoked when a PDT or PDT-entry is not present or when a
// RW protection check fails.
func pageFaultHandler(regs *gate.Registers) {
var ( var (
faultAddress = uintptr(readCR2Fn()) faultAddress = uintptr(readCR2Fn())
faultPage = mm.PageFromAddress(faultAddress) faultPage = mm.PageFromAddress(faultAddress)
@ -35,9 +47,9 @@ func pageFaultHandler(errorCode uint64, frame *irq.Frame, regs *irq.Regs) {
) )
if copy, err = mm.AllocFrame(); err != nil { if copy, err = mm.AllocFrame(); err != nil {
nonRecoverablePageFault(faultAddress, errorCode, frame, regs, err) nonRecoverablePageFault(faultAddress, regs, err)
} else if tmpPage, err = mapTemporaryFn(copy); err != nil { } else if tmpPage, err = mapTemporaryFn(copy); err != nil {
nonRecoverablePageFault(faultAddress, errorCode, frame, regs, err) nonRecoverablePageFault(faultAddress, regs, err)
} else { } else {
// Copy page contents, mark as RW and remove CoW flag // Copy page contents, mark as RW and remove CoW flag
kernel.Memcopy(faultPage.Address(), tmpPage.Address(), mm.PageSize) kernel.Memcopy(faultPage.Address(), tmpPage.Address(), mm.PageSize)
@ -55,44 +67,46 @@ func pageFaultHandler(errorCode uint64, frame *irq.Frame, regs *irq.Regs) {
} }
} }
nonRecoverablePageFault(faultAddress, errorCode, frame, regs, errUnrecoverableFault) nonRecoverablePageFault(faultAddress, regs, errUnrecoverableFault)
} }
func nonRecoverablePageFault(faultAddress uintptr, errorCode uint64, frame *irq.Frame, regs *irq.Regs, err *kernel.Error) { // generalProtectionFaultHandler is invoked for various reasons:
// - segment errors (privilege, type or limit violations)
// - executing privileged instructions outside ring-0
// - attempts to access reserved or unimplemented CPU registers
func generalProtectionFaultHandler(regs *gate.Registers) {
kfmt.Printf("\nGeneral protection fault while accessing address: 0x%x\n", readCR2Fn())
kfmt.Printf("Registers:\n")
regs.DumpTo(kfmt.GetOutputSink())
// TODO: Revisit this when user-mode tasks are implemented
panic(errUnrecoverableFault)
}
func nonRecoverablePageFault(faultAddress uintptr, regs *gate.Registers, err *kernel.Error) {
kfmt.Printf("\nPage fault while accessing address: 0x%16x\nReason: ", faultAddress) kfmt.Printf("\nPage fault while accessing address: 0x%16x\nReason: ", faultAddress)
switch { switch {
case errorCode == 0: case regs.Info == 0:
kfmt.Printf("read from non-present page") kfmt.Printf("read from non-present page")
case errorCode == 1: case regs.Info == 1:
kfmt.Printf("page protection violation (read)") kfmt.Printf("page protection violation (read)")
case errorCode == 2: case regs.Info == 2:
kfmt.Printf("write to non-present page") kfmt.Printf("write to non-present page")
case errorCode == 3: case regs.Info == 3:
kfmt.Printf("page protection violation (write)") kfmt.Printf("page protection violation (write)")
case errorCode == 4: case regs.Info == 4:
kfmt.Printf("page-fault in user-mode") kfmt.Printf("page-fault in user-mode")
case errorCode == 8: case regs.Info == 8:
kfmt.Printf("page table has reserved bit set") kfmt.Printf("page table has reserved bit set")
case errorCode == 16: case regs.Info == 16:
kfmt.Printf("instruction fetch") kfmt.Printf("instruction fetch")
default: default:
kfmt.Printf("unknown") kfmt.Printf("unknown")
} }
kfmt.Printf("\n\nRegisters:\n") kfmt.Printf("\n\nRegisters:\n")
regs.Print() regs.DumpTo(kfmt.GetOutputSink())
frame.Print()
// TODO: Revisit this when user-mode tasks are implemented // TODO: Revisit this when user-mode tasks are implemented
panic(err) panic(err)
} }
func generalProtectionFaultHandler(_ uint64, frame *irq.Frame, regs *irq.Regs) {
kfmt.Printf("\nGeneral protection fault while accessing address: 0x%x\n", readCR2Fn())
kfmt.Printf("Registers:\n")
regs.Print()
frame.Print()
// TODO: Revisit this when user-mode tasks are implemented
panic(errUnrecoverableFault)
}

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"gopheros/kernel" "gopheros/kernel"
"gopheros/kernel/cpu" "gopheros/kernel/cpu"
"gopheros/kernel/irq" "gopheros/kernel/gate"
"gopheros/kernel/kfmt" "gopheros/kernel/kfmt"
"gopheros/kernel/mm" "gopheros/kernel/mm"
"strings" "strings"
@ -15,8 +15,7 @@ import (
func TestRecoverablePageFault(t *testing.T) { func TestRecoverablePageFault(t *testing.T) {
var ( var (
frame irq.Frame regs gate.Registers
regs irq.Regs
pageEntry pageTableEntry pageEntry pageTableEntry
origPage = make([]byte, mm.PageSize) origPage = make([]byte, mm.PageSize)
clonedPage = make([]byte, mm.PageSize) clonedPage = make([]byte, mm.PageSize)
@ -91,7 +90,8 @@ func TestRecoverablePageFault(t *testing.T) {
pageEntry = 0 pageEntry = 0
pageEntry.SetFlags(spec.pteFlags) pageEntry.SetFlags(spec.pteFlags)
pageFaultHandler(2, &frame, &regs) regs.Info = 2
pageFaultHandler(&regs)
}) })
} }
@ -141,8 +141,7 @@ func TestNonRecoverablePageFault(t *testing.T) {
} }
var ( var (
regs irq.Regs regs gate.Registers
frame irq.Frame
buf bytes.Buffer buf bytes.Buffer
) )
@ -156,7 +155,8 @@ func TestNonRecoverablePageFault(t *testing.T) {
} }
}() }()
nonRecoverablePageFault(0xbadf00d000, spec.errCode, &frame, &regs, errUnrecoverableFault) regs.Info = spec.errCode
nonRecoverablePageFault(0xbadf00d000, &regs, errUnrecoverableFault)
if got := buf.String(); !strings.Contains(got, spec.expReason) { if got := buf.String(); !strings.Contains(got, spec.expReason) {
t.Errorf("expected reason %q; got output:\n%q", spec.expReason, got) t.Errorf("expected reason %q; got output:\n%q", spec.expReason, got)
} }
@ -169,10 +169,7 @@ func TestGPFHandler(t *testing.T) {
readCR2Fn = cpu.ReadCR2 readCR2Fn = cpu.ReadCR2
}() }()
var ( var regs gate.Registers
regs irq.Regs
frame irq.Frame
)
readCR2Fn = func() uint64 { readCR2Fn = func() uint64 {
return 0xbadf00d000 return 0xbadf00d000
@ -184,5 +181,5 @@ func TestGPFHandler(t *testing.T) {
} }
}() }()
generalProtectionFaultHandler(0, &frame, &regs) generalProtectionFaultHandler(&regs)
} }

View File

@ -3,14 +3,12 @@ package vmm
import ( import (
"gopheros/kernel" "gopheros/kernel"
"gopheros/kernel/cpu" "gopheros/kernel/cpu"
"gopheros/kernel/irq"
"gopheros/kernel/mm" "gopheros/kernel/mm"
) )
var ( var (
// the following functions are mocked by tests and are automatically // the following functions are mocked by tests and are automatically
// inlined by the compiler. // inlined by the compiler.
handleExceptionWithCodeFn = irq.HandleExceptionWithCode
readCR2Fn = cpu.ReadCR2 readCR2Fn = cpu.ReadCR2
translateFn = Translate translateFn = Translate
@ -24,13 +22,10 @@ func Init(kernelPageOffset uintptr) *kernel.Error {
return err return err
} }
if err := reserveZeroedFrame(); err != nil { // Install arch-specific handlers for vmm-related faults.
return err installFaultHandlers()
}
handleExceptionWithCodeFn(irq.PageFaultException, pageFaultHandler) return reserveZeroedFrame()
handleExceptionWithCodeFn(irq.GPFException, generalProtectionFaultHandler)
return nil
} }
// reserveZeroedFrame reserves a physical frame to be used together with // reserveZeroedFrame reserves a physical frame to be used together with

View File

@ -3,7 +3,7 @@ package vmm
import ( import (
"gopheros/kernel" "gopheros/kernel"
"gopheros/kernel/cpu" "gopheros/kernel/cpu"
"gopheros/kernel/irq" "gopheros/kernel/gate"
"gopheros/kernel/mm" "gopheros/kernel/mm"
"gopheros/multiboot" "gopheros/multiboot"
"testing" "testing"
@ -18,7 +18,7 @@ func TestInit(t *testing.T) {
translateFn = Translate translateFn = Translate
mapTemporaryFn = MapTemporary mapTemporaryFn = MapTemporary
unmapFn = Unmap unmapFn = Unmap
handleExceptionWithCodeFn = irq.HandleExceptionWithCode handleInterruptFn = gate.HandleInterrupt
}() }()
// reserve space for an allocated page // reserve space for an allocated page
@ -42,7 +42,7 @@ func TestInit(t *testing.T) {
switchPDTFn = func(_ uintptr) {} switchPDTFn = func(_ uintptr) {}
unmapFn = func(p mm.Page) *kernel.Error { return nil } unmapFn = func(p mm.Page) *kernel.Error { return nil }
mapTemporaryFn = func(f mm.Frame) (mm.Page, *kernel.Error) { return mm.Page(f), nil } mapTemporaryFn = func(f mm.Frame) (mm.Page, *kernel.Error) { return mm.Page(f), nil }
handleExceptionWithCodeFn = func(_ irq.ExceptionNum, _ irq.ExceptionHandlerWithCode) {} handleInterruptFn = func(_ gate.InterruptNumber, _ uint8, _ func(*gate.Registers)) {}
if err := Init(0); err != nil { if err := Init(0); err != nil {
t.Fatal(err) t.Fatal(err)
@ -92,7 +92,7 @@ func TestInit(t *testing.T) {
switchPDTFn = func(_ uintptr) {} switchPDTFn = func(_ uintptr) {}
unmapFn = func(p mm.Page) *kernel.Error { return nil } unmapFn = func(p mm.Page) *kernel.Error { return nil }
mapTemporaryFn = func(f mm.Frame) (mm.Page, *kernel.Error) { return mm.Page(f), nil } mapTemporaryFn = func(f mm.Frame) (mm.Page, *kernel.Error) { return mm.Page(f), nil }
handleExceptionWithCodeFn = func(_ irq.ExceptionNum, _ irq.ExceptionHandlerWithCode) {} handleInterruptFn = func(_ gate.InterruptNumber, _ uint8, _ func(*gate.Registers)) {}
if err := Init(0); err != expErr { if err := Init(0); err != expErr {
t.Fatalf("expected error: %v; got %v", expErr, err) t.Fatalf("expected error: %v; got %v", expErr, err)
@ -112,7 +112,7 @@ func TestInit(t *testing.T) {
switchPDTFn = func(_ uintptr) {} switchPDTFn = func(_ uintptr) {}
unmapFn = func(p mm.Page) *kernel.Error { return nil } unmapFn = func(p mm.Page) *kernel.Error { return nil }
mapTemporaryFn = func(f mm.Frame) (mm.Page, *kernel.Error) { return mm.Page(f), expErr } mapTemporaryFn = func(f mm.Frame) (mm.Page, *kernel.Error) { return mm.Page(f), expErr }
handleExceptionWithCodeFn = func(_ irq.ExceptionNum, _ irq.ExceptionHandlerWithCode) {} handleInterruptFn = func(_ gate.InterruptNumber, _ uint8, _ func(*gate.Registers)) {}
if err := Init(0); err != expErr { if err := Init(0); err != expErr {
t.Fatalf("expected error: %v; got %v", expErr, err) t.Fatalf("expected error: %v; got %v", expErr, err)