/* * Return a pointer to the register number valid in the current mode of * the virtual CPU. */ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num) { unsigned long *reg_array = (unsigned long *)&vcpu->arch.ctxt.gp_regs.regs; unsigned long mode = *vcpu_cpsr(vcpu) & PSR_AA32_MODE_MASK; switch (mode) { case PSR_AA32_MODE_USR ... PSR_AA32_MODE_SVC: mode &= ~PSR_MODE32_BIT; /* 0 ... 3 */ break; case PSR_AA32_MODE_ABT: mode = 4; break; case PSR_AA32_MODE_UND: mode = 5; break; case PSR_AA32_MODE_SYS: mode = 0; /* SYS maps to USR */ break; default: BUG(); } return reg_array + vcpu_reg_offsets[mode][reg_num]; }
/* * Return the SPSR for the current mode of the virtual CPU. */ unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu) { unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK; switch (mode) { case COMPAT_PSR_MODE_SVC: mode = KVM_SPSR_SVC; break; case COMPAT_PSR_MODE_ABT: mode = KVM_SPSR_ABT; break; case COMPAT_PSR_MODE_UND: mode = KVM_SPSR_UND; break; case COMPAT_PSR_MODE_IRQ: mode = KVM_SPSR_IRQ; break; case COMPAT_PSR_MODE_FIQ: mode = KVM_SPSR_FIQ; break; default: BUG(); } return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode]; }
/* * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on * proper exit to userspace. */ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index) { if (ARM_SERROR_PENDING(exception_index)) { u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu)); /* * HVC/SMC already have an adjusted PC, which we need * to correct in order to return to after having * injected the SError. */ if (hsr_ec == ESR_ELx_EC_HVC32 || hsr_ec == ESR_ELx_EC_HVC64 || hsr_ec == ESR_ELx_EC_SMC32 || hsr_ec == ESR_ELx_EC_SMC64) { u32 adj = kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2; *vcpu_pc(vcpu) -= adj; } return 1; } exception_index = ARM_EXCEPTION_CODE(exception_index); switch (exception_index) { case ARM_EXCEPTION_IRQ: return 1; case ARM_EXCEPTION_EL1_SERROR: /* We may still need to return for single-step */ if (!(*vcpu_cpsr(vcpu) & DBG_SPSR_SS) && kvm_arm_handle_step_debug(vcpu, run)) return 0; else return 1; case ARM_EXCEPTION_TRAP: return handle_trap_exceptions(vcpu, run); case ARM_EXCEPTION_HYP_GONE: /* * EL2 has been reset to the hyp-stub. This happens when a guest * is pre-empted by kvm_reboot()'s shutdown call. */ run->exit_reason = KVM_EXIT_FAIL_ENTRY; return 0; case ARM_EXCEPTION_IL: /* * We attempted an illegal exception return. Guest state must * have been corrupted somehow. Give up. */ run->exit_reason = KVM_EXIT_FAIL_ENTRY; return -EINVAL; default: kvm_pr_unimpl("Unsupported exception type: %d", exception_index); run->exit_reason = KVM_EXIT_INTERNAL_ERROR; return 0; } }
/* * Return the SPSR for the current mode of the virtual CPU. */ static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu) { unsigned long mode = *vcpu_cpsr(vcpu) & PSR_AA32_MODE_MASK; switch (mode) { case PSR_AA32_MODE_SVC: return KVM_SPSR_SVC; case PSR_AA32_MODE_ABT: return KVM_SPSR_ABT; case PSR_AA32_MODE_UND: return KVM_SPSR_UND; case PSR_AA32_MODE_IRQ: return KVM_SPSR_IRQ; case PSR_AA32_MODE_FIQ: return KVM_SPSR_FIQ; default: BUG(); } }
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) { bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY); trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug); /* * This also clears MDCR_EL2_E2PB_MASK to disable guest access * to the profiling buffer. */ vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | MDCR_EL2_TPMS | MDCR_EL2_TPMCR | MDCR_EL2_TDRA | MDCR_EL2_TDOSA); /* Is Guest debugging in effect? */ if (vcpu->guest_debug) { /* Route all software debug exceptions to EL2 */ vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; /* Save guest debug state */ save_guest_debug_regs(vcpu); /* * Single Step (ARM ARM D2.12.3 The software step state * machine) * * If we are doing Single Step we need to manipulate * the guest's MDSCR_EL1.SS and PSTATE.SS. Once the * step has occurred the hypervisor will trap the * debug exception and we return to userspace. * * If the guest attempts to single step its userspace * we would have to deal with a trapped exception * while in the guest kernel. Because this would be * hard to unwind we suppress the guest's ability to * do so by masking MDSCR_EL.SS. * * This confuses guest debuggers which use * single-step behind the scenes but everything * returns to normal once the host is no longer * debugging the system. */ if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { *vcpu_cpsr(vcpu) |= DBG_SPSR_SS; vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS; } else { vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; } trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu)); /* * HW Breakpoints and watchpoints * * We simply switch the debug_ptr to point to our new * external_debug_state which has been populated by the * debug ioctl. The existing KVM_ARM64_DEBUG_DIRTY * mechanism ensures the registers are updated on the * world switch. */ if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { /* Enable breakpoints/watchpoints */ vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE; vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; trap_debug = true; trace_kvm_arm_set_regset("BKPTS", get_num_brps(), &vcpu->arch.debug_ptr->dbg_bcr[0], &vcpu->arch.debug_ptr->dbg_bvr[0]); trace_kvm_arm_set_regset("WAPTS", get_num_wrps(), &vcpu->arch.debug_ptr->dbg_wcr[0], &vcpu->arch.debug_ptr->dbg_wvr[0]); } } BUG_ON(!vcpu->guest_debug && vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state); /* Trap debug register access */ if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2); trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1)); }