Skip to content

Add cnode tag#539

Draft
terryzbai wants to merge 5 commits into
seL4:mainfrom
au-ts:add-cnode-tag
Draft

Add cnode tag#539
terryzbai wants to merge 5 commits into
seL4:mainfrom
au-ts:add-cnode-tag

Conversation

@terryzbai

Copy link
Copy Markdown
Contributor

This PR adds CNode tag to SDF, providing a way for users to define custom CNodes and share among PDs. One of the use cases is to pass capabilities from one PD to another, e.g., ACPI driver passes CNode containing memory window untypeds to PCIe driver so it can dynamically allocate and map memory regions for device drivers.

This PR is based on switch-to-two-level-cnodes PR as it should be getting merged soon.

This adds a smaller CNode as PD's cspace and moves
the original Microkit resource CNode to the root's
first slot, as this makes the CSpace management more
flexible. The changes are:
- size of root CNode: 64
- size of Microkit CNode: 1024 -> 512
- guard size of root CNode: 0
- guard size of Microkit CNode: seL4_WordBits - 6 - 9

This also fixes the capability creation for shared
VSpace and CSpace.

Signed-off-by: Terry Bai <tianyi.bai@unsw.edu.au>
This adds rules for QEMU tests on x86 and enables the
'capdl_spec.json' file generation for analysis.

Signed-off-by: Terry Bai <tianyi.bai@unsw.edu.au>
This checks if people try to place extra caps in slot 0,
which is reserved for Microkit CNode, and adds a test
case for it.

Signed-off-by: Terry Bai <tianyi.bai@unsw.edu.au>
This adds 'cnode' tag in SDF, providing a way for users to
define custom-sized CNodes to be shared among PDs. One
typical use case is to pass capabilities from one PD to
another.

Custom CNodes can be mapped into PDs via 'cap_cspace' with
target 'cnode_name' specified, and other CapMapType fails with
'cnode_name' specified.

Signed-off-by: Terry Bai <tianyi.bai@unsw.edu.au>
This adds a few test cases for checking if invalid
cnode tags or cspace mapping fails as expected.

Signed-off-by: Terry Bai <tianyi.bai@unsw.edu.au>
named_object.name.as_ref().unwrap()
);
};
if let Some(src_pd) = cap_map.pd {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is assignment within if-check, that's extremely confusing.

I would either make temp vars outside the if-checks, or don't bother with them. cap_map.pd and cap_map.cnode are short and clear enough.

capdl_util_make_cnode_cap(pd_src_shadow_cspace.cspace, 0, guard_size)
}
};
} else if let Some(src_cnode) = cap_map.cnode {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes no logical sense that this would be an else-if instead of an if, as you're checking different fields. From a higher level it of course makes perfect sense, as they are mutually exclusive.

However, as you already wrap them in an Option, would it make more sense in Rust to have one shared src field of different types and do a switch on type instead?

Comment on lines +586 to +587
let pd_guard_size = kernel_config.cap_address_bits - cnode.size_bits as u64 - PD_ROOT_CAP_BITS as u64;
let cnode_cap_self_ref = capdl_util_make_cnode_cap(cnode_obj_id, 0, pd_guard_size.try_into().unwrap());

@Indanz Indanz Jun 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below it does it without the weird try_into/unwrap combo. Maybe use as u8 above like is done below?

Perhaps add something like an capdl_util_make_sub_cnode_cap() function and add that to capdl util? Then you can call that everywhere and keep this code in one place.

Edit: I realised that capdl util probably doesn't know about kernel_config.cap_address_bits and PD_ROOT_CAP_BITS, so it can't be there and must be a less generic, more local make_sub_cnode_cap().

Comment on lines +1240 to +1241
let pd_guard_size = kernel_config.cap_address_bits - *size_bits as u64 - PD_ROOT_CAP_BITS as u64;
let cnode_cap = capdl_util_make_cnode_cap(*cnode_obj_id, 0, pd_guard_size.try_into().unwrap());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe replace with a capdl_util_make_sub_cnode_cap() call here too.

However, I'm not sure you want to do this unconditionally, because the user may want to manage a 2-level sub-CSpace themselves. Gobbling all remaining bits up as guard would make this impossible.

I agree that this should be the default behaviour, but I think that it should also be possible for users to specify the guard size (and perhaps value) manually.

So the the guard size would be cap_address_bits - PD_ROOT_CAP_BITS - size_bits - user_guard_size, where the latter is default 0 and the result must be >= 0.

If adding capdl_util_make_sub_cnode_cap(), you would call it with size_bits + user_guard_size instead of just size_bits.

Comment thread tool/microkit/src/sdf.rs
return Err(value_error(
xml_sdf,
node,
format!("invalid paramter 'cnode_name' for target CapMapType"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: paramter.

Comment thread tool/microkit/src/sdf.rs
return Err(value_error(
xml_sdf,
node,
format!("Either 'pd' and 'cnode_name' should be specified"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See, that's why I prefer a generic src instead of one attribute per source type. What you're doing here doesn't scale very well, and it has unclear semantics by design, making things harder for the user instead of easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants