main.rs 5.7 KB

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