aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2023-03-03 17:02:19 +0000
committerKyle Evans <kevans@FreeBSD.org>2023-03-03 17:02:34 +0000
commitd2ae03bae2add82124973876dec95eb126ff34c8 (patch)
treee9c44b9af7dfb53e97c5bac1a152de3bec4807a8
parent577b62c2bacc7dfa228591ca3da361e1bc398301 (diff)
downloadsrc-d2ae03bae2add82124973876dec95eb126ff34c8.tar.gz
src-d2ae03bae2add82124973876dec95eb126ff34c8.zip
arm64: disable the physical timer for now if HCR_EL2.E2H is set
On some hardware, we can't clear HCR_EL2.E2H so accesses to the physical timer hopelessly trap to EL2. Stash off the value of HCR_EL2 and use it in has_hyp() to avoid this. Reviewed by: andrew Differential Revision: https://reviews.freebsd.org/D38884
-rw-r--r--sys/arm64/arm64/genassym.c1
-rw-r--r--sys/arm64/arm64/locore.S5
-rw-r--r--sys/arm64/arm64/machdep.c9
-rw-r--r--sys/arm64/include/machdep.h1
4 files changed, 13 insertions, 3 deletions
diff --git a/sys/arm64/arm64/genassym.c b/sys/arm64/arm64/genassym.c
index bd359699eca9..e444d0166360 100644
--- a/sys/arm64/arm64/genassym.c
+++ b/sys/arm64/arm64/genassym.c
@@ -45,6 +45,7 @@ ASSYM(BP_KERN_DELTA, offsetof(struct arm64_bootparams, kern_delta));
ASSYM(BP_KERN_STACK, offsetof(struct arm64_bootparams, kern_stack));
ASSYM(BP_KERN_TTBR0, offsetof(struct arm64_bootparams, kern_ttbr0));
ASSYM(BP_BOOT_EL, offsetof(struct arm64_bootparams, boot_el));
+ASSYM(BP_HCR_EL2, offsetof(struct arm64_bootparams, hcr_el2));
ASSYM(PCPU_SIZE, sizeof(struct pcpu));
ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb));
diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index da3001711955..1080ebc6217e 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -146,6 +146,7 @@ virtdone:
str x25, [x0, #BP_KERN_STACK]
str x27, [x0, #BP_KERN_TTBR0]
str x23, [x0, #BP_BOOT_EL]
+ str x4, [x0, #BP_HCR_EL2]
/* trace back starts here */
mov fp, #0
@@ -286,8 +287,8 @@ LENTRY(drop_to_el1)
*/
tst x4, #HCR_E2H
mov x3, #CPTR_RES1 /* HCR_E2H == 0 */
- mov x4, #CPTR_FPEN /* HCR_E2H == 1 */
- csel x2, x3, x4, eq
+ mov x5, #CPTR_FPEN /* HCR_E2H == 1 */
+ csel x2, x3, x5, eq
msr cptr_el2, x2
/* Don't trap to EL2 for CP15 traps */
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index 19fa7cd913a0..a076bd0a046a 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#include <machine/armreg.h>
#include <machine/cpu.h>
#include <machine/debug_monitor.h>
+#include <machine/hypervisor.h>
#include <machine/kdb.h>
#include <machine/machdep.h>
#include <machine/metadata.h>
@@ -124,6 +125,7 @@ static struct trapframe proc0_tf;
int early_boot = 1;
int cold = 1;
static int boot_el;
+static uint64_t hcr_el2;
struct kva_md_info kmi;
@@ -191,7 +193,11 @@ bool
has_hyp(void)
{
- return (boot_el == 2);
+ /*
+ * XXX The E2H check is wrong, but it's close enough for now. Needs to
+ * be re-evaluated once we're running regularly in EL2.
+ */
+ return (boot_el == 2 && (hcr_el2 & HCR_E2H) == 0);
}
static void
@@ -865,6 +871,7 @@ initarm(struct arm64_bootparams *abp)
TSRAW(&thread0, TS_ENTER, __func__, NULL);
boot_el = abp->boot_el;
+ hcr_el2 = abp->hcr_el2;
/* Parse loader or FDT boot parametes. Determine last used address. */
lastaddr = parse_boot_param(abp);
diff --git a/sys/arm64/include/machdep.h b/sys/arm64/include/machdep.h
index 112390bb27ef..69babfff8467 100644
--- a/sys/arm64/include/machdep.h
+++ b/sys/arm64/include/machdep.h
@@ -36,6 +36,7 @@ struct arm64_bootparams {
uint64_t kern_delta;
vm_offset_t kern_stack;
vm_paddr_t kern_ttbr0;
+ uint64_t hcr_el2;
int boot_el; /* EL the kernel booted from */
int pad;
};