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