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            tracing::trace!(
84                "map {}: {} {}",
85                src.full_name(),
86                text_handle.id(),
87                data_handle.id()
88            );
89            unsafe {
90                Ok((
91                    Backing::new_owned(
92                        text_handle.monitor_data_start(),
93                        MAX_SIZE - NULLPAGE_SIZE * 2,
94                        text_id,
95                        text_handle,
96                        src.full_name().into(),
97                    ),
98                    Backing::new_owned(
99                        data_handle.monitor_data_start(),
100                        MAX_SIZE - NULLPAGE_SIZE * 2,
101                        data_id,
102                        data_handle,
103                        src.full_name().into(),
104                    ),
105                ))
106            }
107        };
108        dynlink::engines::twizzler::load_segments(src, ld, instance, map)
109    }
110
111    fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result<Backing, DynlinkError> {
112        let (id, full) = name_resolver(&unlib.name)?;
113        let mapping = Space::map(
114            &get_monitor().space,
115            MapInfo {
116                id,
117                flags: MapFlags::READ,
118            },
119        )
120        .map_err(|_err| DynlinkErrorKind::NewBackingFail)?;
121        Ok(unsafe {
122            Backing::new_owned(
123                mapping.monitor_data_start(),
124                MAX_SIZE - NULLPAGE_SIZE * 2,
125                id,
126                mapping,
127                full,
128            )
129        })
130    }
131
132    fn select_compartment(
133        &mut self,
134        _unlib: &UnloadedLibrary,
135    ) -> Option<dynlink::compartment::CompartmentId> {
136        Some(MONITOR_COMPARTMENT_ID)
137    }
138}
139
140static NAMING: OnceLock<NameStore> = OnceLock::new();
141
142pub fn set_naming(root: ObjID) -> Result<(), TwzError> {
143    NAMING
144        .set(NameStore::new_with_root(root)?)
145        .map_err(|_| NamingError::AlreadyBound.into())
146}
147
148pub fn naming() -> Option<&'static NameStore> {
149    NAMING.get()
150}
151
152fn do_name_resolver(name: &str) -> Result<(ObjID, String), DynlinkError> {
153    if let Some(namer) = naming() {
154        let session = namer.root_session();
155        let node = session
156            .get(name, GetFlags::FOLLOW_SYMLINK)
157            .map_err(|_| DynlinkErrorKind::NameNotFound { name: name.into() })?;
158        return match node.kind {
159            NsNodeKind::Object => Ok((node.id, name.into())),
160            _ => Err(DynlinkErrorKind::NameNotFound { name: name.into() }.into()),
161        };
162    }
163
164    find_init_name(name).ok_or(DynlinkErrorKind::NameNotFound { name: name.into() }.into())
165}
166
167fn name_resolver(mut name: &str) -> Result<(ObjID, String), DynlinkError> {
168    if name.starts_with("libstd") {
169        name = "libstd.so";
170    }
171    if name.starts_with("libtest") {
172        name = "libtest.so";
173    }
174
175    if let Ok(r) = do_name_resolver(name) {
176        return Ok(r);
177    }
178
179    let initrdname = format!("/initrd/{}", name);
180    do_name_resolver(initrdname.as_str())
181}
182
183pub fn get_kernel_init_info() -> &'static KernelInitInfo {
184    unsafe {
185        (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE)
186            as *const KernelInitInfo)
187            .as_ref()
188            .unwrap()
189    }
190}
191
192fn find_init_name(name: &str) -> Option<(ObjID, String)> {
193    let init_info = get_kernel_init_info();
194    for n in init_info.names() {
195        if n.name() == name {
196            return Some((n.id(), name.to_string()));
197        }
198    }
199    None
200}