blk.rs 29 KB

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