dynlink/engines/
twizzler.rs1use itertools::{Either, Itertools};
2use twizzler_abi::{
3 object::{ObjID, Protections, MAX_SIZE, NULLPAGE_SIZE},
4 syscall::{
5 sys_object_create, BackingType, CreateTieFlags, CreateTieSpec, LifetimeType, ObjectCreate,
6 ObjectCreateFlags, ObjectSource,
7 },
8};
9
10use super::{Backing, LoadDirective, LoadFlags};
11use crate::{DynlinkError, DynlinkErrorKind};
12
13pub struct Engine;
14
15fn within_object(slot: usize, addr: usize) -> bool {
16 addr >= slot * MAX_SIZE + NULLPAGE_SIZE && addr < (slot + 1) * MAX_SIZE - NULLPAGE_SIZE * 2
17}
18
19pub fn load_segments(
22 src: &Backing,
23 ld: &[LoadDirective],
24 instance: ObjID,
25 map: impl FnOnce(ObjID, ObjID) -> Result<(Backing, Backing), DynlinkError>,
26) -> Result<Vec<Backing>, DynlinkError> {
27 let create_spec = ObjectCreate::new(
28 BackingType::Normal,
29 LifetimeType::Volatile,
30 None,
31 ObjectCreateFlags::DELETE,
32 Protections::all(),
33 );
34
35 let build_copy_cmd = |directive: &LoadDirective| {
36 if !within_object(
37 if directive.load_flags.contains(LoadFlags::TARGETS_DATA) {
38 1
39 } else {
40 0
41 },
42 directive.vaddr,
43 ) || directive.memsz > MAX_SIZE - NULLPAGE_SIZE * 2
44 || directive.offset > MAX_SIZE - NULLPAGE_SIZE * 2
45 || directive.filesz > directive.memsz
46 {
47 return Err(DynlinkError::new(DynlinkErrorKind::LoadDirectiveFail {
48 dir: *directive,
49 }));
50 }
51
52 if directive.filesz != directive.memsz {
57 if directive.filesz < directive.memsz {
58 } else {
63 todo!()
64 }
65 }
66
67 let src_start = NULLPAGE_SIZE + directive.offset;
69 let dest_start = directive.vaddr as usize % MAX_SIZE;
74 let len = directive.filesz;
76
77 if !directive.load_flags.contains(LoadFlags::TARGETS_DATA) {
78 #[cfg(target_arch = "x86_64")]
87 if src_start != dest_start {
88 return Err(DynlinkError::new(DynlinkErrorKind::LoadDirectiveFail {
90 dir: *directive,
91 }));
92 }
93 }
94
95 Ok(ObjectSource::new_copy(
96 src.id(),
97 src_start as u64,
98 dest_start as u64,
99 len,
100 ))
101 };
102
103 let ld = ld.to_vec();
104 let (data_cmds, text_cmds): (Vec<_>, Vec<_>) = ld.into_iter().partition_map(|directive| {
105 if directive.load_flags.contains(LoadFlags::TARGETS_DATA) {
106 Either::Left(build_copy_cmd(&directive))
107 } else {
108 Either::Right(build_copy_cmd(&directive))
109 }
110 });
111
112 let data_cmds = DynlinkError::collect(DynlinkErrorKind::NewBackingFail, data_cmds)?;
113 let text_cmds = DynlinkError::collect(DynlinkErrorKind::NewBackingFail, text_cmds)?;
114
115 let data_id = sys_object_create(
116 create_spec,
117 &data_cmds,
118 &[CreateTieSpec::new(instance, CreateTieFlags::empty())],
119 )
120 .map_err(|_| DynlinkErrorKind::NewBackingFail)?;
121
122 let text_id = sys_object_create(
123 create_spec,
124 &text_cmds,
125 &[CreateTieSpec::new(instance, CreateTieFlags::empty())],
126 )
127 .map_err(|_| DynlinkErrorKind::NewBackingFail)?;
128
129 tracing::trace!(
130 "mapped segments in instance {} to {}, {}",
131 instance,
132 text_id,
133 data_id
134 );
135
136 let (text, data) = map(text_id, data_id)?;
137 Ok(vec![text, data])
138}