From 766bf3328532c6fd06763c6aa7697afeb08fba49 Mon Sep 17 00:00:00 2001 From: Alwin Joshy Date: Thu, 20 Feb 2025 14:44:32 +1100 Subject: [PATCH 01/18] tool: give vspace caps of child nodes to parent Signed-off-by: Alwin Joshy --- libmicrokit/include/microkit.h | 5 +++-- tool/microkit/src/main.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/libmicrokit/include/microkit.h b/libmicrokit/include/microkit.h index 75b72196d..89090cac1 100644 --- a/libmicrokit/include/microkit.h +++ b/libmicrokit/include/microkit.h @@ -24,8 +24,9 @@ typedef seL4_MessageInfo_t microkit_msginfo; #define BASE_ENDPOINT_CAP 74 #define BASE_IRQ_CAP 138 #define BASE_TCB_CAP 202 -#define BASE_VM_TCB_CAP 266 -#define BASE_VCPU_CAP 330 +#define BASE_VSPACE_CAP 266 +#define BASE_VM_TCB_CAP 330 +#define BASE_VCPU_CAP 394 #define MICROKIT_MAX_CHANNELS 62 #define MICROKIT_MAX_CHANNEL_ID (MICROKIT_MAX_CHANNELS - 1) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 985bba8b3..97058fe93 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -54,7 +54,8 @@ const BASE_OUTPUT_NOTIFICATION_CAP: u64 = 10; const BASE_OUTPUT_ENDPOINT_CAP: u64 = BASE_OUTPUT_NOTIFICATION_CAP + 64; const BASE_IRQ_CAP: u64 = BASE_OUTPUT_ENDPOINT_CAP + 64; const BASE_PD_TCB_CAP: u64 = BASE_IRQ_CAP + 64; -const BASE_VM_TCB_CAP: u64 = BASE_PD_TCB_CAP + 64; +const BASE_PD_VSPACE_CAP: u64 = BASE_PD_TCB_CAP + 64; +const BASE_VM_TCB_CAP: u64 = BASE_PD_VSPACE_CAP + 64; const BASE_VCPU_CAP: u64 = BASE_VM_TCB_CAP + 64; const MAX_SYSTEM_INVOCATION_SIZE: u64 = util::mb(128); @@ -2211,6 +2212,33 @@ fn build_system( } } + // Mint access to the child VSpace in the CSpace of root PDs + for (pd_idx, _) in system.protection_domains.iter().enumerate() { + for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { + // Check if we are dealing with a child PD + if let Some(parent_idx) = maybe_child_pd.parent { + // Check that the current PD is the parent of the child + if parent_idx == pd_idx { + let cap_idx = BASE_PD_VSPACE_CAP + maybe_child_pd.id.unwrap(); + assert!(cap_idx < PD_CAP_SIZE); + system_invocations.push(Invocation::new( + config, + InvocationArgs::CnodeMint { + cnode: cnode_objs[pd_idx].cap_addr, + dest_index: cap_idx, + dest_depth: PD_CAP_BITS, + src_root: root_cnode_cap, + src_obj: vspace_objs[maybe_child_idx].cap_addr, + src_depth: config.cap_address_bits, + rights: Rights::All as u64, + badge: 0 + } + )) + } + } + } + } + // Mint access to virtual machine TCBs in the CSpace of parent PDs for (pd_idx, pd) in system.protection_domains.iter().enumerate() { if let Some(vm) = &pd.virtual_machine { From cbb8cc63b2bdafa7c4101f9fff86efcb952c2be8 Mon Sep 17 00:00:00 2001 From: Alwin Joshy Date: Thu, 20 Feb 2025 15:01:01 +1100 Subject: [PATCH 02/18] tool: add more generic microkit_config field Signed-off-by: Alwin Joshy --- tool/microkit/src/main.rs | 12 ++++++------ tool/microkit/src/sel4.rs | 20 +++++++++++++++++++- tool/microkit/tests/test.rs | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 97058fe93..45cd6193e 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -20,8 +20,8 @@ use sdf::{ }; use sel4::{ default_vm_attr, Aarch64Regs, Arch, ArmVmAttributes, BootInfo, Config, Invocation, - InvocationArgs, Object, ObjectType, PageSize, PlatformConfig, Rights, Riscv64Regs, - RiscvVirtualMemory, RiscvVmAttributes, + InvocationArgs, MicrokitConfig, Object, ObjectType, PageSize, PlatformConfig, Rights, + Riscv64Regs, RiscvVirtualMemory, RiscvVmAttributes, }; use std::cmp::{max, min}; use std::collections::{HashMap, HashSet}; @@ -2231,8 +2231,8 @@ fn build_system( src_obj: vspace_objs[maybe_child_idx].cap_addr, src_depth: config.cap_address_bits, rights: Rights::All as u64, - badge: 0 - } + badge: 0, + }, )) } } @@ -2587,7 +2587,7 @@ fn build_system( // In the benchmark configuration, we allow PDs to access their own TCB. // This is necessary for accessing kernel's benchmark API. - if config.benchmark { + if config.microkit_config == MicrokitConfig::Benchmark { let mut tcb_cap_copy_invocation = Invocation::new( config, InvocationArgs::CnodeCopy { @@ -3302,7 +3302,7 @@ fn main() -> Result<(), String> { cap_address_bits: 64, fan_out_limit: json_str_as_u64(&kernel_config_json, "RETYPE_FAN_OUT_LIMIT")?, hypervisor, - benchmark: args.config == "benchmark", + microkit_config: MicrokitConfig::from_str(args.config), fpu: json_str_as_bool(&kernel_config_json, "HAVE_FPU")?, arm_pa_size_bits, arm_smc, diff --git a/tool/microkit/src/sel4.rs b/tool/microkit/src/sel4.rs index 8184c2c23..78ad6135e 100644 --- a/tool/microkit/src/sel4.rs +++ b/tool/microkit/src/sel4.rs @@ -31,6 +31,24 @@ pub struct PlatformConfig { pub memory: Vec, } +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum MicrokitConfig { + Debug, + Benchmark, + Release, +} + +impl MicrokitConfig { + pub fn from_str(string: &str) -> Self { + match string { + "debug" => MicrokitConfig::Debug, + "release" => MicrokitConfig::Release, + "benchmark" => MicrokitConfig::Benchmark, + _ => panic!("Invalid microkit configuration provided!"), + } + } +} + /// Represents an allocated kernel object. /// /// Kernel objects can have multiple caps (and caps can have multiple addresses). @@ -59,7 +77,7 @@ pub struct Config { pub cap_address_bits: u64, pub fan_out_limit: u64, pub hypervisor: bool, - pub benchmark: bool, + pub microkit_config: MicrokitConfig, pub fpu: bool, /// ARM-specific, number of physical address bits pub arm_pa_size_bits: Option, diff --git a/tool/microkit/tests/test.rs b/tool/microkit/tests/test.rs index 24be4fb17..be728dd59 100644 --- a/tool/microkit/tests/test.rs +++ b/tool/microkit/tests/test.rs @@ -17,7 +17,7 @@ const DEFAULT_KERNEL_CONFIG: sel4::Config = sel4::Config { cap_address_bits: 64, fan_out_limit: 256, hypervisor: true, - benchmark: false, + microkit_config: sel4::MicrokitConfig::Debug, fpu: true, arm_pa_size_bits: Some(40), arm_smc: None, From 246fa09e3ec88e82dc2936f96313d0f99e852d2c Mon Sep 17 00:00:00 2001 From: Alwin Joshy Date: Thu, 20 Feb 2025 15:01:46 +1100 Subject: [PATCH 03/18] gdb: add HardwareDebugAPI to debug config Signed-off-by: Alwin Joshy --- build_sdk.py | 3 ++- tool/microkit/src/sel4.rs | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build_sdk.py b/build_sdk.py index d1b768237..6cae4cd5a 100644 --- a/build_sdk.py +++ b/build_sdk.py @@ -334,7 +334,8 @@ class ConfigInfo: kernel_options={ "KernelDebugBuild": True, "KernelPrinting": True, - "KernelVerificationBuild": False + "KernelVerificationBuild": False, + "HardwareDebugAPI": True } ), ConfigInfo( diff --git a/tool/microkit/src/sel4.rs b/tool/microkit/src/sel4.rs index 78ad6135e..2bb512fbb 100644 --- a/tool/microkit/src/sel4.rs +++ b/tool/microkit/src/sel4.rs @@ -212,7 +212,10 @@ impl ObjectType { pub fn fixed_size_bits(self, config: &Config) -> Option { match self { ObjectType::Tcb => match config.arch { - Arch::Aarch64 => Some(11), + Arch::Aarch64 => match config.microkit_config { + MicrokitConfig::Debug => Some(12), + _ => Some(11), + }, Arch::Riscv64 => match config.fpu { true => Some(11), false => Some(10), From aaed22dbcbfbeaf66f6591ebd9cd9f5eda3e562b Mon Sep 17 00:00:00 2001 From: kappamalone Date: Mon, 15 Jul 2024 16:48:44 +1000 Subject: [PATCH 04/18] mint child frame caps into parent Signed-off-by: Krishnan Winter --- libmicrokit/include/microkit.h | 2 ++ tool/microkit/src/main.rs | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/libmicrokit/include/microkit.h b/libmicrokit/include/microkit.h index 89090cac1..63c22b7bf 100644 --- a/libmicrokit/include/microkit.h +++ b/libmicrokit/include/microkit.h @@ -15,6 +15,7 @@ typedef unsigned int microkit_channel; typedef unsigned int microkit_child; typedef seL4_MessageInfo_t microkit_msginfo; +#define VSPACE_CAP 3 #define MONITOR_EP 5 /* Only valid in the 'benchmark' configuration */ #define TCB_CAP 6 @@ -27,6 +28,7 @@ typedef seL4_MessageInfo_t microkit_msginfo; #define BASE_VSPACE_CAP 266 #define BASE_VM_TCB_CAP 330 #define BASE_VCPU_CAP 394 +#define BASE_FRAME_CAP 458 #define MICROKIT_MAX_CHANNELS 62 #define MICROKIT_MAX_CHANNEL_ID (MICROKIT_MAX_CHANNELS - 1) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 45cd6193e..9ab84df5a 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -57,6 +57,7 @@ const BASE_PD_TCB_CAP: u64 = BASE_IRQ_CAP + 64; const BASE_PD_VSPACE_CAP: u64 = BASE_PD_TCB_CAP + 64; const BASE_VM_TCB_CAP: u64 = BASE_PD_VSPACE_CAP + 64; const BASE_VCPU_CAP: u64 = BASE_VM_TCB_CAP + 64; +const BASE_FRAME_CAP: u64 = BASE_VCPU_CAP + 64; const MAX_SYSTEM_INVOCATION_SIZE: u64 = util::mb(128); @@ -1972,6 +1973,54 @@ fn build_system( } } + // mint frame caps of child into parent + let mut base_frame_cap = BASE_FRAME_CAP; + let mut all_mr_by_name_sorted: Vec<&&str> = all_mr_by_name.keys().collect(); + all_mr_by_name_sorted.sort(); + + for (pd_idx, parent) in system.protection_domains.iter().enumerate() { + for maybe_child_pd in system.protection_domains.iter() { + if let Some(parent_idx) = maybe_child_pd.parent { + if parent_idx == pd_idx { + for child_mr_name in &all_mr_by_name_sorted { + if child_mr_name.contains(&maybe_child_pd.name) { + println!("parent: {} wants to map this child memory regions: {}", parent.name, child_mr_name); + + let child_mr = all_mr_by_name[*child_mr_name]; + let mut invocation = Invocation::new(InvocationArgs::CnodeMint{ + cnode: cnode_objs[pd_idx].cap_addr, + dest_index: base_frame_cap, + dest_depth: PD_CAP_BITS, + src_root: root_cnode_cap, + src_obj: mr_pages[child_mr][0].cap_addr, // the memory region has multiple + // pages, we're taking the first one at 0x20300 + src_depth: kernel_config.cap_address_bits, + rights: (Rights::Read as u64 | Rights::Write as u64), + badge: 0, + }); + + invocation.repeat(mr_pages[child_mr].len() as u32, InvocationArgs::CnodeMint{ + cnode: 0, + dest_index: 1, + dest_depth: 0, + src_root: 0, + src_obj: 1, + src_depth: 0, + rights: 0, + badge: 0, + }); + + base_frame_cap += mr_pages[child_mr].len() as u64; + + system_invocations.push(invocation); + } + } + + } + } + } + } + let mut badged_irq_caps: HashMap<&ProtectionDomain, Vec> = HashMap::new(); for (notification_obj, pd) in zip(¬ification_objs, &system.protection_domains) { badged_irq_caps.insert(pd, vec![]); From f3443fb2f127818d31df2369a5bc08da1408bbbc Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Tue, 10 Jun 2025 18:49:22 +1000 Subject: [PATCH 05/18] tool: add child page tables as new elf segment The previous approach for patching the page tables of child PD's into the parent PD was to patch two symbols, one for the table metadata (PGD) which points to entries in the table data array, which is the rest of the paging structures. The drawback of this approach is that you need to hardcode the size of the child paging structures in the parent PD. This commit supports a variable size of table data regions by appending a loadable segment to the ELF of the parent. Co-authored-by: Alwin Joshy Co-authored-by: Szymon Duchniewicz Signed-off-by: Krishnan Winter --- tool/microkit/src/elf.rs | 47 ++++++++++++++++++++++++++++++++++ tool/microkit/src/main.rs | 54 +++++++++++++++++++++++++++++++++++++++ tool/microkit/src/sdf.rs | 22 ++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/tool/microkit/src/elf.rs b/tool/microkit/src/elf.rs index 1b97195a0..bb46c2444 100644 --- a/tool/microkit/src/elf.rs +++ b/tool/microkit/src/elf.rs @@ -97,6 +97,7 @@ struct ElfHeader64 { const ELF_MAGIC: &[u8; 4] = b"\x7FELF"; pub struct ElfSegment { + pub name: Option, pub data: Vec, pub phys_addr: u64, pub virt_addr: u64, @@ -104,6 +105,13 @@ pub struct ElfSegment { attrs: u32, } +#[derive(IntoBytes,Immutable)] +#[repr(C)] +pub struct TableMetadata { + pub base_addr: u64, + pub pgd:[u64;64], +} + impl ElfSegment { pub fn mem_size(&self) -> u64 { self.data.len() as u64 @@ -211,6 +219,7 @@ impl ElfFile { .copy_from_slice(&bytes[segment_start..segment_end]); let segment = ElfSegment { + name: None, data: segment_data, phys_addr: phent.paddr, virt_addr: phent.vaddr, @@ -363,4 +372,42 @@ impl ElfFile { pub fn loadable_segments(&self) -> Vec<&ElfSegment> { self.segments.iter().filter(|s| s.loadable).collect() } + + pub fn create_segment(&mut self, segment_name: &str, size: u64) -> ElfSegment { + let mut last_addr = 0; + for segment in self.segments.iter() { + if segment.virt_addr > last_addr { + last_addr = segment.virt_addr + segment.data.len() as u64; + } + } + + last_addr = last_addr + (0x10000 - (last_addr % 0x10000)); + + return ElfSegment{name: Some(segment_name.to_string()), data: vec![0; size as usize], + phys_addr: last_addr, virt_addr: last_addr, loadable: true, + attrs: ElfSegmentAttributes::Read as u32}; + } + + pub fn populate_segment(&mut self, segment_name: &str, data: &[u8]) { + // Find segment + for segment in self.segments.iter_mut() { + if let Some(name) = &segment.name { + if name == segment_name { + assert!(data.len() <= segment.data.len()); + segment.data = data.to_vec(); + } + } + } + } + + pub fn get_segment(&mut self, segment_name: &str) -> Option<&ElfSegment> { + for segment in &self.segments { + if let Some(name) = &segment.name { + if name == segment_name { + return Some(segment); + } + } + } + return None; + } } diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 9ab84df5a..8dec4c682 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -9,6 +9,7 @@ use elf::ElfFile; use loader::Loader; +use microkit_tool::elf::TableMetadata; use microkit_tool::{ elf, loader, sdf, sel4, util, DisjointMemoryRegion, FindFixedError, MemoryRegion, ObjectAllocator, Region, UntypedObject, MAX_PDS, MAX_VMS, PD_MAX_NAME_LENGTH, @@ -740,6 +741,7 @@ fn build_system( system: &SystemDescription, invocation_table_size: u64, system_cnode_size: u64, + has_built: bool, ) -> Result { assert!(util::is_power_of_two(system_cnode_size)); assert!(invocation_table_size % config.minimum_page_size == 0); @@ -761,6 +763,54 @@ fn build_system( // Determine physical memory region used by the monitor let initial_task_size = phys_mem_region_from_elf(monitor_elf, config.minimum_page_size).size(); + // Only append new segments to the elf on the FIRST iteration of this function. + if (!has_built) { + // If we are mapping the child page tables into the parents, + // calculate the extra that these occupy and increment the pd_elf_size + // appropriately. + for (parent_idx, pd) in system.protection_domains.iter().enumerate() { + let mut pd_extra_elf_size = 0; + // Flag to enable the patching of child page tables + if (pd.child_pts) { + // @kwinter: Assuming that the parents and children have been flattened + // to be consecutive + // Find all child page tables and find size of loadable segments. + for (child_idx, child_pd) in system.protection_domains.iter().enumerate() { + if (child_idx <= parent_idx) { + continue; + } else if (child_idx >= parent_idx && child_pd.parent != Some(parent_idx)) { + break; + } + let mut child_pgd = PGD::new(); + // Find the corresponding elf for this child and add loadable segments + // to page table structures. + let child_elf = &pd_elf_files[parent_idx + child_idx]; + for loadable_segment in child_elf.loadable_segments() { + child_pgd.add_4k_page_at_vaddr(loadable_segment.virt_addr, loadable_segment.data.len() as i64); + } + // Find all associated memory regions and their size. + for child_map in &child_pd.maps { + // Find the memory region associated with this map + for mr in &system.memory_regions { + if mr.name == child_map.mr { + child_pgd.add_4k_page_at_vaddr(child_map.vaddr, mr.size as i64); + } + } + } + // Account for the stack of each child pd + child_pgd.add_4k_page_at_vaddr(config.pd_stack_bottom(child_pd.stack_size), child_pd.stack_size as i64); + // We have now constructed the dummy page tables, calculate how much size we + // need to add to the pd_elf_sizes + pd_extra_elf_size += child_pgd.get_size(); + } + // Push this new region to the parent's elf + let parent_elf = &mut pd_elf_files[parent_idx]; + let new_elf_seg = parent_elf.create_segment(".table_data", pd_extra_elf_size); + parent_elf.segments.push(new_elf_seg); + } + } + } + // Determine physical memory region for 'reserved' memory. // // The 'reserved' memory region will not be touched by seL4 during boot @@ -3426,6 +3476,7 @@ fn main() -> Result<(), String> { let mut system_cnode_size = 2; let mut built_system; + let mut has_built = false; loop { built_system = build_system( &kernel_config, @@ -3435,10 +3486,13 @@ fn main() -> Result<(), String> { &system, invocation_table_size, system_cnode_size, + has_built )?; println!("BUILT: system_cnode_size={} built_system.number_of_system_caps={} invocation_table_size={} built_system.invocation_data_size={}", system_cnode_size, built_system.number_of_system_caps, invocation_table_size, built_system.invocation_data_size); + has_built = true; + if built_system.number_of_system_caps <= system_cnode_size && built_system.invocation_data_size <= invocation_table_size { diff --git a/tool/microkit/src/sdf.rs b/tool/microkit/src/sdf.rs index c41c46e43..23ef34d6c 100644 --- a/tool/microkit/src/sdf.rs +++ b/tool/microkit/src/sdf.rs @@ -189,6 +189,7 @@ pub struct ProtectionDomain { /// Index into the total list of protection domains if a parent /// protection domain exists pub parent: Option, + pub child_pts: bool, /// Location in the parsed SDF file text_pos: roxmltree::TextPos, } @@ -362,6 +363,7 @@ impl ProtectionDomain { // The SMC field is only available in certain configurations // but we do the error-checking further down. "smc", + "child_pts", ]; if is_child { attrs.push("id"); @@ -656,6 +658,25 @@ impl ProtectionDomain { let has_children = !child_pds.is_empty(); + let child_pts = if has_children { + if let Some(xml_child_pts) = node.attribute("child_pts") { + match str_to_bool(xml_child_pts) { + Some(val) => val, + None => { + return Err(value_error( + xml_sdf, + node, + "child_pts must be 'true' or 'false'".to_string(), + )) + } + } + } else { + false + } + } else { + false + }; + Ok(ProtectionDomain { id, name, @@ -675,6 +696,7 @@ impl ProtectionDomain { virtual_machine, has_children, parent: None, + child_pts, text_pos: xml_sdf.doc.text_pos_at(node.range().start), }) } From 7c7b74d96a0d2b56b8465907eb68ebbbd7de897a Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Wed, 11 Jun 2025 14:22:30 +1000 Subject: [PATCH 06/18] tool: cleanup construction of page tables Co-authored-by: Alwin Joshy Signed-off-by: Krishnan Winter --- tool/microkit/Cargo.lock | 21 +++++++++++++++++++++ tool/microkit/Cargo.toml | 1 + tool/microkit/src/elf.rs | 1 + tool/microkit/src/main.rs | 7 ++++--- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tool/microkit/Cargo.lock b/tool/microkit/Cargo.lock index 9073ccf28..3fe3b25ed 100644 --- a/tool/microkit/Cargo.lock +++ b/tool/microkit/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ "roxmltree", "serde", "serde_json", + "zerocopy", ] [[package]] @@ -94,3 +95,23 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/tool/microkit/Cargo.toml b/tool/microkit/Cargo.toml index f58496557..db8bb105b 100644 --- a/tool/microkit/Cargo.toml +++ b/tool/microkit/Cargo.toml @@ -18,6 +18,7 @@ path = "src/main.rs" roxmltree = "0.19.0" serde = { version = "1.0.203", features = ["derive"] } serde_json = "1.0.117" +zerocopy = {version="0.8.25",features=["derive"]} [profile.release] strip = true diff --git a/tool/microkit/src/elf.rs b/tool/microkit/src/elf.rs index bb46c2444..ef6629e9c 100644 --- a/tool/microkit/src/elf.rs +++ b/tool/microkit/src/elf.rs @@ -8,6 +8,7 @@ use crate::util::bytes_to_struct; use std::collections::HashMap; use std::fs; use std::path::Path; +use zerocopy::{Immutable,IntoBytes}; #[repr(C, packed)] struct ElfHeader32 { diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 8dec4c682..d4cc9db65 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -35,6 +35,7 @@ use util::{ comma_sep_u64, comma_sep_usize, human_size_strict, json_str, json_str_as_bool, json_str_as_u64, monitor_serialise_names, monitor_serialise_u64_vec, struct_to_bytes, }; +use zerocopy::{Immutable,IntoBytes}; // Corresponds to the IPC buffer symbol in libmicrokit and the monitor const SYMBOL_IPC_BUFFER: &str = "__sel4_ipc_buffer_obj"; @@ -786,19 +787,19 @@ fn build_system( // to page table structures. let child_elf = &pd_elf_files[parent_idx + child_idx]; for loadable_segment in child_elf.loadable_segments() { - child_pgd.add_4k_page_at_vaddr(loadable_segment.virt_addr, loadable_segment.data.len() as i64); + child_pgd.add_page_at_vaddr_range(loadable_segment.virt_addr, loadable_segment.data.len() as i64, 1, PageSize::Small); } // Find all associated memory regions and their size. for child_map in &child_pd.maps { // Find the memory region associated with this map for mr in &system.memory_regions { if mr.name == child_map.mr { - child_pgd.add_4k_page_at_vaddr(child_map.vaddr, mr.size as i64); + child_pgd.add_page_at_vaddr_range(child_map.vaddr, mr.size as i64, 1, mr.page_size); } } } // Account for the stack of each child pd - child_pgd.add_4k_page_at_vaddr(config.pd_stack_bottom(child_pd.stack_size), child_pd.stack_size as i64); + child_pgd.add_page_at_vaddr_range(config.pd_stack_bottom(child_pd.stack_size), child_pd.stack_size as i64, 1, PageSize::Small); // We have now constructed the dummy page tables, calculate how much size we // need to add to the pd_elf_sizes pd_extra_elf_size += child_pgd.get_size(); From f1a4ecc378c7011951d015919a584088541a0012 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Wed, 11 Jun 2025 14:45:28 +1000 Subject: [PATCH 07/18] tool: cleanup patching of data into elfs Cleanup how we patch child page table's as data into new elf segments. Co-authored-by: Alwin Joshy Signed-off-by: Krishnan Winter --- tool/microkit/src/main.rs | 116 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index d4cc9db65..3b1fdf4bd 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -2072,6 +2072,122 @@ fn build_system( } } + // Create an outline of the page table mappings for each pd. We can later populate this outline + // with the corresponding frame caps should any pd have a parent + let mut all_pd_page_tables: Vec = vec![PGD::new(); 64]; + + let mut sorted_mp_mr_pairs: Vec<(&SysMap, &SysMemoryRegion, String)> = vec![]; + for pd in system.protection_domains.iter() { + for map_set in [&pd.maps, &pd_extra_maps[pd]] { + for mp in map_set { + let mr = all_mr_by_name[mp.mr.as_str()]; + let id = mr.name.clone() + " " + &pd.name; + sorted_mp_mr_pairs.push((mp, mr, id)); + } + } + } + sorted_mp_mr_pairs.sort_by(|a, b| a.1.name.cmp(&b.1.name)); + let mut base_frame_cap = BASE_FRAME_CAP; + + // If a pd has a parent, we mint the child's frame caps into the parent's vspace + // We additionally place these frame caps into the corresponding page in our copy of the tables + for (pd_idx, parent) in system.protection_domains.iter().enumerate() { + for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { + if let Some(parent_idx) = maybe_child_pd.parent { + if parent_idx == pd_idx { + for mp_mr_pair in &sorted_mp_mr_pairs { + let child_mp = mp_mr_pair.0; + let child_mr = mp_mr_pair.1; + let name = &mp_mr_pair.2; + if name.contains(&maybe_child_pd.name) { + println!( + "parent: {} wants to map this child memory regions: {}", + parent.name, child_mr.name + ); + + println!("we have {} frames", mr_pages[child_mr].len()); + let mut invocation = Invocation::new( + config, + InvocationArgs::CnodeMint { + cnode: cnode_objs[pd_idx].cap_addr, + dest_index: base_frame_cap, + dest_depth: PD_CAP_BITS, + src_root: root_cnode_cap, + src_obj: mr_pages[child_mr][0].cap_addr, + src_depth: config.cap_address_bits, + rights: (Rights::Read as u64 | Rights::Write as u64), + badge: 0, + }, + ); + + invocation.repeat( + mr_pages[child_mr].len() as u32, + InvocationArgs::CnodeMint { + cnode: 0, + dest_index: 1, + dest_depth: 0, + src_root: 0, + src_obj: 1, + src_depth: 0, + rights: 0, + badge: 0, + }, + ); + + for mr_idx in 0..mr_pages[child_mr].len() { + let cap = mr_pages[child_mr][mr_idx].cap_addr; + let vaddr = child_mp.vaddr + child_mr.page_size_bytes() * mr_idx as u64; + let minted_cap = base_frame_cap + mr_idx as u64; + + // Check if we have a small or large page. + all_pd_page_tables[maybe_child_idx].add_page_at_vaddr(vaddr, minted_cap, child_mr.page_size); + } + + base_frame_cap += mr_pages[child_mr].len() as u64; + system_invocations.push(invocation); + } + } + } + } + } + } + + for (pd_idx, parent) in system.protection_domains.iter().enumerate() { + let mut parent_pd_view: Vec = vec![PGD::new(); 64]; + let mut child_pds: Vec = vec![]; + + for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { + if let Some(parent_idx) = maybe_child_pd.parent { + if parent_idx == pd_idx { + let id = maybe_child_pd.id.unwrap() as usize; + parent_pd_view[id] = all_pd_page_tables[maybe_child_idx].clone(); + child_pds.push(id); + } + } + } + + if child_pds.is_empty() { + continue; + } + + let mut table_metadata = TableMetadata { base_addr: 0, pgd: [0; 64]}; + let mut table_data = Vec::::new(); + let mut offset = 0; + + for i in child_pds { + offset = parent_pd_view[i].recurse(offset, &mut table_data); + table_metadata.pgd[i] = offset - (512 * 8); + } + + // patch the data in + let elf = &mut pd_elf_files[pd_idx]; + elf.populate_segment(".table_data", &table_data); + let new_elf_seg = elf.get_segment(".table_data").unwrap(); + + table_metadata.base_addr = new_elf_seg.virt_addr; + elf.write_symbol("table_metadata", &table_metadata.as_bytes())?; + } + let mut badged_irq_caps: HashMap<&ProtectionDomain, Vec> = HashMap::new(); for (notification_obj, pd) in zip(¬ification_objs, &system.protection_domains) { badged_irq_caps.insert(pd, vec![]); From be3e3c38e6397758cc28c4095a6f6a95ee6f7cb2 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Thu, 17 Jul 2025 16:28:25 +1000 Subject: [PATCH 08/18] tool: support large pages in child vspace mapping Support for memory regions using large pages to be mapped into the translation tables that are mapped into the parent PD's. Signed-off-by: Krishnan Winter --- tool/microkit/src/lib.rs | 223 ++++++++++++++++++++++++++++++++++++++ tool/microkit/src/main.rs | 105 +++++++++--------- tool/microkit/src/sdf.rs | 7 +- 3 files changed, 283 insertions(+), 52 deletions(-) diff --git a/tool/microkit/src/lib.rs b/tool/microkit/src/lib.rs index dfa642566..5753f5d50 100644 --- a/tool/microkit/src/lib.rs +++ b/tool/microkit/src/lib.rs @@ -14,6 +14,8 @@ use sel4::Config; use std::cmp::min; use std::fmt; +use crate::sel4::PageSize; + // Note that these values are used in the monitor so should also be changed there // if any of these were to change. pub const MAX_PDS: usize = 63; @@ -24,6 +26,227 @@ pub const MAX_VMS: usize = 63; pub const PD_MAX_NAME_LENGTH: usize = 64; pub const VM_MAX_NAME_LENGTH: usize = 64; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct PGD { + puds: Vec>, +} + +impl PGD { + pub fn new() -> Self { + PGD { + puds: vec![None; 512], + } + } + + pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { + let mut offset_table: [u64; 512] = [u64::MAX; 512]; + for i in 0..512 { + if let Some(pud) = &mut self.puds[i] { + curr_offset = pud.recurse(curr_offset, buffer); + offset_table[i] = curr_offset - (512 * 8); + } + } + + for value in &mut offset_table { + buffer.append(&mut value.to_le_bytes().to_vec()); + } + curr_offset + (512 * 8) + } + + pub fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { + let pgd_index = ((vaddr & (0x1ff << 39)) >> 39) as usize; + if self.puds[pgd_index].is_none() { + self.puds[pgd_index] = Some(PUD::new()); + } + self.puds[pgd_index].as_mut().unwrap().add_page_at_vaddr(vaddr, frame, size); + + } + + pub fn add_page_at_vaddr_range(&mut self, mut vaddr: u64, mut data_len: i64, frame: u64, size: PageSize) { + while data_len > 0 { + self.add_page_at_vaddr(vaddr, frame, size); + data_len -= size as i64; + vaddr += size as u64; + } + } + + pub fn get_size(&self) -> u64{ + let mut child_size = 0; + for pud in &self.puds { + if pud.is_some() { + child_size += pud.as_ref().unwrap().get_size(); + } + } + return (512 * 8) + child_size; + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct PUD { + dirs: Vec>, +} + +impl PUD { + fn new() -> Self { + PUD { + dirs: vec![None; 512], + } + } + + fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { + let mut offset_table: [u64; 512] = [u64::MAX; 512]; + for i in 0..512 { + if let Some(dir) = &mut self.dirs[i] { + curr_offset = dir.recurse(curr_offset, buffer); + offset_table[i] = curr_offset - (512 * 8); + } + } + + for value in &mut offset_table { + buffer.append(&mut value.to_le_bytes().to_vec()); + } + curr_offset + (512 * 8) + } + + fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { + let pud_index = ((vaddr & (0x1ff << 30)) >> 30) as usize; + if self.dirs[pud_index].is_none() { + self.dirs[pud_index] = Some(DIR::new()); + } + self.dirs[pud_index].as_mut().unwrap().add_page_at_vaddr(vaddr, frame, size); + } + + fn get_size(&self) -> u64{ + let mut child_size = 0; + for dir in &self.dirs { + if dir.is_some() { + child_size += dir.as_ref().unwrap().get_size(); + } + } + return (512 * 8) + child_size; + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum DirEntry { + PageTable(PT), + LargePage(u64), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DIR { + entries: Vec>, +} + +impl DIR { + fn new() -> Self { + DIR { + entries: vec![None; 512], + } + } + + fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { + let mut offset_table: [u64; 512] = [u64::MAX; 512]; + for i in 0..512 { + if let Some(entry) = &mut self.entries[i] { + match entry { + DirEntry::PageTable(x) => { + curr_offset = x.recurse(curr_offset, buffer); + offset_table[i] = curr_offset - (512 * 8); + }, + DirEntry::LargePage(x) => { + // curr_offset += 8; + // we mark the top bit to signal to the pd that this is a large page + offset_table[i] = *x | (1 << 63); + println!("Large page encountered!"); + } + } + } + } + + for value in &mut offset_table { + buffer.append(&mut value.to_le_bytes().to_vec()); + } + curr_offset + (512 * 8) + } + + fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { + let dir_index = ((vaddr & (0x1ff << 21)) >> 21) as usize; + match size { + PageSize::Small => { + println!("We are NOT adding a large page!\n"); + if self.entries[dir_index].is_none() { + self.entries[dir_index] = Some(DirEntry::PageTable(PT::new())); + } + match &mut self.entries[dir_index] { + Some(DirEntry::PageTable(x)) => { + x.add_page_at_vaddr(vaddr, frame, size); + }, + _ => { + panic!("Trying to add small page where a large page already exists!"); + } + } + }, + PageSize::Large => { + if let Some(DirEntry::PageTable(_)) = self.entries[dir_index] { + panic!("Attempting to insert a large page where a page table already exists!"); + } + println!("We are adding a large page!\n"); + self.entries[dir_index] = Some(DirEntry::LargePage(frame)); + } + } + + } + + fn get_size(&self) -> u64{ + let mut child_size = 0; + for pt in &self.entries { + match pt { + Some(DirEntry::PageTable(x)) => { + child_size += x.get_size(); + }, + _ => {} + } + } + return (512 * 8) + child_size; + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct PT { + large_page: u64, + pages: Vec, +} + +impl PT { + fn new() -> Self { + PT { + pages: vec![u64::MAX; 512], + large_page: u64::MAX, + } + } + + fn recurse(&mut self, curr_offset: u64, buffer: &mut Vec) -> u64 { + for value in &mut self.pages { + buffer.append(&mut value.to_le_bytes().to_vec()); + } + curr_offset + (512 * 8) + } + + fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { + let pt_index = ((vaddr & (0x1ff << 12)) >> 12) as usize; + // Unconditionally overwrite. + assert!(size == PageSize::Small); + self.pages[pt_index] = frame; + } + + fn get_size(&self) -> u64{ + return 512 * 8; + } +} + + #[derive(Debug, Copy, Clone, PartialEq)] pub struct UntypedObject { pub cap: u64, diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 3b1fdf4bd..93e3fb118 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -7,13 +7,12 @@ // we want our asserts, even if the compiler figures out they hold true already during compile-time #![allow(clippy::assertions_on_constants)] -use elf::ElfFile; +use elf::{ElfFile, TableMetadata}; use loader::Loader; -use microkit_tool::elf::TableMetadata; use microkit_tool::{ elf, loader, sdf, sel4, util, DisjointMemoryRegion, FindFixedError, MemoryRegion, ObjectAllocator, Region, UntypedObject, MAX_PDS, MAX_VMS, PD_MAX_NAME_LENGTH, - VM_MAX_NAME_LENGTH, + VM_MAX_NAME_LENGTH, PGD }; use sdf::{ parse, Channel, ProtectionDomain, SysMap, SysMapPerms, SysMemoryRegion, SysMemoryRegionKind, @@ -27,7 +26,7 @@ use sel4::{ use std::cmp::{max, min}; use std::collections::{HashMap, HashSet}; use std::fs; -use std::io::{BufWriter, Write}; +use std::io::{BufWriter, Read, Write}; use std::iter::zip; use std::mem::size_of; use std::path::{Path, PathBuf}; @@ -63,7 +62,7 @@ const BASE_FRAME_CAP: u64 = BASE_VCPU_CAP + 64; const MAX_SYSTEM_INVOCATION_SIZE: u64 = util::mb(128); -const PD_CAP_SIZE: u64 = 512; +const PD_CAP_SIZE: u64 = 4096; const PD_CAP_BITS: u64 = PD_CAP_SIZE.ilog2() as u64; const PD_SCHEDCONTEXT_SIZE: u64 = 1 << 8; @@ -736,7 +735,7 @@ fn emulate_kernel_boot( fn build_system( config: &Config, - pd_elf_files: &Vec, + pd_elf_files: &mut Vec, kernel_elf: &ElfFile, monitor_elf: &ElfFile, system: &SystemDescription, @@ -764,46 +763,49 @@ fn build_system( // Determine physical memory region used by the monitor let initial_task_size = phys_mem_region_from_elf(monitor_elf, config.minimum_page_size).size(); - // Only append new segments to the elf on the FIRST iteration of this function. - if (!has_built) { - // If we are mapping the child page tables into the parents, - // calculate the extra that these occupy and increment the pd_elf_size - // appropriately. - for (parent_idx, pd) in system.protection_domains.iter().enumerate() { - let mut pd_extra_elf_size = 0; - // Flag to enable the patching of child page tables - if (pd.child_pts) { - // @kwinter: Assuming that the parents and children have been flattened - // to be consecutive - // Find all child page tables and find size of loadable segments. - for (child_idx, child_pd) in system.protection_domains.iter().enumerate() { - if (child_idx <= parent_idx) { - continue; - } else if (child_idx >= parent_idx && child_pd.parent != Some(parent_idx)) { - break; - } - let mut child_pgd = PGD::new(); - // Find the corresponding elf for this child and add loadable segments - // to page table structures. - let child_elf = &pd_elf_files[parent_idx + child_idx]; - for loadable_segment in child_elf.loadable_segments() { - child_pgd.add_page_at_vaddr_range(loadable_segment.virt_addr, loadable_segment.data.len() as i64, 1, PageSize::Small); - } - // Find all associated memory regions and their size. - for child_map in &child_pd.maps { - // Find the memory region associated with this map - for mr in &system.memory_regions { - if mr.name == child_map.mr { - child_pgd.add_page_at_vaddr_range(child_map.vaddr, mr.size as i64, 1, mr.page_size); - } + // Create a vector of optional vectors, which we will populate as needed. This maintains the pd_idx mapping. + let mut all_child_page_tables:Vec>> = vec![None; system.protection_domains.len()]; + + // If we are mapping the child page tables into the parents, + // calculate the extra that these occupy and increment the pd_elf_size + // appropriately. + for (parent_idx, pd) in system.protection_domains.iter().enumerate() { + let mut pd_extra_elf_size = 0; + // Flag to enable the patching of child page tables + if pd.child_pts { + // Initialise the page table structure for this parent pd. + all_child_page_tables[parent_idx] = Some(vec![PGD::new(); 64]); + // Find all child page tables and find size of loadable segments. + for (child_idx, child_pd) in system.protection_domains.iter().enumerate() { + if child_idx <= parent_idx { + continue; + } else if child_idx >= parent_idx && child_pd.parent != Some(parent_idx) { + break; + } + + let child_pgd: &mut PGD = &mut all_child_page_tables[parent_idx].as_mut().unwrap()[child_pd.id.unwrap() as usize]; + // Find the corresponding elf for this child and add loadable segments + // to page table structures. + let child_elf = &pd_elf_files[parent_idx + child_idx]; + for loadable_segment in child_elf.loadable_segments() { + child_pgd.add_page_at_vaddr_range(loadable_segment.virt_addr, loadable_segment.data.len() as i64, 1, PageSize::Small); + } + // Find all associated memory regions and their size. + for child_map in &child_pd.maps { + // Find the memory region associated with this map + for mr in &system.memory_regions { + if mr.name == child_map.mr { + child_pgd.add_page_at_vaddr_range(child_map.vaddr, mr.size as i64, 1, mr.page_size); } } - // Account for the stack of each child pd - child_pgd.add_page_at_vaddr_range(config.pd_stack_bottom(child_pd.stack_size), child_pd.stack_size as i64, 1, PageSize::Small); - // We have now constructed the dummy page tables, calculate how much size we - // need to add to the pd_elf_sizes - pd_extra_elf_size += child_pgd.get_size(); } + // Account for the stack of each child pd + child_pgd.add_page_at_vaddr_range(config.pd_stack_bottom(child_pd.stack_size), child_pd.stack_size as i64, 1, PageSize::Small); + // We have now constructed the dummy page tables, calculate how much size we + // need to add to the pd_elf_sizes + pd_extra_elf_size += child_pgd.get_size(); + } + if !has_built { // Push this new region to the parent's elf let parent_elf = &mut pd_elf_files[parent_idx]; let new_elf_seg = parent_elf.create_segment(".table_data", pd_extra_elf_size); @@ -819,8 +821,8 @@ fn build_system( // from this area, which can then be made available to the appropriate // protection domains let mut pd_elf_size = 0; - for pd_elf in pd_elf_files { - for r in phys_mem_regions_from_elf(pd_elf, config.minimum_page_size) { + for pd_elf in pd_elf_files.iter_mut() { + for r in phys_mem_regions_from_elf(&pd_elf, config.minimum_page_size) { pd_elf_size += r.size(); } } @@ -2094,7 +2096,7 @@ fn build_system( for (pd_idx, parent) in system.protection_domains.iter().enumerate() { for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { if let Some(parent_idx) = maybe_child_pd.parent { - if parent_idx == pd_idx { + if parent_idx == pd_idx && parent.child_pts { for mp_mr_pair in &sorted_mp_mr_pairs { let child_mp = mp_mr_pair.0; let child_mr = mp_mr_pair.1; @@ -2140,7 +2142,10 @@ fn build_system( let minted_cap = base_frame_cap + mr_idx as u64; // Check if we have a small or large page. - all_pd_page_tables[maybe_child_idx].add_page_at_vaddr(vaddr, minted_cap, child_mr.page_size); + all_child_page_tables[parent_idx] + .as_mut() + .unwrap()[maybe_child_pd.id.unwrap() as usize] + .add_page_at_vaddr(vaddr, minted_cap, child_mr.page_size); } base_frame_cap += mr_pages[child_mr].len() as u64; @@ -2153,14 +2158,12 @@ fn build_system( } for (pd_idx, parent) in system.protection_domains.iter().enumerate() { - let mut parent_pd_view: Vec = vec![PGD::new(); 64]; let mut child_pds: Vec = vec![]; for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { if let Some(parent_idx) = maybe_child_pd.parent { if parent_idx == pd_idx { let id = maybe_child_pd.id.unwrap() as usize; - parent_pd_view[id] = all_pd_page_tables[maybe_child_idx].clone(); child_pds.push(id); } } @@ -2175,7 +2178,7 @@ fn build_system( let mut offset = 0; for i in child_pds { - offset = parent_pd_view[i].recurse(offset, &mut table_data); + offset = all_child_page_tables[pd_idx].as_mut().unwrap()[i].recurse(offset, &mut table_data); table_metadata.pgd[i] = offset - (512 * 8); } @@ -3597,7 +3600,7 @@ fn main() -> Result<(), String> { loop { built_system = build_system( &kernel_config, - &pd_elf_files, + &mut pd_elf_files, &kernel_elf, &monitor_elf, &system, diff --git a/tool/microkit/src/sdf.rs b/tool/microkit/src/sdf.rs index 23ef34d6c..ab9e39165 100644 --- a/tool/microkit/src/sdf.rs +++ b/tool/microkit/src/sdf.rs @@ -20,7 +20,7 @@ use crate::sel4::{Config, IrqTrigger, PageSize}; use crate::util::str_to_bool; use crate::MAX_PDS; use std::path::{Path, PathBuf}; - +use crate::PGD; /// Events that come through entry points (e.g notified or protected) are given an /// identifier that is used as the badge at runtime. /// On 64-bit platforms, this badge has a limit of 64-bits which means that we are @@ -192,6 +192,10 @@ pub struct ProtectionDomain { pub child_pts: bool, /// Location in the parsed SDF file text_pos: roxmltree::TextPos, + // Create an outline of the page table mappings for each pd. We can + //later populate this outline with the corresponding frame caps should + //any pd have a parent + pub child_page_tables: Option>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -698,6 +702,7 @@ impl ProtectionDomain { parent: None, child_pts, text_pos: xml_sdf.doc.text_pos_at(node.range().start), + child_page_tables: None, }) } } From 8830964717c8e29d5667d8811db67f2376a78e74 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Thu, 17 Jul 2025 12:24:35 +1000 Subject: [PATCH 09/18] tool: fix searching memory maps of child pds Signed-off-by: Krishnan Winter --- tool/microkit/src/lib.rs | 3 -- tool/microkit/src/main.rs | 61 +++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/tool/microkit/src/lib.rs b/tool/microkit/src/lib.rs index 5753f5d50..26937c49f 100644 --- a/tool/microkit/src/lib.rs +++ b/tool/microkit/src/lib.rs @@ -159,7 +159,6 @@ impl DIR { // curr_offset += 8; // we mark the top bit to signal to the pd that this is a large page offset_table[i] = *x | (1 << 63); - println!("Large page encountered!"); } } } @@ -175,7 +174,6 @@ impl DIR { let dir_index = ((vaddr & (0x1ff << 21)) >> 21) as usize; match size { PageSize::Small => { - println!("We are NOT adding a large page!\n"); if self.entries[dir_index].is_none() { self.entries[dir_index] = Some(DirEntry::PageTable(PT::new())); } @@ -192,7 +190,6 @@ impl DIR { if let Some(DirEntry::PageTable(_)) = self.entries[dir_index] { panic!("Attempting to insert a large page where a page table already exists!"); } - println!("We are adding a large page!\n"); self.entries[dir_index] = Some(DirEntry::LargePage(frame)); } } diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 93e3fb118..2947b3efd 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -26,7 +26,7 @@ use sel4::{ use std::cmp::{max, min}; use std::collections::{HashMap, HashSet}; use std::fs; -use std::io::{BufWriter, Read, Write}; +use std::io::{BufWriter, Write}; use std::iter::zip; use std::mem::size_of; use std::path::{Path, PathBuf}; @@ -34,7 +34,7 @@ use util::{ comma_sep_u64, comma_sep_usize, human_size_strict, json_str, json_str_as_bool, json_str_as_u64, monitor_serialise_names, monitor_serialise_u64_vec, struct_to_bytes, }; -use zerocopy::{Immutable,IntoBytes}; +use zerocopy::{IntoBytes}; // Corresponds to the IPC buffer symbol in libmicrokit and the monitor const SYMBOL_IPC_BUFFER: &str = "__sel4_ipc_buffer_obj"; @@ -766,9 +766,8 @@ fn build_system( // Create a vector of optional vectors, which we will populate as needed. This maintains the pd_idx mapping. let mut all_child_page_tables:Vec>> = vec![None; system.protection_domains.len()]; - // If we are mapping the child page tables into the parents, - // calculate the extra that these occupy and increment the pd_elf_size - // appropriately. + // If we are mapping the child page tables into the parent, we will create the paging structures + // now, so that the pd_elf_size can be properly calculated. for (parent_idx, pd) in system.protection_domains.iter().enumerate() { let mut pd_extra_elf_size = 0; // Flag to enable the patching of child page tables @@ -805,6 +804,8 @@ fn build_system( // need to add to the pd_elf_sizes pd_extra_elf_size += child_pgd.get_size(); } + // We only want to add these new elf regions ONCE. As the microkit tool can run multiple times, + // we keep track of we have already built these. if !has_built { // Push this new region to the parent's elf let parent_elf = &mut pd_elf_files[parent_idx]; @@ -2026,33 +2027,32 @@ fn build_system( } } - // mint frame caps of child into parent let mut base_frame_cap = BASE_FRAME_CAP; - let mut all_mr_by_name_sorted: Vec<&&str> = all_mr_by_name.keys().collect(); - all_mr_by_name_sorted.sort(); - for (pd_idx, parent) in system.protection_domains.iter().enumerate() { + for (pd_idx, _) in system.protection_domains.iter().enumerate() { for maybe_child_pd in system.protection_domains.iter() { - if let Some(parent_idx) = maybe_child_pd.parent { - if parent_idx == pd_idx { - for child_mr_name in &all_mr_by_name_sorted { - if child_mr_name.contains(&maybe_child_pd.name) { - println!("parent: {} wants to map this child memory regions: {}", parent.name, child_mr_name); - - let child_mr = all_mr_by_name[*child_mr_name]; - let mut invocation = Invocation::new(InvocationArgs::CnodeMint{ + if maybe_child_pd.parent.is_some_and(|x| x == pd_idx) { + for map_set in [&maybe_child_pd.maps, &pd_extra_maps[maybe_child_pd]] { + for mp in map_set { + + let mr = all_mr_by_name[mp.mr.as_str()]; + let mut invocation = Invocation::new( + config, + InvocationArgs::CnodeMint { cnode: cnode_objs[pd_idx].cap_addr, dest_index: base_frame_cap, dest_depth: PD_CAP_BITS, src_root: root_cnode_cap, - src_obj: mr_pages[child_mr][0].cap_addr, // the memory region has multiple - // pages, we're taking the first one at 0x20300 - src_depth: kernel_config.cap_address_bits, + src_obj: mr_pages[mr][0].cap_addr, + src_depth: config.cap_address_bits, rights: (Rights::Read as u64 | Rights::Write as u64), badge: 0, - }); + }, + ); - invocation.repeat(mr_pages[child_mr].len() as u32, InvocationArgs::CnodeMint{ + invocation.repeat( + mr_pages[mr].len() as u32, + InvocationArgs::CnodeMint { cnode: 0, dest_index: 1, dest_depth: 0, @@ -2061,14 +2061,19 @@ fn build_system( src_depth: 0, rights: 0, badge: 0, - }); + }, + ); - base_frame_cap += mr_pages[child_mr].len() as u64; + for mr_idx in 0..mr_pages[mr].len() { + let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; + let minted_cap = base_frame_cap + mr_idx as u64; - system_invocations.push(invocation); + all_child_page_tables[pd_idx] + .as_mut() + .unwrap()[maybe_child_pd.id.unwrap() as usize] + .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); } } - } } } @@ -2157,10 +2162,10 @@ fn build_system( } } - for (pd_idx, parent) in system.protection_domains.iter().enumerate() { + for (pd_idx, _) in system.protection_domains.iter().enumerate() { let mut child_pds: Vec = vec![]; - for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { + for maybe_child_pd in system.protection_domains.iter() { if let Some(parent_idx) = maybe_child_pd.parent { if parent_idx == pd_idx { let id = maybe_child_pd.id.unwrap() as usize; From 7a66b9f80540c251448bce31e835457b14cc7f57 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Thu, 17 Jul 2025 11:57:07 +1000 Subject: [PATCH 10/18] tool: fix compiler warnings Signed-off-by: Krishnan Winter --- tool/microkit/src/main.rs | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 2947b3efd..d7df27b1f 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -2027,8 +2027,6 @@ fn build_system( } } - let mut base_frame_cap = BASE_FRAME_CAP; - for (pd_idx, _) in system.protection_domains.iter().enumerate() { for maybe_child_pd in system.protection_domains.iter() { if maybe_child_pd.parent.is_some_and(|x| x == pd_idx) { @@ -2040,7 +2038,7 @@ fn build_system( config, InvocationArgs::CnodeMint { cnode: cnode_objs[pd_idx].cap_addr, - dest_index: base_frame_cap, + dest_index: BASE_FRAME_CAP, dest_depth: PD_CAP_BITS, src_root: root_cnode_cap, src_obj: mr_pages[mr][0].cap_addr, @@ -2066,7 +2064,7 @@ fn build_system( for mr_idx in 0..mr_pages[mr].len() { let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; - let minted_cap = base_frame_cap + mr_idx as u64; + let minted_cap = BASE_FRAME_CAP + mr_idx as u64; all_child_page_tables[pd_idx] .as_mut() @@ -2079,10 +2077,6 @@ fn build_system( } } - // Create an outline of the page table mappings for each pd. We can later populate this outline - // with the corresponding frame caps should any pd have a parent - let mut all_pd_page_tables: Vec = vec![PGD::new(); 64]; - let mut sorted_mp_mr_pairs: Vec<(&SysMap, &SysMemoryRegion, String)> = vec![]; for pd in system.protection_domains.iter() { for map_set in [&pd.maps, &pd_extra_maps[pd]] { @@ -2094,12 +2088,12 @@ fn build_system( } } sorted_mp_mr_pairs.sort_by(|a, b| a.1.name.cmp(&b.1.name)); - let mut base_frame_cap = BASE_FRAME_CAP; + let mut frame_cap = BASE_FRAME_CAP; // If a pd has a parent, we mint the child's frame caps into the parent's vspace // We additionally place these frame caps into the corresponding page in our copy of the tables for (pd_idx, parent) in system.protection_domains.iter().enumerate() { - for (maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { + for (_maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { if let Some(parent_idx) = maybe_child_pd.parent { if parent_idx == pd_idx && parent.child_pts { for mp_mr_pair in &sorted_mp_mr_pairs { @@ -2107,17 +2101,11 @@ fn build_system( let child_mr = mp_mr_pair.1; let name = &mp_mr_pair.2; if name.contains(&maybe_child_pd.name) { - println!( - "parent: {} wants to map this child memory regions: {}", - parent.name, child_mr.name - ); - - println!("we have {} frames", mr_pages[child_mr].len()); let mut invocation = Invocation::new( config, InvocationArgs::CnodeMint { cnode: cnode_objs[pd_idx].cap_addr, - dest_index: base_frame_cap, + dest_index: frame_cap, dest_depth: PD_CAP_BITS, src_root: root_cnode_cap, src_obj: mr_pages[child_mr][0].cap_addr, @@ -2142,9 +2130,8 @@ fn build_system( ); for mr_idx in 0..mr_pages[child_mr].len() { - let cap = mr_pages[child_mr][mr_idx].cap_addr; let vaddr = child_mp.vaddr + child_mr.page_size_bytes() * mr_idx as u64; - let minted_cap = base_frame_cap + mr_idx as u64; + let minted_cap = frame_cap + mr_idx as u64; // Check if we have a small or large page. all_child_page_tables[parent_idx] @@ -2153,7 +2140,7 @@ fn build_system( .add_page_at_vaddr(vaddr, minted_cap, child_mr.page_size); } - base_frame_cap += mr_pages[child_mr].len() as u64; + frame_cap += mr_pages[child_mr].len() as u64; system_invocations.push(invocation); } } From 34d2a6ad087f4f5ad84554eb50e24b969ba04b86 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Thu, 17 Jul 2025 12:19:32 +1000 Subject: [PATCH 11/18] tool: remove unused code minting child frame caps Signed-off-by: Krishnan Winter --- tool/microkit/src/main.rs | 79 +++------------------------------------ 1 file changed, 6 insertions(+), 73 deletions(-) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index d7df27b1f..c50f19f12 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -2027,6 +2027,8 @@ fn build_system( } } + let mut frame_cap = BASE_FRAME_CAP; + for (pd_idx, _) in system.protection_domains.iter().enumerate() { for maybe_child_pd in system.protection_domains.iter() { if maybe_child_pd.parent.is_some_and(|x| x == pd_idx) { @@ -2038,7 +2040,7 @@ fn build_system( config, InvocationArgs::CnodeMint { cnode: cnode_objs[pd_idx].cap_addr, - dest_index: BASE_FRAME_CAP, + dest_index: frame_cap, dest_depth: PD_CAP_BITS, src_root: root_cnode_cap, src_obj: mr_pages[mr][0].cap_addr, @@ -2064,85 +2066,16 @@ fn build_system( for mr_idx in 0..mr_pages[mr].len() { let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; - let minted_cap = BASE_FRAME_CAP + mr_idx as u64; + let minted_cap = frame_cap + mr_idx as u64; all_child_page_tables[pd_idx] .as_mut() .unwrap()[maybe_child_pd.id.unwrap() as usize] .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); } - } - } - } - } - } - let mut sorted_mp_mr_pairs: Vec<(&SysMap, &SysMemoryRegion, String)> = vec![]; - for pd in system.protection_domains.iter() { - for map_set in [&pd.maps, &pd_extra_maps[pd]] { - for mp in map_set { - let mr = all_mr_by_name[mp.mr.as_str()]; - let id = mr.name.clone() + " " + &pd.name; - sorted_mp_mr_pairs.push((mp, mr, id)); - } - } - } - sorted_mp_mr_pairs.sort_by(|a, b| a.1.name.cmp(&b.1.name)); - let mut frame_cap = BASE_FRAME_CAP; - - // If a pd has a parent, we mint the child's frame caps into the parent's vspace - // We additionally place these frame caps into the corresponding page in our copy of the tables - for (pd_idx, parent) in system.protection_domains.iter().enumerate() { - for (_maybe_child_idx, maybe_child_pd) in system.protection_domains.iter().enumerate() { - if let Some(parent_idx) = maybe_child_pd.parent { - if parent_idx == pd_idx && parent.child_pts { - for mp_mr_pair in &sorted_mp_mr_pairs { - let child_mp = mp_mr_pair.0; - let child_mr = mp_mr_pair.1; - let name = &mp_mr_pair.2; - if name.contains(&maybe_child_pd.name) { - let mut invocation = Invocation::new( - config, - InvocationArgs::CnodeMint { - cnode: cnode_objs[pd_idx].cap_addr, - dest_index: frame_cap, - dest_depth: PD_CAP_BITS, - src_root: root_cnode_cap, - src_obj: mr_pages[child_mr][0].cap_addr, - src_depth: config.cap_address_bits, - rights: (Rights::Read as u64 | Rights::Write as u64), - badge: 0, - }, - ); - - invocation.repeat( - mr_pages[child_mr].len() as u32, - InvocationArgs::CnodeMint { - cnode: 0, - dest_index: 1, - dest_depth: 0, - src_root: 0, - src_obj: 1, - src_depth: 0, - rights: 0, - badge: 0, - }, - ); - - for mr_idx in 0..mr_pages[child_mr].len() { - let vaddr = child_mp.vaddr + child_mr.page_size_bytes() * mr_idx as u64; - let minted_cap = frame_cap + mr_idx as u64; - - // Check if we have a small or large page. - all_child_page_tables[parent_idx] - .as_mut() - .unwrap()[maybe_child_pd.id.unwrap() as usize] - .add_page_at_vaddr(vaddr, minted_cap, child_mr.page_size); - } - - frame_cap += mr_pages[child_mr].len() as u64; - system_invocations.push(invocation); - } + frame_cap += mr_pages[mr].len() as u64; + system_invocations.push(invocation); } } } From 6d6d56037c308aad4ca755cd8daace397925b79d Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Mon, 21 Jul 2025 15:06:00 +1000 Subject: [PATCH 12/18] tool: apply rustfmt Signed-off-by: Krishnan Winter --- tool/microkit/src/elf.rs | 17 ++++++++----- tool/microkit/src/lib.rs | 40 ++++++++++++++++++------------ tool/microkit/src/main.rs | 51 +++++++++++++++++++++++++++------------ tool/microkit/src/sdf.rs | 2 +- 4 files changed, 71 insertions(+), 39 deletions(-) diff --git a/tool/microkit/src/elf.rs b/tool/microkit/src/elf.rs index ef6629e9c..075cb0b44 100644 --- a/tool/microkit/src/elf.rs +++ b/tool/microkit/src/elf.rs @@ -8,7 +8,7 @@ use crate::util::bytes_to_struct; use std::collections::HashMap; use std::fs; use std::path::Path; -use zerocopy::{Immutable,IntoBytes}; +use zerocopy::{Immutable, IntoBytes}; #[repr(C, packed)] struct ElfHeader32 { @@ -106,11 +106,11 @@ pub struct ElfSegment { attrs: u32, } -#[derive(IntoBytes,Immutable)] +#[derive(IntoBytes, Immutable)] #[repr(C)] pub struct TableMetadata { pub base_addr: u64, - pub pgd:[u64;64], + pub pgd: [u64; 64], } impl ElfSegment { @@ -384,9 +384,14 @@ impl ElfFile { last_addr = last_addr + (0x10000 - (last_addr % 0x10000)); - return ElfSegment{name: Some(segment_name.to_string()), data: vec![0; size as usize], - phys_addr: last_addr, virt_addr: last_addr, loadable: true, - attrs: ElfSegmentAttributes::Read as u32}; + return ElfSegment { + name: Some(segment_name.to_string()), + data: vec![0; size as usize], + phys_addr: last_addr, + virt_addr: last_addr, + loadable: true, + attrs: ElfSegmentAttributes::Read as u32, + }; } pub fn populate_segment(&mut self, segment_name: &str, data: &[u8]) { diff --git a/tool/microkit/src/lib.rs b/tool/microkit/src/lib.rs index 26937c49f..97815379c 100644 --- a/tool/microkit/src/lib.rs +++ b/tool/microkit/src/lib.rs @@ -26,7 +26,6 @@ pub const MAX_VMS: usize = 63; pub const PD_MAX_NAME_LENGTH: usize = 64; pub const VM_MAX_NAME_LENGTH: usize = 64; - #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct PGD { puds: Vec>, @@ -39,7 +38,7 @@ impl PGD { } } - pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { + pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { let mut offset_table: [u64; 512] = [u64::MAX; 512]; for i in 0..512 { if let Some(pud) = &mut self.puds[i] { @@ -59,11 +58,19 @@ impl PGD { if self.puds[pgd_index].is_none() { self.puds[pgd_index] = Some(PUD::new()); } - self.puds[pgd_index].as_mut().unwrap().add_page_at_vaddr(vaddr, frame, size); - + self.puds[pgd_index] + .as_mut() + .unwrap() + .add_page_at_vaddr(vaddr, frame, size); } - pub fn add_page_at_vaddr_range(&mut self, mut vaddr: u64, mut data_len: i64, frame: u64, size: PageSize) { + pub fn add_page_at_vaddr_range( + &mut self, + mut vaddr: u64, + mut data_len: i64, + frame: u64, + size: PageSize, + ) { while data_len > 0 { self.add_page_at_vaddr(vaddr, frame, size); data_len -= size as i64; @@ -71,7 +78,7 @@ impl PGD { } } - pub fn get_size(&self) -> u64{ + pub fn get_size(&self) -> u64 { let mut child_size = 0; for pud in &self.puds { if pud.is_some() { @@ -114,10 +121,13 @@ impl PUD { if self.dirs[pud_index].is_none() { self.dirs[pud_index] = Some(DIR::new()); } - self.dirs[pud_index].as_mut().unwrap().add_page_at_vaddr(vaddr, frame, size); + self.dirs[pud_index] + .as_mut() + .unwrap() + .add_page_at_vaddr(vaddr, frame, size); } - fn get_size(&self) -> u64{ + fn get_size(&self) -> u64 { let mut child_size = 0; for dir in &self.dirs { if dir.is_some() { @@ -154,7 +164,7 @@ impl DIR { DirEntry::PageTable(x) => { curr_offset = x.recurse(curr_offset, buffer); offset_table[i] = curr_offset - (512 * 8); - }, + } DirEntry::LargePage(x) => { // curr_offset += 8; // we mark the top bit to signal to the pd that this is a large page @@ -180,12 +190,12 @@ impl DIR { match &mut self.entries[dir_index] { Some(DirEntry::PageTable(x)) => { x.add_page_at_vaddr(vaddr, frame, size); - }, + } _ => { panic!("Trying to add small page where a large page already exists!"); } } - }, + } PageSize::Large => { if let Some(DirEntry::PageTable(_)) = self.entries[dir_index] { panic!("Attempting to insert a large page where a page table already exists!"); @@ -193,16 +203,15 @@ impl DIR { self.entries[dir_index] = Some(DirEntry::LargePage(frame)); } } - } - fn get_size(&self) -> u64{ + fn get_size(&self) -> u64 { let mut child_size = 0; for pt in &self.entries { match pt { Some(DirEntry::PageTable(x)) => { child_size += x.get_size(); - }, + } _ => {} } } @@ -238,12 +247,11 @@ impl PT { self.pages[pt_index] = frame; } - fn get_size(&self) -> u64{ + fn get_size(&self) -> u64 { return 512 * 8; } } - #[derive(Debug, Copy, Clone, PartialEq)] pub struct UntypedObject { pub cap: u64, diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index c50f19f12..5b80a1bd2 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -11,8 +11,8 @@ use elf::{ElfFile, TableMetadata}; use loader::Loader; use microkit_tool::{ elf, loader, sdf, sel4, util, DisjointMemoryRegion, FindFixedError, MemoryRegion, - ObjectAllocator, Region, UntypedObject, MAX_PDS, MAX_VMS, PD_MAX_NAME_LENGTH, - VM_MAX_NAME_LENGTH, PGD + ObjectAllocator, Region, UntypedObject, MAX_PDS, MAX_VMS, PD_MAX_NAME_LENGTH, PGD, + VM_MAX_NAME_LENGTH, }; use sdf::{ parse, Channel, ProtectionDomain, SysMap, SysMapPerms, SysMemoryRegion, SysMemoryRegionKind, @@ -34,7 +34,7 @@ use util::{ comma_sep_u64, comma_sep_usize, human_size_strict, json_str, json_str_as_bool, json_str_as_u64, monitor_serialise_names, monitor_serialise_u64_vec, struct_to_bytes, }; -use zerocopy::{IntoBytes}; +use zerocopy::IntoBytes; // Corresponds to the IPC buffer symbol in libmicrokit and the monitor const SYMBOL_IPC_BUFFER: &str = "__sel4_ipc_buffer_obj"; @@ -764,7 +764,8 @@ fn build_system( let initial_task_size = phys_mem_region_from_elf(monitor_elf, config.minimum_page_size).size(); // Create a vector of optional vectors, which we will populate as needed. This maintains the pd_idx mapping. - let mut all_child_page_tables:Vec>> = vec![None; system.protection_domains.len()]; + let mut all_child_page_tables: Vec>> = + vec![None; system.protection_domains.len()]; // If we are mapping the child page tables into the parent, we will create the paging structures // now, so that the pd_elf_size can be properly calculated. @@ -782,24 +783,40 @@ fn build_system( break; } - let child_pgd: &mut PGD = &mut all_child_page_tables[parent_idx].as_mut().unwrap()[child_pd.id.unwrap() as usize]; + let child_pgd: &mut PGD = &mut all_child_page_tables[parent_idx].as_mut().unwrap() + [child_pd.id.unwrap() as usize]; // Find the corresponding elf for this child and add loadable segments // to page table structures. let child_elf = &pd_elf_files[parent_idx + child_idx]; for loadable_segment in child_elf.loadable_segments() { - child_pgd.add_page_at_vaddr_range(loadable_segment.virt_addr, loadable_segment.data.len() as i64, 1, PageSize::Small); + child_pgd.add_page_at_vaddr_range( + loadable_segment.virt_addr, + loadable_segment.data.len() as i64, + 1, + PageSize::Small, + ); } // Find all associated memory regions and their size. for child_map in &child_pd.maps { // Find the memory region associated with this map for mr in &system.memory_regions { if mr.name == child_map.mr { - child_pgd.add_page_at_vaddr_range(child_map.vaddr, mr.size as i64, 1, mr.page_size); + child_pgd.add_page_at_vaddr_range( + child_map.vaddr, + mr.size as i64, + 1, + mr.page_size, + ); } } } // Account for the stack of each child pd - child_pgd.add_page_at_vaddr_range(config.pd_stack_bottom(child_pd.stack_size), child_pd.stack_size as i64, 1, PageSize::Small); + child_pgd.add_page_at_vaddr_range( + config.pd_stack_bottom(child_pd.stack_size), + child_pd.stack_size as i64, + 1, + PageSize::Small, + ); // We have now constructed the dummy page tables, calculate how much size we // need to add to the pd_elf_sizes pd_extra_elf_size += child_pgd.get_size(); @@ -2034,7 +2051,6 @@ fn build_system( if maybe_child_pd.parent.is_some_and(|x| x == pd_idx) { for map_set in [&maybe_child_pd.maps, &pd_extra_maps[maybe_child_pd]] { for mp in map_set { - let mr = all_mr_by_name[mp.mr.as_str()]; let mut invocation = Invocation::new( config, @@ -2068,10 +2084,9 @@ fn build_system( let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; let minted_cap = frame_cap + mr_idx as u64; - all_child_page_tables[pd_idx] - .as_mut() - .unwrap()[maybe_child_pd.id.unwrap() as usize] - .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); + all_child_page_tables[pd_idx].as_mut().unwrap() + [maybe_child_pd.id.unwrap() as usize] + .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); } frame_cap += mr_pages[mr].len() as u64; @@ -2098,12 +2113,16 @@ fn build_system( continue; } - let mut table_metadata = TableMetadata { base_addr: 0, pgd: [0; 64]}; + let mut table_metadata = TableMetadata { + base_addr: 0, + pgd: [0; 64], + }; let mut table_data = Vec::::new(); let mut offset = 0; for i in child_pds { - offset = all_child_page_tables[pd_idx].as_mut().unwrap()[i].recurse(offset, &mut table_data); + offset = + all_child_page_tables[pd_idx].as_mut().unwrap()[i].recurse(offset, &mut table_data); table_metadata.pgd[i] = offset - (512 * 8); } @@ -3531,7 +3550,7 @@ fn main() -> Result<(), String> { &system, invocation_table_size, system_cnode_size, - has_built + has_built, )?; println!("BUILT: system_cnode_size={} built_system.number_of_system_caps={} invocation_table_size={} built_system.invocation_data_size={}", system_cnode_size, built_system.number_of_system_caps, invocation_table_size, built_system.invocation_data_size); diff --git a/tool/microkit/src/sdf.rs b/tool/microkit/src/sdf.rs index ab9e39165..eb5015ca5 100644 --- a/tool/microkit/src/sdf.rs +++ b/tool/microkit/src/sdf.rs @@ -19,8 +19,8 @@ use crate::sel4::{Config, IrqTrigger, PageSize}; use crate::util::str_to_bool; use crate::MAX_PDS; -use std::path::{Path, PathBuf}; use crate::PGD; +use std::path::{Path, PathBuf}; /// Events that come through entry points (e.g notified or protected) are given an /// identifier that is used as the badge at runtime. /// On 64-bit platforms, this badge has a limit of 64-bits which means that we are From dac489a3c58aa91772ab41778f6a8000638185df Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Mon, 21 Jul 2025 16:14:37 +1000 Subject: [PATCH 13/18] tool: fix lint errors Signed-off-by: Krishnan Winter --- tool/microkit/src/elf.rs | 6 +++--- tool/microkit/src/lib.rs | 35 +++++++++++++++++++---------------- tool/microkit/src/main.rs | 6 +++--- tool/microkit/src/sel4.rs | 2 +- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/tool/microkit/src/elf.rs b/tool/microkit/src/elf.rs index 075cb0b44..c74db3f23 100644 --- a/tool/microkit/src/elf.rs +++ b/tool/microkit/src/elf.rs @@ -384,14 +384,14 @@ impl ElfFile { last_addr = last_addr + (0x10000 - (last_addr % 0x10000)); - return ElfSegment { + ElfSegment { name: Some(segment_name.to_string()), data: vec![0; size as usize], phys_addr: last_addr, virt_addr: last_addr, loadable: true, attrs: ElfSegmentAttributes::Read as u32, - }; + } } pub fn populate_segment(&mut self, segment_name: &str, data: &[u8]) { @@ -414,6 +414,6 @@ impl ElfFile { } } } - return None; + None } } diff --git a/tool/microkit/src/lib.rs b/tool/microkit/src/lib.rs index 97815379c..b5f931821 100644 --- a/tool/microkit/src/lib.rs +++ b/tool/microkit/src/lib.rs @@ -31,6 +31,12 @@ pub struct PGD { puds: Vec>, } +impl Default for PGD { + fn default() -> Self { + Self::new() + } +} + impl PGD { pub fn new() -> Self { PGD { @@ -40,10 +46,10 @@ impl PGD { pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { let mut offset_table: [u64; 512] = [u64::MAX; 512]; - for i in 0..512 { + for (i, entry) in offset_table.iter_mut().enumerate() { if let Some(pud) = &mut self.puds[i] { curr_offset = pud.recurse(curr_offset, buffer); - offset_table[i] = curr_offset - (512 * 8); + *entry = curr_offset - (512 * 8); } } @@ -85,7 +91,7 @@ impl PGD { child_size += pud.as_ref().unwrap().get_size(); } } - return (512 * 8) + child_size; + (512 * 8) + child_size } } @@ -103,10 +109,10 @@ impl PUD { fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { let mut offset_table: [u64; 512] = [u64::MAX; 512]; - for i in 0..512 { + for (i, entry) in offset_table.iter_mut().enumerate() { if let Some(dir) = &mut self.dirs[i] { curr_offset = dir.recurse(curr_offset, buffer); - offset_table[i] = curr_offset - (512 * 8); + *entry = curr_offset - (512 * 8); } } @@ -134,7 +140,7 @@ impl PUD { child_size += dir.as_ref().unwrap().get_size(); } } - return (512 * 8) + child_size; + (512 * 8) + child_size } } @@ -158,17 +164,17 @@ impl DIR { fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { let mut offset_table: [u64; 512] = [u64::MAX; 512]; - for i in 0..512 { + for (i, dir_entry) in offset_table.iter_mut().enumerate() { if let Some(entry) = &mut self.entries[i] { match entry { DirEntry::PageTable(x) => { curr_offset = x.recurse(curr_offset, buffer); - offset_table[i] = curr_offset - (512 * 8); + *dir_entry = curr_offset - (512 * 8); } DirEntry::LargePage(x) => { // curr_offset += 8; // we mark the top bit to signal to the pd that this is a large page - offset_table[i] = *x | (1 << 63); + *dir_entry = *x | (1 << 63); } } } @@ -208,14 +214,11 @@ impl DIR { fn get_size(&self) -> u64 { let mut child_size = 0; for pt in &self.entries { - match pt { - Some(DirEntry::PageTable(x)) => { - child_size += x.get_size(); - } - _ => {} + if let Some(DirEntry::PageTable(x)) = pt { + child_size += x.get_size(); } } - return (512 * 8) + child_size; + (512 * 8) + child_size } } @@ -248,7 +251,7 @@ impl PT { } fn get_size(&self) -> u64 { - return 512 * 8; + 512 * 8 } } diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 5b80a1bd2..6e8ba5a7f 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -840,7 +840,7 @@ fn build_system( // protection domains let mut pd_elf_size = 0; for pd_elf in pd_elf_files.iter_mut() { - for r in phys_mem_regions_from_elf(&pd_elf, config.minimum_page_size) { + for r in phys_mem_regions_from_elf(pd_elf, config.minimum_page_size) { pd_elf_size += r.size(); } } @@ -2132,7 +2132,7 @@ fn build_system( let new_elf_seg = elf.get_segment(".table_data").unwrap(); table_metadata.base_addr = new_elf_seg.virt_addr; - elf.write_symbol("table_metadata", &table_metadata.as_bytes())?; + elf.write_symbol("table_metadata", table_metadata.as_bytes())?; } let mut badged_irq_caps: HashMap<&ProtectionDomain, Vec> = HashMap::new(); @@ -3465,7 +3465,7 @@ fn main() -> Result<(), String> { cap_address_bits: 64, fan_out_limit: json_str_as_u64(&kernel_config_json, "RETYPE_FAN_OUT_LIMIT")?, hypervisor, - microkit_config: MicrokitConfig::from_str(args.config), + microkit_config: MicrokitConfig::config_from_str(args.config), fpu: json_str_as_bool(&kernel_config_json, "HAVE_FPU")?, arm_pa_size_bits, arm_smc, diff --git a/tool/microkit/src/sel4.rs b/tool/microkit/src/sel4.rs index 2bb512fbb..8eb4cffe4 100644 --- a/tool/microkit/src/sel4.rs +++ b/tool/microkit/src/sel4.rs @@ -39,7 +39,7 @@ pub enum MicrokitConfig { } impl MicrokitConfig { - pub fn from_str(string: &str) -> Self { + pub fn config_from_str(string: &str) -> Self { match string { "debug" => MicrokitConfig::Debug, "release" => MicrokitConfig::Release, From d65777d2d4f22475be5f9df1d4173a1224aad538 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Tue, 5 Aug 2025 15:57:08 +1000 Subject: [PATCH 14/18] tool: add child_pt tag checks Signed-off-by: Krishnan Winter --- tool/microkit/src/main.rs | 148 +++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 72 deletions(-) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 6e8ba5a7f..80106714a 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -2046,93 +2046,97 @@ fn build_system( let mut frame_cap = BASE_FRAME_CAP; - for (pd_idx, _) in system.protection_domains.iter().enumerate() { - for maybe_child_pd in system.protection_domains.iter() { - if maybe_child_pd.parent.is_some_and(|x| x == pd_idx) { - for map_set in [&maybe_child_pd.maps, &pd_extra_maps[maybe_child_pd]] { - for mp in map_set { - let mr = all_mr_by_name[mp.mr.as_str()]; - let mut invocation = Invocation::new( - config, - InvocationArgs::CnodeMint { - cnode: cnode_objs[pd_idx].cap_addr, - dest_index: frame_cap, - dest_depth: PD_CAP_BITS, - src_root: root_cnode_cap, - src_obj: mr_pages[mr][0].cap_addr, - src_depth: config.cap_address_bits, - rights: (Rights::Read as u64 | Rights::Write as u64), - badge: 0, - }, - ); - - invocation.repeat( - mr_pages[mr].len() as u32, - InvocationArgs::CnodeMint { - cnode: 0, - dest_index: 1, - dest_depth: 0, - src_root: 0, - src_obj: 1, - src_depth: 0, - rights: 0, - badge: 0, - }, - ); - - for mr_idx in 0..mr_pages[mr].len() { - let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; - let minted_cap = frame_cap + mr_idx as u64; - - all_child_page_tables[pd_idx].as_mut().unwrap() - [maybe_child_pd.id.unwrap() as usize] - .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); - } + for (pd_idx, pd) in system.protection_domains.iter().enumerate() { + if pd.child_pts { + for maybe_child_pd in system.protection_domains.iter() { + if maybe_child_pd.parent.is_some_and(|x| x == pd_idx) { + for map_set in [&maybe_child_pd.maps, &pd_extra_maps[maybe_child_pd]] { + for mp in map_set { + let mr = all_mr_by_name[mp.mr.as_str()]; + let mut invocation = Invocation::new( + config, + InvocationArgs::CnodeMint { + cnode: cnode_objs[pd_idx].cap_addr, + dest_index: frame_cap, + dest_depth: PD_CAP_BITS, + src_root: root_cnode_cap, + src_obj: mr_pages[mr][0].cap_addr, + src_depth: config.cap_address_bits, + rights: (Rights::Read as u64 | Rights::Write as u64), + badge: 0, + }, + ); + + invocation.repeat( + mr_pages[mr].len() as u32, + InvocationArgs::CnodeMint { + cnode: 0, + dest_index: 1, + dest_depth: 0, + src_root: 0, + src_obj: 1, + src_depth: 0, + rights: 0, + badge: 0, + }, + ); - frame_cap += mr_pages[mr].len() as u64; - system_invocations.push(invocation); + for mr_idx in 0..mr_pages[mr].len() { + let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; + let minted_cap = frame_cap + mr_idx as u64; + + all_child_page_tables[pd_idx].as_mut().unwrap() + [maybe_child_pd.id.unwrap() as usize] + .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); + } + + frame_cap += mr_pages[mr].len() as u64; + system_invocations.push(invocation); + } } } } } } - for (pd_idx, _) in system.protection_domains.iter().enumerate() { - let mut child_pds: Vec = vec![]; + for (pd_idx, pd) in system.protection_domains.iter().enumerate() { + if pd.child_pts { + let mut child_pds: Vec = vec![]; - for maybe_child_pd in system.protection_domains.iter() { - if let Some(parent_idx) = maybe_child_pd.parent { - if parent_idx == pd_idx { - let id = maybe_child_pd.id.unwrap() as usize; - child_pds.push(id); + for maybe_child_pd in system.protection_domains.iter() { + if let Some(parent_idx) = maybe_child_pd.parent { + if parent_idx == pd_idx { + let id = maybe_child_pd.id.unwrap() as usize; + child_pds.push(id); + } } } - } - if child_pds.is_empty() { - continue; - } + if child_pds.is_empty() { + continue; + } - let mut table_metadata = TableMetadata { - base_addr: 0, - pgd: [0; 64], - }; - let mut table_data = Vec::::new(); - let mut offset = 0; + let mut table_metadata = TableMetadata { + base_addr: 0, + pgd: [0; 64], + }; + let mut table_data = Vec::::new(); + let mut offset = 0; - for i in child_pds { - offset = - all_child_page_tables[pd_idx].as_mut().unwrap()[i].recurse(offset, &mut table_data); - table_metadata.pgd[i] = offset - (512 * 8); - } + for i in child_pds { + offset = + all_child_page_tables[pd_idx].as_mut().unwrap()[i].recurse(offset, &mut table_data); + table_metadata.pgd[i] = offset - (512 * 8); + } - // patch the data in - let elf = &mut pd_elf_files[pd_idx]; - elf.populate_segment(".table_data", &table_data); - let new_elf_seg = elf.get_segment(".table_data").unwrap(); + // patch the data in + let elf = &mut pd_elf_files[pd_idx]; + elf.populate_segment(".table_data", &table_data); + let new_elf_seg = elf.get_segment(".table_data").unwrap(); - table_metadata.base_addr = new_elf_seg.virt_addr; - elf.write_symbol("table_metadata", table_metadata.as_bytes())?; + table_metadata.base_addr = new_elf_seg.virt_addr; + elf.write_symbol("table_metadata", table_metadata.as_bytes())?; + } } let mut badged_irq_caps: HashMap<&ProtectionDomain, Vec> = HashMap::new(); From eec7256626fb0e9d20de51adce0541291f08c99d Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Tue, 5 Aug 2025 16:25:45 +1000 Subject: [PATCH 15/18] tool: fix bug when finding child elf Signed-off-by: Krishnan Winter --- tool/microkit/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 80106714a..1b685a0c7 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -785,9 +785,7 @@ fn build_system( let child_pgd: &mut PGD = &mut all_child_page_tables[parent_idx].as_mut().unwrap() [child_pd.id.unwrap() as usize]; - // Find the corresponding elf for this child and add loadable segments - // to page table structures. - let child_elf = &pd_elf_files[parent_idx + child_idx]; + let child_elf = &pd_elf_files[child_idx]; for loadable_segment in child_elf.loadable_segments() { child_pgd.add_page_at_vaddr_range( loadable_segment.virt_addr, From 01d5389981954d74fa5da423062a63112f83b58f Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Wed, 15 Oct 2025 16:41:09 +1100 Subject: [PATCH 16/18] tool: Add support for riscv 39 bit addresses in child pts Signed-off-by: Krishnan Winter --- tool/microkit/src/lib.rs | 34 +++++++++-- tool/microkit/src/main.rs | 124 +++++++++++++++++++++++++++++--------- 2 files changed, 125 insertions(+), 33 deletions(-) diff --git a/tool/microkit/src/lib.rs b/tool/microkit/src/lib.rs index b5f931821..3bf6484b1 100644 --- a/tool/microkit/src/lib.rs +++ b/tool/microkit/src/lib.rs @@ -101,13 +101,13 @@ pub struct PUD { } impl PUD { - fn new() -> Self { + pub fn new() -> Self { PUD { dirs: vec![None; 512], } } - fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { + pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { let mut offset_table: [u64; 512] = [u64::MAX; 512]; for (i, entry) in offset_table.iter_mut().enumerate() { if let Some(dir) = &mut self.dirs[i] { @@ -122,7 +122,7 @@ impl PUD { curr_offset + (512 * 8) } - fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { + pub fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { let pud_index = ((vaddr & (0x1ff << 30)) >> 30) as usize; if self.dirs[pud_index].is_none() { self.dirs[pud_index] = Some(DIR::new()); @@ -133,7 +133,21 @@ impl PUD { .add_page_at_vaddr(vaddr, frame, size); } - fn get_size(&self) -> u64 { + pub fn add_page_at_vaddr_range( + &mut self, + mut vaddr: u64, + mut data_len: i64, + frame: u64, + size: PageSize, + ) { + while data_len > 0 { + self.add_page_at_vaddr(vaddr, frame, size); + data_len -= size as i64; + vaddr += size as u64; + } + } + + pub fn get_size(&self) -> u64 { let mut child_size = 0; for dir in &self.dirs { if dir.is_some() { @@ -255,6 +269,18 @@ impl PT { } } +// #[derive(Debug, Clone)] +// pub enum TopLevelPageTable { +// Riscv64(PUD), +// Aarch64(PGD), +// } + +#[derive(Debug, Clone)] +pub enum TopLevelPageTable { + Riscv64 { top_level: PUD }, + Aarch64 { top_level: PGD}, +} + #[derive(Debug, Copy, Clone, PartialEq)] pub struct UntypedObject { pub cap: u64, diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 1b685a0c7..885dc3fc1 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -12,7 +12,7 @@ use loader::Loader; use microkit_tool::{ elf, loader, sdf, sel4, util, DisjointMemoryRegion, FindFixedError, MemoryRegion, ObjectAllocator, Region, UntypedObject, MAX_PDS, MAX_VMS, PD_MAX_NAME_LENGTH, PGD, - VM_MAX_NAME_LENGTH, + PUD,TopLevelPageTable, VM_MAX_NAME_LENGTH, }; use sdf::{ parse, Channel, ProtectionDomain, SysMap, SysMapPerms, SysMemoryRegion, SysMemoryRegionKind, @@ -764,8 +764,7 @@ fn build_system( let initial_task_size = phys_mem_region_from_elf(monitor_elf, config.minimum_page_size).size(); // Create a vector of optional vectors, which we will populate as needed. This maintains the pd_idx mapping. - let mut all_child_page_tables: Vec>> = - vec![None; system.protection_domains.len()]; + let mut all_child_page_tables: Vec>> = vec![None; system.protection_domains.len()]; // If we are mapping the child page tables into the parent, we will create the paging structures // now, so that the pd_elf_size can be properly calculated. @@ -774,7 +773,11 @@ fn build_system( // Flag to enable the patching of child page tables if pd.child_pts { // Initialise the page table structure for this parent pd. - all_child_page_tables[parent_idx] = Some(vec![PGD::new(); 64]); + all_child_page_tables[parent_idx] = match config.arch { + Arch::Aarch64 => {Some(vec![TopLevelPageTable::Aarch64{top_level: PGD::new()}; 64])}, + Arch::Riscv64 => {Some(vec![TopLevelPageTable::Riscv64{top_level: PUD::new()}; 64])}, + }; + // Find all child page tables and find size of loadable segments. for (child_idx, child_pd) in system.protection_domains.iter().enumerate() { if child_idx <= parent_idx { @@ -783,41 +786,86 @@ fn build_system( break; } - let child_pgd: &mut PGD = &mut all_child_page_tables[parent_idx].as_mut().unwrap() + let child_top_table: &mut TopLevelPageTable = &mut all_child_page_tables[parent_idx].as_mut().unwrap() [child_pd.id.unwrap() as usize]; let child_elf = &pd_elf_files[child_idx]; for loadable_segment in child_elf.loadable_segments() { - child_pgd.add_page_at_vaddr_range( - loadable_segment.virt_addr, - loadable_segment.data.len() as i64, - 1, - PageSize::Small, - ); + match child_top_table { + TopLevelPageTable::Aarch64 { top_level } => { + top_level.add_page_at_vaddr_range( + loadable_segment.virt_addr, + loadable_segment.data.len() as i64, + 1, + PageSize::Small, + ); + }, + TopLevelPageTable::Riscv64 { top_level } => { + top_level.add_page_at_vaddr_range( + loadable_segment.virt_addr, + loadable_segment.data.len() as i64, + 1, + PageSize::Small, + ); + } + }; + } // Find all associated memory regions and their size. for child_map in &child_pd.maps { // Find the memory region associated with this map for mr in &system.memory_regions { if mr.name == child_map.mr { - child_pgd.add_page_at_vaddr_range( - child_map.vaddr, - mr.size as i64, - 1, - mr.page_size, - ); + match child_top_table { + TopLevelPageTable::Aarch64 { top_level } => { + top_level.add_page_at_vaddr_range( + child_map.vaddr, + mr.size as i64, + 1, + mr.page_size, + ); + }, + TopLevelPageTable::Riscv64 { top_level } => { + top_level.add_page_at_vaddr_range( + child_map.vaddr, + mr.size as i64, + 1, + mr.page_size, + ); + } + }; } } } + // Account for the stack of each child pd - child_pgd.add_page_at_vaddr_range( - config.pd_stack_bottom(child_pd.stack_size), - child_pd.stack_size as i64, - 1, - PageSize::Small, - ); + match child_top_table { + TopLevelPageTable::Aarch64 { top_level } => { + top_level.add_page_at_vaddr_range( + config.pd_stack_bottom(child_pd.stack_size), + child_pd.stack_size as i64, + 1, + PageSize::Small, + ); + }, + TopLevelPageTable::Riscv64 { top_level } => { + top_level.add_page_at_vaddr_range( + config.pd_stack_bottom(child_pd.stack_size), + child_pd.stack_size as i64, + 1, + PageSize::Small, + ); + } + }; // We have now constructed the dummy page tables, calculate how much size we // need to add to the pd_elf_sizes - pd_extra_elf_size += child_pgd.get_size(); + pd_extra_elf_size += match child_top_table { + TopLevelPageTable::Aarch64 { top_level } => { + top_level.get_size() + }, + TopLevelPageTable::Riscv64 { top_level } => { + top_level.get_size() + } + }; } // We only want to add these new elf regions ONCE. As the microkit tool can run multiple times, // we keep track of we have already built these. @@ -2083,9 +2131,19 @@ fn build_system( let vaddr = mp.vaddr + mr.page_size_bytes() * mr_idx as u64; let minted_cap = frame_cap + mr_idx as u64; - all_child_page_tables[pd_idx].as_mut().unwrap() - [maybe_child_pd.id.unwrap() as usize] - .add_page_at_vaddr(vaddr, minted_cap, mr.page_size); + let mut child_top = &mut all_child_page_tables[pd_idx].as_mut().unwrap() + [maybe_child_pd.id.unwrap() as usize]; + + match child_top { + TopLevelPageTable::Aarch64 { top_level } => { + top_level.add_page_at_vaddr(vaddr, minted_cap, mr.page_size); + }, + TopLevelPageTable::Riscv64 { top_level } => { + top_level.add_page_at_vaddr(vaddr, minted_cap, mr.page_size); + } + }; + + } frame_cap += mr_pages[mr].len() as u64; @@ -2122,8 +2180,16 @@ fn build_system( let mut offset = 0; for i in child_pds { - offset = - all_child_page_tables[pd_idx].as_mut().unwrap()[i].recurse(offset, &mut table_data); + let mut child_top = &mut all_child_page_tables[pd_idx].as_mut().unwrap()[i]; + offset = match child_top { + TopLevelPageTable::Aarch64 { top_level } => { + top_level.recurse(offset, &mut table_data) + }, + TopLevelPageTable::Riscv64 { top_level } => { + top_level.recurse(offset, &mut table_data) + } + }; + table_metadata.pgd[i] = offset - (512 * 8); } From 196da7af9a48fda36f7151ec12e0700c622431d3 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Fri, 17 Oct 2025 12:40:36 +1100 Subject: [PATCH 17/18] elf: use get_segment in populate_segment Signed-off-by: Krishnan Winter --- tool/microkit/src/elf.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/tool/microkit/src/elf.rs b/tool/microkit/src/elf.rs index c74db3f23..18d011262 100644 --- a/tool/microkit/src/elf.rs +++ b/tool/microkit/src/elf.rs @@ -394,20 +394,8 @@ impl ElfFile { } } - pub fn populate_segment(&mut self, segment_name: &str, data: &[u8]) { - // Find segment + pub fn get_segment(&mut self, segment_name: &str) -> Option<&mut ElfSegment> { for segment in self.segments.iter_mut() { - if let Some(name) = &segment.name { - if name == segment_name { - assert!(data.len() <= segment.data.len()); - segment.data = data.to_vec(); - } - } - } - } - - pub fn get_segment(&mut self, segment_name: &str) -> Option<&ElfSegment> { - for segment in &self.segments { if let Some(name) = &segment.name { if name == segment_name { return Some(segment); @@ -416,4 +404,10 @@ impl ElfFile { } None } + + pub fn populate_segment(&mut self, segment_name: &str, data: &[u8]) { + let mut segment = self.get_segment(segment_name).unwrap(); + assert!(data.len() <= segment.data.len()); + segment.data = data.to_vec(); + } } From a3d41d00e80ae217d4e50174872c4fef929ca784 Mon Sep 17 00:00:00 2001 From: Krishnan Winter Date: Fri, 17 Oct 2025 14:14:37 +1100 Subject: [PATCH 18/18] use constants for page table helper functions Signed-off-by: Krishnan Winter --- tool/microkit/src/elf.rs | 4 ++- tool/microkit/src/lib.rs | 63 +++++++++++++++++++++------------------ tool/microkit/src/main.rs | 2 ++ 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/tool/microkit/src/elf.rs b/tool/microkit/src/elf.rs index 18d011262..b9f781e28 100644 --- a/tool/microkit/src/elf.rs +++ b/tool/microkit/src/elf.rs @@ -9,6 +9,7 @@ use std::collections::HashMap; use std::fs; use std::path::Path; use zerocopy::{Immutable, IntoBytes}; +use crate::sel4::PageSize; #[repr(C, packed)] struct ElfHeader32 { @@ -382,7 +383,8 @@ impl ElfFile { } } - last_addr = last_addr + (0x10000 - (last_addr % 0x10000)); + // Align the last address we found to a page boundary + last_addr = last_addr + (PageSize::Small as u64 - (last_addr % PageSize::Small as u64)); ElfSegment { name: Some(segment_name.to_string()), diff --git a/tool/microkit/src/lib.rs b/tool/microkit/src/lib.rs index 3bf6484b1..0deedb42e 100644 --- a/tool/microkit/src/lib.rs +++ b/tool/microkit/src/lib.rs @@ -26,6 +26,18 @@ pub const MAX_VMS: usize = 63; pub const PD_MAX_NAME_LENGTH: usize = 64; pub const VM_MAX_NAME_LENGTH: usize = 64; +// Note that these constants align with the only architectures that we are +// supporting at the moment +pub const PAGE_TABLE_ENTRIES: u64 = 512; +pub const PAGE_TABLE_MASK: u64 = 0x1ff; +pub enum PageTableMaskShift { + PGD = 39, + PUD = 30, + PD = 21, + PT = 12, +} + + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct PGD { puds: Vec>, @@ -40,27 +52,27 @@ impl Default for PGD { impl PGD { pub fn new() -> Self { PGD { - puds: vec![None; 512], + puds: vec![None; PAGE_TABLE_ENTRIES as usize], } } pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { - let mut offset_table: [u64; 512] = [u64::MAX; 512]; + let mut offset_table: [u64; PAGE_TABLE_ENTRIES as usize] = [u64::MAX; PAGE_TABLE_ENTRIES as usize]; for (i, entry) in offset_table.iter_mut().enumerate() { if let Some(pud) = &mut self.puds[i] { curr_offset = pud.recurse(curr_offset, buffer); - *entry = curr_offset - (512 * 8); + *entry = curr_offset - (PAGE_TABLE_ENTRIES * 8); } } for value in &mut offset_table { buffer.append(&mut value.to_le_bytes().to_vec()); } - curr_offset + (512 * 8) + curr_offset + (PAGE_TABLE_ENTRIES * 8) } pub fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { - let pgd_index = ((vaddr & (0x1ff << 39)) >> 39) as usize; + let pgd_index = ((vaddr & (PAGE_TABLE_MASK << PageTableMaskShift::PGD as u64)) >> PageTableMaskShift::PGD as u64) as usize; if self.puds[pgd_index].is_none() { self.puds[pgd_index] = Some(PUD::new()); } @@ -91,7 +103,7 @@ impl PGD { child_size += pud.as_ref().unwrap().get_size(); } } - (512 * 8) + child_size + (PAGE_TABLE_ENTRIES * 8) + child_size } } @@ -103,27 +115,27 @@ pub struct PUD { impl PUD { pub fn new() -> Self { PUD { - dirs: vec![None; 512], + dirs: vec![None; PAGE_TABLE_ENTRIES as usize], } } pub fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { - let mut offset_table: [u64; 512] = [u64::MAX; 512]; + let mut offset_table: [u64; PAGE_TABLE_ENTRIES as usize] = [u64::MAX; PAGE_TABLE_ENTRIES as usize]; for (i, entry) in offset_table.iter_mut().enumerate() { if let Some(dir) = &mut self.dirs[i] { curr_offset = dir.recurse(curr_offset, buffer); - *entry = curr_offset - (512 * 8); + *entry = curr_offset - (PAGE_TABLE_ENTRIES * 8); } } for value in &mut offset_table { buffer.append(&mut value.to_le_bytes().to_vec()); } - curr_offset + (512 * 8) + curr_offset + (PAGE_TABLE_ENTRIES * 8) } pub fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { - let pud_index = ((vaddr & (0x1ff << 30)) >> 30) as usize; + let pud_index = ((vaddr & (PAGE_TABLE_MASK << PageTableMaskShift::PUD as u64)) >> PageTableMaskShift::PUD as u64) as usize; if self.dirs[pud_index].is_none() { self.dirs[pud_index] = Some(DIR::new()); } @@ -154,7 +166,7 @@ impl PUD { child_size += dir.as_ref().unwrap().get_size(); } } - (512 * 8) + child_size + (PAGE_TABLE_ENTRIES * 8) + child_size } } @@ -172,21 +184,20 @@ pub struct DIR { impl DIR { fn new() -> Self { DIR { - entries: vec![None; 512], + entries: vec![None; PAGE_TABLE_ENTRIES as usize], } } fn recurse(&mut self, mut curr_offset: u64, buffer: &mut Vec) -> u64 { - let mut offset_table: [u64; 512] = [u64::MAX; 512]; + let mut offset_table: [u64; PAGE_TABLE_ENTRIES as usize] = [u64::MAX; PAGE_TABLE_ENTRIES as usize]; for (i, dir_entry) in offset_table.iter_mut().enumerate() { if let Some(entry) = &mut self.entries[i] { match entry { DirEntry::PageTable(x) => { curr_offset = x.recurse(curr_offset, buffer); - *dir_entry = curr_offset - (512 * 8); + *dir_entry = curr_offset - (PAGE_TABLE_ENTRIES * 8); } DirEntry::LargePage(x) => { - // curr_offset += 8; // we mark the top bit to signal to the pd that this is a large page *dir_entry = *x | (1 << 63); } @@ -197,11 +208,11 @@ impl DIR { for value in &mut offset_table { buffer.append(&mut value.to_le_bytes().to_vec()); } - curr_offset + (512 * 8) + curr_offset + (PAGE_TABLE_ENTRIES * 8) } fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { - let dir_index = ((vaddr & (0x1ff << 21)) >> 21) as usize; + let dir_index = ((vaddr & (PAGE_TABLE_MASK << PageTableMaskShift::PD as u64)) >> PageTableMaskShift::PD as u64) as usize; match size { PageSize::Small => { if self.entries[dir_index].is_none() { @@ -232,7 +243,7 @@ impl DIR { child_size += x.get_size(); } } - (512 * 8) + child_size + (PAGE_TABLE_ENTRIES * 8) + child_size } } @@ -245,7 +256,7 @@ pub struct PT { impl PT { fn new() -> Self { PT { - pages: vec![u64::MAX; 512], + pages: vec![u64::MAX; PAGE_TABLE_ENTRIES as usize], large_page: u64::MAX, } } @@ -254,27 +265,21 @@ impl PT { for value in &mut self.pages { buffer.append(&mut value.to_le_bytes().to_vec()); } - curr_offset + (512 * 8) + curr_offset + (PAGE_TABLE_ENTRIES * 8) } fn add_page_at_vaddr(&mut self, vaddr: u64, frame: u64, size: PageSize) { - let pt_index = ((vaddr & (0x1ff << 12)) >> 12) as usize; + let pt_index = ((vaddr & (PAGE_TABLE_MASK << PageTableMaskShift::PT as u64)) >> PageTableMaskShift::PT as u64) as usize; // Unconditionally overwrite. assert!(size == PageSize::Small); self.pages[pt_index] = frame; } fn get_size(&self) -> u64 { - 512 * 8 + PAGE_TABLE_ENTRIES * 8 } } -// #[derive(Debug, Clone)] -// pub enum TopLevelPageTable { -// Riscv64(PUD), -// Aarch64(PGD), -// } - #[derive(Debug, Clone)] pub enum TopLevelPageTable { Riscv64 { top_level: PUD }, diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 885dc3fc1..bd1ffae92 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -790,6 +790,7 @@ fn build_system( [child_pd.id.unwrap() as usize]; let child_elf = &pd_elf_files[child_idx]; for loadable_segment in child_elf.loadable_segments() { + // Adding placeholder cap "1", we will populate the actual caps once they have been allocated match child_top_table { TopLevelPageTable::Aarch64 { top_level } => { top_level.add_page_at_vaddr_range( @@ -815,6 +816,7 @@ fn build_system( // Find the memory region associated with this map for mr in &system.memory_regions { if mr.name == child_map.mr { + // Adding placeholder cap "1", we will populate the actual caps once they have been allocated match child_top_table { TopLevelPageTable::Aarch64 { top_level } => { top_level.add_page_at_vaddr_range(