Nothing to see here, move along
1#![no_std]
2#![no_main]
3#![allow(clippy::single_match)]
4
5use lancer_user::bootstrap as boot;
6
7use lancer_user::show;
8use lancer_user::syscall;
9use lancer_user::untyped::UntypedAllocator;
10
11const SERIAL_ENDPOINT: u64 = 1;
12const FB_ENDPOINT: u64 = 2;
13
14const TAG_NOTIFICATION: u64 = 2;
15const TAG_SCHED_CONTEXT: u64 = 5;
16const RIGHTS_ALL: u64 = 0b1111;
17
18const SLOT_INIT_NOTIF: u64 = 9;
19const SLOT_NETSTACK_NOTIF: u64 = 10;
20const SLOT_VFS_CLIENT_NOTIF: u64 = 12;
21const SLOT_VFS_NOTIF: u64 = 13;
22const SLOT_VFS_PROC: u64 = 15;
23const VFS_RING_BASE_SLOT: u64 = 320;
24const VFS_RING_FRAME_COUNT: u64 = 16;
25const NETSTACK_RING_BASE_SLOT: u64 = 288;
26const NETSTACK_RING_FRAME_COUNT: u64 = 2;
27const SHELL_NETSTACK_RING_DST: u64 = 64;
28const SHELL_VFS_RING_DST: u64 = 128;
29
30const VFS_RING_VADDR: u64 = 0x7000_0000;
31
32const NOTIFY_BIT_CHILD_DEATH: u64 = 0x01;
33
34const SLOT_SHELL_PROC: u64 = 25;
35const SLOT_SHELL_SCHED: u64 = 26;
36const SLOT_SHELL_DEATH_NOTIF: u64 = 27;
37
38#[allow(dead_code)]
39mod staging {
40 pub const SERIAL_PROC: u64 = 400;
41 pub const SERIAL_SCHED: u64 = 401;
42 pub const SERIAL_IRQ: u64 = 402;
43 pub const SERIAL_NOTIF: u64 = 403;
44
45 pub const PS2KBD_PROC: u64 = 410;
46 pub const PS2KBD_SCHED: u64 = 411;
47 pub const PS2KBD_IRQ: u64 = 412;
48 pub const PS2KBD_NOTIF: u64 = 413;
49
50 pub const FBCONSOLE_PROC: u64 = 420;
51 pub const FBCONSOLE_SCHED: u64 = 421;
52 pub const FBCONSOLE_FB: u64 = 422;
53 pub const FBCONSOLE_RING_BASE: u64 = 424;
54 pub const FBCONSOLE_RING_COUNT: u64 = 16;
55
56 pub const NVME_PROC: u64 = 450;
57 pub const NVME_SCHED: u64 = 451;
58 pub const NVME_PCI: u64 = 452;
59 pub const NVME_IRQ: u64 = 453;
60 pub const NVME_NOTIF: u64 = 454;
61
62 pub const LANCERFS_PROC: u64 = 500;
63 pub const LANCERFS_SCHED: u64 = 501;
64 pub const LANCERFS_NOTIF: u64 = 502;
65 pub const LANCERFS_BLOCK_RING_BASE: u64 = 504;
66 pub const LANCERFS_BLOCK_RING_COUNT: u64 = 16;
67
68 pub const VFS_PROC_SLOT: u64 = 530;
69 pub const VFS_SCHED: u64 = 531;
70 pub const VFS_NOTIF: u64 = 532;
71 pub const VFS_LANCERFS_RING_BASE: u64 = 534;
72 pub const VFS_LANCERFS_RING_COUNT: u64 = 16;
73 pub const VFS_RAMFS_RING_BASE: u64 = 560;
74 pub const VFS_RAMFS_RING_COUNT: u64 = 16;
75 pub const VFS_CLIENT_RING_BASE: u64 = 576;
76 pub const VFS_CLIENT_RING_COUNT: u64 = 16;
77
78 pub const RAMFS_PROC: u64 = 600;
79 pub const RAMFS_SCHED: u64 = 601;
80 pub const RAMFS_NOTIF: u64 = 602;
81 pub const RAMFS_VFS_RING_BASE: u64 = 604;
82 pub const RAMFS_VFS_RING_COUNT: u64 = 16;
83
84 pub const VIRTIO_NET_PROC: u64 = 640;
85 pub const VIRTIO_NET_SCHED: u64 = 641;
86 pub const VIRTIO_NET_PCI: u64 = 642;
87 pub const VIRTIO_NET_IRQ: u64 = 643;
88 pub const VIRTIO_NET_NOTIF: u64 = 644;
89 pub const VIRTIO_NET_PACKET_RING_BASE: u64 = 646;
90 pub const VIRTIO_NET_PACKET_RING_COUNT: u64 = 16;
91
92 pub const NETSTACK_PROC: u64 = 680;
93 pub const NETSTACK_SCHED: u64 = 681;
94 pub const NETSTACK_NOTIF: u64 = 682;
95 pub const NETSTACK_DRIVER_RING_BASE: u64 = 684;
96 pub const NETSTACK_DRIVER_RING_COUNT: u64 = 16;
97 pub const NETSTACK_SHELL_RING_BASE: u64 = 700;
98 pub const NETSTACK_SHELL_RING_COUNT: u64 = 4;
99 pub const NETSTACK_INIT_RING_BASE: u64 = 720;
100 pub const NETSTACK_INIT_RING_COUNT: u64 = 2;
101
102 pub const REMOTE_SHELL_PROC: u64 = 750;
103 pub const REMOTE_SHELL_SCHED: u64 = 751;
104 pub const REMOTE_SHELL_NOTIF: u64 = 752;
105 pub const REMOTE_SHELL_NET_RING_BASE: u64 = 754;
106 pub const REMOTE_SHELL_VFS_RING_BASE: u64 = 770;
107 pub const REMOTE_SHELL_VFS_RING_COUNT: u64 = 16;
108}
109
110mod driver_slots {
111 pub const EP: u64 = 1;
112 pub const IRQ: u64 = 2;
113 pub const NOTIF: u64 = 3;
114
115 pub const FB: u64 = 2;
116 pub const CONSOLE_RING_BASE: u64 = 64;
117
118 pub const PCI: u64 = 2;
119 pub const PCI_IRQ: u64 = 3;
120 pub const PCI_NOTIF: u64 = 4;
121 pub const CLIENT_NOTIF: u64 = 6;
122 pub const NETSTACK_NOTIF: u64 = 7;
123 pub const BLOCK_RING_BASE: u64 = 64;
124
125 pub const FS_NOTIF: u64 = 3;
126 pub const FS_DRIVER_NOTIF: u64 = 4;
127 pub const FS_CLIENT_NOTIF: u64 = 6;
128 pub const FS_CLIENT_RING_BASE: u64 = 96;
129
130 pub const VFS_NOTIF: u64 = 3;
131 pub const VFS_LANCERFS_NOTIF: u64 = 4;
132 pub const VFS_LANCERFS_RING_BASE: u64 = 64;
133 pub const VFS_CLIENT0_RING_BASE: u64 = 160;
134 pub const VFS_CLIENT0_NOTIF: u64 = 176;
135 pub const VFS_RAMFS_NOTIF: u64 = 6;
136 pub const VFS_RAMFS_RING_BASE: u64 = 96;
137
138 pub const RAMFS_NOTIF: u64 = 3;
139 pub const RAMFS_VFS_NOTIF: u64 = 4;
140 pub const RAMFS_CLIENT_RING_BASE: u64 = 64;
141
142 pub const NET_EP: u64 = 1;
143 pub const NET_NOTIF: u64 = 3;
144 pub const NET_DRIVER_NOTIF: u64 = 4;
145 pub const NET_SHELL_NOTIF: u64 = 6;
146 pub const NET_INIT_NOTIF: u64 = 8;
147 pub const NET_PACKET_RING_BASE: u64 = 64;
148 pub const NET_SHELL_RING_BASE: u64 = 96;
149 pub const NET_INIT_RING_BASE: u64 = 128;
150
151 pub const RSHELL_EP: u64 = 1;
152 pub const RSHELL_NOTIF: u64 = 3;
153 pub const RSHELL_NETSTACK_NOTIF: u64 = 4;
154 pub const RSHELL_SHELL_RING_BASE: u64 = 64;
155 pub const RSHELL_VFS_RING_BASE: u64 = 128;
156}
157
158struct BootState {
159 has_serial: bool,
160 has_ps2kbd: bool,
161 has_fbconsole: bool,
162 has_nvme: bool,
163 has_lancerfs: bool,
164 has_vfs: bool,
165 has_ramfs: bool,
166 has_virtio_net: bool,
167 has_netstack: bool,
168 has_remote_shell: bool,
169 has_vfs_client: bool,
170}
171
172impl BootState {
173 const fn new() -> Self {
174 Self {
175 has_serial: false,
176 has_ps2kbd: false,
177 has_fbconsole: false,
178 has_nvme: false,
179 has_lancerfs: false,
180 has_vfs: false,
181 has_ramfs: false,
182 has_virtio_net: false,
183 has_netstack: false,
184 has_remote_shell: false,
185 has_vfs_client: false,
186 }
187 }
188}
189
190fn bootstrap_serial(allocator: &mut UntypedAllocator, com1_gsi: u64) -> bool {
191 let pid = match boot::create_process(allocator, b"serial", staging::SERIAL_PROC) {
192 Some(p) => p,
193 None => return false,
194 };
195
196 boot::create_endpoint(allocator, SERIAL_ENDPOINT);
197 boot::grant_cap(SERIAL_ENDPOINT, staging::SERIAL_PROC, driver_slots::EP);
198
199 boot::create_irq_handler(
200 allocator,
201 staging::SERIAL_IRQ,
202 com1_gsi,
203 boot::COM1_VECTOR,
204 0x3F8,
205 8,
206 );
207 boot::create_notification(allocator, staging::SERIAL_NOTIF);
208 syscall::irq_bind(staging::SERIAL_IRQ, staging::SERIAL_NOTIF, 0);
209 boot::grant_cap(staging::SERIAL_IRQ, staging::SERIAL_PROC, driver_slots::IRQ);
210 boot::grant_cap(
211 staging::SERIAL_NOTIF,
212 staging::SERIAL_PROC,
213 driver_slots::NOTIF,
214 );
215
216 boot::start_with_sched(
217 allocator,
218 staging::SERIAL_PROC,
219 staging::SERIAL_SCHED,
220 pid,
221 u64::MAX,
222 )
223}
224
225fn bootstrap_ps2kbd(allocator: &mut UntypedAllocator, kbd_gsi: u64) -> bool {
226 let pid = match boot::create_process(allocator, b"ps2kbd", staging::PS2KBD_PROC) {
227 Some(p) => p,
228 None => return false,
229 };
230
231 boot::grant_cap(SERIAL_ENDPOINT, staging::PS2KBD_PROC, driver_slots::EP);
232
233 boot::create_irq_handler(
234 allocator,
235 staging::PS2KBD_IRQ,
236 kbd_gsi,
237 boot::KBD_VECTOR,
238 0x60,
239 5,
240 );
241 boot::create_notification(allocator, staging::PS2KBD_NOTIF);
242 syscall::irq_bind(staging::PS2KBD_IRQ, staging::PS2KBD_NOTIF, 0);
243 boot::grant_cap(staging::PS2KBD_IRQ, staging::PS2KBD_PROC, driver_slots::IRQ);
244 boot::grant_cap(
245 staging::PS2KBD_NOTIF,
246 staging::PS2KBD_PROC,
247 driver_slots::NOTIF,
248 );
249
250 boot::start_with_sched(
251 allocator,
252 staging::PS2KBD_PROC,
253 staging::PS2KBD_SCHED,
254 pid,
255 u64::MAX,
256 )
257}
258
259fn bootstrap_fbconsole(allocator: &mut UntypedAllocator) -> bool {
260 let pid = match boot::create_process(allocator, b"fbconsole", staging::FBCONSOLE_PROC) {
261 Some(p) => p,
262 None => return false,
263 };
264
265 boot::create_endpoint(allocator, FB_ENDPOINT);
266 boot::grant_cap(FB_ENDPOINT, staging::FBCONSOLE_PROC, driver_slots::EP);
267
268 let r = syscall::fb_create_cap(staging::FBCONSOLE_FB);
269 match r < 0 {
270 true => {
271 show!(init, warn, "failed to create fb cap");
272 return false;
273 }
274 false => {}
275 }
276 boot::grant_cap(
277 staging::FBCONSOLE_FB,
278 staging::FBCONSOLE_PROC,
279 driver_slots::FB,
280 );
281
282 let ring_count = syscall::console_ring_create_cap(staging::FBCONSOLE_RING_BASE);
283 match ring_count <= 0 {
284 true => {
285 show!(init, warn, "failed to create console ring caps");
286 return false;
287 }
288 false => {}
289 }
290 boot::grant_frames(
291 staging::FBCONSOLE_RING_BASE,
292 staging::FBCONSOLE_PROC,
293 driver_slots::CONSOLE_RING_BASE,
294 ring_count as u64,
295 );
296
297 boot::start_with_sched(
298 allocator,
299 staging::FBCONSOLE_PROC,
300 staging::FBCONSOLE_SCHED,
301 pid,
302 u64::MAX,
303 )
304}
305
306fn bootstrap_nvme(allocator: &mut UntypedAllocator, device_idx: u8) -> bool {
307 let pid = match boot::create_process(allocator, b"nvme", staging::NVME_PROC) {
308 Some(p) => p,
309 None => return false,
310 };
311
312 boot::grant_cap(SERIAL_ENDPOINT, staging::NVME_PROC, driver_slots::EP);
313
314 let r = syscall::pci_create_cap(device_idx as u64, staging::NVME_PCI);
315 if r < 0 {
316 show!(init, warn, "nvme: pci_create_cap failed");
317 return false;
318 }
319 show!(init, "nvme: pci cap created");
320
321 syscall::pci_enable_bus_master(staging::NVME_PCI);
322 show!(init, "nvme: bus master enabled");
323
324 syscall::iommu_setup_device(staging::NVME_PCI, staging::NVME_PROC);
325 show!(init, "nvme: iommu setup done");
326
327 let msix_r =
328 syscall::pci_msix_configure(staging::NVME_PCI, 0, boot::NVME_VECTOR, staging::NVME_IRQ);
329 if msix_r < 0 {
330 show!(init, warn, "nvme msix configure failed, skipping");
331 return false;
332 }
333
334 boot::grant_cap(staging::NVME_PCI, staging::NVME_PROC, driver_slots::PCI);
335
336 boot::create_notification(allocator, staging::NVME_NOTIF);
337 syscall::irq_bind(staging::NVME_IRQ, staging::NVME_NOTIF, 0);
338 boot::grant_cap(staging::NVME_IRQ, staging::NVME_PROC, driver_slots::PCI_IRQ);
339 boot::grant_cap(
340 staging::NVME_NOTIF,
341 staging::NVME_PROC,
342 driver_slots::PCI_NOTIF,
343 );
344
345 boot::start_with_sched(
346 allocator,
347 staging::NVME_PROC,
348 staging::NVME_SCHED,
349 pid,
350 u64::MAX,
351 )
352}
353
354fn bootstrap_nvme_service(allocator: &mut UntypedAllocator) -> bool {
355 boot::create_shared_frames(
356 allocator,
357 staging::LANCERFS_BLOCK_RING_BASE,
358 staging::NVME_PROC,
359 driver_slots::BLOCK_RING_BASE,
360 staging::LANCERFS_BLOCK_RING_COUNT,
361 );
362 boot::grant_frames(
363 staging::LANCERFS_BLOCK_RING_BASE,
364 staging::LANCERFS_PROC,
365 driver_slots::BLOCK_RING_BASE,
366 staging::LANCERFS_BLOCK_RING_COUNT,
367 );
368
369 boot::create_notification(allocator, staging::LANCERFS_NOTIF);
370 boot::grant_cap(
371 staging::LANCERFS_NOTIF,
372 staging::NVME_PROC,
373 driver_slots::CLIENT_NOTIF,
374 );
375 boot::grant_cap(
376 staging::NVME_NOTIF,
377 staging::LANCERFS_PROC,
378 driver_slots::FS_DRIVER_NOTIF,
379 );
380 boot::grant_cap(
381 staging::LANCERFS_NOTIF,
382 staging::LANCERFS_PROC,
383 driver_slots::FS_NOTIF,
384 );
385
386 true
387}
388
389fn bootstrap_lancerfs(allocator: &mut UntypedAllocator) -> bool {
390 let pid = match boot::create_process(allocator, b"lancerfs", staging::LANCERFS_PROC) {
391 Some(p) => p,
392 None => return false,
393 };
394
395 boot::grant_cap(SERIAL_ENDPOINT, staging::LANCERFS_PROC, driver_slots::EP);
396
397 boot::start_with_sched(
398 allocator,
399 staging::LANCERFS_PROC,
400 staging::LANCERFS_SCHED,
401 pid,
402 u64::MAX,
403 )
404}
405
406fn bootstrap_vfs(allocator: &mut UntypedAllocator) -> bool {
407 let pid = match boot::create_process(allocator, b"vfs", staging::VFS_PROC_SLOT) {
408 Some(p) => p,
409 None => return false,
410 };
411
412 boot::grant_cap(SERIAL_ENDPOINT, staging::VFS_PROC_SLOT, driver_slots::EP);
413
414 boot::start_with_sched(
415 allocator,
416 staging::VFS_PROC_SLOT,
417 staging::VFS_SCHED,
418 pid,
419 u64::MAX,
420 )
421}
422
423fn bootstrap_vfs_lancerfs(allocator: &mut UntypedAllocator) -> bool {
424 boot::create_shared_frames(
425 allocator,
426 staging::VFS_LANCERFS_RING_BASE,
427 staging::VFS_PROC_SLOT,
428 driver_slots::VFS_LANCERFS_RING_BASE,
429 staging::VFS_LANCERFS_RING_COUNT,
430 );
431 boot::grant_frames(
432 staging::VFS_LANCERFS_RING_BASE,
433 staging::LANCERFS_PROC,
434 driver_slots::FS_CLIENT_RING_BASE,
435 staging::VFS_LANCERFS_RING_COUNT,
436 );
437
438 boot::create_notification(allocator, staging::VFS_NOTIF);
439 boot::grant_cap(
440 staging::VFS_NOTIF,
441 staging::VFS_PROC_SLOT,
442 driver_slots::VFS_NOTIF,
443 );
444 boot::grant_cap(
445 staging::VFS_NOTIF,
446 staging::LANCERFS_PROC,
447 driver_slots::FS_CLIENT_NOTIF,
448 );
449 boot::grant_cap(
450 staging::LANCERFS_NOTIF,
451 staging::VFS_PROC_SLOT,
452 driver_slots::VFS_LANCERFS_NOTIF,
453 );
454
455 true
456}
457
458fn bootstrap_vfs_client(allocator: &mut UntypedAllocator) -> bool {
459 boot::create_shared_frames(
460 allocator,
461 staging::VFS_CLIENT_RING_BASE,
462 staging::VFS_PROC_SLOT,
463 driver_slots::VFS_CLIENT0_RING_BASE,
464 staging::VFS_CLIENT_RING_COUNT,
465 );
466
467 (0..staging::VFS_CLIENT_RING_COUNT).all(|i| {
468 let src = staging::VFS_CLIENT_RING_BASE + i;
469 let dst = VFS_RING_BASE_SLOT + i;
470 syscall::cnode_copy(src, dst, RIGHTS_ALL) >= 0
471 });
472
473 boot::create_notification(allocator, SLOT_VFS_CLIENT_NOTIF);
474 boot::grant_cap(
475 SLOT_VFS_CLIENT_NOTIF,
476 staging::VFS_PROC_SLOT,
477 driver_slots::VFS_CLIENT0_NOTIF,
478 );
479
480 syscall::cnode_copy(staging::VFS_NOTIF, SLOT_VFS_NOTIF, RIGHTS_ALL);
481
482 let proc_cap_slot: u64 = SLOT_VFS_PROC;
483 syscall::cnode_copy(staging::VFS_PROC_SLOT, proc_cap_slot, RIGHTS_ALL);
484
485 true
486}
487
488fn bootstrap_ramfs(allocator: &mut UntypedAllocator) -> Option<i64> {
489 let pid = boot::create_process(allocator, b"ramfs", staging::RAMFS_PROC)?;
490 boot::grant_cap(SERIAL_ENDPOINT, staging::RAMFS_PROC, driver_slots::EP);
491 Some(pid)
492}
493
494fn bootstrap_vfs_ramfs(allocator: &mut UntypedAllocator) -> bool {
495 boot::create_shared_frames(
496 allocator,
497 staging::VFS_RAMFS_RING_BASE,
498 staging::VFS_PROC_SLOT,
499 driver_slots::VFS_RAMFS_RING_BASE,
500 staging::VFS_RAMFS_RING_COUNT,
501 );
502 boot::grant_frames(
503 staging::VFS_RAMFS_RING_BASE,
504 staging::RAMFS_PROC,
505 driver_slots::RAMFS_CLIENT_RING_BASE,
506 staging::RAMFS_VFS_RING_COUNT,
507 );
508
509 boot::create_notification(allocator, staging::RAMFS_NOTIF);
510 boot::grant_cap(
511 staging::RAMFS_NOTIF,
512 staging::RAMFS_PROC,
513 driver_slots::RAMFS_NOTIF,
514 );
515 boot::grant_cap(
516 staging::VFS_NOTIF,
517 staging::RAMFS_PROC,
518 driver_slots::RAMFS_VFS_NOTIF,
519 );
520 boot::grant_cap(
521 staging::RAMFS_NOTIF,
522 staging::VFS_PROC_SLOT,
523 driver_slots::VFS_RAMFS_NOTIF,
524 );
525
526 true
527}
528
529fn bootstrap_virtio_net(
530 allocator: &mut UntypedAllocator,
531 device_idx: u8,
532 virtio_net_gsi: u64,
533) -> Option<i64> {
534 let pid = boot::create_process(allocator, b"virtio-net", staging::VIRTIO_NET_PROC)?;
535
536 boot::grant_cap(SERIAL_ENDPOINT, staging::VIRTIO_NET_PROC, driver_slots::EP);
537
538 let r = syscall::pci_create_cap(device_idx as u64, staging::VIRTIO_NET_PCI);
539 match r < 0 {
540 true => return None,
541 false => {}
542 }
543 syscall::pci_enable_bus_master(staging::VIRTIO_NET_PCI);
544 syscall::iommu_setup_device(staging::VIRTIO_NET_PCI, staging::VIRTIO_NET_PROC);
545
546 let msix_r = syscall::pci_msix_configure(
547 staging::VIRTIO_NET_PCI,
548 0,
549 boot::VIRTIO_NET_VECTOR,
550 staging::VIRTIO_NET_IRQ,
551 );
552 match msix_r < 0 {
553 true => {
554 boot::create_irq_handler(
555 allocator,
556 staging::VIRTIO_NET_IRQ,
557 virtio_net_gsi,
558 boot::VIRTIO_NET_VECTOR,
559 0,
560 1,
561 );
562 }
563 false => {}
564 }
565
566 boot::grant_cap(
567 staging::VIRTIO_NET_PCI,
568 staging::VIRTIO_NET_PROC,
569 driver_slots::PCI,
570 );
571
572 boot::create_notification(allocator, staging::VIRTIO_NET_NOTIF);
573 syscall::irq_bind(staging::VIRTIO_NET_IRQ, staging::VIRTIO_NET_NOTIF, 0);
574 boot::grant_cap(
575 staging::VIRTIO_NET_IRQ,
576 staging::VIRTIO_NET_PROC,
577 driver_slots::PCI_IRQ,
578 );
579 boot::grant_cap(
580 staging::VIRTIO_NET_NOTIF,
581 staging::VIRTIO_NET_PROC,
582 driver_slots::PCI_NOTIF,
583 );
584
585 Some(pid)
586}
587
588fn bootstrap_netstack(allocator: &mut UntypedAllocator) -> Option<i64> {
589 let pid = boot::create_process(allocator, b"netstack", staging::NETSTACK_PROC)?;
590 boot::grant_cap(
591 SERIAL_ENDPOINT,
592 staging::NETSTACK_PROC,
593 driver_slots::NET_EP,
594 );
595 Some(pid)
596}
597
598fn bootstrap_net_service(allocator: &mut UntypedAllocator) -> bool {
599 boot::create_shared_frames(
600 allocator,
601 staging::VIRTIO_NET_PACKET_RING_BASE,
602 staging::VIRTIO_NET_PROC,
603 driver_slots::BLOCK_RING_BASE,
604 staging::VIRTIO_NET_PACKET_RING_COUNT,
605 );
606 boot::grant_frames(
607 staging::VIRTIO_NET_PACKET_RING_BASE,
608 staging::NETSTACK_PROC,
609 driver_slots::NET_PACKET_RING_BASE,
610 staging::NETSTACK_DRIVER_RING_COUNT,
611 );
612
613 boot::create_notification(allocator, staging::NETSTACK_NOTIF);
614 boot::grant_cap(
615 staging::NETSTACK_NOTIF,
616 staging::NETSTACK_PROC,
617 driver_slots::NET_NOTIF,
618 );
619 boot::grant_cap(
620 staging::VIRTIO_NET_NOTIF,
621 staging::NETSTACK_PROC,
622 driver_slots::NET_DRIVER_NOTIF,
623 );
624 boot::grant_cap(
625 staging::NETSTACK_NOTIF,
626 staging::VIRTIO_NET_PROC,
627 driver_slots::NETSTACK_NOTIF,
628 );
629
630 true
631}
632
633fn bootstrap_init_netring(allocator: &mut UntypedAllocator) -> bool {
634 boot::create_shared_frames(
635 allocator,
636 NETSTACK_RING_BASE_SLOT,
637 staging::NETSTACK_PROC,
638 driver_slots::NET_INIT_RING_BASE,
639 NETSTACK_RING_FRAME_COUNT,
640 );
641
642 boot::create_notification(allocator, SLOT_INIT_NOTIF);
643 syscall::cnode_copy(staging::NETSTACK_NOTIF, SLOT_NETSTACK_NOTIF, RIGHTS_ALL);
644 boot::grant_cap(
645 SLOT_INIT_NOTIF,
646 staging::NETSTACK_PROC,
647 driver_slots::NET_INIT_NOTIF,
648 );
649
650 true
651}
652
653fn bootstrap_remote_shell(allocator: &mut UntypedAllocator, has_vfs: bool) -> bool {
654 let pid = match boot::create_process(allocator, b"remote-shell", staging::REMOTE_SHELL_PROC) {
655 Some(p) => p,
656 None => return false,
657 };
658
659 boot::grant_cap(
660 SERIAL_ENDPOINT,
661 staging::REMOTE_SHELL_PROC,
662 driver_slots::RSHELL_EP,
663 );
664
665 boot::grant_frames(
666 staging::REMOTE_SHELL_NET_RING_BASE,
667 staging::REMOTE_SHELL_PROC,
668 driver_slots::RSHELL_SHELL_RING_BASE,
669 staging::NETSTACK_SHELL_RING_COUNT,
670 );
671
672 boot::create_notification(allocator, staging::REMOTE_SHELL_NOTIF);
673 boot::grant_cap(
674 staging::REMOTE_SHELL_NOTIF,
675 staging::REMOTE_SHELL_PROC,
676 driver_slots::RSHELL_NOTIF,
677 );
678 boot::grant_cap(
679 staging::NETSTACK_NOTIF,
680 staging::REMOTE_SHELL_PROC,
681 driver_slots::RSHELL_NETSTACK_NOTIF,
682 );
683 boot::grant_cap(
684 staging::REMOTE_SHELL_NOTIF,
685 staging::NETSTACK_PROC,
686 driver_slots::NET_SHELL_NOTIF,
687 );
688
689 match has_vfs {
690 true => {
691 boot::create_shared_frames(
692 allocator,
693 staging::REMOTE_SHELL_VFS_RING_BASE,
694 staging::REMOTE_SHELL_PROC,
695 driver_slots::RSHELL_VFS_RING_BASE,
696 staging::REMOTE_SHELL_VFS_RING_COUNT,
697 );
698 boot::grant_frames(
699 staging::REMOTE_SHELL_VFS_RING_BASE,
700 staging::VFS_PROC_SLOT,
701 driver_slots::VFS_CLIENT0_RING_BASE,
702 staging::REMOTE_SHELL_VFS_RING_COUNT,
703 );
704
705 boot::grant_cap(SLOT_VFS_CLIENT_NOTIF, staging::REMOTE_SHELL_PROC, 12);
706 boot::grant_cap(SLOT_VFS_NOTIF, staging::REMOTE_SHELL_PROC, 13);
707 boot::grant_cap(staging::VFS_PROC_SLOT, staging::REMOTE_SHELL_PROC, 15);
708 }
709 false => {}
710 }
711
712 match boot::start_with_sched(
713 allocator,
714 staging::REMOTE_SHELL_PROC,
715 staging::REMOTE_SHELL_SCHED,
716 pid,
717 u64::MAX,
718 ) {
719 true => true,
720 false => {
721 show!(init, warn, "remote-shell start_with_sched failed");
722 syscall::proc_destroy(staging::REMOTE_SHELL_PROC);
723 false
724 }
725 }
726}
727
728fn bootstrap_all(allocator: &mut UntypedAllocator) -> BootState {
729 let mut state = BootState::new();
730
731 let com1_gsi = syscall::platform_info(boot::PLATFORM_COM1_GSI);
732 let kbd_gsi = syscall::platform_info(boot::PLATFORM_KBD_GSI);
733 let virtio_net_gsi = syscall::platform_info(boot::PLATFORM_VIRTIO_NET_GSI);
734 let has_fb = syscall::platform_info(boot::PLATFORM_HAS_FRAMEBUFFER) == 1;
735
736 match com1_gsi >= 0 {
737 true => {
738 state.has_serial = bootstrap_serial(allocator, com1_gsi as u64);
739 match state.has_serial {
740 true => show!(init, "serial driver started"),
741 false => show!(init, warn, "serial driver failed"),
742 }
743 }
744 false => show!(init, "skipping serial, no com1"),
745 }
746
747 match kbd_gsi >= 0 && state.has_serial {
748 true => {
749 state.has_ps2kbd = bootstrap_ps2kbd(allocator, kbd_gsi as u64);
750 match state.has_ps2kbd {
751 true => show!(init, "ps2kbd driver started"),
752 false => show!(init, warn, "ps2kbd driver failed"),
753 }
754 }
755 false => show!(init, "skipping ps2kbd"),
756 }
757
758 match has_fb {
759 true => {
760 state.has_fbconsole = bootstrap_fbconsole(allocator);
761 match state.has_fbconsole {
762 true => show!(init, "fbconsole driver started"),
763 false => show!(init, warn, "fbconsole driver failed"),
764 }
765 }
766 false => show!(init, "skipping fbconsole, no framebuffer"),
767 }
768
769 let nvme_dev_idx = boot::find_pci_device_by_class(0x01, 0x08, 0x02);
770 match nvme_dev_idx {
771 Some(idx) => {
772 state.has_nvme = bootstrap_nvme(allocator, idx);
773 match state.has_nvme {
774 true => show!(init, "nvme driver started"),
775 false => show!(init, warn, "nvme driver failed"),
776 }
777 }
778 None => show!(init, "skipping nvme, no device"),
779 }
780
781 if state.has_nvme {
782 show!(init, "creating lancerfs");
783 state.has_lancerfs = bootstrap_lancerfs(allocator);
784 match state.has_lancerfs {
785 true => {
786 bootstrap_nvme_service(allocator);
787 show!(init, "lancerfs started, linked to nvme");
788 }
789 false => show!(init, warn, "lancerfs failed"),
790 }
791 }
792
793 if state.has_lancerfs {
794 show!(init, "creating vfs");
795 state.has_vfs = bootstrap_vfs(allocator);
796 match state.has_vfs {
797 true => {
798 bootstrap_vfs_lancerfs(allocator);
799 state.has_vfs_client = bootstrap_vfs_client(allocator);
800 show!(init, "vfs started, linked to lancerfs");
801 }
802 false => show!(init, warn, "vfs failed"),
803 }
804 }
805
806 let ramfs_available = boot::find_module(b"ramfs").is_some();
807 if ramfs_available && state.has_vfs {
808 show!(init, "creating ramfs");
809 match bootstrap_ramfs(allocator) {
810 Some(pid) => {
811 bootstrap_vfs_ramfs(allocator);
812 state.has_ramfs = boot::start_with_sched(
813 allocator,
814 staging::RAMFS_PROC,
815 staging::RAMFS_SCHED,
816 pid,
817 u64::MAX,
818 );
819 match state.has_ramfs {
820 true => show!(init, "ramfs started, linked to vfs"),
821 false => {
822 syscall::proc_destroy(staging::RAMFS_PROC);
823 show!(init, warn, "ramfs start failed");
824 }
825 }
826 }
827 None => show!(init, warn, "ramfs failed"),
828 }
829 }
830
831 show!(init, "pci scan for virtio-net");
832 let virtio_dev_idx = boot::find_pci_device_by_vendor(0x1AF4, 0x02, 0x00);
833 let mut virtio_net_pid: Option<i64> = None;
834 match virtio_dev_idx {
835 Some(idx) if virtio_net_gsi >= 0 => {
836 virtio_net_pid = bootstrap_virtio_net(allocator, idx, virtio_net_gsi as u64);
837 state.has_virtio_net = virtio_net_pid.is_some();
838 match state.has_virtio_net {
839 true => show!(init, "virtio-net configured"),
840 false => show!(init, warn, "virtio-net driver failed"),
841 }
842 }
843 _ => show!(init, "skipping virtio-net"),
844 }
845
846 let mut netstack_pid: Option<i64> = None;
847 match state.has_virtio_net {
848 true => {
849 netstack_pid = bootstrap_netstack(allocator);
850 state.has_netstack = netstack_pid.is_some();
851 match state.has_netstack {
852 true => {
853 bootstrap_net_service(allocator);
854 bootstrap_init_netring(allocator);
855 show!(init, "netstack created, linking services");
856 }
857 false => show!(init, warn, "netstack failed"),
858 }
859 }
860 false => {}
861 }
862
863 if let Some(pid) = virtio_net_pid {
864 match boot::start_with_sched(
865 allocator,
866 staging::VIRTIO_NET_PROC,
867 staging::VIRTIO_NET_SCHED,
868 pid,
869 u64::MAX,
870 ) {
871 true => show!(init, "virtio-net driver started"),
872 false => {
873 state.has_virtio_net = false;
874 syscall::proc_destroy(staging::VIRTIO_NET_PROC);
875 show!(init, warn, "virtio-net start failed");
876 }
877 }
878 }
879
880 if state.has_netstack {
881 let shell_frames_ok = boot::create_shared_frames(
882 allocator,
883 staging::REMOTE_SHELL_NET_RING_BASE,
884 staging::NETSTACK_PROC,
885 driver_slots::NET_SHELL_RING_BASE,
886 staging::NETSTACK_SHELL_RING_COUNT,
887 );
888 match shell_frames_ok {
889 true => {}
890 false => show!(init, warn, "shell ring frame alloc failed"),
891 }
892 }
893
894 let remote_shell_available = boot::find_module(b"remote-shell").is_some();
895 match remote_shell_available && state.has_netstack {
896 true => {
897 state.has_remote_shell = bootstrap_remote_shell(allocator, state.has_vfs_client);
898 match state.has_remote_shell {
899 true => show!(init, "remote-shell started"),
900 false => show!(init, warn, "remote-shell failed"),
901 }
902 }
903 false => {}
904 }
905
906 if let Some(pid) = netstack_pid {
907 match boot::start_with_sched(
908 allocator,
909 staging::NETSTACK_PROC,
910 staging::NETSTACK_SCHED,
911 pid,
912 u64::MAX,
913 ) {
914 true => show!(init, "netstack started"),
915 false => {
916 state.has_netstack = false;
917 syscall::proc_destroy(staging::NETSTACK_PROC);
918 show!(init, warn, "netstack start failed");
919 }
920 }
921 }
922
923 state
924}
925
926use core::sync::atomic::{AtomicU64, Ordering};
927
928static FLIGHT_CURSOR: AtomicU64 = AtomicU64::new(0);
929
930fn ensure_mount_points() {
931 let mut client = unsafe {
932 lancer_user::fs::FsClient::new(
933 VFS_RING_VADDR as usize,
934 SLOT_VFS_NOTIF as u8,
935 SLOT_VFS_CLIENT_NOTIF as u8,
936 )
937 };
938 match client.mkdir(0, b"tmp") {
939 Ok(()) => {
940 show!(init, "created /tmp mount point");
941 }
942 Err(lancer_user::fs::FsStatus::FileExists) => {}
943 Err(_) => {
944 show!(init, warn, "failed to create /tmp");
945 }
946 }
947}
948
949fn ensure_dir(
950 client: &mut lancer_user::fs::FsClient,
951 parent: u8,
952 name: &[u8],
953) -> Result<(), lancer_user::fs::FsStatus> {
954 match client.mkdir(parent, name) {
955 Ok(()) => Ok(()),
956 Err(lancer_user::fs::FsStatus::FileExists) => Ok(()),
957 Err(e) => Err(e),
958 }
959}
960
961fn open_persistent_log(client: &mut lancer_user::fs::FsClient) -> Option<(u8, &'static str)> {
962 use lancer_user::fs::FsRights;
963
964 let rw_create =
965 FsRights::from_raw(FsRights::READ.raw() | FsRights::WRITE.raw() | FsRights::CREATE.raw());
966
967 let var_h = client.open(0, b"var", FsRights::ALL).ok()?;
968 let log_ok = ensure_dir(client, var_h, b"log").is_ok();
969 match log_ok {
970 true => {
971 let log_h = client.open(var_h, b"log", FsRights::ALL).ok();
972 let _ = client.close(var_h);
973 let log_h = log_h?;
974 match client.open(log_h, b"flight", rw_create) {
975 Ok(h) => {
976 let _ = client.close(log_h);
977 Some((h, "/var/log/flight"))
978 }
979 Err(_) => {
980 let _ = client.close(log_h);
981 None
982 }
983 }
984 }
985 false => {
986 let _ = client.close(var_h);
987 None
988 }
989 }
990}
991
992fn open_tmp_log(client: &mut lancer_user::fs::FsClient) -> Option<(u8, &'static str)> {
993 use lancer_user::fs::FsRights;
994
995 let rw_create =
996 FsRights::from_raw(FsRights::READ.raw() | FsRights::WRITE.raw() | FsRights::CREATE.raw());
997
998 let tmp_h = client.open(0, b"tmp", FsRights::ALL).ok()?;
999 match client.open(tmp_h, b"flight", rw_create) {
1000 Ok(h) => {
1001 let _ = client.close(tmp_h);
1002 Some((h, "/tmp/flight"))
1003 }
1004 Err(_) => {
1005 let _ = client.close(tmp_h);
1006 None
1007 }
1008 }
1009}
1010
1011fn try_drain(
1012 client: &mut lancer_user::fs::FsClient,
1013 handle: u8,
1014 path: &str,
1015 start_cursor: u64,
1016) -> (u64, u64, bool) {
1017 let file_offset = match client.stat(handle) {
1018 Ok(st) => st.size,
1019 Err(_) => 0,
1020 };
1021
1022 let mut cursor = start_cursor;
1023 let mut written: u64 = 0;
1024 let mut buf = [0u8; 4096];
1025 let mut disk_err = false;
1026
1027 loop {
1028 let (new_cursor, bytes_read) = syscall::blackbox_read(cursor, &mut buf);
1029 match bytes_read {
1030 0 => break,
1031 n => match client.write(handle, file_offset + written, &buf[..n]) {
1032 Ok(w) => {
1033 written += w as u64;
1034 cursor = new_cursor;
1035 }
1036 Err(_) => {
1037 disk_err = true;
1038 break;
1039 }
1040 },
1041 }
1042 }
1043
1044 let _ = client.close(handle);
1045
1046 match (written, disk_err) {
1047 (0, false) => show!(init, "flight log empty at cursor {}", start_cursor),
1048 (0, true) => show!(init, warn, "flight log write failed to {}", path),
1049 (_, true) => show!(
1050 init,
1051 warn,
1052 "flight log partial drain {} bytes to {}",
1053 written,
1054 path
1055 ),
1056 (_, false) => show!(init, "flight log drained {} bytes to {}", written, path),
1057 }
1058
1059 (cursor, written, disk_err)
1060}
1061
1062fn drain_flight_log() {
1063 use lancer_user::fs::FsClient;
1064
1065 let mut client = unsafe {
1066 FsClient::reattach(
1067 VFS_RING_VADDR as usize,
1068 SLOT_VFS_NOTIF as u8,
1069 SLOT_VFS_CLIENT_NOTIF as u8,
1070 )
1071 };
1072
1073 let cursor = FLIGHT_CURSOR.load(Ordering::Relaxed);
1074
1075 if let Some((handle, path)) = open_persistent_log(&mut client) {
1076 let (new_cursor, written, failed) = try_drain(&mut client, handle, path, cursor);
1077 match failed && written == 0 {
1078 false => {
1079 FLIGHT_CURSOR.store(new_cursor, Ordering::Relaxed);
1080 return;
1081 }
1082 true => {
1083 show!(init, warn, "persistent log full, falling back to /tmp");
1084 }
1085 }
1086 }
1087
1088 match open_tmp_log(&mut client) {
1089 Some((handle, path)) => {
1090 let (new_cursor, _, _) = try_drain(&mut client, handle, path, cursor);
1091 FLIGHT_CURSOR.store(new_cursor, Ordering::Relaxed);
1092 }
1093 None => {
1094 show!(init, warn, "flight log not writable");
1095 }
1096 }
1097}
1098
1099fn spawn_shell(allocator: &mut UntypedAllocator) -> bool {
1100 let module_idx = match boot::find_module(b"shell") {
1101 Some(idx) => idx,
1102 None => {
1103 show!(init, error, "shell module not found");
1104 return false;
1105 }
1106 };
1107
1108 let ut_slot = match allocator.find_for_retype(boot::TAG_PROCESS, 0) {
1109 Ok(s) => s,
1110 Err(_) => {
1111 show!(init, error, "no untyped large enough for process");
1112 return false;
1113 }
1114 };
1115
1116 let child_pid = syscall::proc_create(ut_slot, SLOT_SHELL_PROC);
1117 if child_pid < 0 {
1118 show!(init, error, "failed to create shell process");
1119 return false;
1120 }
1121
1122 let r = syscall::proc_load_module(SLOT_SHELL_PROC, module_idx);
1123 if r < 0 {
1124 show!(init, error, "failed to load shell module");
1125 syscall::proc_destroy(SLOT_SHELL_PROC);
1126 return false;
1127 }
1128
1129 let shell_ut = match allocator.find_large_untyped(256 * 1024) {
1130 Ok(s) => s,
1131 Err(_) => {
1132 show!(init, error, "no large untyped for shell");
1133 syscall::proc_destroy(SLOT_SHELL_PROC);
1134 return false;
1135 }
1136 };
1137 let r = syscall::cap_grant(shell_ut, SLOT_SHELL_PROC, 28, RIGHTS_ALL);
1138 if r < 0 {
1139 show!(init, error, "failed to grant untyped to shell");
1140 syscall::proc_destroy(SLOT_SHELL_PROC);
1141 return false;
1142 }
1143
1144 let r = syscall::cap_grant(SERIAL_ENDPOINT, SLOT_SHELL_PROC, 1, RIGHTS_ALL);
1145 if r < 0 {
1146 show!(init, error, "failed to grant serial endpoint to shell");
1147 syscall::proc_destroy(SLOT_SHELL_PROC);
1148 return false;
1149 }
1150
1151 [
1152 (SLOT_INIT_NOTIF, 9u64),
1153 (SLOT_NETSTACK_NOTIF, 10),
1154 (SLOT_VFS_CLIENT_NOTIF, 12),
1155 (SLOT_VFS_NOTIF, 13),
1156 (SLOT_VFS_PROC, 15),
1157 ]
1158 .iter()
1159 .for_each(|&(src_slot, dst_slot)| {
1160 let _ = syscall::cap_grant(src_slot, SLOT_SHELL_PROC, dst_slot, RIGHTS_ALL);
1161 });
1162
1163 (0..NETSTACK_RING_FRAME_COUNT).for_each(|i| {
1164 let _ = syscall::cap_grant(
1165 NETSTACK_RING_BASE_SLOT + i,
1166 SLOT_SHELL_PROC,
1167 SHELL_NETSTACK_RING_DST + i,
1168 RIGHTS_ALL,
1169 );
1170 });
1171
1172 (0..VFS_RING_FRAME_COUNT).for_each(|i| {
1173 let _ = syscall::cap_grant(
1174 VFS_RING_BASE_SLOT + i,
1175 SLOT_SHELL_PROC,
1176 SHELL_VFS_RING_DST + i,
1177 RIGHTS_ALL,
1178 );
1179 });
1180
1181 let r = match allocator.alloc_object(TAG_NOTIFICATION, 0, SLOT_SHELL_DEATH_NOTIF) {
1182 Ok(_) => 0,
1183 Err(_) => -1,
1184 };
1185 if r < 0 {
1186 show!(init, error, "failed to create shell death notif");
1187 syscall::proc_destroy(SLOT_SHELL_PROC);
1188 return false;
1189 }
1190
1191 syscall::proc_bind_death_notif(
1192 SLOT_SHELL_PROC,
1193 SLOT_SHELL_DEATH_NOTIF,
1194 NOTIFY_BIT_CHILD_DEATH,
1195 );
1196
1197 let r = match allocator.alloc_object(TAG_SCHED_CONTEXT, 0, SLOT_SHELL_SCHED) {
1198 Ok(_) => 0,
1199 Err(_) => -1,
1200 };
1201 if r < 0 {
1202 show!(init, error, "failed to create shell sched context");
1203 syscall::proc_destroy(SLOT_SHELL_PROC);
1204 syscall::cap_revoke(SLOT_SHELL_DEATH_NOTIF);
1205 return false;
1206 }
1207 let r = syscall::sched_configure(SLOT_SHELL_SCHED, 10_000_000, 10_000_000, 100);
1208 if r < 0 {
1209 show!(init, error, "failed to configure shell sched context");
1210 syscall::proc_destroy(SLOT_SHELL_PROC);
1211 syscall::cap_revoke(SLOT_SHELL_SCHED);
1212 syscall::cap_revoke(SLOT_SHELL_DEATH_NOTIF);
1213 return false;
1214 }
1215
1216 let r = syscall::sched_attach(SLOT_SHELL_SCHED, child_pid as u64);
1217 if r < 0 {
1218 show!(init, error, "failed to attach shell sched context");
1219 syscall::proc_destroy(SLOT_SHELL_PROC);
1220 syscall::cap_revoke(SLOT_SHELL_SCHED);
1221 syscall::cap_revoke(SLOT_SHELL_DEATH_NOTIF);
1222 return false;
1223 }
1224
1225 let r = syscall::proc_start(SLOT_SHELL_PROC, 0);
1226 if r < 0 {
1227 show!(init, error, "failed to start shell");
1228 syscall::proc_destroy(SLOT_SHELL_PROC);
1229 syscall::cap_revoke(SLOT_SHELL_SCHED);
1230 syscall::cap_revoke(SLOT_SHELL_DEATH_NOTIF);
1231 return false;
1232 }
1233
1234 true
1235}
1236
1237fn wait_for_shell_death() {
1238 loop {
1239 let (_, bits) = syscall::notify_wait(SLOT_SHELL_DEATH_NOTIF);
1240 if bits & NOTIFY_BIT_CHILD_DEATH != 0 {
1241 syscall::proc_destroy(SLOT_SHELL_PROC);
1242 syscall::cap_revoke(SLOT_SHELL_SCHED);
1243 syscall::cap_revoke(SLOT_SHELL_DEATH_NOTIF);
1244 break;
1245 }
1246 }
1247}
1248
1249#[unsafe(no_mangle)]
1250pub extern "C" fn lancer_main() -> ! {
1251 let mut allocator = match UntypedAllocator::from_boot_info() {
1252 Ok(a) => a,
1253 Err(_) => {
1254 show!(init, error, "failed to init untyped allocator");
1255 syscall::exit();
1256 }
1257 };
1258
1259 let boot_state = bootstrap_all(&mut allocator);
1260
1261 let has_vfs = boot_state.has_vfs_client
1262 && (0..VFS_RING_FRAME_COUNT)
1263 .all(|i| syscall::frame_map(VFS_RING_BASE_SLOT + i, VFS_RING_VADDR + i * 4096, 1) >= 0);
1264 match has_vfs {
1265 true => {
1266 syscall::notify_wait(SLOT_VFS_CLIENT_NOTIF);
1267 show!(init, "vfs ring mapped");
1268 ensure_mount_points();
1269 drain_flight_log();
1270 }
1271 false => {
1272 show!(init, warn, "vfs not available");
1273 }
1274 }
1275
1276 loop {
1277 match spawn_shell(&mut allocator) {
1278 true => {
1279 wait_for_shell_death();
1280 show!(init, "shell exited, respawning");
1281 if has_vfs {
1282 drain_flight_log();
1283 }
1284 }
1285 false => {
1286 show!(init, error, "shell spawn failed, retrying");
1287 syscall::sched_yield();
1288 }
1289 }
1290 }
1291}