monitor/
dlengine.rs

1use std::sync::OnceLock;
2
3use dynlink::{
4    compartment::{CompartmentId, MONITOR_COMPARTMENT_ID},
5    engines::{Backing, ContextEngine, LoadCtx},
6    library::UnloadedLibrary,
7    DynlinkError, DynlinkErrorKind,
8};
9use naming_core::{GetFlags, NameStore, NsNodeKind};
10use twizzler_abi::{
11    aux::KernelInitInfo,
12    object::{Protections, MAX_SIZE, NULLPAGE_SIZE},
13    syscall::{BackingType, ObjectCreate, ObjectCreateFlags},
14};
15use twizzler_rt_abi::{
16    error::{NamingError, TwzError},
17    object::{MapFlags, ObjID},
18};
19
20use crate::mon::{
21    get_monitor,
22    space::{MapInfo, Space},
23};
24
25pub struct Engine;
26
27fn get_new_sctx_instance(_sctx: ObjID) -> ObjID {
28    // TODO: we don't support real sctx instances yet
29    twizzler_abi::syscall::sys_object_create(
30        ObjectCreate::new(
31            BackingType::Normal,
32            twizzler_abi::syscall::LifetimeType::Volatile,
33            None,
34            ObjectCreateFlags::empty(),
35            Protections::all(),
36        ),
37        &[],
38        &[],
39    )
40    .unwrap()
41}
42
43impl ContextEngine for Engine {
44    fn load_segments(
45        &mut self,
46        src: &Backing,
47        ld: &[dynlink::engines::LoadDirective],
48        comp_id: CompartmentId,
49        load_ctx: &mut LoadCtx,
50    ) -> Result<Vec<Backing>, dynlink::DynlinkError> {
51        let instance = *load_ctx
52            .set
53            .entry(comp_id)
54            .or_insert_with(|| get_new_sctx_instance(1.into()));
55        let map = |text_id, data_id| {
56            #[allow(deprecated)]
57            let (text_handle, data_handle) = get_monitor()
58                .space
59                .lock()
60                .unwrap()
61                .map_pair(
62                    MapInfo {
63                        id: text_id,
64                        flags: MapFlags::READ | MapFlags::EXEC,
65                    },
66                    MapInfo {
67                        id: data_id,
68                        flags: MapFlags::READ | MapFlags::WRITE,
69                    },
70                )
71                .map_err(|_| DynlinkErrorKind::NewBackingFail)?;
72
73            if data_handle.monitor_data_start() as usize
74                != text_handle.monitor_data_start() as usize + MAX_SIZE
75            {
76                tracing::error!(
77                                "internal runtime error: failed to map text and data adjacent and in-order ({:p} {:p})",
78                                text_handle.monitor_data_start(),
79                                data_handle.monitor_data_start(),
80                            );
81                return Err(DynlinkErrorKind::NewBackingFail.into());
82            }
83            unsafe {
84                Ok((
85                    Backing::new_owned(
86                        text_handle.monitor_data_start(),
87                        MAX_SIZE - NULLPAGE_SIZE * 2,
88                        text_id,
89                        text_handle,
90                        src.full_name().to_owned(),
91                    ),
92                    Backing::new_owned(
93                        data_handle.monitor_data_start(),
94                        MAX_SIZE - NULLPAGE_SIZE * 2,
95                        data_id,
96                        data_handle,
97                        src.full_name().to_owned(),
98                    ),
99                ))
100            }
101        };
102        dynlink::engines::twizzler::load_segments(src, ld, instance, map)
103    }
104
105    fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result<Backing, DynlinkError> {
106        let (id, full) = name_resolver(&unlib.name)?;
107        let mapping = Space::map(
108            &get_monitor().space,
109            MapInfo {
110                id,
111                flags: MapFlags::READ,
112            },
113        )
114        .map_err(|_err| DynlinkErrorKind::NewBackingFail)?;
115        Ok(unsafe {
116            Backing::new_owned(
117                mapping.monitor_data_start(),
118                MAX_SIZE - NULLPAGE_SIZE * 2,
119                id,
120                mapping,
121                full,
122            )
123        })
124    }
125
126    fn select_compartment(
127        &mut self,
128        _unlib: &UnloadedLibrary,
129    ) -> Option<dynlink::compartment::CompartmentId> {
130        Some(MONITOR_COMPARTMENT_ID)
131    }
132}
133
134static NAMING: OnceLock<NameStore> = OnceLock::new();
135
136pub fn set_naming(root: ObjID) -> Result<(), TwzError> {
137    NAMING
138        .set(NameStore::new_with_root(root)?)
139        .map_err(|_| NamingError::AlreadyBound.into())
140}
141
142pub fn naming() -> Option<&'static NameStore> {
143    NAMING.get()
144}
145
146fn do_name_resolver(name: &str) -> Result<(ObjID, String), DynlinkError> {
147    if let Some(namer) = naming() {
148        let session = namer.root_session();
149        let node = session.get(name, GetFlags::FOLLOW_SYMLINK).map_err(|_| {
150            DynlinkErrorKind::NameNotFound {
151                name: name.to_string(),
152            }
153        })?;
154        return match node.kind {
155            NsNodeKind::Object => Ok((node.id, name.to_string())),
156            _ => Err(DynlinkErrorKind::NameNotFound {
157                name: name.to_string(),
158            }
159            .into()),
160        };
161    }
162
163    find_init_name(name).ok_or(
164        DynlinkErrorKind::NameNotFound {
165            name: name.to_string(),
166        }
167        .into(),
168    )
169}
170
171fn name_resolver(mut name: &str) -> Result<(ObjID, String), DynlinkError> {
172    if name.starts_with("libstd") {
173        name = "libstd.so";
174    }
175    if name.starts_with("libtest") {
176        name = "libtest.so";
177    }
178
179    if let Ok(r) = do_name_resolver(name) {
180        return Ok(r);
181    }
182
183    let initrdname = format!("/initrd/{}", name);
184    do_name_resolver(initrdname.as_str())
185}
186
187pub fn get_kernel_init_info() -> &'static KernelInitInfo {
188    unsafe {
189        (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE)
190            as *const KernelInitInfo)
191            .as_ref()
192            .unwrap()
193    }
194}
195
196fn find_init_name(name: &str) -> Option<(ObjID, String)> {
197    let init_info = get_kernel_init_info();
198    for n in init_info.names() {
199        if n.name() == name {
200            return Some((n.id(), name.to_owned()));
201        }
202    }
203    None
204}