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