From: Jeuk Kim <[email protected]>
A guest can ring an MCQ CQ doorbell before the completion queue exists.
The CQ head write path then dereferences a NULL CQ through
ufs_mcq_cq_full().
Ignore CQ head updates for missing CQs, and make ufs_mcq_cq_full()
handle a missing CQ defensively.
Fixes: f78762a3cc8 ("hw/ufs: Fix mcq completion queue wraparound")
Reported-by: Rayhan Ramdhany Hanaputra <[email protected]>
Cc: [email protected]
Signed-off-by: Jeuk Kim <[email protected]>
---
hw/ufs/ufs.c | 4 ++++
hw/ufs/ufs.h | 9 ++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index d5fba15e2a..1819ba2e8a 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -817,6 +817,10 @@ static void ufs_write_mcq_op_reg(UfsHc *u, hwaddr offset,
uint32_t data,
case offsetof(UfsMcqOpReg, cq.hp): {
UfsCq *cq = u->cq[qid];
+ if (!cq) {
+ break;
+ }
+
if (ufs_mcq_cq_full(u, qid) && !QTAILQ_EMPTY(&cq->req_list)) {
/* Enqueueing to CQ was blocked because it was full */
qemu_bh_schedule(cq->bh);
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index 13d964c5ae..9e800cafac 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -203,7 +203,14 @@ static inline bool ufs_mcq_cq_empty(UfsHc *u, uint32_t qid)
static inline bool ufs_mcq_cq_full(UfsHc *u, uint32_t qid)
{
uint32_t tail = ufs_mcq_cq_tail(u, qid);
- uint16_t cq_size = u->cq[qid]->size;
+ UfsCq *cq = u->cq[qid];
+ uint16_t cq_size;
+
+ if (!cq) {
+ return false;
+ }
+
+ cq_size = cq->size;
tail = (tail + sizeof(UfsCqEntry)) % (sizeof(UfsCqEntry) * cq_size);
return tail == ufs_mcq_cq_head(u, qid);
--
2.43.0