Next Generation WASM Microkernel Operating System
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use crate::arch;
9use crate::mem::frame_alloc::{FRAME_ALLOC, FrameAllocator};
10use crate::mem::frame_alloc::{Frame, frame_list::FrameList};
11use alloc::sync::Arc;
12use core::alloc::Layout;
13use core::fmt::Debug;
14use core::iter;
15use core::num::NonZeroUsize;
16use spin::{LazyLock, OnceLock};
17
18pub trait Provider: Debug {
19 // TODO make async
20 fn get_frame(&self, at_offset: usize, will_write: bool) -> crate::Result<Frame>;
21 // TODO make async
22 fn get_frames(
23 &self,
24 at_offset: usize,
25 len: NonZeroUsize,
26 will_write: bool,
27 ) -> crate::Result<FrameList>;
28 fn free_frame(&self, frame: Frame);
29 fn free_frames(&self, frames: FrameList);
30}
31
32pub static THE_ZERO_FRAME: LazyLock<Arc<TheZeroFrame>> = LazyLock::new(|| {
33 let frame_alloc = FRAME_ALLOC.get().unwrap();
34 Arc::new(TheZeroFrame::new(frame_alloc))
35});
36
37#[derive(Debug)]
38pub struct TheZeroFrame {
39 frame_alloc: &'static FrameAllocator,
40 frame: OnceLock<Frame>,
41}
42
43impl TheZeroFrame {
44 pub fn new(frame_alloc: &'static FrameAllocator) -> Self {
45 Self {
46 frame_alloc,
47 frame: OnceLock::new(),
48 }
49 }
50 pub(super) fn frame(&self) -> &Frame {
51 self.frame.get_or_init(|| {
52 let frame = self.frame_alloc.alloc_one_zeroed().unwrap();
53 tracing::trace!("THE_ZERO_FRAME: {}", frame.addr());
54 frame
55 })
56 }
57}
58
59impl Provider for TheZeroFrame {
60 fn get_frame(&self, _at_offset: usize, will_write: bool) -> crate::Result<Frame> {
61 if will_write {
62 self.frame_alloc.alloc_one_zeroed().map_err(Into::into)
63 } else {
64 Ok(self.frame().clone())
65 }
66 }
67
68 fn get_frames(
69 &self,
70 _at_offset: usize,
71 len: NonZeroUsize,
72 will_write: bool,
73 ) -> crate::Result<FrameList> {
74 if will_write {
75 self.frame_alloc
76 .alloc_contiguous_zeroed(
77 Layout::from_size_align(len.get(), arch::PAGE_SIZE).unwrap(),
78 )
79 .map_err(Into::into)
80 } else {
81 Ok(FrameList::from_iter(iter::repeat_n(
82 self.frame().clone(),
83 len.get(),
84 )))
85 }
86 }
87
88 fn free_frame(&self, frame: Frame) {
89 drop(frame);
90 }
91
92 fn free_frames(&self, frames: FrameList) {
93 for frame in frames {
94 self.free_frame(frame);
95 }
96 }
97}