blk.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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. /// Driver for a VirtIO block device.
  13. ///
  14. /// This is a simple virtual block device, e.g. disk.
  15. ///
  16. /// Read and write requests (and other exotic requests) are placed in the queue and serviced
  17. /// (probably out of order) by the device except where noted.
  18. ///
  19. /// # Example
  20. ///
  21. /// ```
  22. /// # use virtio_drivers::{Error, Hal};
  23. /// # use virtio_drivers::transport::Transport;
  24. /// use virtio_drivers::device::blk::{VirtIOBlk, SECTOR_SIZE};
  25. ///
  26. /// # fn example<HalImpl: Hal, T: Transport>(transport: T) -> Result<(), Error> {
  27. /// let mut disk = VirtIOBlk::<HalImpl, _>::new(transport)?;
  28. ///
  29. /// println!("VirtIO block device: {} kB", disk.capacity() * SECTOR_SIZE as u64 / 2);
  30. ///
  31. /// // Read sector 0 and then copy it to sector 1.
  32. /// let mut buf = [0; SECTOR_SIZE];
  33. /// disk.read_block(0, &mut buf)?;
  34. /// disk.write_block(1, &buf)?;
  35. /// # Ok(())
  36. /// # }
  37. /// ```
  38. pub struct VirtIOBlk<H: Hal, T: Transport> {
  39. transport: T,
  40. queue: VirtQueue<H, { QUEUE_SIZE as usize }>,
  41. capacity: u64,
  42. readonly: bool,
  43. }
  44. impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
  45. /// Create a new VirtIO-Blk driver.
  46. pub fn new(mut transport: T) -> Result<Self> {
  47. let mut readonly = false;
  48. transport.begin_init(|features| {
  49. let features = BlkFeature::from_bits_truncate(features);
  50. info!("device features: {:?}", features);
  51. readonly = features.contains(BlkFeature::RO);
  52. // negotiate these flags only
  53. let supported_features = BlkFeature::empty();
  54. (features & supported_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. readonly,
  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.readonly
  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. /// Reads a block into the given buffer.
  88. ///
  89. /// Blocks until the read completes or there is an error.
  90. pub fn read_block(&mut self, block_id: usize, buf: &mut [u8]) -> Result {
  91. assert_eq!(buf.len(), SECTOR_SIZE);
  92. let req = BlkReq {
  93. type_: ReqType::In,
  94. reserved: 0,
  95. sector: block_id as u64,
  96. };
  97. let mut resp = BlkResp::default();
  98. self.queue.add_notify_wait_pop(
  99. &[req.as_bytes()],
  100. &mut [buf, resp.as_bytes_mut()],
  101. &mut self.transport,
  102. )?;
  103. resp.status.into()
  104. }
  105. /// Submits a request to read a block, but returns immediately without waiting for the read to
  106. /// complete.
  107. ///
  108. /// # Arguments
  109. ///
  110. /// * `block_id` - The identifier of the block to read.
  111. /// * `req` - A buffer which the driver can use for the request to send to the device. The
  112. /// contents don't matter as `read_block_nb` will initialise it, but like the other buffers it
  113. /// needs to be valid (and not otherwise used) until the corresponding `complete_read_block`
  114. /// call.
  115. /// * `buf` - The buffer in memory into which the block should be read.
  116. /// * `resp` - A mutable reference to a variable provided by the caller
  117. /// to contain the status of the request. The caller can safely
  118. /// read the variable only after the request is complete.
  119. ///
  120. /// # Usage
  121. ///
  122. /// It will submit request to the VirtIO block device and return a token identifying
  123. /// the position of the first Descriptor in the chain. If there are not enough
  124. /// Descriptors to allocate, then it returns [`Error::QueueFull`].
  125. ///
  126. /// The caller can then call `peek_used` with the returned token to check whether the device has
  127. /// finished handling the request. Once it has, the caller must call `complete_read_block` with
  128. /// the same buffers before reading the response.
  129. ///
  130. /// ```
  131. /// # use virtio_drivers::{Error, Hal};
  132. /// # use virtio_drivers::device::blk::VirtIOBlk;
  133. /// # use virtio_drivers::transport::Transport;
  134. /// use virtio_drivers::device::blk::{BlkReq, BlkResp, RespStatus};
  135. ///
  136. /// # fn example<H: Hal, T: Transport>(blk: &mut VirtIOBlk<H, T>) -> Result<(), Error> {
  137. /// let mut request = BlkReq::default();
  138. /// let mut buffer = [0; 512];
  139. /// let mut response = BlkResp::default();
  140. /// let token = unsafe { blk.read_block_nb(42, &mut request, &mut buffer, &mut response) }?;
  141. ///
  142. /// // Wait for an interrupt to tell us that the request completed...
  143. /// assert_eq!(blk.peek_used(), Some(token));
  144. ///
  145. /// unsafe {
  146. /// blk.complete_read_block(token, &request, &mut buffer, &mut response)?;
  147. /// }
  148. /// if response.status() == RespStatus::OK {
  149. /// println!("Successfully read block.");
  150. /// } else {
  151. /// println!("Error {:?} reading block.", response.status());
  152. /// }
  153. /// # Ok(())
  154. /// # }
  155. /// ```
  156. ///
  157. /// # Safety
  158. ///
  159. /// `req`, `buf` and `resp` are still borrowed by the underlying VirtIO block device even after
  160. /// this method returns. Thus, it is the caller's responsibility to guarantee that they are not
  161. /// accessed before the request is completed in order to avoid data races.
  162. pub unsafe fn read_block_nb(
  163. &mut self,
  164. block_id: usize,
  165. req: &mut BlkReq,
  166. buf: &mut [u8],
  167. resp: &mut BlkResp,
  168. ) -> Result<u16> {
  169. assert_eq!(buf.len(), SECTOR_SIZE);
  170. *req = BlkReq {
  171. type_: ReqType::In,
  172. reserved: 0,
  173. sector: block_id as u64,
  174. };
  175. let token = self
  176. .queue
  177. .add(&[req.as_bytes()], &mut [buf, resp.as_bytes_mut()])?;
  178. if self.queue.should_notify() {
  179. self.transport.notify(QUEUE);
  180. }
  181. Ok(token)
  182. }
  183. /// Completes a read operation which was started by `read_block_nb`.
  184. ///
  185. /// # Safety
  186. ///
  187. /// The same buffers must be passed in again as were passed to `read_block_nb` when it returned
  188. /// the token.
  189. pub unsafe fn complete_read_block(
  190. &mut self,
  191. token: u16,
  192. req: &BlkReq,
  193. buf: &mut [u8],
  194. resp: &mut BlkResp,
  195. ) -> Result<()> {
  196. self.queue
  197. .pop_used(token, &[req.as_bytes()], &mut [buf, resp.as_bytes_mut()])?;
  198. resp.status.into()
  199. }
  200. /// Writes the contents of the given buffer to a block.
  201. ///
  202. /// Blocks until the write is complete or there is an error.
  203. pub fn write_block(&mut self, block_id: usize, buf: &[u8]) -> Result {
  204. assert_eq!(buf.len(), SECTOR_SIZE);
  205. let req = BlkReq {
  206. type_: ReqType::Out,
  207. reserved: 0,
  208. sector: block_id as u64,
  209. };
  210. let mut resp = BlkResp::default();
  211. self.queue.add_notify_wait_pop(
  212. &[req.as_bytes(), buf],
  213. &mut [resp.as_bytes_mut()],
  214. &mut self.transport,
  215. )?;
  216. resp.status.into()
  217. }
  218. /// Submits a request to write a block, but returns immediately without waiting for the write to
  219. /// complete.
  220. ///
  221. /// # Arguments
  222. ///
  223. /// * `block_id` - The identifier of the block to write.
  224. /// * `req` - A buffer which the driver can use for the request to send to the device. The
  225. /// contents don't matter as `read_block_nb` will initialise it, but like the other buffers it
  226. /// needs to be valid (and not otherwise used) until the corresponding `complete_read_block`
  227. /// call.
  228. /// * `buf` - The buffer in memory containing the data to write to the block.
  229. /// * `resp` - A mutable reference to a variable provided by the caller
  230. /// to contain the status of the request. The caller can safely
  231. /// read the variable only after the request is complete.
  232. ///
  233. /// # Usage
  234. ///
  235. /// See [VirtIOBlk::read_block_nb].
  236. ///
  237. /// # Safety
  238. ///
  239. /// See [VirtIOBlk::read_block_nb].
  240. pub unsafe fn write_block_nb(
  241. &mut self,
  242. block_id: usize,
  243. req: &mut BlkReq,
  244. buf: &[u8],
  245. resp: &mut BlkResp,
  246. ) -> Result<u16> {
  247. assert_eq!(buf.len(), SECTOR_SIZE);
  248. *req = BlkReq {
  249. type_: ReqType::Out,
  250. reserved: 0,
  251. sector: block_id as u64,
  252. };
  253. let token = self
  254. .queue
  255. .add(&[req.as_bytes(), buf], &mut [resp.as_bytes_mut()])?;
  256. if self.queue.should_notify() {
  257. self.transport.notify(QUEUE);
  258. }
  259. Ok(token)
  260. }
  261. /// Completes a write operation which was started by `write_block_nb`.
  262. ///
  263. /// # Safety
  264. ///
  265. /// The same buffers must be passed in again as were passed to `write_block_nb` when it returned
  266. /// the token.
  267. pub unsafe fn complete_write_block(
  268. &mut self,
  269. token: u16,
  270. req: &BlkReq,
  271. buf: &[u8],
  272. resp: &mut BlkResp,
  273. ) -> Result<()> {
  274. self.queue
  275. .pop_used(token, &[req.as_bytes(), buf], &mut [resp.as_bytes_mut()])?;
  276. resp.status.into()
  277. }
  278. /// Fetches the token of the next completed request from the used ring and returns it, without
  279. /// removing it from the used ring. If there are no pending completed requests returns `None`.
  280. pub fn peek_used(&mut self) -> Option<u16> {
  281. self.queue.peek_used()
  282. }
  283. /// Returns the size of the device's VirtQueue.
  284. ///
  285. /// This can be used to tell the caller how many channels to monitor on.
  286. pub fn virt_queue_size(&self) -> u16 {
  287. QUEUE_SIZE
  288. }
  289. }
  290. impl<H: Hal, T: Transport> Drop for VirtIOBlk<H, T> {
  291. fn drop(&mut self) {
  292. // Clear any pointers pointing to DMA regions, so the device doesn't try to access them
  293. // after they have been freed.
  294. self.transport.queue_unset(QUEUE);
  295. }
  296. }
  297. #[repr(C)]
  298. struct BlkConfig {
  299. /// Number of 512 Bytes sectors
  300. capacity_low: Volatile<u32>,
  301. capacity_high: Volatile<u32>,
  302. size_max: Volatile<u32>,
  303. seg_max: Volatile<u32>,
  304. cylinders: Volatile<u16>,
  305. heads: Volatile<u8>,
  306. sectors: Volatile<u8>,
  307. blk_size: Volatile<u32>,
  308. physical_block_exp: Volatile<u8>,
  309. alignment_offset: Volatile<u8>,
  310. min_io_size: Volatile<u16>,
  311. opt_io_size: Volatile<u32>,
  312. // ... ignored
  313. }
  314. /// A VirtIO block device request.
  315. #[repr(C)]
  316. #[derive(AsBytes, Debug)]
  317. pub struct BlkReq {
  318. type_: ReqType,
  319. reserved: u32,
  320. sector: u64,
  321. }
  322. impl Default for BlkReq {
  323. fn default() -> Self {
  324. Self {
  325. type_: ReqType::In,
  326. reserved: 0,
  327. sector: 0,
  328. }
  329. }
  330. }
  331. /// Response of a VirtIOBlk request.
  332. #[repr(C)]
  333. #[derive(AsBytes, Debug, FromBytes)]
  334. pub struct BlkResp {
  335. status: RespStatus,
  336. }
  337. impl BlkResp {
  338. /// Return the status of a VirtIOBlk request.
  339. pub fn status(&self) -> RespStatus {
  340. self.status
  341. }
  342. }
  343. #[repr(u32)]
  344. #[derive(AsBytes, Debug)]
  345. enum ReqType {
  346. In = 0,
  347. Out = 1,
  348. Flush = 4,
  349. Discard = 11,
  350. WriteZeroes = 13,
  351. }
  352. /// Status of a VirtIOBlk request.
  353. #[repr(transparent)]
  354. #[derive(AsBytes, Copy, Clone, Debug, Eq, FromBytes, PartialEq)]
  355. pub struct RespStatus(u8);
  356. impl RespStatus {
  357. /// Ok.
  358. pub const OK: RespStatus = RespStatus(0);
  359. /// IoErr.
  360. pub const IO_ERR: RespStatus = RespStatus(1);
  361. /// Unsupported yet.
  362. pub const UNSUPPORTED: RespStatus = RespStatus(2);
  363. /// Not ready.
  364. pub const NOT_READY: RespStatus = RespStatus(3);
  365. }
  366. impl From<RespStatus> for Result {
  367. fn from(status: RespStatus) -> Self {
  368. match status {
  369. RespStatus::OK => Ok(()),
  370. RespStatus::IO_ERR => Err(Error::IoError),
  371. RespStatus::UNSUPPORTED => Err(Error::Unsupported),
  372. RespStatus::NOT_READY => Err(Error::NotReady),
  373. _ => Err(Error::IoError),
  374. }
  375. }
  376. }
  377. impl Default for BlkResp {
  378. fn default() -> Self {
  379. BlkResp {
  380. status: RespStatus::NOT_READY,
  381. }
  382. }
  383. }
  384. /// The standard sector size of a VirtIO block device. Data is read and written in multiples of this
  385. /// size.
  386. pub const SECTOR_SIZE: usize = 512;
  387. bitflags! {
  388. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
  389. struct BlkFeature: u64 {
  390. /// Device supports request barriers. (legacy)
  391. const BARRIER = 1 << 0;
  392. /// Maximum size of any single segment is in `size_max`.
  393. const SIZE_MAX = 1 << 1;
  394. /// Maximum number of segments in a request is in `seg_max`.
  395. const SEG_MAX = 1 << 2;
  396. /// Disk-style geometry specified in geometry.
  397. const GEOMETRY = 1 << 4;
  398. /// Device is read-only.
  399. const RO = 1 << 5;
  400. /// Block size of disk is in `blk_size`.
  401. const BLK_SIZE = 1 << 6;
  402. /// Device supports scsi packet commands. (legacy)
  403. const SCSI = 1 << 7;
  404. /// Cache flush command support.
  405. const FLUSH = 1 << 9;
  406. /// Device exports information on optimal I/O alignment.
  407. const TOPOLOGY = 1 << 10;
  408. /// Device can toggle its cache between writeback and writethrough modes.
  409. const CONFIG_WCE = 1 << 11;
  410. /// Device can support discard command, maximum discard sectors size in
  411. /// `max_discard_sectors` and maximum discard segment number in
  412. /// `max_discard_seg`.
  413. const DISCARD = 1 << 13;
  414. /// Device can support write zeroes command, maximum write zeroes sectors
  415. /// size in `max_write_zeroes_sectors` and maximum write zeroes segment
  416. /// number in `max_write_zeroes_seg`.
  417. const WRITE_ZEROES = 1 << 14;
  418. // device independent
  419. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  420. const ANY_LAYOUT = 1 << 27; // legacy
  421. const RING_INDIRECT_DESC = 1 << 28;
  422. const RING_EVENT_IDX = 1 << 29;
  423. const UNUSED = 1 << 30; // legacy
  424. const VERSION_1 = 1 << 32; // detect legacy
  425. // the following since virtio v1.1
  426. const ACCESS_PLATFORM = 1 << 33;
  427. const RING_PACKED = 1 << 34;
  428. const IN_ORDER = 1 << 35;
  429. const ORDER_PLATFORM = 1 << 36;
  430. const SR_IOV = 1 << 37;
  431. const NOTIFICATION_DATA = 1 << 38;
  432. }
  433. }
  434. #[cfg(test)]
  435. mod tests {
  436. use super::*;
  437. use crate::{
  438. hal::fake::FakeHal,
  439. transport::{
  440. fake::{FakeTransport, QueueStatus, State},
  441. DeviceStatus, DeviceType,
  442. },
  443. };
  444. use alloc::{sync::Arc, vec};
  445. use core::{mem::size_of, ptr::NonNull};
  446. use std::{sync::Mutex, thread};
  447. #[test]
  448. fn config() {
  449. let mut config_space = BlkConfig {
  450. capacity_low: Volatile::new(0x42),
  451. capacity_high: Volatile::new(0x02),
  452. size_max: Volatile::new(0),
  453. seg_max: Volatile::new(0),
  454. cylinders: Volatile::new(0),
  455. heads: Volatile::new(0),
  456. sectors: Volatile::new(0),
  457. blk_size: Volatile::new(0),
  458. physical_block_exp: Volatile::new(0),
  459. alignment_offset: Volatile::new(0),
  460. min_io_size: Volatile::new(0),
  461. opt_io_size: Volatile::new(0),
  462. };
  463. let state = Arc::new(Mutex::new(State {
  464. status: DeviceStatus::empty(),
  465. driver_features: 0,
  466. guest_page_size: 0,
  467. interrupt_pending: false,
  468. queues: vec![QueueStatus::default(); 1],
  469. }));
  470. let transport = FakeTransport {
  471. device_type: DeviceType::Console,
  472. max_queue_size: QUEUE_SIZE.into(),
  473. device_features: BlkFeature::RO.bits(),
  474. config_space: NonNull::from(&mut config_space),
  475. state: state.clone(),
  476. };
  477. let blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  478. assert_eq!(blk.capacity(), 0x02_0000_0042);
  479. assert_eq!(blk.readonly(), true);
  480. }
  481. #[test]
  482. fn read() {
  483. let mut config_space = BlkConfig {
  484. capacity_low: Volatile::new(66),
  485. capacity_high: Volatile::new(0),
  486. size_max: Volatile::new(0),
  487. seg_max: Volatile::new(0),
  488. cylinders: Volatile::new(0),
  489. heads: Volatile::new(0),
  490. sectors: Volatile::new(0),
  491. blk_size: Volatile::new(0),
  492. physical_block_exp: Volatile::new(0),
  493. alignment_offset: Volatile::new(0),
  494. min_io_size: Volatile::new(0),
  495. opt_io_size: Volatile::new(0),
  496. };
  497. let state = Arc::new(Mutex::new(State {
  498. status: DeviceStatus::empty(),
  499. driver_features: 0,
  500. guest_page_size: 0,
  501. interrupt_pending: false,
  502. queues: vec![QueueStatus::default(); 1],
  503. }));
  504. let transport = FakeTransport {
  505. device_type: DeviceType::Console,
  506. max_queue_size: QUEUE_SIZE.into(),
  507. device_features: 0,
  508. config_space: NonNull::from(&mut config_space),
  509. state: state.clone(),
  510. };
  511. let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  512. // Start a thread to simulate the device waiting for a read request.
  513. let handle = thread::spawn(move || {
  514. println!("Device waiting for a request.");
  515. State::wait_until_queue_notified(&state, QUEUE);
  516. println!("Transmit queue was notified.");
  517. state
  518. .lock()
  519. .unwrap()
  520. .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
  521. assert_eq!(
  522. request,
  523. BlkReq {
  524. type_: ReqType::In,
  525. reserved: 0,
  526. sector: 42
  527. }
  528. .as_bytes()
  529. );
  530. let mut response = vec![0; SECTOR_SIZE];
  531. response[0..9].copy_from_slice(b"Test data");
  532. response.extend_from_slice(
  533. BlkResp {
  534. status: RespStatus::OK,
  535. }
  536. .as_bytes(),
  537. );
  538. response
  539. });
  540. });
  541. // Read a block from the device.
  542. let mut buffer = [0; 512];
  543. blk.read_block(42, &mut buffer).unwrap();
  544. assert_eq!(&buffer[0..9], b"Test data");
  545. handle.join().unwrap();
  546. }
  547. #[test]
  548. fn write() {
  549. let mut config_space = BlkConfig {
  550. capacity_low: Volatile::new(66),
  551. capacity_high: Volatile::new(0),
  552. size_max: Volatile::new(0),
  553. seg_max: Volatile::new(0),
  554. cylinders: Volatile::new(0),
  555. heads: Volatile::new(0),
  556. sectors: Volatile::new(0),
  557. blk_size: Volatile::new(0),
  558. physical_block_exp: Volatile::new(0),
  559. alignment_offset: Volatile::new(0),
  560. min_io_size: Volatile::new(0),
  561. opt_io_size: Volatile::new(0),
  562. };
  563. let state = Arc::new(Mutex::new(State {
  564. status: DeviceStatus::empty(),
  565. driver_features: 0,
  566. guest_page_size: 0,
  567. interrupt_pending: false,
  568. queues: vec![QueueStatus::default(); 1],
  569. }));
  570. let transport = FakeTransport {
  571. device_type: DeviceType::Console,
  572. max_queue_size: QUEUE_SIZE.into(),
  573. device_features: 0,
  574. config_space: NonNull::from(&mut config_space),
  575. state: state.clone(),
  576. };
  577. let mut blk = VirtIOBlk::<FakeHal, FakeTransport<BlkConfig>>::new(transport).unwrap();
  578. // Start a thread to simulate the device waiting for a write request.
  579. let handle = thread::spawn(move || {
  580. println!("Device waiting for a request.");
  581. State::wait_until_queue_notified(&state, QUEUE);
  582. println!("Transmit queue was notified.");
  583. state
  584. .lock()
  585. .unwrap()
  586. .read_write_queue::<{ QUEUE_SIZE as usize }>(QUEUE, |request| {
  587. assert_eq!(
  588. &request[0..size_of::<BlkReq>()],
  589. BlkReq {
  590. type_: ReqType::Out,
  591. reserved: 0,
  592. sector: 42
  593. }
  594. .as_bytes()
  595. );
  596. let data = &request[size_of::<BlkReq>()..];
  597. assert_eq!(data.len(), SECTOR_SIZE);
  598. assert_eq!(&data[0..9], b"Test data");
  599. let mut response = Vec::new();
  600. response.extend_from_slice(
  601. BlkResp {
  602. status: RespStatus::OK,
  603. }
  604. .as_bytes(),
  605. );
  606. response
  607. });
  608. });
  609. // Write a block to the device.
  610. let mut buffer = [0; 512];
  611. buffer[0..9].copy_from_slice(b"Test data");
  612. blk.write_block(42, &mut buffer).unwrap();
  613. handle.join().unwrap();
  614. }
  615. }