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