main.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #![no_std]
  2. #![no_main]
  3. #![feature(asm_const)]
  4. #![feature(abi_x86_interrupt)]
  5. #[macro_use]
  6. extern crate log;
  7. extern crate alloc;
  8. mod boot;
  9. mod hal;
  10. mod heap;
  11. mod logger;
  12. mod trap;
  13. #[cfg(feature = "tcp")]
  14. mod tcp;
  15. use self::hal::HalImpl;
  16. use virtio_drivers::{
  17. device::{blk::VirtIOBlk, gpu::VirtIOGpu, net::VirtIONet},
  18. transport::{
  19. pci::{
  20. bus::{BarInfo, Cam, Command, DeviceFunction, PciRoot},
  21. virtio_device_type, PciTransport,
  22. },
  23. DeviceType, Transport,
  24. },
  25. };
  26. /// Memory mapped address space to access PCI configuration.
  27. ///
  28. /// Currently it is hardcoded (from qemu/roms/seabios/src/hw/dev-q35.h)
  29. ///
  30. /// TODO: get it from ACPI MCFG table.
  31. const MMCONFIG_BASE: usize = 0xB000_0000;
  32. const NET_BUFFER_LEN: usize = 2048;
  33. const NET_QUEUE_SIZE: usize = 16;
  34. fn system_off() -> ! {
  35. use x86_64::instructions::{hlt, port::PortWriteOnly};
  36. unsafe {
  37. PortWriteOnly::new(0x604).write(0x2000u16);
  38. loop {
  39. hlt();
  40. }
  41. }
  42. }
  43. #[no_mangle]
  44. extern "C" fn main(_mbi: *const u8) -> ! {
  45. logger::init(log::LevelFilter::Info).unwrap();
  46. info!("virtio-drivers example started.");
  47. trap::init();
  48. heap::init_heap();
  49. enumerate_pci(MMCONFIG_BASE as _);
  50. info!("test end");
  51. system_off();
  52. }
  53. fn virtio_device(transport: impl Transport) {
  54. match transport.device_type() {
  55. DeviceType::Block => virtio_blk(transport),
  56. DeviceType::GPU => virtio_gpu(transport),
  57. DeviceType::Network => virtio_net(transport),
  58. t => warn!("Unrecognized virtio device: {:?}", t),
  59. }
  60. }
  61. fn virtio_blk<T: Transport>(transport: T) {
  62. let mut blk = VirtIOBlk::<HalImpl, T>::new(transport).expect("failed to create blk driver");
  63. assert!(!blk.readonly());
  64. let mut input = [0xffu8; 512];
  65. let mut output = [0; 512];
  66. for i in 0..32 {
  67. for x in input.iter_mut() {
  68. *x = i as u8;
  69. }
  70. blk.write_block(i, &input).expect("failed to write");
  71. blk.read_block(i, &mut output).expect("failed to read");
  72. assert_eq!(input, output);
  73. }
  74. info!("virtio-blk test finished");
  75. }
  76. fn virtio_gpu<T: Transport>(transport: T) {
  77. let mut gpu = VirtIOGpu::<HalImpl, T>::new(transport).expect("failed to create gpu driver");
  78. let (width, height) = gpu.resolution().expect("failed to get resolution");
  79. let width = width as usize;
  80. let height = height as usize;
  81. info!("GPU resolution is {}x{}", width, height);
  82. let fb = gpu.setup_framebuffer().expect("failed to get fb");
  83. for y in 0..height {
  84. for x in 0..width {
  85. let idx = (y * width + x) * 4;
  86. fb[idx] = x as u8;
  87. fb[idx + 1] = y as u8;
  88. fb[idx + 2] = (x + y) as u8;
  89. }
  90. }
  91. gpu.flush().expect("failed to flush");
  92. //delay some time
  93. info!("virtio-gpu show graphics....");
  94. for _ in 0..10000 {
  95. for _ in 0..100000 {
  96. unsafe {
  97. core::arch::asm!("nop");
  98. }
  99. }
  100. }
  101. info!("virtio-gpu test finished");
  102. }
  103. fn virtio_net<T: Transport>(transport: T) {
  104. let net = VirtIONet::<HalImpl, T, NET_QUEUE_SIZE>::new(transport, NET_BUFFER_LEN)
  105. .expect("failed to create net driver");
  106. info!("MAC address: {:02x?}", net.mac_address());
  107. #[cfg(not(feature = "tcp"))]
  108. {
  109. let mut net = net;
  110. loop {
  111. match net.receive() {
  112. Ok(buf) => {
  113. info!("RECV {} bytes: {:02x?}", buf.packet_len(), buf.packet());
  114. let tx_buf = virtio_drivers::device::net::TxBuffer::from(buf.packet());
  115. net.send(tx_buf).expect("failed to send");
  116. net.recycle_rx_buffer(buf).unwrap();
  117. break;
  118. }
  119. Err(virtio_drivers::Error::NotReady) => continue,
  120. Err(err) => panic!("failed to recv: {:?}", err),
  121. }
  122. }
  123. info!("virtio-net test finished");
  124. }
  125. #[cfg(feature = "tcp")]
  126. tcp::test_echo_server(net);
  127. }
  128. fn enumerate_pci(mmconfig_base: *mut u8) {
  129. info!("mmconfig_base = {:#x}", mmconfig_base as usize);
  130. let mut pci_root = unsafe { PciRoot::new(mmconfig_base, Cam::Ecam) };
  131. for (device_function, info) in pci_root.enumerate_bus(0) {
  132. let (status, command) = pci_root.get_status_command(device_function);
  133. info!(
  134. "Found {} at {}, status {:?} command {:?}",
  135. info, device_function, status, command
  136. );
  137. if let Some(virtio_type) = virtio_device_type(&info) {
  138. info!(" VirtIO {:?}", virtio_type);
  139. // Enable the device to use its BARs.
  140. pci_root.set_command(
  141. device_function,
  142. Command::IO_SPACE | Command::MEMORY_SPACE | Command::BUS_MASTER,
  143. );
  144. dump_bar_contents(&mut pci_root, device_function, 4);
  145. let mut transport =
  146. PciTransport::new::<HalImpl>(&mut pci_root, device_function).unwrap();
  147. info!(
  148. "Detected virtio PCI device with device type {:?}, features {:#018x}",
  149. transport.device_type(),
  150. transport.read_device_features(),
  151. );
  152. virtio_device(transport);
  153. }
  154. }
  155. }
  156. fn dump_bar_contents(root: &mut PciRoot, device_function: DeviceFunction, bar_index: u8) {
  157. let bar_info = root.bar_info(device_function, bar_index).unwrap();
  158. trace!("Dumping bar {}: {:#x?}", bar_index, bar_info);
  159. if let BarInfo::Memory { address, size, .. } = bar_info {
  160. let start = address as *const u8;
  161. unsafe {
  162. let mut buf = [0u8; 32];
  163. for i in 0..size / 32 {
  164. let ptr = start.add(i as usize * 32);
  165. core::ptr::copy(ptr, buf.as_mut_ptr(), 32);
  166. if buf.iter().any(|b| *b != 0xff) {
  167. trace!(" {:?}: {:x?}", ptr, buf);
  168. }
  169. }
  170. }
  171. }
  172. trace!("End of dump");
  173. }
  174. #[panic_handler]
  175. fn panic(info: &core::panic::PanicInfo) -> ! {
  176. error!("{}", info);
  177. system_off()
  178. }