arm64 kvm: inject sError to trigger sigbus
Use an sErr injection to trigger sigbus when we receive EFAULT from the run ioctl. After applying this patch, mmap_test_runsc_kvm will be passed on Arm64. Signed-off-by: Bin Lu <bin.lu@arm.com> COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/4542 from lubinszARM:pr_kvm_mmap_1 f81bd42466d1d60a581e5fb34de18b78878c68c1 PiperOrigin-RevId: 340461239
This commit is contained in:
parent
1a3f417f4a
commit
0e96f8065e
|
@ -79,6 +79,18 @@ func bluepillStopGuest(c *vCPU) {
|
|||
c.runData.requestInterruptWindow = 0
|
||||
}
|
||||
|
||||
// bluepillSigBus is reponsible for injecting NMI to trigger sigbus.
|
||||
//
|
||||
//go:nosplit
|
||||
func bluepillSigBus(c *vCPU) {
|
||||
if _, _, errno := syscall.RawSyscall( // escapes: no.
|
||||
syscall.SYS_IOCTL,
|
||||
uintptr(c.fd),
|
||||
_KVM_NMI, 0); errno != 0 {
|
||||
throw("NMI injection failed")
|
||||
}
|
||||
}
|
||||
|
||||
// bluepillReadyStopGuest checks whether the current vCPU is ready for interrupt injection.
|
||||
//
|
||||
//go:nosplit
|
||||
|
|
|
@ -27,15 +27,20 @@ var (
|
|||
// The action for bluepillSignal is changed by sigaction().
|
||||
bluepillSignal = syscall.SIGILL
|
||||
|
||||
// vcpuSErr is the event of system error.
|
||||
vcpuSErr = kvmVcpuEvents{
|
||||
// vcpuSErrBounce is the event of system error for bouncing KVM.
|
||||
vcpuSErrBounce = kvmVcpuEvents{
|
||||
exception: exception{
|
||||
sErrPending: 1,
|
||||
sErrHasEsr: 0,
|
||||
pad: [6]uint8{0, 0, 0, 0, 0, 0},
|
||||
sErrEsr: 1,
|
||||
},
|
||||
rsvd: [12]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
|
||||
// vcpuSErrNMI is the event of system error to trigger sigbus.
|
||||
vcpuSErrNMI = kvmVcpuEvents{
|
||||
exception: exception{
|
||||
sErrPending: 1,
|
||||
sErrHasEsr: 1,
|
||||
sErrEsr: _ESR_ELx_SERR_NMI,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -80,11 +80,24 @@ func getHypercallID(addr uintptr) int {
|
|||
//
|
||||
//go:nosplit
|
||||
func bluepillStopGuest(c *vCPU) {
|
||||
if _, _, errno := syscall.RawSyscall(
|
||||
if _, _, errno := syscall.RawSyscall( // escapes: no.
|
||||
syscall.SYS_IOCTL,
|
||||
uintptr(c.fd),
|
||||
_KVM_SET_VCPU_EVENTS,
|
||||
uintptr(unsafe.Pointer(&vcpuSErr))); errno != 0 {
|
||||
uintptr(unsafe.Pointer(&vcpuSErrBounce))); errno != 0 {
|
||||
throw("sErr injection failed")
|
||||
}
|
||||
}
|
||||
|
||||
// bluepillSigBus is reponsible for injecting sError to trigger sigbus.
|
||||
//
|
||||
//go:nosplit
|
||||
func bluepillSigBus(c *vCPU) {
|
||||
if _, _, errno := syscall.RawSyscall( // escapes: no.
|
||||
syscall.SYS_IOCTL,
|
||||
uintptr(c.fd),
|
||||
_KVM_SET_VCPU_EVENTS,
|
||||
uintptr(unsafe.Pointer(&vcpuSErrNMI))); errno != 0 {
|
||||
throw("sErr injection failed")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,12 +146,7 @@ func bluepillHandler(context unsafe.Pointer) {
|
|||
// MMIO exit we receive EFAULT from the run ioctl. We
|
||||
// always inject an NMI here since we may be in kernel
|
||||
// mode and have interrupts disabled.
|
||||
if _, _, errno := syscall.RawSyscall( // escapes: no.
|
||||
syscall.SYS_IOCTL,
|
||||
uintptr(c.fd),
|
||||
_KVM_NMI, 0); errno != 0 {
|
||||
throw("NMI injection failed")
|
||||
}
|
||||
bluepillSigBus(c)
|
||||
continue // Rerun vCPU.
|
||||
default:
|
||||
throw("run failed")
|
||||
|
|
|
@ -151,6 +151,9 @@ const (
|
|||
_ESR_SEGV_PEMERR_L1 = 0xd
|
||||
_ESR_SEGV_PEMERR_L2 = 0xe
|
||||
_ESR_SEGV_PEMERR_L3 = 0xf
|
||||
|
||||
// Custom ISS field definitions for system error.
|
||||
_ESR_ELx_SERR_NMI = 0x1
|
||||
)
|
||||
|
||||
// Arm64: MMIO base address used to dispatch hypercalls.
|
||||
|
|
|
@ -257,11 +257,13 @@ func (c *vCPU) SwitchToUser(switchOpts ring0.SwitchOpts, info *arch.SignalInfo)
|
|||
|
||||
case ring0.PageFault:
|
||||
return c.fault(int32(syscall.SIGSEGV), info)
|
||||
case ring0.El0ErrNMI:
|
||||
return c.fault(int32(syscall.SIGBUS), info)
|
||||
case ring0.Vector(bounce): // ring0.VirtualizationException
|
||||
return usermem.NoAccess, platform.ErrContextInterrupt
|
||||
case ring0.El0Sync_undef:
|
||||
case ring0.El0SyncUndef:
|
||||
return c.fault(int32(syscall.SIGILL), info)
|
||||
case ring0.El1Sync_undef:
|
||||
case ring0.El1SyncUndef:
|
||||
*info = arch.SignalInfo{
|
||||
Signo: int32(syscall.SIGILL),
|
||||
Code: 1, // ILL_ILLOPC (illegal opcode).
|
||||
|
|
|
@ -58,46 +58,55 @@ type Vector uintptr
|
|||
|
||||
// Exception vectors.
|
||||
const (
|
||||
El1SyncInvalid = iota
|
||||
El1IrqInvalid
|
||||
El1FiqInvalid
|
||||
El1ErrorInvalid
|
||||
El1InvSync = iota
|
||||
El1InvIrq
|
||||
El1InvFiq
|
||||
El1InvError
|
||||
|
||||
El1Sync
|
||||
El1Irq
|
||||
El1Fiq
|
||||
El1Error
|
||||
El1Err
|
||||
|
||||
El0Sync
|
||||
El0Irq
|
||||
El0Fiq
|
||||
El0Error
|
||||
El0Sync_invalid
|
||||
El0Irq_invalid
|
||||
El0Fiq_invalid
|
||||
El0Error_invalid
|
||||
El1Sync_da
|
||||
El1Sync_ia
|
||||
El1Sync_sp_pc
|
||||
El1Sync_undef
|
||||
El1Sync_dbg
|
||||
El1Sync_inv
|
||||
El0Sync_svc
|
||||
El0Sync_da
|
||||
El0Sync_ia
|
||||
El0Sync_fpsimd_acc
|
||||
El0Sync_sve_acc
|
||||
El0Sync_sys
|
||||
El0Sync_sp_pc
|
||||
El0Sync_undef
|
||||
El0Sync_dbg
|
||||
El0Sync_inv
|
||||
El0Err
|
||||
|
||||
El0InvSync
|
||||
El0InvIrq
|
||||
El0InvFiq
|
||||
El0InvErr
|
||||
|
||||
El1SyncDa
|
||||
El1SyncIa
|
||||
El1SyncSpPc
|
||||
El1SyncUndef
|
||||
El1SyncDbg
|
||||
El1SyncInv
|
||||
|
||||
El0SyncSVC
|
||||
El0SyncDa
|
||||
El0SyncIa
|
||||
El0SyncFpsimdAcc
|
||||
El0SyncSveAcc
|
||||
El0SyncSys
|
||||
El0SyncSpPc
|
||||
El0SyncUndef
|
||||
El0SyncDbg
|
||||
El0SyncInv
|
||||
|
||||
El0ErrNMI
|
||||
El0ErrBounce
|
||||
|
||||
_NR_INTERRUPTS
|
||||
)
|
||||
|
||||
// System call vectors.
|
||||
const (
|
||||
Syscall Vector = El0Sync_svc
|
||||
PageFault Vector = El0Sync_da
|
||||
VirtualizationException Vector = El0Error
|
||||
Syscall Vector = El0SyncSVC
|
||||
PageFault Vector = El0SyncDa
|
||||
VirtualizationException Vector = El0ErrBounce
|
||||
)
|
||||
|
||||
// VirtualAddressBits returns the number bits available for virtual addresses.
|
||||
|
|
|
@ -288,6 +288,10 @@
|
|||
#define ESR_ELx_WFx_ISS_WFE (UL(1) << 0)
|
||||
#define ESR_ELx_xVC_IMM_MASK ((1UL << 16) - 1)
|
||||
|
||||
/* ISS field definitions for system error */
|
||||
#define ESR_ELx_SERR_MASK (0x1)
|
||||
#define ESR_ELx_SERR_NMI (0x1)
|
||||
|
||||
// LOAD_KERNEL_ADDRESS loads a kernel address.
|
||||
#define LOAD_KERNEL_ADDRESS(from, to) \
|
||||
MOVD from, to; \
|
||||
|
@ -691,7 +695,7 @@ el0_sp_pc:
|
|||
B ·Shutdown(SB)
|
||||
|
||||
el0_undef:
|
||||
EXCEPTION_WITH_ERROR(1, El0Sync_undef)
|
||||
EXCEPTION_WITH_ERROR(1, El0SyncUndef)
|
||||
|
||||
el0_dbg:
|
||||
B ·Shutdown(SB)
|
||||
|
@ -707,6 +711,29 @@ TEXT ·El0_fiq(SB),NOSPLIT,$0
|
|||
|
||||
TEXT ·El0_error(SB),NOSPLIT,$0
|
||||
KERNEL_ENTRY_FROM_EL0
|
||||
WORD $0xd5385219 // MRS ESR_EL1, R25
|
||||
AND $ESR_ELx_SERR_MASK, R25, R24
|
||||
CMP $ESR_ELx_SERR_NMI, R24
|
||||
BEQ el0_nmi
|
||||
B el0_bounce
|
||||
el0_nmi:
|
||||
WORD $0xd538d092 //MRS TPIDR_EL1, R18
|
||||
WORD $0xd538601a //MRS FAR_EL1, R26
|
||||
|
||||
MOVD R26, CPU_FAULT_ADDR(RSV_REG)
|
||||
|
||||
MOVD $1, R3
|
||||
MOVD R3, CPU_ERROR_TYPE(RSV_REG) // Set error type to user.
|
||||
|
||||
MOVD $El0ErrNMI, R3
|
||||
MOVD R3, CPU_VECTOR_CODE(RSV_REG)
|
||||
|
||||
MRS ESR_EL1, R3
|
||||
MOVD R3, CPU_ERROR_CODE(RSV_REG)
|
||||
|
||||
B ·kernelExitToEl1(SB)
|
||||
|
||||
el0_bounce:
|
||||
WORD $0xd538d092 //MRS TPIDR_EL1, R18
|
||||
WORD $0xd538601a //MRS FAR_EL1, R26
|
||||
|
||||
|
@ -718,7 +745,7 @@ TEXT ·El0_error(SB),NOSPLIT,$0
|
|||
MOVD $VirtualizationException, R3
|
||||
MOVD R3, CPU_VECTOR_CODE(RSV_REG)
|
||||
|
||||
B ·HaltAndResume(SB)
|
||||
B ·kernelExitToEl1(SB)
|
||||
|
||||
TEXT ·El0_sync_invalid(SB),NOSPLIT,$0
|
||||
B ·Shutdown(SB)
|
||||
|
|
|
@ -47,43 +47,36 @@ func Emit(w io.Writer) {
|
|||
fmt.Fprintf(w, "#define _KERNEL_FLAGS 0x%02x\n", KernelFlagsSet)
|
||||
|
||||
fmt.Fprintf(w, "\n// Vectors.\n")
|
||||
fmt.Fprintf(w, "#define El1SyncInvalid 0x%02x\n", El1SyncInvalid)
|
||||
fmt.Fprintf(w, "#define El1IrqInvalid 0x%02x\n", El1IrqInvalid)
|
||||
fmt.Fprintf(w, "#define El1FiqInvalid 0x%02x\n", El1FiqInvalid)
|
||||
fmt.Fprintf(w, "#define El1ErrorInvalid 0x%02x\n", El1ErrorInvalid)
|
||||
|
||||
fmt.Fprintf(w, "#define El1Sync 0x%02x\n", El1Sync)
|
||||
fmt.Fprintf(w, "#define El1Irq 0x%02x\n", El1Irq)
|
||||
fmt.Fprintf(w, "#define El1Fiq 0x%02x\n", El1Fiq)
|
||||
fmt.Fprintf(w, "#define El1Error 0x%02x\n", El1Error)
|
||||
fmt.Fprintf(w, "#define El1Err 0x%02x\n", El1Err)
|
||||
|
||||
fmt.Fprintf(w, "#define El0Sync 0x%02x\n", El0Sync)
|
||||
fmt.Fprintf(w, "#define El0Irq 0x%02x\n", El0Irq)
|
||||
fmt.Fprintf(w, "#define El0Fiq 0x%02x\n", El0Fiq)
|
||||
fmt.Fprintf(w, "#define El0Error 0x%02x\n", El0Error)
|
||||
fmt.Fprintf(w, "#define El0Err 0x%02x\n", El0Err)
|
||||
|
||||
fmt.Fprintf(w, "#define El0Sync_invalid 0x%02x\n", El0Sync_invalid)
|
||||
fmt.Fprintf(w, "#define El0Irq_invalid 0x%02x\n", El0Irq_invalid)
|
||||
fmt.Fprintf(w, "#define El0Fiq_invalid 0x%02x\n", El0Fiq_invalid)
|
||||
fmt.Fprintf(w, "#define El0Error_invalid 0x%02x\n", El0Error_invalid)
|
||||
fmt.Fprintf(w, "#define El1SyncDa 0x%02x\n", El1SyncDa)
|
||||
fmt.Fprintf(w, "#define El1SyncIa 0x%02x\n", El1SyncIa)
|
||||
fmt.Fprintf(w, "#define El1SyncSpPc 0x%02x\n", El1SyncSpPc)
|
||||
fmt.Fprintf(w, "#define El1SyncUndef 0x%02x\n", El1SyncUndef)
|
||||
fmt.Fprintf(w, "#define El1SyncDbg 0x%02x\n", El1SyncDbg)
|
||||
fmt.Fprintf(w, "#define El1SyncInv 0x%02x\n", El1SyncInv)
|
||||
|
||||
fmt.Fprintf(w, "#define El1Sync_da 0x%02x\n", El1Sync_da)
|
||||
fmt.Fprintf(w, "#define El1Sync_ia 0x%02x\n", El1Sync_ia)
|
||||
fmt.Fprintf(w, "#define El1Sync_sp_pc 0x%02x\n", El1Sync_sp_pc)
|
||||
fmt.Fprintf(w, "#define El1Sync_undef 0x%02x\n", El1Sync_undef)
|
||||
fmt.Fprintf(w, "#define El1Sync_dbg 0x%02x\n", El1Sync_dbg)
|
||||
fmt.Fprintf(w, "#define El1Sync_inv 0x%02x\n", El1Sync_inv)
|
||||
fmt.Fprintf(w, "#define El0SyncSVC 0x%02x\n", El0SyncSVC)
|
||||
fmt.Fprintf(w, "#define El0SyncDa 0x%02x\n", El0SyncDa)
|
||||
fmt.Fprintf(w, "#define El0SyncIa 0x%02x\n", El0SyncIa)
|
||||
fmt.Fprintf(w, "#define El0SyncFpsimdAcc 0x%02x\n", El0SyncFpsimdAcc)
|
||||
fmt.Fprintf(w, "#define El0SyncSveAcc 0x%02x\n", El0SyncSveAcc)
|
||||
fmt.Fprintf(w, "#define El0SyncSys 0x%02x\n", El0SyncSys)
|
||||
fmt.Fprintf(w, "#define El0SyncSpPc 0x%02x\n", El0SyncSpPc)
|
||||
fmt.Fprintf(w, "#define El0SyncUndef 0x%02x\n", El0SyncUndef)
|
||||
fmt.Fprintf(w, "#define El0SyncDbg 0x%02x\n", El0SyncDbg)
|
||||
fmt.Fprintf(w, "#define El0SyncInv 0x%02x\n", El0SyncInv)
|
||||
|
||||
fmt.Fprintf(w, "#define El0Sync_svc 0x%02x\n", El0Sync_svc)
|
||||
fmt.Fprintf(w, "#define El0Sync_da 0x%02x\n", El0Sync_da)
|
||||
fmt.Fprintf(w, "#define El0Sync_ia 0x%02x\n", El0Sync_ia)
|
||||
fmt.Fprintf(w, "#define El0Sync_fpsimd_acc 0x%02x\n", El0Sync_fpsimd_acc)
|
||||
fmt.Fprintf(w, "#define El0Sync_sve_acc 0x%02x\n", El0Sync_sve_acc)
|
||||
fmt.Fprintf(w, "#define El0Sync_sys 0x%02x\n", El0Sync_sys)
|
||||
fmt.Fprintf(w, "#define El0Sync_sp_pc 0x%02x\n", El0Sync_sp_pc)
|
||||
fmt.Fprintf(w, "#define El0Sync_undef 0x%02x\n", El0Sync_undef)
|
||||
fmt.Fprintf(w, "#define El0Sync_dbg 0x%02x\n", El0Sync_dbg)
|
||||
fmt.Fprintf(w, "#define El0Sync_inv 0x%02x\n", El0Sync_inv)
|
||||
fmt.Fprintf(w, "#define El0ErrNMI 0x%02x\n", El0ErrNMI)
|
||||
|
||||
fmt.Fprintf(w, "#define PageFault 0x%02x\n", PageFault)
|
||||
fmt.Fprintf(w, "#define Syscall 0x%02x\n", Syscall)
|
||||
|
|
Loading…
Reference in New Issue