Add backend_adjust_offset to avoid the windows overlap

In mihawk, the windows overlap will cause the cache coherence.
Hostboot writes the SPD data to BMC through a window and read it
back with another window. It causes the data missed and DIMM lost.

Hostboot log
   23.80714|<<DBG-956|SPD::getMemType() - MemType: 0xff, Error: NoHUID: 0x30008.

BMC log: The overlaped windows
  Window @ 0x756e0000 for size 0x00046000 maps flash offset 0x000e7000
  Window @ 0x757e0000 for size 0x00048000 maps flash offset 0x000e5000

Tested: 1. In mihawk, it can fix the SPD cache coherence issue
        2. Add unit test to verify VPNOR offset alignment

Change-Id: I92670ade4e2a91b5c49a0acabfc0456f90d49b93
Signed-off-by: Alvin Wang <alvinwang@msn.com>
[AJ: Remove some MSG_INFO() spam, fix whitespace issues]
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/vpnor/backend.cpp b/vpnor/backend.cpp
index f1b2c63..43591db 100644
--- a/vpnor/backend.cpp
+++ b/vpnor/backend.cpp
@@ -419,6 +419,8 @@
         const pnor_partition& part = priv->vpnor->table->partition(offset);
         if (vpnor_partition_is_readonly(part))
         {
+            MSG_DBG("Try to write read only partition (part=%s, offset=0x%x)\n",
+                    part.data.name, offset);
             return -EPERM;
         }
     }
@@ -462,6 +464,47 @@
     return reset_lpc_memory;
 }
 
+/*
+ * vpnor_align_offset() - Align the offset
+ * @context:    The backend context pointer
+ * @offset:	The flash offset
+ * @window_size:The window size
+ *
+ * Return:      0 on success otherwise negative error code
+ */
+static int vpnor_align_offset(struct backend* backend, uint32_t* offset,
+                              uint32_t window_size)
+{
+    const struct vpnor_data* priv = (const struct vpnor_data*)backend->priv;
+
+    /* Adjust the offset to align with the offset of partition base */
+    try
+    {
+        // Get the base of the partition
+        const pnor_partition& part = priv->vpnor->table->partition(*offset);
+        uint32_t base = part.data.base * VPNOR_ERASE_SIZE;
+
+        // Get the base offset relative to the window_size
+        uint32_t base_offset = base & (window_size - 1);
+
+        // Adjust the offset to align with the base
+        *offset = ((*offset - base_offset) & ~(window_size - 1)) + base_offset;
+        MSG_DBG(
+            "vpnor_align_offset: to @ 0x%.8x(base=0x%.8x base_offset=0x%.8x)\n",
+            *offset, base, base_offset);
+        return 0;
+    }
+    catch (const openpower::virtual_pnor::UnmappedOffset& e)
+    {
+        /*
+         * Writes to unmapped areas are not meaningful, so deny the request.
+         * This removes the ability for a compromised host to abuse unused
+         * space if any data was to be persisted (which it isn't).
+         */
+        return -EACCES;
+    }
+}
+
 static const struct backend_ops vpnor_ops = {
     .init = vpnor_dev_init,
     .free = vpnor_free,
@@ -471,6 +514,7 @@
     .write = vpnor_write,
     .validate = vpnor_validate,
     .reset = vpnor_reset,
+    .align_offset = vpnor_align_offset,
 };
 
 struct backend backend_get_vpnor(void)