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