cat_dev/fsemul/sdio/proto/
read.rs

1//! An SDIO 'read' request to read bytes from somewhere on the disk.
2
3use crate::fsemul::sdio::{
4	errors::{SdioApiError, SdioProtocolError},
5	proto::SDIO_BLOCK_SIZE_AS_U32,
6};
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
9
10/// Handle a Read Request coming over the SDIO Control port.
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct SdioControlReadRequest {
13	lba: u32,
14	blocks: u32,
15	channel: u32,
16}
17
18impl SdioControlReadRequest {
19	/// Create a new SDIO Read Request to head to the `CONTROL` port.
20	///
21	/// This assumes you're passing in the LBA as it appears in the DLF file,
22	/// (e.g. divisble by [`SDIO_BLOCK_SIZE_AS_U32`]). If you want the raw LBA
23	/// you can call [`Self::new_with_raw_lba`].
24	///
25	/// ## Errors
26	///
27	/// - If the LBA address is not a possible block address (must be divisble by
28	///   [`SDIO_BLOCK_SIZE_AS_U32`]).
29	/// - If the channel's first byte is greater than or equal to `0xC` when
30	///   encoded to little endian.
31	pub fn new(lba: u32, blocks: u32, channel: u32) -> Result<Self, SdioApiError> {
32		if lba < SDIO_BLOCK_SIZE_AS_U32 || !lba.is_multiple_of(SDIO_BLOCK_SIZE_AS_U32) {
33			return Err(SdioApiError::InvalidLBA(lba));
34		}
35		let as_bytes = channel.to_le_bytes();
36		if as_bytes[0] >= 0xC {
37			return Err(SdioApiError::InvalidChannel(as_bytes[0], channel));
38		}
39
40		Ok(Self {
41			lba: lba / SDIO_BLOCK_SIZE_AS_U32,
42			blocks,
43			channel,
44		})
45	}
46
47	/// Create a new SDIO Read Request to head to the `CONTROL` port.
48	///
49	/// This assumes you're passing in the LBA as it appears on the network,
50	/// (e.g. not the number being divisble by 512).
51	///
52	/// ## Errors
53	///
54	/// - If the channel's first byte is greater than or equal to `0xC` when
55	///   encoded to little endian.
56	pub fn new_with_raw_lba(raw_lba: u32, blocks: u32, channel: u32) -> Result<Self, SdioApiError> {
57		let as_bytes = channel.to_le_bytes();
58		if as_bytes[0] >= 0xC {
59			return Err(SdioApiError::InvalidChannel(as_bytes[0], channel));
60		}
61
62		Ok(Self {
63			lba: raw_lba,
64			blocks,
65			channel,
66		})
67	}
68
69	/// Get the address to read from.
70	#[must_use]
71	pub const fn lba(&self) -> u32 {
72		self.lba * SDIO_BLOCK_SIZE_AS_U32
73	}
74
75	/// Set the "raw" address to read from, this is not in the same form as
76	/// `read_request.lba()`.
77	///
78	/// This is if we took the LBA returned by the LBA block method and divided
79	/// it by block size.
80	pub fn set_raw_lba(&mut self, new_lba: u32) {
81		self.lba = new_lba;
82	}
83
84	/// Set the address to read from.
85	///
86	/// ## Errors
87	///
88	/// - If the LBA address is not a possible block address (must be divisble by
89	///   [`SDIO_BLOCK_SIZE_AS_U32`]).
90	pub fn set_lba(&mut self, new_lba: u32) -> Result<(), SdioApiError> {
91		if new_lba < SDIO_BLOCK_SIZE_AS_U32 || !new_lba.is_multiple_of(SDIO_BLOCK_SIZE_AS_U32) {
92			return Err(SdioApiError::InvalidLBA(new_lba));
93		}
94
95		self.lba = new_lba / SDIO_BLOCK_SIZE_AS_U32;
96		Ok(())
97	}
98
99	/// Get the amount of blocks to read.
100	#[must_use]
101	pub const fn blocks(&self) -> u32 {
102		self.blocks
103	}
104
105	/// Set the amount of blocks to read from SDIO.
106	pub fn set_blocks(&mut self, new_blocks: u32) {
107		self.blocks = new_blocks;
108	}
109
110	/// Get the channel to read from.
111	#[must_use]
112	pub const fn channel(&self) -> u32 {
113		self.channel
114	}
115
116	/// Set the channel this read request is on.
117	///
118	/// ## Errors
119	///
120	/// - If the channel's first byte is greater than or equal to `0xC` when
121	///   encoded to little endian.
122	pub fn set_channel(&mut self, new_channel: u32) -> Result<(), SdioApiError> {
123		let as_bytes = new_channel.to_le_bytes();
124		if as_bytes[0] >= 0xC {
125			return Err(SdioApiError::InvalidChannel(as_bytes[0], new_channel));
126		}
127
128		self.channel = new_channel;
129		Ok(())
130	}
131}
132
133impl TryFrom<Bytes> for SdioControlReadRequest {
134	type Error = SdioProtocolError;
135
136	fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
137		if value.len() != 512 {
138			return Err(SdioProtocolError::PrintfInvalidSize(value.len()));
139		}
140		let packet_type = value.get_u16_le();
141		if packet_type != 0 {
142			return Err(SdioProtocolError::UnknownPrintfPacketType(packet_type));
143		}
144		_ = value.get_u16_le();
145
146		let lba = value.get_u32_le();
147		let blocks = value.get_u32_le();
148		if value[0] >= 0xC {
149			return Err(SdioProtocolError::PrintfInvalidChannel(
150				value[0],
151				u32::from_le_bytes([value[0], value[1], value[2], value[3]]),
152			));
153		}
154		let channel = value.get_u32_le();
155
156		Ok(Self {
157			lba,
158			blocks,
159			channel,
160		})
161	}
162}
163
164impl TryFrom<&SdioControlReadRequest> for Bytes {
165	type Error = SdioProtocolError;
166
167	fn try_from(value: &SdioControlReadRequest) -> Result<Self, Self::Error> {
168		let channel_first_byte = value.channel.to_le_bytes()[0];
169		if channel_first_byte >= 0xC {
170			return Err(SdioProtocolError::PrintfInvalidChannel(
171				channel_first_byte,
172				value.channel,
173			));
174		}
175		let mut serialized = BytesMut::with_capacity(512);
176		serialized.put_u32_le(0);
177		serialized.put_u32_le(value.lba);
178		serialized.put_u32_le(value.blocks);
179		serialized.put_u32_le(value.channel);
180		serialized.extend_from_slice(&[0; 0x1F0]);
181		Ok(serialized.freeze())
182	}
183}
184
185impl TryFrom<SdioControlReadRequest> for Bytes {
186	type Error = SdioProtocolError;
187
188	fn try_from(value: SdioControlReadRequest) -> Result<Self, Self::Error> {
189		Self::try_from(&value)
190	}
191}
192
193const CONTROL_READ_REQUEST_FIELDS: &[NamedField<'static>] = &[
194	NamedField::new("raw_lba"),
195	NamedField::new("blocks"),
196	NamedField::new("channel"),
197];
198
199impl Structable for SdioControlReadRequest {
200	fn definition(&self) -> StructDef<'_> {
201		StructDef::new_static(
202			"SdioControlReadRequest",
203			Fields::Named(CONTROL_READ_REQUEST_FIELDS),
204		)
205	}
206}
207
208impl Valuable for SdioControlReadRequest {
209	fn as_value(&self) -> Value<'_> {
210		Value::Structable(self)
211	}
212
213	fn visit(&self, visitor: &mut dyn Visit) {
214		visitor.visit_named_fields(&NamedValues::new(
215			CONTROL_READ_REQUEST_FIELDS,
216			&[
217				Valuable::as_value(&self.lba),
218				Valuable::as_value(&self.blocks),
219				Valuable::as_value(&self.channel),
220			],
221		));
222	}
223}
224
225#[cfg(test)]
226mod unit_tests {
227	use super::*;
228
229	#[test]
230	pub fn parse_read_request() {
231		// Real life read request packet being parsed.
232		{
233			let read_request = SdioControlReadRequest::try_from(Bytes::from(vec![
234				0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
235				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271			]))
272			.expect("Failed to parse real life SDIO Control Read Request");
273
274			assert_eq!(
275				read_request.lba(),
276				0xFFFF_0000,
277				"Failed to parse correct address to read from on a real life read request.",
278			);
279			assert_eq!(
280				read_request.blocks(),
281				2,
282				"Failed to parse correct amount of blocks to read from real life read request.",
283			);
284			assert_eq!(
285				read_request.channel(),
286				0,
287				"Failed to parse the correct channel to read from on a real life read request.",
288			);
289		}
290	}
291}