251 lines
7.7 KiB
Diff
251 lines
7.7 KiB
Diff
|
|
From f526797b83113cc64e3e658c22d8a5d269896a2a Mon Sep 17 00:00:00 2001
|
||
|
|
From: Ben Horgan <ben.horgan@arm.com>
|
||
|
|
Date: Fri, 4 Mar 2022 16:48:14 +0000
|
||
|
|
Subject: [PATCH] feat: emulate cntp timer register accesses using cnthps
|
||
|
|
|
||
|
|
Upstream-Status: Inappropriate [Experimental feature]
|
||
|
|
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
|
||
|
|
Change-Id: I67508203273baf3bd8e6be2d99717028db945715
|
||
|
|
---
|
||
|
|
Makefile | 3 +-
|
||
|
|
src/arch/aarch64/hypervisor/BUILD.gn | 1 +
|
||
|
|
src/arch/aarch64/hypervisor/cpu.c | 11 ++-
|
||
|
|
src/arch/aarch64/hypervisor/handler.c | 6 ++
|
||
|
|
src/arch/aarch64/hypervisor/timer_el1.c | 104 ++++++++++++++++++++++++
|
||
|
|
src/arch/aarch64/hypervisor/timer_el1.h | 20 +++++
|
||
|
|
src/arch/aarch64/msr.h | 8 ++
|
||
|
|
7 files changed, 150 insertions(+), 3 deletions(-)
|
||
|
|
create mode 100644 src/arch/aarch64/hypervisor/timer_el1.c
|
||
|
|
create mode 100644 src/arch/aarch64/hypervisor/timer_el1.h
|
||
|
|
|
||
|
|
diff --git a/Makefile b/Makefile
|
||
|
|
index 95cab9a5..21cca938 100644
|
||
|
|
--- a/Makefile
|
||
|
|
+++ b/Makefile
|
||
|
|
@@ -60,7 +60,8 @@ CHECKPATCH := $(CURDIR)/third_party/linux/scripts/checkpatch.pl \
|
||
|
|
# debug_el1.c : uses XMACROS, which checkpatch doesn't understand.
|
||
|
|
# perfmon.c : uses XMACROS, which checkpatch doesn't understand.
|
||
|
|
# feature_id.c : uses XMACROS, which checkpatch doesn't understand.
|
||
|
|
-CHECKPATCH_IGNORE := "src/arch/aarch64/hypervisor/debug_el1.c\|src/arch/aarch64/hypervisor/perfmon.c\|src/arch/aarch64/hypervisor/feature_id.c"
|
||
|
|
+# timer_el1.c : uses XMACROS, which checkpatch doesn't understand.
|
||
|
|
+CHECKPATCH_IGNORE := "src/arch/aarch64/hypervisor/debug_el1.c\|src/arch/aarch64/hypervisor/perfmon.c\|src/arch/aarch64/hypervisor/feature_id.c\|src/arch/aarch64/hypervisor/timer_el1.c"
|
||
|
|
|
||
|
|
OUT ?= out/$(PROJECT)
|
||
|
|
OUT_DIR = out/$(PROJECT)
|
||
|
|
diff --git a/src/arch/aarch64/hypervisor/BUILD.gn b/src/arch/aarch64/hypervisor/BUILD.gn
|
||
|
|
index 6068d1e8..de1a414d 100644
|
||
|
|
--- a/src/arch/aarch64/hypervisor/BUILD.gn
|
||
|
|
+++ b/src/arch/aarch64/hypervisor/BUILD.gn
|
||
|
|
@@ -45,6 +45,7 @@ source_set("hypervisor") {
|
||
|
|
"handler.c",
|
||
|
|
"perfmon.c",
|
||
|
|
"psci_handler.c",
|
||
|
|
+ "timer_el1.c",
|
||
|
|
"vm.c",
|
||
|
|
]
|
||
|
|
|
||
|
|
diff --git a/src/arch/aarch64/hypervisor/cpu.c b/src/arch/aarch64/hypervisor/cpu.c
|
||
|
|
index bcf5ffce..d2df77d8 100644
|
||
|
|
--- a/src/arch/aarch64/hypervisor/cpu.c
|
||
|
|
+++ b/src/arch/aarch64/hypervisor/cpu.c
|
||
|
|
@@ -98,13 +98,20 @@ void arch_regs_reset(struct vcpu *vcpu)
|
||
|
|
if (is_primary) {
|
||
|
|
/*
|
||
|
|
* cnthctl_el2 is redefined when VHE is enabled.
|
||
|
|
- * EL1PCTEN, don't trap phys cnt access.
|
||
|
|
- * EL1PCEN, don't trap phys timer access.
|
||
|
|
+ * EL1PCTEN, don't trap phys cnt access. Except when in
|
||
|
|
+ * secure world without vhe.
|
||
|
|
+ * EL1PCEN, don't trap phys timer access. Except when in
|
||
|
|
+ * secure world without vhe.
|
||
|
|
*/
|
||
|
|
if (has_vhe_support()) {
|
||
|
|
cnthctl |= (1U << 10) | (1U << 11);
|
||
|
|
} else {
|
||
|
|
+#if SECURE_WORLD == 1
|
||
|
|
+ cnthctl &= ~(1U << 0);
|
||
|
|
+ cnthctl &= ~(1U << 1);
|
||
|
|
+#else
|
||
|
|
cnthctl |= (1U << 0) | (1U << 1);
|
||
|
|
+#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
|
||
|
|
index 4bd8a3b4..4c1b6e48 100644
|
||
|
|
--- a/src/arch/aarch64/hypervisor/handler.c
|
||
|
|
+++ b/src/arch/aarch64/hypervisor/handler.c
|
||
|
|
@@ -34,6 +34,7 @@
|
||
|
|
#include "psci_handler.h"
|
||
|
|
#include "smc.h"
|
||
|
|
#include "sysregs.h"
|
||
|
|
+#include "timer_el1.h"
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Hypervisor Fault Address Register Non-Secure.
|
||
|
|
@@ -1277,6 +1278,11 @@ void handle_system_register_access(uintreg_t esr_el2)
|
||
|
|
inject_el1_unknown_exception(vcpu, esr_el2);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
+ } else if (timer_el1_is_register_access(esr_el2)) {
|
||
|
|
+ if (!timer_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/timer_el1.c b/src/arch/aarch64/hypervisor/timer_el1.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..c30e5543
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/src/arch/aarch64/hypervisor/timer_el1.c
|
||
|
|
@@ -0,0 +1,104 @@
|
||
|
|
+/*
|
||
|
|
+ * Copyright 2022 The Hafnium Authors.
|
||
|
|
+ *
|
||
|
|
+ * Use of this source code is governed by a BSD-style
|
||
|
|
+ * license that can be found in the LICENSE file or at
|
||
|
|
+ * https://opensource.org/licenses/BSD-3-Clause.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+#include "timer_el1.h"
|
||
|
|
+
|
||
|
|
+#include "hf/dlog.h"
|
||
|
|
+
|
||
|
|
+#include "msr.h"
|
||
|
|
+#include "sysregs.h"
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Physical timer (CNTP) register encodings as defined in
|
||
|
|
+ * table D13-8 of the ARMv8 ARM (DDI0487F).
|
||
|
|
+ * TYPE, op0, op1, crn, crm, op2
|
||
|
|
+ * The register names are the concatenation of
|
||
|
|
+ * "CNTP_", TYPE and "_EL2".
|
||
|
|
+ */
|
||
|
|
+#define CNTP_REGISTERS \
|
||
|
|
+ X(CTL, 3, 3, 14, 2, 1) \
|
||
|
|
+ X(CVAL, 3, 3, 14, 2, 2) \
|
||
|
|
+ X(TVAL, 3, 3, 14, 2, 0) \
|
||
|
|
+
|
||
|
|
+bool timer_el1_is_register_access(uintreg_t esr)
|
||
|
|
+{
|
||
|
|
+ uintreg_t sys_register = GET_ISS_SYSREG(esr);
|
||
|
|
+ bool is_timer_access;
|
||
|
|
+ switch (sys_register) {
|
||
|
|
+#define X(type, op0, op1, crn, crm, op2) \
|
||
|
|
+ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
|
||
|
|
+ is_timer_access = true; \
|
||
|
|
+ break;
|
||
|
|
+ CNTP_REGISTERS
|
||
|
|
+#undef X
|
||
|
|
+ case (GET_ISS_ENCODING(3, 3, 14, 0, 1)):
|
||
|
|
+ is_timer_access = true;
|
||
|
|
+ break;
|
||
|
|
+ default:
|
||
|
|
+ is_timer_access = false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return is_timer_access;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* Accesses to CNTP timer emulated with CNTHPS */
|
||
|
|
+bool timer_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;
|
||
|
|
+
|
||
|
|
+ if (ISS_IS_READ(esr)) {
|
||
|
|
+ switch (sys_register) {
|
||
|
|
+#define X(type, op0, op1, crn, crm, op2) \
|
||
|
|
+ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
|
||
|
|
+ value = read_msr(MSR_CNTHPS_##type##_EL2); \
|
||
|
|
+ vcpu->regs.r[rt_register] = value; \
|
||
|
|
+ break;
|
||
|
|
+ CNTP_REGISTERS
|
||
|
|
+#undef X
|
||
|
|
+ case (GET_ISS_ENCODING(3, 3, 14, 0, 1)):
|
||
|
|
+ value = read_msr(cntpct_el0);
|
||
|
|
+ vcpu->regs.r[rt_register] = value;
|
||
|
|
+ break;
|
||
|
|
+ default:
|
||
|
|
+ dlog_notice(
|
||
|
|
+ "Unsupported timer 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;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ value = vcpu->regs.r[rt_register];
|
||
|
|
+ switch (sys_register) {
|
||
|
|
+#define X(type, op0, op1, crn, crm, op2) \
|
||
|
|
+ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \
|
||
|
|
+ write_msr(MSR_CNTHPS_##type##_EL2, value); \
|
||
|
|
+ break;
|
||
|
|
+ CNTP_REGISTERS
|
||
|
|
+#undef X
|
||
|
|
+ default:
|
||
|
|
+ dlog_notice(
|
||
|
|
+ "Unsupported timer register "
|
||
|
|
+ "write: "
|
||
|
|
+ "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, "
|
||
|
|
+ "rt=%d, value=%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), value);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
diff --git a/src/arch/aarch64/hypervisor/timer_el1.h b/src/arch/aarch64/hypervisor/timer_el1.h
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..04a43b6c
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/src/arch/aarch64/hypervisor/timer_el1.h
|
||
|
|
@@ -0,0 +1,20 @@
|
||
|
|
+/*
|
||
|
|
+ * Copyright 2022 The Hafnium Authors.
|
||
|
|
+ *
|
||
|
|
+ * Use of this source code is governed by a BSD-style
|
||
|
|
+ * license that can be found in the LICENSE file or at
|
||
|
|
+ * https://opensource.org/licenses/BSD-3-Clause.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "hf/arch/types.h"
|
||
|
|
+
|
||
|
|
+#include "hf/cpu.h"
|
||
|
|
+
|
||
|
|
+#include "vmapi/hf/ffa.h"
|
||
|
|
+
|
||
|
|
+bool timer_el1_is_register_access(uintreg_t esr);
|
||
|
|
+
|
||
|
|
+bool timer_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 cd6778b4..55e78330 100644
|
||
|
|
--- a/src/arch/aarch64/msr.h
|
||
|
|
+++ b/src/arch/aarch64/msr.h
|
||
|
|
@@ -126,3 +126,11 @@
|
||
|
|
#define MSR_ELR_EL12 S3_5_C4_C0_1
|
||
|
|
|
||
|
|
#endif
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Secure EL2 Physical timer (CNTHPS) register encodings as defined in
|
||
|
|
+ * table D13-8 of the ARMv8 ARM (DDI0487F).
|
||
|
|
+ */
|
||
|
|
+#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
|
||
|
|
|