#![no_std] #![no_main] #![deny(warnings)] #[macro_use] extern crate alloc; #[macro_use] extern crate log; // #[macro_use] extern crate opensbi_rt; use device_tree::util::SliceRead; use device_tree::{DeviceTree, Node}; use log::LevelFilter; use virtio_drivers::*; mod virtio_impl; #[no_mangle] extern "C" fn main(_hartid: usize, device_tree_paddr: usize) { log::set_max_level(LevelFilter::Info); init_dt(device_tree_paddr); info!("test end"); } fn init_dt(dtb: usize) { info!("device tree @ {:#x}", dtb); #[repr(C)] struct DtbHeader { be_magic: u32, be_size: u32, } let header = unsafe { &*(dtb as *const DtbHeader) }; let magic = u32::from_be(header.be_magic); const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed; assert_eq!(magic, DEVICE_TREE_MAGIC); let size = u32::from_be(header.be_size); let dtb_data = unsafe { core::slice::from_raw_parts(dtb as *const u8, size as usize) }; let dt = DeviceTree::load(dtb_data).expect("failed to parse device tree"); walk_dt_node(&dt.root); } fn walk_dt_node(dt: &Node) { if let Ok(compatible) = dt.prop_str("compatible") { if compatible == "virtio,mmio" { virtio_probe(dt); } } for child in dt.children.iter() { walk_dt_node(child); } } fn virtio_probe(node: &Node) { if let Some(reg) = node.prop_raw("reg") { let paddr = reg.as_slice().read_be_u64(0).unwrap(); let size = reg.as_slice().read_be_u64(8).unwrap(); let vaddr = paddr; info!("walk dt addr={:#x}, size={:#x}", paddr, size); let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) }; info!( "Detected virtio device with vendor id {:#X}", header.vendor_id() ); info!("Device tree node {:?}", node); match header.device_type() { DeviceType::Block => virtio_blk(header), DeviceType::GPU => virtio_gpu(header), DeviceType::Input => virtio_input(header), DeviceType::Network => virtio_net(header), t => warn!("Unrecognized virtio device: {:?}", t), } } } fn virtio_blk(header: &'static mut VirtIOHeader) { let mut blk = VirtIOBlk::new(header).expect("failed to create blk driver"); let mut input = vec![0xffu8; 512]; let mut output = vec![0; 512]; for i in 0..32 { for x in input.iter_mut() { *x = i as u8; } blk.write_block(i, &input).expect("failed to write"); blk.read_block(i, &mut output).expect("failed to read"); assert_eq!(input, output); } info!("virtio-blk test finished"); } fn virtio_gpu(header: &'static mut VirtIOHeader) { let mut gpu = VirtIOGpu::new(header).expect("failed to create gpu driver"); let fb = gpu.setup_framebuffer().expect("failed to get fb"); for y in 0..768 { for x in 0..1024 { let idx = (y * 1024 + x) * 4; fb[idx] = x as u8; fb[idx + 1] = y as u8; fb[idx + 2] = (x + y) as u8; } } gpu.flush().expect("failed to flush"); info!("virtio-gpu test finished"); } fn virtio_input(header: &'static mut VirtIOHeader) { let mut event_buf = [0u64; 32]; let mut _input = VirtIOInput::new(header, &mut event_buf).expect("failed to create input driver"); // loop { // input.ack_interrupt().expect("failed to ack"); // info!("mouse: {:?}", input.mouse_xy()); // } // TODO: handle external interrupt } fn virtio_net(header: &'static mut VirtIOHeader) { let mut net = VirtIONet::new(header).expect("failed to create net driver"); let mut buf = [0u8; 0x100]; let len = net.recv(&mut buf).expect("failed to recv"); info!("recv: {:?}", &buf[..len]); net.send(&buf[..len]).expect("failed to send"); info!("virtio-net test finished"); }