1919use 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} ;
2323use crate :: MAX_PDS ;
2424use std:: collections:: HashSet ;
2525use std:: fmt:: Display ;
26+ use std:: fs;
2627use 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
130132impl 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
12061218impl 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