From f7910aa7534d27bc146c2addca49ce5c8b5f8c36 Mon Sep 17 00:00:00 2001 From: kettenis Date: Wed, 10 Jul 2024 10:53:55 +0000 Subject: [PATCH] Hook up the Qualcomm UEFI Secure Application that handles EFI variables to efi(4) such that we can access EFI variables through ioctls on /dev/efi. ok patrick@ --- sys/arch/arm64/include/efivar.h | 7 ++- sys/dev/efi/efi.c | 57 ++++++++++++++------- sys/dev/fdt/qcscm.c | 87 +++++++++++++++++++++++++++++++-- 3 files changed, 128 insertions(+), 23 deletions(-) diff --git a/sys/arch/arm64/include/efivar.h b/sys/arch/arm64/include/efivar.h index 190549a4a91..3bc3a8644a3 100644 --- a/sys/arch/arm64/include/efivar.h +++ b/sys/arch/arm64/include/efivar.h @@ -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 * @@ -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 *); diff --git a/sys/dev/efi/efi.c b/sys/dev/efi/efi.c index 6f8b37bb017..6be687645f8 100644 --- a/sys/dev/efi/efi.c +++ b/sys/dev/efi/efi.c @@ -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 * @@ -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); diff --git a/sys/dev/fdt/qcscm.c b/sys/dev/fdt/qcscm.c index 50b9f9e0b23..cb7d9d466d4 100644 --- a/sys/dev/fdt/qcscm.c +++ b/sys/dev/fdt/qcscm.c @@ -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 * @@ -33,11 +33,14 @@ #include #include +#include #include #include #include +#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 -- 2.20.1