Skip to content

Commit b1eda39

Browse files
committed
CapMap: Remove the root cnode upper bound
This commit determines the size of the root cnode based upon the largest slot number that is specified in the sdf. Signed-off-by: Callum <c.berry@student.unsw.edu.au>
1 parent 8b6f6d4 commit b1eda39

8 files changed

Lines changed: 60 additions & 38 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/manual.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,8 @@ Stop the PD from switching to guest execution mode when a Microkit entrypoint re
959959
Converts the slot identifier of the `<cspace>`'s capability element into an
960960
`seL4_CPtr` value to be used in `libsel4` calls by the PD.
961961

962-
If the slot exceeds the valid range of inputs (`0 <= slot < MICROKIT_MAX_USER_CAPS`), it returns the value `seL4_CapNull`.
962+
If the slot is not in the valid range of inputs (`0 < slot < microkit_root_cnode_size_bits`), it returns the value `seL4_CapNull`.
963+
The value of `microkit_root_cnode_size_bits` is determined based on the largest slot specified in the `<cspace>`.
963964

964965
# System Description File {#sysdesc}
965966

libmicrokit/include/microkit.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ typedef seL4_MessageInfo_t microkit_msginfo;
3333
#define BASE_IOPORT_CAP 394
3434
#define BASE_USER_CAPS 458
3535

36-
/* This should be kept in sync with `PD_ROOT_CAP_BITS` in capdl/builder.rs */
37-
#define PD_ROOT_CAP_BITS 6
38-
#define PD_ROOT_CAP_SIZE (1ULL << PD_ROOT_CAP_BITS)
39-
4036
#define MICROKIT_MAX_USER_CAPS 128
4137
#define MICROKIT_MAX_CHANNELS 62
4238
#define MICROKIT_MAX_CHANNEL_ID (MICROKIT_MAX_CHANNELS - 1)
@@ -70,6 +66,7 @@ extern seL4_Word microkit_irqs;
7066
extern seL4_Word microkit_notifications;
7167
extern seL4_Word microkit_pps;
7268
extern seL4_Word microkit_ioports;
69+
extern seL4_Word microkit_root_cnode_size_bits;
7370

7471
/*
7572
* Output a single character on the debug console.
@@ -607,14 +604,14 @@ static inline void microkit_deferred_irq_ack(microkit_channel ch)
607604
* Convert the "slot" identifier from the system file for the extra user caps
608605
* <cspace> element into the seL4_CPtr at runtime.
609606
*
610-
* If the slot exceeds the valid range of inputs (0 <= slot < MICROKIT_MAX_USER_CAPS),
607+
* If the slot is not in the valid range of inputs (0 < slot < microkit_root_cnode_size_bits),
611608
* it returns the value `seL4_CapNull`.
612609
**/
613610
static inline seL4_CPtr microkit_cspace_root_slot_to_cptr(seL4_Word slot)
614611
{
615-
if (slot == 0 || slot >= PD_ROOT_CAP_SIZE) {
612+
if (slot == 0 || slot >= (1ULL << microkit_root_cnode_size_bits)) {
616613
return seL4_CapNull;
617614
}
618615

619-
return slot << (seL4_WordBits - PD_ROOT_CAP_BITS);
616+
return slot << (seL4_WordBits - microkit_root_cnode_size_bits);
620617
}

libmicrokit/src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ seL4_Word microkit_irqs;
3838
seL4_Word microkit_notifications;
3939
seL4_Word microkit_pps;
4040
seL4_Word microkit_ioports;
41+
seL4_Word microkit_root_cnode_size_bits;
4142

4243
#define BIT(n) (1ULL << (n))
4344
#define MASK(n) (BIT(n) - 1ULL)

tool/microkit/src/capdl/builder.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,6 @@ const PD_BASE_VM_TCB_CAP: u64 = PD_BASE_PD_TCB_CAP + 64;
9393
const PD_BASE_VCPU_CAP: u64 = PD_BASE_VM_TCB_CAP + 64;
9494
const PD_BASE_IOPORT_CAP: u64 = PD_BASE_VCPU_CAP + 64;
9595

96-
/* This should be kept in sync with `PD_ROOT_CAP_BITS` in libmicrokit/include/microkit.h */
97-
const PD_ROOT_CAP_SIZE: u32 = 64;
98-
const PD_ROOT_CAP_BITS: u8 = PD_ROOT_CAP_SIZE.ilog2() as u8;
9996
pub const PD_CAP_SIZE: u32 = 512;
10097
const PD_CAP_BITS: u8 = PD_CAP_SIZE.ilog2() as u8;
10198
const PD_SCHEDCONTEXT_EXTRA_SIZE: u64 = 256;
@@ -1065,14 +1062,20 @@ pub fn build_capdl_spec(
10651062
PD_CAP_BITS,
10661063
caps_to_insert_to_pd_cspace,
10671064
);
1065+
1066+
let root_cnode_size_bits = match &pd.cspace {
1067+
Some(cspace) => cspace.size_bits,
1068+
None => 1,
1069+
} as u8;
1070+
10681071
let pd_guard_size =
1069-
kernel_config.cap_address_bits - PD_CAP_BITS as u64 - PD_ROOT_CAP_BITS as u64;
1072+
kernel_config.cap_address_bits - PD_CAP_BITS as u64 - root_cnode_size_bits as u64;
10701073
let pd_cnode_cap = capdl_util_make_cnode_cap(pd_cnode_obj_id, 0, pd_guard_size as u8);
10711074

10721075
let pd_root_cnode_obj_id = capdl_util_make_cnode_obj(
10731076
&mut spec_container,
10741077
&(pd.name.clone() + "_root"),
1075-
PD_ROOT_CAP_BITS,
1078+
root_cnode_size_bits,
10761079
Vec::new(),
10771080
);
10781081
// leave the guard size root cnode as 0
@@ -1256,7 +1259,8 @@ pub fn build_capdl_spec(
12561259
// Step 6. Handle extra cap mappings
12571260
// *********************************
12581261
for (pd_dest_idx, pd) in system.protection_domains.iter().enumerate() {
1259-
for cap_map in pd.cap_maps.iter() {
1262+
let Some(cspace) = &pd.cspace else { continue };
1263+
for cap_map in cspace.cap_maps.iter() {
12601264
// TODO: Once we add more CapMap options, they might not all have
12611265
// the pd_name. But for now, they do.
12621266
let pd_src_shadow_cspace = &pd_shadow_cspaces[&cap_map.pd.unwrap()];

tool/microkit/src/sdf.rs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::sel4::{
2020
Arch, ArmRiscvIrqTrigger, Config, PageSize, X86IoapicIrqPolarity, X86IoapicIrqTrigger,
2121
};
2222

23-
use crate::util::{get_full_path, ranges_overlap, round_up, str_to_bool};
23+
use crate::util::{calculate_size_bits, get_full_path, ranges_overlap, round_up, str_to_bool};
2424
use crate::MAX_PDS;
2525
use sel4_capdl_initializer_types::{
2626
object, x86_io_address_space, DomainSchedDuration, DomainSchedEntry, FillEntryContentBootInfoId,
@@ -45,10 +45,6 @@ use std::str::FromStr;
4545
const PD_MAX_ID: u64 = 61;
4646
const VCPU_MAX_ID: u64 = PD_MAX_ID;
4747

48-
/// This is the maximum slot allowed for cap maps. This can change if you wish,
49-
/// but also update the MICROKIT_MAX_USER_CAPS define in `microkit.h`.
50-
const CAP_MAP_MAX_SLOT: u64 = 128;
51-
5248
pub const MONITOR_PRIORITY: u8 = 255;
5349
const PD_MAX_PRIORITY: u8 = 254;
5450
/// In microseconds
@@ -613,7 +609,7 @@ pub struct ProtectionDomain {
613609
pub irqs: Vec<SysIrq>,
614610
pub ioports: Vec<IOPort>,
615611
pub setvars: Vec<SysSetVar>,
616-
pub cap_maps: Vec<CapMap>,
612+
pub cspace: Option<CSpace>,
617613
pub virtual_machine: Option<VirtualMachine>,
618614
/// Only used when parsing child PDs. All elements will be removed
619615
/// once we flatten each PD and its children into one list.
@@ -655,9 +651,10 @@ pub struct CapMap {
655651
text_pos: roxmltree::TextPos,
656652
}
657653

658-
#[derive(Debug)]
654+
#[derive(Debug, PartialEq, Eq)]
659655
pub struct CSpace {
660-
cap_maps: Vec<CapMap>,
656+
pub cap_maps: Vec<CapMap>,
657+
pub size_bits: u64,
661658
}
662659

663660
#[derive(Debug, PartialEq, Eq)]
@@ -1604,7 +1601,7 @@ impl ProtectionDomain {
16041601
irqs,
16051602
ioports,
16061603
setvars,
1607-
cap_maps: cspace.map(|cspace| cspace.cap_maps).unwrap_or_default(),
1604+
cspace,
16081605
child_pds,
16091606
virtual_machine,
16101607
has_children,
@@ -1781,15 +1778,6 @@ impl CapMap {
17811778
));
17821779
}
17831780

1784-
// TODO: Rework this so that we don't have a fixed upper limit.
1785-
if slot >= CAP_MAP_MAX_SLOT {
1786-
return Err(value_error(
1787-
xml_sdf,
1788-
node,
1789-
format!("There are only {CAP_MAP_MAX_SLOT} destination cspace slots available."),
1790-
));
1791-
}
1792-
17931781
Ok(CapMap {
17941782
cap_type,
17951783
pd_name,
@@ -1823,7 +1811,17 @@ impl CSpace {
18231811
})
18241812
}
18251813

1826-
Ok(CSpace { cap_maps })
1814+
// Default to 1, the minimum allowed by the kernel.
1815+
let size_bits = cap_maps
1816+
.iter()
1817+
.map(|cap_map| calculate_size_bits(cap_map.slot + 1))
1818+
.max()
1819+
.unwrap_or(1) as u64;
1820+
1821+
Ok(CSpace {
1822+
cap_maps,
1823+
size_bits,
1824+
})
18271825
}
18281826
}
18291827

@@ -2873,8 +2871,8 @@ pub fn parse(
28732871
.enumerate()
28742872
.map(|(idx, pd)| (pd.name.clone(), idx))
28752873
.collect();
2876-
for pd in pds.iter_mut() {
2877-
for cap_map in pd.cap_maps.iter_mut() {
2874+
for cspace in pds.iter_mut().filter_map(|pd| pd.cspace.as_mut()) {
2875+
for cap_map in cspace.cap_maps.iter_mut() {
28782876
let Some(&pd) = pd_names_to_id.get(&cap_map.pd_name) else {
28792877
return Err(format!(
28802878
"Error: unknown PD name '{}': {}",
@@ -3128,9 +3126,10 @@ pub fn parse(
31283126
// Ensure that there are no overlapping extra cap maps in the user caps region
31293127
// and we are not mapping in the same cap from the same source more than once
31303128
for pd in &pds {
3129+
let Some(cspace) = &pd.cspace else { continue };
31313130
let mut user_cap_slots = HashMap::<u64, Vec<_>>::new();
31323131

3133-
for cap_map in &pd.cap_maps {
3132+
for cap_map in &cspace.cap_maps {
31343133
user_cap_slots
31353134
.entry(cap_map.slot)
31363135
.and_modify(|v| v.push(cap_map))

tool/microkit/src/symbols.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ pub fn patch_symbols(
135135
.write_symbol("microkit_ioports", &pd.ioport_bits().to_le_bytes())
136136
.unwrap();
137137

138+
elf_obj
139+
.write_symbol(
140+
"microkit_root_cnode_size_bits",
141+
&pd.cspace
142+
.as_ref()
143+
.map_or(0u64, |cspace| cspace.size_bits)
144+
.to_le_bytes(),
145+
)
146+
.unwrap();
147+
138148
let mut symbols_to_write: Vec<(&String, u64)> = Vec::new();
139149
for setvar in pd.setvars.iter() {
140150
// Check that the symbol exists in the ELF

tool/microkit/src/util.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ pub fn ranges_overlap<T: PartialOrd>(left: &Range<T>, right: &Range<T>) -> bool
7373
!(left.end <= right.start || right.end <= left.start)
7474
}
7575

76+
/// Returns the number of bits required to repr the input
77+
pub fn calculate_size_bits<T: Into<u64>>(size: T) -> u8 {
78+
let size: u64 = size.into();
79+
if size <= 1 {
80+
0
81+
} else {
82+
(size - 1).ilog2() as u8 + 1
83+
}
84+
}
85+
7686
/// Product a 'human readable' string for the size.
7787
///
7888
/// 'strict' means that it must be simply represented.

0 commit comments

Comments
 (0)