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:
parent
7b12fbd940
commit
7deeab3cbc
@ -2,12 +2,24 @@ package vmm
|
||||
|
||||
import (
|
||||
"gopheros/kernel"
|
||||
"gopheros/kernel/irq"
|
||||
"gopheros/kernel/gate"
|
||||
"gopheros/kernel/kfmt"
|
||||
"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 (
|
||||
faultAddress = uintptr(readCR2Fn())
|
||||
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 {
|
||||
nonRecoverablePageFault(faultAddress, errorCode, frame, regs, err)
|
||||
nonRecoverablePageFault(faultAddress, regs, err)
|
||||
} else if tmpPage, err = mapTemporaryFn(copy); err != nil {
|
||||
nonRecoverablePageFault(faultAddress, errorCode, frame, regs, err)
|
||||
nonRecoverablePageFault(faultAddress, regs, err)
|
||||
} else {
|
||||
// Copy page contents, mark as RW and remove CoW flag
|
||||
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)
|
||||
switch {
|
||||
case errorCode == 0:
|
||||
case regs.Info == 0:
|
||||
kfmt.Printf("read from non-present page")
|
||||
case errorCode == 1:
|
||||
case regs.Info == 1:
|
||||
kfmt.Printf("page protection violation (read)")
|
||||
case errorCode == 2:
|
||||
case regs.Info == 2:
|
||||
kfmt.Printf("write to non-present page")
|
||||
case errorCode == 3:
|
||||
case regs.Info == 3:
|
||||
kfmt.Printf("page protection violation (write)")
|
||||
case errorCode == 4:
|
||||
case regs.Info == 4:
|
||||
kfmt.Printf("page-fault in user-mode")
|
||||
case errorCode == 8:
|
||||
case regs.Info == 8:
|
||||
kfmt.Printf("page table has reserved bit set")
|
||||
case errorCode == 16:
|
||||
case regs.Info == 16:
|
||||
kfmt.Printf("instruction fetch")
|
||||
default:
|
||||
kfmt.Printf("unknown")
|
||||
}
|
||||
|
||||
kfmt.Printf("\n\nRegisters:\n")
|
||||
regs.Print()
|
||||
frame.Print()
|
||||
regs.DumpTo(kfmt.GetOutputSink())
|
||||
|
||||
// TODO: Revisit this when user-mode tasks are implemented
|
||||
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)
|
||||
}
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"gopheros/kernel"
|
||||
"gopheros/kernel/cpu"
|
||||
"gopheros/kernel/irq"
|
||||
"gopheros/kernel/gate"
|
||||
"gopheros/kernel/kfmt"
|
||||
"gopheros/kernel/mm"
|
||||
"strings"
|
||||
@ -15,8 +15,7 @@ import (
|
||||
|
||||
func TestRecoverablePageFault(t *testing.T) {
|
||||
var (
|
||||
frame irq.Frame
|
||||
regs irq.Regs
|
||||
regs gate.Registers
|
||||
pageEntry pageTableEntry
|
||||
origPage = make([]byte, mm.PageSize)
|
||||
clonedPage = make([]byte, mm.PageSize)
|
||||
@ -91,7 +90,8 @@ func TestRecoverablePageFault(t *testing.T) {
|
||||
pageEntry = 0
|
||||
pageEntry.SetFlags(spec.pteFlags)
|
||||
|
||||
pageFaultHandler(2, &frame, ®s)
|
||||
regs.Info = 2
|
||||
pageFaultHandler(®s)
|
||||
})
|
||||
}
|
||||
|
||||
@ -141,8 +141,7 @@ func TestNonRecoverablePageFault(t *testing.T) {
|
||||
}
|
||||
|
||||
var (
|
||||
regs irq.Regs
|
||||
frame irq.Frame
|
||||
regs gate.Registers
|
||||
buf bytes.Buffer
|
||||
)
|
||||
|
||||
@ -156,7 +155,8 @@ func TestNonRecoverablePageFault(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
nonRecoverablePageFault(0xbadf00d000, spec.errCode, &frame, ®s, errUnrecoverableFault)
|
||||
regs.Info = spec.errCode
|
||||
nonRecoverablePageFault(0xbadf00d000, ®s, errUnrecoverableFault)
|
||||
if got := buf.String(); !strings.Contains(got, spec.expReason) {
|
||||
t.Errorf("expected reason %q; got output:\n%q", spec.expReason, got)
|
||||
}
|
||||
@ -169,10 +169,7 @@ func TestGPFHandler(t *testing.T) {
|
||||
readCR2Fn = cpu.ReadCR2
|
||||
}()
|
||||
|
||||
var (
|
||||
regs irq.Regs
|
||||
frame irq.Frame
|
||||
)
|
||||
var regs gate.Registers
|
||||
|
||||
readCR2Fn = func() uint64 {
|
||||
return 0xbadf00d000
|
||||
@ -184,5 +181,5 @@ func TestGPFHandler(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
generalProtectionFaultHandler(0, &frame, ®s)
|
||||
generalProtectionFaultHandler(®s)
|
||||
}
|
@ -3,14 +3,12 @@ package vmm
|
||||
import (
|
||||
"gopheros/kernel"
|
||||
"gopheros/kernel/cpu"
|
||||
"gopheros/kernel/irq"
|
||||
"gopheros/kernel/mm"
|
||||
)
|
||||
|
||||
var (
|
||||
// the following functions are mocked by tests and are automatically
|
||||
// inlined by the compiler.
|
||||
handleExceptionWithCodeFn = irq.HandleExceptionWithCode
|
||||
readCR2Fn = cpu.ReadCR2
|
||||
translateFn = Translate
|
||||
|
||||
@ -24,13 +22,10 @@ func Init(kernelPageOffset uintptr) *kernel.Error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := reserveZeroedFrame(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Install arch-specific handlers for vmm-related faults.
|
||||
installFaultHandlers()
|
||||
|
||||
handleExceptionWithCodeFn(irq.PageFaultException, pageFaultHandler)
|
||||
handleExceptionWithCodeFn(irq.GPFException, generalProtectionFaultHandler)
|
||||
return nil
|
||||
return reserveZeroedFrame()
|
||||
}
|
||||
|
||||
// reserveZeroedFrame reserves a physical frame to be used together with
|
||||
|
@ -3,7 +3,7 @@ package vmm
|
||||
import (
|
||||
"gopheros/kernel"
|
||||
"gopheros/kernel/cpu"
|
||||
"gopheros/kernel/irq"
|
||||
"gopheros/kernel/gate"
|
||||
"gopheros/kernel/mm"
|
||||
"gopheros/multiboot"
|
||||
"testing"
|
||||
@ -18,7 +18,7 @@ func TestInit(t *testing.T) {
|
||||
translateFn = Translate
|
||||
mapTemporaryFn = MapTemporary
|
||||
unmapFn = Unmap
|
||||
handleExceptionWithCodeFn = irq.HandleExceptionWithCode
|
||||
handleInterruptFn = gate.HandleInterrupt
|
||||
}()
|
||||
|
||||
// reserve space for an allocated page
|
||||
@ -42,7 +42,7 @@ func TestInit(t *testing.T) {
|
||||
switchPDTFn = func(_ uintptr) {}
|
||||
unmapFn = func(p mm.Page) *kernel.Error { return 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 {
|
||||
t.Fatal(err)
|
||||
@ -92,7 +92,7 @@ func TestInit(t *testing.T) {
|
||||
switchPDTFn = func(_ uintptr) {}
|
||||
unmapFn = func(p mm.Page) *kernel.Error { return 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 {
|
||||
t.Fatalf("expected error: %v; got %v", expErr, err)
|
||||
@ -112,7 +112,7 @@ func TestInit(t *testing.T) {
|
||||
switchPDTFn = func(_ uintptr) {}
|
||||
unmapFn = func(p mm.Page) *kernel.Error { return nil }
|
||||
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 {
|
||||
t.Fatalf("expected error: %v; got %v", expErr, err)
|
||||
|
Loading…
x
Reference in New Issue
Block a user