Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,10 @@ scripts/__pycache__

# Third-party sources and build artifacts (cloned/built locally)
third-party/

# EFI System Partition build artifact
esp/

# Debug capture files
serial-capture*.txt
xhci_ftrace*.txt
22 changes: 22 additions & 0 deletions kernel/src/arch_impl/aarch64/gic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,10 @@ pub fn configure_spi_edge_triggered(irq: u32) {
///
/// Also routes the SPI to the current CPU via ITARGETSR (GICv2) or
/// IROUTER (GICv3). Only valid for IRQs >= 32 (SPIs).
///
/// Includes DSB+ISB to ensure the GICD write completes before returning.
/// Without this, the CPU write buffer may delay the enable, causing the
/// caller to miss an immediate pending interrupt.
pub fn enable_spi(irq: u32) {
if irq < 32 {
return; // Only SPIs (32+)
Expand Down Expand Up @@ -553,18 +557,36 @@ pub fn enable_spi(irq: u32) {
}

gicd_write(GICD_ISENABLER + (reg_index as usize * 4), 1 << bit);
// DSB ensures the GICD write has completed (drained from write buffer)
// before we return. ISB ensures subsequent instructions see the effect.
unsafe {
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb", options(nomem, nostack));
}
}

/// Disable an SPI in the GIC distributor (GICD_ICENABLER).
///
/// Only valid for IRQs >= 32 (SPIs).
///
/// Includes DSB+ISB to ensure the GICD write has completed before
/// returning. Without this, subsequent MMIO operations (e.g., xHC ERDP
/// writes) could trigger new MSIs before the disable takes effect,
/// causing interrupt storms on virtual xHCI controllers.
pub fn disable_spi(irq: u32) {
if irq < 32 {
return; // Only SPIs (32+)
}
let reg_index = irq / 32;
let bit = irq % 32;
gicd_write(GICD_ICENABLER + (reg_index as usize * 4), 1 << bit);
// DSB ensures the GICD write has completed (drained from write buffer)
// before we return. This is critical in interrupt handlers where
// subsequent MMIO to other devices (xHC) could generate new MSIs.
unsafe {
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb", options(nomem, nostack));
}
}

/// Clear any pending state for an SPI (write-1-to-clear via GICD_ICPENDR).
Expand Down
53 changes: 47 additions & 6 deletions kernel/src/arch_impl/aarch64/timer_interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ pub extern "C" fn timer_interrupt_handler() {
// Increment timer interrupt counter (used for debugging when needed)
let _count = TIMER_INTERRUPT_COUNT.fetch_add(1, Ordering::Relaxed) + 1;

// Debug breadcrumb: print '.' every 200 ticks (~1 second) to verify timer is alive
if cpu_id == 0 && _count % 200 == 0 {
raw_serial_char(b'.');
}

// CPU 0 only: poll input devices (single-device, not safe from multiple CPUs)
if cpu_id == 0 {
poll_keyboard_to_stdin();
Expand Down Expand Up @@ -227,20 +232,22 @@ pub extern "C" fn timer_interrupt_handler() {
print_timer_count_decimal(crate::drivers::usb::xhci::KBD_EVENT_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" xo=");
print_timer_count_decimal(crate::drivers::usb::xhci::XFER_OTHER_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" xe=");
print_timer_count_decimal(crate::drivers::usb::xhci::XO_ERR_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" xi=");
print_hex_u64(crate::drivers::usb::xhci::XO_LAST_INFO.load(Ordering::Relaxed));
raw_serial_str(b" mi=");
print_timer_count_decimal(crate::drivers::usb::xhci::MSI_EVENT_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" psc=");
print_timer_count_decimal(crate::drivers::usb::xhci::PSC_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" r=");
print_timer_count_decimal(crate::drivers::usb::xhci::EP0_RESET_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" rf=");
print_timer_count_decimal(crate::drivers::usb::xhci::EP0_RESET_FAIL_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" ps=");
print_timer_count_decimal(crate::drivers::usb::xhci::EP0_PENDING_STUCK_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" nz=");
print_timer_count_decimal(crate::drivers::usb::hid::NONZERO_KBD_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" lr=");
print_hex_u64(crate::drivers::usb::hid::LAST_KBD_REPORT_U64.load(Ordering::Relaxed));
raw_serial_str(b" nk=");
print_timer_count_decimal(crate::drivers::usb::xhci::NKRO_EVENT_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" nr=");
print_hex_u64(crate::drivers::usb::xhci::LAST_NKRO_REPORT_U64.load(Ordering::Relaxed));
raw_serial_str(b" DS=");
print_timer_count_decimal(crate::drivers::usb::xhci::DMA_SENTINEL_SURVIVED.load(Ordering::SeqCst));
raw_serial_str(b" DR=");
Expand All @@ -251,6 +258,40 @@ pub extern "C" fn timer_interrupt_handler() {
print_timer_count_decimal(crate::drivers::usb::ehci::EHCI_CTL_ERRORS.load(Ordering::Relaxed) as u64);
raw_serial_str(b" ei=");
print_timer_count_decimal(crate::drivers::usb::ehci::EHCI_INT_COMPLETIONS.load(Ordering::Relaxed) as u64);
raw_serial_str(b" us=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_USBSTS.load(Ordering::Relaxed) as u64);
raw_serial_str(b" ps=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_KBD_PORTSC.load(Ordering::Relaxed) as u64);
raw_serial_str(b" ep=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_KBD_EP_STATE.load(Ordering::Relaxed) as u64);
raw_serial_str(b" se=");
print_timer_count_decimal(crate::drivers::usb::xhci::DIAG_SPI_ENABLE_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" er=");
print_timer_count_decimal(crate::drivers::usb::xhci::ENDPOINT_RESET_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" ef=");
print_timer_count_decimal(crate::drivers::usb::xhci::ENDPOINT_RESET_FAIL_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" db=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_DOORBELL_EP_STATE.load(Ordering::Relaxed) as u64);
raw_serial_str(b" fd=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_FIRST_DB.load(Ordering::Relaxed) as u64);
raw_serial_str(b" fc=");
print_timer_count_decimal(crate::drivers::usb::xhci::DIAG_FIRST_XFER_CC.load(Ordering::Relaxed) as u64);
raw_serial_str(b" tp=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_FIRST_XFER_PTR.load(Ordering::Relaxed));
raw_serial_str(b" qp=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_FIRST_QUEUED_PHYS.load(Ordering::Relaxed));
raw_serial_str(b" fs=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_FIRST_XFER_SLEP.load(Ordering::Relaxed) as u64);
raw_serial_str(b" ts=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_FIRST_XFER_STATUS.load(Ordering::Relaxed) as u64);
raw_serial_str(b" tc=");
print_hex_u64(crate::drivers::usb::xhci::DIAG_FIRST_XFER_CONTROL.load(Ordering::Relaxed) as u64);
raw_serial_str(b" gr=");
print_timer_count_decimal(crate::drivers::usb::xhci::EP0_GET_REPORT_COUNT.load(Ordering::Relaxed));
raw_serial_str(b" gk=");
print_timer_count_decimal(crate::drivers::usb::xhci::EP0_GET_REPORT_OK.load(Ordering::Relaxed));
raw_serial_str(b" ge=");
print_timer_count_decimal(crate::drivers::usb::xhci::EP0_GET_REPORT_ERR.load(Ordering::Relaxed));
raw_serial_str(b"]\n");
}
}
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/drivers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,15 @@ pub fn init() -> usize {
// Initialize XHCI USB host controller (keyboard + mouse)
// NEC uPD720200: vendor 0x1033, device 0x0194
if let Some(xhci_dev) = pci::find_device(0x1033, 0x0194) {
crate::serial_aarch64::raw_serial_str(b"[drv-dbg] calling xhci::init\n");
match usb::xhci::init(&xhci_dev) {
Ok(()) => {
crate::serial_aarch64::raw_serial_str(b"[drv-dbg] xhci init Ok\n");
serial_println!("[drivers] XHCI USB controller initialized");
crate::serial_aarch64::raw_serial_str(b"[drv-dbg] after serial_println\n");
}
Err(e) => {
crate::serial_aarch64::raw_serial_str(b"[drv-dbg] xhci init Err\n");
serial_println!("[drivers] XHCI USB init failed: {}", e);
}
}
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/drivers/usb/descriptors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub mod descriptor_type {
pub const INTERFACE: u8 = 4;
pub const ENDPOINT: u8 = 5;
pub const HID_REPORT: u8 = 0x22;
pub const BOS: u8 = 0x0F;
}

/// USB Class Codes
Expand All @@ -126,10 +127,13 @@ pub mod hid_protocol {
pub mod request {
pub const GET_DESCRIPTOR: u8 = 0x06;
pub const SET_CONFIGURATION: u8 = 0x09;
pub const SET_INTERFACE: u8 = 0x0B;
pub const SET_ISOCH_DELAY: u8 = 0x31;
}

/// USB HID Class Requests
pub mod hid_request {
pub const SET_REPORT: u8 = 0x09;
pub const SET_IDLE: u8 = 0x0A;
pub const SET_PROTOCOL: u8 = 0x0B;
}
Loading
Loading