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)