summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWai-Hong Tam <waihong@google.com>2022-08-25 09:18:19 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-08-25 17:56:30 +0000
commit5ef5865465e3e03e7cdb75c7b875796a6b65af1b (patch)
tree348a7f3aaa7de1c2cb4f2fa7f5bad23193a548d2
parente79a44fa76c50c65e330766b7830bebae5f901a9 (diff)
downloadchrome-ec-5ef5865465e3e03e7cdb75c7b875796a6b65af1b.tar.gz
zephyr: test: Emulate flash write and erase and add the test cases
Implement the flash write and erase functions in the flash emulator. The functions call the underlying flash controller to execute. Add the simple test cases to exercise the flash write and erase, and then readback the data to compare the results. BRANCH=None BUG=b:236075787, b:236075595, b:236075283 TEST=./twister -s zephyr/test/drivers/drivers.default Change-Id: I50cb83c19382362c86a319d0feefa683f6b216bf Signed-off-by: Wai-Hong Tam <waihong@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3857443 Reviewed-by: Jeremy Bettis <jbettis@chromium.org> Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com> Commit-Queue: Jeremy Bettis <jbettis@chromium.org>
-rw-r--r--zephyr/emul/emul_flash.c98
-rw-r--r--zephyr/test/drivers/default/src/flash.c59
2 files changed, 151 insertions, 6 deletions
diff --git a/zephyr/emul/emul_flash.c b/zephyr/emul/emul_flash.c
index 49130d2d32..d0749bf53e 100644
--- a/zephyr/emul/emul_flash.c
+++ b/zephyr/emul/emul_flash.c
@@ -5,6 +5,7 @@
#define DT_DRV_COMPAT cros_ec_flash_emul
+#include <zephyr/drivers/flash.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(emul_flash);
@@ -16,13 +17,19 @@ LOG_MODULE_REGISTER(emul_flash);
#include "flash.h"
-struct flash_emul_data {};
+struct flash_emul_data {
+ const struct device *flash_dev;
+};
struct flash_emul_cfg {
/** Pointer to run-time data */
struct flash_emul_data *data;
};
+#define FLASH_DEV DT_CHOSEN(zephyr_flash_controller)
+
+#define DRV_DATA(dev) ((struct flash_emul_data *)(dev)->data)
+
/* Variables to emulate the protection */
bool ro_protected, all_protected;
@@ -47,20 +54,99 @@ void system_set_image_copy(enum ec_image copy)
static int cros_flash_emul_init(const struct device *dev)
{
- return 0;
+ struct flash_emul_data *data = DRV_DATA(dev);
+
+ data->flash_dev = DEVICE_DT_GET(FLASH_DEV);
+ if (!device_is_ready(data->flash_dev)) {
+ LOG_ERR("%s device not ready", data->flash_dev->name);
+ return -ENODEV;
+ }
+
+ return EC_SUCCESS;
+}
+
+static int flash_check_writable_range(int offset, int size)
+{
+ /* Check out of range */
+ if (offset + size > CONFIG_FLASH_SIZE_BYTES) {
+ return EC_ERROR_INVAL;
+ }
+
+ /* Check RO protected and within the RO range */
+ if (ro_protected &&
+ MAX(CONFIG_WP_STORAGE_OFF, offset) <
+ MIN(CONFIG_WP_STORAGE_OFF + CONFIG_WP_STORAGE_SIZE,
+ offset + size)) {
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ return EC_SUCCESS;
}
static int cros_flash_emul_write(const struct device *dev, int offset, int size,
const char *src_data)
{
- __ASSERT(false, "Not implemented");
- return -EINVAL;
+ int ret = 0;
+ struct flash_emul_data *data = DRV_DATA(dev);
+
+ /* Check protection */
+ if (all_protected) {
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ if (flash_check_writable_range(offset, size)) {
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ /* Check invalid data pointer? */
+ if (src_data == 0) {
+ return -EINVAL;
+ }
+
+ /* Lock physical flash operations */
+ crec_flash_lock_mapped_storage(1);
+
+ ret = flash_write(data->flash_dev, offset, src_data, size);
+
+ /* Unlock physical flash operations */
+ crec_flash_lock_mapped_storage(0);
+
+ return ret;
}
static int cros_flash_emul_erase(const struct device *dev, int offset, int size)
{
- __ASSERT(false, "Not implemented");
- return -EINVAL;
+ int ret = 0;
+ struct flash_emul_data *data = DRV_DATA(dev);
+
+ /* Check protection */
+ if (all_protected) {
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ if (flash_check_writable_range(offset, size)) {
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ /* Address must be aligned to erase size */
+ if ((offset % CONFIG_FLASH_ERASE_SIZE) != 0) {
+ return -EINVAL;
+ }
+
+ /* Erase size must be a non-zero multiple of sectors */
+ if ((size == 0) || (size % CONFIG_FLASH_ERASE_SIZE) != 0) {
+ return -EINVAL;
+ }
+
+ /* Lock physical flash operations */
+ crec_flash_lock_mapped_storage(1);
+
+ ret = flash_erase(data->flash_dev, offset, size);
+
+ /* Unlock physical flash operations */
+ crec_flash_lock_mapped_storage(0);
+
+ return ret;
}
static int cros_flash_emul_get_protect(const struct device *dev, int bank)
diff --git a/zephyr/test/drivers/default/src/flash.c b/zephyr/test/drivers/default/src/flash.c
index 67ecff82bd..b0cf9df449 100644
--- a/zephyr/test/drivers/default/src/flash.c
+++ b/zephyr/test/drivers/default/src/flash.c
@@ -11,6 +11,7 @@
#include "ec_commands.h"
#include "emul/emul_flash.h"
+#include "flash.h"
#include "host_command.h"
#include "test/drivers/test_state.h"
@@ -132,6 +133,61 @@ ZTEST_USER(flash, test_hostcmd_flash_protect_wp_deasserted)
response.flags);
}
+#define TEST_BUF_SIZE 0x100
+
+ZTEST_USER(flash, test_hostcmd_flash_write_and_erase)
+{
+ uint8_t in_buf[TEST_BUF_SIZE];
+ uint8_t out_buf[sizeof(struct ec_params_flash_write) + TEST_BUF_SIZE];
+
+ struct ec_params_flash_read read_params = {
+ .offset = 0x10000,
+ .size = TEST_BUF_SIZE,
+ };
+ struct host_cmd_handler_args read_args =
+ BUILD_HOST_COMMAND(EC_CMD_FLASH_READ, 0, in_buf, read_params);
+
+ struct ec_params_flash_erase erase_params = {
+ .offset = 0x10000,
+ .size = 0x10000,
+ };
+ struct host_cmd_handler_args erase_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_FLASH_ERASE, 0, erase_params);
+
+ /* The write host command structs need to be filled run-time */
+ struct ec_params_flash_write *write_params =
+ (struct ec_params_flash_write *)out_buf;
+ struct host_cmd_handler_args write_args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_FLASH_WRITE, 0);
+
+ write_params->offset = 0x10000;
+ write_params->size = TEST_BUF_SIZE;
+ write_args.params = write_params;
+ write_args.params_size = sizeof(*write_params) + TEST_BUF_SIZE;
+
+ /* Flash write to all 0xec */
+ memset(write_params + 1, 0xec, TEST_BUF_SIZE);
+ zassert_ok(host_command_process(&write_args), NULL);
+
+ /* Flash read and compare the readback data */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_equal(read_args.response_size, TEST_BUF_SIZE, NULL);
+ zassert_equal(in_buf[0], 0xec, "readback data not expected: 0x%x",
+ in_buf[0]);
+ zassert_equal(in_buf[TEST_BUF_SIZE - 1], 0xec,
+ "readback data not expected: 0x%x", in_buf[0]);
+
+ /* Flash erase */
+ zassert_ok(host_command_process(&erase_args), NULL);
+
+ /* Flash read and compare the readback data */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_equal(in_buf[0], 0xff, "readback data not expected: 0x%x",
+ in_buf[0]);
+ zassert_equal(in_buf[TEST_BUF_SIZE - 1], 0xff,
+ "readback data not expected: 0x%x", in_buf[0]);
+}
+
static void flash_reset(void)
{
/* Set the GPIO WP_L to default */
@@ -151,6 +207,9 @@ static void flash_after(void *data)
{
ARG_UNUSED(data);
flash_reset();
+
+ /* The test modifies this bank. Erase it in case of failure. */
+ crec_flash_erase(0x10000, 0x10000);
}
ZTEST_SUITE(flash, drivers_predicate_post_main, NULL, flash_before, flash_after,