Hi Cédric, Philippe

> Subject: Re: [PATCH v6 00/11] hw/usb/ehci: Add 64-bit descriptor addressing
> support
> 
> On 7/9/26 23:09, Philippe Mathieu-Daudé wrote:
> > On 12/5/26 16:47, Cédric Le Goater wrote:
> >> + Gerd, Marc-André,
> >>
> >> May be they can provide some more feedback.
> >>
> >> On 5/11/26 08:13, Cédric Le Goater wrote:
> >>> On 5/4/26 07:27, Cédric Le Goater wrote:
> >>>> On 5/4/26 04:53, Jamin Lin wrote:
> >>>>> EHCI supports 64-bit addressing through the CTRLDSSEGMENT
> >>>>> register, which provides the upper 32 bits of descriptor addresses
> >>>>> when the controller advertises 64-bit capability.
> >>>>>
> >>>>> Currently QEMU EHCI model only partially supports this
> >>>>> functionality and descriptor addresses are effectively treated as
> >>>>> 32-bit. This becomes problematic on systems where system memory is
> >>>>> located above the 4GB boundary.
> >>>>>
> >>>>> The Linux EHCI driver enables 64-bit addressing if the controller
> >>>>> advertises the capability. During initialization it programs the
> >>>>> segment register to zero:
> >>>>>
> >>>>>    https://github.com/torvalds/linux/blob/master/drivers/usb/host/
> >>>>> ehci-hcd.c#L600
> >>>>>
> >>>>> The driver also notes that descriptor structures allocated from
> >>>>> the DMA pool use segment zero semantics. Descriptor memory is
> >>>>> allocated using the DMA API and platforms may configure a 64-bit
> >>>>> DMA mask, allowing descriptor memory to be placed above 4GB.
> >>>>>
> >>>>> On AST2700 platforms, system DRAM is mapped at 0x400000000. As a
> >>>>> result, descriptor addresses constructed directly from the EHCI
> >>>>> registers do not match the actual system addresses used by the
> >>>>> controller when accessing queue heads (QH) and queue element
> >>>>> transfer descriptors (qTD).
> >>>>>
> >>>>> This patch series implements full 64-bit descriptor addressing
> >>>>> support in the EHCI emulation. Descriptor address handling is
> >>>>> updated to use 64-bit values and the descriptor structures (QH,
> >>>>> qTD, iTD and siTD) are extended to support the upper address bits
> >>>>> provided by the segment register.
> >>>>>
> >>>>> Add a ctrldssegment-default property so platforms can provide a
> >>>>> descriptor address offset when constructing descriptor addresses.
> >>>>> This allows systems where DRAM resides above 4GB to access EHCI
> >>>>> descriptors correctly.
> >>>>>
> >>>>> The AST2700 machine uses this property to account for its DRAM
> >>>>> mapping at 0x400000000 and enables 64-bit EHCI DMA addressing.
> >>>>>
> >>>>> Test Result:
> >>>>> 1. EHCI 32bits with ast2600-evb machine Command line:
> >>>>> ./build/qemu-system-arm \
> >>>>>    -machine ast2600-evb \
> >>>>>    -m 1G \
> >>>>>    -drive file=image-bmc,if=mtd,format=raw \
> >>>>>    -nographic \
> >>>>>    -device usb-kbd,bus=usb-bus.1,id=mykbd \
> >>>>>    -drive id=usbdisk,if=none,file=image0.ext4,format=raw \
> >>>>>    -device usb-storage,bus=usb-bus.1,id=mystorage,drive=usbdisk
> >>>>>    -snapshot \
> >>>>>    -nographic
> >>>>> Result:
> >>>>> unable to initialize usb specBus 001 Device 001: ID 1d6b:0002
> >>>>> Linux 6.18.3-v00.08.01-g172b7e27a30d ehci_hcd EHCI Host Controller
> >>>>> Bus 001 Device 002: ID 0627:0001 QEMU QEMU USB Keyboard Bus 001
> >>>>> Device 003: ID 46f4:0001 QEMU QEMU USB HARDDRIVE Bus 002
> Device
> >>>>> 001: ID 1d6b:0001 Linux 6.18.3-v00.08.01- g172b7e27a30d uhci_hcd
> >>>>> Generic UHCI Host Controller
> >>>>>
> >>>>> 2. EHCI 64bits with ast2700a2-evb machine Command line:
> >>>>> ./build/qemu-system-aarch64 -M ast2700a2-evb -nographic\
> >>>>>   -bios ast27x0_bootrom.bin \
> >>>>>   -drive file=image-bmc,format=raw,if=mtd \
> >>>>>   -snapshot \
> >>>>>   -device usb-kbd,bus=usb-bus.3,id=mykbd \
> >>>>>   -drive id=usbdisk,if=none,file=image0.ext4,format=raw \
> >>>>>   -device usb-storage,bus=usb-bus.3,id=mystorage,drive=usbdisk
> >>>>> Result:
> >>>>> root@ast2700-default:~# lsusb
> >>>>> unable to initialize usb specBus 001 Device 001: ID 1d6b:0001
> >>>>> Linux 6.18.3-v00.08.01-g172b7e27a30d uhci_hcd Generic UHCI Host
> >>>>> Controller Bus 002 Device 001: ID 1d6b:0002 Linux
> >>>>> 6.18.3-v00.08.01- g172b7e27a30d ehci_hcd EHCI Host Controller Bus
> >>>>> 002 Device 002: ID 0627:0001 QEMU QEMU USB Keyboard Bus 002
> Device
> >>>>> 003: ID 46f4:0001 QEMU QEMU USB HARDDRIVE
> >>>>> v1
> >>>>>   1. Fix checkpatch coding style issues
> >>>>>   2. Implement 64-bit addressing for QH/qTD/iTD/siTD descriptors
> >>>>>   3. Add descriptor address offset property
> >>>>>   4. Enable 64-bit EHCI DMA addressing on AST2700
> >>>>>   5. Configure descriptor address offset for AST2700
> >>>>>
> >>>>> v2
> >>>>>   1. Remove unused EHCIfstn structure and dead code
> >>>>>   2. Replace fprintf(stderr, ...) with
> >>>>> qemu_log_mask(LOG_GUEST_ERROR)
> >>>>>   3. Replace DPRINTF debug logs with trace events
> >>>>>   4. Add functional tests for USB EHCI on AST2600 and AST2700
> >>>>> A1/A2
> >>>>>   5. Fix review issue
> >>>>>
> >>>>> v3:
> >>>>>   1. Add Migration version test function
> >>>>>   2. Add EHCI 64-bit buffer pointer fields description in commit
> >>>>> log
> >>>>>
> >>>>> v4:
> >>>>>   1. Reorder patches in the series
> >>>>>   2. Fix EHCI migration issues
> >>>>>   3. Introduce a common properties macro for both sysbus and PCI
> >>>>>   4. Drop the descriptor address offset property
> >>>>>   5. Add ctrldssegment-default property
> >>>>>   6. Address review comments
> >>>>>
> >>>>> v5:
> >>>>>   1. Add 11.0 machine compatibility properties
> >>>>>
> >>>>> v6:
> >>>>>   1. Update reviewer suggested improvements.
> >>>>> Jamin Lin (11):
> >>>>>    tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test
> >>>>> for
> >>>>>      AST2600 SDK
> >>>>>    hw/usb/hcd-ehci: Change descriptor addresses to 64-bit with
> >>>>> migration
> >>>>>      compatibility
> >>>>>    hw/usb/hcd-ehci: Add property to advertise 64-bit addressing
> >>>>>      capability
> >>>>>    hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
> >>>>>    hw/usb/hcd-ehci: Implement 64-bit qTD descriptor addressing
> >>>>>    hw/usb/hcd-ehci: Implement 64-bit iTD descriptor addressing
> >>>>>    hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing
> >>>>>    hw/usb/hcd-ehci: Add ctrldssegment-default property
> >>>>>    hw/arm/aspeed_ast27x0: Set EHCI ctrldssegment-default
> >>>>>    hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing
> >>>>>    tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test
> >>>>> for
> >>>>>      AST2700 A1/A2
> >>>>>
> >>>>>   hw/usb/hcd-ehci.h                             |  2
> 9 +++-
> >>>>>   hw/arm/aspeed_ast27x0.c                       |   5
> +
> >>>>>   hw/core/machine.c                             |
>  5 +-
> >>>>>   hw/usb/hcd-ehci.c                             | 162
> ++++++++++++
> >>>>> +-----
> >>>>>   hw/usb/trace-events                           |  26
> +--
> >>>>>   .../aarch64/test_aspeed_ast2700a1.py          |   7 +
> >>>>>   .../aarch64/test_aspeed_ast2700a2.py          |   7 +
> >>>>>   .../functional/arm/test_aspeed_ast2600_sdk.py |   7 +
> >>>>>   8 files changed, 185 insertions(+), 63 deletions(-)
> >>>>>
> >>>>
> >>>> Applied to
> >>>>
> >>>>      https://github.com/legoater/qemu aspeed-next
> >>>
> >>> Jamin,
> >>>
> >>> I dropped the series from aspeed-next and kept :
> >>>
> >>>    tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test
> >>> for AST2600 SDK
> >>>
> >>> The USB subsystem is orphan but it is still used in the virt world.
> >>> This series is modifying the EHCI internals in such way that
> >>> migration is impacted and the CTRLDSSEGMENT (Control Data Structure
> >>> Segment
> >>> Register) implementation is incomplete AFAICT. From EHCI specs :
> >>>
> >>>     This register allows the host software to locate all control
> >>> data
> >>>     structures within the *same 4 Gigabyte memory segment*.
> >>>
> >>> Linux driver seems buggy too.
> >>>
> >>> Overall, the risk of regression is too high given the time I can
> >>> dedicate to this topic.
> >>>
> >>> Thanks for all the good work you done there, specially for migration.
> >>> If someone can Ack the series and step forward to become USB
> >>> maintainer, then I will reconsider.
> >
> > I'm not an USB expert / maintainer but FWIW this series looked good
> > enough to me when I looked at it. Maybe consider to merge after the
> > 11.1 release?
> 
> Yes. I would like to too but ...
> 
> The change in size of the EHCIqh and EHCIitd descriptors is a bit worrying 
> since
> these are used for guest DMA, see ehci_flush_qh(), or compare, see
> ehci_verify_qh().
> 
> This should be fine for Linux, which has support since day one. Other older
> guest OSes may not allocate the extra space. This is a 20+ year old spec so 
> the
> risk is probably low but I don't have the expertise to assess the impact tbh.
> 
> Anyhow if we want the model to be correct, we should not write beyond
> spec-defined descriptor boundaries when in 32-bit mode.
> 
> More work ...
> 
> Thanks,
> 
> C.

Thanks for pointing this out.

I agree that even though the QEMU internal EHCIqh, EHCIqtd, and EHCIitd 
structures include the extended high buffer pointer fields, we must not access 
those fields in guest memory when 64-bit addressing capability is not 
advertised.

I have updated the patch accordingly.

The descriptor DMA size is now selected based on caps_64bit_addr:

When 64-bit addressing is supported and advertised, the complete descriptor, 
including the high buffer pointer fields, is transferred.
In 32-bit mode, DMA reads and writes stop at the beginning of bufptr_hi, so 
QEMU does not access memory beyond the descriptor layout defined for 32-bit 
addressing.

I also clear the local descriptor structures before partial DMA reads. 
Therefore, the high buffer pointer fields remain zero in 32-bit mode rather 
than containing stale or uninitialized values.

This has been applied to:

QH fetching, verification, and writeback
qTD fetching and verification
iTD fetching and writeback

For example:
/*
 * EHCIqh / EHCIqtd / EHCIitd are sized to always include the extended
 * high buffer pointer fields from EHCI 1.0 Appendix B. When 64-bit
 * addressing capability is not advertised to the guest, the descriptors
 * in guest memory only have the classic 32-bit layout, so DMA transfers
 * must not read or write past that boundary.
 */
#define EHCI_QH_DWORDS_32   (offsetof(EHCIqh,  bufptr_hi) / sizeof(uint32_t))
#define EHCI_QTD_DWORDS_32  (offsetof(EHCIqtd, bufptr_hi) / sizeof(uint32_t))
#define EHCI_ITD_DWORDS_32  (offsetof(EHCIitd, bufptr_hi) / sizeof(uint32_t))

#define EHCI_QH_DWORDS_32 \
    (offsetof(EHCIqh, bufptr_hi) / sizeof(uint32_t))

static uint32_t ehci_qh_dwords(const EHCIState *s)
{
    return s->caps_64bit_addr ?
           (sizeof(EHCIqh) >> 2) : EHCI_QH_DWORDS_32;
}

ehci_flush_qh() now uses this selected size, so in 32-bit mode it will not 
write the extended high buffer pointer fields back to guest memory.

Similarly, ehci_state_fetchqtd() only reads qtd.bufptr_hi when caps_64bit_addr 
is enabled:

memset(qtd.bufptr_hi, 0, sizeof(qtd.bufptr_hi));

if (... ||
    (q->ehci->caps_64bit_addr &&
         get_dwords(q->ehci, addr + offsetof(EHCIqtd, bufptr_hi),
                    qtd.bufptr_hi, ARRAY_SIZE(qtd.bufptr_hi)) < 0)) {    return 
0;
}

This should preserve compatibility with guests that allocate only the original 
32-bit EHCI descriptor size, while still allowing the model to support the 
extended 64-bit descriptor layout.
If you think this approach looks OK, I'll include it in the next revision (v7).

Thanks,
Jamin

Reply via email to