From: Jeuk Kim <[email protected]>
Reject SQATTR.SIZE and CQATTR.SIZE values that produce zero-entry MCQ
queues. Such queues can later trigger a divide-by-zero while advancing
queue pointers.
Fixes: 5c079578d2e ("hw/ufs: Add support MCQ of UFSHCI 4.0")
Cc: [email protected]
Signed-off-by: Jeuk Kim <[email protected]>
---
hw/ufs/trace-events | 2 ++
hw/ufs/ufs.c | 18 ++++++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
index 531dcfc686..7734b35f08 100644
--- a/hw/ufs/trace-events
+++ b/hw/ufs/trace-events
@@ -40,10 +40,12 @@ ufs_err_mcq_db_wr_invalid_sqid(uint8_t qid) "invalid mcq
sqid %"PRIu8""
ufs_err_mcq_db_wr_invalid_db(uint8_t qid, uint32_t db) "invalid mcq doorbell
sqid %"PRIu8", db %"PRIu32""
ufs_err_mcq_create_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
ufs_err_mcq_create_sq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
+ufs_err_mcq_create_sq_invalid_size(uint8_t qid) "invalid mcq sq size for sqid
%"PRIu8""
ufs_err_mcq_create_sq_already_exists(uint8_t qid) "mcq sqid %"PRIu8 "already
exists"
ufs_err_mcq_delete_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
ufs_err_mcq_delete_sq_not_exists(uint8_t qid) "mcq sqid %"PRIu8 "not exists"
ufs_err_mcq_create_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
+ufs_err_mcq_create_cq_invalid_size(uint8_t qid) "invalid mcq cq size for cqid
%"PRIu8""
ufs_err_mcq_create_cq_already_exists(uint8_t qid) "mcq cqid %"PRIu8 "already
exists"
ufs_err_mcq_delete_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
ufs_err_mcq_delete_cq_not_exists(uint8_t qid) "mcq cqid %"PRIu8 "not exists"
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 1819ba2e8a..4ccd7aa64d 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -506,6 +506,8 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid,
uint32_t attr)
UfsMcqReg *reg = &u->mcq_reg[qid];
UfsSq *sq;
uint8_t cqid = FIELD_EX32(attr, SQATTR, CQID);
+ uint16_t qsize =
+ ((FIELD_EX32(attr, SQATTR, SIZE) + 1) << 2) / sizeof(UfsSqEntry);
if (qid >= u->params.mcq_maxq) {
trace_ufs_err_mcq_create_sq_invalid_sqid(qid);
@@ -527,12 +529,17 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid,
uint32_t attr)
return false;
}
+ if (!qsize) {
+ trace_ufs_err_mcq_create_sq_invalid_size(qid);
+ return false;
+ }
+
sq = g_malloc0(sizeof(*sq));
sq->u = u;
sq->sqid = qid;
sq->cq = u->cq[cqid];
sq->addr = ((uint64_t)reg->squba << 32) | reg->sqlba;
- sq->size = ((FIELD_EX32(attr, SQATTR, SIZE) + 1) << 2) /
sizeof(UfsSqEntry);
+ sq->size = qsize;
sq->bh = qemu_bh_new_guarded(ufs_mcq_process_sq, sq,
&DEVICE(u)->mem_reentrancy_guard);
@@ -576,6 +583,8 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid,
uint32_t attr)
{
UfsMcqReg *reg = &u->mcq_reg[qid];
UfsCq *cq;
+ uint16_t qsize =
+ ((FIELD_EX32(attr, CQATTR, SIZE) + 1) << 2) / sizeof(UfsCqEntry);
if (qid >= u->params.mcq_maxq) {
trace_ufs_err_mcq_create_cq_invalid_cqid(qid);
@@ -587,11 +596,16 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid,
uint32_t attr)
return false;
}
+ if (!qsize) {
+ trace_ufs_err_mcq_create_cq_invalid_size(qid);
+ return false;
+ }
+
cq = g_malloc0(sizeof(*cq));
cq->u = u;
cq->cqid = qid;
cq->addr = ((uint64_t)reg->cquba << 32) | reg->cqlba;
- cq->size = ((FIELD_EX32(attr, CQATTR, SIZE) + 1) << 2) /
sizeof(UfsCqEntry);
+ cq->size = qsize;
cq->bh = qemu_bh_new_guarded(ufs_mcq_process_cq, cq,
&DEVICE(u)->mem_reentrancy_guard);
--
2.43.0