summaryrefslogtreecommitdiff
path: root/meta-arm/meta-arm-bsp/recipes-bsp/hafnium/files/tc/0002-feat-emulate-interrupt-controller-register-access.patch
blob: d9ec6e2a995aad2dbf132bb6d1442a21c9b77891 (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
157
From 97a8ca1835f5d9512dacda497540d5523e56c7dd 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 4c1b6e48..cd5146bd 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -1283,6 +1283,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_unknown_exception(vcpu, esr_el2);
 		return;
diff --git a/src/arch/aarch64/hypervisor/perfmon.c b/src/arch/aarch64/hypervisor/perfmon.c
index f13b0354..05e216c8 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 81669ba1..c90d45bf 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 55e78330..82aa8846 100644
--- a/src/arch/aarch64/msr.h
+++ b/src/arch/aarch64/msr.h
@@ -134,3 +134,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