Nothing to see here, move along meow
1#![cfg_attr(feature = "userspace", no_std)]
2#![cfg_attr(feature = "userspace", no_main)]
3#![allow(dead_code)]
4
5#[cfg(not(feature = "userspace"))]
6fn main() {}
7
8#[cfg(feature = "userspace")]
9mod service {
10 use lancer_lancerfs::dispatch::FsState;
11 use lancer_lancerfs::handle::HandleTableSet;
12 use lancer_lancerfs::{block_io, blockref_block_num, cache, commit, dispatch, ipc_proto, pool};
13 use lancer_user::syscall;
14
15 const BLOCK_RING_BASE_SLOT: u64 = 64;
16 const BLOCK_RING_FRAME_COUNT: u64 = 16;
17 const NOTIF_SLOT: u64 = 3;
18 #[allow(dead_code)]
19 const DRIVER_NOTIF_SLOT: u64 = 4;
20 const CLIENT_RING_BASE_SLOT: u64 = 96;
21 const CLIENT_RING_FRAME_COUNT: u64 = 16;
22 const CLIENT_NOTIF_SLOT: u64 = 6;
23
24 const BLOCK_RING_VADDR: u64 = 0x5000_0000;
25 const CLIENT_RING_VADDR: u64 = 0x5010_0000;
26 const RING_DATA_OFFSET: usize = 8192;
27 const RING_DATA_PAGES: usize = 14;
28
29 const CLIENT_RING_DATA_OFFSET: usize = 8192;
30 const CLIENT_RING_DATA_PAGES: usize = 14;
31
32 static mut CACHE: cache::BlockCache = cache::BlockCache::new();
33 static mut POOL: pool::NodePool = pool::NodePool::new();
34 static mut HANDLES: HandleTableSet = HandleTableSet::new();
35
36 fn mount(bio: &mut block_io::BlockIo, cache_ref: &mut cache::BlockCache) -> FsState {
37 lancer_user::show!(lancerfs, "reading superblocks");
38
39 let sb_pair = match commit::load_validated_superblock_pair(bio) {
40 Ok(pair) => {
41 lancer_user::show!(lancerfs, "superblock pair loaded");
42 pair
43 }
44 Err(_) => {
45 lancer_user::show!(lancerfs, error, "no valid superblock found");
46 syscall::exit();
47 }
48 };
49
50 #[allow(clippy::deref_addrof)]
51 let pool_ref = unsafe { &mut *(&raw mut POOL) };
52
53 let tree_root = sb_pair.active().tree_root;
54 let root_ref = match lancer_lancerfs::btree::btree_lookup(
55 pool_ref, cache_ref, bio, &tree_root, 1, None,
56 ) {
57 Ok(Some(r)) => r,
58 _ => {
59 lancer_user::show!(lancerfs, error, "root inode not found in metadata tree");
60 syscall::exit();
61 }
62 };
63 pool_ref.clear_all();
64
65 let root_block = blockref_block_num(&root_ref);
66 let root_inode = match lancer_lancerfs::file::read_inode(cache_ref, bio, root_block) {
67 Ok(inode) => inode,
68 Err(_) => {
69 lancer_user::show!(lancerfs, error, "failed to read root inode");
70 syscall::exit();
71 }
72 };
73
74 {
75 let active = sb_pair.active();
76 lancer_user::show!(
77 lancerfs,
78 "mounted {} blocks seq {} txn {} tree_root {:#x} freemap_root {:#x}",
79 active.total_blocks,
80 active.sequence,
81 active.transaction_id,
82 active.tree_root.physical_block_addr(),
83 active.freemap_root.physical_block_addr()
84 );
85 }
86
87 let mut state = FsState::from_superblock_pair(
88 sb_pair,
89 root_block,
90 root_inode.object_id,
91 root_inode.generation,
92 );
93
94 lancer_user::show!(
95 lancerfs,
96 "ditto allocable {} scrub cursor {}",
97 state.ditto.allocable_data_blocks(),
98 state.scrub.cursor()
99 );
100
101 state.handles = unsafe { core::ptr::read(&raw const HANDLES) };
102 state
103 }
104
105 #[unsafe(no_mangle)]
106 pub extern "C" fn lancer_main() -> ! {
107 lancer_user::show!(lancerfs, "starting");
108
109 match (0..BLOCK_RING_FRAME_COUNT).all(|i| {
110 syscall::frame_map(BLOCK_RING_BASE_SLOT + i, BLOCK_RING_VADDR + i * 4096, 1) >= 0
111 }) {
112 true => {}
113 false => {
114 lancer_user::show!(lancerfs, error, "failed to map block ring");
115 syscall::exit();
116 }
117 }
118
119 let ring_base = BLOCK_RING_VADDR as *mut u8;
120
121 let request_ring =
122 unsafe { lancer_core::packet_ring::PacketRingWriter::init(ring_base, 4096, 32) };
123 let response_ring = unsafe {
124 lancer_core::packet_ring::PacketRingReader::attach(ring_base.add(4096), 4096)
125 };
126 let data_area = (BLOCK_RING_VADDR as usize + RING_DATA_OFFSET) as *mut u8;
127 let data_area_size = RING_DATA_PAGES * 4096;
128
129 lancer_user::show!(lancerfs, "waiting for nvme driver");
130 syscall::notify_wait(NOTIF_SLOT);
131
132 let sector_size = 512u32;
133 let mut bio = unsafe {
134 block_io::BlockIo::init(
135 request_ring,
136 response_ring,
137 data_area,
138 data_area_size,
139 sector_size,
140 )
141 };
142
143 #[allow(clippy::deref_addrof)]
144 let cache_ref = unsafe { &mut *(&raw mut CACHE) };
145
146 let mut fs_state = mount(&mut bio, cache_ref);
147
148 let has_client_ring = (0..CLIENT_RING_FRAME_COUNT).all(|i| {
149 syscall::frame_map(CLIENT_RING_BASE_SLOT + i, CLIENT_RING_VADDR + i * 4096, 1) >= 0
150 });
151
152 let (client_request_ring, client_response_ring, client_data_area, client_data_area_size) =
153 match has_client_ring {
154 true => {
155 lancer_user::show!(lancerfs, "client ring mapped");
156 let client_base = CLIENT_RING_VADDR as *mut u8;
157 let crr = unsafe {
158 lancer_core::packet_ring::PacketRingReader::attach(client_base, 4096)
159 };
160 let crw = unsafe {
161 lancer_core::packet_ring::PacketRingWriter::init(
162 client_base.wrapping_add(4096),
163 4096,
164 32,
165 )
166 };
167 let cda = (CLIENT_RING_VADDR as usize + CLIENT_RING_DATA_OFFSET) as *mut u8;
168 let cds = CLIENT_RING_DATA_PAGES * 4096;
169 (Some(crr), Some(crw), cda, cds)
170 }
171 false => {
172 lancer_user::show!(lancerfs, "no client ring, standalone mode");
173 (None, None, core::ptr::null_mut(), 0)
174 }
175 };
176
177 #[allow(clippy::deref_addrof)]
178 let pool = unsafe { &mut *(&raw mut POOL) };
179
180 let mut scratch = [0u8; 8192];
181 let mut hash_table = [0u16; 1 << 12];
182
183 lancer_user::show!(lancerfs, "entering dispatch loop");
184 syscall::notify_signal(CLIENT_NOTIF_SLOT, 1);
185
186 let client_pid: u16 = 0;
187 let _ = fs_state.handles.install_root_handle(
188 client_pid,
189 fs_state.root_object_id,
190 fs_state.root_generation,
191 fs_state.root_inode_block,
192 );
193
194 loop {
195 syscall::notify_wait(NOTIF_SLOT);
196
197 if let (Some(reader), Some(writer)) = (&client_request_ring, &client_response_ring) {
198 let mut req_buf = [0u8; 64];
199 let mut processed = 0u32;
200 (0..64u32).for_each(|_| {
201 if let Some(len) = reader.try_pop(&mut req_buf)
202 && len >= ipc_proto::FsRequest::SIZE
203 && let Some(req) = ipc_proto::FsRequest::from_bytes(&req_buf)
204 {
205 let resp = dispatch::dispatch_request(
206 &req,
207 pool,
208 cache_ref,
209 &mut bio,
210 &mut fs_state,
211 client_data_area,
212 client_data_area_size,
213 client_pid,
214 &mut scratch,
215 &mut hash_table,
216 );
217 let _ = writer.try_push(resp.as_bytes());
218 processed += 1;
219 }
220 });
221
222 if processed > 0 {
223 syscall::notify_signal(CLIENT_NOTIF_SLOT, 1);
224 }
225 }
226 }
227 }
228}