pvmfw: Refactor to add config::Range

config::Range ensures non-zero length and also derives Copy.
Validation after instantations can be removed.

Bug: N/A
Test: Build and run protected VM
Change-Id: I84f0ca0fd8240d9fc376224e4c28df1fef5ea230
diff --git a/pvmfw/src/config.rs b/pvmfw/src/config.rs
index d0a6b7f..2451ec9 100644
--- a/pvmfw/src/config.rs
+++ b/pvmfw/src/config.rs
@@ -16,6 +16,7 @@
 
 use core::fmt;
 use core::mem;
+use core::num::NonZeroUsize;
 use core::ops::Range;
 use core::result;
 use log::{info, warn};
@@ -133,19 +134,6 @@
     size: u32,
 }
 
-impl HeaderEntry {
-    pub fn as_range(&self) -> Option<Range<usize>> {
-        let size = usize::try_from(self.size).unwrap();
-        if size != 0 {
-            let offset = self.offset.try_into().unwrap();
-            // Allow overflows here for the Range to properly describe the entry (validated later).
-            Some(offset..(offset + size))
-        } else {
-            None
-        }
-    }
-}
-
 #[repr(C, packed)]
 #[derive(Clone, Copy, Debug, Eq, FromBytes, PartialEq)]
 pub struct Version {
@@ -161,10 +149,38 @@
     }
 }
 
+/// Range with non-empty length.
+#[derive(Debug, Copy, Clone)]
+struct NonEmptyRange {
+    start: usize,
+    size: NonZeroUsize,
+}
+
+impl NonEmptyRange {
+    pub fn new(start: usize, size: usize) -> Option<Self> {
+        // Ensure end() is safe.
+        start.checked_add(size).unwrap();
+
+        Some(Self { start, size: NonZeroUsize::new(size)? })
+    }
+
+    fn end(&self) -> usize {
+        self.start + self.len()
+    }
+
+    fn len(&self) -> usize {
+        self.size.into()
+    }
+
+    fn as_range(&self) -> Range<usize> {
+        self.start..self.end()
+    }
+}
+
 #[derive(Debug)]
 pub struct Config<'a> {
     body: &'a mut [u8],
-    ranges: [Option<Range<usize>>; Entry::COUNT],
+    ranges: [Option<NonEmptyRange>; Entry::COUNT],
 }
 
 impl<'a> Config<'a> {
@@ -209,14 +225,24 @@
         // Validate that we won't get an invalid alignment in the following due to padding to u64.
         const_assert_eq!(mem::size_of::<HeaderEntry>() % mem::size_of::<u64>(), 0);
 
+        // Ensure entries are in the body.
         let limits = header.body_lowest_bound()?..total_size;
-        let ranges = [
-            // TODO: Find a way to do this programmatically even if the trait
-            // `core::marker::Copy` is not implemented for `core::ops::Range<usize>`.
-            Self::validated_body_range(Entry::Bcc, &header_entries, &limits)?,
-            Self::validated_body_range(Entry::DebugPolicy, &header_entries, &limits)?,
-            Self::validated_body_range(Entry::VmDtbo, &header_entries, &limits)?,
-        ];
+        let mut ranges: [Option<NonEmptyRange>; Entry::COUNT] = [None; Entry::COUNT];
+        for entry in [Entry::Bcc, Entry::DebugPolicy, Entry::VmDtbo] {
+            let Some(header_entry) = header_entries.get(entry as usize) else { continue };
+            let entry_offset = header_entry.offset.try_into().unwrap();
+            let entry_size = header_entry.size.try_into().unwrap();
+            let Some(range) = NonEmptyRange::new(entry_offset, entry_size) else { continue };
+            let range = range.as_range();
+            if !range.is_within(&limits) {
+                return Err(Error::EntryOutOfBounds(entry, range, limits));
+            }
+
+            ranges[entry as usize] = NonEmptyRange::new(
+                entry_offset - limits.start, // is_within() validates safety of this.
+                entry_size,
+            );
+        }
 
         Ok(Self { body, ranges })
     }
@@ -237,7 +263,7 @@
         let (bcc, rest) = rest.split_at_mut(bcc_end);
 
         let dp = if let Some(dp_range) = dp_range {
-            let dp_start = dp_range.start.checked_sub(bcc_range.end).unwrap();
+            let dp_start = dp_range.start.checked_sub(bcc_range.end()).unwrap();
             let dp_end = dp_range.len();
             let (_, rest) = rest.split_at_mut(dp_start);
             let (dp, _) = rest.split_at_mut(dp_end);
@@ -249,28 +275,7 @@
         Ok((bcc, dp))
     }
 
-    pub fn get_entry_range(&self, entry: Entry) -> Option<Range<usize>> {
-        self.ranges[entry as usize].clone()
-    }
-
-    fn validated_body_range(
-        entry: Entry,
-        header_entries: &[HeaderEntry],
-        limits: &Range<usize>,
-    ) -> Result<Option<Range<usize>>> {
-        if let Some(header_entry) = header_entries.get(entry as usize) {
-            if let Some(r) = header_entry.as_range() {
-                return if r.start <= r.end && r.is_within(limits) {
-                    let start = r.start - limits.start;
-                    let end = r.end - limits.start;
-
-                    Ok(Some(start..end))
-                } else {
-                    Err(Error::EntryOutOfBounds(entry, r, limits.clone()))
-                };
-            }
-        }
-
-        Ok(None)
+    fn get_entry_range(&self, entry: Entry) -> Option<NonEmptyRange> {
+        self.ranges[entry as usize]
     }
 }