123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- #![no_std]
- #![no_main]
- mod exceptions;
- mod hal;
- mod logger;
- mod pl011;
- use core::{mem::size_of, panic::PanicInfo, ptr::NonNull};
- use fdt::{node::FdtNode, standard_nodes::Compatible, Fdt};
- use hal::HalImpl;
- use log::{debug, error, info, trace, warn, LevelFilter};
- use psci::system_off;
- use virtio_drivers::{
- pci::{
- bus::{Cam, PciRoot},
- virtio_device_type,
- },
- DeviceType, MmioTransport, Transport, VirtIOBlk, VirtIOGpu, VirtIOHeader, VirtIONet,
- };
- #[no_mangle]
- extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
- logger::init(LevelFilter::Debug).unwrap();
- info!("virtio-drivers example started.");
- debug!(
- "x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}",
- x0, x1, x2, x3
- );
- info!("Loading FDT from {:#018x}", x0);
- // Safe because the pointer is a valid pointer to unaliased memory.
- let fdt = unsafe { Fdt::from_ptr(x0 as *const u8).unwrap() };
- for node in fdt.all_nodes() {
- // Dump information about the node for debugging.
- trace!(
- "{}: {:?}",
- node.name,
- node.compatible().map(Compatible::first),
- );
- if let Some(reg) = node.reg() {
- for range in reg {
- trace!(
- " {:#018x?}, length {:?}",
- range.starting_address,
- range.size
- );
- }
- }
- // Check whether it is a VirtIO MMIO device.
- if let (Some(compatible), Some(region)) =
- (node.compatible(), node.reg().and_then(|mut reg| reg.next()))
- {
- if compatible.all().any(|s| s == "virtio,mmio")
- && region.size.unwrap_or(0) > size_of::<VirtIOHeader>()
- {
- debug!("Found VirtIO MMIO device at {:?}", region);
- let header = NonNull::new(region.starting_address 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);
- }
- }
- }
- }
- }
- if let Some(pci_node) = fdt.find_compatible(&["pci-host-cam-generic"]) {
- info!("Found PCI node: {}", pci_node.name);
- enumerate_pci(pci_node, Cam::MmioCam);
- }
- if let Some(pcie_node) = fdt.find_compatible(&["pci-host-ecam-generic"]) {
- info!("Found PCIe node: {}", pcie_node.name);
- enumerate_pci(pcie_node, Cam::Ecam);
- }
- system_off().unwrap();
- }
- fn virtio_device(transport: impl Transport) {
- match transport.device_type() {
- DeviceType::Block => virtio_blk(transport),
- DeviceType::GPU => virtio_gpu(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 = [0xffu8; 512];
- let mut output = [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");
- info!("virtio-gpu test finished");
- }
- fn virtio_net<T: Transport>(transport: T) {
- let mut net = VirtIONet::<HalImpl, T>::new(transport).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");
- }
- fn enumerate_pci(pci_node: FdtNode, cam: Cam) {
- let reg = pci_node.reg().expect("PCI node missing reg property.");
- for region in reg {
- info!(
- "Reg: {:?}-{:#x}",
- region.starting_address,
- region.starting_address as usize + region.size.unwrap()
- );
- // Safe because we know the pointer is to a valid MMIO region.
- let mut pci_root = unsafe { PciRoot::new(region.starting_address as *mut u8, cam) };
- for (device_function, info) in pci_root.enumerate_bus(0) {
- let (status, command) = pci_root.get_status_command(device_function);
- info!(
- "Found {} at {}, status {:?} command {:?}",
- info, device_function, status, command
- );
- if let Some(virtio_type) = virtio_device_type(&info) {
- info!(" VirtIO {:?}", virtio_type);
- }
- }
- }
- }
- #[panic_handler]
- fn panic(info: &PanicInfo) -> ! {
- error!("{}", info);
- system_off().unwrap();
- loop {}
- }
|