Sergii Dmytruk has uploaded this change for review.

View Change

[RFC] tests: add tests for OTP regions

Change-Id: I4ff584395367dfd52db89332d8e45d7e865276e1
Signed-off-by: Hatim Kanchwala <hatim at hatimak.me>
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
---
A tests/chip_otp.c
M tests/meson.build
M tests/tests.c
M tests/tests.h
4 files changed, 403 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/flashrom refs/changes/06/59406/1
diff --git a/tests/chip_otp.c b/tests/chip_otp.c
new file mode 100644
index 0000000..f0bc591
--- /dev/null
+++ b/tests/chip_otp.c
@@ -0,0 +1,380 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2021 3mdeb Embedded Systems Consulting
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <include/test.h>
+#include <string.h>
+
+#include "chipdrivers.h"
+#include "flash.h"
+#include "libflashrom.h"
+#include "otp.h"
+#include "programmer.h"
+
+/*
+ * Tests in this file do not use any mocking, because using OTP emulation in
+ * dummyflasher programmer is sufficient
+ */
+
+enum { MAX_REGION_SIZE = 512 };
+
+/* This data is used in multiple tests */
+static uint8_t empty[MAX_REGION_SIZE];
+static uint8_t image[MAX_REGION_SIZE];
+
+static void setup(struct flashrom_flashctx *flash, struct flashchip *chip, const char *programmer_param)
+{
+ flash->chip = chip;
+
+ assert_int_equal(0, programmer_init(&programmer_dummy, programmer_param));
+ /* Assignment below normally happens while probing, but this test is not probing. */
+ flash->mst = &registered_masters[0];
+
+ for (unsigned int i = 0; i < MAX_REGION_SIZE; i++) {
+ empty[i] = 0xff;
+ image[i] = i;
+ }
+}
+
+static void teardown(void)
+{
+ assert_int_equal(0, programmer_shutdown());
+}
+
+/* Setup the struct for W25Q128.V, all values come from flashchips.c */
+static const struct flashchip chip_W25Q40_V = {
+ .vendor = "aklm&dummyflasher",
+ .total_size = 512,
+ .tested = TEST_OK_PREW,
+ .read = spi_chip_read,
+ .write = spi_chip_write_256,
+ .unlock = spi_disable_blockprotect,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_RDSR2 |
+ FEATURE_WRSR_EXT,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 128} },
+ .block_erase = spi_block_erase_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 16} },
+ .block_erase = spi_block_erase_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 8} },
+ .block_erase = spi_block_erase_d8,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = spi_block_erase_60,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = spi_block_erase_c7,
+ }
+ },
+ .otp = &gd_w256_3_otp,
+};
+
+/* Setup the struct for EN25QH128, all values come from flashchips.c */
+static const struct flashchip chip_EN25QH128 = {
+ .vendor = "aklm&dummyflasher",
+ .total_size = 16384,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 4096} },
+ .block_erase = spi_block_erase_20,
+ }, {
+ .eraseblocks = { {64 * 1024, 256} },
+ .block_erase = spi_block_erase_d8,
+ }, {
+ .eraseblocks = { { 16384 * 1024, 1} },
+ .block_erase = spi_block_erase_60,
+ }, {
+ .eraseblocks = { { 16384 * 1024, 1} },
+ .block_erase = spi_block_erase_c7,
+ }
+ },
+ .unlock = spi_disable_blockprotect_bp3_srwd,
+ .write = spi_chip_write_256,
+ .read = spi_chip_read,
+ .otp = &en512_16384otp,
+};
+
+void otp_regs_status_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q40_V;
+
+ char *param_dup = strdup("bus=spi,emulate=W25Q40.V");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ assert_true(flashrom_otp_chip_supported(&flash));
+
+ size_t nregions;
+ struct flashrom_otp_region regions[FLASHROM_OTP_MAX_REGIONS];
+ assert_int_equal(0, flashrom_otp_get_regions(&flash, regions, &nregions));
+ assert_int_equal(3, nregions);
+ assert_int_equal(256, regions[0].size);
+ assert_false(regions[0].locked);
+ assert_int_equal(256, regions[1].size);
+ assert_false(regions[1].locked);
+ assert_int_equal(256, regions[2].size);
+ assert_false(regions[2].locked);
+
+ bool locked;
+ assert_int_equal(0, flashrom_otp_status(&flash, 0, &locked));
+ assert_false(locked);
+ assert_int_equal(0, flashrom_otp_status(&flash, 1, &locked));
+ assert_false(locked);
+ assert_int_equal(0, flashrom_otp_status(&flash, 2, &locked));
+ assert_false(locked);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_mode_status_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_EN25QH128;
+
+ char *param_dup = strdup("bus=spi,emulate=EN25QH128");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ assert_true(flashrom_otp_chip_supported(&flash));
+
+ size_t nregions;
+ struct flashrom_otp_region regions[FLASHROM_OTP_MAX_REGIONS];
+ assert_int_equal(0, flashrom_otp_get_regions(&flash, regions, &nregions));
+ assert_int_equal(1, nregions);
+ assert_int_equal(512, regions[0].size);
+ assert_false(regions[0].locked);
+
+ bool locked;
+ assert_int_equal(0, flashrom_otp_status(&flash, 0, &locked));
+ assert_false(locked);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_regs_locking_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q40_V;
+
+ char *param_dup = strdup("bus=spi,emulate=W25Q40.V");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ assert_int_equal(0, flashrom_otp_lock(&flash, 0));
+ assert_int_equal(0, flashrom_otp_lock(&flash, 2));
+ /* No such regions */
+ assert_int_equal(1, flashrom_otp_lock(&flash, -1));
+ assert_int_equal(1, flashrom_otp_lock(&flash, 3));
+
+ size_t nregions;
+ struct flashrom_otp_region regions[FLASHROM_OTP_MAX_REGIONS];
+ assert_int_equal(0, flashrom_otp_get_regions(&flash, regions, &nregions));
+ assert_int_equal(3, nregions);
+ assert_int_equal(256, regions[0].size);
+ assert_true(regions[0].locked);
+ assert_int_equal(256, regions[1].size);
+ assert_false(regions[1].locked);
+ assert_int_equal(256, regions[2].size);
+ assert_true(regions[2].locked);
+
+ assert_int_equal(0, flashrom_otp_lock(&flash, 1));
+
+ bool locked;
+ assert_int_equal(0, flashrom_otp_status(&flash, 0, &locked));
+ assert_true(locked);
+ assert_int_equal(0, flashrom_otp_status(&flash, 1, &locked));
+ assert_true(locked);
+ assert_int_equal(0, flashrom_otp_status(&flash, 2, &locked));
+ assert_true(locked);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_mode_locking_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_EN25QH128;
+
+ char *param_dup = strdup("bus=spi,emulate=EN25QH128");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ assert_int_equal(0, flashrom_otp_lock(&flash, 0));
+
+ size_t nregions;
+ struct flashrom_otp_region regions[FLASHROM_OTP_MAX_REGIONS];
+ assert_int_equal(0, flashrom_otp_get_regions(&flash, regions, &nregions));
+ assert_int_equal(1, nregions);
+ assert_int_equal(512, regions[0].size);
+ assert_true(regions[0].locked);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_regs_ops_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ enum { REGION_SIZE = 256 };
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q40_V;
+ uint8_t buf[REGION_SIZE];
+
+ char *param_dup = strdup("bus=spi,emulate=W25Q40.V");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ /* Write image for the first region */
+ assert_int_equal(0, flashrom_otp_write(&flash, 0, image, REGION_SIZE));
+
+ /* Check that we read back what we've written */
+ assert_int_equal(0, flashrom_otp_read(&flash, 0, buf, REGION_SIZE));
+ assert_memory_equal(buf, image, REGION_SIZE);
+
+ /* Check that other regions are still empty */
+ assert_int_equal(0, flashrom_otp_read(&flash, 1, buf, REGION_SIZE));
+ assert_memory_equal(buf, empty, REGION_SIZE);
+ assert_int_equal(0, flashrom_otp_read(&flash, 2, buf, REGION_SIZE));
+ assert_memory_equal(buf, empty, REGION_SIZE);
+
+ /* Can erase regions */
+ assert_int_equal(0, flashrom_otp_erase(&flash, 0));
+ assert_int_equal(0, flashrom_otp_read(&flash, 0, buf, REGION_SIZE));
+ assert_memory_equal(buf, empty, REGION_SIZE);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_mode_ops_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ enum { REGION_SIZE = 512 };
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_EN25QH128;
+ uint8_t buf[REGION_SIZE];
+
+ char *param_dup = strdup("bus=spi,emulate=EN25QH128");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ /* Write image */
+ assert_int_equal(0, flashrom_otp_write(&flash, 0, image, REGION_SIZE));
+
+ /* Check that we read back what we've written */
+ assert_int_equal(0, flashrom_otp_read(&flash, 0, buf, REGION_SIZE));
+ assert_memory_equal(buf, image, REGION_SIZE);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_regs_in_locked_state_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ enum { REGION_SIZE = 256 };
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q40_V;
+ uint8_t buf[REGION_SIZE];
+
+ char *param_dup = strdup("bus=spi,emulate=W25Q40.V");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ /* Write first region and lock it */
+ assert_int_equal(0, flashrom_otp_write(&flash, 0, image, REGION_SIZE));
+ assert_int_equal(0, flashrom_otp_lock(&flash, 0));
+
+ /* Lost ability to write or erase it */
+ assert_int_equal(1, flashrom_otp_write(&flash, 0, image, REGION_SIZE));
+ assert_int_equal(1, flashrom_otp_erase(&flash, 0));
+
+ /* Can still write or erase other regions */
+ assert_int_equal(0, flashrom_otp_write(&flash, 1, image, REGION_SIZE));
+ assert_int_equal(0, flashrom_otp_write(&flash, 2, image, REGION_SIZE));
+ assert_int_equal(0, flashrom_otp_erase(&flash, 1));
+ assert_int_equal(0, flashrom_otp_erase(&flash, 2));
+
+ /* Region's content is correct after all manipulations */
+ assert_int_equal(0, flashrom_otp_read(&flash, 0, buf, REGION_SIZE));
+ assert_memory_equal(buf, image, REGION_SIZE);
+
+ teardown();
+
+ free(param_dup);
+}
+
+void otp_mode_in_locked_state_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ enum { REGION_SIZE = 512 };
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_EN25QH128;
+ uint8_t buf[REGION_SIZE];
+
+ char *param_dup = strdup("bus=spi,emulate=EN25QH128");
+
+ setup(&flash, &mock_chip, param_dup);
+
+ /* Write first region and lock it */
+ assert_int_equal(0, flashrom_otp_write(&flash, 0, image, REGION_SIZE));
+ assert_int_equal(0, flashrom_otp_lock(&flash, 0));
+
+ /* Lost ability to write or erase it */
+ assert_int_equal(1, flashrom_otp_write(&flash, 0, image, REGION_SIZE));
+ assert_int_equal(1, flashrom_otp_erase(&flash, 0));
+
+ /* Region's content is correct after all manipulations */
+ assert_int_equal(0, flashrom_otp_read(&flash, 0, buf, REGION_SIZE));
+ assert_memory_equal(buf, image, REGION_SIZE);
+
+ teardown();
+
+ free(param_dup);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 1cfef87..84fd336 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -24,6 +24,7 @@
'layout.c',
'chip.c',
'chip_wp.c',
+ 'chip_otp.c',
]

mocks = [
diff --git a/tests/tests.c b/tests/tests.c
index 981b73f..29329c2 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -368,5 +368,17 @@
};
ret |= cmocka_run_group_tests_name("chip_wp.c tests", chip_wp_tests, NULL, NULL);

+ const struct CMUnitTest chip_otp_tests[] = {
+ cmocka_unit_test(otp_regs_status_dummyflasher_test_success),
+ cmocka_unit_test(otp_mode_status_dummyflasher_test_success),
+ cmocka_unit_test(otp_regs_locking_dummyflasher_test_success),
+ cmocka_unit_test(otp_mode_locking_dummyflasher_test_success),
+ cmocka_unit_test(otp_regs_ops_dummyflasher_test_success),
+ cmocka_unit_test(otp_mode_ops_dummyflasher_test_success),
+ cmocka_unit_test(otp_regs_in_locked_state_test_success),
+ cmocka_unit_test(otp_mode_in_locked_state_test_success),
+ };
+ ret |= cmocka_run_group_tests_name("chip_otp.c tests", chip_otp_tests, NULL, NULL);
+
return ret;
}
diff --git a/tests/tests.h b/tests/tests.h
index 6ba44a9..ad1091d 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -76,4 +76,14 @@
void full_chip_erase_with_wp_dummyflasher_test_success(void **state);
void partial_chip_erase_with_wp_dummyflasher_test_success(void **state);

+/* chip_otp.c */
+void otp_regs_status_dummyflasher_test_success(void **state);
+void otp_mode_status_dummyflasher_test_success(void **state);
+void otp_regs_locking_dummyflasher_test_success(void **state);
+void otp_mode_locking_dummyflasher_test_success(void **state);
+void otp_regs_ops_dummyflasher_test_success(void **state);
+void otp_mode_ops_dummyflasher_test_success(void **state);
+void otp_regs_in_locked_state_test_success(void **state);
+void otp_mode_in_locked_state_test_success(void **state);
+
#endif /* TESTS_H */

To view, visit change 59406. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I4ff584395367dfd52db89332d8e45d7e865276e1
Gerrit-Change-Number: 59406
Gerrit-PatchSet: 1
Gerrit-Owner: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Gerrit-MessageType: newchange