main.rs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #![no_std]
  2. #![no_main]
  3. mod exceptions;
  4. mod hal;
  5. mod logger;
  6. mod pl011;
  7. use core::{mem::size_of, panic::PanicInfo, ptr::NonNull};
  8. use fdt::{node::FdtNode, standard_nodes::Compatible, Fdt};
  9. use hal::HalImpl;
  10. use log::{debug, error, info, trace, warn, LevelFilter};
  11. use psci::system_off;
  12. use virtio_drivers::{
  13. pci::bus::{Cam, PciRoot},
  14. DeviceType, MmioTransport, Transport, VirtIOBlk, VirtIOGpu, VirtIOHeader, VirtIONet,
  15. };
  16. #[no_mangle]
  17. extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
  18. logger::init(LevelFilter::Debug).unwrap();
  19. info!("virtio-drivers example started.");
  20. debug!(
  21. "x0={:#018x}, x1={:#018x}, x2={:#018x}, x3={:#018x}",
  22. x0, x1, x2, x3
  23. );
  24. info!("Loading FDT from {:#018x}", x0);
  25. // Safe because the pointer is a valid pointer to unaliased memory.
  26. let fdt = unsafe { Fdt::from_ptr(x0 as *const u8).unwrap() };
  27. for node in fdt.all_nodes() {
  28. // Dump information about the node for debugging.
  29. trace!(
  30. "{}: {:?}",
  31. node.name,
  32. node.compatible().map(Compatible::first),
  33. );
  34. if let Some(reg) = node.reg() {
  35. for range in reg {
  36. trace!(
  37. " {:#018x?}, length {:?}",
  38. range.starting_address,
  39. range.size
  40. );
  41. }
  42. }
  43. // Check whether it is a VirtIO MMIO device.
  44. if let (Some(compatible), Some(region)) =
  45. (node.compatible(), node.reg().and_then(|mut reg| reg.next()))
  46. {
  47. if compatible.all().any(|s| s == "virtio,mmio")
  48. && region.size.unwrap_or(0) > size_of::<VirtIOHeader>()
  49. {
  50. debug!("Found VirtIO MMIO device at {:?}", region);
  51. let header = NonNull::new(region.starting_address as *mut VirtIOHeader).unwrap();
  52. match unsafe { MmioTransport::new(header) } {
  53. Err(e) => warn!("Error creating VirtIO MMIO transport: {}", e),
  54. Ok(transport) => {
  55. info!(
  56. "Detected virtio MMIO device with vendor id {:#X}, device type {:?}, version {:?}",
  57. transport.vendor_id(),
  58. transport.device_type(),
  59. transport.version(),
  60. );
  61. virtio_device(transport);
  62. }
  63. }
  64. }
  65. }
  66. }
  67. if let Some(pci_node) = fdt.find_compatible(&["pci-host-cam-generic"]) {
  68. info!("Found PCI node: {}", pci_node.name);
  69. enumerate_pci(pci_node, Cam::MmioCam);
  70. }
  71. if let Some(pcie_node) = fdt.find_compatible(&["pci-host-ecam-generic"]) {
  72. info!("Found PCIe node: {}", pcie_node.name);
  73. enumerate_pci(pcie_node, Cam::Ecam);
  74. }
  75. system_off().unwrap();
  76. }
  77. fn virtio_device(transport: impl Transport) {
  78. match transport.device_type() {
  79. DeviceType::Block => virtio_blk(transport),
  80. DeviceType::GPU => virtio_gpu(transport),
  81. DeviceType::Network => virtio_net(transport),
  82. t => warn!("Unrecognized virtio device: {:?}", t),
  83. }
  84. }
  85. fn virtio_blk<T: Transport>(transport: T) {
  86. let mut blk = VirtIOBlk::<HalImpl, T>::new(transport).expect("failed to create blk driver");
  87. let mut input = [0xffu8; 512];
  88. let mut output = [0; 512];
  89. for i in 0..32 {
  90. for x in input.iter_mut() {
  91. *x = i as u8;
  92. }
  93. blk.write_block(i, &input).expect("failed to write");
  94. blk.read_block(i, &mut output).expect("failed to read");
  95. assert_eq!(input, output);
  96. }
  97. info!("virtio-blk test finished");
  98. }
  99. fn virtio_gpu<T: Transport>(transport: T) {
  100. let mut gpu = VirtIOGpu::<HalImpl, T>::new(transport).expect("failed to create gpu driver");
  101. let (width, height) = gpu.resolution().expect("failed to get resolution");
  102. let width = width as usize;
  103. let height = height as usize;
  104. info!("GPU resolution is {}x{}", width, height);
  105. let fb = gpu.setup_framebuffer().expect("failed to get fb");
  106. for y in 0..height {
  107. for x in 0..width {
  108. let idx = (y * width + x) * 4;
  109. fb[idx] = x as u8;
  110. fb[idx + 1] = y as u8;
  111. fb[idx + 2] = (x + y) as u8;
  112. }
  113. }
  114. gpu.flush().expect("failed to flush");
  115. info!("virtio-gpu test finished");
  116. }
  117. fn virtio_net<T: Transport>(transport: T) {
  118. let mut net = VirtIONet::<HalImpl, T>::new(transport).expect("failed to create net driver");
  119. let mut buf = [0u8; 0x100];
  120. let len = net.recv(&mut buf).expect("failed to recv");
  121. info!("recv: {:?}", &buf[..len]);
  122. net.send(&buf[..len]).expect("failed to send");
  123. info!("virtio-net test finished");
  124. }
  125. fn enumerate_pci(pci_node: FdtNode, cam: Cam) {
  126. let reg = pci_node.reg().expect("PCI node missing reg property.");
  127. for region in reg {
  128. info!(
  129. "Reg: {:?}-{:#x}",
  130. region.starting_address,
  131. region.starting_address as usize + region.size.unwrap()
  132. );
  133. // Safe because we know the pointer is to a valid MMIO region.
  134. let mut pci_root = unsafe { PciRoot::new(region.starting_address as *mut u8, cam) };
  135. for (device_function, info) in pci_root.enumerate_bus(0) {
  136. info!("Found {} at {}", info, device_function);
  137. }
  138. }
  139. }
  140. #[panic_handler]
  141. fn panic(info: &PanicInfo) -> ! {
  142. error!("{}", info);
  143. system_off().unwrap();
  144. loop {}
  145. }