hw/block/pflash_cfi02: Fix command address comparison
Most AMD commands only examine 11 bits of the address. This masks the
addresses used in the comparison to 11 bits. The exceptions are word or
sector addresses which use offset directly rather than the shifted
offset, boff.
Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-4-stephen.checkoway@oberlin.edu>
Acked-by: Thomas Huth <thuth@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index e64dc69c..4be3837 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -281,11 +281,13 @@
}
offset &= pfl->chip_len - 1;
- boff = offset & (pfl->sector_len - 1);
+ boff = offset;
if (pfl->width == 2)
boff = boff >> 1;
else if (pfl->width == 4)
boff = boff >> 2;
+ /* Only the least-significant 11 bits are used in most cases. */
+ boff &= 0x7FF;
switch (pfl->wcycle) {
case 0:
/* Set the device in I/O access mode if required */
@@ -538,6 +540,10 @@
}
}
+ /* Only 11 bits are used in the comparison. */
+ pfl->unlock_addr0 &= 0x7FF;
+ pfl->unlock_addr1 &= 0x7FF;
+
pflash_setup_mappings(pfl);
pfl->rom_mode = 1;
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index e7e16a8..e090b2e 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -21,8 +21,8 @@
#define FLASH_WIDTH 2
#define CFI_ADDR (FLASH_WIDTH * 0x55)
-#define UNLOCK0_ADDR (FLASH_WIDTH * 0x5555)
-#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AAA)
+#define UNLOCK0_ADDR (FLASH_WIDTH * 0x555)
+#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AA)
#define CFI_CMD 0x98
#define UNLOCK0_CMD 0xAA
@@ -190,6 +190,14 @@
g_assert_cmphex(flash_read(6), ==, 0xCDEF);
g_assert_cmphex(flash_read(8), ==, 0xFFFF);
+ /* Test ignored high order bits of address. */
+ flash_write(FLASH_WIDTH * 0x5555, UNLOCK0_CMD);
+ flash_write(FLASH_WIDTH * 0x2AAA, UNLOCK1_CMD);
+ flash_write(FLASH_WIDTH * 0x5555, AUTOSELECT_CMD);
+ g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
+ g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
+ reset();
+
qtest_quit(global_qtest);
}