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 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}