Nothing to see here, move along
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| syscall::frame_map(BLOCK_RING_BASE_SLOT + i, BLOCK_RING_VADDR + i * 4096, 1) >= 0) {
110 true => {}
111 false => {
112 lancer_user::show!(lancerfs, error, "failed to map block ring");
113 syscall::exit();
114 }
115 }
116
117 let ring_base = BLOCK_RING_VADDR as *mut u8;
118
119 let request_ring =
120 unsafe { lancer_core::packet_ring::PacketRingWriter::init(ring_base, 4096, 32) };
121 let response_ring = unsafe {
122 lancer_core::packet_ring::PacketRingReader::attach(ring_base.add(4096), 4096)
123 };
124 let data_area = (BLOCK_RING_VADDR as usize + RING_DATA_OFFSET) as *mut u8;
125 let data_area_size = RING_DATA_PAGES * 4096;
126
127 lancer_user::show!(lancerfs, "waiting for nvme driver");
128 syscall::notify_wait(NOTIF_SLOT);
129
130 let sector_size = 512u32;
131 let mut bio = unsafe {
132 block_io::BlockIo::init(
133 request_ring,
134 response_ring,
135 data_area,
136 data_area_size,
137 sector_size,
138 )
139 };
140
141 #[allow(clippy::deref_addrof)]
142 let cache_ref = unsafe { &mut *(&raw mut CACHE) };
143
144 let mut fs_state = mount(&mut bio, cache_ref);
145
146 let has_client_ring = (0..CLIENT_RING_FRAME_COUNT).all(|i| syscall::frame_map(CLIENT_RING_BASE_SLOT + i, CLIENT_RING_VADDR + i * 4096, 1) >= 0);
147
148 let (client_request_ring, client_response_ring, client_data_area, client_data_area_size) =
149 match has_client_ring {
150 true => {
151 lancer_user::show!(lancerfs, "client ring mapped");
152 let client_base = CLIENT_RING_VADDR as *mut u8;
153 let crr = unsafe {
154 lancer_core::packet_ring::PacketRingReader::attach(client_base, 4096)
155 };
156 let crw = unsafe {
157 lancer_core::packet_ring::PacketRingWriter::init(
158 client_base.wrapping_add(4096),
159 4096,
160 32,
161 )
162 };
163 let cda = (CLIENT_RING_VADDR as usize + CLIENT_RING_DATA_OFFSET) as *mut u8;
164 let cds = CLIENT_RING_DATA_PAGES * 4096;
165 (Some(crr), Some(crw), cda, cds)
166 }
167 false => {
168 lancer_user::show!(lancerfs, "no client ring, standalone mode");
169 (None, None, core::ptr::null_mut(), 0)
170 }
171 };
172
173 #[allow(clippy::deref_addrof)]
174 let pool = unsafe { &mut *(&raw mut POOL) };
175
176 let mut scratch = [0u8; 8192];
177 let mut hash_table = [0u16; 1 << 12];
178
179 lancer_user::show!(lancerfs, "entering dispatch loop");
180 syscall::notify_signal(CLIENT_NOTIF_SLOT, 1);
181
182 let client_pid: u16 = 0;
183 let _ = fs_state.handles.install_root_handle(
184 client_pid,
185 fs_state.root_object_id,
186 fs_state.root_generation,
187 fs_state.root_inode_block,
188 );
189
190 loop {
191 syscall::notify_wait(NOTIF_SLOT);
192
193 if let (Some(reader), Some(writer)) = (&client_request_ring, &client_response_ring) {
194 let mut req_buf = [0u8; 64];
195 let mut processed = 0u32;
196 (0..64u32).for_each(|_| {
197 if let Some(len) = reader.try_pop(&mut req_buf)
198 && len >= ipc_proto::FsRequest::SIZE
199 && let Some(req) = ipc_proto::FsRequest::from_bytes(&req_buf)
200 {
201 let resp = dispatch::dispatch_request(
202 &req,
203 pool,
204 cache_ref,
205 &mut bio,
206 &mut fs_state,
207 client_data_area,
208 client_data_area_size,
209 client_pid,
210 &mut scratch,
211 &mut hash_table,
212 );
213 let _ = writer.try_push(resp.as_bytes());
214 processed += 1;
215 }
216 });
217
218 if processed > 0 {
219 syscall::notify_signal(CLIENT_NOTIF_SLOT, 1);
220 }
221 }
222 }
223 }
224}