git: 278111b8a541 - main - Allow the kernel to emulate the physical counter on arm64
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 25 Aug 2022 11:17:39 UTC
The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=278111b8a54141bdaf4c4a045539db21febf053f commit 278111b8a54141bdaf4c4a045539db21febf053f Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2022-06-27 12:37:40 +0000 Commit: Andrew Turner <andrew@FreeBSD.org> CommitDate: 2022-08-25 11:17:23 +0000 Allow the kernel to emulate the physical counter on arm64 When running under a VM we don't have access to the physical counter. Add support to emulate this instruction by handling the trap in the kernel. As it is slow only enable when the hw.emulate_phys_counter tunable is set on boot. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D35613 --- sys/arm/arm/generic_timer.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c index 0e0e8a53bcce..0c242a31d9a7 100644 --- a/sys/arm/arm/generic_timer.c +++ b/sys/arm/arm/generic_timer.c @@ -63,6 +63,10 @@ __FBSDID("$FreeBSD$"); #include <machine/machdep.h> /* For arm_set_delay */ #endif +#if defined(__aarch64__) +#include <machine/undefined.h> +#endif + #ifdef FDT #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_bus.h> @@ -235,12 +239,52 @@ setup_user_access(void *arg __unused) isb(); } +#ifdef __aarch64__ +static int +cntpct_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame, + uint32_t esr) +{ + uint64_t val; + int reg; + + if ((insn & MRS_MASK) != MRS_VALUE) + return (0); + + if (MRS_SPECIAL(insn) != MRS_SPECIAL(CNTPCT_EL0)) + return (0); + + reg = MRS_REGISTER(insn); + val = READ_SPECIALREG(cntvct_el0); + if (reg < nitems(frame->tf_x)) { + frame->tf_x[reg] = val; + } else if (reg == 30) { + frame->tf_lr = val; + } + + /* + * We will handle this instruction, move to the next so we + * don't trap here again. + */ + frame->tf_elr += INSN_SIZE; + + return (1); +} +#endif + static void tmr_setup_user_access(void *arg __unused) { + int emulate; - if (arm_tmr_sc != NULL) + if (arm_tmr_sc != NULL) { smp_rendezvous(NULL, setup_user_access, NULL, NULL); +#ifdef __aarch64__ + if (TUNABLE_INT_FETCH("hw.emulate_phys_counter", &emulate) && + emulate != 0) { + install_undef_handler(true, cntpct_handler); + } +#endif + } } SYSINIT(tmr_ua, SI_SUB_SMP, SI_ORDER_ANY, tmr_setup_user_access, NULL);