1*5dbfd905Skettenis /* $OpenBSD: qcscm.c,v 1.9 2024/08/04 15:30:08 kettenis Exp $ */ 25172d7d1Spatrick /* 35172d7d1Spatrick * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se> 45172d7d1Spatrick * 55172d7d1Spatrick * Permission to use, copy, modify, and distribute this software for any 65172d7d1Spatrick * purpose with or without fee is hereby granted, provided that the above 75172d7d1Spatrick * copyright notice and this permission notice appear in all copies. 85172d7d1Spatrick * 95172d7d1Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 105172d7d1Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 115172d7d1Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 125172d7d1Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 135172d7d1Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 145172d7d1Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 155172d7d1Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 165172d7d1Spatrick */ 175172d7d1Spatrick 185172d7d1Spatrick #include <sys/param.h> 195172d7d1Spatrick #include <sys/systm.h> 205172d7d1Spatrick #include <sys/queue.h> 215172d7d1Spatrick #include <sys/malloc.h> 225172d7d1Spatrick #include <sys/sysctl.h> 235172d7d1Spatrick #include <sys/device.h> 245172d7d1Spatrick #include <sys/evcount.h> 255172d7d1Spatrick #include <sys/socket.h> 265172d7d1Spatrick #include <sys/timeout.h> 275172d7d1Spatrick #include <sys/atomic.h> 285172d7d1Spatrick 295172d7d1Spatrick #include <uvm/uvm_extern.h> 305172d7d1Spatrick 315172d7d1Spatrick #include <machine/intr.h> 325172d7d1Spatrick #include <machine/bus.h> 335172d7d1Spatrick #include <machine/fdt.h> 345172d7d1Spatrick 355172d7d1Spatrick #include <dev/efi/efi.h> 36f7910aa7Skettenis #include <machine/efivar.h> 375172d7d1Spatrick 385172d7d1Spatrick #include <dev/ofw/openfirm.h> 395172d7d1Spatrick #include <dev/ofw/ofw_misc.h> 405172d7d1Spatrick #include <dev/ofw/fdt.h> 415172d7d1Spatrick 42f7910aa7Skettenis #include "efi.h" 43f7910aa7Skettenis 445172d7d1Spatrick /* #define QCSCM_DEBUG */ 455172d7d1Spatrick 465172d7d1Spatrick #define ARM_SMCCC_STD_CALL (0U << 31) 475172d7d1Spatrick #define ARM_SMCCC_FAST_CALL (1U << 31) 485172d7d1Spatrick #define ARM_SMCCC_LP64 (1U << 30) 494b4ba7b0Spatrick #define ARM_SMCCC_OWNER_SIP 2 505172d7d1Spatrick 515172d7d1Spatrick #define QCTEE_TZ_OWNER_TZ_APPS 48 525172d7d1Spatrick #define QCTEE_TZ_OWNER_QSEE_OS 50 535172d7d1Spatrick 545172d7d1Spatrick #define QCTEE_TZ_SVC_APP_ID_PLACEHOLDER 0 555172d7d1Spatrick #define QCTEE_TZ_SVC_APP_MGR 1 565172d7d1Spatrick 575172d7d1Spatrick #define QCTEE_OS_RESULT_SUCCESS 0 585172d7d1Spatrick #define QCTEE_OS_RESULT_INCOMPLETE 1 595172d7d1Spatrick #define QCTEE_OS_RESULT_BLOCKED_ON_LISTENER 2 605172d7d1Spatrick #define QCTEE_OS_RESULT_FAILURE 0xffffffff 615172d7d1Spatrick 625172d7d1Spatrick #define QCTEE_OS_SCM_RES_APP_ID 0xee01 635172d7d1Spatrick #define QCTEE_OS_SCM_RES_QSEOS_LISTENER_ID 0xee02 645172d7d1Spatrick 655172d7d1Spatrick #define QCTEE_UEFI_GET_VARIABLE 0x8000 665172d7d1Spatrick #define QCTEE_UEFI_SET_VARIABLE 0x8001 675172d7d1Spatrick #define QCTEE_UEFI_GET_NEXT_VARIABLE 0x8002 685172d7d1Spatrick #define QCTEE_UEFI_QUERY_VARIABLE_INFO 0x8003 695172d7d1Spatrick 705172d7d1Spatrick #define QCTEE_UEFI_SUCCESS 0 715172d7d1Spatrick #define QCTEE_UEFI_BUFFER_TOO_SMALL 0x80000005 725172d7d1Spatrick #define QCTEE_UEFI_DEVICE_ERROR 0x80000007 735172d7d1Spatrick #define QCTEE_UEFI_NOT_FOUND 0x8000000e 745172d7d1Spatrick 754b4ba7b0Spatrick #define QCSCM_SVC_PIL 0x02 764b4ba7b0Spatrick #define QCSCM_PIL_PAS_INIT_IMAGE 0x01 774b4ba7b0Spatrick #define QCSCM_PIL_PAS_MEM_SETUP 0x02 784b4ba7b0Spatrick #define QCSCM_PIL_PAS_AUTH_AND_RESET 0x05 794b4ba7b0Spatrick #define QCSCM_PIL_PAS_SHUTDOWN 0x06 804b4ba7b0Spatrick #define QCSCM_PIL_PAS_IS_SUPPORTED 0x07 814b4ba7b0Spatrick #define QCSCM_PIL_PAS_MSS_RESET 0x0a 824b4ba7b0Spatrick 835172d7d1Spatrick #define QCSCM_INTERRUPTED 1 845172d7d1Spatrick 855172d7d1Spatrick #define QCSCM_ARGINFO_NUM(x) (((x) & 0xf) << 0) 865172d7d1Spatrick #define QCSCM_ARGINFO_TYPE(x, y) (((y) & 0x3) << (4 + 2 * (x))) 875172d7d1Spatrick #define QCSCM_ARGINFO_TYPE_VAL 0 885172d7d1Spatrick #define QCSCM_ARGINFO_TYPE_RO 1 895172d7d1Spatrick #define QCSCM_ARGINFO_TYPE_RW 2 905172d7d1Spatrick #define QCSCM_ARGINFO_TYPE_BUFVAL 3 915172d7d1Spatrick 925172d7d1Spatrick #define EFI_VARIABLE_NON_VOLATILE 0x00000001 935172d7d1Spatrick #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 945172d7d1Spatrick #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 955172d7d1Spatrick 9641e484b3Spatrick #define UNIX_GPS_EPOCH_OFFSET 315964800 9741e484b3Spatrick 985172d7d1Spatrick struct qcscm_dmamem { 995172d7d1Spatrick bus_dmamap_t qdm_map; 1005172d7d1Spatrick bus_dma_segment_t qdm_seg; 1015172d7d1Spatrick size_t qdm_size; 1025172d7d1Spatrick caddr_t qdm_kva; 1035172d7d1Spatrick }; 1045172d7d1Spatrick 1055172d7d1Spatrick #define QCSCM_DMA_MAP(_qdm) ((_qdm)->qdm_map) 1065172d7d1Spatrick #define QCSCM_DMA_LEN(_qdm) ((_qdm)->qdm_size) 1075172d7d1Spatrick #define QCSCM_DMA_DVA(_qdm) ((uint64_t)(_qdm)->qdm_map->dm_segs[0].ds_addr) 1085172d7d1Spatrick #define QCSCM_DMA_KVA(_qdm) ((void *)(_qdm)->qdm_kva) 1095172d7d1Spatrick 1105172d7d1Spatrick EFI_GUID qcscm_uefi_rtcinfo_guid = 1115172d7d1Spatrick { 0x882f8c2b, 0x9646, 0x435f, 1125172d7d1Spatrick { 0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd } }; 1135172d7d1Spatrick 1145172d7d1Spatrick struct qcscm_softc { 1155172d7d1Spatrick struct device sc_dev; 1165172d7d1Spatrick int sc_node; 1175172d7d1Spatrick bus_dma_tag_t sc_dmat; 1185172d7d1Spatrick 1195172d7d1Spatrick struct qcscm_dmamem *sc_extarg; 1205172d7d1Spatrick uint32_t sc_uefi_id; 1215172d7d1Spatrick }; 1225172d7d1Spatrick 1235172d7d1Spatrick int qcscm_match(struct device *, void *, void *); 1245172d7d1Spatrick void qcscm_attach(struct device *parent, struct device *self, void *args); 1255172d7d1Spatrick 1265172d7d1Spatrick const struct cfattach qcscm_ca = { 1275172d7d1Spatrick sizeof (struct qcscm_softc), qcscm_match, qcscm_attach 1285172d7d1Spatrick }; 1295172d7d1Spatrick 1305172d7d1Spatrick struct cfdriver qcscm_cd = { 1315172d7d1Spatrick NULL, "qcscm", DV_DULL 1325172d7d1Spatrick }; 1335172d7d1Spatrick 1345172d7d1Spatrick void qcscm_smc_exec(uint64_t *, uint64_t *); 1355172d7d1Spatrick int qcscm_smc_call(struct qcscm_softc *, uint8_t, uint8_t, uint8_t, 1365172d7d1Spatrick uint32_t, uint64_t *, int, uint64_t *); 1375172d7d1Spatrick int qcscm_tee_app_get_id(struct qcscm_softc *, const char *, uint32_t *); 1385172d7d1Spatrick int qcscm_tee_app_send(struct qcscm_softc *, uint32_t, uint64_t, uint64_t, 1395172d7d1Spatrick uint64_t, uint64_t); 1405172d7d1Spatrick 1415172d7d1Spatrick EFI_STATUS qcscm_uefi_get_variable(struct qcscm_softc *, CHAR16 *, 1425172d7d1Spatrick int, EFI_GUID *, uint32_t *, uint8_t *, int *); 1435172d7d1Spatrick EFI_STATUS qcscm_uefi_set_variable(struct qcscm_softc *, CHAR16 *, 1445172d7d1Spatrick int, EFI_GUID *, uint32_t, uint8_t *, int); 1455172d7d1Spatrick EFI_STATUS qcscm_uefi_get_next_variable(struct qcscm_softc *, 1465172d7d1Spatrick CHAR16 *, int *, EFI_GUID *); 1475172d7d1Spatrick 148f7910aa7Skettenis EFI_STATUS qcscm_efi_get_variable(CHAR16 *, EFI_GUID *, UINT32 *, 149f7910aa7Skettenis UINTN *, VOID *); 150f7910aa7Skettenis EFI_STATUS qcscm_efi_set_variable(CHAR16 *, EFI_GUID *, UINT32, 151f7910aa7Skettenis UINTN, VOID *); 152f7910aa7Skettenis EFI_STATUS qcscm_efi_get_next_variable_name(UINTN *, CHAR16 *, EFI_GUID *); 153f7910aa7Skettenis 1545172d7d1Spatrick #ifdef QCSCM_DEBUG 1555172d7d1Spatrick void qcscm_uefi_dump_variables(struct qcscm_softc *); 1565172d7d1Spatrick void qcscm_uefi_dump_variable(struct qcscm_softc *, CHAR16 *, int, 1575172d7d1Spatrick EFI_GUID *); 1585172d7d1Spatrick #endif 1595172d7d1Spatrick 1605172d7d1Spatrick int qcscm_uefi_rtc_get(uint32_t *); 1615172d7d1Spatrick int qcscm_uefi_rtc_set(uint32_t); 1625172d7d1Spatrick 1635172d7d1Spatrick struct qcscm_dmamem * 1645172d7d1Spatrick qcscm_dmamem_alloc(struct qcscm_softc *, bus_size_t, bus_size_t); 1655172d7d1Spatrick void qcscm_dmamem_free(struct qcscm_softc *, struct qcscm_dmamem *); 1665172d7d1Spatrick 1675172d7d1Spatrick struct qcscm_softc *qcscm_sc; 1685172d7d1Spatrick 1695172d7d1Spatrick int 1705172d7d1Spatrick qcscm_match(struct device *parent, void *match, void *aux) 1715172d7d1Spatrick { 1725172d7d1Spatrick struct fdt_attach_args *faa = aux; 1735172d7d1Spatrick 1745172d7d1Spatrick return OF_is_compatible(faa->fa_node, "qcom,scm"); 1755172d7d1Spatrick } 1765172d7d1Spatrick 1775172d7d1Spatrick void 1785172d7d1Spatrick qcscm_attach(struct device *parent, struct device *self, void *aux) 1795172d7d1Spatrick { 1805172d7d1Spatrick struct qcscm_softc *sc = (struct qcscm_softc *)self; 1815172d7d1Spatrick struct fdt_attach_args *faa = aux; 1825172d7d1Spatrick 1835172d7d1Spatrick sc->sc_node = faa->fa_node; 1845172d7d1Spatrick sc->sc_dmat = faa->fa_dmat; 1855172d7d1Spatrick 1865172d7d1Spatrick sc->sc_extarg = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 1875172d7d1Spatrick if (sc->sc_extarg == NULL) { 1885172d7d1Spatrick printf(": can't allocate memory for extended args\n"); 1895172d7d1Spatrick return; 1905172d7d1Spatrick } 1915172d7d1Spatrick 1925172d7d1Spatrick if (qcscm_tee_app_get_id(sc, "qcom.tz.uefisecapp", &sc->sc_uefi_id)) { 1935172d7d1Spatrick printf(": can't retrieve UEFI App\n"); 1945172d7d1Spatrick return; 1955172d7d1Spatrick } 1965172d7d1Spatrick 1975172d7d1Spatrick printf("\n"); 1985172d7d1Spatrick qcscm_sc = sc; 1995172d7d1Spatrick 200f7910aa7Skettenis #if NEFI > 0 201f7910aa7Skettenis efi_get_variable = qcscm_efi_get_variable; 202f7910aa7Skettenis efi_set_variable = qcscm_efi_set_variable; 203f7910aa7Skettenis efi_get_next_variable_name = qcscm_efi_get_next_variable_name; 204f7910aa7Skettenis #endif 205f7910aa7Skettenis 2065172d7d1Spatrick #ifdef QCSCM_DEBUG 2075172d7d1Spatrick qcscm_uefi_dump_variables(sc); 2085172d7d1Spatrick qcscm_uefi_dump_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 2095172d7d1Spatrick &qcscm_uefi_rtcinfo_guid); 2105172d7d1Spatrick #endif 2115172d7d1Spatrick } 2125172d7d1Spatrick 2135172d7d1Spatrick /* Expects an uint64_t[8] */ 2145172d7d1Spatrick void 2155172d7d1Spatrick qcscm_smc_exec(uint64_t *in, uint64_t *out) 2165172d7d1Spatrick { 2175172d7d1Spatrick __asm( 2184e4da9dcSpatrick "ldp x0, x1, [%0, #0]\n" 2194e4da9dcSpatrick "ldp x2, x3, [%0, #16]\n" 2204e4da9dcSpatrick "ldp x4, x5, [%0, #32]\n" 2214e4da9dcSpatrick "ldp x6, x7, [%0, #48]\n" 2220f0ca422Spatrick "ldp x8, x9, [%0, #64]\n" 2230f0ca422Spatrick "ldp x10, x11, [%0, #80]\n" 2240f0ca422Spatrick "ldp x12, x13, [%0, #96]\n" 2250f0ca422Spatrick "ldp x14, x15, [%0, #112]\n" 2260f0ca422Spatrick "ldp x16, x17, [%0, #128]\n" 2275172d7d1Spatrick "smc #0\n" 2284e4da9dcSpatrick "stp x0, x1, [%1, #0]\n" 2294e4da9dcSpatrick "stp x2, x3, [%1, #16]\n" 2304e4da9dcSpatrick "stp x4, x5, [%1, #32]\n" 2310f0ca422Spatrick "stp x6, x7, [%1, #48]\n" 2320f0ca422Spatrick "stp x8, x9, [%1, #64]\n" 2330f0ca422Spatrick "stp x10, x11, [%1, #80]\n" 2340f0ca422Spatrick "stp x12, x13, [%1, #96]\n" 2350f0ca422Spatrick "stp x14, x15, [%1, #112]\n" 2360f0ca422Spatrick "stp x16, x17, [%1, #128]\n" :: 2374e4da9dcSpatrick "r" (in), "r" (out) : 2380f0ca422Spatrick "x0", "x1", "x2", "x3", "x4", "x5", 2390f0ca422Spatrick "x6", "x7", "x8", "x9", "x10", "x11", 2400f0ca422Spatrick "x12", "x13", "x14", "x15", "x16", "x17", 2414e4da9dcSpatrick "memory"); 2425172d7d1Spatrick } 2435172d7d1Spatrick 2445172d7d1Spatrick int 2455172d7d1Spatrick qcscm_smc_call(struct qcscm_softc *sc, uint8_t owner, uint8_t svc, uint8_t cmd, 2465172d7d1Spatrick uint32_t arginfo, uint64_t *args, int arglen, uint64_t *res) 2475172d7d1Spatrick { 2480f0ca422Spatrick uint64_t smcreq[18] = { 0 }, smcres[18] = { 0 }; 2495172d7d1Spatrick uint64_t *smcextreq; 2505172d7d1Spatrick int i; 2515172d7d1Spatrick 2525172d7d1Spatrick /* 4 of our 10 possible args fit into x2-x5 */ 2535172d7d1Spatrick smcreq[0] = ARM_SMCCC_STD_CALL | ARM_SMCCC_LP64 | 2545172d7d1Spatrick owner << 24 | svc << 8 | cmd; 2555172d7d1Spatrick smcreq[1] = arginfo; 2565172d7d1Spatrick for (i = 0; i < min(arglen, 4); i++) 2575172d7d1Spatrick smcreq[2 + i] = args[i]; 2585172d7d1Spatrick 2595172d7d1Spatrick /* In case we have more than 4, use x5 as ptr to extra args */ 2605172d7d1Spatrick smcextreq = QCSCM_DMA_KVA(sc->sc_extarg); 2615172d7d1Spatrick if (arglen > 4) { 2625172d7d1Spatrick smcreq[5] = QCSCM_DMA_DVA(sc->sc_extarg); 2635172d7d1Spatrick smcextreq = QCSCM_DMA_KVA(sc->sc_extarg); 2645172d7d1Spatrick for (i = 0; i < min(arglen - 3, 7); i++) { 2655172d7d1Spatrick smcextreq[i] = args[3 + i]; 2665172d7d1Spatrick } 2675172d7d1Spatrick } 2685172d7d1Spatrick 2695172d7d1Spatrick for (;;) { 2705172d7d1Spatrick qcscm_smc_exec(smcreq, smcres); 2715172d7d1Spatrick /* If the call gets interrupted, try again and re-pass x0/x6 */ 2725172d7d1Spatrick if (smcres[0] == QCSCM_INTERRUPTED) { 2735172d7d1Spatrick smcreq[0] = smcres[0]; 2745172d7d1Spatrick smcreq[6] = smcres[6]; 2755172d7d1Spatrick continue; 2765172d7d1Spatrick } 2775172d7d1Spatrick break; 2785172d7d1Spatrick } 2795172d7d1Spatrick 2805172d7d1Spatrick if (res) { 2815172d7d1Spatrick res[0] = smcres[1]; 2825172d7d1Spatrick res[1] = smcres[2]; 2835172d7d1Spatrick res[2] = smcres[3]; 2845172d7d1Spatrick } 2855172d7d1Spatrick 2865172d7d1Spatrick return smcres[0]; 2875172d7d1Spatrick } 2885172d7d1Spatrick 2895172d7d1Spatrick /* Retrieve id of app running in TEE by name */ 2905172d7d1Spatrick int 2915172d7d1Spatrick qcscm_tee_app_get_id(struct qcscm_softc *sc, const char *name, uint32_t *id) 2925172d7d1Spatrick { 2935172d7d1Spatrick struct qcscm_dmamem *qdm; 2945172d7d1Spatrick uint64_t res[3]; 2955172d7d1Spatrick uint64_t args[2]; 2965172d7d1Spatrick uint32_t arginfo; 2975172d7d1Spatrick int ret; 2985172d7d1Spatrick 2995172d7d1Spatrick /* Max name length is 64 */ 3005172d7d1Spatrick if (strlen(name) > 64) 3015172d7d1Spatrick return EINVAL; 3025172d7d1Spatrick 3035172d7d1Spatrick /* Alloc some phys mem to hold the name */ 3045172d7d1Spatrick qdm = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 3055172d7d1Spatrick if (qdm == NULL) 3065172d7d1Spatrick return ENOMEM; 3075172d7d1Spatrick 3085172d7d1Spatrick /* Copy name of app we want to get an id for to page */ 3095172d7d1Spatrick memcpy(QCSCM_DMA_KVA(qdm), name, strlen(name)); 3105172d7d1Spatrick 3115172d7d1Spatrick /* Pass address of name and length */ 3125172d7d1Spatrick arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 3135172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_RW); 3145172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 3155172d7d1Spatrick args[0] = QCSCM_DMA_DVA(qdm); 3165172d7d1Spatrick args[1] = strlen(name); 3175172d7d1Spatrick 3185172d7d1Spatrick /* Make call into TEE */ 3195172d7d1Spatrick ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_QSEE_OS, QCTEE_TZ_SVC_APP_MGR, 3205172d7d1Spatrick 0x03, arginfo, args, nitems(args), res); 3215172d7d1Spatrick 3225172d7d1Spatrick /* If the call succeeded, check the response status */ 3235172d7d1Spatrick if (ret == 0) 3245172d7d1Spatrick ret = res[0]; 3255172d7d1Spatrick 3265172d7d1Spatrick /* If the response status is successful as well, retrieve data */ 3275172d7d1Spatrick if (ret == 0) 3285172d7d1Spatrick *id = res[2]; 3295172d7d1Spatrick 3305172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 3315172d7d1Spatrick return ret; 3325172d7d1Spatrick } 3335172d7d1Spatrick 3345172d7d1Spatrick /* Message interface to app running in TEE */ 3355172d7d1Spatrick int 3365172d7d1Spatrick qcscm_tee_app_send(struct qcscm_softc *sc, uint32_t id, uint64_t req_phys, 3375172d7d1Spatrick uint64_t req_len, uint64_t rsp_phys, uint64_t rsp_len) 3385172d7d1Spatrick { 3395172d7d1Spatrick uint64_t res[3]; 3405172d7d1Spatrick uint64_t args[5]; 3415172d7d1Spatrick uint32_t arginfo; 3425172d7d1Spatrick int ret; 3435172d7d1Spatrick 3445172d7d1Spatrick /* Pass id of app we target, plus request and response buffers */ 3455172d7d1Spatrick arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 3465172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 3475172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 3485172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 3495172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(3, QCSCM_ARGINFO_TYPE_RW); 3505172d7d1Spatrick arginfo |= QCSCM_ARGINFO_TYPE(4, QCSCM_ARGINFO_TYPE_VAL); 3515172d7d1Spatrick args[0] = id; 3525172d7d1Spatrick args[1] = req_phys; 3535172d7d1Spatrick args[2] = req_len; 3545172d7d1Spatrick args[3] = rsp_phys; 3555172d7d1Spatrick args[4] = rsp_len; 3565172d7d1Spatrick 3575172d7d1Spatrick membar_sync(); 3585172d7d1Spatrick 3595172d7d1Spatrick /* Make call into TEE */ 3605172d7d1Spatrick ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_TZ_APPS, 3615172d7d1Spatrick QCTEE_TZ_SVC_APP_ID_PLACEHOLDER, 0x01, 3625172d7d1Spatrick arginfo, args, nitems(args), res); 3635172d7d1Spatrick 3645172d7d1Spatrick membar_sync(); 3655172d7d1Spatrick 3665172d7d1Spatrick /* If the call succeeded, check the response status */ 3675172d7d1Spatrick if (ret == 0) 3685172d7d1Spatrick ret = res[0]; 3695172d7d1Spatrick 3705172d7d1Spatrick return ret; 3715172d7d1Spatrick } 3725172d7d1Spatrick 3735172d7d1Spatrick struct qcscm_req_uefi_get_variable { 3745172d7d1Spatrick uint32_t command_id; 3755172d7d1Spatrick uint32_t length; 3765172d7d1Spatrick uint32_t name_offset; 3775172d7d1Spatrick uint32_t name_size; 3785172d7d1Spatrick uint32_t guid_offset; 3795172d7d1Spatrick uint32_t guid_size; 3805172d7d1Spatrick uint32_t data_size; 3815172d7d1Spatrick }; 3825172d7d1Spatrick 3835172d7d1Spatrick struct qcscm_rsp_uefi_get_variable { 3845172d7d1Spatrick uint32_t command_id; 3855172d7d1Spatrick uint32_t length; 3865172d7d1Spatrick uint32_t status; 3875172d7d1Spatrick uint32_t attributes; 3885172d7d1Spatrick uint32_t data_offset; 3895172d7d1Spatrick uint32_t data_size; 3905172d7d1Spatrick }; 3915172d7d1Spatrick 3925172d7d1Spatrick EFI_STATUS 3935172d7d1Spatrick qcscm_uefi_get_variable(struct qcscm_softc *sc, 3945172d7d1Spatrick CHAR16 *name, int name_size, EFI_GUID *guid, 3955172d7d1Spatrick uint32_t *attributes, uint8_t *data, int *data_size) 3965172d7d1Spatrick { 3975172d7d1Spatrick struct qcscm_req_uefi_get_variable *req; 3985172d7d1Spatrick struct qcscm_rsp_uefi_get_variable *resp; 3995172d7d1Spatrick struct qcscm_dmamem *qdm; 4005172d7d1Spatrick size_t reqsize, respsize; 4015172d7d1Spatrick off_t reqoff, respoff; 4025172d7d1Spatrick int ret; 4035172d7d1Spatrick 4045172d7d1Spatrick reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)); 4055172d7d1Spatrick respsize = ALIGN(sizeof(*resp)) + ALIGN(*data_size); 4065172d7d1Spatrick 4075172d7d1Spatrick reqoff = 0; 4085172d7d1Spatrick respoff = reqsize; 4095172d7d1Spatrick 4105172d7d1Spatrick qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 4115172d7d1Spatrick if (qdm == NULL) 4125172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 4135172d7d1Spatrick 4145172d7d1Spatrick req = QCSCM_DMA_KVA(qdm) + reqoff; 4155172d7d1Spatrick req->command_id = QCTEE_UEFI_GET_VARIABLE; 4165172d7d1Spatrick req->data_size = *data_size; 4175172d7d1Spatrick req->name_offset = ALIGN(sizeof(*req)); 4185172d7d1Spatrick req->name_size = name_size; 4195172d7d1Spatrick req->guid_offset = ALIGN(req->name_offset + req->name_size); 4205172d7d1Spatrick req->guid_size = sizeof(*guid); 4215172d7d1Spatrick req->length = req->guid_offset + req->guid_size; 4225172d7d1Spatrick 4235172d7d1Spatrick memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 4245172d7d1Spatrick memcpy((char *)req + req->name_offset, name, name_size); 4255172d7d1Spatrick 4265172d7d1Spatrick ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 4275172d7d1Spatrick QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 4285172d7d1Spatrick QCSCM_DMA_DVA(qdm) + respoff, respsize); 4295172d7d1Spatrick if (ret) { 4305172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4315172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 4325172d7d1Spatrick } 4335172d7d1Spatrick 4345172d7d1Spatrick resp = QCSCM_DMA_KVA(qdm) + respoff; 4355172d7d1Spatrick if (resp->command_id != QCTEE_UEFI_GET_VARIABLE || 436f7910aa7Skettenis resp->length < sizeof(*resp)) { 4375172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4385172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 4395172d7d1Spatrick } 4405172d7d1Spatrick 4415172d7d1Spatrick if (resp->status) { 4425172d7d1Spatrick if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 4435172d7d1Spatrick *data_size = resp->data_size; 4445172d7d1Spatrick if (attributes) 4455172d7d1Spatrick *attributes = resp->attributes; 4465172d7d1Spatrick ret = resp->status; 4475172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4485172d7d1Spatrick return ret; 4495172d7d1Spatrick } 4505172d7d1Spatrick 451f7910aa7Skettenis if (resp->length > respsize || 452f7910aa7Skettenis resp->data_offset + resp->data_size > resp->length) { 4535172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4545172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 4555172d7d1Spatrick } 4565172d7d1Spatrick 4575172d7d1Spatrick if (attributes) 4585172d7d1Spatrick *attributes = resp->attributes; 4595172d7d1Spatrick 4605172d7d1Spatrick if (*data_size == 0) { 4615172d7d1Spatrick *data_size = resp->data_size; 4625172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4635172d7d1Spatrick return QCTEE_UEFI_SUCCESS; 4645172d7d1Spatrick } 4655172d7d1Spatrick 4665172d7d1Spatrick if (resp->data_size > *data_size) { 4675172d7d1Spatrick *data_size = resp->data_size; 4685172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4695172d7d1Spatrick return QCTEE_UEFI_BUFFER_TOO_SMALL; 4705172d7d1Spatrick } 4715172d7d1Spatrick 4725172d7d1Spatrick memcpy(data, (char *)resp + resp->data_offset, resp->data_size); 4735172d7d1Spatrick *data_size = resp->data_size; 4745172d7d1Spatrick 4755172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 4765172d7d1Spatrick return EFI_SUCCESS; 4775172d7d1Spatrick } 4785172d7d1Spatrick 4795172d7d1Spatrick struct qcscm_req_uefi_set_variable { 4805172d7d1Spatrick uint32_t command_id; 4815172d7d1Spatrick uint32_t length; 4825172d7d1Spatrick uint32_t name_offset; 4835172d7d1Spatrick uint32_t name_size; 4845172d7d1Spatrick uint32_t guid_offset; 4855172d7d1Spatrick uint32_t guid_size; 4865172d7d1Spatrick uint32_t attributes; 4875172d7d1Spatrick uint32_t data_offset; 4885172d7d1Spatrick uint32_t data_size; 4895172d7d1Spatrick }; 4905172d7d1Spatrick 4915172d7d1Spatrick struct qcscm_rsp_uefi_set_variable { 4925172d7d1Spatrick uint32_t command_id; 4935172d7d1Spatrick uint32_t length; 4945172d7d1Spatrick uint32_t status; 4955172d7d1Spatrick uint32_t unknown[2]; 4965172d7d1Spatrick }; 4975172d7d1Spatrick 4985172d7d1Spatrick EFI_STATUS 4995172d7d1Spatrick qcscm_uefi_set_variable(struct qcscm_softc *sc, 5005172d7d1Spatrick CHAR16 *name, int name_size, EFI_GUID *guid, 5015172d7d1Spatrick uint32_t attributes, uint8_t *data, int data_size) 5025172d7d1Spatrick { 5035172d7d1Spatrick struct qcscm_req_uefi_set_variable *req; 5045172d7d1Spatrick struct qcscm_rsp_uefi_set_variable *resp; 5055172d7d1Spatrick struct qcscm_dmamem *qdm; 5065172d7d1Spatrick size_t reqsize, respsize; 5075172d7d1Spatrick off_t reqoff, respoff; 5085172d7d1Spatrick int ret; 5095172d7d1Spatrick 5105172d7d1Spatrick reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)) + 5115172d7d1Spatrick ALIGN(data_size); 5125172d7d1Spatrick respsize = ALIGN(sizeof(*resp)); 5135172d7d1Spatrick 5145172d7d1Spatrick reqoff = 0; 5155172d7d1Spatrick respoff = reqsize; 5165172d7d1Spatrick 5175172d7d1Spatrick qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 5185172d7d1Spatrick if (qdm == NULL) 5195172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 5205172d7d1Spatrick 5215172d7d1Spatrick req = QCSCM_DMA_KVA(qdm) + reqoff; 5225172d7d1Spatrick req->command_id = QCTEE_UEFI_SET_VARIABLE; 5235172d7d1Spatrick req->attributes = attributes; 5245172d7d1Spatrick req->name_offset = ALIGN(sizeof(*req)); 5255172d7d1Spatrick req->name_size = name_size; 5265172d7d1Spatrick req->guid_offset = ALIGN(req->name_offset + req->name_size); 5275172d7d1Spatrick req->guid_size = sizeof(*guid); 5285172d7d1Spatrick req->data_offset = ALIGN(req->guid_offset + req->guid_size); 5295172d7d1Spatrick req->data_size = data_size; 5305172d7d1Spatrick req->length = req->data_offset + req->data_size; 5315172d7d1Spatrick 5325172d7d1Spatrick memcpy((char *)req + req->name_offset, name, name_size); 5335172d7d1Spatrick memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 5345172d7d1Spatrick memcpy((char *)req + req->data_offset, data, data_size); 5355172d7d1Spatrick 5365172d7d1Spatrick ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 5375172d7d1Spatrick QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 5385172d7d1Spatrick QCSCM_DMA_DVA(qdm) + respoff, respsize); 5395172d7d1Spatrick if (ret) { 5405172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 5415172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 5425172d7d1Spatrick } 5435172d7d1Spatrick 5445172d7d1Spatrick resp = QCSCM_DMA_KVA(qdm) + respoff; 5455172d7d1Spatrick if (resp->command_id != QCTEE_UEFI_SET_VARIABLE || 5465172d7d1Spatrick resp->length < sizeof(*resp) || resp->length > respsize) { 5475172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 5485172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 5495172d7d1Spatrick } 5505172d7d1Spatrick 5515172d7d1Spatrick if (resp->status) { 5525172d7d1Spatrick ret = resp->status; 5535172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 5545172d7d1Spatrick return ret; 5555172d7d1Spatrick } 5565172d7d1Spatrick 5575172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 5585172d7d1Spatrick return QCTEE_UEFI_SUCCESS; 5595172d7d1Spatrick } 5605172d7d1Spatrick 5615172d7d1Spatrick struct qcscm_req_uefi_get_next_variable { 5625172d7d1Spatrick uint32_t command_id; 5635172d7d1Spatrick uint32_t length; 5645172d7d1Spatrick uint32_t guid_offset; 5655172d7d1Spatrick uint32_t guid_size; 5665172d7d1Spatrick uint32_t name_offset; 5675172d7d1Spatrick uint32_t name_size; 5685172d7d1Spatrick }; 5695172d7d1Spatrick 5705172d7d1Spatrick struct qcscm_rsp_uefi_get_next_variable { 5715172d7d1Spatrick uint32_t command_id; 5725172d7d1Spatrick uint32_t length; 5735172d7d1Spatrick uint32_t status; 5745172d7d1Spatrick uint32_t guid_offset; 5755172d7d1Spatrick uint32_t guid_size; 5765172d7d1Spatrick uint32_t name_offset; 5775172d7d1Spatrick uint32_t name_size; 5785172d7d1Spatrick }; 5795172d7d1Spatrick 5805172d7d1Spatrick EFI_STATUS 5815172d7d1Spatrick qcscm_uefi_get_next_variable(struct qcscm_softc *sc, 5825172d7d1Spatrick CHAR16 *name, int *name_size, EFI_GUID *guid) 5835172d7d1Spatrick { 5845172d7d1Spatrick struct qcscm_req_uefi_get_next_variable *req; 5855172d7d1Spatrick struct qcscm_rsp_uefi_get_next_variable *resp; 5865172d7d1Spatrick struct qcscm_dmamem *qdm; 5875172d7d1Spatrick size_t reqsize, respsize; 5885172d7d1Spatrick off_t reqoff, respoff; 5895172d7d1Spatrick int ret; 5905172d7d1Spatrick 5915172d7d1Spatrick reqsize = ALIGN(sizeof(*req)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 5925172d7d1Spatrick respsize = ALIGN(sizeof(*resp)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 5935172d7d1Spatrick 5945172d7d1Spatrick reqoff = 0; 5955172d7d1Spatrick respoff = reqsize; 5965172d7d1Spatrick 5975172d7d1Spatrick qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 5985172d7d1Spatrick if (qdm == NULL) 5995172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 6005172d7d1Spatrick 6015172d7d1Spatrick req = QCSCM_DMA_KVA(qdm) + reqoff; 6025172d7d1Spatrick req->command_id = QCTEE_UEFI_GET_NEXT_VARIABLE; 6035172d7d1Spatrick req->guid_offset = ALIGN(sizeof(*req)); 6045172d7d1Spatrick req->guid_size = sizeof(*guid); 6055172d7d1Spatrick req->name_offset = ALIGN(req->guid_offset + req->guid_size); 6065172d7d1Spatrick req->name_size = *name_size; 6075172d7d1Spatrick req->length = req->name_offset + req->name_size; 6085172d7d1Spatrick 6095172d7d1Spatrick memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 6105172d7d1Spatrick memcpy((char *)req + req->name_offset, name, *name_size); 6115172d7d1Spatrick 6125172d7d1Spatrick ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 6135172d7d1Spatrick QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 6145172d7d1Spatrick QCSCM_DMA_DVA(qdm) + respoff, respsize); 6155172d7d1Spatrick if (ret) { 6165172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6175172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 6185172d7d1Spatrick } 6195172d7d1Spatrick 6205172d7d1Spatrick resp = QCSCM_DMA_KVA(qdm) + respoff; 6215172d7d1Spatrick if (resp->command_id != QCTEE_UEFI_GET_NEXT_VARIABLE || 6225172d7d1Spatrick resp->length < sizeof(*resp) || resp->length > respsize) { 6235172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6245172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 6255172d7d1Spatrick } 6265172d7d1Spatrick 6275172d7d1Spatrick if (resp->status) { 6285172d7d1Spatrick if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 6295172d7d1Spatrick *name_size = resp->name_size; 6305172d7d1Spatrick ret = resp->status; 6315172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6325172d7d1Spatrick return ret; 6335172d7d1Spatrick } 6345172d7d1Spatrick 6355172d7d1Spatrick if (resp->guid_offset + resp->guid_size > resp->length || 6365172d7d1Spatrick resp->name_offset + resp->name_size > resp->length) { 6375172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6385172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 6395172d7d1Spatrick } 6405172d7d1Spatrick 6415172d7d1Spatrick if (resp->guid_size != sizeof(*guid)) { 6425172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6435172d7d1Spatrick return QCTEE_UEFI_DEVICE_ERROR; 6445172d7d1Spatrick } 6455172d7d1Spatrick 6465172d7d1Spatrick if (resp->name_size > *name_size) { 6475172d7d1Spatrick *name_size = resp->name_size; 6485172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6495172d7d1Spatrick return QCTEE_UEFI_BUFFER_TOO_SMALL; 6505172d7d1Spatrick } 6515172d7d1Spatrick 6525172d7d1Spatrick memcpy(guid, (char *)resp + resp->guid_offset, sizeof(*guid)); 6535172d7d1Spatrick memcpy(name, (char *)resp + resp->name_offset, resp->name_size); 6545172d7d1Spatrick *name_size = resp->name_size; 6555172d7d1Spatrick 6565172d7d1Spatrick qcscm_dmamem_free(sc, qdm); 6575172d7d1Spatrick return QCTEE_UEFI_SUCCESS; 6585172d7d1Spatrick } 6595172d7d1Spatrick 660f7910aa7Skettenis #if NEFI > 0 661f7910aa7Skettenis 662f7910aa7Skettenis EFI_STATUS 663f7910aa7Skettenis qcscm_efi_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attributes, 664f7910aa7Skettenis UINTN *data_size, VOID *data) 665f7910aa7Skettenis { 666f7910aa7Skettenis struct qcscm_softc *sc = qcscm_sc; 667f7910aa7Skettenis EFI_STATUS status; 668f7910aa7Skettenis int name_size; 669f7910aa7Skettenis int size; 670f7910aa7Skettenis 671f7910aa7Skettenis name_size = 0; 672f7910aa7Skettenis while (name[name_size]) 673f7910aa7Skettenis name_size++; 674f7910aa7Skettenis name_size++; 675f7910aa7Skettenis 676f7910aa7Skettenis size = *data_size; 677f7910aa7Skettenis status = qcscm_uefi_get_variable(sc, name, name_size * 2, guid, 678f7910aa7Skettenis attributes, data, &size); 679f7910aa7Skettenis *data_size = size; 680f7910aa7Skettenis 681f7910aa7Skettenis /* Convert 32-bit status code to 64-bit. */ 682f7910aa7Skettenis return ((status & 0xf0000000) << 32 | (status & 0x0fffffff)); 683f7910aa7Skettenis } 684f7910aa7Skettenis 685f7910aa7Skettenis EFI_STATUS 686f7910aa7Skettenis qcscm_efi_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attributes, 687f7910aa7Skettenis UINTN data_size, VOID *data) 688f7910aa7Skettenis { 689f7910aa7Skettenis struct qcscm_softc *sc = qcscm_sc; 690f7910aa7Skettenis EFI_STATUS status; 691f7910aa7Skettenis int name_size; 692f7910aa7Skettenis 693f7910aa7Skettenis name_size = 0; 694f7910aa7Skettenis while (name[name_size]) 695f7910aa7Skettenis name_size++; 696f7910aa7Skettenis name_size++; 697f7910aa7Skettenis 698f7910aa7Skettenis status = qcscm_uefi_set_variable(sc, name, name_size * 2, guid, 699f7910aa7Skettenis attributes, data, data_size); 700f7910aa7Skettenis 701f7910aa7Skettenis /* Convert 32-bit status code to 64-bit. */ 702f7910aa7Skettenis return ((status & 0xf0000000) << 32 | (status & 0x0fffffff)); 703f7910aa7Skettenis } 704f7910aa7Skettenis 705f7910aa7Skettenis EFI_STATUS 706f7910aa7Skettenis qcscm_efi_get_next_variable_name(UINTN *name_size, CHAR16 *name, 707f7910aa7Skettenis EFI_GUID *guid) 708f7910aa7Skettenis { 709f7910aa7Skettenis struct qcscm_softc *sc = qcscm_sc; 710f7910aa7Skettenis EFI_STATUS status; 711f7910aa7Skettenis int size; 712f7910aa7Skettenis 713f7910aa7Skettenis size = *name_size; 714f7910aa7Skettenis status = qcscm_uefi_get_next_variable(sc, name, &size, guid); 715f7910aa7Skettenis *name_size = size; 716f7910aa7Skettenis 717f7910aa7Skettenis /* Convert 32-bit status code to 64-bit. */ 718f7910aa7Skettenis return ((status & 0xf0000000) << 32 | (status & 0x0fffffff)); 719f7910aa7Skettenis } 720f7910aa7Skettenis 721f7910aa7Skettenis #endif 722f7910aa7Skettenis 7235172d7d1Spatrick #ifdef QCSCM_DEBUG 724f7910aa7Skettenis 7255172d7d1Spatrick void 7265172d7d1Spatrick qcscm_uefi_dump_variables(struct qcscm_softc *sc) 7275172d7d1Spatrick { 7285172d7d1Spatrick CHAR16 name[128]; 7295172d7d1Spatrick EFI_GUID guid; 7305172d7d1Spatrick int namesize = sizeof(name); 7315172d7d1Spatrick int i, ret; 7325172d7d1Spatrick 7335172d7d1Spatrick memset(name, 0, sizeof(name)); 7345172d7d1Spatrick memset(&guid, 0, sizeof(guid)); 7355172d7d1Spatrick 7365172d7d1Spatrick for (;;) { 7375172d7d1Spatrick ret = qcscm_uefi_get_next_variable(sc, name, &namesize, &guid); 7385172d7d1Spatrick if (ret == 0) { 7395172d7d1Spatrick printf("%s: ", sc->sc_dev.dv_xname); 7405172d7d1Spatrick for (i = 0; i < namesize / 2; i++) 7415172d7d1Spatrick printf("%c", name[i]); 7425172d7d1Spatrick printf(" { 0x%08x, 0x%04x, 0x%04x, { ", 7435172d7d1Spatrick guid.Data1, guid.Data2, guid.Data3); 7445172d7d1Spatrick for (i = 0; i < 8; i++) { 7455172d7d1Spatrick printf(" 0x%02x,", guid.Data4[i]); 7465172d7d1Spatrick } 7475172d7d1Spatrick printf(" }"); 7485172d7d1Spatrick printf("\n"); 7495172d7d1Spatrick namesize = sizeof(name); 7505172d7d1Spatrick continue; 7515172d7d1Spatrick } 7525172d7d1Spatrick break; 7535172d7d1Spatrick } 7545172d7d1Spatrick } 7555172d7d1Spatrick 7565172d7d1Spatrick void 7575172d7d1Spatrick qcscm_uefi_dump_variable(struct qcscm_softc *sc, CHAR16 *name, int namesize, 7585172d7d1Spatrick EFI_GUID *guid) 7595172d7d1Spatrick { 7605172d7d1Spatrick uint8_t data[512]; 7615172d7d1Spatrick int datasize = sizeof(data); 7625172d7d1Spatrick int i, ret; 7635172d7d1Spatrick 7645172d7d1Spatrick ret = qcscm_uefi_get_variable(sc, name, namesize, guid, 7655172d7d1Spatrick NULL, data, &datasize); 7665172d7d1Spatrick if (ret != QCTEE_UEFI_SUCCESS) { 7675172d7d1Spatrick printf("%s: error reading ", sc->sc_dev.dv_xname); 7685172d7d1Spatrick for (i = 0; i < namesize / 2; i++) 7695172d7d1Spatrick printf("%c", name[i]); 7705172d7d1Spatrick printf("\n"); 7715172d7d1Spatrick return; 7725172d7d1Spatrick } 7735172d7d1Spatrick 7745172d7d1Spatrick printf("%s: ", sc->sc_dev.dv_xname); 7755172d7d1Spatrick for (i = 0; i < namesize / 2; i++) 7765172d7d1Spatrick printf("%c", name[i]); 7775172d7d1Spatrick printf(" = "); 7785172d7d1Spatrick for (i = 0; i < datasize; i++) 7795172d7d1Spatrick printf("%02x", data[i]); 7805172d7d1Spatrick printf("\n"); 7815172d7d1Spatrick } 782f7910aa7Skettenis 7835172d7d1Spatrick #endif 7845172d7d1Spatrick 7855172d7d1Spatrick int 7865172d7d1Spatrick qcscm_uefi_rtc_get(uint32_t *off) 7875172d7d1Spatrick { 7885172d7d1Spatrick struct qcscm_softc *sc = qcscm_sc; 7895172d7d1Spatrick uint32_t rtcinfo[3]; 7905172d7d1Spatrick int rtcinfosize = sizeof(rtcinfo); 7915172d7d1Spatrick 7925172d7d1Spatrick if (sc == NULL) 7935172d7d1Spatrick return ENXIO; 7945172d7d1Spatrick 7955172d7d1Spatrick if (qcscm_uefi_get_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 7965172d7d1Spatrick &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 7975172d7d1Spatrick &rtcinfosize) != 0) 7985172d7d1Spatrick return EIO; 7995172d7d1Spatrick 80041e484b3Spatrick /* UEFI stores the offset based on GPS epoch */ 80141e484b3Spatrick *off = rtcinfo[0] + UNIX_GPS_EPOCH_OFFSET; 8025172d7d1Spatrick return 0; 8035172d7d1Spatrick } 8045172d7d1Spatrick 8055172d7d1Spatrick int 8065172d7d1Spatrick qcscm_uefi_rtc_set(uint32_t off) 8075172d7d1Spatrick { 8085172d7d1Spatrick struct qcscm_softc *sc = qcscm_sc; 8095172d7d1Spatrick uint32_t rtcinfo[3]; 8105172d7d1Spatrick int rtcinfosize = sizeof(rtcinfo); 8115172d7d1Spatrick 8125172d7d1Spatrick if (sc == NULL) 8135172d7d1Spatrick return ENXIO; 8145172d7d1Spatrick 8155172d7d1Spatrick if (qcscm_uefi_get_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 8165172d7d1Spatrick &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 8175172d7d1Spatrick &rtcinfosize) != 0) 8185172d7d1Spatrick return EIO; 8195172d7d1Spatrick 82041e484b3Spatrick /* UEFI stores the offset based on GPS epoch */ 82141e484b3Spatrick off -= UNIX_GPS_EPOCH_OFFSET; 82241e484b3Spatrick 8235172d7d1Spatrick /* No need to set if we're not changing anything */ 8245172d7d1Spatrick if (rtcinfo[0] == off) 8255172d7d1Spatrick return 0; 8265172d7d1Spatrick 8275172d7d1Spatrick rtcinfo[0] = off; 8285172d7d1Spatrick 8295172d7d1Spatrick if (qcscm_uefi_set_variable(sc, u"RTCInfo", sizeof(u"RTCInfo"), 8305172d7d1Spatrick &qcscm_uefi_rtcinfo_guid, EFI_VARIABLE_NON_VOLATILE | 8315172d7d1Spatrick EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 8325172d7d1Spatrick (uint8_t *)rtcinfo, sizeof(rtcinfo)) != 0) 8335172d7d1Spatrick return EIO; 8345172d7d1Spatrick 8355172d7d1Spatrick return 0; 8365172d7d1Spatrick } 8375172d7d1Spatrick 8384b4ba7b0Spatrick int 8394b4ba7b0Spatrick qcscm_pas_init_image(uint32_t peripheral, paddr_t metadata) 8404b4ba7b0Spatrick { 8414b4ba7b0Spatrick struct qcscm_softc *sc = qcscm_sc; 8424b4ba7b0Spatrick uint64_t res[3]; 8434b4ba7b0Spatrick uint64_t args[2]; 8444b4ba7b0Spatrick uint32_t arginfo; 8454b4ba7b0Spatrick int ret; 8464b4ba7b0Spatrick 8474b4ba7b0Spatrick if (sc == NULL) 8484b4ba7b0Spatrick return ENXIO; 8494b4ba7b0Spatrick 8504b4ba7b0Spatrick arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 8514b4ba7b0Spatrick arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 8524b4ba7b0Spatrick arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 8534b4ba7b0Spatrick args[0] = peripheral; 8544b4ba7b0Spatrick args[1] = metadata; 8554b4ba7b0Spatrick 8564b4ba7b0Spatrick /* Make call into TEE */ 8574b4ba7b0Spatrick ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 8584b4ba7b0Spatrick QCSCM_PIL_PAS_INIT_IMAGE, arginfo, args, nitems(args), res); 8594b4ba7b0Spatrick 8604b4ba7b0Spatrick /* If the call succeeded, check the response status */ 8614b4ba7b0Spatrick if (ret == 0) 8624b4ba7b0Spatrick ret = res[0]; 8634b4ba7b0Spatrick 8644b4ba7b0Spatrick return ret; 8654b4ba7b0Spatrick } 8664b4ba7b0Spatrick 8674b4ba7b0Spatrick int 8684b4ba7b0Spatrick qcscm_pas_mem_setup(uint32_t peripheral, paddr_t addr, size_t size) 8694b4ba7b0Spatrick { 8704b4ba7b0Spatrick struct qcscm_softc *sc = qcscm_sc; 8714b4ba7b0Spatrick uint64_t res[3]; 8724b4ba7b0Spatrick uint64_t args[3]; 8734b4ba7b0Spatrick uint32_t arginfo; 8744b4ba7b0Spatrick int ret; 8754b4ba7b0Spatrick 8764b4ba7b0Spatrick if (sc == NULL) 8774b4ba7b0Spatrick return ENXIO; 8784b4ba7b0Spatrick 8794b4ba7b0Spatrick arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 8804b4ba7b0Spatrick arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 8814b4ba7b0Spatrick arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 8824b4ba7b0Spatrick arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 8834b4ba7b0Spatrick args[0] = peripheral; 8844b4ba7b0Spatrick args[1] = addr; 8854b4ba7b0Spatrick args[2] = size; 8864b4ba7b0Spatrick 8874b4ba7b0Spatrick /* Make call into TEE */ 8884b4ba7b0Spatrick ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 8894b4ba7b0Spatrick QCSCM_PIL_PAS_MEM_SETUP, arginfo, args, nitems(args), res); 8904b4ba7b0Spatrick 8914b4ba7b0Spatrick /* If the call succeeded, check the response status */ 8924b4ba7b0Spatrick if (ret == 0) 8934b4ba7b0Spatrick ret = res[0]; 8944b4ba7b0Spatrick 8954b4ba7b0Spatrick return ret; 8964b4ba7b0Spatrick } 8974b4ba7b0Spatrick 8984b4ba7b0Spatrick int 8994b4ba7b0Spatrick qcscm_pas_auth_and_reset(uint32_t peripheral) 9004b4ba7b0Spatrick { 9014b4ba7b0Spatrick struct qcscm_softc *sc = qcscm_sc; 9024b4ba7b0Spatrick uint64_t res[3]; 9034b4ba7b0Spatrick uint64_t args[1]; 9044b4ba7b0Spatrick uint32_t arginfo; 9054b4ba7b0Spatrick int ret; 9064b4ba7b0Spatrick 9074b4ba7b0Spatrick if (sc == NULL) 9084b4ba7b0Spatrick return ENXIO; 9094b4ba7b0Spatrick 9104b4ba7b0Spatrick arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 9114b4ba7b0Spatrick arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 9124b4ba7b0Spatrick args[0] = peripheral; 9134b4ba7b0Spatrick 9144b4ba7b0Spatrick /* Make call into TEE */ 9154b4ba7b0Spatrick ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 9164b4ba7b0Spatrick QCSCM_PIL_PAS_AUTH_AND_RESET, arginfo, args, nitems(args), res); 9174b4ba7b0Spatrick 9184b4ba7b0Spatrick /* If the call succeeded, check the response status */ 9194b4ba7b0Spatrick if (ret == 0) 9204b4ba7b0Spatrick ret = res[0]; 9214b4ba7b0Spatrick 9224b4ba7b0Spatrick return ret; 9234b4ba7b0Spatrick } 9244b4ba7b0Spatrick 925*5dbfd905Skettenis int 926*5dbfd905Skettenis qcscm_pas_shutdown(uint32_t peripheral) 927*5dbfd905Skettenis { 928*5dbfd905Skettenis struct qcscm_softc *sc = qcscm_sc; 929*5dbfd905Skettenis uint64_t res[3]; 930*5dbfd905Skettenis uint64_t args[1]; 931*5dbfd905Skettenis uint32_t arginfo; 932*5dbfd905Skettenis int ret; 933*5dbfd905Skettenis 934*5dbfd905Skettenis if (sc == NULL) 935*5dbfd905Skettenis return ENXIO; 936*5dbfd905Skettenis 937*5dbfd905Skettenis arginfo = QCSCM_ARGINFO_NUM(nitems(args)); 938*5dbfd905Skettenis arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 939*5dbfd905Skettenis args[0] = peripheral; 940*5dbfd905Skettenis 941*5dbfd905Skettenis /* Make call into TEE */ 942*5dbfd905Skettenis ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 943*5dbfd905Skettenis QCSCM_PIL_PAS_SHUTDOWN, arginfo, args, nitems(args), res); 944*5dbfd905Skettenis 945*5dbfd905Skettenis /* If the call succeeded, check the response status */ 946*5dbfd905Skettenis if (ret == 0) 947*5dbfd905Skettenis ret = res[0]; 948*5dbfd905Skettenis 949*5dbfd905Skettenis return ret; 950*5dbfd905Skettenis } 951*5dbfd905Skettenis 9525172d7d1Spatrick /* DMA code */ 9535172d7d1Spatrick struct qcscm_dmamem * 9545172d7d1Spatrick qcscm_dmamem_alloc(struct qcscm_softc *sc, bus_size_t size, bus_size_t align) 9555172d7d1Spatrick { 9565172d7d1Spatrick struct qcscm_dmamem *qdm; 9575172d7d1Spatrick int nsegs; 9585172d7d1Spatrick 9595172d7d1Spatrick qdm = malloc(sizeof(*qdm), M_DEVBUF, M_WAITOK | M_ZERO); 9605172d7d1Spatrick qdm->qdm_size = size; 9615172d7d1Spatrick 9625172d7d1Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 9635172d7d1Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &qdm->qdm_map) != 0) 9645172d7d1Spatrick goto qdmfree; 9655172d7d1Spatrick 9668b8fb239Skettenis if (bus_dmamem_alloc_range(sc->sc_dmat, size, align, 0, 9678b8fb239Skettenis &qdm->qdm_seg, 1, &nsegs, BUS_DMA_WAITOK, 0, 0xffffffff) != 0) 9685172d7d1Spatrick goto destroy; 9695172d7d1Spatrick 9705172d7d1Spatrick if (bus_dmamem_map(sc->sc_dmat, &qdm->qdm_seg, nsegs, size, 9715172d7d1Spatrick &qdm->qdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 9725172d7d1Spatrick goto free; 9735172d7d1Spatrick 9745172d7d1Spatrick if (bus_dmamap_load(sc->sc_dmat, qdm->qdm_map, qdm->qdm_kva, size, 9755172d7d1Spatrick NULL, BUS_DMA_WAITOK) != 0) 9765172d7d1Spatrick goto unmap; 9775172d7d1Spatrick 9785172d7d1Spatrick bzero(qdm->qdm_kva, size); 9795172d7d1Spatrick 9805172d7d1Spatrick return (qdm); 9815172d7d1Spatrick 9825172d7d1Spatrick unmap: 9835172d7d1Spatrick bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, size); 9845172d7d1Spatrick free: 9855172d7d1Spatrick bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 9865172d7d1Spatrick destroy: 9875172d7d1Spatrick bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 9885172d7d1Spatrick qdmfree: 9895172d7d1Spatrick free(qdm, M_DEVBUF, sizeof(*qdm)); 9905172d7d1Spatrick 9915172d7d1Spatrick return (NULL); 9925172d7d1Spatrick } 9935172d7d1Spatrick 9945172d7d1Spatrick void 9955172d7d1Spatrick qcscm_dmamem_free(struct qcscm_softc *sc, struct qcscm_dmamem *qdm) 9965172d7d1Spatrick { 9975172d7d1Spatrick bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, qdm->qdm_size); 9985172d7d1Spatrick bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 9995172d7d1Spatrick bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 10005172d7d1Spatrick free(qdm, M_DEVBUF, sizeof(*qdm)); 10015172d7d1Spatrick } 1002