Skip to content

Commit d83fa50

Browse files
tool: implement memory region data prefilling
Signed-off-by: Bill Nguyen <bill.nguyen@unsw.edu.au>
1 parent e846634 commit d83fa50

15 files changed

+345
-55
lines changed

tool/microkit/src/capdl/builder.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
capdl::{
2020
irq::create_irq_handler_cap,
2121
memory::{create_vspace, create_vspace_ept, map_page},
22-
spec::{capdl_obj_physical_size_bits, ElfContent},
22+
spec::{capdl_obj_physical_size_bits, BytesContent, ElfContent, FillContent},
2323
util::*,
2424
},
2525
elf::ElfFile,
@@ -104,7 +104,7 @@ const PD_SCHEDCONTEXT_EXTRA_SIZE_BITS: u64 = PD_SCHEDCONTEXT_EXTRA_SIZE.ilog2()
104104
pub const SLOT_BITS: u64 = 5;
105105
pub const SLOT_SIZE: u64 = 1 << SLOT_BITS;
106106

107-
pub type FrameFill = Fill<ElfContent>;
107+
pub type FrameFill = Fill<FillContent>;
108108
pub type CapDLNamedObject = NamedObject<FrameFill>;
109109

110110
pub struct ExpectedAllocation {
@@ -230,12 +230,12 @@ impl CapDLSpecContainer {
230230
start: dest_offset,
231231
end: dest_offset + len_to_cpy,
232232
},
233-
content: FillEntryContent::Data(ElfContent {
233+
content: FillEntryContent::Data(FillContent::ElfContent(ElfContent {
234234
elf_id,
235235
elf_seg_idx: seg_idx,
236236
elf_seg_data_range: (section_offset as usize
237237
..((section_offset + len_to_cpy) as usize)),
238-
}),
238+
})),
239239
});
240240
}
241241

@@ -510,11 +510,39 @@ pub fn build_capdl_spec(
510510
let paddr = mr
511511
.paddr()
512512
.map(|base_paddr| Word(base_paddr + (frame_sequence * mr.page_size_bytes())));
513+
514+
let frame_fill = if let Some(prefill_bytes) = &mr.prefill_bytes {
515+
let starting_byte_idx = frame_sequence * mr.page_size_bytes();
516+
let remaining_bytes_to_fill = prefill_bytes.len() as u64 - starting_byte_idx;
517+
let num_bytes_to_fill = min(mr.page_size_bytes(), remaining_bytes_to_fill);
518+
519+
let mut frame_bytes = vec![];
520+
frame_bytes.extend_from_slice(
521+
&prefill_bytes[starting_byte_idx as usize
522+
..(starting_byte_idx + num_bytes_to_fill) as usize],
523+
);
524+
525+
FrameFill {
526+
entries: [FillEntry {
527+
range: Range {
528+
start: 0,
529+
end: num_bytes_to_fill,
530+
},
531+
content: FillEntryContent::Data(FillContent::BytesContent(BytesContent {
532+
bytes: frame_bytes,
533+
})),
534+
}]
535+
.to_vec(),
536+
}
537+
} else {
538+
FrameFill {
539+
entries: [].to_vec(),
540+
}
541+
};
542+
513543
frame_ids.push(capdl_util_make_frame_obj(
514544
&mut spec_container,
515-
Fill {
516-
entries: [].to_vec(),
517-
},
545+
frame_fill,
518546
&format!("mr_{}_{:09}", mr.name, frame_sequence),
519547
paddr,
520548
frame_size_bits as u8,

tool/microkit/src/capdl/packaging.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//
66

77
use crate::{
8-
capdl::{initialiser::CapDLInitialiser, CapDLSpecContainer},
8+
capdl::{initialiser::CapDLInitialiser, spec::FillContent, CapDLSpecContainer},
99
elf::ElfFile,
1010
sel4::{Config, PageSize},
1111
};
@@ -23,10 +23,19 @@ pub fn pack_spec_into_initial_task(
2323
let (mut output_spec, embedded_frame_data_list) = spec_container.spec.embed_fill(
2424
PageSize::Small.fixed_size_bits(sel4_config) as u8,
2525
|_| embed_frames,
26-
|d, buf| {
27-
buf.copy_from_slice(
28-
&system_elfs[d.elf_id].segments[d.elf_seg_idx].data()[d.elf_seg_data_range.clone()],
29-
);
26+
|d, buf: &mut [u8]| {
27+
match d {
28+
FillContent::ElfContent(elf_content) => {
29+
buf.copy_from_slice(
30+
&system_elfs[elf_content.elf_id].segments[elf_content.elf_seg_idx].data()
31+
[elf_content.elf_seg_data_range.clone()],
32+
);
33+
}
34+
FillContent::BytesContent(bytes_content) => {
35+
buf.copy_from_slice(&bytes_content.bytes);
36+
}
37+
}
38+
3039
compress_frames
3140
},
3241
);

tool/microkit/src/capdl/spec.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ pub struct ElfContent {
2121
pub elf_seg_data_range: Range<usize>,
2222
}
2323

24+
#[derive(Clone, Serialize)]
25+
pub struct BytesContent {
26+
pub bytes: Vec<u8>,
27+
}
28+
29+
#[derive(Clone, Serialize)]
30+
pub enum FillContent {
31+
ElfContent(ElfContent),
32+
BytesContent(BytesContent),
33+
}
34+
2435
/// CNode and SchedContext are quirky as they have variable size.
2536
pub fn capdl_obj_physical_size_bits(obj: &Object<FrameFill>, sel4_config: &Config) -> u64 {
2637
match obj {

tool/microkit/src/main.rs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use microkit_tool::sel4::{
2323
};
2424
use microkit_tool::symbols::patch_symbols;
2525
use microkit_tool::util::{
26-
human_size_strict, json_str, json_str_as_bool, json_str_as_u64, round_down, round_up,
26+
get_full_path, human_size_strict, json_str, json_str_as_bool, json_str_as_u64, round_down,
27+
round_up,
2728
};
2829
use microkit_tool::{DisjointMemoryRegion, MemoryRegion};
2930
use std::collections::HashMap;
@@ -40,17 +41,6 @@ const KERNEL_COPY_FILENAME: &str = "sel4.elf";
4041
// also copy the 32-bit version that was prepared by build_sdk.py for convenience.
4142
const KERNEL32_COPY_FILENAME: &str = "sel4_32.elf";
4243

43-
fn get_full_path(path: &Path, search_paths: &Vec<PathBuf>) -> Option<PathBuf> {
44-
for search_path in search_paths {
45-
let full_path = search_path.join(path);
46-
if full_path.exists() {
47-
return Some(full_path.to_path_buf());
48-
}
49-
}
50-
51-
None
52-
}
53-
5444
fn print_usage() {
5545
println!("usage: microkit [-h] [-o OUTPUT] [--image-type {{binary,elf,uimage}}] [-r REPORT] --board BOARD --config CONFIG [--capdl-json CAPDL_SPEC] --search-path [SEARCH_PATH ...] system")
5646
}
@@ -560,7 +550,12 @@ fn main() -> Result<(), String> {
560550
"Microkit tool has various assumptions about the word size being 64-bits."
561551
);
562552

563-
let mut system = match parse(args.system, &xml, &kernel_config) {
553+
let mut search_paths = vec![std::env::current_dir().unwrap()];
554+
for path in args.search_paths {
555+
search_paths.push(PathBuf::from(path));
556+
}
557+
558+
let mut system = match parse(args.system, &xml, &kernel_config, &search_paths) {
564559
Ok(system) => system,
565560
Err(err) => {
566561
eprintln!("{err}");
@@ -617,11 +612,6 @@ fn main() -> Result<(), String> {
617612
std::process::exit(1);
618613
});
619614

620-
let mut search_paths = vec![std::env::current_dir().unwrap()];
621-
for path in args.search_paths {
622-
search_paths.push(PathBuf::from(path));
623-
}
624-
625615
// This list refers to all PD ELFs as well as the Monitor ELF.
626616
// The monitor is very similar to a PD so it is useful to pass around
627617
// a list like this.

tool/microkit/src/sdf.rs

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
use crate::sel4::{
2020
Arch, ArmRiscvIrqTrigger, Config, PageSize, X86IoapicIrqPolarity, X86IoapicIrqTrigger,
2121
};
22-
use crate::util::{ranges_overlap, str_to_bool};
22+
use crate::util::{get_full_path, ranges_overlap, round_up, str_to_bool};
2323
use crate::MAX_PDS;
2424
use std::collections::HashSet;
2525
use std::fmt::Display;
26+
use std::fs;
2627
use std::path::{Path, PathBuf};
2728

2829
/// Events that come through entry points (e.g notified or protected) are given an
@@ -125,6 +126,7 @@ pub struct SysMemoryRegion {
125126
/// due to the user's SDF or created by the tool for setting up the
126127
/// stack, ELF, etc.
127128
pub kind: SysMemoryRegionKind,
129+
pub prefill_bytes: Option<Vec<u8>>,
128130
}
129131

130132
impl SysMemoryRegion {
@@ -212,6 +214,7 @@ pub enum SysSetVarKind {
212214
Paddr { region: String },
213215
Id { id: u64 },
214216
X86IoPortAddr { address: u64 },
217+
PrefillSize { mr: String },
215218
}
216219

217220
#[derive(Debug, PartialEq, Eq)]
@@ -346,6 +349,7 @@ impl SysMap {
346349
if allow_setvar {
347350
attrs.push("setvar_vaddr");
348351
attrs.push("setvar_size");
352+
attrs.push("setvar_prefill_size");
349353
}
350354
check_attributes(xml_sdf, node, &attrs)?;
351355

@@ -646,6 +650,14 @@ impl ProtectionDomain {
646650
checked_add_setvar(&mut setvars, setvar, xml_sdf, &child)?;
647651
}
648652

653+
if let Some(setvar_prefill_size) = child.attribute("setvar_prefill_size") {
654+
let setvar = SysSetVar {
655+
symbol: setvar_prefill_size.to_string(),
656+
kind: SysSetVarKind::PrefillSize { mr: map.mr.clone() },
657+
};
658+
checked_add_setvar(&mut setvars, setvar, xml_sdf, &child)?;
659+
}
660+
649661
maps.push(map);
650662
}
651663
"irq" => {
@@ -1204,17 +1216,75 @@ impl VirtualMachine {
12041216
}
12051217

12061218
impl SysMemoryRegion {
1219+
fn determine_size(
1220+
xml_sdf: &XmlSystemDescription,
1221+
node: &roxmltree::Node,
1222+
prefill_bytes_maybe: &Option<Vec<u8>>,
1223+
page_size: u64,
1224+
) -> Result<u64, String> {
1225+
match checked_lookup(xml_sdf, node, "size") {
1226+
Ok(size_str) => {
1227+
// Size explicitly specified
1228+
let size_parsed = sdf_parse_number(size_str, node)?;
1229+
1230+
if !size_parsed.is_multiple_of(page_size) {
1231+
return Err(value_error(
1232+
xml_sdf,
1233+
node,
1234+
"size is not a multiple of the page size".to_string(),
1235+
));
1236+
}
1237+
1238+
match &prefill_bytes_maybe {
1239+
Some(bytes) => {
1240+
if bytes.len() > size_parsed as usize {
1241+
return Err(value_error(
1242+
xml_sdf,
1243+
node,
1244+
format!(
1245+
"size of prefill file exceeds memory region size: {:x} > {:x}",
1246+
bytes.len(),
1247+
size_parsed
1248+
),
1249+
));
1250+
}
1251+
1252+
Ok(size_parsed)
1253+
}
1254+
None => Ok(size_parsed),
1255+
}
1256+
}
1257+
1258+
Err(_) => {
1259+
// No size explicitly specified
1260+
match &prefill_bytes_maybe {
1261+
Some(bytes) => Ok(round_up(bytes.len() as u64, page_size)),
1262+
1263+
None => Err(value_error(
1264+
xml_sdf,
1265+
node,
1266+
"size must be specified if memory region is not prefilled".to_string(),
1267+
)),
1268+
}
1269+
}
1270+
}
1271+
}
1272+
12071273
fn from_xml(
12081274
config: &Config,
12091275
xml_sdf: &XmlSystemDescription,
12101276
node: &roxmltree::Node,
1277+
search_paths: &Vec<PathBuf>,
12111278
) -> Result<SysMemoryRegion, String> {
1212-
check_attributes(xml_sdf, node, &["name", "size", "page_size", "phys_addr"])?;
1279+
check_attributes(
1280+
xml_sdf,
1281+
node,
1282+
&["name", "size", "page_size", "phys_addr", "prefill_path"],
1283+
)?;
12131284

12141285
let name = checked_lookup(xml_sdf, node, "name")?;
1215-
let size = sdf_parse_number(checked_lookup(xml_sdf, node, "size")?, node)?;
1216-
let mut page_size_specified_by_user = false;
12171286

1287+
let mut page_size_specified_by_user = false;
12181288
let page_size = if let Some(xml_page_size) = node.attribute("page_size") {
12191289
page_size_specified_by_user = true;
12201290
sdf_parse_number(xml_page_size, node)?
@@ -1231,13 +1301,42 @@ impl SysMemoryRegion {
12311301
));
12321302
}
12331303

1234-
if !size.is_multiple_of(page_size) {
1235-
return Err(value_error(
1236-
xml_sdf,
1237-
node,
1238-
"size is not a multiple of the page size".to_string(),
1239-
));
1240-
}
1304+
let prefill_bytes_maybe = node
1305+
.attribute("prefill_path")
1306+
.map(|path_str| {
1307+
get_full_path(&PathBuf::from(path_str), search_paths)
1308+
.ok_or_else(|| {
1309+
value_error(
1310+
xml_sdf,
1311+
node,
1312+
format!("unable to find prefill file: '{path_str}'"),
1313+
)
1314+
})
1315+
.and_then(|prefill_path| {
1316+
fs::read(&prefill_path)
1317+
.map_err(|_| {
1318+
value_error(
1319+
xml_sdf,
1320+
node,
1321+
format!("failed to read file '{path_str}' at prefill_path"),
1322+
)
1323+
})
1324+
.and_then(|bytes| {
1325+
if bytes.is_empty() {
1326+
Err(value_error(
1327+
xml_sdf,
1328+
node,
1329+
format!("prefill file '{path_str}' is empty"),
1330+
))
1331+
} else {
1332+
Ok(bytes)
1333+
}
1334+
})
1335+
})
1336+
})
1337+
.transpose()?;
1338+
1339+
let size = Self::determine_size(xml_sdf, node, &prefill_bytes_maybe, page_size)?;
12411340

12421341
let phys_addr = if let Some(xml_phys_addr) = node.attribute("phys_addr") {
12431342
SysMemoryRegionPaddr::Specified(sdf_parse_number(xml_phys_addr, node)?)
@@ -1267,6 +1366,7 @@ impl SysMemoryRegion {
12671366
phys_addr,
12681367
text_pos: Some(xml_sdf.doc.text_pos_at(node.range().start)),
12691368
kind: SysMemoryRegionKind::User,
1369+
prefill_bytes: prefill_bytes_maybe,
12701370
})
12711371
}
12721372
}
@@ -1605,7 +1705,12 @@ fn pd_flatten(
16051705
Ok(all_pds)
16061706
}
16071707

1608-
pub fn parse(filename: &str, xml: &str, config: &Config) -> Result<SystemDescription, String> {
1708+
pub fn parse(
1709+
filename: &str,
1710+
xml: &str,
1711+
config: &Config,
1712+
search_paths: &Vec<PathBuf>,
1713+
) -> Result<SystemDescription, String> {
16091714
let doc = match roxmltree::Document::parse(xml) {
16101715
Ok(doc) => doc,
16111716
Err(err) => return Err(format!("Could not parse '{filename}': {err}")),
@@ -1645,7 +1750,12 @@ pub fn parse(filename: &str, xml: &str, config: &Config) -> Result<SystemDescrip
16451750
root_pds.push(ProtectionDomain::from_xml(config, &xml_sdf, &child, false)?)
16461751
}
16471752
"channel" => channel_nodes.push(child),
1648-
"memory_region" => mrs.push(SysMemoryRegion::from_xml(config, &xml_sdf, &child)?),
1753+
"memory_region" => mrs.push(SysMemoryRegion::from_xml(
1754+
config,
1755+
&xml_sdf,
1756+
&child,
1757+
search_paths,
1758+
)?),
16491759
"virtual_machine" => {
16501760
let pos = xml_sdf.doc.text_pos_at(child.range().start);
16511761
return Err(format!(

0 commit comments

Comments
 (0)