summaryrefslogtreecommitdiff
path: root/meta-arm/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-feat-emulate-interrupt-controller-register-access.patch
blob: 3e6761519ad09d8f88da3dc89a6f34f75f375c59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
From 9f5b07e30c82713b9598ea60d9f802bd419b560f Mon Sep 17 00:00:00 2001
From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Date: Tue, 26 Apr 2022 14:43:58 +0100
Subject: [PATCH] feat: emulate interrupt controller register access

This emulates ICC_SGI1R_EL1 and ICC_IGRPEN1_EL1 register

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I0c11f034f3676067597461a183a341c809adcaa4
Upstream-Status: Inappropriate [Experimental feature]
---
 src/arch/aarch64/hypervisor/handler.c |  5 ++
 src/arch/aarch64/hypervisor/perfmon.c | 84 +++++++++++++++++++++++++++
 src/arch/aarch64/hypervisor/perfmon.h |  5 ++
 src/arch/aarch64/msr.h                |  3 +
 4 files changed, 97 insertions(+)

diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index c495df40f3f5..13578fc99670 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -1301,6 +1301,11 @@ void handle_system_register_access(uintreg_t esr_el2)
 			inject_el1_unknown_exception(vcpu, esr_el2);
 			return;
 		}
+	} else if (intr_ctrl_is_register_access(esr_el2)) {
+		if (!intr_ctrl_el1_process_access(vcpu, vm_id, esr_el2)) {
+			inject_el1_unknown_exception(vcpu, esr_el2);
+			return;
+		}
 	} else {
 		inject_el1_sysreg_trap_exception(vcpu, esr_el2);
 		return;
diff --git a/src/arch/aarch64/hypervisor/perfmon.c b/src/arch/aarch64/hypervisor/perfmon.c
index f13b035480d8..05e216c84c2e 100644
--- a/src/arch/aarch64/hypervisor/perfmon.c
+++ b/src/arch/aarch64/hypervisor/perfmon.c
@@ -116,6 +116,10 @@
 	X(PMEVTYPER30_EL0   , 3, 3, 14, 15, 6) \
 	X(PMCCFILTR_EL0     , 3, 3, 14, 15, 7)
 
+#define INTR_CTRL_REGISTERS                    \
+	X(ICC_IGRPEN1_EL1   , 3, 0, 12, 12, 7) \
+	X(ICC_SGI1R_EL1     , 3, 0, 12, 11, 5) \
+
 /* clang-format on */
 
 /**
@@ -232,3 +236,83 @@ uintreg_t perfmon_get_pmccfiltr_el0_init_value(ffa_vm_id_t vm_id)
 
 	return 0;
 }
+
+bool intr_ctrl_is_register_access(uintreg_t esr)
+{
+	uintreg_t op0 = GET_ISS_OP0(esr);
+	uintreg_t op1 = GET_ISS_OP1(esr);
+	uintreg_t crn = GET_ISS_CRN(esr);
+	uintreg_t crm = GET_ISS_CRM(esr);
+
+	if (op0 == 3 && op1 == 0 && crn == 12 && crm == 12) {
+		return true;
+	}
+
+	if (op0 == 3 && op1 == 0 && crn == 12 && crm == 11) {
+		return true;
+	}
+
+	return false;
+}
+
+bool intr_ctrl_el1_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id,
+				  uintreg_t esr)
+{
+	uintreg_t sys_register = GET_ISS_SYSREG(esr);
+	uintreg_t rt_register = GET_ISS_RT(esr);
+	uintreg_t value;
+
+	/* +1 because Rt can access register XZR */
+	CHECK(rt_register < NUM_GP_REGS + 1);
+
+	if (ISS_IS_READ(esr)) {
+		switch (sys_register) {
+#define X(reg_name, op0, op1, crn, crm, op2)              \
+	case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
+		value = read_msr(reg_name);               \
+		break;
+			INTR_CTRL_REGISTERS
+#undef X
+		default:
+			value = vcpu->regs.r[rt_register];
+			dlog_notice(
+				"Unsupported interrupt control register "
+				"read: "
+				"op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, "
+				"rt=%d.\n",
+				GET_ISS_OP0(esr), GET_ISS_OP1(esr),
+				GET_ISS_CRN(esr), GET_ISS_CRM(esr),
+				GET_ISS_OP2(esr), GET_ISS_RT(esr));
+			break;
+		}
+		if (rt_register != RT_REG_XZR) {
+			vcpu->regs.r[rt_register] = value;
+		}
+	} else {
+		if (rt_register != RT_REG_XZR) {
+			value = vcpu->regs.r[rt_register];
+		} else {
+			value = 0;
+		}
+		switch (sys_register) {
+#define X(reg_name, op0, op1, crn, crm, op2)              \
+	case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
+		write_msr(reg_name, value);               \
+		break;
+			INTR_CTRL_REGISTERS
+#undef X
+		default:
+			dlog_notice(
+				"Unsupported interrupt control register "
+				"write: "
+				"op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, "
+				"rt=%d.\n",
+				GET_ISS_OP0(esr), GET_ISS_OP1(esr),
+				GET_ISS_CRN(esr), GET_ISS_CRM(esr),
+				GET_ISS_OP2(esr), GET_ISS_RT(esr));
+			break;
+		}
+	}
+
+	return true;
+}
diff --git a/src/arch/aarch64/hypervisor/perfmon.h b/src/arch/aarch64/hypervisor/perfmon.h
index 81669ba1c401..c90d45bfc239 100644
--- a/src/arch/aarch64/hypervisor/perfmon.h
+++ b/src/arch/aarch64/hypervisor/perfmon.h
@@ -70,3 +70,8 @@ bool perfmon_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id,
 			    uintreg_t esr_el2);
 
 uintreg_t perfmon_get_pmccfiltr_el0_init_value(ffa_vm_id_t vm_id);
+
+bool intr_ctrl_is_register_access(uintreg_t esr);
+
+bool intr_ctrl_el1_process_access(struct vcpu *vcpu, ffa_vm_id_t vm_id,
+				  uintreg_t esr);
diff --git a/src/arch/aarch64/msr.h b/src/arch/aarch64/msr.h
index bf1a66d1d4c5..b88a14b52f68 100644
--- a/src/arch/aarch64/msr.h
+++ b/src/arch/aarch64/msr.h
@@ -139,3 +139,6 @@
 #define MSR_CNTHPS_CTL_EL2 S3_4_C14_C5_1
 #define MSR_CNTHPS_CVAL_EL2 S3_4_C14_C5_2
 #define MSR_CNTHPS_TVAL_EL2 S3_4_C14_C5_0
+
+#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
+#define ICC_SGI1R_EL1 S3_0_C12_C11_5