Fix kernel flags handling and add missing vectors.

PiperOrigin-RevId: 199877174
Change-Id: I9d19ea301608c2b989df0a6123abb1e779427853
This commit is contained in:
Adin Scannell 2018-06-08 17:50:55 -07:00 committed by Shentubot
parent 2fbd1cf57c
commit c0ab059e7b
5 changed files with 70 additions and 31 deletions

View File

@ -150,13 +150,20 @@ func (c *vCPU) fault(signal int32) (*arch.SignalInfo, usermem.AccessType, error)
// the code provided here. We need to re-execute.
return nil, usermem.NoAccess, platform.ErrContextInterrupt
}
info := &arch.SignalInfo{Signo: signal}
info := &arch.SignalInfo{
Signo: signal,
}
info.SetAddr(uint64(faultAddr))
accessType := usermem.AccessType{
Read: code&(1<<1) == 0,
Write: code&(1<<1) != 0,
Execute: code&(1<<4) != 0,
}
if !accessType.Write && !accessType.Execute {
info.Code = 1 // SEGV_MAPERR.
} else {
info.Code = 2 // SEGV_ACCERR.
}
return info, accessType, platform.ErrContextSignal
}
@ -191,30 +198,55 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts) (*arch.SignalInfo, user
return c.fault(int32(syscall.SIGSEGV))
case ring0.Debug, ring0.Breakpoint:
info := &arch.SignalInfo{Signo: int32(syscall.SIGTRAP)}
info := &arch.SignalInfo{
Signo: int32(syscall.SIGTRAP),
Code: 1, // TRAP_BRKPT (breakpoint).
}
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.GeneralProtectionFault:
if !ring0.IsCanonical(switchOpts.Registers.Rip) {
// If the RIP is non-canonical, it's a SEGV.
info := &arch.SignalInfo{Signo: int32(syscall.SIGSEGV)}
return info, usermem.AccessType{}, platform.ErrContextSignal
info := &arch.SignalInfo{
Signo: int32(syscall.SIGSEGV),
Code: arch.SignalInfoKernel,
}
// Otherwise, we deliver a SIGBUS.
info := &arch.SignalInfo{Signo: int32(syscall.SIGBUS)}
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.InvalidOpcode:
info := &arch.SignalInfo{Signo: int32(syscall.SIGILL)}
info := &arch.SignalInfo{
Signo: int32(syscall.SIGILL),
Code: 1, // ILL_ILLOPC (illegal opcode).
}
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.DivideByZero:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGFPE),
Code: 1, // FPE_INTDIV (divide by zero).
}
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.X87FloatingPointException:
info := &arch.SignalInfo{Signo: int32(syscall.SIGFPE)}
info := &arch.SignalInfo{
Signo: int32(syscall.SIGFPE),
Code: 7, // FPE_FLTINV (invalid operation).
}
info.SetAddr(switchOpts.Registers.Rip) // Include address.
return info, usermem.AccessType{}, platform.ErrContextSignal
case ring0.Vector(bounce):
return nil, usermem.NoAccess, platform.ErrContextInterrupt
case ring0.AlignmentCheck:
info := &arch.SignalInfo{
Signo: int32(syscall.SIGBUS),
Code: 2, // BUS_ADRERR (physical address does not exist).
}
return info, usermem.NoAccess, platform.ErrContextSignal
case ring0.NMI:
// An NMI is generated only when a fault is not servicable by
// KVM itself, so we think some mapping is writeable but it's

View File

@ -248,10 +248,12 @@ TEXT ·exception(SB),NOSPLIT,$0
user:
SWAP_GS()
XCHGQ CPU_REGISTERS+PTRACE_RAX(GS), AX // Swap for AX (regs).
REGISTERS_SAVE(AX, 0) // Save all except IP, FLAGS, SP, AX.
MOVQ CPU_REGISTERS+PTRACE_RAX(GS), BX // Load saved AX value.
MOVQ BX, PTRACE_RAX(AX) // Save everything else.
ADDQ $-8, SP // Adjust for flags.
MOVQ $_KERNEL_FLAGS, 0(SP); BYTE $0x9d; // Reset flags (POPFQ).
XCHGQ CPU_REGISTERS+PTRACE_RAX(GS), AX // Swap for user regs.
REGISTERS_SAVE(AX, 0) // Save all except IP, FLAGS, SP, AX.
MOVQ CPU_REGISTERS+PTRACE_RAX(GS), BX // Restore original AX.
MOVQ BX, PTRACE_RAX(AX) // Save it.
MOVQ BX, PTRACE_ORIGRAX(AX)
MOVQ 16(SP), BX; MOVQ BX, PTRACE_RIP(AX)
MOVQ 24(SP), CX; MOVQ CX, PTRACE_CS(AX)

View File

@ -20,20 +20,6 @@ import (
"encoding/binary"
)
const (
// KernelFlagsSet should always be set in the kernel.
KernelFlagsSet = _RFLAGS_RESERVED
// UserFlagsSet are always set in userspace.
UserFlagsSet = _RFLAGS_RESERVED | _RFLAGS_IF
// KernelFlagsClear should always be clear in the kernel.
KernelFlagsClear = _RFLAGS_IF | _RFLAGS_NT | _RFLAGS_IOPL
// UserFlagsClear are always cleared in userspace.
UserFlagsClear = _RFLAGS_NT | _RFLAGS_IOPL
)
// init initializes architecture-specific state.
func (k *Kernel) init(opts KernelOpts) {
// Save the root page tables.
@ -85,6 +71,9 @@ func (c *CPU) init() {
c.registers.Ss = uint64(Kdata)
c.registers.Fs = uint64(Kdata)
c.registers.Gs = uint64(Kdata)
// Set mandatory flags.
c.registers.Eflags = KernelFlagsSet
}
// StackTop returns the kernel's stack address.
@ -119,7 +108,7 @@ func (c *CPU) TSS() (uint64, uint16, *SegmentDescriptor) {
//
//go:nosplit
func (c *CPU) CR0() uint64 {
return _CR0_PE | _CR0_PG | _CR0_ET
return _CR0_PE | _CR0_PG | _CR0_AM | _CR0_ET
}
// CR4 returns the CPU's CR4 value.
@ -240,7 +229,7 @@ func start(c *CPU) {
// Set the syscall target.
wrmsr(_MSR_LSTAR, kernelFunc(sysenter))
wrmsr(_MSR_SYSCALL_MASK, _RFLAGS_STEP|_RFLAGS_IF|_RFLAGS_DF|_RFLAGS_IOPL|_RFLAGS_AC|_RFLAGS_NT)
wrmsr(_MSR_SYSCALL_MASK, KernelFlagsClear|_RFLAGS_DF)
// NOTE: This depends on having the 64-bit segments immediately
// following the 32-bit user segments. This is simply the way the

View File

@ -38,7 +38,8 @@ func Emit(w io.Writer) {
fmt.Fprintf(w, "#define CPU_KERNEL_SYSCALL 0x%02x\n", reflect.ValueOf(&c.KernelSyscall).Pointer()-reflect.ValueOf(c).Pointer())
fmt.Fprintf(w, "\n// Bits.\n")
fmt.Fprintf(w, "#define _RFLAGS_IF 0x%02x\n", _RFLAGS_IF)
fmt.Fprintf(w, "#define _RFLAGS_IF 0x%02x\n", _RFLAGS_IF)
fmt.Fprintf(w, "#define _KERNEL_FLAGS 0x%02x\n", KernelFlagsSet)
fmt.Fprintf(w, "\n// Vectors.\n")
fmt.Fprintf(w, "#define DivideByZero 0x%02x\n", DivideByZero)

View File

@ -24,6 +24,7 @@ import (
const (
_CR0_PE = 1 << 0
_CR0_ET = 1 << 4
_CR0_AM = 1 << 18
_CR0_PG = 1 << 31
_CR4_PSE = 1 << 4
@ -55,6 +56,20 @@ const (
_MSR_SYSCALL_MASK = 0xc0000084
)
const (
// KernelFlagsSet should always be set in the kernel.
KernelFlagsSet = _RFLAGS_RESERVED
// UserFlagsSet are always set in userspace.
UserFlagsSet = _RFLAGS_RESERVED | _RFLAGS_IF
// KernelFlagsClear should always be clear in the kernel.
KernelFlagsClear = _RFLAGS_STEP | _RFLAGS_IF | _RFLAGS_IOPL | _RFLAGS_AC | _RFLAGS_NT
// UserFlagsClear are always cleared in userspace.
UserFlagsClear = _RFLAGS_NT | _RFLAGS_IOPL
)
// Vector is an exception vector.
type Vector uintptr