Nothing to see here, move along meow
1#[cfg(feature = "userspace")]
2mod real_io {
3 use crate::error::FsError;
4 use lancer_core::block_io::{BlockRequest, BlockResponse};
5 use lancer_core::fs::BLOCK_SIZE_MIN;
6 use lancer_core::packet_ring::{PacketRingReader, PacketRingWriter};
7 use lancer_user::syscall;
8
9 const DRIVER_NOTIF_SLOT: u64 = 4;
10 const NOTIF_SLOT: u64 = 3;
11 const POLL_LIMIT: u32 = 10_000_000;
12 const PUSH_RETRY_LIMIT: u32 = 100_000;
13
14 pub struct BlockIo {
15 request_ring: PacketRingWriter,
16 response_ring: PacketRingReader,
17 data_area: *mut u8,
18 data_area_size: usize,
19 sector_size: u32,
20 next_tag: u32,
21 }
22
23 impl BlockIo {
24 #[allow(clippy::missing_safety_doc)]
25 pub unsafe fn init(
26 request_ring: PacketRingWriter,
27 response_ring: PacketRingReader,
28 data_area: *mut u8,
29 data_area_size: usize,
30 sector_size: u32,
31 ) -> Self {
32 Self {
33 request_ring,
34 response_ring,
35 data_area,
36 data_area_size,
37 sector_size,
38 next_tag: 0,
39 }
40 }
41
42 fn alloc_tag(&mut self) -> u32 {
43 let tag = self.next_tag;
44 self.next_tag = self.next_tag.wrapping_add(1);
45 tag
46 }
47
48 fn push_request(&self, req: &BlockRequest) -> Result<(), FsError> {
49 let data = req.as_bytes();
50 let pushed = (0..PUSH_RETRY_LIMIT).any(|_| self.request_ring.try_push(data));
51 match pushed {
52 true => Ok(()),
53 false => Err(FsError::RingFull),
54 }
55 }
56
57 fn wait_response(&self, expected_tag: u32) -> Result<BlockResponse, FsError> {
58 let mut stale_count: u32 = 0;
59 (0..POLL_LIMIT)
60 .find_map(|_| {
61 let mut buf = [0u8; 32];
62 match self.response_ring.try_pop(&mut buf) {
63 Some(len) if len >= BlockResponse::SIZE => {
64 match BlockResponse::from_bytes(&buf) {
65 Some(resp) if resp.tag == expected_tag => Some(Ok(resp)),
66 Some(_) => {
67 stale_count += 1;
68 match stale_count > 16 {
69 true => Some(Err(FsError::Io(0xFFFD))),
70 false => None,
71 }
72 }
73 None => Some(Err(FsError::Io(0xFFFC))),
74 }
75 }
76 Some(_) => Some(Err(FsError::Io(0xFFFC))),
77 None => {
78 syscall::notify_wait(NOTIF_SLOT);
79 None
80 }
81 }
82 })
83 .unwrap_or(Err(FsError::Io(0xFFFF)))
84 }
85
86 fn submit_and_wait(&mut self, req: BlockRequest) -> Result<BlockResponse, FsError> {
87 let tag = req.tag;
88 self.push_request(&req)?;
89 syscall::notify_signal(DRIVER_NOTIF_SLOT, 1);
90 self.wait_response(tag)
91 }
92
93 fn blocks_to_lba(&self, block_num: u64) -> u64 {
94 block_num * (BLOCK_SIZE_MIN as u64 / self.sector_size as u64)
95 }
96
97 fn blocks_to_sectors(&self, block_count: u16) -> Result<u16, FsError> {
98 let ratio = BLOCK_SIZE_MIN / self.sector_size;
99 (block_count as u32)
100 .checked_mul(ratio)
101 .and_then(|n| u16::try_from(n).ok())
102 .ok_or(FsError::InvalidBlock)
103 }
104
105 pub fn read_blocks(
106 &mut self,
107 block_num: u64,
108 count: u16,
109 buf: &mut [u8],
110 ) -> Result<(), FsError> {
111 let sector_count = self.blocks_to_sectors(count)?;
112 let transfer_bytes = sector_count as usize * self.sector_size as usize;
113 let tag = self.alloc_tag();
114 let lba = self.blocks_to_lba(block_num);
115 let req = BlockRequest::read(tag, lba, sector_count, 0);
116 let resp = self.submit_and_wait(req)?;
117
118 match resp.status {
119 0 => {
120 let copy_len = transfer_bytes.min(buf.len()).min(self.data_area_size);
121 unsafe {
122 core::ptr::copy_nonoverlapping(
123 self.data_area as *const u8,
124 buf.as_mut_ptr(),
125 copy_len,
126 );
127 }
128 Ok(())
129 }
130 status => Err(FsError::Io(status)),
131 }
132 }
133
134 pub fn write_blocks(
135 &mut self,
136 block_num: u64,
137 count: u16,
138 buf: &[u8],
139 ) -> Result<(), FsError> {
140 let sector_count = self.blocks_to_sectors(count)?;
141 let transfer_bytes = sector_count as usize * self.sector_size as usize;
142 let copy_len = transfer_bytes.min(buf.len()).min(self.data_area_size);
143 unsafe {
144 core::ptr::copy_nonoverlapping(buf.as_ptr(), self.data_area, copy_len);
145 }
146
147 let tag = self.alloc_tag();
148 let lba = self.blocks_to_lba(block_num);
149 let req = BlockRequest::write(tag, lba, sector_count, 0);
150 let resp = self.submit_and_wait(req)?;
151
152 match resp.status {
153 0 => Ok(()),
154 status => Err(FsError::Io(status)),
155 }
156 }
157
158 pub fn flush(&mut self) -> Result<(), FsError> {
159 let tag = self.alloc_tag();
160 let req = BlockRequest::flush(tag);
161 let resp = self.submit_and_wait(req)?;
162
163 match resp.status {
164 0 => Ok(()),
165 status => Err(FsError::Io(status)),
166 }
167 }
168
169 pub fn sector_size(&self) -> u32 {
170 self.sector_size
171 }
172 }
173}
174
175#[cfg(feature = "userspace")]
176pub use real_io::BlockIo;
177
178#[cfg(not(feature = "userspace"))]
179mod mem_io {
180 use crate::error::FsError;
181
182 const BLOCK_SIZE: usize = 4096;
183
184 pub struct BlockIo {
185 storage: std::vec::Vec<u8>,
186 num_blocks: u64,
187 write_limit: Option<u64>,
188 }
189
190 impl BlockIo {
191 pub fn new_memory(num_blocks: u64) -> Self {
192 Self {
193 storage: std::vec![0u8; num_blocks as usize * BLOCK_SIZE],
194 num_blocks,
195 write_limit: None,
196 }
197 }
198
199 pub fn clone_storage(&self) -> std::vec::Vec<u8> {
200 self.storage.clone()
201 }
202
203 pub fn from_storage(data: std::vec::Vec<u8>) -> Self {
204 let num_blocks = (data.len() / BLOCK_SIZE) as u64;
205 Self {
206 storage: data,
207 num_blocks,
208 write_limit: None,
209 }
210 }
211
212 pub fn raw_block_mut(&mut self, block_num: u64) -> Option<&mut [u8]> {
213 let start = block_num as usize * BLOCK_SIZE;
214 let end = start + BLOCK_SIZE;
215 match end <= self.storage.len() {
216 true => Some(&mut self.storage[start..end]),
217 false => None,
218 }
219 }
220
221 pub fn set_write_limit(&mut self, limit: Option<u64>) {
222 self.write_limit = limit;
223 }
224
225 pub fn read_blocks(
226 &mut self,
227 block_num: u64,
228 count: u16,
229 buf: &mut [u8],
230 ) -> Result<(), FsError> {
231 let start = block_num as usize * BLOCK_SIZE;
232 let len = count as usize * BLOCK_SIZE;
233 let end = start + len;
234 match end <= self.storage.len() {
235 true => {
236 let copy_len = len.min(buf.len());
237 buf[..copy_len].copy_from_slice(&self.storage[start..start + copy_len]);
238 Ok(())
239 }
240 false => Err(FsError::InvalidBlock),
241 }
242 }
243
244 pub fn write_blocks(
245 &mut self,
246 block_num: u64,
247 count: u16,
248 buf: &[u8],
249 ) -> Result<(), FsError> {
250 match self.write_limit {
251 Some(0) => return Err(FsError::Io(0xDEAD)),
252 Some(ref mut n) => *n -= 1,
253 None => {}
254 }
255 let start = block_num as usize * BLOCK_SIZE;
256 let len = count as usize * BLOCK_SIZE;
257 let end = start + len;
258 match end <= self.storage.len() {
259 true => {
260 let copy_len = len.min(buf.len());
261 self.storage[start..start + copy_len].copy_from_slice(&buf[..copy_len]);
262 Ok(())
263 }
264 false => Err(FsError::InvalidBlock),
265 }
266 }
267
268 pub fn flush(&mut self) -> Result<(), FsError> {
269 Ok(())
270 }
271
272 pub fn sector_size(&self) -> u32 {
273 512
274 }
275 }
276}
277
278#[cfg(not(feature = "userspace"))]
279pub use mem_io::BlockIo;