Handle all exception vectors.

PiperOrigin-RevId: 200144655
Change-Id: I5a753c74b75007b7714d6fe34aa0d2e845dc5c41
This commit is contained in:
Adin Scannell
2018-06-11 17:57:19 -07:00
committed by Shentubot
parent ea4a468fba
commit 09b0a9c320
2 changed files with 49 additions and 8 deletions
+45 -3
View File
@@ -137,6 +137,18 @@ func (c *vCPU) initArchState() error {
return c.setSystemTime()
}
// nonCanonical generates a canonical address return.
//
//go:nosplit
func nonCanonical(addr uint64, signal int32) (*arch.SignalInfo, usermem.AccessType, error) {
info := &arch.SignalInfo{
Signo: signal,
Code: arch.SignalInfoKernel,
}
info.SetAddr(addr) // Include address.
return info, usermem.NoAccess, platform.ErrContextSignal
}
// fault generates an appropriate fault return.
//
//go:nosplit
@@ -169,6 +181,17 @@ func (c *vCPU) fault(signal int32) (*arch.SignalInfo, usermem.AccessType, error)
// SwitchToUser unpacks architectural-details.
func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, usermem.AccessType, error) {
// Check for canonical addresses.
if regs := switchOpts.Registers; !ring0.IsCanonical(regs.Rip) {
return nonCanonical(regs.Rip, int32(syscall.SIGSEGV))
} else if !ring0.IsCanonical(regs.Rsp) {
return nonCanonical(regs.Rsp, int32(syscall.SIGBUS))
} else if !ring0.IsCanonical(regs.Fs_base) {
return nonCanonical(regs.Fs_base, int32(syscall.SIGBUS))
} else if !ring0.IsCanonical(regs.Gs_base) {
return nonCanonical(regs.Gs_base, int32(syscall.SIGBUS))
}
// Assign PCIDs.
if c.PCIDs != nil {
var requireFlushPCID bool // Force a flush?
@@ -205,7 +228,11 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.GeneralProtectionFault:
case ring0.GeneralProtectionFault,
ring0.SegmentNotPresent,
ring0.BoundRangeExceeded,
ring0.InvalidTSS,
ring0.StackSegmentFault:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGSEGV),
Code: arch.SignalInfoKernel,
@@ -229,7 +256,16 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.X87FloatingPointException:
case ring0.Overflow:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGFPE),
Code: 1, // FPE_INTOVF (integer overflow).
}
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.X87FloatingPointException,
ring0.SIMDFloatingPointException:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGFPE),
Code: 7, // FPE_FLTINV (invalid operation).
@@ -237,7 +273,7 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.Vector(bounce):
case ring0.Vector(bounce): // ring0.VirtualizationException
return nil, usermem.NoAccess, platform.ErrContextInterrupt
case ring0.AlignmentCheck:
@@ -255,6 +291,12 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
// directly into the instance.
return c.fault(int32(syscall.SIGBUS))
case ring0.DeviceNotAvailable,
ring0.DoubleFault,
ring0.CoprocessorSegmentOverrun,
ring0.MachineCheck,
ring0.SecurityException:
fallthrough
default:
panic(fmt.Sprintf("unexpected vector: 0x%x", vector))
}
+4 -5
View File
@@ -161,18 +161,17 @@ func IsCanonical(addr uint64) bool {
// Also note that this function transitively depends on the compiler generating
// code that uses IP-relative addressing inside of absolute addresses. That's
// the case for amd64, but may not be the case for other architectures.
//
// Precondition: the Rip, Rsp, Fs and Gs registers must be canonical.
//
//go:nosplit
func (c *CPU) SwitchToUser(switchOpts SwitchOpts) (vector Vector) {
// Check for canonical addresses.
regs := switchOpts.Registers
if !IsCanonical(regs.Rip) || !IsCanonical(regs.Rsp) || !IsCanonical(regs.Fs_base) || !IsCanonical(regs.Gs_base) {
return GeneralProtectionFault
}
userCR3 := switchOpts.PageTables.CR3(!switchOpts.Flush, switchOpts.UserPCID)
kernelCR3 := c.kernel.PageTables.CR3(true, switchOpts.KernelPCID)
// Sanitize registers.
regs := switchOpts.Registers
regs.Eflags &= ^uint64(UserFlagsClear)
regs.Eflags |= UserFlagsSet
regs.Cs = uint64(Ucode64) // Required for iret.