Heki {
+ /// HEKI handler for locking VTL0's control registers
+ pub fn lock_regs(&self) -> Result {
+ self.gate.lock_control_registers()?;
+ Ok(0)
+ }
+
+ /// HEKI handler for protecting certain memory ranges (e.g., kernel text, data, heap).
+ /// `pa` and `nranges` specify a memory area containing the information about the memory ranges to protect.
+ pub fn protect_memory(&self, pa: u64, nranges: u64) -> Result {
+ if PhysAddr::try_new(pa)
+ .ok()
+ .as_ref()
+ .is_none_or(|p| !p.is_aligned(Size4KiB::SIZE))
+ || nranges == 0
+ {
+ return Err(VsmError::InvalidInputAddress);
+ }
+
+ if self.gate.end_of_boot_reached() {
+ return Err(VsmError::OperationAfterEndOfBoot(
+ "kernel memory protection",
+ ));
+ }
+
+ let heki_pages = copy_heki_pages_from_vtl0(&self.gate, pa, nranges)
+ .ok_or(VsmError::HekiPagesCopyFailed)?;
+
+ for heki_page in heki_pages {
+ for heki_range in &heki_page {
+ let pa = heki_range.pa;
+ let epa = heki_range.epa;
+ let mem_attr = heki_range
+ .mem_attr()
+ .ok_or(VsmError::MemoryAttributeInvalid)?;
+
+ if !heki_range.is_aligned(Size4KiB::SIZE) {
+ return Err(VsmError::AddressNotPageAligned);
+ }
+
+ let va = heki_range.va;
+ log::debug!(
+ "HEKI: Protect memory: va {:#x} pa {:#x} epa {:#x} {:?} (size: {})",
+ va,
+ pa,
+ epa,
+ mem_attr,
+ epa - pa
+ );
+
+ if pa == epa {
+ continue;
+ }
+
+ self.gate.protect_frames(
+ PhysFrame::range(
+ // `HekiRange::is_valid` already validated both physical addresses.
+ PhysFrame::containing_address(PhysAddr::new(pa)),
+ PhysFrame::containing_address(PhysAddr::new(epa)),
+ ),
+ mem_attr,
+ )?;
+ }
+ }
+ Ok(0)
+ }
+
+ /// HEKI handler for loading kernel data (e.g., certificates, blocklist, kernel symbols) into VTL1.
+ /// `pa` and `nranges` specify memory areas containing the information about the memory ranges to load.
+ pub fn load_kdata(&self, pa: u64, nranges: u64) -> Result