From 43700e8052a0e1f81bd1c528f0f17952134aba89 Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Tue, 24 Feb 2026 17:21:15 +1100 Subject: [PATCH 1/6] WIP: Handing off untypeds to PD Signed-off-by: Szymon Duchniewicz --- .../sel4-capdl-initializer/src/initialize.rs | 122 +++++++++++++++++- .../sel4-capdl-initializer/types/src/spec.rs | 1 + 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/crates/sel4-capdl-initializer/src/initialize.rs b/crates/sel4-capdl-initializer/src/initialize.rs index cdb91a420..76e59a3ee 100644 --- a/crates/sel4-capdl-initializer/src/initialize.rs +++ b/crates/sel4-capdl-initializer/src/initialize.rs @@ -17,7 +17,7 @@ use log::{debug, error, info, trace}; use sel4::{ CapRights, CapTypeForFrameObjectOfFixedSize, cap_type, - init_thread::{self, Slot}, + init_thread::{self, Slot, SlotRegion}, }; use sel4_capdl_initializer_types::*; @@ -26,8 +26,27 @@ use crate::error::CapDLInitializerError; use crate::hold_slots::HoldSlots; use crate::memory::{CopyAddrs, get_user_image_frame_slot}; + +// XXX: added temp +use sel4::CPtr; +use sel4::cap::CNode; +use sel4::NoExplicitInvocationContext; + type Result = CoreResult; +// Info passed to the initial task from capDL, based on bootinfo +pub struct CapDLBootInfo { + // TODO: figure out the size of this, might have more untypeds after splitting? and where to + // allocate + // XXX: is this necessary? can untypeds be offset by this already? (2 level index in singel + // entry?) + untyped_cnode_idx: usize, + untypeds: SlotRegion, + #[allow(non_snake_case)] + untypedList: [sel4::UntypedDesc; sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] +} + + pub struct Initializer<'a> { bootinfo: &'a sel4::BootInfoPtr, user_image_bounds: Range, @@ -83,6 +102,7 @@ impl<'a> Initializer<'a> { fn run(&mut self) -> Result<()> { self.create_objects()?; + self.create_untyped_info()?; self.init_irqs()?; self.init_asids()?; @@ -119,6 +139,8 @@ impl<'a> Initializer<'a> { arr.sort_unstable_by_key(|i| uts[*i].paddr()); arr }; + let mut uts_watermark_by_paddr: [usize; + sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] = [0; sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)]; // Index root objects @@ -190,6 +212,9 @@ impl<'a> Initializer<'a> { ); } + // Since the capDL spec object list (AFTER THE objects which have a specified PHYS ADDR) is expected + // in a descending order of obj size, we + // use this to get the start (inclusive) and end (exclusive) range of indexes of objects of all sizes let mut by_size_start: [usize; sel4::WORD_SIZE] = array::from_fn(|_| 0); let mut by_size_end: [usize; sel4::WORD_SIZE] = array::from_fn(|_| 0); { @@ -197,6 +222,7 @@ impl<'a> Initializer<'a> { let obj = &self.object(obj_id.into()); if let Some(blueprint) = obj.blueprint() { by_size_end[blueprint.physical_size_bits()] += 1; + info!("obj size: {}", blueprint.physical_size_bits()); } } let mut acc = first_obj_without_paddr; @@ -207,6 +233,11 @@ impl<'a> Initializer<'a> { } } + info!("start end"); + for size in 0..sel4::WORD_SIZE { + info!("{} {}", by_size_start[size], by_size_end[size]); + } + // In order to allocate objects which specify paddrs, we may have to // allocate dummies to manipulate watermarks. We must always retain at // least one reference to an object allocated from an untyped, or else @@ -217,7 +248,7 @@ impl<'a> Initializer<'a> { // Create root objects let mut next_obj_with_paddr = 0; - for i_ut in uts_by_paddr.iter() { + for (idx, i_ut) in uts_by_paddr.iter().enumerate() { let ut = &uts[*i_ut]; let ut_size_bits = ut.size_bits(); let ut_size_bytes = 1 << ut_size_bits; @@ -246,6 +277,9 @@ impl<'a> Initializer<'a> { }; let target_is_obj_with_paddr = target < ut_paddr_end; while cur_paddr < target { + // If not allocating objects with set physical address, doing a first fit alloc + // algo (untypeds sorted in ascending paddr, objects for allocation sorted in + // descending order by size) let max_size_bits = usize::try_from(cur_paddr.trailing_zeros()) .unwrap() .min((target - cur_paddr).trailing_zeros().try_into().unwrap()); @@ -281,6 +315,7 @@ impl<'a> Initializer<'a> { 1, )?; cur_paddr += 1 << size_bits; + uts_watermark_by_paddr[idx] += 1 << size_bits; *obj_id += 1; created = true; break; @@ -290,6 +325,7 @@ impl<'a> Initializer<'a> { if !created { if target_is_obj_with_paddr { let hold_slot = hold_slots.get_slot()?; + // TODO: later, save this untyped and reuse it trace!( "Creating dummy: paddr=0x{cur_paddr:x}, size_bits={max_size_bits}" ); @@ -303,7 +339,10 @@ impl<'a> Initializer<'a> { )?; hold_slots.report_used(); cur_paddr += 1 << max_size_bits; + uts_watermark_by_paddr[idx] += 1 << max_size_bits; } else { + // Not allocating an object with specified paddr, and cannot fit any + // remaining objects in this untyped. Skip cur_paddr = target; } } @@ -325,6 +364,7 @@ impl<'a> Initializer<'a> { 1, )?; cur_paddr += 1 << blueprint.physical_size_bits(); + uts_watermark_by_paddr[idx] += 1 << blueprint.physical_size_bits(); next_obj_with_paddr += 1; } else { break; @@ -332,6 +372,12 @@ impl<'a> Initializer<'a> { } } + info!("paddr, watermark, ut capacity, %tage"); + for idx in 0..uts.len() { + let size = 1 << &uts[uts_by_paddr[idx]].size_bits(); + info!("0x{:x} {} {} {}%", uts[uts_by_paddr[idx]].paddr(), uts_watermark_by_paddr[idx], size, 100*uts_watermark_by_paddr[idx] / size); + } + // Ensure that we've created every root object let mut oom = false; for bits in 0..sel4::WORD_SIZE { @@ -349,7 +395,9 @@ impl<'a> Initializer<'a> { // Create child objects + info!("DONE CREATING ROOT OBJECTS!"); for cover in self.spec.untyped_covers.iter() { + info!("CREATING UNTYPED COVER STUFF!"); let parent_obj_id = cover.parent; let parent = self.named_object(parent_obj_id); let parent_cptr = self.orig_cap::(parent_obj_id); @@ -474,6 +522,76 @@ impl<'a> Initializer<'a> { Ok(()) } + fn create_untyped_info(&mut self) -> Result<()> { + // Sort untypeds by paddr + let mut _uts_by_paddr_backing: [usize; + sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] = array::from_fn(|i| i); // TODO (not a big deal) allocate in image rather than on stack + let uts = self.bootinfo.untyped_list(); + let uts_by_paddr = { + let arr = &mut _uts_by_paddr_backing[..uts.len()]; + arr.sort_unstable_by_key(|i| uts[*i].paddr()); + arr + }; + // Check if a CNode (and memory region) marked for receiving untypeds exists, if so construct meta data on all + // remaining untypeds, copy (or move?) the untypeds to the receiving CNode and pass the + // meta data to the marked memory region. + let mut receiving_untypeds_cnode_id; + let mut receiving_untypeds_frame_id; + let mut found = false; + for (obj_id, obj) in self.filter_objects::() { + if obj.receive_all_untypeds { + receiving_untypeds_cnode_id = obj_id; + found = true; + } + } + if !found { + debug!("No CNode found for receiving untyped objects"); + return Ok(()); + } + found = false; + for (obj_id, obj) in self.filter_objects::>() { + //if let Some(name) = object_name(self.named_object(obj_id)) { + // XXX: FIX: modify memory regions to contain a better way of indicating it should + // receive the untyped metadata + if object_name(self.named_object(obj_id)).unwrap_or_else(|| "").contains("remaining_untypeds") { + // Get the first Frame of the memory region (if larger than a page, only get the + // first page) + receiving_untypeds_frame_id = obj_id; + found = true; + break; + } + } + if !found { + error!("CNode for receiving untyped objects found, but no matching Frame (Memory Region) found!"); + } + info!("Found both CNode and Frame for receiving untypeds and their meta data"); + + // Move all untypeds to the new CNode + // TODO: move only CLEAN untypeds to the new CNode (watermark == 0). Also move the split + // untypeds created when aligning objects to phys addr + // // TODO: fix hack for calculating CPtr idx: 1 << (kernel_config,cap_address_bits - + // root_cnode_size_bits) + let untyped_cptr_slot = CPtr::from_bits(1 << (64 - 6)); + for (ut_idx, ut) in uts.iter().enumerate() { + let cnode_cap: CNode = self.orig_cslot((receiving_untypeds_cnode_id).into()).cap().into(); + cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE).move_( + &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE) + ); + //init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx), sel4::WORD_SIZE).move_(src) + //init_thread_cnode_absolute_cptr() + //self.ut_cap(ut_idx) + } + + + // TODO: figure out how create_objects tracks untyped info + // TODO: move all "clean" untypeds after create_objects to new CNode + // TODO: move CNode to the root CNode slot in target PD's Cnode, save the idx to the passed + // on struct + // TODO: construct the struct (and array) containing all untyped info, put it inside the + // memory region marked ("remaining_untypeds" name? maybe mark in spec instead?) + Ok(()) + } + fn init_irqs(&mut self) -> Result<()> { debug!("Initializing IRQs"); diff --git a/crates/sel4-capdl-initializer/types/src/spec.rs b/crates/sel4-capdl-initializer/types/src/spec.rs index 1e07006a5..628a7a84d 100644 --- a/crates/sel4-capdl-initializer/types/src/spec.rs +++ b/crates/sel4-capdl-initializer/types/src/spec.rs @@ -384,6 +384,7 @@ pub mod object { pub struct CNode { pub size_bits: u8, pub slots: Vec, + pub receive_all_untypeds: bool, } #[derive(Debug, Clone, Eq, PartialEq, IsObject, HasCapTable)] From eea81b5f25bd0d4112f6fc04f582f9d74ba6e445 Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Thu, 5 Mar 2026 13:50:05 +1100 Subject: [PATCH 2/6] WIP: add patching in frame with untyped metadata * Temporarily swap the original CNode cap pointing to CNode receiving the untypeds with the one specified in the capDL spec which has a specific guard setup. Signed-off-by: Szymon Duchniewicz --- .../sel4-capdl-initializer/src/initialize.rs | 102 ++++++++++++++---- crates/sel4/src/init_thread.rs | 2 +- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/crates/sel4-capdl-initializer/src/initialize.rs b/crates/sel4-capdl-initializer/src/initialize.rs index 76e59a3ee..e2afb71ca 100644 --- a/crates/sel4-capdl-initializer/src/initialize.rs +++ b/crates/sel4-capdl-initializer/src/initialize.rs @@ -8,6 +8,7 @@ use core::array; use core::ops::Range; use core::result::Result as CoreResult; use core::slice; +use core::mem; use rkyv::Archive; use rkyv::ops::ArchivedRange; @@ -27,28 +28,25 @@ use crate::hold_slots::HoldSlots; use crate::memory::{CopyAddrs, get_user_image_frame_slot}; -// XXX: added temp -use sel4::CPtr; -use sel4::cap::CNode; -use sel4::NoExplicitInvocationContext; - type Result = CoreResult; // Info passed to the initial task from capDL, based on bootinfo +#[repr(C)] pub struct CapDLBootInfo { // TODO: figure out the size of this, might have more untypeds after splitting? and where to // allocate // XXX: is this necessary? can untypeds be offset by this already? (2 level index in singel // entry?) - untyped_cnode_idx: usize, + untyped_cnode_cap: sel4::Cap, untypeds: SlotRegion, #[allow(non_snake_case)] - untypedList: [sel4::UntypedDesc; sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] + untypedList: [sel4::sys::seL4_UntypedDesc; sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] } pub struct Initializer<'a> { bootinfo: &'a sel4::BootInfoPtr, + capdl_bootinfo: CapDLBootInfo, user_image_bounds: Range, copy_addrs: CopyAddrs, spec: &'a ::Archived, @@ -81,8 +79,14 @@ impl<'a> Initializer<'a> { ) .unwrap(); + let capdl_bootinfo = CapDLBootInfo { untyped_cnode_cap: sel4::Cap::::from_bits(0 as sel4::CPtrBits), untypeds: + SlotRegion::::from_range(0..0), + untypedList:bootinfo.inner().untypedList.clone(), // TODO (not a big deal) allocate in image rather than on stack + }; + Initializer { bootinfo, + capdl_bootinfo, user_image_bounds, copy_addrs, spec, @@ -102,7 +106,6 @@ impl<'a> Initializer<'a> { fn run(&mut self) -> Result<()> { self.create_objects()?; - self.create_untyped_info()?; self.init_irqs()?; self.init_asids()?; @@ -118,6 +121,7 @@ impl<'a> Initializer<'a> { self.init_tcbs()?; self.init_cspaces()?; + self.create_untyped_info()?; self.start_threads()?; Ok(()) @@ -314,6 +318,13 @@ impl<'a> Initializer<'a> { self.orig_cslot((*obj_id).into()).index(), 1, )?; + if let Some(a) = named_obj.object.as_::() && a.receive_all_untypeds { + info!("Mutating guard of receiving Cap, swapping and deleting original!"); + let guard = sel4::CNodeCapData::new(0, 56).into_word(); + init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64 + 1, sel4::WORD_SIZE).mutate(&init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64, sel4::WORD_SIZE), guard); + // swap + init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64, sel4::WORD_SIZE).move_(&init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64 + 1, sel4::WORD_SIZE)); + } cur_paddr += 1 << size_bits; uts_watermark_by_paddr[idx] += 1 << size_bits; *obj_id += 1; @@ -535,14 +546,19 @@ impl<'a> Initializer<'a> { // Check if a CNode (and memory region) marked for receiving untypeds exists, if so construct meta data on all // remaining untypeds, copy (or move?) the untypeds to the receiving CNode and pass the // meta data to the marked memory region. - let mut receiving_untypeds_cnode_id; - let mut receiving_untypeds_frame_id; + let mut receiving_untypeds_cnode_id = None; + let mut root_cnode_id = None; + let mut receiving_untypeds_frame_id = None; + let mut receiving_untypeds_frame_obj = None; let mut found = false; for (obj_id, obj) in self.filter_objects::() { if obj.receive_all_untypeds { - receiving_untypeds_cnode_id = obj_id; + receiving_untypeds_cnode_id = Some(obj_id); found = true; } + if object_name(self.named_object(obj_id)).unwrap_or_else(||"").contains("_root") { + root_cnode_id = Some(obj_id); + } } if !found { debug!("No CNode found for receiving untyped objects"); @@ -556,13 +572,14 @@ impl<'a> Initializer<'a> { if object_name(self.named_object(obj_id)).unwrap_or_else(|| "").contains("remaining_untypeds") { // Get the first Frame of the memory region (if larger than a page, only get the // first page) - receiving_untypeds_frame_id = obj_id; + receiving_untypeds_frame_id = Some(obj_id); + receiving_untypeds_frame_obj = Some(obj); found = true; break; } } if !found { - error!("CNode for receiving untyped objects found, but no matching Frame (Memory Region) found!"); + panic!("CNode for receiving untyped objects found, but no matching Frame (Memory Region) found!"); } info!("Found both CNode and Frame for receiving untypeds and their meta data"); @@ -571,24 +588,69 @@ impl<'a> Initializer<'a> { // untypeds created when aligning objects to phys addr // // TODO: fix hack for calculating CPtr idx: 1 << (kernel_config,cap_address_bits - // root_cnode_size_bits) - let untyped_cptr_slot = CPtr::from_bits(1 << (64 - 6)); + let mut untyped_cptr_slot = 0; + //let cap = self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")); + self.capdl_bootinfo = CapDLBootInfo { + untyped_cnode_cap: self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")), + untypeds: SlotRegion::::from_range(0..self.bootinfo.untyped().len()), + // XXX: maybe not clone it but initialise an empty array with default() trait? https://gist.github.com/ChrisWellsWood/84421854794037e760808d5d97d21421 + untypedList: self.bootinfo.inner().untypedList.clone(), // TODO (not a big deal) allocate in image rather than on stack + }; for (ut_idx, ut) in uts.iter().enumerate() { - let cnode_cap: CNode = self.orig_cslot((receiving_untypeds_cnode_id).into()).cap().into(); - cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE).move_( + //let cnode_cap: CNode = self.orig_cslot((receiving_untypeds_cnode_id).into()).cap().into(); + let res = self.capdl_bootinfo.untyped_cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE).move_( &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE) ); - //init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx), sel4::WORD_SIZE).move_(src) - //init_thread_cnode_absolute_cptr() - //self.ut_cap(ut_idx) + match res { + Ok(()) => {}, + Err(e) => panic!("Failed to copy untypeds {}", e) + } + // XXX: add info on watermark? actually will probably need to discard dirty Untypeds + // and only put here clean ones/split the dirty ones (and move here the splie ones) + self.capdl_bootinfo.untypedList[ut_idx] = ut.inner().clone(); + + untyped_cptr_slot += 1; + //cnode_cap = self.orig_cap::(root_cnode_id.expect("root Cnode not found but got here")); + //info!("root Cnode cap: {:?}", cnode_cap); + //info!("target slot Absolute CPtr: {:?}", cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE)); + // + //let res = cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE).copy( + // &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE), + // CapRights::all() + //); + //info!("Res: {:?}", res); + //break; } - // TODO: figure out how create_objects tracks untyped info // TODO: move all "clean" untypeds after create_objects to new CNode // TODO: move CNode to the root CNode slot in target PD's Cnode, save the idx to the passed // on struct // TODO: construct the struct (and array) containing all untyped info, put it inside the // memory region marked ("remaining_untypeds" name? maybe mark in spec instead?) + + // Fill the frame with the struct of untyped info + let frame_object_type = + sel4::FrameObjectType::from_bits(receiving_untypeds_frame_obj.expect("Receiving untyped info Frame obj not found but got here").size_bits.into()).unwrap(); + let frame = self.orig_cap::(receiving_untypeds_frame_id.expect("Receiving untyped info Frame ID not found but got here")); + frame.frame_map( + init_thread::slot::VSPACE.cap(), + self.copy_addrs.select(frame_object_type), + CapRights::read_write(), + vm_attributes_from_whether_cached_and_exec(true, false), + )?; + let p = &self.capdl_bootinfo as *const CapDLBootInfo as *const u8; + let capdl_bootinfo_slice = unsafe { slice::from_raw_parts(p, mem::size_of::()) }; + let dst_frame = self.copy_addrs.select(frame_object_type) as *mut u8; + let dst = unsafe { slice::from_raw_parts_mut(dst_frame, mem::size_of::()) }; + + info!("capdl_bootinfo.untyped_cnode_cap: {:?}\n", self.capdl_bootinfo.untyped_cnode_cap); + dst.copy_from_slice(capdl_bootinfo_slice); + //pub fn copy_out(&self, dst: &mut [u8]) { + // dst.copy_from_slice(&self.bytes) + //} + + frame.frame_unmap()?; Ok(()) } diff --git a/crates/sel4/src/init_thread.rs b/crates/sel4/src/init_thread.rs index f70a3d575..5e5487b69 100644 --- a/crates/sel4/src/init_thread.rs +++ b/crates/sel4/src/init_thread.rs @@ -76,7 +76,7 @@ pub struct SlotRegion { #[allow(clippy::len_without_is_empty)] impl SlotRegion { - pub(crate) const fn from_range(range: Range) -> Self { + pub const fn from_range(range: Range) -> Self { Self { range, _phantom: PhantomData, From 5a37178e5c31198829318bbf691f5c7399fd0238 Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Fri, 6 Mar 2026 14:14:06 +1100 Subject: [PATCH 3/6] Working: handing off untypeds to microkit PD requires modified microkit, szymon/handoff-untypeds branch Signed-off-by: Szymon Duchniewicz --- .../sel4-capdl-initializer/src/initialize.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/sel4-capdl-initializer/src/initialize.rs b/crates/sel4-capdl-initializer/src/initialize.rs index e2afb71ca..e21c6da16 100644 --- a/crates/sel4-capdl-initializer/src/initialize.rs +++ b/crates/sel4-capdl-initializer/src/initialize.rs @@ -79,10 +79,14 @@ impl<'a> Initializer<'a> { ) .unwrap(); - let capdl_bootinfo = CapDLBootInfo { untyped_cnode_cap: sel4::Cap::::from_bits(0 as sel4::CPtrBits), untypeds: - SlotRegion::::from_range(0..0), - untypedList:bootinfo.inner().untypedList.clone(), // TODO (not a big deal) allocate in image rather than on stack + let capdl_bootinfo = CapDLBootInfo { + untyped_cnode_cap: sel4::Cap::::from_bits(1 << (64-6) as sel4::CPtrBits), + // leave slot 0 empty (used as self-reference to the CNode itself) + untypeds: SlotRegion::::from_range(1..bootinfo.untyped().len()+1), + // XXX: maybe not clone it but initialise an empty array with default() trait? https://gist.github.com/ChrisWellsWood/84421854794037e760808d5d97d21421 + untypedList:bootinfo.inner().untypedList.clone(), // TODO (not a big deal) allocate in image rather than on stack }; + info!("capdl_bootinfo: {:?}", capdl_bootinfo.untyped_cnode_cap); Initializer { bootinfo, @@ -318,13 +322,6 @@ impl<'a> Initializer<'a> { self.orig_cslot((*obj_id).into()).index(), 1, )?; - if let Some(a) = named_obj.object.as_::() && a.receive_all_untypeds { - info!("Mutating guard of receiving Cap, swapping and deleting original!"); - let guard = sel4::CNodeCapData::new(0, 56).into_word(); - init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64 + 1, sel4::WORD_SIZE).mutate(&init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64, sel4::WORD_SIZE), guard); - // swap - init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64, sel4::WORD_SIZE).move_(&init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.orig_cslot((*obj_id).into()).index() as u64 + 1, sel4::WORD_SIZE)); - } cur_paddr += 1 << size_bits; uts_watermark_by_paddr[idx] += 1 << size_bits; *obj_id += 1; @@ -588,17 +585,17 @@ impl<'a> Initializer<'a> { // untypeds created when aligning objects to phys addr // // TODO: fix hack for calculating CPtr idx: 1 << (kernel_config,cap_address_bits - // root_cnode_size_bits) - let mut untyped_cptr_slot = 0; + let mut untyped_cptr_slot = 1; //let cap = self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")); - self.capdl_bootinfo = CapDLBootInfo { - untyped_cnode_cap: self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")), - untypeds: SlotRegion::::from_range(0..self.bootinfo.untyped().len()), - // XXX: maybe not clone it but initialise an empty array with default() trait? https://gist.github.com/ChrisWellsWood/84421854794037e760808d5d97d21421 - untypedList: self.bootinfo.inner().untypedList.clone(), // TODO (not a big deal) allocate in image rather than on stack - }; + // this is the initial Cap to the CNode that got created, with guardsize = 0, hence need to + // do some arithmetic with addressing + let untyped_cnode_cap_init = self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")); + for (ut_idx, ut) in uts.iter().enumerate() { + // TODO: extract size_bits from the capdl_spec for the root cnode and the receiving_untyped_cnode + info!("untyped cptr offset: {:x}", untyped_cptr_slot); //let cnode_cap: CNode = self.orig_cslot((receiving_untypeds_cnode_id).into()).cap().into(); - let res = self.capdl_bootinfo.untyped_cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE).move_( + let res = untyped_cnode_cap_init.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, 8).move_( &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE) ); match res { @@ -607,7 +604,10 @@ impl<'a> Initializer<'a> { } // XXX: add info on watermark? actually will probably need to discard dirty Untypeds // and only put here clean ones/split the dirty ones (and move here the splie ones) - self.capdl_bootinfo.untypedList[ut_idx] = ut.inner().clone(); + // XXX: should this be addressed with regards to untyped_cptr_slot and not ut_idx? + // maybe reshape the untyped CNode so thye always live from idx 0 -> + // capdl_bootinfo.untypeds.end? + self.capdl_bootinfo.untypedList[untyped_cptr_slot as usize] = ut.inner().clone(); untyped_cptr_slot += 1; //cnode_cap = self.orig_cap::(root_cnode_id.expect("root Cnode not found but got here")); From e66495957e36bf7058634068f320feab77955138 Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Fri, 6 Mar 2026 16:13:29 +1100 Subject: [PATCH 4/6] cleanup Signed-off-by: Szymon Duchniewicz --- .../sel4-capdl-initializer/src/initialize.rs | 115 ++++++------------ 1 file changed, 35 insertions(+), 80 deletions(-) diff --git a/crates/sel4-capdl-initializer/src/initialize.rs b/crates/sel4-capdl-initializer/src/initialize.rs index e21c6da16..70b5389d3 100644 --- a/crates/sel4-capdl-initializer/src/initialize.rs +++ b/crates/sel4-capdl-initializer/src/initialize.rs @@ -33,14 +33,15 @@ type Result = CoreResult; // Info passed to the initial task from capDL, based on bootinfo #[repr(C)] pub struct CapDLBootInfo { - // TODO: figure out the size of this, might have more untypeds after splitting? and where to - // allocate // XXX: is this necessary? can untypeds be offset by this already? (2 level index in singel // entry?) - untyped_cnode_cap: sel4::Cap, + untyped_cnode_cptr: sel4::Cap, untypeds: SlotRegion, + // TODO: figure out the size of this, might have more untypeds after splitting? and where to + // allocate #[allow(non_snake_case)] - untypedList: [sel4::sys::seL4_UntypedDesc; sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] + untypedList: [sel4::sys::seL4_UntypedDesc; sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)], + // TODO: add watermark tracking } @@ -80,13 +81,13 @@ impl<'a> Initializer<'a> { .unwrap(); let capdl_bootinfo = CapDLBootInfo { - untyped_cnode_cap: sel4::Cap::::from_bits(1 << (64-6) as sel4::CPtrBits), + untyped_cnode_cptr: sel4::Cap::::from_bits(1 << (64-6) as sel4::CPtrBits), // leave slot 0 empty (used as self-reference to the CNode itself) untypeds: SlotRegion::::from_range(1..bootinfo.untyped().len()+1), // XXX: maybe not clone it but initialise an empty array with default() trait? https://gist.github.com/ChrisWellsWood/84421854794037e760808d5d97d21421 untypedList:bootinfo.inner().untypedList.clone(), // TODO (not a big deal) allocate in image rather than on stack }; - info!("capdl_bootinfo: {:?}", capdl_bootinfo.untyped_cnode_cap); + info!("capdl_bootinfo.untyped_cnode_cptr: {:?}", capdl_bootinfo.untyped_cnode_cptr); Initializer { bootinfo, @@ -230,7 +231,6 @@ impl<'a> Initializer<'a> { let obj = &self.object(obj_id.into()); if let Some(blueprint) = obj.blueprint() { by_size_end[blueprint.physical_size_bits()] += 1; - info!("obj size: {}", blueprint.physical_size_bits()); } } let mut acc = first_obj_without_paddr; @@ -241,11 +241,6 @@ impl<'a> Initializer<'a> { } } - info!("start end"); - for size in 0..sel4::WORD_SIZE { - info!("{} {}", by_size_start[size], by_size_end[size]); - } - // In order to allocate objects which specify paddrs, we may have to // allocate dummies to manipulate watermarks. We must always retain at // least one reference to an object allocated from an untyped, or else @@ -403,9 +398,7 @@ impl<'a> Initializer<'a> { // Create child objects - info!("DONE CREATING ROOT OBJECTS!"); for cover in self.spec.untyped_covers.iter() { - info!("CREATING UNTYPED COVER STUFF!"); let parent_obj_id = cover.parent; let parent = self.named_object(parent_obj_id); let parent_cptr = self.orig_cap::(parent_obj_id); @@ -532,36 +525,25 @@ impl<'a> Initializer<'a> { fn create_untyped_info(&mut self) -> Result<()> { // Sort untypeds by paddr - let mut _uts_by_paddr_backing: [usize; - sel4::sel4_cfg_usize!(MAX_NUM_BOOTINFO_UNTYPED_CAPS)] = array::from_fn(|i| i); // TODO (not a big deal) allocate in image rather than on stack - let uts = self.bootinfo.untyped_list(); - let uts_by_paddr = { - let arr = &mut _uts_by_paddr_backing[..uts.len()]; - arr.sort_unstable_by_key(|i| uts[*i].paddr()); - arr - }; + debug!("Create untyped info"); + // Check if a CNode (and memory region) marked for receiving untypeds exists, if so construct meta data on all // remaining untypeds, copy (or move?) the untypeds to the receiving CNode and pass the // meta data to the marked memory region. - let mut receiving_untypeds_cnode_id = None; - let mut root_cnode_id = None; - let mut receiving_untypeds_frame_id = None; - let mut receiving_untypeds_frame_obj = None; - let mut found = false; + let mut receiving_untypeds_cnode_id_opt = None; + let mut receiving_untypeds_cnode_obj_opt = None; + let mut receiving_untypeds_frame_id_opt = None; + let mut receiving_untypeds_frame_obj_opt = None; for (obj_id, obj) in self.filter_objects::() { if obj.receive_all_untypeds { - receiving_untypeds_cnode_id = Some(obj_id); - found = true; - } - if object_name(self.named_object(obj_id)).unwrap_or_else(||"").contains("_root") { - root_cnode_id = Some(obj_id); + receiving_untypeds_cnode_id_opt = Some(obj_id); + receiving_untypeds_cnode_obj_opt = Some(obj); } } - if !found { + if receiving_untypeds_cnode_id_opt.is_none() { debug!("No CNode found for receiving untyped objects"); return Ok(()); } - found = false; for (obj_id, obj) in self.filter_objects::>() { //if let Some(name) = object_name(self.named_object(obj_id)) { // XXX: FIX: modify memory regions to contain a better way of indicating it should @@ -569,40 +551,33 @@ impl<'a> Initializer<'a> { if object_name(self.named_object(obj_id)).unwrap_or_else(|| "").contains("remaining_untypeds") { // Get the first Frame of the memory region (if larger than a page, only get the // first page) - receiving_untypeds_frame_id = Some(obj_id); - receiving_untypeds_frame_obj = Some(obj); - found = true; + receiving_untypeds_frame_id_opt = Some(obj_id); + receiving_untypeds_frame_obj_opt = Some(obj); break; } } - if !found { + if receiving_untypeds_frame_id_opt.is_none() { panic!("CNode for receiving untyped objects found, but no matching Frame (Memory Region) found!"); } - info!("Found both CNode and Frame for receiving untypeds and their meta data"); + let receiving_untypeds_cnode_id = receiving_untypeds_cnode_id_opt.expect("Receiving untypeds CNode ID is None but got here"); + let receiving_untypeds_cnode_obj = receiving_untypeds_cnode_obj_opt.expect("Receiving untypeds CNode obj is None but got here"); + let receiving_untypeds_frame_id = receiving_untypeds_frame_id_opt.expect("Receiving untypeds Frame ID is None but got here"); + let receiving_untypeds_frame_obj = receiving_untypeds_frame_obj_opt.expect("Receiving untypeds Frame Obj is None but got here"); // Move all untypeds to the new CNode // TODO: move only CLEAN untypeds to the new CNode (watermark == 0). Also move the split // untypeds created when aligning objects to phys addr - // // TODO: fix hack for calculating CPtr idx: 1 << (kernel_config,cap_address_bits - - // root_cnode_size_bits) let mut untyped_cptr_slot = 1; - //let cap = self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")); // this is the initial Cap to the CNode that got created, with guardsize = 0, hence need to - // do some arithmetic with addressing - let untyped_cnode_cap_init = self.orig_cap::(receiving_untypeds_cnode_id.expect("Untypeds Cnode not found but got here")); - - for (ut_idx, ut) in uts.iter().enumerate() { - // TODO: extract size_bits from the capdl_spec for the root cnode and the receiving_untyped_cnode - info!("untyped cptr offset: {:x}", untyped_cptr_slot); - //let cnode_cap: CNode = self.orig_cslot((receiving_untypeds_cnode_id).into()).cap().into(); - let res = untyped_cnode_cap_init.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, 8).move_( + // use depth == sizeBits of the CNode + //let receiving_untyped_cnode_size_bits = self.named_object(receiving + let untyped_cnode_cptr_init = self.orig_cap::(receiving_untypeds_cnode_id); + + for (ut_idx, ut) in self.bootinfo.untyped_list().iter().enumerate() { + untyped_cnode_cptr_init.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, receiving_untypeds_cnode_obj.size_bits as usize).move_( &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE) - ); - match res { - Ok(()) => {}, - Err(e) => panic!("Failed to copy untypeds {}", e) - } - // XXX: add info on watermark? actually will probably need to discard dirty Untypeds + ).inspect_err(|e| panic!("Failed to copy untypeds {}", e)); + // XXX: add info on watermark? will need to discard dirty Untypeds // and only put here clean ones/split the dirty ones (and move here the splie ones) // XXX: should this be addressed with regards to untyped_cptr_slot and not ut_idx? // maybe reshape the untyped CNode so thye always live from idx 0 -> @@ -610,29 +585,13 @@ impl<'a> Initializer<'a> { self.capdl_bootinfo.untypedList[untyped_cptr_slot as usize] = ut.inner().clone(); untyped_cptr_slot += 1; - //cnode_cap = self.orig_cap::(root_cnode_id.expect("root Cnode not found but got here")); - //info!("root Cnode cap: {:?}", cnode_cap); - //info!("target slot Absolute CPtr: {:?}", cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE)); - // - //let res = cnode_cap.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, sel4::WORD_SIZE).copy( - // &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE), - // CapRights::all() - //); - //info!("Res: {:?}", res); - //break; } - // TODO: figure out how create_objects tracks untyped info - // TODO: move all "clean" untypeds after create_objects to new CNode - // TODO: move CNode to the root CNode slot in target PD's Cnode, save the idx to the passed - // on struct - // TODO: construct the struct (and array) containing all untyped info, put it inside the - // memory region marked ("remaining_untypeds" name? maybe mark in spec instead?) - + // TODO: mark memory region in capDL spec (rn matching by "remaining_untypeds" name?) // Fill the frame with the struct of untyped info let frame_object_type = - sel4::FrameObjectType::from_bits(receiving_untypeds_frame_obj.expect("Receiving untyped info Frame obj not found but got here").size_bits.into()).unwrap(); - let frame = self.orig_cap::(receiving_untypeds_frame_id.expect("Receiving untyped info Frame ID not found but got here")); + sel4::FrameObjectType::from_bits(receiving_untypeds_frame_obj.size_bits.into()).unwrap(); + let frame = self.orig_cap::(receiving_untypeds_frame_id); frame.frame_map( init_thread::slot::VSPACE.cap(), self.copy_addrs.select(frame_object_type), @@ -644,12 +603,8 @@ impl<'a> Initializer<'a> { let dst_frame = self.copy_addrs.select(frame_object_type) as *mut u8; let dst = unsafe { slice::from_raw_parts_mut(dst_frame, mem::size_of::()) }; - info!("capdl_bootinfo.untyped_cnode_cap: {:?}\n", self.capdl_bootinfo.untyped_cnode_cap); + info!("capdl_bootinfo.untyped_cnode_cptr: {:?}\n", self.capdl_bootinfo.untyped_cnode_cptr); dst.copy_from_slice(capdl_bootinfo_slice); - //pub fn copy_out(&self, dst: &mut [u8]) { - // dst.copy_from_slice(&self.bytes) - //} - frame.frame_unmap()?; Ok(()) } From ced578d6724d9ee7d96a4e17b00698be17f3c89f Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Mon, 9 Mar 2026 13:46:27 +1100 Subject: [PATCH 5/6] fix: change hardcoded value to extract capDL info * For PD that receives untypeds, compute index of the receiving untypeds CNode based on the guard size of its cap and the sizeBits of the CNode. Signed-off-by: Szymon Duchniewicz --- crates/sel4-capdl-initializer/src/initialize.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/crates/sel4-capdl-initializer/src/initialize.rs b/crates/sel4-capdl-initializer/src/initialize.rs index 70b5389d3..b29083607 100644 --- a/crates/sel4-capdl-initializer/src/initialize.rs +++ b/crates/sel4-capdl-initializer/src/initialize.rs @@ -81,7 +81,9 @@ impl<'a> Initializer<'a> { .unwrap(); let capdl_bootinfo = CapDLBootInfo { - untyped_cnode_cptr: sel4::Cap::::from_bits(1 << (64-6) as sel4::CPtrBits), + // This value gets set in create_untyped_info(), as it needs to extract root CNode + // sizebits from the capDL spec + untyped_cnode_cptr: sel4::Cap::::from_bits(0 as sel4::CPtrBits), // leave slot 0 empty (used as self-reference to the CNode itself) untypeds: SlotRegion::::from_range(1..bootinfo.untyped().len()+1), // XXX: maybe not clone it but initialise an empty array with default() trait? https://gist.github.com/ChrisWellsWood/84421854794037e760808d5d97d21421 @@ -524,7 +526,6 @@ impl<'a> Initializer<'a> { } fn create_untyped_info(&mut self) -> Result<()> { - // Sort untypeds by paddr debug!("Create untyped info"); // Check if a CNode (and memory region) marked for receiving untypeds exists, if so construct meta data on all @@ -538,6 +539,15 @@ impl<'a> Initializer<'a> { if obj.receive_all_untypeds { receiving_untypeds_cnode_id_opt = Some(obj_id); receiving_untypeds_cnode_obj_opt = Some(obj); + // root cnode is constructed with microkit_cnode at idx 0 and + // receiving_untypeds_cnode at idx 1. To extract index for it relative to + // root_cnode: + // receiving_untypeds_cnode at slot 0 has a reference to itself with + // guardSize = (WORD_SIZE - root_cnode.sizeBits - receiving_untypeds_cnode.sizeBits), + // receiving_untypeds_cnode idx in relation to root_cnode is therefore: + // 1 << (WORD_SIZE - (WORD_SIZE - guardSize - receiving_untypeds_cnode.sizeBits)) + let receiving_untypeds_cnode_cap_guard_size = obj.slots[0].cap.badge().expect("receiving_untypeds_cnode does not have a cap at slot 0 (expected a cap pointing to the CNode itself, with a proper guard set up)") as usize; + self.capdl_bootinfo.untyped_cnode_cptr = sel4::Cap::::from_bits(1 << (receiving_untypeds_cnode_cap_guard_size + obj.size_bits as usize) as sel4::CPtrBits); } } if receiving_untypeds_cnode_id_opt.is_none() { @@ -545,7 +555,6 @@ impl<'a> Initializer<'a> { return Ok(()); } for (obj_id, obj) in self.filter_objects::>() { - //if let Some(name) = object_name(self.named_object(obj_id)) { // XXX: FIX: modify memory regions to contain a better way of indicating it should // receive the untyped metadata if object_name(self.named_object(obj_id)).unwrap_or_else(|| "").contains("remaining_untypeds") { @@ -603,7 +612,7 @@ impl<'a> Initializer<'a> { let dst_frame = self.copy_addrs.select(frame_object_type) as *mut u8; let dst = unsafe { slice::from_raw_parts_mut(dst_frame, mem::size_of::()) }; - info!("capdl_bootinfo.untyped_cnode_cptr: {:?}\n", self.capdl_bootinfo.untyped_cnode_cptr); + debug!("capdl_bootinfo.untyped_cnode_cptr: {:?}\n", self.capdl_bootinfo.untyped_cnode_cptr); dst.copy_from_slice(capdl_bootinfo_slice); frame.frame_unmap()?; Ok(()) From b3ef6934a3fa42428041c5e79c014d211bbae0d9 Mon Sep 17 00:00:00 2001 From: Szymon Duchniewicz Date: Mon, 9 Mar 2026 15:34:23 +1100 Subject: [PATCH 6/6] Use capdl spec marking of Frame to receive untyped Signed-off-by: Szymon Duchniewicz --- crates/sel4-capdl-initializer/src/initialize.rs | 8 ++------ crates/sel4-capdl-initializer/types/src/spec.rs | 1 + crates/sel4-capdl-initializer/types/src/transform.rs | 1 + 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/sel4-capdl-initializer/src/initialize.rs b/crates/sel4-capdl-initializer/src/initialize.rs index b29083607..56f45779b 100644 --- a/crates/sel4-capdl-initializer/src/initialize.rs +++ b/crates/sel4-capdl-initializer/src/initialize.rs @@ -555,11 +555,7 @@ impl<'a> Initializer<'a> { return Ok(()); } for (obj_id, obj) in self.filter_objects::>() { - // XXX: FIX: modify memory regions to contain a better way of indicating it should - // receive the untyped metadata - if object_name(self.named_object(obj_id)).unwrap_or_else(|| "").contains("remaining_untypeds") { - // Get the first Frame of the memory region (if larger than a page, only get the - // first page) + if obj.receive_all_untypeds { receiving_untypeds_frame_id_opt = Some(obj_id); receiving_untypeds_frame_obj_opt = Some(obj); break; @@ -583,7 +579,7 @@ impl<'a> Initializer<'a> { let untyped_cnode_cptr_init = self.orig_cap::(receiving_untypeds_cnode_id); for (ut_idx, ut) in self.bootinfo.untyped_list().iter().enumerate() { - untyped_cnode_cptr_init.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, receiving_untypeds_cnode_obj.size_bits as usize).move_( + let _ = untyped_cnode_cptr_init.absolute_cptr_from_bits_with_depth(untyped_cptr_slot, receiving_untypeds_cnode_obj.size_bits as usize).move_( &init_thread::slot::CNODE.cap().absolute_cptr_from_bits_with_depth(self.ut_cap(ut_idx).bits(), sel4::WORD_SIZE) ).inspect_err(|e| panic!("Failed to copy untypeds {}", e)); // XXX: add info on watermark? will need to discard dirty Untypeds diff --git a/crates/sel4-capdl-initializer/types/src/spec.rs b/crates/sel4-capdl-initializer/types/src/spec.rs index 628a7a84d..f16e59675 100644 --- a/crates/sel4-capdl-initializer/types/src/spec.rs +++ b/crates/sel4-capdl-initializer/types/src/spec.rs @@ -427,6 +427,7 @@ pub mod object { pub size_bits: u8, pub paddr: Option, pub init: D, + pub receive_all_untypeds: bool, } #[derive(Debug, Clone, Eq, PartialEq, IsObject, HasCapTable)] diff --git a/crates/sel4-capdl-initializer/types/src/transform.rs b/crates/sel4-capdl-initializer/types/src/transform.rs index 1c7e8a2e6..97dcd3082 100644 --- a/crates/sel4-capdl-initializer/types/src/transform.rs +++ b/crates/sel4-capdl-initializer/types/src/transform.rs @@ -100,6 +100,7 @@ impl Spec { .contains(&obj_id); f(obj, is_root)? }, + receive_all_untypeds: obj.receive_all_untypeds, }), Object::PageTable(obj) => Object::PageTable(obj.clone()), Object::AsidPool(obj) => Object::AsidPool(obj.clone()),