pvmfw: Rework DeviceAssignmentError::InvalidReg

Embed the region information in the error variant and distinguish
between rejecting the virtual or physical range.

Test: atest libpvmfw.device_assignment.test
Change-Id: I4d88bc0490804dd7c9d174cfe590119feb3cff7e
diff --git a/pvmfw/src/device_assignment.rs b/pvmfw/src/device_assignment.rs
index fb00e72..edfe000 100644
--- a/pvmfw/src/device_assignment.rs
+++ b/pvmfw/src/device_assignment.rs
@@ -55,8 +55,10 @@
     InvalidSymbols,
     /// Malformed <reg>. Can't parse.
     MalformedReg,
-    /// Invalid <reg>. Failed to validate with HVC.
-    InvalidReg,
+    /// Invalid physical <reg> of assigned device.
+    InvalidPhysReg(u64, u64),
+    /// Invalid virtual <reg> of assigned device.
+    InvalidReg(u64, u64),
     /// Invalid <interrupts>
     InvalidInterrupts,
     /// Malformed <iommus>
@@ -104,7 +106,12 @@
                 "Invalid property in /__symbols__. Must point to valid assignable device node."
             ),
             Self::MalformedReg => write!(f, "Malformed <reg>. Can't parse"),
-            Self::InvalidReg => write!(f, "Invalid <reg>. Failed to validate with hypervisor"),
+            Self::InvalidReg(addr, size) => {
+                write!(f, "Invalid guest MMIO region (addr: {addr:#x}, size: {size:#x})")
+            }
+            Self::InvalidPhysReg(addr, size) => {
+                write!(f, "Invalid physical MMIO region (addr: {addr:#x}, size: {size:#x})")
+            }
             Self::InvalidInterrupts => write!(f, "Invalid <interrupts>"),
             Self::MalformedIommus => write!(f, "Malformed <iommus>. Can't parse."),
             Self::InvalidIommus => {
@@ -521,21 +528,29 @@
         physical_device_reg: &[DeviceReg],
         hypervisor: &dyn DeviceAssigningHypervisor,
     ) -> Result<()> {
-        if device_reg.len() != physical_device_reg.len() {
-            return Err(DeviceAssignmentError::InvalidReg);
-        }
+        let mut virt_regs = device_reg.iter();
+        let mut phys_regs = physical_device_reg.iter();
         // PV reg and physical reg should have 1:1 match in order.
-        for (reg, phys_reg) in device_reg.iter().zip(physical_device_reg.iter()) {
+        for (reg, phys_reg) in virt_regs.by_ref().zip(phys_regs.by_ref()) {
             let addr = hypervisor.get_phys_mmio_token(reg.addr, reg.size).map_err(|e| {
                 error!("Hypervisor error while requesting MMIO token: {e}");
-                DeviceAssignmentError::InvalidReg
+                DeviceAssignmentError::InvalidReg(reg.addr, reg.size)
             })?;
             // Only check address because hypervisor guaranatees size match when success.
             if phys_reg.addr != addr {
-                error!("Failed to validate device <reg>. No matching phys reg for reg={reg:x?}");
-                return Err(DeviceAssignmentError::InvalidReg);
+                error!("Assigned device {reg:x?} has unexpected physical address");
+                return Err(DeviceAssignmentError::InvalidPhysReg(addr, reg.size));
             }
         }
+
+        if let Some(DeviceReg { addr, size }) = virt_regs.next() {
+            return Err(DeviceAssignmentError::InvalidReg(*addr, *size));
+        }
+
+        if let Some(DeviceReg { addr, size }) = phys_regs.next() {
+            return Err(DeviceAssignmentError::InvalidPhysReg(*addr, *size));
+        }
+
         Ok(())
     }
 
@@ -1308,7 +1323,7 @@
         };
         let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor);
 
-        assert_eq!(device_info, Err(DeviceAssignmentError::InvalidReg));
+        assert_eq!(device_info, Err(DeviceAssignmentError::InvalidReg(0x9, 0xFF)));
     }
 
     #[test]
@@ -1324,7 +1339,7 @@
         };
         let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor);
 
-        assert_eq!(device_info, Err(DeviceAssignmentError::InvalidReg));
+        assert_eq!(device_info, Err(DeviceAssignmentError::InvalidPhysReg(0xF10000, 0x1000)));
     }
 
     #[test]