Skip to content

Commit 14672a9

Browse files
committed
Merge tag 'qcom-drivers-fixes-for-6.9' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into for-next
Qualcomm driver fix for v6.9 This reworks the memory layout of the argument buffers passed to trusted applications in QSEECOM, to avoid failures and system crashes. * tag 'qcom-drivers-fixes-for-6.9' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: firmware: qcom: uefisecapp: Fix memory related IO errors and crashes Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 7e68538 + ed09f81 commit 14672a9

File tree

4 files changed

+153
-86
lines changed

4 files changed

+153
-86
lines changed

drivers/firmware/qcom/qcom_qseecom_uefisecapp.c

Lines changed: 91 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,19 @@ struct qsee_rsp_uefi_query_variable_info {
221221
* alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
222222
* however, has an alignment of 4 byte (32 bits). So far, this seems to work
223223
* fine here. See also the comment on the typedef of efi_guid_t.
224+
*
225+
* Note: It looks like uefisecapp is quite picky about how the memory passed to
226+
* it is structured and aligned. In particular the request/response setup used
227+
* for QSEE_CMD_UEFI_GET_VARIABLE. While qcom_qseecom_app_send(), in theory,
228+
* accepts separate buffers/addresses for the request and response parts, in
229+
* practice, however, it seems to expect them to be both part of a larger
230+
* contiguous block. We initially allocated separate buffers for the request
231+
* and response but this caused the QSEE_CMD_UEFI_GET_VARIABLE command to
232+
* either not write any response to the response buffer or outright crash the
233+
* device. Therefore, we now allocate a single contiguous block of DMA memory
234+
* for both and properly align the data using the macros below. In particular,
235+
* request and response structs are aligned at 8 byte (via __reqdata_offs()),
236+
* following the driver that this has been reverse-engineered from.
224237
*/
225238
#define qcuefi_buf_align_fields(fields...) \
226239
({ \
@@ -244,6 +257,12 @@ struct qsee_rsp_uefi_query_variable_info {
244257
#define __array_offs(type, count, offset) \
245258
__field_impl(sizeof(type) * (count), __alignof__(type), offset)
246259

260+
#define __array_offs_aligned(type, count, align, offset) \
261+
__field_impl(sizeof(type) * (count), align, offset)
262+
263+
#define __reqdata_offs(size, offset) \
264+
__array_offs_aligned(u8, size, 8, offset)
265+
247266
#define __array(type, count) __array_offs(type, count, NULL)
248267
#define __field_offs(type, offset) __array_offs(type, 1, offset)
249268
#define __field(type) __array_offs(type, 1, NULL)
@@ -277,10 +296,15 @@ static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const e
277296
unsigned long buffer_size = *data_size;
278297
efi_status_t efi_status = EFI_SUCCESS;
279298
unsigned long name_length;
299+
dma_addr_t cmd_buf_dma;
300+
size_t cmd_buf_size;
301+
void *cmd_buf;
280302
size_t guid_offs;
281303
size_t name_offs;
282304
size_t req_size;
283305
size_t rsp_size;
306+
size_t req_offs;
307+
size_t rsp_offs;
284308
ssize_t status;
285309

286310
if (!name || !guid)
@@ -304,17 +328,19 @@ static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const e
304328
__array(u8, buffer_size)
305329
);
306330

307-
req_data = kzalloc(req_size, GFP_KERNEL);
308-
if (!req_data) {
331+
cmd_buf_size = qcuefi_buf_align_fields(
332+
__reqdata_offs(req_size, &req_offs)
333+
__reqdata_offs(rsp_size, &rsp_offs)
334+
);
335+
336+
cmd_buf = qseecom_dma_alloc(qcuefi->client, cmd_buf_size, &cmd_buf_dma, GFP_KERNEL);
337+
if (!cmd_buf) {
309338
efi_status = EFI_OUT_OF_RESOURCES;
310339
goto out;
311340
}
312341

313-
rsp_data = kzalloc(rsp_size, GFP_KERNEL);
314-
if (!rsp_data) {
315-
efi_status = EFI_OUT_OF_RESOURCES;
316-
goto out_free_req;
317-
}
342+
req_data = cmd_buf + req_offs;
343+
rsp_data = cmd_buf + rsp_offs;
318344

319345
req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
320346
req_data->data_size = buffer_size;
@@ -332,7 +358,9 @@ static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const e
332358

333359
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
334360

335-
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
361+
status = qcom_qseecom_app_send(qcuefi->client,
362+
cmd_buf_dma + req_offs, req_size,
363+
cmd_buf_dma + rsp_offs, rsp_size);
336364
if (status) {
337365
efi_status = EFI_DEVICE_ERROR;
338366
goto out_free;
@@ -407,9 +435,7 @@ static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const e
407435
memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
408436

409437
out_free:
410-
kfree(rsp_data);
411-
out_free_req:
412-
kfree(req_data);
438+
qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
413439
out:
414440
return efi_status;
415441
}
@@ -422,10 +448,15 @@ static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const e
422448
struct qsee_rsp_uefi_set_variable *rsp_data;
423449
efi_status_t efi_status = EFI_SUCCESS;
424450
unsigned long name_length;
451+
dma_addr_t cmd_buf_dma;
452+
size_t cmd_buf_size;
453+
void *cmd_buf;
425454
size_t name_offs;
426455
size_t guid_offs;
427456
size_t data_offs;
428457
size_t req_size;
458+
size_t req_offs;
459+
size_t rsp_offs;
429460
ssize_t status;
430461

431462
if (!name || !guid)
@@ -450,17 +481,19 @@ static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const e
450481
__array_offs(u8, data_size, &data_offs)
451482
);
452483

453-
req_data = kzalloc(req_size, GFP_KERNEL);
454-
if (!req_data) {
484+
cmd_buf_size = qcuefi_buf_align_fields(
485+
__reqdata_offs(req_size, &req_offs)
486+
__reqdata_offs(sizeof(*rsp_data), &rsp_offs)
487+
);
488+
489+
cmd_buf = qseecom_dma_alloc(qcuefi->client, cmd_buf_size, &cmd_buf_dma, GFP_KERNEL);
490+
if (!cmd_buf) {
455491
efi_status = EFI_OUT_OF_RESOURCES;
456492
goto out;
457493
}
458494

459-
rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
460-
if (!rsp_data) {
461-
efi_status = EFI_OUT_OF_RESOURCES;
462-
goto out_free_req;
463-
}
495+
req_data = cmd_buf + req_offs;
496+
rsp_data = cmd_buf + rsp_offs;
464497

465498
req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
466499
req_data->attributes = attributes;
@@ -483,8 +516,9 @@ static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const e
483516
if (data_size)
484517
memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
485518

486-
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data,
487-
sizeof(*rsp_data));
519+
status = qcom_qseecom_app_send(qcuefi->client,
520+
cmd_buf_dma + req_offs, req_size,
521+
cmd_buf_dma + rsp_offs, sizeof(*rsp_data));
488522
if (status) {
489523
efi_status = EFI_DEVICE_ERROR;
490524
goto out_free;
@@ -507,9 +541,7 @@ static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const e
507541
}
508542

509543
out_free:
510-
kfree(rsp_data);
511-
out_free_req:
512-
kfree(req_data);
544+
qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
513545
out:
514546
return efi_status;
515547
}
@@ -521,10 +553,15 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
521553
struct qsee_req_uefi_get_next_variable *req_data;
522554
struct qsee_rsp_uefi_get_next_variable *rsp_data;
523555
efi_status_t efi_status = EFI_SUCCESS;
556+
dma_addr_t cmd_buf_dma;
557+
size_t cmd_buf_size;
558+
void *cmd_buf;
524559
size_t guid_offs;
525560
size_t name_offs;
526561
size_t req_size;
527562
size_t rsp_size;
563+
size_t req_offs;
564+
size_t rsp_offs;
528565
ssize_t status;
529566

530567
if (!name_size || !name || !guid)
@@ -545,17 +582,19 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
545582
__array(*name, *name_size / sizeof(*name))
546583
);
547584

548-
req_data = kzalloc(req_size, GFP_KERNEL);
549-
if (!req_data) {
585+
cmd_buf_size = qcuefi_buf_align_fields(
586+
__reqdata_offs(req_size, &req_offs)
587+
__reqdata_offs(rsp_size, &rsp_offs)
588+
);
589+
590+
cmd_buf = qseecom_dma_alloc(qcuefi->client, cmd_buf_size, &cmd_buf_dma, GFP_KERNEL);
591+
if (!cmd_buf) {
550592
efi_status = EFI_OUT_OF_RESOURCES;
551593
goto out;
552594
}
553595

554-
rsp_data = kzalloc(rsp_size, GFP_KERNEL);
555-
if (!rsp_data) {
556-
efi_status = EFI_OUT_OF_RESOURCES;
557-
goto out_free_req;
558-
}
596+
req_data = cmd_buf + req_offs;
597+
rsp_data = cmd_buf + rsp_offs;
559598

560599
req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
561600
req_data->guid_offset = guid_offs;
@@ -572,7 +611,9 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
572611
goto out_free;
573612
}
574613

575-
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
614+
status = qcom_qseecom_app_send(qcuefi->client,
615+
cmd_buf_dma + req_offs, req_size,
616+
cmd_buf_dma + rsp_offs, rsp_size);
576617
if (status) {
577618
efi_status = EFI_DEVICE_ERROR;
578619
goto out_free;
@@ -645,9 +686,7 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
645686
}
646687

647688
out_free:
648-
kfree(rsp_data);
649-
out_free_req:
650-
kfree(req_data);
689+
qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
651690
out:
652691
return efi_status;
653692
}
@@ -659,26 +698,34 @@ static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi,
659698
struct qsee_req_uefi_query_variable_info *req_data;
660699
struct qsee_rsp_uefi_query_variable_info *rsp_data;
661700
efi_status_t efi_status = EFI_SUCCESS;
701+
dma_addr_t cmd_buf_dma;
702+
size_t cmd_buf_size;
703+
void *cmd_buf;
704+
size_t req_offs;
705+
size_t rsp_offs;
662706
int status;
663707

664-
req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
665-
if (!req_data) {
708+
cmd_buf_size = qcuefi_buf_align_fields(
709+
__reqdata_offs(sizeof(*req_data), &req_offs)
710+
__reqdata_offs(sizeof(*rsp_data), &rsp_offs)
711+
);
712+
713+
cmd_buf = qseecom_dma_alloc(qcuefi->client, cmd_buf_size, &cmd_buf_dma, GFP_KERNEL);
714+
if (!cmd_buf) {
666715
efi_status = EFI_OUT_OF_RESOURCES;
667716
goto out;
668717
}
669718

670-
rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
671-
if (!rsp_data) {
672-
efi_status = EFI_OUT_OF_RESOURCES;
673-
goto out_free_req;
674-
}
719+
req_data = cmd_buf + req_offs;
720+
rsp_data = cmd_buf + rsp_offs;
675721

676722
req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
677723
req_data->attributes = attr;
678724
req_data->length = sizeof(*req_data);
679725

680-
status = qcom_qseecom_app_send(qcuefi->client, req_data, sizeof(*req_data), rsp_data,
681-
sizeof(*rsp_data));
726+
status = qcom_qseecom_app_send(qcuefi->client,
727+
cmd_buf_dma + req_offs, sizeof(*req_data),
728+
cmd_buf_dma + rsp_offs, sizeof(*rsp_data));
682729
if (status) {
683730
efi_status = EFI_DEVICE_ERROR;
684731
goto out_free;
@@ -711,9 +758,7 @@ static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi,
711758
*max_variable_size = rsp_data->max_variable_size;
712759

713760
out_free:
714-
kfree(rsp_data);
715-
out_free_req:
716-
kfree(req_data);
761+
qseecom_dma_free(qcuefi->client, cmd_buf_size, cmd_buf, cmd_buf_dma);
717762
out:
718763
return efi_status;
719764
}

drivers/firmware/qcom/qcom_scm.c

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,9 +1576,9 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_get_id);
15761576
/**
15771577
* qcom_scm_qseecom_app_send() - Send to and receive data from a given QSEE app.
15781578
* @app_id: The ID of the target app.
1579-
* @req: Request buffer sent to the app (must be DMA-mappable).
1579+
* @req: DMA address of the request buffer sent to the app.
15801580
* @req_size: Size of the request buffer.
1581-
* @rsp: Response buffer, written to by the app (must be DMA-mappable).
1581+
* @rsp: DMA address of the response buffer, written to by the app.
15821582
* @rsp_size: Size of the response buffer.
15831583
*
15841584
* Sends a request to the QSEE app associated with the given ID and read back
@@ -1589,52 +1589,27 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_get_id);
15891589
*
15901590
* Return: Zero on success, nonzero on failure.
15911591
*/
1592-
int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size, void *rsp,
1593-
size_t rsp_size)
1592+
int qcom_scm_qseecom_app_send(u32 app_id, dma_addr_t req, size_t req_size,
1593+
dma_addr_t rsp, size_t rsp_size)
15941594
{
15951595
struct qcom_scm_qseecom_resp res = {};
15961596
struct qcom_scm_desc desc = {};
1597-
dma_addr_t req_phys;
1598-
dma_addr_t rsp_phys;
15991597
int status;
16001598

1601-
/* Map request buffer */
1602-
req_phys = dma_map_single(__scm->dev, req, req_size, DMA_TO_DEVICE);
1603-
status = dma_mapping_error(__scm->dev, req_phys);
1604-
if (status) {
1605-
dev_err(__scm->dev, "qseecom: failed to map request buffer\n");
1606-
return status;
1607-
}
1608-
1609-
/* Map response buffer */
1610-
rsp_phys = dma_map_single(__scm->dev, rsp, rsp_size, DMA_FROM_DEVICE);
1611-
status = dma_mapping_error(__scm->dev, rsp_phys);
1612-
if (status) {
1613-
dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
1614-
dev_err(__scm->dev, "qseecom: failed to map response buffer\n");
1615-
return status;
1616-
}
1617-
1618-
/* Set up SCM call data */
16191599
desc.owner = QSEECOM_TZ_OWNER_TZ_APPS;
16201600
desc.svc = QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER;
16211601
desc.cmd = QSEECOM_TZ_CMD_APP_SEND;
16221602
desc.arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL,
16231603
QCOM_SCM_RW, QCOM_SCM_VAL,
16241604
QCOM_SCM_RW, QCOM_SCM_VAL);
16251605
desc.args[0] = app_id;
1626-
desc.args[1] = req_phys;
1606+
desc.args[1] = req;
16271607
desc.args[2] = req_size;
1628-
desc.args[3] = rsp_phys;
1608+
desc.args[3] = rsp;
16291609
desc.args[4] = rsp_size;
16301610

1631-
/* Perform call */
16321611
status = qcom_scm_qseecom_call(&desc, &res);
16331612

1634-
/* Unmap buffers */
1635-
dma_unmap_single(__scm->dev, rsp_phys, rsp_size, DMA_FROM_DEVICE);
1636-
dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
1637-
16381613
if (status)
16391614
return status;
16401615

0 commit comments

Comments
 (0)