1*c95a3ae2Sjmcneill /* $NetBSD: qcomscm.c,v 1.1 2024/12/30 12:31:10 jmcneill Exp $ */ 2*c95a3ae2Sjmcneill /* $OpenBSD: qcscm.c,v 1.9 2024/08/04 15:30:08 kettenis Exp $ */ 3*c95a3ae2Sjmcneill /* 4*c95a3ae2Sjmcneill * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se> 5*c95a3ae2Sjmcneill * 6*c95a3ae2Sjmcneill * Permission to use, copy, modify, and distribute this software for any 7*c95a3ae2Sjmcneill * purpose with or without fee is hereby granted, provided that the above 8*c95a3ae2Sjmcneill * copyright notice and this permission notice appear in all copies. 9*c95a3ae2Sjmcneill * 10*c95a3ae2Sjmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*c95a3ae2Sjmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*c95a3ae2Sjmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*c95a3ae2Sjmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*c95a3ae2Sjmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*c95a3ae2Sjmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*c95a3ae2Sjmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*c95a3ae2Sjmcneill */ 18*c95a3ae2Sjmcneill 19*c95a3ae2Sjmcneill #include <sys/param.h> 20*c95a3ae2Sjmcneill #include <sys/systm.h> 21*c95a3ae2Sjmcneill #include <sys/device.h> 22*c95a3ae2Sjmcneill #include <sys/kmem.h> 23*c95a3ae2Sjmcneill #include <sys/bus.h> 24*c95a3ae2Sjmcneill #include <sys/uuid.h> 25*c95a3ae2Sjmcneill 26*c95a3ae2Sjmcneill #include <dev/efi/efi.h> 27*c95a3ae2Sjmcneill #include <dev/acpi/acpivar.h> 28*c95a3ae2Sjmcneill #include <dev/acpi/qcomscm.h> 29*c95a3ae2Sjmcneill 30*c95a3ae2Sjmcneill #define ARM_SMCCC_STD_CALL (0U << 31) 31*c95a3ae2Sjmcneill #define ARM_SMCCC_FAST_CALL (1U << 31) 32*c95a3ae2Sjmcneill #define ARM_SMCCC_LP64 (1U << 30) 33*c95a3ae2Sjmcneill #define ARM_SMCCC_OWNER_SIP 2 34*c95a3ae2Sjmcneill 35*c95a3ae2Sjmcneill #define QCTEE_TZ_OWNER_TZ_APPS 48 36*c95a3ae2Sjmcneill #define QCTEE_TZ_OWNER_QSEE_OS 50 37*c95a3ae2Sjmcneill 38*c95a3ae2Sjmcneill #define QCTEE_TZ_SVC_APP_ID_PLACEHOLDER 0 39*c95a3ae2Sjmcneill #define QCTEE_TZ_SVC_APP_MGR 1 40*c95a3ae2Sjmcneill 41*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_SUCCESS 0 42*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_INCOMPLETE 1 43*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_BLOCKED_ON_LISTENER 2 44*c95a3ae2Sjmcneill #define QCTEE_OS_RESULT_FAILURE 0xffffffff 45*c95a3ae2Sjmcneill 46*c95a3ae2Sjmcneill #define QCTEE_OS_SCM_RES_APP_ID 0xee01 47*c95a3ae2Sjmcneill #define QCTEE_OS_SCM_RES_QSEOS_LISTENER_ID 0xee02 48*c95a3ae2Sjmcneill 49*c95a3ae2Sjmcneill #define QCTEE_UEFI_GET_VARIABLE 0x8000 50*c95a3ae2Sjmcneill #define QCTEE_UEFI_SET_VARIABLE 0x8001 51*c95a3ae2Sjmcneill #define QCTEE_UEFI_GET_NEXT_VARIABLE 0x8002 52*c95a3ae2Sjmcneill #define QCTEE_UEFI_QUERY_VARIABLE_INFO 0x8003 53*c95a3ae2Sjmcneill 54*c95a3ae2Sjmcneill #define QCTEE_UEFI_SUCCESS 0 55*c95a3ae2Sjmcneill #define QCTEE_UEFI_BUFFER_TOO_SMALL 0x80000005 56*c95a3ae2Sjmcneill #define QCTEE_UEFI_DEVICE_ERROR 0x80000007 57*c95a3ae2Sjmcneill #define QCTEE_UEFI_NOT_FOUND 0x8000000e 58*c95a3ae2Sjmcneill 59*c95a3ae2Sjmcneill #define QCSCM_SVC_PIL 0x02 60*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_INIT_IMAGE 0x01 61*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_MEM_SETUP 0x02 62*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_AUTH_AND_RESET 0x05 63*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_SHUTDOWN 0x06 64*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_IS_SUPPORTED 0x07 65*c95a3ae2Sjmcneill #define QCSCM_PIL_PAS_MSS_RESET 0x0a 66*c95a3ae2Sjmcneill 67*c95a3ae2Sjmcneill #define QCSCM_INTERRUPTED 1 68*c95a3ae2Sjmcneill #define QCSCM_EBUSY -22 69*c95a3ae2Sjmcneill 70*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_NUM(x) (((x) & 0xf) << 0) 71*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE(x, y) (((y) & 0x3) << (4 + 2 * (x))) 72*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_VAL 0 73*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_RO 1 74*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_RW 2 75*c95a3ae2Sjmcneill #define QCSCM_ARGINFO_TYPE_BUFVAL 3 76*c95a3ae2Sjmcneill 77*c95a3ae2Sjmcneill #define EFI_VARIABLE_NON_VOLATILE 0x00000001 78*c95a3ae2Sjmcneill #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 79*c95a3ae2Sjmcneill #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 80*c95a3ae2Sjmcneill 81*c95a3ae2Sjmcneill #define UNIX_GPS_EPOCH_OFFSET 315964800 82*c95a3ae2Sjmcneill 83*c95a3ae2Sjmcneill #define EFI_VAR_RTCINFO __UNCONST(u"RTCInfo") 84*c95a3ae2Sjmcneill 85*c95a3ae2Sjmcneill extern struct arm32_bus_dma_tag arm_generic_dma_tag; 86*c95a3ae2Sjmcneill 87*c95a3ae2Sjmcneill struct qcscm_dmamem { 88*c95a3ae2Sjmcneill bus_dmamap_t qdm_map; 89*c95a3ae2Sjmcneill bus_dma_segment_t qdm_seg; 90*c95a3ae2Sjmcneill size_t qdm_size; 91*c95a3ae2Sjmcneill void *qdm_kva; 92*c95a3ae2Sjmcneill }; 93*c95a3ae2Sjmcneill 94*c95a3ae2Sjmcneill #define QCSCM_DMA_MAP(_qdm) ((_qdm)->qdm_map) 95*c95a3ae2Sjmcneill #define QCSCM_DMA_LEN(_qdm) ((_qdm)->qdm_size) 96*c95a3ae2Sjmcneill #define QCSCM_DMA_DVA(_qdm) ((uint64_t)(_qdm)->qdm_map->dm_segs[0].ds_addr) 97*c95a3ae2Sjmcneill #define QCSCM_DMA_KVA(_qdm, off) ((void *)((uintptr_t)(_qdm)->qdm_kva + (off))) 98*c95a3ae2Sjmcneill 99*c95a3ae2Sjmcneill static struct uuid qcscm_uefi_rtcinfo_guid = 100*c95a3ae2Sjmcneill { 0x882f8c2b, 0x9646, 0x435f, 101*c95a3ae2Sjmcneill 0x8d, 0xe5, { 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd } }; 102*c95a3ae2Sjmcneill 103*c95a3ae2Sjmcneill struct qcscm_softc { 104*c95a3ae2Sjmcneill device_t sc_dev; 105*c95a3ae2Sjmcneill bus_dma_tag_t sc_dmat; 106*c95a3ae2Sjmcneill 107*c95a3ae2Sjmcneill struct qcscm_dmamem *sc_extarg; 108*c95a3ae2Sjmcneill uint32_t sc_uefi_id; 109*c95a3ae2Sjmcneill }; 110*c95a3ae2Sjmcneill 111*c95a3ae2Sjmcneill static int qcscm_match(device_t, cfdata_t, void *); 112*c95a3ae2Sjmcneill static void qcscm_attach(device_t, device_t, void *); 113*c95a3ae2Sjmcneill 114*c95a3ae2Sjmcneill CFATTACH_DECL_NEW(qcomscm, sizeof(struct qcscm_softc), 115*c95a3ae2Sjmcneill qcscm_match, qcscm_attach, NULL, NULL); 116*c95a3ae2Sjmcneill 117*c95a3ae2Sjmcneill static inline void qcscm_smc_exec(uint64_t *, uint64_t *); 118*c95a3ae2Sjmcneill int qcscm_smc_call(struct qcscm_softc *, uint8_t, uint8_t, uint8_t, 119*c95a3ae2Sjmcneill uint32_t, uint64_t *, int, uint64_t *); 120*c95a3ae2Sjmcneill int qcscm_tee_app_get_id(struct qcscm_softc *, const char *, uint32_t *); 121*c95a3ae2Sjmcneill int qcscm_tee_app_send(struct qcscm_softc *, uint32_t, uint64_t, uint64_t, 122*c95a3ae2Sjmcneill uint64_t, uint64_t); 123*c95a3ae2Sjmcneill 124*c95a3ae2Sjmcneill efi_status qcscm_uefi_get_variable(struct qcscm_softc *, efi_char *, 125*c95a3ae2Sjmcneill int, struct uuid *, uint32_t *, uint8_t *, int *); 126*c95a3ae2Sjmcneill efi_status qcscm_uefi_set_variable(struct qcscm_softc *, efi_char *, 127*c95a3ae2Sjmcneill int, struct uuid *, uint32_t, uint8_t *, int); 128*c95a3ae2Sjmcneill efi_status qcscm_uefi_get_next_variable(struct qcscm_softc *, 129*c95a3ae2Sjmcneill efi_char *, int *, struct uuid *); 130*c95a3ae2Sjmcneill 131*c95a3ae2Sjmcneill efi_status qcscm_efi_get_variable(efi_char *, struct uuid *, uint32_t *, 132*c95a3ae2Sjmcneill u_long *, void *); 133*c95a3ae2Sjmcneill efi_status qcscm_efi_set_variable(efi_char *, struct uuid *, uint32_t, 134*c95a3ae2Sjmcneill u_long, void *); 135*c95a3ae2Sjmcneill efi_status qcscm_efi_get_next_variable_name(u_long *, efi_char *, struct uuid *); 136*c95a3ae2Sjmcneill 137*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG 138*c95a3ae2Sjmcneill void qcscm_uefi_dump_variables(struct qcscm_softc *); 139*c95a3ae2Sjmcneill void qcscm_uefi_dump_variable(struct qcscm_softc *, efi_char *, int, 140*c95a3ae2Sjmcneill struct uuid *); 141*c95a3ae2Sjmcneill #endif 142*c95a3ae2Sjmcneill 143*c95a3ae2Sjmcneill int qcscm_uefi_rtc_get(uint32_t *); 144*c95a3ae2Sjmcneill int qcscm_uefi_rtc_set(uint32_t); 145*c95a3ae2Sjmcneill 146*c95a3ae2Sjmcneill struct qcscm_dmamem * 147*c95a3ae2Sjmcneill qcscm_dmamem_alloc(struct qcscm_softc *, bus_size_t, bus_size_t); 148*c95a3ae2Sjmcneill void qcscm_dmamem_free(struct qcscm_softc *, struct qcscm_dmamem *); 149*c95a3ae2Sjmcneill 150*c95a3ae2Sjmcneill struct qcscm_softc *qcscm_sc; 151*c95a3ae2Sjmcneill 152*c95a3ae2Sjmcneill static const struct device_compatible_entry compat_data[] = { 153*c95a3ae2Sjmcneill { .compat = "QCOM04DD" }, 154*c95a3ae2Sjmcneill DEVICE_COMPAT_EOL 155*c95a3ae2Sjmcneill }; 156*c95a3ae2Sjmcneill 157*c95a3ae2Sjmcneill static int 158*c95a3ae2Sjmcneill qcscm_match(device_t parent, cfdata_t cf, void *aux) 159*c95a3ae2Sjmcneill { 160*c95a3ae2Sjmcneill struct acpi_attach_args *aa = aux; 161*c95a3ae2Sjmcneill 162*c95a3ae2Sjmcneill return acpi_compatible_match(aa, compat_data); 163*c95a3ae2Sjmcneill } 164*c95a3ae2Sjmcneill 165*c95a3ae2Sjmcneill static void 166*c95a3ae2Sjmcneill qcscm_attach(device_t parent, device_t self, void *aux) 167*c95a3ae2Sjmcneill { 168*c95a3ae2Sjmcneill struct qcscm_softc *sc = device_private(self); 169*c95a3ae2Sjmcneill int error; 170*c95a3ae2Sjmcneill 171*c95a3ae2Sjmcneill sc->sc_dev = self; 172*c95a3ae2Sjmcneill error = bus_dmatag_subregion(&arm_generic_dma_tag, 173*c95a3ae2Sjmcneill 0, __MASK(32), &sc->sc_dmat, 0); 174*c95a3ae2Sjmcneill KASSERT(error == 0); 175*c95a3ae2Sjmcneill 176*c95a3ae2Sjmcneill sc->sc_extarg = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 177*c95a3ae2Sjmcneill if (sc->sc_extarg == NULL) { 178*c95a3ae2Sjmcneill aprint_error(": can't allocate memory for extended args\n"); 179*c95a3ae2Sjmcneill return; 180*c95a3ae2Sjmcneill } 181*c95a3ae2Sjmcneill 182*c95a3ae2Sjmcneill aprint_naive("\n"); 183*c95a3ae2Sjmcneill aprint_normal("\n"); 184*c95a3ae2Sjmcneill 185*c95a3ae2Sjmcneill #if notyet 186*c95a3ae2Sjmcneill error = qcscm_tee_app_get_id(sc, "qcom.tz.uefisecapp", &sc->sc_uefi_id); 187*c95a3ae2Sjmcneill if (error != 0) { 188*c95a3ae2Sjmcneill aprint_error_dev(self, "can't retrieve UEFI App: %d\n", error); 189*c95a3ae2Sjmcneill sc->sc_uefi_id = UINT32_MAX; 190*c95a3ae2Sjmcneill } 191*c95a3ae2Sjmcneill #else 192*c95a3ae2Sjmcneill sc->sc_uefi_id = UINT32_MAX; 193*c95a3ae2Sjmcneill #endif 194*c95a3ae2Sjmcneill 195*c95a3ae2Sjmcneill qcscm_sc = sc; 196*c95a3ae2Sjmcneill 197*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG 198*c95a3ae2Sjmcneill qcscm_uefi_dump_variables(sc); 199*c95a3ae2Sjmcneill qcscm_uefi_dump_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO), 200*c95a3ae2Sjmcneill &qcscm_uefi_rtcinfo_guid); 201*c95a3ae2Sjmcneill #endif 202*c95a3ae2Sjmcneill } 203*c95a3ae2Sjmcneill 204*c95a3ae2Sjmcneill /* Expects an uint64_t[18] */ 205*c95a3ae2Sjmcneill static inline void 206*c95a3ae2Sjmcneill qcscm_smc_exec(uint64_t *in, uint64_t *out) 207*c95a3ae2Sjmcneill { 208*c95a3ae2Sjmcneill asm volatile( 209*c95a3ae2Sjmcneill "ldp x0, x1, [%[in], #0]\n" 210*c95a3ae2Sjmcneill "ldp x2, x3, [%[in], #16]\n" 211*c95a3ae2Sjmcneill "ldp x4, x5, [%[in], #32]\n" 212*c95a3ae2Sjmcneill "ldp x6, x7, [%[in], #48]\n" 213*c95a3ae2Sjmcneill "ldp x8, x9, [%[in], #64]\n" 214*c95a3ae2Sjmcneill "ldp x10, x11, [%[in], #80]\n" 215*c95a3ae2Sjmcneill "ldp x12, x13, [%[in], #96]\n" 216*c95a3ae2Sjmcneill "ldp x14, x15, [%[in], #112]\n" 217*c95a3ae2Sjmcneill "ldp x16, x17, [%[in], #128]\n" 218*c95a3ae2Sjmcneill "smc #0\n" 219*c95a3ae2Sjmcneill "stp x0, x1, [%[out], #0]\n" 220*c95a3ae2Sjmcneill "stp x2, x3, [%[out], #16]\n" 221*c95a3ae2Sjmcneill "stp x4, x5, [%[out], #32]\n" 222*c95a3ae2Sjmcneill "stp x6, x7, [%[out], #48]\n" 223*c95a3ae2Sjmcneill "stp x8, x9, [%[out], #64]\n" 224*c95a3ae2Sjmcneill "stp x10, x11, [%[out], #80]\n" 225*c95a3ae2Sjmcneill "stp x12, x13, [%[out], #96]\n" 226*c95a3ae2Sjmcneill "stp x14, x15, [%[out], #112]\n" 227*c95a3ae2Sjmcneill "stp x16, x17, [%[out], #128]\n" 228*c95a3ae2Sjmcneill : 229*c95a3ae2Sjmcneill : [in] "r" (in), [out] "r" (out) 230*c95a3ae2Sjmcneill : "x0", "x1", "x2", "x3", "x4", "x5", 231*c95a3ae2Sjmcneill "x6", "x7", "x8", "x9", "x10", "x11", 232*c95a3ae2Sjmcneill "x12", "x13", "x14", "x15", "x16", "x17", 233*c95a3ae2Sjmcneill "memory"); 234*c95a3ae2Sjmcneill } 235*c95a3ae2Sjmcneill 236*c95a3ae2Sjmcneill int 237*c95a3ae2Sjmcneill qcscm_smc_call(struct qcscm_softc *sc, uint8_t owner, uint8_t svc, uint8_t cmd, 238*c95a3ae2Sjmcneill uint32_t arginfo, uint64_t *args, int arglen, uint64_t *res) 239*c95a3ae2Sjmcneill { 240*c95a3ae2Sjmcneill uint64_t smcreq[18] = { 0 }, smcres[18] = { 0 }; 241*c95a3ae2Sjmcneill uint64_t *smcextreq; 242*c95a3ae2Sjmcneill int i, busy_retry; 243*c95a3ae2Sjmcneill 244*c95a3ae2Sjmcneill /* 4 of our 10 possible args fit into x2-x5 */ 245*c95a3ae2Sjmcneill smcreq[0] = ARM_SMCCC_STD_CALL | ARM_SMCCC_LP64 | 246*c95a3ae2Sjmcneill owner << 24 | svc << 8 | cmd; 247*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG_SMC 248*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "owner %#x svc %#x cmd %#x req %#lx\n", 249*c95a3ae2Sjmcneill owner, svc, cmd, smcreq[0]); 250*c95a3ae2Sjmcneill #endif 251*c95a3ae2Sjmcneill smcreq[1] = arginfo; 252*c95a3ae2Sjmcneill for (i = 0; i < uimin(arglen, 4); i++) 253*c95a3ae2Sjmcneill smcreq[2 + i] = args[i]; 254*c95a3ae2Sjmcneill 255*c95a3ae2Sjmcneill /* In case we have more than 4, use x5 as ptr to extra args */ 256*c95a3ae2Sjmcneill if (arglen > 4) { 257*c95a3ae2Sjmcneill smcreq[5] = QCSCM_DMA_DVA(sc->sc_extarg); 258*c95a3ae2Sjmcneill smcextreq = QCSCM_DMA_KVA(sc->sc_extarg, 0); 259*c95a3ae2Sjmcneill for (i = 0; i < uimin(arglen - 3, 7); i++) { 260*c95a3ae2Sjmcneill smcextreq[i] = args[3 + i]; 261*c95a3ae2Sjmcneill } 262*c95a3ae2Sjmcneill cpu_drain_writebuf(); 263*c95a3ae2Sjmcneill } 264*c95a3ae2Sjmcneill 265*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG_SMC 266*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "smcreq[before]:"); 267*c95a3ae2Sjmcneill for (i = 0; i < __arraycount(smcreq); i++) { 268*c95a3ae2Sjmcneill printf(" %#lx", smcreq[i]); 269*c95a3ae2Sjmcneill } 270*c95a3ae2Sjmcneill printf("\n"); 271*c95a3ae2Sjmcneill #endif 272*c95a3ae2Sjmcneill for (busy_retry = 20; busy_retry > 0; busy_retry--) { 273*c95a3ae2Sjmcneill int intr_retry = 1000000; 274*c95a3ae2Sjmcneill for (;;) { 275*c95a3ae2Sjmcneill qcscm_smc_exec(smcreq, smcres); 276*c95a3ae2Sjmcneill /* If the call gets interrupted, try again and re-pass x0/x6 */ 277*c95a3ae2Sjmcneill if (smcres[0] == QCSCM_INTERRUPTED) { 278*c95a3ae2Sjmcneill if (--intr_retry == 0) { 279*c95a3ae2Sjmcneill break; 280*c95a3ae2Sjmcneill } 281*c95a3ae2Sjmcneill smcreq[0] = smcres[0]; 282*c95a3ae2Sjmcneill smcreq[6] = smcres[6]; 283*c95a3ae2Sjmcneill continue; 284*c95a3ae2Sjmcneill } 285*c95a3ae2Sjmcneill break; 286*c95a3ae2Sjmcneill } 287*c95a3ae2Sjmcneill 288*c95a3ae2Sjmcneill if (smcres[0] != QCSCM_EBUSY) { 289*c95a3ae2Sjmcneill break; 290*c95a3ae2Sjmcneill } 291*c95a3ae2Sjmcneill delay(30000); 292*c95a3ae2Sjmcneill } 293*c95a3ae2Sjmcneill 294*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG_SMC 295*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "smcreq[after]:"); 296*c95a3ae2Sjmcneill for (i = 0; i < __arraycount(smcreq); i++) { 297*c95a3ae2Sjmcneill printf(" %#lx", smcreq[i]); 298*c95a3ae2Sjmcneill } 299*c95a3ae2Sjmcneill printf("\n"); 300*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "smcres[after]:"); 301*c95a3ae2Sjmcneill for (i = 0; i < __arraycount(smcres); i++) { 302*c95a3ae2Sjmcneill printf(" %#lx", smcres[i]); 303*c95a3ae2Sjmcneill } 304*c95a3ae2Sjmcneill printf("\n"); 305*c95a3ae2Sjmcneill #endif 306*c95a3ae2Sjmcneill 307*c95a3ae2Sjmcneill if (res) { 308*c95a3ae2Sjmcneill res[0] = smcres[1]; 309*c95a3ae2Sjmcneill res[1] = smcres[2]; 310*c95a3ae2Sjmcneill res[2] = smcres[3]; 311*c95a3ae2Sjmcneill } 312*c95a3ae2Sjmcneill 313*c95a3ae2Sjmcneill return smcres[0]; 314*c95a3ae2Sjmcneill } 315*c95a3ae2Sjmcneill 316*c95a3ae2Sjmcneill /* Retrieve id of app running in TEE by name */ 317*c95a3ae2Sjmcneill int 318*c95a3ae2Sjmcneill qcscm_tee_app_get_id(struct qcscm_softc *sc, const char *name, uint32_t *id) 319*c95a3ae2Sjmcneill { 320*c95a3ae2Sjmcneill struct qcscm_dmamem *qdm; 321*c95a3ae2Sjmcneill uint64_t res[3]; 322*c95a3ae2Sjmcneill uint64_t args[2]; 323*c95a3ae2Sjmcneill uint32_t arginfo; 324*c95a3ae2Sjmcneill int ret; 325*c95a3ae2Sjmcneill 326*c95a3ae2Sjmcneill /* Max name length is 64 */ 327*c95a3ae2Sjmcneill if (strlen(name) > 64) 328*c95a3ae2Sjmcneill return EINVAL; 329*c95a3ae2Sjmcneill 330*c95a3ae2Sjmcneill /* Alloc some phys mem to hold the name */ 331*c95a3ae2Sjmcneill qdm = qcscm_dmamem_alloc(sc, PAGE_SIZE, 8); 332*c95a3ae2Sjmcneill if (qdm == NULL) 333*c95a3ae2Sjmcneill return ENOMEM; 334*c95a3ae2Sjmcneill 335*c95a3ae2Sjmcneill /* Copy name of app we want to get an id for to page */ 336*c95a3ae2Sjmcneill memcpy(QCSCM_DMA_KVA(qdm, 0), name, strlen(name)); 337*c95a3ae2Sjmcneill 338*c95a3ae2Sjmcneill /* Pass address of name and length */ 339*c95a3ae2Sjmcneill arginfo = QCSCM_ARGINFO_NUM(__arraycount(args)); 340*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_RW); 341*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 342*c95a3ae2Sjmcneill args[0] = QCSCM_DMA_DVA(qdm); 343*c95a3ae2Sjmcneill args[1] = strlen(name); 344*c95a3ae2Sjmcneill 345*c95a3ae2Sjmcneill cpu_drain_writebuf(); 346*c95a3ae2Sjmcneill 347*c95a3ae2Sjmcneill /* Make call into TEE */ 348*c95a3ae2Sjmcneill ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_QSEE_OS, QCTEE_TZ_SVC_APP_MGR, 349*c95a3ae2Sjmcneill 0x03, arginfo, args, __arraycount(args), res); 350*c95a3ae2Sjmcneill 351*c95a3ae2Sjmcneill /* If the call succeeded, check the response status */ 352*c95a3ae2Sjmcneill if (ret == 0) 353*c95a3ae2Sjmcneill ret = res[0]; 354*c95a3ae2Sjmcneill 355*c95a3ae2Sjmcneill /* If the response status is successful as well, retrieve data */ 356*c95a3ae2Sjmcneill if (ret == 0) 357*c95a3ae2Sjmcneill *id = res[2]; 358*c95a3ae2Sjmcneill 359*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 360*c95a3ae2Sjmcneill return ret; 361*c95a3ae2Sjmcneill } 362*c95a3ae2Sjmcneill 363*c95a3ae2Sjmcneill /* Message interface to app running in TEE */ 364*c95a3ae2Sjmcneill int 365*c95a3ae2Sjmcneill qcscm_tee_app_send(struct qcscm_softc *sc, uint32_t id, uint64_t req_phys, 366*c95a3ae2Sjmcneill uint64_t req_len, uint64_t rsp_phys, uint64_t rsp_len) 367*c95a3ae2Sjmcneill { 368*c95a3ae2Sjmcneill uint64_t res[3]; 369*c95a3ae2Sjmcneill uint64_t args[5]; 370*c95a3ae2Sjmcneill uint32_t arginfo; 371*c95a3ae2Sjmcneill int ret; 372*c95a3ae2Sjmcneill 373*c95a3ae2Sjmcneill /* Pass id of app we target, plus request and response buffers */ 374*c95a3ae2Sjmcneill arginfo = QCSCM_ARGINFO_NUM(__arraycount(args)); 375*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 376*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 377*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 378*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(3, QCSCM_ARGINFO_TYPE_RW); 379*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(4, QCSCM_ARGINFO_TYPE_VAL); 380*c95a3ae2Sjmcneill args[0] = id; 381*c95a3ae2Sjmcneill args[1] = req_phys; 382*c95a3ae2Sjmcneill args[2] = req_len; 383*c95a3ae2Sjmcneill args[3] = rsp_phys; 384*c95a3ae2Sjmcneill args[4] = rsp_len; 385*c95a3ae2Sjmcneill 386*c95a3ae2Sjmcneill /* Make call into TEE */ 387*c95a3ae2Sjmcneill ret = qcscm_smc_call(sc, QCTEE_TZ_OWNER_TZ_APPS, 388*c95a3ae2Sjmcneill QCTEE_TZ_SVC_APP_ID_PLACEHOLDER, 0x01, 389*c95a3ae2Sjmcneill arginfo, args, __arraycount(args), res); 390*c95a3ae2Sjmcneill 391*c95a3ae2Sjmcneill /* If the call succeeded, check the response status */ 392*c95a3ae2Sjmcneill if (ret == 0) 393*c95a3ae2Sjmcneill ret = res[0]; 394*c95a3ae2Sjmcneill 395*c95a3ae2Sjmcneill return ret; 396*c95a3ae2Sjmcneill } 397*c95a3ae2Sjmcneill 398*c95a3ae2Sjmcneill struct qcscm_req_uefi_get_variable { 399*c95a3ae2Sjmcneill uint32_t command_id; 400*c95a3ae2Sjmcneill uint32_t length; 401*c95a3ae2Sjmcneill uint32_t name_offset; 402*c95a3ae2Sjmcneill uint32_t name_size; 403*c95a3ae2Sjmcneill uint32_t guid_offset; 404*c95a3ae2Sjmcneill uint32_t guid_size; 405*c95a3ae2Sjmcneill uint32_t data_size; 406*c95a3ae2Sjmcneill }; 407*c95a3ae2Sjmcneill 408*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_get_variable { 409*c95a3ae2Sjmcneill uint32_t command_id; 410*c95a3ae2Sjmcneill uint32_t length; 411*c95a3ae2Sjmcneill uint32_t status; 412*c95a3ae2Sjmcneill uint32_t attributes; 413*c95a3ae2Sjmcneill uint32_t data_offset; 414*c95a3ae2Sjmcneill uint32_t data_size; 415*c95a3ae2Sjmcneill }; 416*c95a3ae2Sjmcneill 417*c95a3ae2Sjmcneill efi_status 418*c95a3ae2Sjmcneill qcscm_uefi_get_variable(struct qcscm_softc *sc, 419*c95a3ae2Sjmcneill efi_char *name, int name_size, struct uuid *guid, 420*c95a3ae2Sjmcneill uint32_t *attributes, uint8_t *data, int *data_size) 421*c95a3ae2Sjmcneill { 422*c95a3ae2Sjmcneill struct qcscm_req_uefi_get_variable *req; 423*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_get_variable *resp; 424*c95a3ae2Sjmcneill struct qcscm_dmamem *qdm; 425*c95a3ae2Sjmcneill size_t reqsize, respsize; 426*c95a3ae2Sjmcneill off_t reqoff, respoff; 427*c95a3ae2Sjmcneill int ret; 428*c95a3ae2Sjmcneill 429*c95a3ae2Sjmcneill if (sc->sc_uefi_id == UINT32_MAX) 430*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 431*c95a3ae2Sjmcneill 432*c95a3ae2Sjmcneill reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)); 433*c95a3ae2Sjmcneill respsize = ALIGN(sizeof(*resp)) + ALIGN(*data_size); 434*c95a3ae2Sjmcneill 435*c95a3ae2Sjmcneill reqoff = 0; 436*c95a3ae2Sjmcneill respoff = reqsize; 437*c95a3ae2Sjmcneill 438*c95a3ae2Sjmcneill qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 439*c95a3ae2Sjmcneill if (qdm == NULL) 440*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 441*c95a3ae2Sjmcneill 442*c95a3ae2Sjmcneill req = QCSCM_DMA_KVA(qdm, reqoff); 443*c95a3ae2Sjmcneill req->command_id = QCTEE_UEFI_GET_VARIABLE; 444*c95a3ae2Sjmcneill req->data_size = *data_size; 445*c95a3ae2Sjmcneill req->name_offset = ALIGN(sizeof(*req)); 446*c95a3ae2Sjmcneill req->name_size = name_size; 447*c95a3ae2Sjmcneill req->guid_offset = ALIGN(req->name_offset + req->name_size); 448*c95a3ae2Sjmcneill req->guid_size = sizeof(*guid); 449*c95a3ae2Sjmcneill req->length = req->guid_offset + req->guid_size; 450*c95a3ae2Sjmcneill 451*c95a3ae2Sjmcneill memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 452*c95a3ae2Sjmcneill memcpy((char *)req + req->name_offset, name, name_size); 453*c95a3ae2Sjmcneill 454*c95a3ae2Sjmcneill cpu_drain_writebuf(); 455*c95a3ae2Sjmcneill 456*c95a3ae2Sjmcneill ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 457*c95a3ae2Sjmcneill QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 458*c95a3ae2Sjmcneill QCSCM_DMA_DVA(qdm) + respoff, respsize); 459*c95a3ae2Sjmcneill if (ret) { 460*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 461*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 462*c95a3ae2Sjmcneill } 463*c95a3ae2Sjmcneill 464*c95a3ae2Sjmcneill cpu_drain_writebuf(); 465*c95a3ae2Sjmcneill 466*c95a3ae2Sjmcneill resp = QCSCM_DMA_KVA(qdm, respoff); 467*c95a3ae2Sjmcneill if (resp->command_id != QCTEE_UEFI_GET_VARIABLE || 468*c95a3ae2Sjmcneill resp->length < sizeof(*resp)) { 469*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 470*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 471*c95a3ae2Sjmcneill } 472*c95a3ae2Sjmcneill 473*c95a3ae2Sjmcneill if (resp->status) { 474*c95a3ae2Sjmcneill if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 475*c95a3ae2Sjmcneill *data_size = resp->data_size; 476*c95a3ae2Sjmcneill if (attributes) 477*c95a3ae2Sjmcneill *attributes = resp->attributes; 478*c95a3ae2Sjmcneill ret = resp->status; 479*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 480*c95a3ae2Sjmcneill return ret; 481*c95a3ae2Sjmcneill } 482*c95a3ae2Sjmcneill 483*c95a3ae2Sjmcneill if (resp->length > respsize || 484*c95a3ae2Sjmcneill resp->data_offset + resp->data_size > resp->length) { 485*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 486*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 487*c95a3ae2Sjmcneill } 488*c95a3ae2Sjmcneill 489*c95a3ae2Sjmcneill if (attributes) 490*c95a3ae2Sjmcneill *attributes = resp->attributes; 491*c95a3ae2Sjmcneill 492*c95a3ae2Sjmcneill if (*data_size == 0) { 493*c95a3ae2Sjmcneill *data_size = resp->data_size; 494*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 495*c95a3ae2Sjmcneill return QCTEE_UEFI_SUCCESS; 496*c95a3ae2Sjmcneill } 497*c95a3ae2Sjmcneill 498*c95a3ae2Sjmcneill if (resp->data_size > *data_size) { 499*c95a3ae2Sjmcneill *data_size = resp->data_size; 500*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 501*c95a3ae2Sjmcneill return QCTEE_UEFI_BUFFER_TOO_SMALL; 502*c95a3ae2Sjmcneill } 503*c95a3ae2Sjmcneill 504*c95a3ae2Sjmcneill memcpy(data, (char *)resp + resp->data_offset, resp->data_size); 505*c95a3ae2Sjmcneill *data_size = resp->data_size; 506*c95a3ae2Sjmcneill 507*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 508*c95a3ae2Sjmcneill return EFI_SUCCESS; 509*c95a3ae2Sjmcneill } 510*c95a3ae2Sjmcneill 511*c95a3ae2Sjmcneill struct qcscm_req_uefi_set_variable { 512*c95a3ae2Sjmcneill uint32_t command_id; 513*c95a3ae2Sjmcneill uint32_t length; 514*c95a3ae2Sjmcneill uint32_t name_offset; 515*c95a3ae2Sjmcneill uint32_t name_size; 516*c95a3ae2Sjmcneill uint32_t guid_offset; 517*c95a3ae2Sjmcneill uint32_t guid_size; 518*c95a3ae2Sjmcneill uint32_t attributes; 519*c95a3ae2Sjmcneill uint32_t data_offset; 520*c95a3ae2Sjmcneill uint32_t data_size; 521*c95a3ae2Sjmcneill }; 522*c95a3ae2Sjmcneill 523*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_set_variable { 524*c95a3ae2Sjmcneill uint32_t command_id; 525*c95a3ae2Sjmcneill uint32_t length; 526*c95a3ae2Sjmcneill uint32_t status; 527*c95a3ae2Sjmcneill uint32_t unknown[2]; 528*c95a3ae2Sjmcneill }; 529*c95a3ae2Sjmcneill 530*c95a3ae2Sjmcneill efi_status 531*c95a3ae2Sjmcneill qcscm_uefi_set_variable(struct qcscm_softc *sc, 532*c95a3ae2Sjmcneill efi_char *name, int name_size, struct uuid *guid, 533*c95a3ae2Sjmcneill uint32_t attributes, uint8_t *data, int data_size) 534*c95a3ae2Sjmcneill { 535*c95a3ae2Sjmcneill struct qcscm_req_uefi_set_variable *req; 536*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_set_variable *resp; 537*c95a3ae2Sjmcneill struct qcscm_dmamem *qdm; 538*c95a3ae2Sjmcneill size_t reqsize, respsize; 539*c95a3ae2Sjmcneill off_t reqoff, respoff; 540*c95a3ae2Sjmcneill int ret; 541*c95a3ae2Sjmcneill 542*c95a3ae2Sjmcneill if (sc->sc_uefi_id == UINT32_MAX) 543*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 544*c95a3ae2Sjmcneill 545*c95a3ae2Sjmcneill reqsize = ALIGN(sizeof(*req)) + ALIGN(name_size) + ALIGN(sizeof(*guid)) + 546*c95a3ae2Sjmcneill ALIGN(data_size); 547*c95a3ae2Sjmcneill respsize = ALIGN(sizeof(*resp)); 548*c95a3ae2Sjmcneill 549*c95a3ae2Sjmcneill reqoff = 0; 550*c95a3ae2Sjmcneill respoff = reqsize; 551*c95a3ae2Sjmcneill 552*c95a3ae2Sjmcneill qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 553*c95a3ae2Sjmcneill if (qdm == NULL) 554*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 555*c95a3ae2Sjmcneill 556*c95a3ae2Sjmcneill req = QCSCM_DMA_KVA(qdm, reqoff); 557*c95a3ae2Sjmcneill req->command_id = QCTEE_UEFI_SET_VARIABLE; 558*c95a3ae2Sjmcneill req->attributes = attributes; 559*c95a3ae2Sjmcneill req->name_offset = ALIGN(sizeof(*req)); 560*c95a3ae2Sjmcneill req->name_size = name_size; 561*c95a3ae2Sjmcneill req->guid_offset = ALIGN(req->name_offset + req->name_size); 562*c95a3ae2Sjmcneill req->guid_size = sizeof(*guid); 563*c95a3ae2Sjmcneill req->data_offset = ALIGN(req->guid_offset + req->guid_size); 564*c95a3ae2Sjmcneill req->data_size = data_size; 565*c95a3ae2Sjmcneill req->length = req->data_offset + req->data_size; 566*c95a3ae2Sjmcneill 567*c95a3ae2Sjmcneill memcpy((char *)req + req->name_offset, name, name_size); 568*c95a3ae2Sjmcneill memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 569*c95a3ae2Sjmcneill memcpy((char *)req + req->data_offset, data, data_size); 570*c95a3ae2Sjmcneill 571*c95a3ae2Sjmcneill ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 572*c95a3ae2Sjmcneill QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 573*c95a3ae2Sjmcneill QCSCM_DMA_DVA(qdm) + respoff, respsize); 574*c95a3ae2Sjmcneill if (ret) { 575*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 576*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 577*c95a3ae2Sjmcneill } 578*c95a3ae2Sjmcneill 579*c95a3ae2Sjmcneill resp = QCSCM_DMA_KVA(qdm, respoff); 580*c95a3ae2Sjmcneill if (resp->command_id != QCTEE_UEFI_SET_VARIABLE || 581*c95a3ae2Sjmcneill resp->length < sizeof(*resp) || resp->length > respsize) { 582*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 583*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 584*c95a3ae2Sjmcneill } 585*c95a3ae2Sjmcneill 586*c95a3ae2Sjmcneill if (resp->status) { 587*c95a3ae2Sjmcneill ret = resp->status; 588*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 589*c95a3ae2Sjmcneill return ret; 590*c95a3ae2Sjmcneill } 591*c95a3ae2Sjmcneill 592*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 593*c95a3ae2Sjmcneill return QCTEE_UEFI_SUCCESS; 594*c95a3ae2Sjmcneill } 595*c95a3ae2Sjmcneill 596*c95a3ae2Sjmcneill struct qcscm_req_uefi_get_next_variable { 597*c95a3ae2Sjmcneill uint32_t command_id; 598*c95a3ae2Sjmcneill uint32_t length; 599*c95a3ae2Sjmcneill uint32_t guid_offset; 600*c95a3ae2Sjmcneill uint32_t guid_size; 601*c95a3ae2Sjmcneill uint32_t name_offset; 602*c95a3ae2Sjmcneill uint32_t name_size; 603*c95a3ae2Sjmcneill }; 604*c95a3ae2Sjmcneill 605*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_get_next_variable { 606*c95a3ae2Sjmcneill uint32_t command_id; 607*c95a3ae2Sjmcneill uint32_t length; 608*c95a3ae2Sjmcneill uint32_t status; 609*c95a3ae2Sjmcneill uint32_t guid_offset; 610*c95a3ae2Sjmcneill uint32_t guid_size; 611*c95a3ae2Sjmcneill uint32_t name_offset; 612*c95a3ae2Sjmcneill uint32_t name_size; 613*c95a3ae2Sjmcneill }; 614*c95a3ae2Sjmcneill 615*c95a3ae2Sjmcneill efi_status 616*c95a3ae2Sjmcneill qcscm_uefi_get_next_variable(struct qcscm_softc *sc, 617*c95a3ae2Sjmcneill efi_char *name, int *name_size, struct uuid *guid) 618*c95a3ae2Sjmcneill { 619*c95a3ae2Sjmcneill struct qcscm_req_uefi_get_next_variable *req; 620*c95a3ae2Sjmcneill struct qcscm_rsp_uefi_get_next_variable *resp; 621*c95a3ae2Sjmcneill struct qcscm_dmamem *qdm; 622*c95a3ae2Sjmcneill size_t reqsize, respsize; 623*c95a3ae2Sjmcneill off_t reqoff, respoff; 624*c95a3ae2Sjmcneill int ret; 625*c95a3ae2Sjmcneill 626*c95a3ae2Sjmcneill if (sc->sc_uefi_id == UINT32_MAX) 627*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 628*c95a3ae2Sjmcneill 629*c95a3ae2Sjmcneill reqsize = ALIGN(sizeof(*req)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 630*c95a3ae2Sjmcneill respsize = ALIGN(sizeof(*resp)) + ALIGN(sizeof(*guid)) + ALIGN(*name_size); 631*c95a3ae2Sjmcneill 632*c95a3ae2Sjmcneill reqoff = 0; 633*c95a3ae2Sjmcneill respoff = reqsize; 634*c95a3ae2Sjmcneill 635*c95a3ae2Sjmcneill qdm = qcscm_dmamem_alloc(sc, round_page(reqsize + respsize), 8); 636*c95a3ae2Sjmcneill if (qdm == NULL) 637*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 638*c95a3ae2Sjmcneill 639*c95a3ae2Sjmcneill req = QCSCM_DMA_KVA(qdm, reqoff); 640*c95a3ae2Sjmcneill req->command_id = QCTEE_UEFI_GET_NEXT_VARIABLE; 641*c95a3ae2Sjmcneill req->guid_offset = ALIGN(sizeof(*req)); 642*c95a3ae2Sjmcneill req->guid_size = sizeof(*guid); 643*c95a3ae2Sjmcneill req->name_offset = ALIGN(req->guid_offset + req->guid_size); 644*c95a3ae2Sjmcneill req->name_size = *name_size; 645*c95a3ae2Sjmcneill req->length = req->name_offset + req->name_size; 646*c95a3ae2Sjmcneill 647*c95a3ae2Sjmcneill memcpy((char *)req + req->guid_offset, guid, sizeof(*guid)); 648*c95a3ae2Sjmcneill memcpy((char *)req + req->name_offset, name, *name_size); 649*c95a3ae2Sjmcneill 650*c95a3ae2Sjmcneill ret = qcscm_tee_app_send(sc, sc->sc_uefi_id, 651*c95a3ae2Sjmcneill QCSCM_DMA_DVA(qdm) + reqoff, reqsize, 652*c95a3ae2Sjmcneill QCSCM_DMA_DVA(qdm) + respoff, respsize); 653*c95a3ae2Sjmcneill if (ret) { 654*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 655*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 656*c95a3ae2Sjmcneill } 657*c95a3ae2Sjmcneill 658*c95a3ae2Sjmcneill resp = QCSCM_DMA_KVA(qdm, respoff); 659*c95a3ae2Sjmcneill if (resp->command_id != QCTEE_UEFI_GET_NEXT_VARIABLE || 660*c95a3ae2Sjmcneill resp->length < sizeof(*resp) || resp->length > respsize) { 661*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 662*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 663*c95a3ae2Sjmcneill } 664*c95a3ae2Sjmcneill 665*c95a3ae2Sjmcneill if (resp->status) { 666*c95a3ae2Sjmcneill if (resp->status == QCTEE_UEFI_BUFFER_TOO_SMALL) 667*c95a3ae2Sjmcneill *name_size = resp->name_size; 668*c95a3ae2Sjmcneill ret = resp->status; 669*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 670*c95a3ae2Sjmcneill return ret; 671*c95a3ae2Sjmcneill } 672*c95a3ae2Sjmcneill 673*c95a3ae2Sjmcneill if (resp->guid_offset + resp->guid_size > resp->length || 674*c95a3ae2Sjmcneill resp->name_offset + resp->name_size > resp->length) { 675*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 676*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 677*c95a3ae2Sjmcneill } 678*c95a3ae2Sjmcneill 679*c95a3ae2Sjmcneill if (resp->guid_size != sizeof(*guid)) { 680*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 681*c95a3ae2Sjmcneill return QCTEE_UEFI_DEVICE_ERROR; 682*c95a3ae2Sjmcneill } 683*c95a3ae2Sjmcneill 684*c95a3ae2Sjmcneill if (resp->name_size > *name_size) { 685*c95a3ae2Sjmcneill *name_size = resp->name_size; 686*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 687*c95a3ae2Sjmcneill return QCTEE_UEFI_BUFFER_TOO_SMALL; 688*c95a3ae2Sjmcneill } 689*c95a3ae2Sjmcneill 690*c95a3ae2Sjmcneill memcpy(guid, (char *)resp + resp->guid_offset, sizeof(*guid)); 691*c95a3ae2Sjmcneill memcpy(name, (char *)resp + resp->name_offset, resp->name_size); 692*c95a3ae2Sjmcneill *name_size = resp->name_size; 693*c95a3ae2Sjmcneill 694*c95a3ae2Sjmcneill qcscm_dmamem_free(sc, qdm); 695*c95a3ae2Sjmcneill return QCTEE_UEFI_SUCCESS; 696*c95a3ae2Sjmcneill } 697*c95a3ae2Sjmcneill 698*c95a3ae2Sjmcneill efi_status 699*c95a3ae2Sjmcneill qcscm_efi_get_variable(efi_char *name, struct uuid *guid, uint32_t *attributes, 700*c95a3ae2Sjmcneill u_long *data_size, void *data) 701*c95a3ae2Sjmcneill { 702*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 703*c95a3ae2Sjmcneill efi_status status; 704*c95a3ae2Sjmcneill int name_size; 705*c95a3ae2Sjmcneill int size; 706*c95a3ae2Sjmcneill 707*c95a3ae2Sjmcneill name_size = 0; 708*c95a3ae2Sjmcneill while (name[name_size]) 709*c95a3ae2Sjmcneill name_size++; 710*c95a3ae2Sjmcneill name_size++; 711*c95a3ae2Sjmcneill 712*c95a3ae2Sjmcneill size = *data_size; 713*c95a3ae2Sjmcneill status = qcscm_uefi_get_variable(sc, name, name_size * 2, guid, 714*c95a3ae2Sjmcneill attributes, data, &size); 715*c95a3ae2Sjmcneill *data_size = size; 716*c95a3ae2Sjmcneill 717*c95a3ae2Sjmcneill /* Convert 32-bit status code to 64-bit. */ 718*c95a3ae2Sjmcneill return ((status & 0xf0000000) << 32 | (status & 0x0fffffff)); 719*c95a3ae2Sjmcneill } 720*c95a3ae2Sjmcneill 721*c95a3ae2Sjmcneill efi_status 722*c95a3ae2Sjmcneill qcscm_efi_set_variable(efi_char *name, struct uuid *guid, uint32_t attributes, 723*c95a3ae2Sjmcneill u_long data_size, void *data) 724*c95a3ae2Sjmcneill { 725*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 726*c95a3ae2Sjmcneill efi_status status; 727*c95a3ae2Sjmcneill int name_size; 728*c95a3ae2Sjmcneill 729*c95a3ae2Sjmcneill name_size = 0; 730*c95a3ae2Sjmcneill while (name[name_size]) 731*c95a3ae2Sjmcneill name_size++; 732*c95a3ae2Sjmcneill name_size++; 733*c95a3ae2Sjmcneill 734*c95a3ae2Sjmcneill status = qcscm_uefi_set_variable(sc, name, name_size * 2, guid, 735*c95a3ae2Sjmcneill attributes, data, data_size); 736*c95a3ae2Sjmcneill 737*c95a3ae2Sjmcneill /* Convert 32-bit status code to 64-bit. */ 738*c95a3ae2Sjmcneill return ((status & 0xf0000000) << 32 | (status & 0x0fffffff)); 739*c95a3ae2Sjmcneill } 740*c95a3ae2Sjmcneill 741*c95a3ae2Sjmcneill efi_status 742*c95a3ae2Sjmcneill qcscm_efi_get_next_variable_name(u_long *name_size, efi_char *name, 743*c95a3ae2Sjmcneill struct uuid *guid) 744*c95a3ae2Sjmcneill { 745*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 746*c95a3ae2Sjmcneill efi_status status; 747*c95a3ae2Sjmcneill int size; 748*c95a3ae2Sjmcneill 749*c95a3ae2Sjmcneill size = *name_size; 750*c95a3ae2Sjmcneill status = qcscm_uefi_get_next_variable(sc, name, &size, guid); 751*c95a3ae2Sjmcneill *name_size = size; 752*c95a3ae2Sjmcneill 753*c95a3ae2Sjmcneill /* Convert 32-bit status code to 64-bit. */ 754*c95a3ae2Sjmcneill return ((status & 0xf0000000) << 32 | (status & 0x0fffffff)); 755*c95a3ae2Sjmcneill } 756*c95a3ae2Sjmcneill 757*c95a3ae2Sjmcneill #ifdef QCSCM_DEBUG 758*c95a3ae2Sjmcneill 759*c95a3ae2Sjmcneill void 760*c95a3ae2Sjmcneill qcscm_uefi_dump_variables(struct qcscm_softc *sc) 761*c95a3ae2Sjmcneill { 762*c95a3ae2Sjmcneill efi_char name[128]; 763*c95a3ae2Sjmcneill struct uuid guid; 764*c95a3ae2Sjmcneill int namesize = sizeof(name); 765*c95a3ae2Sjmcneill int i, ret; 766*c95a3ae2Sjmcneill 767*c95a3ae2Sjmcneill memset(name, 0, sizeof(name)); 768*c95a3ae2Sjmcneill memset(&guid, 0, sizeof(guid)); 769*c95a3ae2Sjmcneill 770*c95a3ae2Sjmcneill for (;;) { 771*c95a3ae2Sjmcneill ret = qcscm_uefi_get_next_variable(sc, name, &namesize, &guid); 772*c95a3ae2Sjmcneill if (ret == 0) { 773*c95a3ae2Sjmcneill printf("%s: ", device_xname(sc->sc_dev)); 774*c95a3ae2Sjmcneill for (i = 0; i < namesize / 2; i++) 775*c95a3ae2Sjmcneill printf("%c", name[i]); 776*c95a3ae2Sjmcneill printf(" { 0x%08x, 0x%04x, 0x%04x, { ", 777*c95a3ae2Sjmcneill guid.time_low, guid.time_mid, guid.time_hi_and_version); 778*c95a3ae2Sjmcneill printf(" 0x%02x, 0x%02x,", 779*c95a3ae2Sjmcneill guid.clock_seq_hi_and_reserved, 780*c95a3ae2Sjmcneill guid.clock_seq_low); 781*c95a3ae2Sjmcneill for (i = 0; i < 6; i++) { 782*c95a3ae2Sjmcneill printf(" 0x%02x,", guid.node[i]); 783*c95a3ae2Sjmcneill } 784*c95a3ae2Sjmcneill printf(" }"); 785*c95a3ae2Sjmcneill printf("\n"); 786*c95a3ae2Sjmcneill namesize = sizeof(name); 787*c95a3ae2Sjmcneill continue; 788*c95a3ae2Sjmcneill } 789*c95a3ae2Sjmcneill break; 790*c95a3ae2Sjmcneill } 791*c95a3ae2Sjmcneill } 792*c95a3ae2Sjmcneill 793*c95a3ae2Sjmcneill void 794*c95a3ae2Sjmcneill qcscm_uefi_dump_variable(struct qcscm_softc *sc, efi_char *name, int namesize, 795*c95a3ae2Sjmcneill struct uuid *guid) 796*c95a3ae2Sjmcneill { 797*c95a3ae2Sjmcneill uint8_t data[512]; 798*c95a3ae2Sjmcneill int datasize = sizeof(data); 799*c95a3ae2Sjmcneill int i, ret; 800*c95a3ae2Sjmcneill 801*c95a3ae2Sjmcneill ret = qcscm_uefi_get_variable(sc, name, namesize, guid, 802*c95a3ae2Sjmcneill NULL, data, &datasize); 803*c95a3ae2Sjmcneill if (ret != QCTEE_UEFI_SUCCESS) { 804*c95a3ae2Sjmcneill printf("%s: error reading ", device_xname(sc->sc_dev)); 805*c95a3ae2Sjmcneill for (i = 0; i < namesize / 2; i++) 806*c95a3ae2Sjmcneill printf("%c", name[i]); 807*c95a3ae2Sjmcneill printf("\n"); 808*c95a3ae2Sjmcneill return; 809*c95a3ae2Sjmcneill } 810*c95a3ae2Sjmcneill 811*c95a3ae2Sjmcneill printf("%s: ", device_xname(sc->sc_dev)); 812*c95a3ae2Sjmcneill for (i = 0; i < namesize / 2; i++) 813*c95a3ae2Sjmcneill printf("%c", name[i]); 814*c95a3ae2Sjmcneill printf(" = "); 815*c95a3ae2Sjmcneill for (i = 0; i < datasize; i++) 816*c95a3ae2Sjmcneill printf("%02x", data[i]); 817*c95a3ae2Sjmcneill printf("\n"); 818*c95a3ae2Sjmcneill } 819*c95a3ae2Sjmcneill 820*c95a3ae2Sjmcneill #endif 821*c95a3ae2Sjmcneill 822*c95a3ae2Sjmcneill int 823*c95a3ae2Sjmcneill qcscm_uefi_rtc_get(uint32_t *off) 824*c95a3ae2Sjmcneill { 825*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 826*c95a3ae2Sjmcneill uint32_t rtcinfo[3]; 827*c95a3ae2Sjmcneill int rtcinfosize = sizeof(rtcinfo); 828*c95a3ae2Sjmcneill 829*c95a3ae2Sjmcneill if (sc == NULL) 830*c95a3ae2Sjmcneill return ENXIO; 831*c95a3ae2Sjmcneill 832*c95a3ae2Sjmcneill if (qcscm_uefi_get_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO), 833*c95a3ae2Sjmcneill &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 834*c95a3ae2Sjmcneill &rtcinfosize) != 0) 835*c95a3ae2Sjmcneill return EIO; 836*c95a3ae2Sjmcneill 837*c95a3ae2Sjmcneill /* UEFI stores the offset based on GPS epoch */ 838*c95a3ae2Sjmcneill *off = rtcinfo[0] + UNIX_GPS_EPOCH_OFFSET; 839*c95a3ae2Sjmcneill return 0; 840*c95a3ae2Sjmcneill } 841*c95a3ae2Sjmcneill 842*c95a3ae2Sjmcneill int 843*c95a3ae2Sjmcneill qcscm_uefi_rtc_set(uint32_t off) 844*c95a3ae2Sjmcneill { 845*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 846*c95a3ae2Sjmcneill uint32_t rtcinfo[3]; 847*c95a3ae2Sjmcneill int rtcinfosize = sizeof(rtcinfo); 848*c95a3ae2Sjmcneill 849*c95a3ae2Sjmcneill if (sc == NULL) 850*c95a3ae2Sjmcneill return ENXIO; 851*c95a3ae2Sjmcneill 852*c95a3ae2Sjmcneill if (qcscm_uefi_get_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO), 853*c95a3ae2Sjmcneill &qcscm_uefi_rtcinfo_guid, NULL, (uint8_t *)rtcinfo, 854*c95a3ae2Sjmcneill &rtcinfosize) != 0) 855*c95a3ae2Sjmcneill return EIO; 856*c95a3ae2Sjmcneill 857*c95a3ae2Sjmcneill /* UEFI stores the offset based on GPS epoch */ 858*c95a3ae2Sjmcneill off -= UNIX_GPS_EPOCH_OFFSET; 859*c95a3ae2Sjmcneill 860*c95a3ae2Sjmcneill /* No need to set if we're not changing anything */ 861*c95a3ae2Sjmcneill if (rtcinfo[0] == off) 862*c95a3ae2Sjmcneill return 0; 863*c95a3ae2Sjmcneill 864*c95a3ae2Sjmcneill rtcinfo[0] = off; 865*c95a3ae2Sjmcneill 866*c95a3ae2Sjmcneill if (qcscm_uefi_set_variable(sc, EFI_VAR_RTCINFO, sizeof(EFI_VAR_RTCINFO), 867*c95a3ae2Sjmcneill &qcscm_uefi_rtcinfo_guid, EFI_VARIABLE_NON_VOLATILE | 868*c95a3ae2Sjmcneill EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 869*c95a3ae2Sjmcneill (uint8_t *)rtcinfo, sizeof(rtcinfo)) != 0) 870*c95a3ae2Sjmcneill return EIO; 871*c95a3ae2Sjmcneill 872*c95a3ae2Sjmcneill return 0; 873*c95a3ae2Sjmcneill } 874*c95a3ae2Sjmcneill 875*c95a3ae2Sjmcneill int 876*c95a3ae2Sjmcneill qcscm_pas_init_image(uint32_t peripheral, paddr_t metadata) 877*c95a3ae2Sjmcneill { 878*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 879*c95a3ae2Sjmcneill uint64_t res[3]; 880*c95a3ae2Sjmcneill uint64_t args[2]; 881*c95a3ae2Sjmcneill uint32_t arginfo; 882*c95a3ae2Sjmcneill int ret; 883*c95a3ae2Sjmcneill 884*c95a3ae2Sjmcneill if (sc == NULL) 885*c95a3ae2Sjmcneill return ENXIO; 886*c95a3ae2Sjmcneill 887*c95a3ae2Sjmcneill arginfo = QCSCM_ARGINFO_NUM(__arraycount(args)); 888*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 889*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_RW); 890*c95a3ae2Sjmcneill args[0] = peripheral; 891*c95a3ae2Sjmcneill args[1] = metadata; 892*c95a3ae2Sjmcneill 893*c95a3ae2Sjmcneill /* Make call into TEE */ 894*c95a3ae2Sjmcneill ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 895*c95a3ae2Sjmcneill QCSCM_PIL_PAS_INIT_IMAGE, arginfo, args, __arraycount(args), res); 896*c95a3ae2Sjmcneill 897*c95a3ae2Sjmcneill /* If the call succeeded, check the response status */ 898*c95a3ae2Sjmcneill if (ret == 0) 899*c95a3ae2Sjmcneill ret = res[0]; 900*c95a3ae2Sjmcneill 901*c95a3ae2Sjmcneill return ret; 902*c95a3ae2Sjmcneill } 903*c95a3ae2Sjmcneill 904*c95a3ae2Sjmcneill int 905*c95a3ae2Sjmcneill qcscm_pas_mem_setup(uint32_t peripheral, paddr_t addr, size_t size) 906*c95a3ae2Sjmcneill { 907*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 908*c95a3ae2Sjmcneill uint64_t res[3]; 909*c95a3ae2Sjmcneill uint64_t args[3]; 910*c95a3ae2Sjmcneill uint32_t arginfo; 911*c95a3ae2Sjmcneill int ret; 912*c95a3ae2Sjmcneill 913*c95a3ae2Sjmcneill if (sc == NULL) 914*c95a3ae2Sjmcneill return ENXIO; 915*c95a3ae2Sjmcneill 916*c95a3ae2Sjmcneill arginfo = QCSCM_ARGINFO_NUM(__arraycount(args)); 917*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 918*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(1, QCSCM_ARGINFO_TYPE_VAL); 919*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(2, QCSCM_ARGINFO_TYPE_VAL); 920*c95a3ae2Sjmcneill args[0] = peripheral; 921*c95a3ae2Sjmcneill args[1] = addr; 922*c95a3ae2Sjmcneill args[2] = size; 923*c95a3ae2Sjmcneill 924*c95a3ae2Sjmcneill /* Make call into TEE */ 925*c95a3ae2Sjmcneill ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 926*c95a3ae2Sjmcneill QCSCM_PIL_PAS_MEM_SETUP, arginfo, args, __arraycount(args), res); 927*c95a3ae2Sjmcneill 928*c95a3ae2Sjmcneill /* If the call succeeded, check the response status */ 929*c95a3ae2Sjmcneill if (ret == 0) 930*c95a3ae2Sjmcneill ret = res[0]; 931*c95a3ae2Sjmcneill 932*c95a3ae2Sjmcneill return ret; 933*c95a3ae2Sjmcneill } 934*c95a3ae2Sjmcneill 935*c95a3ae2Sjmcneill int 936*c95a3ae2Sjmcneill qcscm_pas_auth_and_reset(uint32_t peripheral) 937*c95a3ae2Sjmcneill { 938*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 939*c95a3ae2Sjmcneill uint64_t res[3]; 940*c95a3ae2Sjmcneill uint64_t args[1]; 941*c95a3ae2Sjmcneill uint32_t arginfo; 942*c95a3ae2Sjmcneill int ret; 943*c95a3ae2Sjmcneill 944*c95a3ae2Sjmcneill if (sc == NULL) 945*c95a3ae2Sjmcneill return ENXIO; 946*c95a3ae2Sjmcneill 947*c95a3ae2Sjmcneill arginfo = QCSCM_ARGINFO_NUM(__arraycount(args)); 948*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 949*c95a3ae2Sjmcneill args[0] = peripheral; 950*c95a3ae2Sjmcneill 951*c95a3ae2Sjmcneill /* Make call into TEE */ 952*c95a3ae2Sjmcneill ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 953*c95a3ae2Sjmcneill QCSCM_PIL_PAS_AUTH_AND_RESET, arginfo, args, __arraycount(args), res); 954*c95a3ae2Sjmcneill 955*c95a3ae2Sjmcneill /* If the call succeeded, check the response status */ 956*c95a3ae2Sjmcneill if (ret == 0) 957*c95a3ae2Sjmcneill ret = res[0]; 958*c95a3ae2Sjmcneill 959*c95a3ae2Sjmcneill return ret; 960*c95a3ae2Sjmcneill } 961*c95a3ae2Sjmcneill 962*c95a3ae2Sjmcneill int 963*c95a3ae2Sjmcneill qcscm_pas_shutdown(uint32_t peripheral) 964*c95a3ae2Sjmcneill { 965*c95a3ae2Sjmcneill struct qcscm_softc *sc = qcscm_sc; 966*c95a3ae2Sjmcneill uint64_t res[3]; 967*c95a3ae2Sjmcneill uint64_t args[1]; 968*c95a3ae2Sjmcneill uint32_t arginfo; 969*c95a3ae2Sjmcneill int ret; 970*c95a3ae2Sjmcneill 971*c95a3ae2Sjmcneill if (sc == NULL) 972*c95a3ae2Sjmcneill return ENXIO; 973*c95a3ae2Sjmcneill 974*c95a3ae2Sjmcneill arginfo = QCSCM_ARGINFO_NUM(__arraycount(args)); 975*c95a3ae2Sjmcneill arginfo |= QCSCM_ARGINFO_TYPE(0, QCSCM_ARGINFO_TYPE_VAL); 976*c95a3ae2Sjmcneill args[0] = peripheral; 977*c95a3ae2Sjmcneill 978*c95a3ae2Sjmcneill /* Make call into TEE */ 979*c95a3ae2Sjmcneill ret = qcscm_smc_call(sc, ARM_SMCCC_OWNER_SIP, QCSCM_SVC_PIL, 980*c95a3ae2Sjmcneill QCSCM_PIL_PAS_SHUTDOWN, arginfo, args, __arraycount(args), res); 981*c95a3ae2Sjmcneill 982*c95a3ae2Sjmcneill /* If the call succeeded, check the response status */ 983*c95a3ae2Sjmcneill if (ret == 0) 984*c95a3ae2Sjmcneill ret = res[0]; 985*c95a3ae2Sjmcneill 986*c95a3ae2Sjmcneill return ret; 987*c95a3ae2Sjmcneill } 988*c95a3ae2Sjmcneill 989*c95a3ae2Sjmcneill /* DMA code */ 990*c95a3ae2Sjmcneill struct qcscm_dmamem * 991*c95a3ae2Sjmcneill qcscm_dmamem_alloc(struct qcscm_softc *sc, bus_size_t size, bus_size_t align) 992*c95a3ae2Sjmcneill { 993*c95a3ae2Sjmcneill struct qcscm_dmamem *qdm; 994*c95a3ae2Sjmcneill int nsegs; 995*c95a3ae2Sjmcneill 996*c95a3ae2Sjmcneill qdm = kmem_zalloc(sizeof(*qdm), KM_SLEEP); 997*c95a3ae2Sjmcneill qdm->qdm_size = size; 998*c95a3ae2Sjmcneill 999*c95a3ae2Sjmcneill if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 1000*c95a3ae2Sjmcneill BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &qdm->qdm_map) != 0) 1001*c95a3ae2Sjmcneill goto qdmfree; 1002*c95a3ae2Sjmcneill 1003*c95a3ae2Sjmcneill if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, 1004*c95a3ae2Sjmcneill &qdm->qdm_seg, 1, &nsegs, BUS_DMA_WAITOK) != 0) 1005*c95a3ae2Sjmcneill goto destroy; 1006*c95a3ae2Sjmcneill 1007*c95a3ae2Sjmcneill if (bus_dmamem_map(sc->sc_dmat, &qdm->qdm_seg, nsegs, size, 1008*c95a3ae2Sjmcneill &qdm->qdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 1009*c95a3ae2Sjmcneill goto free; 1010*c95a3ae2Sjmcneill 1011*c95a3ae2Sjmcneill if (bus_dmamap_load(sc->sc_dmat, qdm->qdm_map, qdm->qdm_kva, size, 1012*c95a3ae2Sjmcneill NULL, BUS_DMA_WAITOK) != 0) 1013*c95a3ae2Sjmcneill goto unmap; 1014*c95a3ae2Sjmcneill 1015*c95a3ae2Sjmcneill memset(qdm->qdm_kva, 0, size); 1016*c95a3ae2Sjmcneill 1017*c95a3ae2Sjmcneill return (qdm); 1018*c95a3ae2Sjmcneill 1019*c95a3ae2Sjmcneill unmap: 1020*c95a3ae2Sjmcneill bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, size); 1021*c95a3ae2Sjmcneill free: 1022*c95a3ae2Sjmcneill bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 1023*c95a3ae2Sjmcneill destroy: 1024*c95a3ae2Sjmcneill bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 1025*c95a3ae2Sjmcneill qdmfree: 1026*c95a3ae2Sjmcneill kmem_free(qdm, sizeof(*qdm)); 1027*c95a3ae2Sjmcneill 1028*c95a3ae2Sjmcneill return (NULL); 1029*c95a3ae2Sjmcneill } 1030*c95a3ae2Sjmcneill 1031*c95a3ae2Sjmcneill void 1032*c95a3ae2Sjmcneill qcscm_dmamem_free(struct qcscm_softc *sc, struct qcscm_dmamem *qdm) 1033*c95a3ae2Sjmcneill { 1034*c95a3ae2Sjmcneill bus_dmamem_unmap(sc->sc_dmat, qdm->qdm_kva, qdm->qdm_size); 1035*c95a3ae2Sjmcneill bus_dmamem_free(sc->sc_dmat, &qdm->qdm_seg, 1); 1036*c95a3ae2Sjmcneill bus_dmamap_destroy(sc->sc_dmat, qdm->qdm_map); 1037*c95a3ae2Sjmcneill kmem_free(qdm, sizeof(*qdm)); 1038*c95a3ae2Sjmcneill } 1039