pvmfw: Receive payload location from DT

To unify the cases where pvmfw is loaded into pVM address space by pKVM
(the VMM is then allowed to set registers x1 and x2) or by the VMM
itself (all registers except x0 are silently zeroed by pKVM), locate the
pre-loaded kernel through the DT, in a similar way to the ramdisk.

Keep supporting the x1/x2 ABI when the legacy feature is enabled.

Bug: 253616035
Test: Boot pvmfw & check logs with a crosvm with crrev.com/c/4064759
Change-Id: I74d3e52025fa1fbc5e74246e9fb09a7fb46222a0
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 5b9efd2..dcd17b7 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -17,6 +17,24 @@
 use core::ffi::CStr;
 use core::ops::Range;
 
+/// Extract from /config the address range containing the pre-loaded kernel.
+pub fn kernel_range(fdt: &libfdt::Fdt) -> libfdt::Result<Option<Range<usize>>> {
+    let config = CStr::from_bytes_with_nul(b"/config\0").unwrap();
+    let addr = CStr::from_bytes_with_nul(b"kernel-address\0").unwrap();
+    let size = CStr::from_bytes_with_nul(b"kernel-size\0").unwrap();
+
+    if let Some(config) = fdt.node(config)? {
+        if let (Some(addr), Some(size)) = (config.getprop_u32(addr)?, config.getprop_u32(size)?) {
+            let addr = addr as usize;
+            let size = size as usize;
+
+            return Ok(Some(addr..(addr + size)));
+        }
+    }
+
+    Ok(None)
+}
+
 /// Extract from /chosen the address range containing the pre-loaded ramdisk.
 pub fn initrd_range(fdt: &libfdt::Fdt) -> libfdt::Result<Option<Range<usize>>> {
     let start = CStr::from_bytes_with_nul(b"linux,initrd-start\0").unwrap();