int __vgic_v3_perform_cpuif_access()

in kvm/hyp/vgic-v3-sr.c [1013:1140]


int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
{
	int rt;
	u32 esr;
	u32 vmcr;
	void (*fn)(struct kvm_vcpu *, u32, int);
	bool is_read;
	u32 sysreg;

	esr = kvm_vcpu_get_esr(vcpu);
	if (vcpu_mode_is_32bit(vcpu)) {
		if (!kvm_condition_valid(vcpu)) {
			__kvm_skip_instr(vcpu);
			return 1;
		}

		sysreg = esr_cp15_to_sysreg(esr);
	} else {
		sysreg = esr_sys64_to_sysreg(esr);
	}

	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;

	switch (sysreg) {
	case SYS_ICC_IAR0_EL1:
	case SYS_ICC_IAR1_EL1:
		if (unlikely(!is_read))
			return 0;
		fn = __vgic_v3_read_iar;
		break;
	case SYS_ICC_EOIR0_EL1:
	case SYS_ICC_EOIR1_EL1:
		if (unlikely(is_read))
			return 0;
		fn = __vgic_v3_write_eoir;
		break;
	case SYS_ICC_IGRPEN1_EL1:
		if (is_read)
			fn = __vgic_v3_read_igrpen1;
		else
			fn = __vgic_v3_write_igrpen1;
		break;
	case SYS_ICC_BPR1_EL1:
		if (is_read)
			fn = __vgic_v3_read_bpr1;
		else
			fn = __vgic_v3_write_bpr1;
		break;
	case SYS_ICC_AP0Rn_EL1(0):
	case SYS_ICC_AP1Rn_EL1(0):
		if (is_read)
			fn = __vgic_v3_read_apxr0;
		else
			fn = __vgic_v3_write_apxr0;
		break;
	case SYS_ICC_AP0Rn_EL1(1):
	case SYS_ICC_AP1Rn_EL1(1):
		if (is_read)
			fn = __vgic_v3_read_apxr1;
		else
			fn = __vgic_v3_write_apxr1;
		break;
	case SYS_ICC_AP0Rn_EL1(2):
	case SYS_ICC_AP1Rn_EL1(2):
		if (is_read)
			fn = __vgic_v3_read_apxr2;
		else
			fn = __vgic_v3_write_apxr2;
		break;
	case SYS_ICC_AP0Rn_EL1(3):
	case SYS_ICC_AP1Rn_EL1(3):
		if (is_read)
			fn = __vgic_v3_read_apxr3;
		else
			fn = __vgic_v3_write_apxr3;
		break;
	case SYS_ICC_HPPIR0_EL1:
	case SYS_ICC_HPPIR1_EL1:
		if (unlikely(!is_read))
			return 0;
		fn = __vgic_v3_read_hppir;
		break;
	case SYS_ICC_IGRPEN0_EL1:
		if (is_read)
			fn = __vgic_v3_read_igrpen0;
		else
			fn = __vgic_v3_write_igrpen0;
		break;
	case SYS_ICC_BPR0_EL1:
		if (is_read)
			fn = __vgic_v3_read_bpr0;
		else
			fn = __vgic_v3_write_bpr0;
		break;
	case SYS_ICC_DIR_EL1:
		if (unlikely(is_read))
			return 0;
		fn = __vgic_v3_write_dir;
		break;
	case SYS_ICC_RPR_EL1:
		if (unlikely(!is_read))
			return 0;
		fn = __vgic_v3_read_rpr;
		break;
	case SYS_ICC_CTLR_EL1:
		if (is_read)
			fn = __vgic_v3_read_ctlr;
		else
			fn = __vgic_v3_write_ctlr;
		break;
	case SYS_ICC_PMR_EL1:
		if (is_read)
			fn = __vgic_v3_read_pmr;
		else
			fn = __vgic_v3_write_pmr;
		break;
	default:
		return 0;
	}

	vmcr = __vgic_v3_read_vmcr();
	rt = kvm_vcpu_sys_get_rt(vcpu);
	fn(vcpu, vmcr, rt);

	__kvm_skip_instr(vcpu);

	return 1;
}