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