Make EFI runtime calls more robust on arm64 as well. While I have not seen
authorkettenis <kettenis@openbsd.org>
Sun, 6 Nov 2022 11:44:30 +0000 (11:44 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 6 Nov 2022 11:44:30 +0000 (11:44 +0000)
any broken implementations yet, Linux developers claim that arm64 machines
intended to run Windows are not much better than x86 machines.  And I
totally believe that.

ok patrick@

sys/arch/arm64/arm64/support.S
sys/arch/arm64/arm64/trap.c
sys/arch/arm64/conf/files.arm64
sys/arch/arm64/dev/efi_machdep.c

index a08d11d..5eebc4d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: support.S,v 1.9 2019/03/15 05:42:38 kevlo Exp $ */
+/* $OpenBSD: support.S,v 1.10 2022/11/06 11:44:30 kettenis Exp $ */
 /*-
  * Copyright (c) 2014 Andrew Turner
  * Copyright (c) 2014-2015 The FreeBSD Foundation
@@ -36,8 +36,9 @@
 #include <machine/vmparam.h>
 
 #include "assym.h"
+#include "efi.h"
 
-#ifdef DDB
+#if defined(DDB) || NEFI > 0
 ENTRY(setjmp)
        RETGUARD_SETUP(setjmp, x15)
        /* Store the stack pointer */
index d30e40e..1932e38 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.40 2022/08/15 13:33:22 jsg Exp $ */
+/* $OpenBSD: trap.c,v 1.41 2022/11/06 11:44:30 kettenis Exp $ */
 /*-
  * Copyright (c) 2014 Andrew Turner
  * All rights reserved.
@@ -158,11 +158,14 @@ kdata_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int exe)
                 * Only allow user-space access using
                 * unprivileged load/store instructions.
                 */
-               if (!is_unpriv_ldst(frame->tf_elr)) {
+               if (is_unpriv_ldst(frame->tf_elr))
+                       map = &p->p_vmspace->vm_map;
+               else if (pcb->pcb_onfault != NULL)
+                       map = kernel_map;
+               else {
                        panic("attempt to access user address"
                              " 0x%llx from EL1", far);
                }
-               map = &p->p_vmspace->vm_map;
        }
 
        /* Handle referenced/modified emulation */
@@ -175,7 +178,7 @@ kdata_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int exe)
 
        if (error != 0) {
                if (curcpu()->ci_idepth == 0 &&
-                   pcb->pcb_onfault != 0) {
+                   pcb->pcb_onfault != NULL) {
                        frame->tf_elr = (register_t)pcb->pcb_onfault;
                        return;
                }
@@ -215,6 +218,9 @@ do_el1h_sync(struct trapframe *frame)
        case EXCP_FP_SIMD:
        case EXCP_TRAP_FP:
                panic("FP exception in the kernel");
+       case EXCP_INSN_ABORT:
+               kdata_abort(frame, esr, far, 1);
+               break;
        case EXCP_DATA_ABORT:
                kdata_abort(frame, esr, far, 0);
                break;
index 2a7bdba..e8087bc 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: files.arm64,v 1.61 2022/10/03 19:32:22 kettenis Exp $
+# $OpenBSD: files.arm64,v 1.62 2022/11/06 11:44:30 kettenis Exp $
 
 maxpartitions  16
 maxusers       2 8 128
@@ -65,7 +65,7 @@ file  arch/arm64/dev/simplebus.c              simplebus
 
 device efi {}
 attach efi at fdt
-file   arch/arm64/dev/efi_machdep.c            efi
+file   arch/arm64/dev/efi_machdep.c            efi needs-flag
 
 device smbios
 attach smbios at efi
index 1dd2c4e..3779f9f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efi_machdep.c,v 1.4 2022/10/29 20:35:50 kettenis Exp $        */
+/*     $OpenBSD: efi_machdep.c,v 1.5 2022/11/06 11:44:30 kettenis Exp $        */
 
 /*
  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
@@ -26,6 +26,7 @@
 #include <machine/bus.h>
 #include <machine/fdt.h>
 #include <machine/fpu.h>
+#include <machine/pcb.h>
 
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/fdt.h>
@@ -75,6 +76,11 @@ void efi_leave(struct efi_softc *);
 int    efi_gettime(struct todr_chip_handle *, struct timeval *);
 int    efi_settime(struct todr_chip_handle *, struct timeval *);
 
+label_t efi_jmpbuf;
+
+#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \
+    (efi_leave(sc), EFAULT) : (efi_enter(sc), 0))
+
 int
 efi_match(struct device *parent, void *match, void *aux)
 {
@@ -161,7 +167,8 @@ efi_attach(struct device *parent, struct device *self, void *aux)
                config_found(self, &fa, NULL);
        }
        
-       efi_enter(sc);
+       if (efi_enter_check(sc))
+               return;
        status = sc->sc_rs->GetTime(&time, NULL);
        efi_leave(sc);
        if (status != EFI_SUCCESS)
@@ -252,6 +259,12 @@ efi_map_runtime(struct efi_softc *sc)
        }
 }
 
+void
+efi_fault(void)
+{
+       longjmp(&efi_jmpbuf);
+}
+
 void
 efi_enter(struct efi_softc *sc)
 {
@@ -268,6 +281,8 @@ efi_enter(struct efi_softc *sc)
        cpu_setttb(pm->pm_asid, pm->pm_pt0pa);
 
        fpu_kernel_enter();
+
+       curcpu()->ci_curpcb->pcb_onfault = (void *)efi_fault;
 }
 
 void
@@ -276,6 +291,8 @@ efi_leave(struct efi_softc *sc)
        struct pmap *pm = curcpu()->ci_curpm;
        uint64_t tcr;
 
+       curcpu()->ci_curpcb->pcb_onfault = NULL;
+
        fpu_kernel_exit();
 
        WRITE_SPECIALREG(ttbr0_el1, pmap_kernel()->pm_pt0pa);
@@ -296,7 +313,8 @@ efi_gettime(struct todr_chip_handle *handle, struct timeval *tv)
        EFI_TIME time;
        EFI_STATUS status;
 
-       efi_enter(sc);
+       if (efi_enter_check(sc))
+               return EFAULT;
        status = sc->sc_rs->GetTime(&time, NULL);
        efi_leave(sc);
        if (status != EFI_SUCCESS)
@@ -340,7 +358,8 @@ efi_settime(struct todr_chip_handle *handle, struct timeval *tv)
        time.TimeZone = 0;
        time.Daylight = 0;
 
-       efi_enter(sc);
+       if (efi_enter_check(sc))
+               return EFAULT;
        status = sc->sc_rs->SetTime(&time);
        efi_leave(sc);
        if (status != EFI_SUCCESS)