USB: NO_64BIT_SUPPORT behavioral quirk — force 32-bit DMA
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).
This commit is contained in:
@@ -449,8 +449,13 @@ impl<const N: usize> Xhci<N> {
|
||||
|
||||
// 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::<Trb>();
|
||||
let cmd = Ring::new::<N>(cap.ac64(), entries_per_page, true)?;
|
||||
let cmd = Ring::new::<N>(ac64, entries_per_page, true)?;
|
||||
|
||||
let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded();
|
||||
|
||||
@@ -467,11 +472,11 @@ impl<const N: usize> Xhci<N> {
|
||||
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::<N>(cap.ac64())?),
|
||||
primary_event_ring: Mutex::new(EventRing::new::<N>(ac64)?),
|
||||
handles: CHashMap::new(),
|
||||
next_handle: AtomicUsize::new(0),
|
||||
port_states: CHashMap::new(),
|
||||
@@ -963,7 +968,7 @@ impl<const N: usize> Xhci<N> {
|
||||
if buf_count == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let scratchpad_buf_arr = ScratchpadBufferArray::new::<N>(self.cap.ac64(), buf_count)?;
|
||||
let scratchpad_buf_arr = ScratchpadBufferArray::new::<N>(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<const N: usize> Xhci<N> {
|
||||
((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<T>(_ac64: bool) -> Result<Dma<T>> {
|
||||
// TODO: ac64
|
||||
Ok(Dma::zeroed()?.assume_init())
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed<T>(&self) -> Result<Dma<T>> {
|
||||
Self::alloc_dma_zeroed_raw(self.cap.ac64())
|
||||
Self::alloc_dma_zeroed_raw(self.ac64_effective())
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed_unsized_raw<T>(_ac64: bool, count: usize) -> Result<Dma<[T]>> {
|
||||
// TODO: ac64
|
||||
Ok(Dma::zeroed_slice(count)?.assume_init())
|
||||
}
|
||||
pub unsafe fn alloc_dma_zeroed_unsized<T>(&self, count: usize) -> Result<Dma<[T]>> {
|
||||
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<const N: usize> Xhci<N> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut ring = Ring::new::<N>(self.cap.ac64(), 16, true)?;
|
||||
let mut ring = Ring::new::<N>(self.ac64_effective(), 16, true)?;
|
||||
|
||||
{
|
||||
input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit).
|
||||
|
||||
Reference in New Issue
Block a user