1use crate::sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
2use alloc::sync::Arc;
3use bincode::config::standard;
4use bincode::enc::write::Writer as BincodeWriter;
5use bincode::error::EncodeError;
6use bincode::{Encode, encode_into_slice, encode_into_writer};
7use core::cell::UnsafeCell;
8use cu29::prelude::*;
9
10const BLK: usize = 512;
11
12pub struct ForceSyncSend<T>(UnsafeCell<T>);
13impl<T> ForceSyncSend<T> {
14 pub const fn new(inner: T) -> Self {
15 Self(UnsafeCell::new(inner))
16 }
17 #[inline]
18 fn inner(&self) -> &T {
19 unsafe { &*self.0.get() }
20 }
21 #[inline]
22 #[allow(clippy::mut_from_ref)]
23 fn inner_mut(&self) -> &mut T {
24 unsafe { &mut *self.0.get() }
25 }
26}
27unsafe impl<T> Send for ForceSyncSend<T> {}
28unsafe impl<T> Sync for ForceSyncSend<T> {}
29
30impl<B: BlockDevice> BlockDevice for ForceSyncSend<B> {
31 type Error = B::Error;
32
33 #[cfg(all(feature = "eh02", not(feature = "eh1")))]
34 fn read(&self, blocks: &mut [Block], start: BlockIdx, reason: &str) -> Result<(), Self::Error> {
35 self.inner_mut().read(blocks, start, reason)
36 }
37
38 #[cfg(feature = "eh1")]
39 fn read(&self, blocks: &mut [Block], start: BlockIdx) -> Result<(), Self::Error> {
40 self.inner_mut().read(blocks, start)
41 }
42
43 fn write(&self, blocks: &[Block], start: BlockIdx) -> Result<(), Self::Error> {
44 self.inner_mut().write(blocks, start)
45 }
46 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
47 self.inner().num_blocks()
48 }
49}
50
51pub struct SdBlockWriter<BD: BlockDevice> {
53 bd: Arc<ForceSyncSend<BD>>,
54 current_blk: BlockIdx, position_blk: usize, capacity_bytes: usize, written: usize, buffer: Block, }
60
61impl<BD: BlockDevice> SdBlockWriter<BD> {
62 pub fn new(bd: Arc<ForceSyncSend<BD>>, start_block: BlockIdx, capacity_bytes: usize) -> Self {
63 Self {
64 bd,
65 current_blk: start_block,
66 position_blk: 0,
67 capacity_bytes,
68 written: 0,
69 buffer: Block::new(),
70 }
71 }
72
73 #[inline]
74 fn flush_full(&mut self) -> Result<(), EncodeError> {
75 self.bd
76 .write(core::slice::from_ref(&self.buffer), self.current_blk)
77 .expect("write failed on full block");
78 self.current_blk += BlockCount(1);
79 self.position_blk = 0;
80 self.buffer = Block::new();
81 Ok(())
82 }
83
84 pub fn flush_tail(&mut self) -> Result<(), EncodeError> {
86 if self.position_blk != 0 {
87 self.bd
88 .write(core::slice::from_ref(&self.buffer), self.current_blk)
89 .expect("write failed on flush");
90 self.current_blk += BlockCount(1);
92 self.position_blk = 0;
93 self.buffer = Block::new();
94 }
95 Ok(())
96 }
97}
98
99impl<BD: BlockDevice> BincodeWriter for SdBlockWriter<BD> {
100 fn write(&mut self, mut bytes: &[u8]) -> Result<(), EncodeError> {
101 if self
102 .written
103 .checked_add(bytes.len())
104 .is_none_or(|w| w > self.capacity_bytes)
105 {
106 return Err(EncodeError::UnexpectedEnd);
107 }
108
109 if self.position_blk != 0 {
110 let take = core::cmp::min(BLK - self.position_blk, bytes.len());
111 self.buffer.as_mut()[self.position_blk..self.position_blk + take]
112 .copy_from_slice(&bytes[..take]);
113 self.position_blk += take;
114 self.written += take;
115 bytes = &bytes[take..];
116 if self.position_blk == BLK {
117 self.flush_full()?;
118 }
119 }
120
121 while bytes.len() >= BLK {
122 let mut blk = Block::new();
123 blk.as_mut().copy_from_slice(&bytes[..BLK]);
124 self.bd
125 .write(core::slice::from_ref(&blk), self.current_blk)
126 .expect("write failed");
127 self.current_blk += BlockCount(1);
128 self.written += BLK;
129 bytes = &bytes[BLK..];
130 }
131
132 if !bytes.is_empty() {
133 let n = bytes.len();
134 self.buffer.as_mut()[self.position_blk..self.position_blk + n].copy_from_slice(bytes);
135 self.position_blk += n;
136 self.written += n;
137 if self.position_blk == BLK {
138 self.flush_full()?;
139 }
140 }
141
142 Ok(())
143 }
144}
145
146pub struct EMMCSectionStorage<BD: BlockDevice> {
147 bd: Arc<ForceSyncSend<BD>>,
148 start_block: BlockIdx,
149 content_writer: SdBlockWriter<BD>,
150}
151
152impl<BD: BlockDevice> EMMCSectionStorage<BD> {
153 fn new(bd: Arc<ForceSyncSend<BD>>, start_block: BlockIdx, data_capacity: usize) -> Self {
154 let content_writer =
156 SdBlockWriter::new(bd.clone(), start_block + BlockCount(1), data_capacity); Self {
158 bd,
159 start_block,
160 content_writer,
161 }
162 }
163}
164
165impl<BD: BlockDevice> SectionStorage for EMMCSectionStorage<BD> {
166 fn initialize<E: Encode>(&mut self, header: &E) -> Result<usize, EncodeError> {
167 self.post_update_header(header)?;
168 Ok(SECTION_HEADER_COMPACT_SIZE as usize)
169 }
170
171 fn post_update_header<E: Encode>(&mut self, header: &E) -> Result<usize, EncodeError> {
172 let mut block = Block::new();
174 let wrote = encode_into_slice(header, block.as_mut(), standard())?;
175 self.bd
176 .write(&[block], self.start_block)
177 .map_err(|_| EncodeError::UnexpectedEnd)?;
178 Ok(wrote)
179 }
180
181 fn append<E: Encode>(&mut self, entry: &E) -> Result<usize, EncodeError> {
182 let bf = self.content_writer.written;
183 encode_into_writer(entry, &mut self.content_writer, standard())
184 .map_err(|_| EncodeError::UnexpectedEnd)?;
185 Ok(self.content_writer.written - bf)
186 }
187
188 fn flush(&mut self) -> CuResult<usize> {
189 let bf = self.content_writer.written;
190 self.content_writer
191 .flush_tail()
192 .map_err(|_| CuError::from("flush failed"))?;
193 Ok(self.content_writer.written - bf)
194 }
195}
196
197pub struct EMMCLogger<BD: BlockDevice> {
198 bd: Arc<ForceSyncSend<BD>>,
199 next_block: BlockIdx,
200 last_block: BlockIdx,
201 temporary_end_marker: Option<BlockIdx>,
202}
203
204impl<BD: BlockDevice> EMMCLogger<BD> {
205 pub fn new(bd: BD, start: BlockIdx, size: BlockCount) -> CuResult<Self> {
206 let main_header = MainHeader {
207 magic: MAIN_MAGIC,
208 first_section_offset: BLK as u16,
209 page_size: BLK as u16,
210 };
211 let mut block: Block = Block::new();
212
213 encode_into_slice(&main_header, block.as_mut(), standard())
214 .map_err(|_| CuError::from("Could not encode the main header"))?;
215
216 bd.write(&[block], start)
217 .map_err(|_| CuError::from("Could not write main header"))?;
218
219 let next_block = start + BlockCount(1); let last_block = start + size;
221
222 Ok(Self {
223 bd: Arc::new(ForceSyncSend::new(bd)),
224 next_block,
225 last_block,
226 temporary_end_marker: None,
227 })
228 }
229
230 fn alloc_section(&mut self, size: BlockCount) -> CuResult<BlockIdx> {
232 let start = self.next_block;
233 self.next_block += size;
234 if self.next_block > self.last_block {
235 return Err(CuError::from("out of space"));
236 }
237 Ok(start)
238 }
239
240 fn clear_temporary_end_marker(&mut self) {
241 if let Some(marker) = self.temporary_end_marker.take() {
242 self.next_block = marker;
243 }
244 }
245
246 fn write_end_marker(&mut self, temporary: bool) -> CuResult<()> {
247 let block_size = SECTION_HEADER_COMPACT_SIZE as usize;
248 let blocks_needed = 1; let start_block = self.next_block;
250 let end_block = start_block + BlockCount(blocks_needed as u32);
251 if end_block > self.last_block {
252 return Err(CuError::from("out of space"));
253 }
254
255 let header = SectionHeader {
256 magic: SECTION_MAGIC,
257 block_size: SECTION_HEADER_COMPACT_SIZE,
258 entry_type: UnifiedLogType::LastEntry,
259 offset_to_next_section: (blocks_needed * block_size) as u32,
260 used: 0,
261 is_open: temporary,
262 };
263
264 let mut header_block = Block::new();
265 encode_into_slice(&header, header_block.as_mut(), standard())
266 .map_err(|_| CuError::from("Could not encode end-of-log header"))?;
267 self.bd
268 .write(&[header_block], start_block)
269 .map_err(|_| CuError::from("Could not write end-of-log header"))?;
270
271 self.temporary_end_marker = Some(start_block);
272 self.next_block = end_block;
273 Ok(())
274 }
275}
276
277impl<BD> UnifiedLogWrite<EMMCSectionStorage<BD>> for EMMCLogger<BD>
278where
279 BD: BlockDevice + Send + Sync + 'static,
280{
281 fn add_section(
282 &mut self,
283 entry_type: UnifiedLogType,
284 requested_section_size: usize,
285 ) -> CuResult<SectionHandle<EMMCSectionStorage<BD>>> {
286 self.clear_temporary_end_marker();
287 let block_size = SECTION_HEADER_COMPACT_SIZE; if block_size != 512 {
289 panic!("EMMC: only 512 byte blocks supported");
290 }
291
292 let section_header = SectionHeader {
293 magic: SECTION_MAGIC,
294 block_size,
295 entry_type,
296 offset_to_next_section: requested_section_size as u32,
297 used: 0,
298 is_open: true,
299 };
300
301 let section_size_in_blks: u32 = (requested_section_size / block_size as usize) as u32 + 1; let start_block = self.alloc_section(BlockCount(section_size_in_blks))?;
303
304 let storage = EMMCSectionStorage::new(
305 Arc::clone(&self.bd),
306 start_block,
307 ((section_size_in_blks - 1) * block_size as u32) as usize,
308 );
309
310 let handle = SectionHandle::create(section_header, storage)?;
312 self.write_end_marker(true)?;
313 Ok(handle)
314 }
315
316 fn flush_section(&mut self, section: &mut SectionHandle<EMMCSectionStorage<BD>>) {
317 section.mark_closed();
318 section
320 .get_storage_mut()
321 .flush()
322 .expect("EMMC: flush failed");
323 section
325 .post_update_header()
326 .expect("EMMC: post update header failed");
327 }
328
329 fn status(&self) -> UnifiedLogStatus {
330 UnifiedLogStatus {
331 total_used_space: (self.next_block.0 as usize) * BLK,
332 total_allocated_space: (self.next_block.0 as usize) * BLK,
333 }
334 }
335}
336
337impl<BD: BlockDevice> Drop for EMMCLogger<BD> {
338 fn drop(&mut self) {
339 self.clear_temporary_end_marker();
340 if let Err(e) = self.write_end_marker(false) {
341 panic!("Failed to flush the unified logger: {}", e);
342 }
343 }
344}