Skip to content

在 satrryos qemu aarch64 上初始化 usbhub 后获取 usb 设备列表卡住 #44

@PaiGack

Description

@PaiGack
[  8.398521 0:2 starry_api::vfs::dev::usb::usb_host:120] [USB] Initializing USB Host Controller
[  8.399462 0:2 starry_api::vfs::dev::usb::usb_host:48] [USB] iomap: paddr=0x10010000, size=0x4000
[  8.400452 0:2 starry_api::vfs::dev::usb::usb_host:54] [USB] phys_to_virt => vaddr = 0xffff000010010000
[  8.403943 0:2 starry_api::vfs::dev::usb::usb_host:75] [USB] mapping protect OK, final vaddr = 0xffff000010010000
[  8.404896 0:2 starry_api::vfs::dev::usb::usb_host:122] [USB] XHCI base mapped at vaddr = 0xffff000010010000
[  8.406619 0:2 starry_api::vfs::dev::usb::usb_host:125] [USB] USBHost created
[  8.407381 0:2 starry_api::vfs::dev::usb::usb_host:130] [USB] Register IRQ 36
[  8.408204 0:2 starry_api::vfs::dev::usb::usb_host:133] Register IRQ ok
[  8.408850 0:2 starry_api::vfs::dev::usb::usb_host:141] [USB] calling host.init()
[  8.415294 0:2 starry_api::vfs::dev::usb::usb_host:41] [USB] page_size
[  8.416195 0:2 starry_api::vfs::dev::usb::usb_host:41] [USB] page_size
[  8.416755 0:2 starry_api::vfs::dev::usb::usb_host:41] [USB] page_size
[  8.422651 0:2 starry_api::vfs::dev::usb::usb_host:34] [USB] sleep 50 ms
[  8.473889 0:2 starry_api::vfs::dev::usb::usb_host:34] [USB] sleep 100 ms
qemu-system-aarch64: info: [UVC] usb_video_handle_reset, 0x56207cdc0690
[  8.576635 0:2 starry_api::vfs::dev::usb::usb_host:34] [USB] sleep 100 ms
[  8.677687 0:2 starry_api::vfs::dev::usb::usb_host:144] [USB] host.init OK
[  8.679136 0:2 crab_usb::backend::xhci:248] Port 0: Enabled: false, Connected: false, Speed 0, Power true
[  8.680027 0:2 crab_usb::backend::xhci:248] Port 1: Enabled: false, Connected: false, Speed 0, Power true
[  8.680753 0:2 crab_usb::backend::xhci:248] Port 2: Enabled: false, Connected: false, Speed 0, Power true
[  8.681638 0:2 crab_usb::backend::xhci:248] Port 3: Enabled: false, Connected: false, Speed 0, Power true
[  8.682341 0:2 crab_usb::backend::xhci:248] Port 4: Enabled: true, Connected: true, Speed 3, Power true
[  8.683194 0:2 crab_usb::backend::xhci:248] Port 5: Enabled: false, Connected: false, Speed 0, Power true
[  8.683900 0:2 crab_usb::backend::xhci:248] Port 6: Enabled: false, Connected: false, Speed 0, Power true
[  8.684598 0:2 crab_usb::backend::xhci:248] Port 7: Enabled: false, Connected: false, Speed 0, Power true
[  8.685453 0:2 crab_usb::backend::xhci::root:525] New device on port 4
[  8.686512 0:2 crab_usb::backend::xhci::ring:80] [CMD] >> EnableSlot(EnableSlot { slot_type: 0, cycle_bit: true }) @BusAddr(45EC2000)
[  8.689034 0:2 usb_if::transfer::wait:73] WaitMap: try_wait_for_result called with id 45EC2000, elem@0xffff00004e20b400 false

qemu 启动命令 (qemu 支持 uvc 的代码仓库在 https://cnb.cool/rzhangsan/ChenLongOS_ai_stack/qemu-10.0.0)

# 编译
make ARCH=aarch64 build SMP=1

# qeum 运行
#   挂载虚拟 usb 设备
#       usb-video 摄像头
/opt/qemu-10.0.0/bin/qemu-system-aarch64 -m 1G -smp 1 -cpu cortex-a72 -machine virt \
  -kernel workspace_aarch64-qemu-virt.bin \
  -device virtio-blk-pci,drive=disk0 \
  -drive id=disk0,if=none,format=raw,file=disk.img \
  -device virtio-net-pci,netdev=net0 \
  -netdev user,id=net0,hostfwd=tcp::10122-:22 \
  -device qemu-xhci,id=xhci,msi=off,msix=off \
  -device usb-video,bus=xhci.0,id=myuvc0,file=qemu/sample-30s.mp4 \
  -nographic

在 satrryos 中初始化 usbhub 及获取 list 代码

extern crate alloc;

use alloc::{boxed::Box, vec::Vec};
use core::{ptr::NonNull, time::Duration};

use axerrno::AxError;
use axhal::{
    irq::register,
    mem::{PhysAddr, phys_to_virt, virt_to_phys},
    paging::MappingFlags,
};
use axmm::kernel_aspace;
use crab_usb::err::USBError;
pub use crab_usb::*;
use mbarrier::mb;
use spin::{Mutex, Once};

// ===> qemu xhci addr
const USB_3_HOST_MMIO_BASE: usize = 0x10010000;
const USB_3_HOST_MMIO_SIZE: usize = 0x4000;
const USB_3_HOST_IRQ: usize = 36;
// <=== qemu xhci addr end

// ===> todo broad xhci addr
// <=== todo broad xhci addr

static USB_HOST: Once<Mutex<USBHost>> = Once::new();
static USB_IRQ_HANDLE: Once<EventHandler> = Once::new();

struct KernelImpl;
impl_trait! {
    impl Kernel for KernelImpl {
        fn sleep<'a>(duration: Duration) -> BoxFuture<'a, ()> {
            warn!("[USB] sleep {} ms", duration.as_millis());
            Box::pin(async move {
                axhal::time::busy_wait(duration);
            })
        }

        fn page_size() -> usize {
            warn!("[USB] page_size");
            0x1000
        }
    }
}

fn iomap(paddr: PhysAddr, size: usize) -> Result<NonNull<u8>, AxError> {
    warn!(
        "[USB] iomap: paddr=0x{:x}, size=0x{:x}",
        paddr.as_usize(),
        size
    );
    let vaddr = phys_to_virt(paddr);
    warn!("[USB] phys_to_virt => vaddr = 0x{:x}", vaddr.as_usize());

    let mut g = kernel_aspace().lock();

    if let Err(e) = g.map_linear(
        vaddr,
        paddr,
        size,
        MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE,
    ) {
        if !matches!(e, AxError::AlreadyExists) {
            return Err(e);
        }
    }

    g.protect(
        vaddr,
        size,
        MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE,
    )?;

    warn!(
        "[USB] mapping protect OK, final vaddr = 0x{:x}",
        vaddr.as_usize()
    );

    mb();

    Ok(unsafe { NonNull::new_unchecked(vaddr.as_mut_ptr()) })
}

struct Cache;

impl dma_api::Impl for Cache {
    fn map(addr: NonNull<u8>, _size: usize, _direction: dma_api::Direction) -> u64 {
        virt_to_phys((addr.as_ptr() as usize).into()).as_usize() as _
    }

    fn unmap(_addr: NonNull<u8>, _size: usize) {}

    fn flush(addr: NonNull<u8>, size: usize) {
        aarch64_cpu_ext::cache::dcache_range(
            aarch64_cpu_ext::cache::CacheOp::Clean,
            addr.as_ptr() as usize,
            size,
        );
    }

    fn invalidate(addr: NonNull<u8>, size: usize) {
        aarch64_cpu_ext::cache::dcache_range(
            aarch64_cpu_ext::cache::CacheOp::Invalidate,
            addr.as_ptr() as usize,
            size,
        );
    }
}

dma_api::set_impl!(Cache);

fn irq_handler() {
    // warn!("[USB] IRQ irq_handler");
    USB_IRQ_HANDLE.wait().handle_event();
}

fn get_usb_host() -> &'static Mutex<USBHost> {
    USB_HOST.call_once(|| {
        warn!("[USB] Initializing USB Host Controller");
        let mmio_base = iomap(USB_3_HOST_MMIO_BASE.into(), USB_3_HOST_MMIO_SIZE).unwrap();
        warn!("[USB] XHCI base mapped at vaddr = {:?}", mmio_base);

        let mut host = USBHost::new_xhci(mmio_base);
        warn!("[USB] USBHost created");

        let event_handler = host.event_handler();
        USB_IRQ_HANDLE.call_once(|| event_handler);

        warn!("[USB] Register IRQ {}", USB_3_HOST_IRQ);
        match register(USB_3_HOST_IRQ, irq_handler) {
            true => {
                warn!("Register IRQ ok");
            }
            false => {
                warn!("Register IRQ fail");
            }
        }

        spin_on::spin_on(async move {
            warn!("[USB] calling host.init()");
            host.init().await.unwrap();

            warn!("[USB] host.init OK");
            Mutex::new(host)
        })
    })
}

pub fn get_device_list() -> Result<Vec<DeviceInfo>, USBError> {
    // warn!("[USB] get usb host");
    let mut host = get_usb_host().lock();

    // warn!("[USB] get usb list");
    spin_on::spin_on(async {
        let ls = host.device_list().await?;

        // warn!("[USB] collect");
        Ok(ls.collect())
    })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions