virtio.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. mod virtio_blk;
  2. #[cfg(not(target_arch = "riscv64"))]
  3. compile_error!("VirtIO drivers are only supported on RISC-V architecture");
  4. use crate::kernel::{
  5. block::{make_device, BlockDevice},
  6. mem::{AsMemoryBlock, MemoryBlock, Page},
  7. };
  8. use alloc::sync::Arc;
  9. use core::num::NonZero;
  10. use eonix_hal::{arch_exported::fdt::FDT, mm::ArchPhysAccess};
  11. use eonix_log::{println_info, println_warn};
  12. use eonix_mm::{
  13. address::{Addr, PAddr, PhysAccess},
  14. paging::PFN,
  15. };
  16. use eonix_runtime::task::Task;
  17. use eonix_sync::Spin;
  18. use virtio_drivers::{
  19. device::blk::VirtIOBlk,
  20. transport::{mmio::MmioTransport, Transport},
  21. Hal,
  22. };
  23. pub struct HAL;
  24. unsafe impl Hal for HAL {
  25. fn dma_alloc(
  26. pages: usize,
  27. _direction: virtio_drivers::BufferDirection,
  28. ) -> (virtio_drivers::PhysAddr, core::ptr::NonNull<u8>) {
  29. let page = Page::alloc_at_least(pages);
  30. let paddr = page.start().addr();
  31. let ptr = page.as_memblk().as_byte_ptr();
  32. page.into_raw();
  33. (paddr, ptr)
  34. }
  35. unsafe fn dma_dealloc(
  36. paddr: virtio_drivers::PhysAddr,
  37. _vaddr: core::ptr::NonNull<u8>,
  38. _pages: usize,
  39. ) -> i32 {
  40. let pfn = PFN::from(PAddr::from(paddr));
  41. unsafe {
  42. // SAFETY: The caller ensures that the pfn corresponds to a valid
  43. // page allocated by `dma_alloc`.
  44. Page::from_raw(pfn);
  45. }
  46. 0
  47. }
  48. unsafe fn mmio_phys_to_virt(
  49. paddr: virtio_drivers::PhysAddr,
  50. size: usize,
  51. ) -> core::ptr::NonNull<u8> {
  52. MemoryBlock::new(NonZero::new(paddr).expect("paddr must be non-zero"), size).as_byte_ptr()
  53. }
  54. unsafe fn share(
  55. buffer: core::ptr::NonNull<[u8]>,
  56. _direction: virtio_drivers::BufferDirection,
  57. ) -> virtio_drivers::PhysAddr {
  58. let paddr = unsafe {
  59. // SAFETY: The caller ensures that the buffer is valid.
  60. ArchPhysAccess::from_ptr(buffer.cast::<u8>())
  61. };
  62. paddr.addr()
  63. }
  64. unsafe fn unshare(
  65. _paddr: virtio_drivers::PhysAddr,
  66. _buffer: core::ptr::NonNull<[u8]>,
  67. _direction: virtio_drivers::BufferDirection,
  68. ) {
  69. }
  70. }
  71. pub fn init_virtio_devices() {
  72. let mut disk_id = 0;
  73. for reg in FDT
  74. .all_nodes()
  75. .filter(|node| {
  76. node.compatible()
  77. .is_some_and(|compatible| compatible.all().any(|s| s == "virtio,mmio"))
  78. })
  79. .filter_map(|node| node.reg())
  80. .flatten()
  81. {
  82. let base = PAddr::from(reg.starting_address as usize);
  83. let size = reg.size.expect("Virtio device must have a size");
  84. let base = unsafe {
  85. // SAFETY: We get the base address from the FDT, which is guaranteed to be valid.
  86. ArchPhysAccess::as_ptr(base)
  87. };
  88. match unsafe { MmioTransport::new(base, size) } {
  89. Ok(transport) => match transport.device_type() {
  90. virtio_drivers::transport::DeviceType::Block => {
  91. let block_device = VirtIOBlk::<HAL, _>::new(transport)
  92. .expect("Failed to initialize VirtIO Block device");
  93. let block_device = BlockDevice::register_disk(
  94. make_device(8, 16 * disk_id),
  95. 2147483647,
  96. Arc::new(Spin::new(block_device)),
  97. )
  98. .expect("Failed to register VirtIO Block device");
  99. Task::block_on(block_device.partprobe())
  100. .expect("Failed to probe partitions for VirtIO Block device");
  101. disk_id += 1;
  102. }
  103. virtio_drivers::transport::DeviceType::Network => {
  104. println_info!(
  105. "Initializing Virtio Network device at {:?} with size {:#x}",
  106. base,
  107. size
  108. );
  109. }
  110. virtio_drivers::transport::DeviceType::Console => {
  111. println_info!(
  112. "Initializing Virtio Console at {:?} with size {:#x}",
  113. base,
  114. size
  115. );
  116. }
  117. virtio_drivers::transport::DeviceType::EntropySource => {
  118. println_info!(
  119. "Initializing Virtio Entropy Source at {:?} with size {:#x}",
  120. base,
  121. size
  122. );
  123. }
  124. _ => {}
  125. },
  126. Err(err) => {
  127. println_warn!(
  128. "Failed to initialize Virtio device at {:?} with size {:#x}: {}",
  129. base,
  130. size,
  131. err
  132. );
  133. }
  134. }
  135. }
  136. }