blk.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. //! Driver for VirtIO block devices.
  2. use crate::hal::Hal;
  3. use crate::queue::VirtQueue;
  4. use crate::transport::Transport;
  5. use crate::volatile::{volread, Volatile};
  6. use crate::{Error, Result};
  7. use bitflags::bitflags;
  8. use log::info;
  9. use zerocopy::{AsBytes, FromBytes};
  10. const QUEUE: u16 = 0;
  11. const QUEUE_SIZE: u16 = 16;
  12. const SUPPORTED_FEATURES: BlkFeature = BlkFeature::RO.union(BlkFeature::FLUSH);
  13. /// Driver for a VirtIO block device.
  14. ///
  15. /// This is a simple virtual block device, e.g. disk.
  16. ///
  17. /// Read and write requests (and other exotic requests) are placed in the queue and serviced
  18. /// (probably out of order) by the device except where noted.
  19. ///
  20. /// # Example
  21. ///
  22. /// ```
  23. /// # use virtio_drivers::{Error, Hal};
  24. /// # use virtio_drivers::transport::Transport;
  25. /// use virtio_drivers::device::blk::{VirtIOBlk, SECTOR_SIZE};
  26. ///
  27. /// # fn example<HalImpl: Hal, T: Transport>(transport: T) -> Result<(), Error> {
  28. /// let mut disk = VirtIOBlk::<HalImpl, _>::new(transport)?;
  29. ///
  30. /// println!("VirtIO block device: {} kB", disk.capacity() * SECTOR_SIZE as u64 / 2);
  31. ///
  32. /// // Read sector 0 and then copy it to sector 1.
  33. /// let mut buf = [0; SECTOR_SIZE];
  34. /// disk.read_block(0, &mut buf)?;
  35. /// disk.write_block(1, &buf)?;
  36. /// # Ok(())
  37. /// # }
  38. /// ```
  39. pub struct VirtIOBlk<H: Hal, T: Transport> {
  40. transport: T,
  41. queue: VirtQueue<H, { QUEUE_SIZE as usize }>,
  42. capacity: u64,
  43. negotiated_features: BlkFeature,
  44. }
  45. impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
  46. /// Create a new VirtIO-Blk driver.
  47. pub fn new(mut transport: T) -> Result<Self> {
  48. let mut negotiated_features = BlkFeature::empty();
  49. transport.begin_init(|features| {
  50. let features = BlkFeature::from_bits_truncate(features);
  51. info!("device features: {:?}", features);
  52. negotiated_features = features & SUPPORTED_FEATURES;
  53. // Negotiate these features only.
  54. negotiated_features.bits()
  55. });
  56. // Read configuration space.
  57. let config = transport.config_space::<BlkConfig>()?;
  58. info!("config: {:?}", config);
  59. // Safe because config is a valid pointer to the device configuration space.
  60. let capacity = unsafe {
  61. volread!(config, capacity_low) as u64 | (volread!(config, capacity_high) as u64) << 32
  62. };
  63. info!("found a block device of size {}KB", capacity / 2);
  64. let queue = VirtQueue::new(&mut transport, QUEUE)?;
  65. transport.finish_init();
  66. Ok(VirtIOBlk {
  67. transport,
  68. queue,
  69. capacity,
  70. negotiated_features,
  71. })
  72. }
  73. /// Gets the capacity of the block device, in 512 byte ([`SECTOR_SIZE`]) sectors.
  74. pub fn capacity(&self) -> u64 {
  75. self.capacity
  76. }
  77. /// Returns true if the block device is read-only, or false if it allows writes.
  78. pub fn readonly(&self) -> bool {
  79. self.negotiated_features.contains(BlkFeature::RO)
  80. }
  81. /// Acknowledges a pending interrupt, if any.
  82. ///
  83. /// Returns true if there was an interrupt to acknowledge.
  84. pub fn ack_interrupt(&mut self) -> bool {
  85. self.transport.ack_interrupt()
  86. }
  87. /// Sends the given request to the device and waits for a response, with no extra data.
  88. fn request(&mut self, request: BlkReq) -> Result {
  89. let mut resp = BlkResp::default();
  90. self.queue.add_notify_wait_pop(
  91. &[request.as_bytes()],
  92. &mut [resp.as_bytes_mut()],
  93. &mut self.transport,
  94. )?;
  95. resp.status.into()
  96. }
  97. /// Sends the given request to the device and waits for a response, including the given data.
  98. fn request_read(&mut self, request: BlkReq, data: &mut [u8]) -> Result {
  99. let mut resp = BlkResp::default();
  100. self.queue.add_notify_wait_pop(
  101. &[request.as_bytes()],
  102. &mut [data, resp.as_bytes_mut()],
  103. &mut self.transport,
  104. )?;
  105. resp.status.into()
  106. }
  107. /// Sends the given request and data to the device and waits for a response.
  108. fn request_write(&mut self, request: BlkReq, data: &[u8]) -> Result {
  109. let mut resp = BlkResp::default();
  110. self.queue.add_notify_wait_pop(
  111. &[request.as_bytes(), data],
  112. &mut [resp.as_bytes_mut()],
  113. &mut self.transport,
  114. )?;
  115. resp.status.into()
  116. }
  117. /// Requests the device to flush any pending writes to storage.
  118. ///
  119. /// This will be ignored if the device doesn't support the `VIRTIO_BLK_F_FLUSH` feature.
  120. pub fn flush(&mut self) -> Result {
  121. if self.negotiated_features.contains(BlkFeature::FLUSH) {
  122. self.request(BlkReq {
  123. type_: ReqType::Flush,
  124. ..Default::default()
  125. })
  126. } else {
  127. Ok(())
  128. }
  129. }
  130. /// Gets the device ID.
  131. ///
  132. /// The ID is written as ASCII into the given buffer, which must be 20 bytes long, and the used
  133. /// length returned.
  134. pub fn device_id(&mut self, id: &mut [u8; 20]) -> Result<usize> {
  135. self.request_read(
  136. BlkReq {
  137. type_: ReqType::GetId,
  138. ..Default::default()
  139. },
  140. id,
  141. )?;
  142. let length = id.iter().position(|&x| x == 0).unwrap_or(20);
  143. Ok(length)
  144. }
  145. /// Reads a block into the given buffer.
  146. ///
  147. /// Blocks until the read completes or there is an error.
  148. pub fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> Result {
  149. assert_eq!(buf.len(), SECTOR_SIZE);
  150. self.request_read(
  151. BlkReq {
  152. type_: ReqType::In,
  153. reserved: 0,
  154. sector: block_id as u64,
  155. },
  156. buf,
  157. )
  158. }
  159. /// Submits a request to read a block, but returns immediately without waiting for the read to
  160. /// complete.
  161. ///
  162. /// # Arguments
  163. ///
  164. /// * `block_id` - The identifier of the block to read.
  165. /// * `req` - A buffer which the driver can use for the request to send to the device. The
  166. /// contents don't matter as `read_block_nb` will initialise it, but like the other buffers it
  167. /// needs to be valid (and not otherwise used) until the corresponding `complete_read_block`
  168. /// call.
  169. /// * `buf` - The buffer in memory into which the block should be read.
  170. /// * `resp` - A mutable reference to a variable provided by the caller
  171. /// to contain the status of the request. The caller can safely
  172. /// read the variable only after the request is complete.
  173. ///
  174. /// # Usage
  175. ///
  176. /// It will submit request to the VirtIO block device and return a token identifying
  177. /// the position of the first Descriptor in the chain. If there are not enough
  178. /// Descriptors to allocate, then it returns [`Error::QueueFull`].
  179. ///
  180. /// The caller can then call `peek_used` with the returned token to check whether the device has
  181. /// finished handling the request. Once it has, the caller must call `complete_read_block` with
  182. /// the same buffers before reading the response.
  183. ///
  184. /// ```
  185. /// # use virtio_drivers::{Error, Hal};
  186. /// # use virtio_drivers::device::blk::VirtIOBlk;
  187. /// # use virtio_drivers::transport::Transport;
  188. /// use virtio_drivers::device::blk::{BlkReq, BlkResp, RespStatus};
  189. ///
  190. /// # fn example<H: Hal, T: Transport>(blk: &mut VirtIOBlk<H, T>) -> Result<(), Error> {
  191. /// let mut request = BlkReq::default();
  192. /// let mut buffer = [0; 512];
  193. /// let mut response = BlkResp::default();
  194. /// let token = unsafe { blk.read_block_nb(42, &mut request, &mut buffer, &mut response) }?;
  195. ///
  196. /// // Wait for an interrupt to tell us that the request completed...
  197. /// assert_eq!(blk.peek_used(), Some(token));
  198. ///
  199. /// unsafe {
  200. /// blk.complete_read_block(token, &request, &mut buffer, &mut response)?;
  201. /// }
  202. /// if response.status() == RespStatus::OK {
  203. /// println!("Successfully read block.");
  204. /// } else {
  205. /// println!("Error {:?} reading block.", response.status());
  206. /// }
  207. /// # Ok(())
  208. /// # }
  209. /// ```
  210. ///
  211. /// # Safety
  212. ///
  213. /// `req`, `buf` and `resp` are still borrowed by the underlying VirtIO block device even after
  214. /// this method returns. Thus, it is the caller's responsibility to guarantee that they are not
  215. /// accessed before the request is completed in order to avoid data races.
  216. pub unsafe fn read_block_nb(
  217. &mut self,
  218. block_id: usize,
  219. req: &mut BlkReq,
  220. buf: &mut [u8],
  221. resp: &mut BlkResp,
  222. ) -> Result<u16> {
  223. assert_eq!(buf.len(), SECTOR_SIZE);
  224. *req = BlkReq {
  225. type_: ReqType::In,
  226. reserved: 0,
  227. sector: block_id as u64,
  228. };
  229. let token = self
  230. .queue
  231. .add(&[req.as_bytes()], &mut [buf, resp.as_bytes_mut()])?;
  232. if self.queue.should_notify() {
  233. self.transport.notify(QUEUE);
  234. }
  235. Ok(token)
  236. }
  237. /// Completes a read operation which was started by `read_block_nb`.
  238. ///
  239. /// # Safety
  240. ///
  241. /// The same buffers must be passed in again as were passed to `read_block_nb` when it returned
  242. /// the token.
  243. pub unsafe fn complete_read_block(
  244. &mut self,
  245. token: u16,
  246. req: &BlkReq,
  247. buf: &mut [u8],
  248. resp: &mut BlkResp,
  249. ) -> Result<()> {
  250. self.queue
  251. .pop_used(token, &[req.as_bytes()], &mut [buf, resp.as_bytes_mut()])?;
  252. resp.status.into()
  253. }
  254. /// Writes the contents of the given buffer to a block.
  255. ///
  256. /// Blocks until the write is complete or there is an error.
  257. pub fn write_block(&mut self, block_id: usize, buf: &[u8]) -> Result {
  258. assert_eq!(buf.len(), SECTOR_SIZE);
  259. self.request_write(
  260. BlkReq {
  261. type_: ReqType::Out,
  262. sector: block_id as u64,
  263. ..Default::default()
  264. },
  265. buf,
  266. )
  267. }
  268. /// Submits a request to write a block, but returns immediately without waiting for the write to
  269. /// complete.
  270. ///
  271. /// # Arguments
  272. ///
  273. /// * `block_id` - The identifier of the block to write.
  274. /// * `req` - A buffer which the driver can use for the request to send to the device. The
  275. /// contents don't matter as `read_block_nb` will initialise it, but like the other buffers it
  276. /// needs to be valid (and not otherwise used) until the corresponding `complete_read_block`
  277. /// call.
  278. /// * `buf` - The buffer in memory containing the data to write to the block.
  279. /// * `resp` - A mutable reference to a variable provided by the caller
  280. /// to contain the status of the request. The caller can safely
  281. /// read the variable only after the request is complete.
  282. ///
  283. /// # Usage
  284. ///
  285. /// See [VirtIOBlk::read_block_nb].
  286. ///
  287. /// # Safety
  288. ///
  289. /// See [VirtIOBlk::read_block_nb].
  290. pub unsafe fn write_block_nb(
  291. &mut self,
  292. block_id: usize,
  293. req: &mut BlkReq,
  294. buf: &[u8],
  295. resp: &mut BlkResp,
  296. ) -> Result<u16> {
  297. assert_eq!(buf.len(), SECTOR_SIZE);
  298. *req = BlkReq {
  299. type_: ReqType::Out,
  300. reserved: 0,
  301. sector: block_id as u64,
  302. };
  303. let token = self
  304. .queue
  305. .add(&[req.as_bytes(), buf], &mut [resp.as_bytes_mut()])?;
  306. if self.queue.should_notify() {
  307. self.transport.notify(QUEUE);
  308. }
  309. Ok(token)
  310. }
  311. /// Completes a write operation which was started by `write_block_nb`.
  312. ///
  313. /// # Safety
  314. ///
  315. /// The same buffers must be passed in again as were passed to `write_block_nb` when it returned
  316. /// the token.
  317. pub unsafe fn complete_write_block(
  318. &mut self,
  319. token: u16,
  320. req: &BlkReq,
  321. buf: &[u8],
  322. resp: &mut BlkResp,
  323. ) -> Result<()> {
  324. self.queue
  325. .pop_used(token, &[req.as_bytes(), buf], &mut [resp.as_bytes_mut()])?;
  326. resp.status.into()
  327. }
  328. /// Fetches the token of the next completed request from the used ring and returns it, without
  329. /// removing it from the used ring. If there are no pending completed requests returns `None`.
  330. pub fn peek_used(&mut self) -> Option<u16> {
  331. self.queue.peek_used()
  332. }
  333. /// Returns the size of the device's VirtQueue.
  334. ///
  335. /// This can be used to tell the caller how many channels to monitor on.
  336. pub fn virt_queue_size(&self) -> u16 {
  337. QUEUE_SIZE
  338. }
  339. }
  340. impl<H: Hal, T: Transport> Drop for VirtIOBlk<H, T> {
  341. fn drop(&mut self) {
  342. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  343. // after they have been freed.
  344. self.transport.queue_unset(QUEUE);
  345. }
  346. }
  347. #[repr(C)]
  348. struct BlkConfig {
  349. /// Number of 512 Bytes sectors
  350. capacity_low: Volatile<u32>,
  351. capacity_high: Volatile<u32>,
  352. size_max: Volatile<u32>,
  353. seg_max: Volatile<u32>,
  354. cylinders: Volatile<u16>,
  355. heads: Volatile<u8>,
  356. sectors: Volatile<u8>,
  357. blk_size: Volatile<u32>,
  358. physical_block_exp: Volatile<u8>,
  359. alignment_offset: Volatile<u8>,
  360. min_io_size: Volatile<u16>,
  361. opt_io_size: Volatile<u32>,
  362. // ... ignored
  363. }
  364. /// A VirtIO block device request.
  365. #[repr(C)]
  366. #[derive(AsBytes, Debug)]
  367. pub struct BlkReq {
  368. type_: ReqType,
  369. reserved: u32,
  370. sector: u64,
  371. }
  372. impl Default for BlkReq {
  373. fn default() -> Self {
  374. Self {
  375. type_: ReqType::In,
  376. reserved: 0,
  377. sector: 0,
  378. }
  379. }
  380. }
  381. /// Response of a VirtIOBlk request.
  382. #[repr(C)]
  383. #[derive(AsBytes, Debug, FromBytes)]
  384. pub struct BlkResp {
  385. status: RespStatus,
  386. }
  387. impl BlkResp {
  388. /// Return the status of a VirtIOBlk request.
  389. pub fn status(&self) -> RespStatus {
  390. self.status
  391. }
  392. }
  393. #[repr(u32)]
  394. #[derive(AsBytes, Debug)]
  395. enum ReqType {
  396. In = 0,
  397. Out = 1,
  398. Flush = 4,
  399. GetId = 8,
  400. GetLifetime = 10,
  401. Discard = 11,
  402. WriteZeroes = 13,
  403. SecureErase = 14,
  404. }
  405. /// Status of a VirtIOBlk request.
  406. #[repr(transparent)]
  407. #[derive(AsBytes, Copy, Clone, Debug, Eq, FromBytes, PartialEq)]
  408. pub struct RespStatus(u8);
  409. impl RespStatus {
  410. /// Ok.
  411. pub const OK: RespStatus = RespStatus(0);
  412. /// IoErr.
  413. pub const IO_ERR: RespStatus = RespStatus(1);
  414. /// Unsupported yet.
  415. pub const UNSUPPORTED: RespStatus = RespStatus(2);
  416. /// Not ready.
  417. pub const NOT_READY: RespStatus = RespStatus(3);
  418. }
  419. impl From<RespStatus> for Result {
  420. fn from(status: RespStatus) -> Self {
  421. match status {
  422. RespStatus::OK => Ok(()),
  423. RespStatus::IO_ERR => Err(Error::IoError),
  424. RespStatus::UNSUPPORTED => Err(Error::Unsupported),
  425. RespStatus::NOT_READY => Err(Error::NotReady),
  426. _ => Err(Error::IoError),
  427. }
  428. }
  429. }
  430. impl Default for BlkResp {
  431. fn default() -> Self {
  432. BlkResp {
  433. status: RespStatus::NOT_READY,
  434. }
  435. }
  436. }
  437. /// The standard sector size of a VirtIO block device. Data is read and written in multiples of this
  438. /// size.
  439. pub const SECTOR_SIZE: usize = 512;
  440. bitflags! {
  441. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
  442. struct BlkFeature: u64 {
  443. /// Device supports request barriers. (legacy)
  444. const BARRIER = 1 << 0;
  445. /// Maximum size of any single segment is in `size_max`.
  446. const SIZE_MAX = 1 << 1;
  447. /// Maximum number of segments in a request is in `seg_max`.
  448. const SEG_MAX = 1 << 2;
  449. /// Disk-style geometry specified in geometry.
  450. const GEOMETRY = 1 << 4;
  451. /// Device is read-only.
  452. const RO = 1 << 5;
  453. /// Block size of disk is in `blk_size`.
  454. const BLK_SIZE = 1 << 6;
  455. /// Device supports scsi packet commands. (legacy)
  456. const SCSI = 1 << 7;
  457. /// Cache flush command support.
  458. const FLUSH = 1 << 9;
  459. /// Device exports information on optimal I/O alignment.
  460. const TOPOLOGY = 1 << 10;
  461. /// Device can toggle its cache between writeback and writethrough modes.
  462. const CONFIG_WCE = 1 << 11;
  463. /// Device supports multiqueue.
  464. const MQ = 1 << 12;
  465. /// Device can support discard command, maximum discard sectors size in
  466. /// `max_discard_sectors` and maximum discard segment number in
  467. /// `max_discard_seg`.
  468. const DISCARD = 1 << 13;
  469. /// Device can support write zeroes command, maximum write zeroes sectors
  470. /// size in `max_write_zeroes_sectors` and maximum write zeroes segment
  471. /// number in `max_write_zeroes_seg`.
  472. const WRITE_ZEROES = 1 << 14;
  473. /// Device supports providing storage lifetime information.
  474. const LIFETIME = 1 << 15;
  475. /// Device can support the secure erase command.
  476. const SECURE_ERASE = 1 << 16;
  477. // device independent
  478. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  479. const ANY_LAYOUT = 1 << 27; // legacy
  480. const RING_INDIRECT_DESC = 1 << 28;
  481. const RING_EVENT_IDX = 1 << 29;
  482. const UNUSED = 1 << 30; // legacy
  483. const VERSION_1 = 1 << 32; // detect legacy
  484. // the following since virtio v1.1
  485. const ACCESS_PLATFORM = 1 << 33;
  486. const RING_PACKED = 1 << 34;
  487. const IN_ORDER = 1 << 35;
  488. const ORDER_PLATFORM = 1 << 36;
  489. const SR_IOV = 1 << 37;
  490. const NOTIFICATION_DATA = 1 << 38;
  491. }
  492. }
  493. #[cfg(test)]
  494. mod tests {
  495. use super::*;
  496. use crate::{
  497. hal::fake::FakeHal,
  498. transport::{
  499. fake::{FakeTransport, QueueStatus, State},
  500. DeviceStatus, DeviceType,
  501. },
  502. };
  503. use alloc::{sync::Arc, vec};
  504. use core::{mem::size_of, ptr::NonNull};
  505. use std::{sync::Mutex, thread};
  506. #[test]
  507. fn config() {
  508. let mut config_space = BlkConfig {
  509. capacity_low: Volatile::new(0x42),
  510. capacity_high: Volatile::new(0x02),
  511. size_max: Volatile::new(0),
  512. seg_max: Volatile::new(0),
  513. cylinders: Volatile::new(0),
  514. heads: Volatile::new(0),
  515. sectors: Volatile::new(0),
  516. blk_size: Volatile::new(0),
  517. physical_block_exp: Volatile::new(0),
  518. alignment_offset: Volatile::new(0),
  519. min_io_size: Volatile::new(0),
  520. opt_io_size: Volatile::new(0),
  521. };
  522. let state = Arc::new(Mutex::new(State {
  523. status: DeviceStatus::empty(),
  524. driver_features: 0,
  525. guest_page_size: 0,
  526. interrupt_pending: false,
  527. queues: vec![QueueStatus::default()],
  528. }));
  529. let transport = FakeTransport {
  530. device_type: DeviceType::Console,
  531. max_queue_size: QUEUE_SIZE.into(),
  532. device_features: BlkFeature::RO.bits(),
  533. config_space: NonNull::from(&mut config_space),
  534. state: state.clone(),
  535. };
  536. let blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  537. assert_eq!(blk.capacity(), 0x02_0000_0042);
  538. assert_eq!(blk.readonly(), true);
  539. }
  540. #[test]
  541. fn read() {
  542. let mut config_space = BlkConfig {
  543. capacity_low: Volatile::new(66),
  544. capacity_high: Volatile::new(0),
  545. size_max: Volatile::new(0),
  546. seg_max: Volatile::new(0),
  547. cylinders: Volatile::new(0),
  548. heads: Volatile::new(0),
  549. sectors: Volatile::new(0),
  550. blk_size: Volatile::new(0),
  551. physical_block_exp: Volatile::new(0),
  552. alignment_offset: Volatile::new(0),
  553. min_io_size: Volatile::new(0),
  554. opt_io_size: Volatile::new(0),
  555. };
  556. let state = Arc::new(Mutex::new(State {
  557. status: DeviceStatus::empty(),
  558. driver_features: 0,
  559. guest_page_size: 0,
  560. interrupt_pending: false,
  561. queues: vec![QueueStatus::default()],
  562. }));
  563. let transport = FakeTransport {
  564. device_type: DeviceType::Console,
  565. max_queue_size: QUEUE_SIZE.into(),
  566. device_features: 0,
  567. config_space: NonNull::from(&mut config_space),
  568. state: state.clone(),
  569. };
  570. let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  571. // Start a thread to simulate the device waiting for a read request.
  572. let handle = thread::spawn(move || {
  573. println!("Device waiting for a request.");
  574. State::wait_until_queue_notified(&state, QUEUE);
  575. println!("Transmit queue was notified.");
  576. state
  577. .lock()
  578. .unwrap()
  579. .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
  580. assert_eq!(
  581. request,
  582. BlkReq {
  583. type_: ReqType::In,
  584. reserved: 0,
  585. sector: 42
  586. }
  587. .as_bytes()
  588. );
  589. let mut response = vec![0; SECTOR_SIZE];
  590. response[0..9].copy_from_slice(b"Test data");
  591. response.extend_from_slice(
  592. BlkResp {
  593. status: RespStatus::OK,
  594. }
  595. .as_bytes(),
  596. );
  597. response
  598. });
  599. });
  600. // Read a block from the device.
  601. let mut buffer = [0; 512];
  602. blk.read_block(42, &mut buffer).unwrap();
  603. assert_eq!(&buffer[0..9], b"Test data");
  604. handle.join().unwrap();
  605. }
  606. #[test]
  607. fn write() {
  608. let mut config_space = BlkConfig {
  609. capacity_low: Volatile::new(66),
  610. capacity_high: Volatile::new(0),
  611. size_max: Volatile::new(0),
  612. seg_max: Volatile::new(0),
  613. cylinders: Volatile::new(0),
  614. heads: Volatile::new(0),
  615. sectors: Volatile::new(0),
  616. blk_size: Volatile::new(0),
  617. physical_block_exp: Volatile::new(0),
  618. alignment_offset: Volatile::new(0),
  619. min_io_size: Volatile::new(0),
  620. opt_io_size: Volatile::new(0),
  621. };
  622. let state = Arc::new(Mutex::new(State {
  623. status: DeviceStatus::empty(),
  624. driver_features: 0,
  625. guest_page_size: 0,
  626. interrupt_pending: false,
  627. queues: vec![QueueStatus::default()],
  628. }));
  629. let transport = FakeTransport {
  630. device_type: DeviceType::Console,
  631. max_queue_size: QUEUE_SIZE.into(),
  632. device_features: 0,
  633. config_space: NonNull::from(&mut config_space),
  634. state: state.clone(),
  635. };
  636. let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  637. // Start a thread to simulate the device waiting for a write request.
  638. let handle = thread::spawn(move || {
  639. println!("Device waiting for a request.");
  640. State::wait_until_queue_notified(&state, QUEUE);
  641. println!("Transmit queue was notified.");
  642. state
  643. .lock()
  644. .unwrap()
  645. .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
  646. assert_eq!(
  647. &request[0..size_of::<BlkReq>()],
  648. BlkReq {
  649. type_: ReqType::Out,
  650. reserved: 0,
  651. sector: 42
  652. }
  653. .as_bytes()
  654. );
  655. let data = &request[size_of::<BlkReq>()..];
  656. assert_eq!(data.len(), SECTOR_SIZE);
  657. assert_eq!(&data[0..9], b"Test data");
  658. let mut response = Vec::new();
  659. response.extend_from_slice(
  660. BlkResp {
  661. status: RespStatus::OK,
  662. }
  663. .as_bytes(),
  664. );
  665. response
  666. });
  667. });
  668. // Write a block to the device.
  669. let mut buffer = [0; 512];
  670. buffer[0..9].copy_from_slice(b"Test data");
  671. blk.write_block(42, &mut buffer).unwrap();
  672. // Request to flush should be ignored as the device doesn't support it.
  673. blk.flush().unwrap();
  674. handle.join().unwrap();
  675. }
  676. #[test]
  677. fn flush() {
  678. let mut config_space = BlkConfig {
  679. capacity_low: Volatile::new(66),
  680. capacity_high: Volatile::new(0),
  681. size_max: Volatile::new(0),
  682. seg_max: Volatile::new(0),
  683. cylinders: Volatile::new(0),
  684. heads: Volatile::new(0),
  685. sectors: Volatile::new(0),
  686. blk_size: Volatile::new(0),
  687. physical_block_exp: Volatile::new(0),
  688. alignment_offset: Volatile::new(0),
  689. min_io_size: Volatile::new(0),
  690. opt_io_size: Volatile::new(0),
  691. };
  692. let state = Arc::new(Mutex::new(State {
  693. status: DeviceStatus::empty(),
  694. driver_features: 0,
  695. guest_page_size: 0,
  696. interrupt_pending: false,
  697. queues: vec![QueueStatus::default()],
  698. }));
  699. let transport = FakeTransport {
  700. device_type: DeviceType::Console,
  701. max_queue_size: QUEUE_SIZE.into(),
  702. device_features: BlkFeature::FLUSH.bits(),
  703. config_space: NonNull::from(&mut config_space),
  704. state: state.clone(),
  705. };
  706. let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  707. // Start a thread to simulate the device waiting for a flush request.
  708. let handle = thread::spawn(move || {
  709. println!("Device waiting for a request.");
  710. State::wait_until_queue_notified(&state, QUEUE);
  711. println!("Transmit queue was notified.");
  712. state
  713. .lock()
  714. .unwrap()
  715. .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
  716. assert_eq!(
  717. request,
  718. BlkReq {
  719. type_: ReqType::Flush,
  720. reserved: 0,
  721. sector: 0,
  722. }
  723. .as_bytes()
  724. );
  725. let mut response = Vec::new();
  726. response.extend_from_slice(
  727. BlkResp {
  728. status: RespStatus::OK,
  729. }
  730. .as_bytes(),
  731. );
  732. response
  733. });
  734. });
  735. // Request to flush.
  736. blk.flush().unwrap();
  737. handle.join().unwrap();
  738. }
  739. #[test]
  740. fn device_id() {
  741. let mut config_space = BlkConfig {
  742. capacity_low: Volatile::new(66),
  743. capacity_high: Volatile::new(0),
  744. size_max: Volatile::new(0),
  745. seg_max: Volatile::new(0),
  746. cylinders: Volatile::new(0),
  747. heads: Volatile::new(0),
  748. sectors: Volatile::new(0),
  749. blk_size: Volatile::new(0),
  750. physical_block_exp: Volatile::new(0),
  751. alignment_offset: Volatile::new(0),
  752. min_io_size: Volatile::new(0),
  753. opt_io_size: Volatile::new(0),
  754. };
  755. let state = Arc::new(Mutex::new(State {
  756. status: DeviceStatus::empty(),
  757. driver_features: 0,
  758. guest_page_size: 0,
  759. interrupt_pending: false,
  760. queues: vec![QueueStatus::default()],
  761. }));
  762. let transport = FakeTransport {
  763. device_type: DeviceType::Console,
  764. max_queue_size: QUEUE_SIZE.into(),
  765. device_features: 0,
  766. config_space: NonNull::from(&mut config_space),
  767. state: state.clone(),
  768. };
  769. let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  770. // Start a thread to simulate the device waiting for a flush request.
  771. let handle = thread::spawn(move || {
  772. println!("Device waiting for a request.");
  773. State::wait_until_queue_notified(&state, QUEUE);
  774. println!("Transmit queue was notified.");
  775. state
  776. .lock()
  777. .unwrap()
  778. .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
  779. assert_eq!(
  780. request,
  781. BlkReq {
  782. type_: ReqType::GetId,
  783. reserved: 0,
  784. sector: 0,
  785. }
  786. .as_bytes()
  787. );
  788. let mut response = Vec::new();
  789. response.extend_from_slice(b"device_id\0\0\0\0\0\0\0\0\0\0\0");
  790. response.extend_from_slice(
  791. BlkResp {
  792. status: RespStatus::OK,
  793. }
  794. .as_bytes(),
  795. );
  796. response
  797. });
  798. });
  799. let mut id = [0; 20];
  800. let length = blk.device_id(&mut id).unwrap();
  801. assert_eq!(&id[0..length], b"device_id");
  802. handle.join().unwrap();
  803. }
  804. }