xref: /aosp_15_r20/bootable/libbootloader/gbl/libstorage/src/ram_block.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This module provides an implementation of [BlockIo] backed by RAM.
16 
17 use crate::{is_aligned, is_buffer_aligned, BlockInfo, BlockIo, SliceMaybeUninit};
18 use core::ops::DerefMut;
19 use gbl_async::yield_now;
20 use liberror::Error;
21 use safemath::SafeNum;
22 
23 /// `RamBlockIo` implements [BlockIo] backed by user provided buffer.
24 pub struct RamBlockIo<T> {
25     /// The storage block size in bytes.
26     pub block_size: u64,
27     /// The storage access alignment in bytes.
28     pub alignment: u64,
29     /// The backing storage data.
30     pub storage: T,
31     /// The number of successful write calls.
32     pub num_writes: usize,
33     /// The number of successful read calls.
34     pub num_reads: usize,
35     /// Injected error to be returned by the next read/write IO.
36     pub error: Option<Error>,
37 }
38 
39 impl<T: DerefMut<Target = [u8]>> RamBlockIo<T> {
40     /// Creates an new instance.
new(block_size: u64, alignment: u64, storage: T) -> Self41     pub fn new(block_size: u64, alignment: u64, storage: T) -> Self {
42         assert_eq!(
43             storage.len() % usize::try_from(block_size).unwrap(),
44             0,
45             "storage size is not multiple of block size, {}, {}",
46             storage.len(),
47             block_size
48         );
49         Self { block_size, alignment, storage, num_writes: 0, num_reads: 0, error: None }
50     }
51 
52     /// Gets the underlying ramdisk storage.
storage(&mut self) -> &mut [u8]53     pub fn storage(&mut self) -> &mut [u8] {
54         &mut self.storage[..]
55     }
56 
57     /// Checks injected error, simulates async waiting, checks read/write parameters and returns the
58     /// offset in number of bytes.
checks( &mut self, blk_offset: u64, buf: &(impl SliceMaybeUninit + ?Sized), ) -> Result<usize, Error>59     async fn checks(
60         &mut self,
61         blk_offset: u64,
62         buf: &(impl SliceMaybeUninit + ?Sized),
63     ) -> Result<usize, Error> {
64         assert!(is_buffer_aligned(buf.as_ref(), self.alignment).unwrap_or(false));
65         assert!(is_aligned(buf.len(), self.block_size).unwrap_or(false));
66         yield_now().await;
67         self.error.take().map(|e| Err(e)).unwrap_or(Ok(()))?;
68         Ok((SafeNum::from(blk_offset) * self.block_size).try_into().unwrap())
69     }
70 }
71 
72 // SAFETY:
73 // `read_blocks` clones `out.len()` bytes to output which initializes all elements in `out`
74 unsafe impl<T: DerefMut<Target = [u8]>> BlockIo for RamBlockIo<T> {
info(&mut self) -> BlockInfo75     fn info(&mut self) -> BlockInfo {
76         BlockInfo {
77             block_size: self.block_size,
78             num_blocks: u64::try_from(self.storage.len()).unwrap() / self.block_size,
79             alignment: self.alignment,
80         }
81     }
82 
read_blocks( &mut self, blk_offset: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<(), Error>83     async fn read_blocks(
84         &mut self,
85         blk_offset: u64,
86         out: &mut (impl SliceMaybeUninit + ?Sized),
87     ) -> Result<(), Error> {
88         let offset = self.checks(blk_offset, out).await?;
89         let out_len = out.len();
90         Ok(out.clone_from_slice(&self.storage[offset..][..out_len]))
91     }
92 
write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<(), Error>93     async fn write_blocks(&mut self, blk_offset: u64, data: &mut [u8]) -> Result<(), Error> {
94         let offset = self.checks(blk_offset, &mut *data).await?;
95         Ok(self.storage[offset..][..data.len()].clone_from_slice(data))
96     }
97 }
98