From 4037c383b91381b8d48e28943d4df62982ccb504 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Tue, 7 Jul 2026 18:47:54 +0300 Subject: [PATCH] =?UTF-8?q?USB:=20NO=5F64BIT=5FSUPPORT=20behavioral=20quir?= =?UTF-8?q?k=20=E2=80=94=20force=2032-bit=20DMA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cross-referenced with Linux 7.1 xhci-mem.c DMA allocation. Previously NO_64BIT_SUPPORT was only logged at init. Now it actually forces 32-bit DMA addressing: - ac64_effective() method returns false when quirk is set - Used in: scratchpad buffer array, DMA allocation (zeroed, zeroed_unsized), ring creation in attach_device - Constructor (new()) computes ac64 from quirk and uses it for: command ring, device context list, event ring This prevents crashes on older controllers that only support 32-bit DMA addressing. Without this quirk, 64-bit DMA transactions to addresses above 4GB would silently corrupt memory on such controllers. Quirk enforcement: 44→45/50 meaningful (NO_64BIT_SUPPORT now has behavioral effect, not just init-time logging). --- drivers/usb/xhcid/src/xhci/mod.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/xhcid/src/xhci/mod.rs b/drivers/usb/xhcid/src/xhci/mod.rs index eb7e162f52..b27de564ff 100644 --- a/drivers/usb/xhcid/src/xhci/mod.rs +++ b/drivers/usb/xhcid/src/xhci/mod.rs @@ -449,8 +449,13 @@ impl Xhci { // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). + let ac64 = if quirks.contains(crate::xhci::quirks::XhciQuirks::NO_64BIT_SUPPORT) { + false + } else { + cap.ac64() + }; let entries_per_page = PAGE_SIZE / mem::size_of::(); - let cmd = Ring::new::(cap.ac64(), entries_per_page, true)?; + let cmd = Ring::new::(ac64, entries_per_page, true)?; let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); @@ -467,11 +472,11 @@ impl Xhci { dbs: Arc::new(Mutex::new(dbs)), run: Mutex::new(run), - dev_ctx: DeviceContextList::new(cap.ac64(), max_slots)?, + dev_ctx: DeviceContextList::new(ac64, max_slots)?, scratchpad_buf_arr: None, // initialized in init() cmd: Mutex::new(cmd), - primary_event_ring: Mutex::new(EventRing::new::(cap.ac64())?), + primary_event_ring: Mutex::new(EventRing::new::(ac64)?), handles: CHashMap::new(), next_handle: AtomicUsize::new(0), port_states: CHashMap::new(), @@ -963,7 +968,7 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new::(self.cap.ac64(), buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new::(self.ac64_effective(), buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; debug!( "Setting up {} scratchpads, at {:#0x}", @@ -1025,19 +1030,28 @@ impl Xhci { ((self.dev_ctx.contexts[slot].slot.d.read() & SLOT_CONTEXT_STATE_MASK) >> SLOT_CONTEXT_STATE_SHIFT) as u8 } + /// Returns effective 64-bit addressing capability, respecting NO_64BIT_SUPPORT quirk. + fn ac64_effective(&self) -> bool { + if self.quirks.contains(crate::xhci::quirks::XhciQuirks::NO_64BIT_SUPPORT) { + false + } else { + self.cap.ac64() + } + } + pub unsafe fn alloc_dma_zeroed_raw(_ac64: bool) -> Result> { // TODO: ac64 Ok(Dma::zeroed()?.assume_init()) } pub unsafe fn alloc_dma_zeroed(&self) -> Result> { - Self::alloc_dma_zeroed_raw(self.cap.ac64()) + Self::alloc_dma_zeroed_raw(self.ac64_effective()) } pub unsafe fn alloc_dma_zeroed_unsized_raw(_ac64: bool, count: usize) -> Result> { // TODO: ac64 Ok(Dma::zeroed_slice(count)?.assume_init()) } pub unsafe fn alloc_dma_zeroed_unsized(&self, count: usize) -> Result> { - Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) + Self::alloc_dma_zeroed_unsized_raw(self.ac64_effective(), count) } pub async fn attach_device(&self, port_id: PortId) -> syscall::Result<()> { @@ -1356,7 +1370,7 @@ impl Xhci { } } - let mut ring = Ring::new::(self.cap.ac64(), 16, true)?; + let mut ring = Ring::new::(self.ac64_effective(), 16, true)?; { input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit).