Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions tool/microkit/src/sdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,33 @@ impl SysMapPerms {
}

impl SysMap {
pub fn new(
mr: String,
vaddr: u64,
perms: Option<u8>,
cached: Option<bool>,
max_vaddr: u64,
) -> Result<SysMap, String> {
if vaddr >= max_vaddr {
return Err(format!(
"vaddr (0x{vaddr:x}) must be less than 0x{max_vaddr:x}"
));
}
let perms: u8 = perms.unwrap_or(SysMapPerms::Read as u8 | SysMapPerms::Write as u8);
if perms == SysMapPerms::Write as u8 {
return Err("perms must not be 'w', write-only mappings are not allowed".to_string());
}

let cached: bool = cached.unwrap_or(true);
Ok(SysMap {
mr,
vaddr,
perms,
cached,
text_pos: None,
})
}

fn from_xml(
xml_sdf: &XmlSystemDescription,
node: &roxmltree::Node,
Expand Down Expand Up @@ -494,6 +521,131 @@ impl ProtectionDomain {
ioports
}

pub fn new(
config: &Config,
id: Option<u64>,
name: String,
priority: Option<u8>,
budget: Option<u64>,
period: Option<u64>,
passive: Option<bool>,
stack_size: Option<u64>,
smc: Option<bool>,
cpu: Option<u8>,
program_image: PathBuf,
program_image_for_symbols: Option<PathBuf>,
fpu: Option<bool>,
maps: Vec<SysMap>,
irqs: Vec<SysIrq>,
ioports: Vec<IOPort>,
mut setvars: Vec<SysSetVar>,
cap_maps: Vec<CapMap>,
virtual_machine: Option<VirtualMachine>,
child_pds: Vec<ProtectionDomain>,
parent: Option<usize>,
setvar_id: Option<String>,
) -> Result<ProtectionDomain, String> {
let priority = priority.unwrap_or(0);

if priority > PD_MAX_PRIORITY {
return Err(format!("priority must be between 0 and {PD_MAX_PRIORITY}"));
}
let budget = budget.unwrap_or(BUDGET_DEFAULT);
let period = period.unwrap_or(budget);
if budget > period {
return Err(format!(
"budget ({budget}) must be less than, or equal to, period ({period})"
));
}
let passive = passive.unwrap_or(false);
let stack_size = stack_size.unwrap_or(PD_DEFAULT_STACK_SIZE);

#[allow(clippy::manual_range_contains)]
if stack_size < PD_MIN_STACK_SIZE || stack_size > PD_MAX_STACK_SIZE {
return Err(
format!(
"stack size must be between 0x{PD_MIN_STACK_SIZE:x} bytes and 0x{PD_MAX_STACK_SIZE:x} bytes"
),
);
}

if !stack_size.is_multiple_of(config.page_sizes()[0]) {
return Err(format!(
"stack size must be aligned to the smallest page size, {} bytes",
config.page_sizes()[0]
));
}
let smc = smc.unwrap_or(false);
if smc {
match config.arm_smc {
Some(smc_allowed) => {
if !smc_allowed {
return Err("Using SMC support without ARM SMC forwarding support enabled in the kernel for this platform".to_string());
}
}
None => {
return Err(
"ARM SMC forwarding support is not available for this architecture"
.to_string(),
)
}
}
}
let cpu = CpuCore(cpu.unwrap_or(0));
if cpu.0 >= config.num_cores {
return Err(format!(
"cpu core must be less than {}, got {}",
config.num_cores, cpu.0
));
}
let fpu = fpu.unwrap_or(true);

// Check that the protection domain is a child before allowing setvar_id to be set.
let setvar_id = if id.is_some() { setvar_id } else { None };

let has_children: bool = child_pds.is_empty();
for child in &child_pds {
if child.id.is_none() {
return Err("child pds must have an id".to_string());
}
if let Some(setvar) = &child.setvar_id {
let setvar = SysSetVar {
symbol: setvar.to_string(),
kind: SysSetVarKind::Id {
id: child.id.unwrap(),
},
};
setvars.push(setvar);
}
}

Ok(ProtectionDomain {
id,
name,
priority,
budget,
period,
passive,
stack_size,
smc,
cpu,
program_image,
program_image_for_symbols,
fpu,
maps,
irqs,
ioports,
setvars,
cap_maps,
virtual_machine,
child_pds,
has_children,
parent,
setvar_id,
text_pos: None,
})
}

fn from_xml(
config: &Config,
xml_sdf: &XmlSystemDescription,
Expand Down Expand Up @@ -1482,6 +1634,72 @@ impl SysMemoryRegion {
}
}

pub fn new(
config: &Config,
name: String,
size: u64,
page_size: Option<u64>,
phys_addr: Option<u64>,
kind: SysMemoryRegionKind,
prefill_path: Option<&str>,
search_paths: &Vec<PathBuf>,
) -> Result<SysMemoryRegion, String> {
let mut page_size_specified_by_user = true;
let page_size = page_size.unwrap_or_else(|| {
page_size_specified_by_user = false;
config.page_sizes()[0]
});

let page_size_valid = config.page_sizes().contains(&page_size);
if !page_size_valid {
return Err(format!("page size 0x{page_size:x} not supported"));
}
let prefill_bytes = prefill_path
.map(|path_str| {
get_full_path(&PathBuf::from(path_str), search_paths)
.ok_or_else(|| format!("unable to find prefill file: '{path_str}'"))
.and_then(|prefill_path| {
fs::read(&prefill_path)
.map_err(|_| {
format!("failed to read file '{path_str}' at prefill_path")
})
.and_then(|bytes| {
if bytes.is_empty() {
Err(format!("prefill file '{path_str}' is empty"))
} else {
Ok(bytes)
}
})
})
})
.transpose()?;

let phys_addr = if let Some(paddr) = phys_addr {
SysMemoryRegionPaddr::Specified(paddr)
} else {
// At this point it is unsure whether this MR is a subject of a setvar region_paddr.
SysMemoryRegionPaddr::Unspecified
};

if let SysMemoryRegionPaddr::Specified(sdf_paddr) = phys_addr {
if !sdf_paddr.is_multiple_of(page_size) {
return Err("phys_addr is not aligned to the page size".to_string());
}
}
let page_count = size / page_size;
Ok(SysMemoryRegion {
name,
size,
page_size_specified_by_user,
page_size: page_size.into(),
page_count,
phys_addr,
text_pos: None,
kind,
prefill_bytes,
})
}

fn from_xml(
config: &Config,
xml_sdf: &XmlSystemDescription,
Expand Down Expand Up @@ -1584,6 +1802,33 @@ impl SysMemoryRegion {
}

impl ChannelEnd {
pub fn new(
pd_name: String,
id: u64,
notify: Option<bool>,
pp: Option<bool>,
setvar_id: Option<String>,
pds: &[ProtectionDomain],
) -> Result<ChannelEnd, String> {
if id > PD_MAX_ID {
return Err(format!("id must be < {}", PD_MAX_ID + 1));
}
let notify = notify.unwrap_or(true);
let pp = pp.unwrap_or(false);

if let Some(pd_idx) = pds.iter().position(|pd| pd.name == pd_name) {
Ok(ChannelEnd {
pd: pd_idx,
id,
notify,
pp,
setvar_id,
})
} else {
Err(format!("invalid PD name '{pd_name}'"))
}
}

fn from_xml<'a>(
xml_sdf: &'a XmlSystemDescription,
node: &'a roxmltree::Node,
Expand Down Expand Up @@ -1655,6 +1900,14 @@ impl ChannelEnd {
}

impl Channel {
pub fn new(end_a: ChannelEnd, end_b: ChannelEnd) -> Result<Channel, String> {
if end_a.pp && end_b.pp {
return Err("cannot ppc bidirectionally".to_string());
}

Ok(Channel { end_a, end_b })
}

/// It should be noted that this function assumes that `pds` is populated
/// with all the Protection Domains that could potentially be connected with
/// the channel.
Expand Down