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 tracing::error!("invalid directives: {:?}", directive);
48 return Err(DynlinkError::new(DynlinkErrorKind::LoadDirectiveFail {
49 dir: *directive,
50 }));
51 }
52
53 if directive.filesz != directive.memsz {
58 if directive.filesz < directive.memsz {
59 } else {
64 todo!()
65 }
66 }
67
68 let src_start = NULLPAGE_SIZE + directive.offset;
70 let dest_start = directive.vaddr as usize % MAX_SIZE;
75 let len = directive.filesz;
77
78 if !directive.load_flags.contains(LoadFlags::TARGETS_DATA) {
79 #[cfg(target_arch = "x86_64")]
88 if src_start != dest_start {
89 tracing::error!(
90 "invalid align: {:?}, {:x} {:x}",
91 directive,
92 src_start,
93 dest_start
94 );
95 return Err(DynlinkError::new(DynlinkErrorKind::LoadDirectiveFail {
97 dir: *directive,
98 }));
99 }
100 }
101
102 Ok(ObjectSource::new_copy(src.id(), src_start as u64, dest_start as u64, len).into())
103 };
104
105 let ld = ld.to_vec();
106 let (data_cmds, text_cmds): (Vec<_>, Vec<_>) = ld.into_iter().partition_map(|directive| {
107 if directive.load_flags.contains(LoadFlags::TARGETS_DATA) {
108 Either::Left(build_copy_cmd(&directive))
109 } else {
110 Either::Right(build_copy_cmd(&directive))
111 }
112 });
113
114 let data_cmds = DynlinkError::collect(DynlinkErrorKind::NewBackingFail, data_cmds)?;
115 let text_cmds = DynlinkError::collect(DynlinkErrorKind::NewBackingFail, text_cmds)?;
116
117 let data_id = sys_object_create(
118 create_spec,
119 &data_cmds,
120 &[CreateTieSpec::new(instance, CreateTieFlags::empty()).into()],
121 )
122 .map_err(|_| DynlinkErrorKind::NewBackingFail)?;
123
124 let text_id = sys_object_create(
125 create_spec,
126 &text_cmds,
127 &[CreateTieSpec::new(instance, CreateTieFlags::empty()).into()],
128 )
129 .map_err(|_| DynlinkErrorKind::NewBackingFail)?;
130 tracing::trace!(
133 "mapped segments in instance {} to {}, {}",
134 instance,
135 text_id,
136 data_id
137 );
138
139 let (text, data) = map(text_id, data_id)?;
140 Ok(vec![text, data])
141}