123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- #![no_std]
- #![no_main]
- #![deny(warnings)]
- #[macro_use]
- extern crate log;
- extern crate alloc;
- extern crate opensbi_rt;
- use alloc::vec;
- use core::ptr::NonNull;
- use fdt::{node::FdtNode, standard_nodes::Compatible, Fdt};
- use log::LevelFilter;
- use virtio_drivers::{
- device::{blk::VirtIOBlk, gpu::VirtIOGpu, input::VirtIOInput, net::VirtIONet},
- transport::{
- mmio::{MmioTransport, VirtIOHeader},
- DeviceType, Transport,
- },
- };
- use virtio_impl::HalImpl;
- mod virtio_impl;
- #[cfg(feature = "tcp")]
- mod tcp;
- const NET_BUFFER_LEN: usize = 2048;
- const NET_QUEUE_SIZE: usize = 16;
- #[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);
- // Safe because the pointer is a valid pointer to unaliased memory.
- let fdt = unsafe { Fdt::from_ptr(dtb as *const u8).unwrap() };
- walk_dt(fdt);
- }
- fn walk_dt(fdt: Fdt) {
- for node in fdt.all_nodes() {
- if let Some(compatible) = node.compatible() {
- if compatible.all().any(|s| s == "virtio,mmio") {
- virtio_probe(node);
- }
- }
- }
- }
- fn virtio_probe(node: FdtNode) {
- if let Some(reg) = node.reg().and_then(|mut reg| reg.next()) {
- let paddr = reg.starting_address as usize;
- let size = reg.size.unwrap();
- let vaddr = paddr;
- info!("walk dt addr={:#x}, size={:#x}", paddr, size);
- info!(
- "Device tree node {}: {:?}",
- node.name,
- node.compatible().map(Compatible::first),
- );
- let header = NonNull::new(vaddr as *mut VirtIOHeader).unwrap();
- match unsafe { MmioTransport::new(header) } {
- Err(e) => warn!("Error creating VirtIO MMIO transport: {}", e),
- Ok(transport) => {
- info!(
- "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}",
- transport.vendor_id(),
- transport.device_type(),
- transport.version(),
- );
- virtio_device(transport);
- }
- }
- }
- }
- fn virtio_device(transport: impl Transport) {
- match transport.device_type() {
- DeviceType::Block => virtio_blk(transport),
- DeviceType::GPU => virtio_gpu(transport),
- DeviceType::Input => virtio_input(transport),
- DeviceType::Network => virtio_net(transport),
- t => warn!("Unrecognized virtio device: {:?}", t),
- }
- }
- fn virtio_blk<T: Transport>(transport: T) {
- let mut blk = VirtIOBlk::<HalImpl, T>::new(transport).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<T: Transport>(transport: T) {
- let mut gpu = VirtIOGpu::<HalImpl, T>::new(transport).expect("failed to create gpu driver");
- let (width, height) = gpu.resolution().expect("failed to get resolution");
- let width = width as usize;
- let height = height as usize;
- info!("GPU resolution is {}x{}", width, height);
- let fb = gpu.setup_framebuffer().expect("failed to get fb");
- for y in 0..height {
- for x in 0..width {
- let idx = (y * width + 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");
- //delay some time
- info!("virtio-gpu show graphics....");
- for _ in 0..10000 {
- for _ in 0..100000 {
- unsafe {
- core::arch::asm!("nop");
- }
- }
- }
- info!("virtio-gpu test finished");
- }
- fn virtio_input<T: Transport>(transport: T) {
- //let mut event_buf = [0u64; 32];
- let mut _input =
- VirtIOInput::<HalImpl, T>::new(transport).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<T: Transport>(transport: T) {
- let net = VirtIONet::<HalImpl, T, NET_QUEUE_SIZE>::new(transport, NET_BUFFER_LEN)
- .expect("failed to create net driver");
- info!("MAC address: {:02x?}", net.mac_address());
- #[cfg(not(feature = "tcp"))]
- {
- let mut net = net;
- loop {
- match net.receive() {
- Ok(buf) => {
- info!("RECV {} bytes: {:02x?}", buf.packet_len(), buf.packet());
- let tx_buf = virtio_drivers::device::net::TxBuffer::from(buf.packet());
- net.send(tx_buf).expect("failed to send");
- net.recycle_rx_buffer(buf).unwrap();
- break;
- }
- Err(virtio_drivers::Error::NotReady) => continue,
- Err(err) => panic!("failed to recv: {:?}", err),
- }
- }
- info!("virtio-net test finished");
- }
- #[cfg(feature = "tcp")]
- tcp::test_echo_server(net);
- }
|