Skip to content

Rebase UFS controller - #166

Draft
Jerome Haxhiaj (jeromehaxhiaj-qti) wants to merge 17 commits into
libqemu/v11.0from
ufs_rework
Draft

Jerome Haxhiaj (jeromehaxhiaj-qti) wants to merge 17 commits into
libqemu/v11.0from
ufs_rework

Conversation

@jeromehaxhiaj-qti

Copy link
Copy Markdown
  • Rebase UFS controller from mainsteam which brings better support for UFS4.1
  • Rework sysbus UFS

DO NO MERGE. This PR reverts multiple libqemu specific commits which should be discarded in the next rebase of libqemu.

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: f78762a ("hw/ufs: Fix mcq completion queue wraparound")
Reported-by: Rayhan Ramdhany Hanaputra <hanaputrarayhan@gmail.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
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: 5c07957 ("hw/ufs: Add support MCQ of UFSHCI 4.0")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
MCQ requests are allocated with their SQ, but can remain in flight on the
CQ list or in the SCSI layer after leaving the SQ free list.

Reject runtime SQ deletion while any request is still outstanding, and
use separate teardown helpers so device exit can still release MCQ
queues after child devices have been unrealized.

Fixes: 5c07957 ("hw/ufs: Add support MCQ of UFSHCI 4.0")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
ufs_emulate_report_luns() writes the 4-byte LUN list length into
outbuf[0..3] via stl_be_p() but leaves outbuf[4..7], the reserved
field, uninitialized. Those bytes are then DMA'd to guest memory,
leaking uninitialized QEMU stack data.

Fixes: 7708e29 ("hw/ufs/lu: skip automatic zero-init of large array")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Apply current UFS 4.1 Specification to QEMU-UFS.

QEMU-UFS device emulates operation via UFS 4.0 Specification,
but current latest Spec. version is UFS 4.1. So extent internal
DESCRIPTOR/FLAG/ATTRIBUTE declaration to follow UFS 4.1 Spec.

It does not implement any actual functionallity, but only adds
minimum supportability for further implementation.

Signed-off-by: Jaemyung Lee <jaemyung.lee@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Change internal flag handling operation same as attribute's

In UFS device, some flag queries directly trigger specific device
behaviour like attribute's, not only changes the internal values.
So restructure flag query processing functions same as attribute
processing, to facilitate linking detailed implementations based on
individual flag value changes.

Signed-off-by: Jaemyung Lee <jaemyung.lee@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
When no I/O occurs, the UFS Device performs various internal operations.
To emulate this, adds a timer that periodically checks the current I/O
status of the device and call the ufs_process_idle() function when idle.

Signed-off-by: Jaemyung Lee <jaemyung.lee@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Add UFS Write Booster implementation which follows UFS 4.1 Spec.

Signed-off-by: Jaemyung Lee <jaemyung.lee@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Emulate the UFS HID extended feature. Host interacts via five
attributes (IDN 0x35-0x39):

  bDefragOperation   trigger: Disable / Analysis / Defrag
  dHIDAvailableSize  fragmented 4KB units (published by analysis)
  dHIDSize           host-requested defrag target (4KB units)
  bHIDProgressRatio  0-100%; reading 100 resets HID
  bHIDState          current state; terminal-state read resets HID

Successful user-data SCSI WRITE commands increment an internal
fragment counter; HID analysis publishes the counter through
dHIDAvailableSize. Defrag operates on min(dHIDSize,
dHIDAvailableSize), so a small dHIDSize yields a partial defrag.
bDefragOperation auto-clears on terminal state. The state machine
advances from ufs_process_idle(); transitions occur only while the
device is idle.

Signed-off-by: Keoseong Park <keosung.park@samsung.com>
Reviewed-by: Jeuk Kim <jeuk20.kim@samsung.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
After DME_LINK_STARTUP a UFSHCI host typically negotiates the link power
mode: it reads PA layer attributes (connected RX/TX data lanes, max RX
HS/PWM gears) via DME_GET and then issues DME_SET(PA_PWRMODE), waiting for
the UIC power-mode-change completion (IS.UPMS / HCS.UPMCRS). The device
only handled DME_LINK_STARTUP and DME_HIBER_{ENTER,EXIT} and returned
FAILURE for every other DME command, so a host that performs power-mode
change could never complete it.

Return canned PA attribute values (1 lane, HS-G4, FAST_MODE) on
DME_GET/PEER_GET and acknowledge DME_SET/PEER_SET. For DME_SET(PA_PWRMODE)
also raise IS.UPMS and set HCS.UPMCRS=PWR_LOCAL so the power-mode change
completes. The emulated link has no PHY, so no state is persisted.

For example, the Linux ufshcd driver reads these attributes during probe
and otherwise aborts with "invalid connected lanes value".

Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
In UFSHCI 4.1 the MCQ completion queue entry carries the request tag in
the cqe.task_tag field (DW5), whereas 4.0 hosts derive it from the UTP
command descriptor base address. The device reports version 4.1 in the VER
register but left task_tag/lun zero in the completion path, so a
4.1-compliant host reads tag 0 for every completion and cannot match it to
the outstanding request.

Add the task_tag/lun/iid fields to UfsCqEntry per the UFSHCI 4.1 CQE
layout and populate them from the request UPIU header.

For example, the Linux ufshcd_mcq_get_tag() uses cqe.task_tag for
version >= 4.1, so without this SCSI commands hung (e.g. INQUIRY to the
device W-LUN) while device-management commands still completed.

Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
ufs_init_scsi_device() creates an internal scsi-hd and adds it as a
child of lu->bus. qdev_realize_and_unref() then drops the construction
reference, leaving the bus child ownership to tear it down.

ufs_lu_unrealize() still unrefs lu->scsi_dev directly. If the UFS
controller is ejected through ACPI PCI hotplug, the scsi-hd object can be
finalized there and then the bus child removal RCU callback later unrefs
the same object again.

Keep lu->scsi_dev as a borrowed pointer and clear it during unrealize
without unreffing it.

Add a qtest that ejects the UFS controller through the x86 ACPI PCI
hotplug eject register. On an ASAN build, the test reproduces the UAF
before the fix.

Fixes: 096434f ("hw/ufs: Modify lu.c to share codes with SCSI subsystem")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
This change enables the access of the UFS controllers via
MMIO.

Signed-off-by: Jerome Haxhiaj <jhaxhiaj@qti.qualcomm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants