USB: eliminate all 6 panic!() sites in xhcid hot paths

irq_reactor.rs (4→0):
- EventTrbFuture::poll() on Finished: panic → log::error + Poll::Pending
- next_transfer_event_trb(): panic on invalid TRB type → log::error
- next_command_completion_event_trb(): panic → log::error
- next_misc_event_trb(): panic → log::error

ring.rs (1→0):
- trb_phys_ptr(): panic on out-of-bounds TRB → log::error + return 0

main.rs (1→0):
- feature_info Msi variant mismatch: panic → log::error + fallback to Polling

Rationale: A malformed hardware TRB or transient PCID state inconsistency
must not crash the IRQ reactor thread — these are the highest-risk
single-point failures in the USB hotplug path.  Now degrades gracefully
with error logging and safe fallbacks (zero physical address, Polling
interrupt method, Poll::Pending state).
This commit is contained in:
Red Bear OS
2026-07-07 17:30:43 +03:00
parent 21cf3d900c
commit 171d8c5258
3 changed files with 13 additions and 6 deletions
+4 -1
View File
@@ -64,7 +64,10 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option<File>, Interru
if has_msix {
let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) {
PciFeatureInfo::Msi(_) => panic!(),
PciFeatureInfo::Msi(_) => {
log::error!("xhcid: feature_info returned Msi despite has_msix=true — falling back to MSI path");
return (None, InterruptMethod::Polling);
}
PciFeatureInfo::MsiX(s) => s,
};
let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) };
+7 -4
View File
@@ -622,7 +622,10 @@ impl Future for EventTrbFuture {
return task::Poll::Pending;
}
},
&mut Self::Finished => panic!("Polling finished EventTrbFuture again."),
&mut Self::Finished => {
log::error!("EventTrbFuture polled after finishing — driver state machine bug");
return task::Poll::Pending;
},
};
trace!("finished!");
*this = Self::Finished;
@@ -674,7 +677,7 @@ impl<const N: usize> Xhci<N> {
doorbell: EventDoorbell,
) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
if !last_trb.is_transfer_trb() {
panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", last_trb.trb_type(), last_trb)
log::error!("next_transfer_event_trb: invalid TRB type {} — expected transfer TRB. TRB: {:?}", last_trb.trb_type(), last_trb);
}
let is_isoch_or_vf = last_trb.trb_type() == TrbType::Isoch as u8;
@@ -705,7 +708,7 @@ impl<const N: usize> Xhci<N> {
command_ring.trb_phys_ptr(self.cap.ac64(), trb)
);
if !trb.is_command_trb() {
panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb)
log::error!("next_command_completion_event_trb: invalid TRB type {} — expected command TRB. TRB: {:?}", trb.trb_type(), trb);
}
EventTrbFuture::Pending {
state: FutureState {
@@ -733,7 +736,7 @@ impl<const N: usize> Xhci<N> {
TrbType::MfindexWrap as u8,
];
if !valid_trb_types.contains(&(trb_type as u8)) {
panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type)
log::error!("next_misc_event_trb: invalid TRB type {:?} — not in valid misc event TRB types list", trb_type);
}
EventTrbFuture::Pending {
state: FutureState {
+2 -1
View File
@@ -116,7 +116,8 @@ impl Ring {
|| (trb_virt_pointer as usize)
> (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::<Trb>()
{
panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb);
log::error!("trb_phys_ptr: TRB outside ring bounds. TRB: {:?} (at {:p}) — returning 0", trb, trb);
return 0;
}
let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64;