1use core::{
4 ffi::c_void,
5 fmt::{LowerHex, UpperHex},
6 mem::MaybeUninit,
7 ptr::{addr_of, addr_of_mut},
8 sync::atomic::{AtomicU32, AtomicU64, Ordering},
9};
10
11use bitflags::bitflags;
12
13use crate::{
14 bindings::{
15 object_cmd, object_create, object_tie, sync_info, twz_rt_object_cmd, LEN_MUL,
16 OBJECT_CMD_DELETE, OBJECT_CMD_SYNC, OBJECT_CMD_UPDATE,
17 },
18 error::{RawTwzError, ResourceError, TwzError},
19 nk, Result,
20};
21
22#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
24#[repr(transparent)]
25pub struct ObjID(twizzler_types::ObjID);
26
27impl ObjID {
28 pub const NR_PARTS: usize = 2;
30
31 pub const fn new(raw: twizzler_types::ObjID) -> Self {
33 Self(raw)
34 }
35
36 pub const fn raw(&self) -> twizzler_types::ObjID {
38 self.0
39 }
40
41 pub const fn from_parts(parts: [u64; Self::NR_PARTS]) -> Self {
43 Self::new(((parts[0] as u128) << 64) | (parts[1] as u128))
44 }
45
46 pub const fn parts(&self) -> [u64; Self::NR_PARTS] {
48 [(self.0 >> 64) as u64, (self.0 & 0xffffffffffffffff) as u64]
49 }
50}
51
52impl core::convert::AsRef<ObjID> for ObjID {
53 fn as_ref(&self) -> &ObjID {
54 self
55 }
56}
57
58impl From<twizzler_types::ObjID> for ObjID {
59 fn from(id: twizzler_types::ObjID) -> Self {
60 Self::new(id)
61 }
62}
63
64impl LowerHex for ObjID {
65 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
66 write!(f, "{:x}", self.0)
67 }
68}
69
70impl UpperHex for ObjID {
71 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
72 write!(f, "{:X}", self.0)
73 }
74}
75
76impl core::fmt::Display for ObjID {
77 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78 write!(f, "ObjID({:x})", self.0)
79 }
80}
81
82impl core::fmt::Debug for ObjID {
83 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84 write!(f, "ObjID({:x})", self.0)
85 }
86}
87
88#[repr(transparent)]
96pub struct ObjectHandle(pub(crate) crate::bindings::object_handle);
97
98impl core::fmt::Debug for ObjectHandle {
99 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 write!(
101 f,
102 "ObjectHandle({:?}, {:p}, {:x}, {:?})",
103 self.id(),
104 self.start(),
105 self.valid_len(),
106 self.map_flags()
107 )
108 }
109}
110
111unsafe impl Send for ObjectHandle {}
112unsafe impl Sync for ObjectHandle {}
113
114bitflags::bitflags! {
115 #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug)]
117 pub struct MapFlags : crate::bindings::map_flags {
118 const READ = crate::bindings::MAP_FLAG_R;
120 const WRITE = crate::bindings::MAP_FLAG_W;
122 const EXEC = crate::bindings::MAP_FLAG_X;
124 const PERSIST = crate::bindings::MAP_FLAG_PERSIST;
126 const INDIRECT = crate::bindings::MAP_FLAG_INDIRECT;
128 const NO_NULLPAGE = crate::bindings::MAP_FLAG_NO_NULLPAGE;
129 }
130}
131
132impl MapFlags {
133 pub fn rw() -> Self {
134 Self::READ | Self::WRITE | Self::PERSIST
135 }
136
137 pub fn rw_volatile() -> Self {
138 Self::READ | Self::WRITE
139 }
140
141 pub fn ro() -> Self {
142 Self::READ | Self::INDIRECT
143 }
144
145 pub fn rx() -> Self {
146 Self::READ | Self::EXEC | Self::INDIRECT
147 }
148}
149
150#[repr(u32)]
151pub enum ObjectCmd {
152 Delete = OBJECT_CMD_DELETE,
153 Sync = OBJECT_CMD_SYNC,
154 Update = OBJECT_CMD_UPDATE,
155}
156
157impl TryFrom<object_cmd> for ObjectCmd {
158 type Error = TwzError;
159
160 fn try_from(value: object_cmd) -> core::result::Result<Self, Self::Error> {
161 match value {
162 OBJECT_CMD_DELETE => Ok(ObjectCmd::Delete),
163 OBJECT_CMD_SYNC => Ok(ObjectCmd::Sync),
164 OBJECT_CMD_UPDATE => Ok(ObjectCmd::Update),
165 _ => Err(TwzError::INVALID_ARGUMENT),
166 }
167 }
168}
169
170#[allow(dead_code)]
171impl ObjectHandle {
172 fn refs(&self) -> *const AtomicU64 {
173 self.0.runtime_info.cast()
174 }
175
176 pub fn start(&self) -> *mut u8 {
178 self.0.start.cast()
179 }
180
181 pub fn meta(&self) -> *mut MetaInfo {
183 self.0.meta.cast()
184 }
185
186 pub fn meta_exts(&self) -> &[MetaExt] {
188 unsafe {
189 core::slice::from_raw_parts(
190 self.0.meta.cast::<u8>().add(size_of::<MetaInfo>()).cast(),
191 (*self.meta()).extcount as usize,
192 )
193 }
194 }
195
196 fn all_meta_exts(&self) -> &[MetaExt] {
198 unsafe {
199 core::slice::from_raw_parts(
200 self.0.meta.cast::<u8>().add(size_of::<MetaInfo>()).cast(),
201 16,
202 )
203 }
204 }
205
206 pub fn find_meta_ext(&self, tag: MetaExtTag) -> Option<&MetaExt> {
208 self.meta_exts()
209 .iter()
210 .find(|e| e.value.load(Ordering::SeqCst) != 0 && e.tag == tag)
211 }
212
213 pub unsafe fn set_meta_ext(&self, ext: MetaExt) -> Result<()> {
214 let meta_exts = self.meta_exts();
215 for me in meta_exts {
216 if me.tag == ext.tag {
217 me.value
218 .store(ext.value.load(Ordering::SeqCst), Ordering::SeqCst);
219 return Ok(());
220 }
221 }
222 let meta_exts = self.all_meta_exts();
223 for (idx, me) in meta_exts.iter().enumerate() {
224 if me.tag == MEXT_EMPTY {
225 if me
226 .value
227 .swap(ext.value.load(Ordering::Relaxed), Ordering::SeqCst)
228 == 0
229 {
230 let ptr = addr_of!(me.tag) as *mut MetaExtTag;
231 ptr.write(ext.tag);
232 (*self.meta()).extcount = (idx + 1) as u16;
233 return Ok(());
234 }
235 }
236 }
237 Err(TwzError::Resource(ResourceError::OutOfResources))
238 }
239
240 pub fn runtime_info(&self) -> *mut u8 {
242 self.0.runtime_info.cast()
243 }
244
245 pub fn map_flags(&self) -> MapFlags {
247 MapFlags::from_bits_truncate(self.0.map_flags)
248 }
249
250 pub fn valid_len(&self) -> usize {
252 (self.0.valid_len as usize) * crate::bindings::LEN_MUL
253 }
254
255 pub fn id(&self) -> ObjID {
257 ObjID::new(self.0.id)
258 }
259
260 pub fn into_raw(self) -> crate::bindings::object_handle {
262 let this = core::mem::ManuallyDrop::new(self);
263 this.0
264 }
265
266 pub fn from_raw(raw: crate::bindings::object_handle) -> Self {
268 Self(raw)
269 }
270
271 pub fn cmd<T>(&self, cmd: ObjectCmd, arg: *mut T) -> Result<()> {
273 let err = unsafe {
274 nk!(twz_rt_object_cmd(
275 &self.0 as *const _ as *mut _,
276 cmd as object_cmd,
277 arg.cast()
278 ))
279 };
280 let raw = RawTwzError::new(err);
281 if raw.is_success() {
282 Ok(())
283 } else {
284 Err(raw.error())
285 }
286 }
287
288 pub unsafe fn new(
294 id: ObjID,
295 runtime_info: *mut core::ffi::c_void,
296 start: *mut core::ffi::c_void,
297 meta: *mut core::ffi::c_void,
298 map_flags: MapFlags,
299 valid_len: usize,
300 ) -> Self {
301 Self::from_raw(crate::bindings::object_handle {
302 id: id.0,
303 runtime_info,
304 start,
305 meta,
306 map_flags: map_flags.bits(),
307 valid_len: (valid_len / LEN_MUL) as u32,
308 })
309 }
310}
311
312impl Clone for ObjectHandle {
313 fn clone(&self) -> Self {
314 unsafe {
315 let Some(ref rc) = self.refs().as_ref() else {
316 return Self(self.0);
317 };
318 let old_count = rc.fetch_add(1, Ordering::Relaxed);
320 if old_count >= i64::MAX as u64 {
323 nk!(crate::core::twz_rt_abort());
324 }
325 }
326 Self(self.0)
327 }
328}
329
330impl Drop for ObjectHandle {
331 fn drop(&mut self) {
332 unsafe {
333 let Some(ref rc) = self.refs().as_ref() else {
334 return;
335 };
336 if rc.fetch_sub(1, Ordering::Release) != 1 {
338 return;
339 }
340 }
341 core::sync::atomic::fence(Ordering::Acquire);
344 nk!(twz_rt_release_handle(self, 0));
345 }
346}
347
348impl AsRef<ObjectHandle> for ObjectHandle {
349 fn as_ref(&self) -> &ObjectHandle {
350 self
351 }
352}
353
354impl From<Result<ObjectHandle>> for crate::bindings::map_result {
355 fn from(value: Result<ObjectHandle>) -> Self {
356 match value {
357 Ok(handle) => Self {
358 handle: handle.into_raw(),
359 error: RawTwzError::success().raw(),
360 },
361 Err(e) => Self {
362 handle: crate::bindings::object_handle::default(),
363 error: e.raw(),
364 },
365 }
366 }
367}
368
369impl From<crate::bindings::map_result> for Result<ObjectHandle> {
370 fn from(value: crate::bindings::map_result) -> Self {
371 let raw = RawTwzError::new(value.error);
372 if raw.is_success() {
373 Ok(ObjectHandle(value.handle))
374 } else {
375 Err(raw.error())
376 }
377 }
378}
379
380pub fn twz_rt_map_object(id: ObjID, flags: MapFlags) -> Result<ObjectHandle> {
382 unsafe { nk!(crate::bindings::twz_rt_map_object(id.raw(), flags.bits()).into()) }
383}
384
385pub fn twz_rt_get_object_handle(ptr: *const u8) -> Result<ObjectHandle> {
386 use crate::error::ObjectError;
387
388 let res = unsafe {
389 nk!(crate::bindings::twz_rt_get_object_handle(
390 (ptr as *mut u8).cast()
391 ))
392 };
393 if res.id == 0 {
394 return Err(TwzError::Object(ObjectError::NotMapped));
395 }
396 Ok(ObjectHandle(res))
397}
398
399pub fn twz_rt_resolve_fot(
400 this: &ObjectHandle,
401 idx: u64,
402 valid_len: usize,
403 flags: MapFlags,
404) -> Result<ObjectHandle> {
405 unsafe {
406 nk!(crate::bindings::twz_rt_resolve_fot(
407 &this.0 as *const _ as *mut _,
408 idx,
409 valid_len,
410 flags.bits(),
411 ))
412 .into()
413 }
414}
415
416impl From<Result<u32>> for crate::bindings::u32_result {
417 fn from(value: Result<u32>) -> Self {
418 match value {
419 Ok(val) => Self {
420 val,
421 err: RawTwzError::success().raw(),
422 },
423 Err(e) => Self {
424 val: 0,
425 err: e.raw(),
426 },
427 }
428 }
429}
430
431impl From<crate::bindings::u32_result> for Result<u32> {
432 fn from(value: crate::bindings::u32_result) -> Self {
433 let raw = RawTwzError::new(value.err);
434 if raw.is_success() {
435 Ok(value.val)
436 } else {
437 Err(raw.error())
438 }
439 }
440}
441
442pub fn twz_rt_insert_fot(this: &ObjectHandle, entry: *const u8) -> Result<u32> {
443 unsafe {
444 let res = nk!(crate::bindings::twz_rt_insert_fot(
445 &this.0 as *const _ as *mut _,
446 (entry as *mut u8).cast(),
447 ));
448 res.into()
449 }
450}
451
452pub fn twz_rt_resolve_fot_local(
453 start: *mut u8,
454 idx: u64,
455 valid_len: usize,
456 flags: MapFlags,
457) -> *mut u8 {
458 unsafe {
459 let res = nk!(crate::bindings::twz_rt_resolve_fot_local(
460 start.cast(),
461 idx,
462 valid_len,
463 flags.bits()
464 ));
465 res.cast()
466 }
467}
468
469use crate::bindings::release_flags;
470
471pub fn twz_rt_release_handle(handle: &mut ObjectHandle, flags: release_flags) {
473 unsafe { nk!(crate::bindings::twz_rt_release_handle(&mut handle.0, flags)) }
474}
475
476pub fn twz_rt_update_handle(handle: &mut ObjectHandle) -> Result<()> {
478 let r = unsafe { nk!(crate::bindings::twz_rt_update_handle(&mut handle.0)) };
479 let r = RawTwzError::new(r);
480 if r.is_success() {
481 Ok(())
482 } else {
483 Err(r.error())
484 }
485}
486
487#[deprecated]
488pub fn twz_rt_map_two_objects(
489 id1: ObjID,
490 flags1: MapFlags,
491 id2: ObjID,
492 flags2: MapFlags,
493) -> Result<(ObjectHandle, ObjectHandle)> {
494 unsafe {
495 let mut res1 = MaybeUninit::uninit();
496 let mut res2 = MaybeUninit::uninit();
497 nk!(crate::bindings::__twz_rt_map_two_objects(
498 id1.raw(),
499 flags1.bits(),
500 id2.raw(),
501 flags2.bits(),
502 res1.as_mut_ptr(),
503 res2.as_mut_ptr(),
504 ));
505
506 let res1 = res1.assume_init();
507 let res2 = res2.assume_init();
508
509 let res1: Result<ObjectHandle> = res1.into();
510 let res2: Result<ObjectHandle> = res2.into();
511
512 Ok((res1?, res2?))
513 }
514}
515
516bitflags::bitflags! {
517 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
519 pub struct Protections: u16 {
520 const READ = crate::bindings::MAP_FLAG_R as u16;
522 const WRITE = crate::bindings::MAP_FLAG_W as u16;
524 const EXEC = crate::bindings::MAP_FLAG_X as u16;
526 }
527}
528
529impl From<Protections> for MapFlags {
530 fn from(p: Protections) -> Self {
531 let mut f = MapFlags::empty();
532 if p.contains(Protections::READ) {
533 f.insert(MapFlags::READ);
534 }
535
536 if p.contains(Protections::WRITE) {
537 f.insert(MapFlags::WRITE);
538 }
539
540 if p.contains(Protections::EXEC) {
541 f.insert(MapFlags::EXEC);
542 }
543 f
544 }
545}
546
547impl From<MapFlags> for Protections {
548 fn from(value: MapFlags) -> Self {
549 let mut f = Self::empty();
550 if value.contains(MapFlags::READ) {
551 f.insert(Protections::READ);
552 }
553 if value.contains(MapFlags::WRITE) {
554 f.insert(Protections::WRITE);
555 }
556 if value.contains(MapFlags::EXEC) {
557 f.insert(Protections::EXEC);
558 }
559 f
560 }
561}
562
563bitflags::bitflags! {
564#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
566pub struct MetaFlags: u16 {
567 const IMMUTABLE = 1;
568}
569}
570
571#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
573#[repr(transparent)]
574pub struct Nonce(pub u128);
575
576#[derive(Clone, Copy, Debug, PartialEq, Hash)]
578#[repr(C)]
579pub struct MetaInfo {
580 pub nonce: Nonce,
582 pub kuid: ObjID,
584 pub flags: MetaFlags,
586 pub default_prot: Protections,
588 pub fotcount: u16,
590 pub extcount: u16,
592}
593
594#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
596#[repr(transparent)]
597pub struct MetaExtTag(pub u64);
598
599#[repr(C)]
601pub struct MetaExt {
602 pub tag: MetaExtTag,
604 pub value: AtomicU64,
606}
607
608impl MetaExt {
609 pub fn new(tag: MetaExtTag, value: u64) -> Self {
610 Self {
611 tag,
612 value: AtomicU64::new(value),
613 }
614 }
615}
616
617pub const MEXT_EMPTY: MetaExtTag = MetaExtTag(0);
618pub const MEXT_SIZED: MetaExtTag = MetaExtTag(1);
619
620pub const MAX_SIZE: usize = 1024 * 1024 * 1024;
622pub const NULLPAGE_SIZE: usize = 0x1000;
624
625#[repr(C)]
626pub struct FotEntry {
627 pub values: [u64; 2],
628 pub resolver: u64,
629 pub flags: AtomicU32,
630}
631
632bitflags::bitflags! {
633 #[repr(C)]
634 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
635 pub struct FotFlags : u32 {
636 const ALLOCATED = 1;
637 const ACTIVE = 2;
638 const DELETED = 4;
639 const RESOLVER = 8;
640 }
641}
642
643#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Default)]
644#[repr(C)]
645pub struct ObjectSource {
650 pub id: ObjID,
652 pub src_start: u64,
655 pub dest_start: u64,
657 pub len: usize,
659}
660
661impl From<ObjectSource> for crate::bindings::object_source {
662 fn from(value: ObjectSource) -> Self {
663 Self {
664 id: value.id.raw(),
665 src_start: value.src_start,
666 dest_start: value.dest_start,
667 len: value.len as u64,
668 }
669 }
670}
671
672impl ObjectSource {
673 pub fn new_copy(id: ObjID, src_start: u64, dest_start: u64, len: usize) -> Self {
675 Self {
676 id,
677 src_start,
678 dest_start,
679 len,
680 }
681 }
682
683 pub fn new_zero(dest_start: u64, len: usize) -> Self {
685 Self {
686 id: ObjID::new(0),
687 src_start: 0,
688 dest_start,
689 len,
690 }
691 }
692}
693
694#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Default)]
695#[repr(u32)]
696pub enum BackingType {
698 #[default]
700 Normal = crate::bindings::BACKING_TYPE_NORMAL,
701}
702
703#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Default)]
704#[repr(u32)]
705pub enum LifetimeType {
709 #[default]
711 Volatile = crate::bindings::LIFETIME_TYPE_VOLATILE,
712 Persistent = crate::bindings::LIFETIME_TYPE_PERSISTENT,
714}
715
716impl From<u32> for LifetimeType {
717 fn from(value: u32) -> Self {
718 match value {
719 crate::bindings::LIFETIME_TYPE_VOLATILE => LifetimeType::Volatile,
720 crate::bindings::LIFETIME_TYPE_PERSISTENT => LifetimeType::Persistent,
721 _ => panic!("Invalid lifetime type"),
722 }
723 }
724}
725
726impl From<u32> for BackingType {
727 fn from(value: u32) -> Self {
728 match value {
729 crate::bindings::BACKING_TYPE_NORMAL => BackingType::Normal,
730 _ => panic!("Invalid backing type"),
731 }
732 }
733}
734
735bitflags! {
736 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
738 pub struct ObjectCreateFlags: u32 {
739 const DELETE = 1;
740 const NO_NONCE = 2;
741 }
742}
743
744bitflags! {
745 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
747 pub struct CreateTieFlags: u32 {
748 }
749}
750
751#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
752#[repr(C)]
753pub struct ObjectCreate {
755 pub kuid: ObjID,
756 pub bt: BackingType,
757 pub lt: LifetimeType,
758 pub flags: ObjectCreateFlags,
759 pub def_prot: Protections,
760}
761impl ObjectCreate {
762 pub fn new(
764 bt: BackingType,
765 lt: LifetimeType,
766 kuid: Option<ObjID>,
767 flags: ObjectCreateFlags,
768 def_prot: Protections,
769 ) -> Self {
770 Self {
771 kuid: kuid.unwrap_or_else(|| ObjID::new(0)),
772 bt,
773 lt,
774 flags,
775 def_prot,
776 }
777 }
778}
779
780impl Default for ObjectCreate {
781 fn default() -> Self {
782 Self::new(
783 BackingType::Normal,
784 LifetimeType::Volatile,
785 None,
786 ObjectCreateFlags::empty(),
787 Protections::all(),
788 )
789 }
790}
791
792impl From<ObjectCreate> for crate::bindings::object_create {
793 fn from(value: ObjectCreate) -> Self {
794 Self {
795 kuid: value.kuid.0,
796 lifetime: value.lt as u32,
797 backing: value.bt as u32,
798 flags: value.flags.bits(),
799 prot: value.def_prot.bits() as u32,
800 }
801 }
802}
803
804impl From<object_create> for ObjectCreate {
805 fn from(value: object_create) -> Self {
806 Self {
807 kuid: ObjID::new(value.kuid),
808 bt: BackingType::from(value.backing),
809 lt: LifetimeType::from(value.lifetime),
810 flags: ObjectCreateFlags::from_bits_truncate(value.flags),
811 def_prot: Protections::from_bits_truncate(value.prot as u16),
812 }
813 }
814}
815
816#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
817#[repr(C)]
818pub struct CreateTieSpec {
821 pub id: ObjID,
822 pub flags: CreateTieFlags,
823}
824
825impl CreateTieSpec {
826 pub fn new(id: ObjID, flags: CreateTieFlags) -> Self {
828 Self { id, flags }
829 }
830}
831
832impl From<CreateTieSpec> for object_tie {
833 fn from(value: CreateTieSpec) -> Self {
834 Self {
835 id: value.id.raw(),
836 flags: value.flags.bits(),
837 }
838 }
839}
840
841unsafe impl Send for sync_info {}
842unsafe impl Sync for sync_info {}
843
844impl sync_info {
845 pub unsafe fn try_release(&self) -> Result<()> {
846 self.release_ptr
847 .cast::<AtomicU64>()
848 .as_ref()
849 .unwrap()
850 .compare_exchange(
851 self.release_compare,
852 self.release_set,
853 Ordering::SeqCst,
854 Ordering::SeqCst,
855 )
856 .map_err(|_| TwzError::Resource(ResourceError::Refused))
857 .map(|_| ())
858 }
859
860 pub unsafe fn set_durable(&self, err: impl Into<RawTwzError>) {
861 if self.durable_ptr.is_null() {
862 return;
863 }
864
865 self.durable_ptr
866 .cast::<AtomicU64>()
867 .as_ref()
868 .unwrap()
869 .store(err.into().raw(), Ordering::SeqCst);
870 }
871}