Hook up the Qualcomm UEFI Secure Application that handles EFI variables to
authorkettenis <kettenis@openbsd.org>
Wed, 10 Jul 2024 10:53:55 +0000 (10:53 +0000)
committerkettenis <kettenis@openbsd.org>
Wed, 10 Jul 2024 10:53:55 +0000 (10:53 +0000)
efi(4) such that we can access EFI variables through ioctls on /dev/efi.

ok patrick@

sys/arch/arm64/include/efivar.h
sys/dev/efi/efi.c
sys/dev/fdt/qcscm.c

index 190549a..3bc3a86 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efivar.h,v 1.1 2023/01/14 12:11:11 kettenis Exp $     */
+/*     $OpenBSD: efivar.h,v 1.2 2024/07/10 10:53:55 kettenis Exp $     */
 /*
  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
  *
@@ -30,6 +30,11 @@ struct efi_softc {
        struct todr_chip_handle sc_todr;
 };
 
+
+extern EFI_GET_VARIABLE efi_get_variable;
+extern EFI_SET_VARIABLE efi_set_variable;
+extern EFI_GET_NEXT_VARIABLE_NAME efi_get_next_variable_name;
+
 void   efi_enter(struct efi_softc *);
 void   efi_leave(struct efi_softc *);
 
index 6f8b37b..6be6876 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efi.c,v 1.1 2023/01/14 12:11:11 kettenis Exp $        */
+/*     $OpenBSD: efi.c,v 1.2 2024/07/10 10:53:55 kettenis Exp $        */
 /*
  * Copyright (c) 2022 3mdeb <contact@3mdeb.com>
  *
@@ -33,6 +33,10 @@ int  efiioc_var_next(struct efi_softc *sc, void *);
 int    efiioc_var_set(struct efi_softc *sc, void *);
 int    efi_adapt_error(EFI_STATUS);
 
+EFI_GET_VARIABLE efi_get_variable;
+EFI_SET_VARIABLE efi_set_variable;
+EFI_GET_NEXT_VARIABLE_NAME efi_get_next_variable_name;
+
 int
 efiopen(dev_t dev, int flag, int mode, struct proc *p)
 {
@@ -142,13 +146,18 @@ efiioc_var_get(struct efi_softc *sc, void *data)
                goto leave;
        }
 
-       if (efi_enter_check(sc)) {
-               error = ENOSYS;
-               goto leave;
+       if (efi_get_variable) {
+               status = efi_get_variable(name, (EFI_GUID *)&ioc->vendor,
+                                       &ioc->attrib, &ioc->datasize, value);
+       } else {
+               if (efi_enter_check(sc)) {
+                       error = ENOSYS;
+                       goto leave;
+               }
+               status = sc->sc_rs->GetVariable(name, (EFI_GUID *)&ioc->vendor,
+                   &ioc->attrib, &ioc->datasize, value);
+               efi_leave(sc);
        }
-       status = sc->sc_rs->GetVariable(name, (EFI_GUID *)&ioc->vendor,
-           &ioc->attrib, &ioc->datasize, value);
-       efi_leave(sc);
 
        if (status == EFI_BUFFER_TOO_SMALL) {
                /*
@@ -183,13 +192,18 @@ efiioc_var_next(struct efi_softc *sc, void *data)
        if (error)
                goto leave;
 
-       if (efi_enter_check(sc)) {
-               error = ENOSYS;
-               goto leave;
+       if (efi_get_next_variable_name) {
+               status = efi_get_next_variable_name(&ioc->namesize,
+                   name, (EFI_GUID *)&ioc->vendor);
+       } else {
+               if (efi_enter_check(sc)) {
+                       error = ENOSYS;
+                       goto leave;
+               }
+               status = sc->sc_rs->GetNextVariableName(&ioc->namesize,
+                   name, (EFI_GUID *)&ioc->vendor);
+               efi_leave(sc);
        }
-       status = sc->sc_rs->GetNextVariableName(&ioc->namesize,
-           name, (EFI_GUID *)&ioc->vendor);
-       efi_leave(sc);
 
        if (status == EFI_BUFFER_TOO_SMALL) {
                /*
@@ -242,13 +256,18 @@ efiioc_var_set(struct efi_softc *sc, void *data)
                goto leave;
        }
 
-       if (efi_enter_check(sc)) {
-               error = ENOSYS;
-               goto leave;
+       if (efi_set_variable) {
+               status = efi_set_variable(name, (EFI_GUID *)&ioc->vendor,
+                   ioc->attrib, ioc->datasize, value);
+       } else {
+               if (efi_enter_check(sc)) {
+                       error = ENOSYS;
+                       goto leave;
+               }
+               status = sc->sc_rs->SetVariable(name, (EFI_GUID *)&ioc->vendor,
+                   ioc->attrib, ioc->datasize, value);
+               efi_leave(sc);
        }
-       status = sc->sc_rs->SetVariable(name, (EFI_GUID *)&ioc->vendor,
-           ioc->attrib, ioc->datasize, value);
-       efi_leave(sc);
 
        error = efi_adapt_error(status);
 
index 50b9f9e..cb7d9d4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: qcscm.c,v 1.7 2024/07/04 20:11:46 kettenis Exp $ */
+/* $OpenBSD: qcscm.c,v 1.8 2024/07/10 10:53:55 kettenis Exp $ */
 /*
  * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se>
  *
 #include <machine/fdt.h>
 
 #include <dev/efi/efi.h>
+#include <machine/efivar.h>
 
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_misc.h>
 #include <dev/ofw/fdt.h>
 
+#include "efi.h"
+
 /* #define QCSCM_DEBUG */
 
 #define ARM_SMCCC_STD_CALL                     (0U << 31)
@@ -142,6 +145,12 @@ EFI_STATUS qcscm_uefi_set_variable(struct qcscm_softc *, CHAR16 *,
 EFI_STATUS qcscm_uefi_get_next_variable(struct qcscm_softc *,
            CHAR16 *, int *, EFI_GUID *);
 
+EFI_STATUS qcscm_efi_get_variable(CHAR16 *, EFI_GUID *, UINT32 *,
+           UINTN *, VOID *);
+EFI_STATUS qcscm_efi_set_variable(CHAR16 *, EFI_GUID *, UINT32,
+           UINTN, VOID *);
+EFI_STATUS qcscm_efi_get_next_variable_name(UINTN *, CHAR16 *, EFI_GUID *);
+
 #ifdef QCSCM_DEBUG
 void   qcscm_uefi_dump_variables(struct qcscm_softc *);
 void   qcscm_uefi_dump_variable(struct qcscm_softc *, CHAR16 *, int,
@@ -188,6 +197,12 @@ qcscm_attach(struct device *parent, struct device *self, void *aux)
        printf("\n");
        qcscm_sc = sc;
 
+#if NEFI > 0
+       efi_get_variable = qcscm_efi_get_variable;
+       efi_set_variable = qcscm_efi_set_variable;
+       efi_get_next_variable_name = qcscm_efi_get_next_variable_name;
+#endif
+
 #ifdef QCSCM_DEBUG
        qcscm_uefi_dump_variables(sc);
        qcscm_uefi_dump_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"),
@@ -418,7 +433,7 @@ qcscm_uefi_get_variable(struct qcscm_softc *sc,
 
        resp = QCSCM_DMA_KVA(qdm) + respoff;
        if (resp->command_id != QCTEE_UEFI_GET_VARIABLE ||
-           resp->length < sizeof(*resp) || resp->length > respsize) {
+           resp->length < sizeof(*resp)) {
                qcscm_dmamem_free(sc, qdm);
                return QCTEE_UEFI_DEVICE_ERROR;
        }
@@ -433,7 +448,8 @@ qcscm_uefi_get_variable(struct qcscm_softc *sc,
                return ret;
        }
 
-       if (resp->data_offset + resp->data_size > resp->length) {
+       if (resp->length > respsize ||
+           resp->data_offset + resp->data_size > resp->length) {
                qcscm_dmamem_free(sc, qdm);
                return QCTEE_UEFI_DEVICE_ERROR;
        }
@@ -641,7 +657,71 @@ qcscm_uefi_get_next_variable(struct qcscm_softc *sc,
        return QCTEE_UEFI_SUCCESS;
 }
 
+#if NEFI > 0
+
+EFI_STATUS
+qcscm_efi_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attributes,
+   UINTN *data_size, VOID *data)
+{
+       struct qcscm_softc *sc = qcscm_sc;
+       EFI_STATUS status;
+       int name_size;
+       int size;
+
+       name_size = 0;
+       while (name[name_size])
+               name_size++;
+       name_size++;
+
+       size = *data_size;
+       status = qcscm_uefi_get_variable(sc, name, name_size * 2, guid,
+           attributes, data, &size);
+       *data_size = size;
+
+       /* Convert 32-bit status code to 64-bit. */
+       return ((status & 0xf0000000) << 32 | (status & 0x0fffffff));
+}
+
+EFI_STATUS
+qcscm_efi_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attributes,
+    UINTN data_size, VOID *data)
+{
+       struct qcscm_softc *sc = qcscm_sc;
+       EFI_STATUS status;
+       int name_size;
+
+       name_size = 0;
+       while (name[name_size])
+               name_size++;
+       name_size++;
+
+       status = qcscm_uefi_set_variable(sc, name, name_size * 2, guid,
+           attributes, data, data_size);
+
+       /* Convert 32-bit status code to 64-bit. */
+       return ((status & 0xf0000000) << 32 | (status & 0x0fffffff));
+}
+
+EFI_STATUS
+qcscm_efi_get_next_variable_name(UINTN *name_size, CHAR16 *name,
+    EFI_GUID *guid)
+{
+       struct qcscm_softc *sc = qcscm_sc;
+       EFI_STATUS status;
+       int size;
+
+       size = *name_size;
+       status = qcscm_uefi_get_next_variable(sc, name, &size, guid);
+       *name_size = size;
+
+       /* Convert 32-bit status code to 64-bit. */
+       return ((status & 0xf0000000) << 32 | (status & 0x0fffffff));
+}
+
+#endif
+
 #ifdef QCSCM_DEBUG
+
 void
 qcscm_uefi_dump_variables(struct qcscm_softc *sc)
 {
@@ -699,6 +779,7 @@ qcscm_uefi_dump_variable(struct qcscm_softc *sc, CHAR16 *name, int namesize,
                printf("%02x", data[i]);
        printf("\n");
 }
+
 #endif
 
 int