[PATCH 10/10] cros_ec: Add vstore support

Simon Glass sjg at chromium.org
Sat Jan 16 22:52:31 CET 2021


The EC can store small amounts of data for the benefit of the
verified boot process. Since the EC is seldom reset, this can allow the
AP to store data that survives a reboot or a suspend/resume cycle.

Add support for this.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 drivers/misc/cros_ec.c         | 71 ++++++++++++++++++++++++++++++++++
 drivers/misc/cros_ec_sandbox.c | 52 ++++++++++++++++++++++++-
 include/cros_ec.h              | 43 ++++++++++++++++++++
 test/dm/cros_ec.c              | 38 ++++++++++++++++++
 4 files changed, 202 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index c22bb4b5b50..ebfa7c41c25 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -1557,6 +1557,77 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable)
 	return 0;
 }
 
+int cros_ec_vstore_supported(struct udevice *dev)
+{
+	return cros_ec_check_feature(dev, EC_FEATURE_VSTORE);
+}
+
+int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp)
+{
+	struct ec_response_vstore_info *resp;
+
+	if (ec_command_inptr(dev, EC_CMD_VSTORE_INFO, 0, NULL, 0,
+			     (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
+		return -EIO;
+
+	if (lockedp)
+		*lockedp = resp->slot_locked;
+
+	return resp->slot_count;
+}
+
+/*
+ * cros_ec_vstore_read - Read data from EC vstore slot
+ *
+ * @slot: vstore slot to read from
+ * @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes
+ */
+int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data)
+{
+	struct ec_params_vstore_read req;
+	struct ec_response_vstore_read *resp;
+
+	req.slot = slot;
+	if (ec_command_inptr(dev, EC_CMD_VSTORE_READ, 0, &req, sizeof(req),
+			     (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
+		return -EIO;
+
+	if (!data || req.slot >= EC_VSTORE_SLOT_MAX)
+		return -EINVAL;
+
+	memcpy(data, resp->data, sizeof(resp->data));
+
+	return 0;
+}
+
+/*
+ * cros_ec_vstore_write - Save data into EC vstore slot
+ *
+ * @slot: vstore slot to write into
+ * @data: data to write
+ * @size: size of data in bytes
+ *
+ * Maximum size of data is EC_VSTORE_SLOT_SIZE.  It is the callers
+ * responsibility to check the number of implemented slots by
+ * querying the vstore info.
+ */
+int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
+			 size_t size)
+{
+	struct ec_params_vstore_write req;
+
+	if (slot >= EC_VSTORE_SLOT_MAX || size > EC_VSTORE_SLOT_SIZE)
+		return -EINVAL;
+
+	req.slot = slot;
+	memcpy(req.data, data, size);
+
+	if (ec_command(dev, EC_CMD_VSTORE_WRITE, 0, &req, sizeof(req), NULL, 0))
+		return -EIO;
+
+	return 0;
+}
+
 int cros_ec_get_switches(struct udevice *dev)
 {
 	struct dm_cros_ec_ops *ops;
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 845876cfb0c..cb8adc4495a 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -62,6 +62,15 @@ struct ec_keymatrix_entry {
 	int keycode;	/* corresponding linux key code */
 };
 
+enum {
+	VSTORE_SLOT_COUNT	= 4,
+};
+
+struct vstore_slot {
+	bool locked;
+	u8 data[EC_VSTORE_SLOT_SIZE];
+};
+
 /**
  * struct ec_state - Information about the EC state
  *
@@ -75,7 +84,7 @@ struct ec_keymatrix_entry {
  * @keyscan: Current keyscan information (bit set for each row/column pressed)
  * @recovery_req: Keyboard recovery requested
  * @test_flags: Flags that control behaviour for tests
- * @switches: Current switches value (EC_SWITCH_)
+ * @slot_locked: Locked vstore slots (mask)
  */
 struct ec_state {
 	u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
@@ -88,6 +97,7 @@ struct ec_state {
 	uint8_t keyscan[KEYBOARD_COLS];
 	bool recovery_req;
 	uint test_flags;
+	struct vstore_slot slot[VSTORE_SLOT_COUNT];
 } s_state, *g_state;
 
 /**
@@ -495,13 +505,51 @@ static int process_cmd(struct ec_state *ec,
 		struct ec_response_get_features *resp = resp_data;
 
 		resp->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FLASH) |
-			EC_FEATURE_MASK_0(EC_FEATURE_I2C);
+			EC_FEATURE_MASK_0(EC_FEATURE_I2C) |
+			EC_FEATURE_MASK_0(EC_FEATURE_VSTORE);
 		resp->flags[1] =
 			EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) |
 			EC_FEATURE_MASK_1(EC_FEATURE_ISH);
 		len = sizeof(*resp);
 		break;
 	}
+	case EC_CMD_VSTORE_INFO: {
+		struct ec_response_vstore_info *resp = resp_data;
+		int i;
+
+		resp->slot_count = VSTORE_SLOT_COUNT;
+		resp->slot_locked = 0;
+		for (i = 0; i < VSTORE_SLOT_COUNT; i++) {
+			if (ec->slot[i].locked)
+				resp->slot_locked |= 1 << i;
+		}
+		len = sizeof(*resp);
+		break;
+	};
+	case EC_CMD_VSTORE_WRITE: {
+		const struct ec_params_vstore_write *req = req_data;
+		struct vstore_slot *slot;
+
+		if (req->slot >= EC_VSTORE_SLOT_MAX)
+			return -EINVAL;
+		slot = &ec->slot[req->slot];
+		slot->locked = true;
+		memcpy(slot->data, req->data, EC_VSTORE_SLOT_SIZE);
+		len = 0;
+		break;
+	}
+	case EC_CMD_VSTORE_READ: {
+		const struct ec_params_vstore_read *req = req_data;
+		struct ec_response_vstore_read *resp = resp_data;
+		struct vstore_slot *slot;
+
+		if (req->slot >= EC_VSTORE_SLOT_MAX)
+			return -EINVAL;
+		slot = &ec->slot[req->slot];
+		memcpy(resp->data, slot->data, EC_VSTORE_SLOT_SIZE);
+		len = sizeof(*resp);
+		break;
+	}
 	default:
 		printf("   ** Unknown EC command %#02x\n", req_hdr->command);
 		return -1;
diff --git a/include/cros_ec.h b/include/cros_ec.h
index cb91343e3d8..eddc23d48f8 100644
--- a/include/cros_ec.h
+++ b/include/cros_ec.h
@@ -596,4 +596,47 @@ int cros_ec_check_feature(struct udevice *dev, uint feature);
  */
 int cros_ec_get_switches(struct udevice *dev);
 
+/**
+ * cros_ec_vstore_supported() - Check if vstore is supported
+ *
+ * @dev: CROS-EC device
+ * @return false if not supported, true if supported, -ve on error
+ */
+int cros_ec_vstore_supported(struct udevice *dev);
+
+/**
+ * cros_ec_vstore_info() - Get vstore information
+ *
+ * @dev: CROS-EC device
+ * @lockedp: mask of locked slots
+ * @return number of vstore slots supported by the EC,, -ve on error
+ */
+int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp);
+
+/**
+ * cros_ec_vstore_read() - Read data from EC vstore slot
+ *
+ * @dev: CROS-EC device
+ * @slot: vstore slot to read from
+ * @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data);
+
+/**
+ * cros_ec_vstore_write() - Save data into EC vstore slot
+ *
+ * The maximum size of data is EC_VSTORE_SLOT_SIZE.  It is the caller's
+ * responsibility to check the number of implemented slots by querying the
+ * vstore info.
+ *
+ * @dev: CROS-EC device
+ * @slot: vstore slot to write into
+ * @data: data to write
+ * @size: size of data in bytes
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
+			 size_t size);
+
 #endif
diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c
index 0da7548fd24..30cb70e0882 100644
--- a/test/dm/cros_ec.c
+++ b/test/dm/cros_ec.c
@@ -56,6 +56,7 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts)
 	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
 	ut_assertok(cros_ec_get_features(dev, &feat));
 	ut_asserteq_64(1U << EC_FEATURE_FLASH | 1U << EC_FEATURE_I2C |
+		1u << EC_FEATURE_VSTORE |
 		1ULL << EC_FEATURE_UNIFIED_WAKE_MASKS | 1ULL << EC_FEATURE_ISH,
 		feat);
 
@@ -68,6 +69,7 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts)
 	ut_assertok(run_command("crosec features", 0));
 	ut_assert_nextline("flash");
 	ut_assert_nextline("i2c");
+	ut_assert_nextline("vstore");
 	ut_assert_nextline("unified_wake_masks");
 	ut_assert_nextline("ish");
 	ut_assert_console_end();
@@ -138,3 +140,39 @@ static int dm_test_cros_ec_events(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_cros_ec_events, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_vstore(struct unit_test_state *uts)
+{
+	const int size = EC_VSTORE_SLOT_SIZE;
+	u8 test_data[size], data[size];
+	struct udevice *dev;
+	u32 locked;
+	int i;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+	ut_asserteq(true, cros_ec_vstore_supported(dev));
+
+	ut_asserteq(4, cros_ec_vstore_info(dev, &locked));
+	ut_asserteq(0, locked);
+
+	/* Write some data */
+	for (i = 0; i < size; i++)
+		test_data[i] = ' ' + i;
+	ut_assertok(cros_ec_vstore_write(dev, 2, test_data, size));
+
+	/* Check it is locked */
+	ut_asserteq(4, cros_ec_vstore_info(dev, &locked));
+	ut_asserteq(1 << 2, locked);
+
+	/* Read it back and compare */
+	ut_assertok(cros_ec_vstore_read(dev, 2, data));
+	ut_asserteq_mem(test_data, data, size);
+
+	/* Try another slot to make sure it is empty */
+	ut_assertok(cros_ec_vstore_read(dev, 0, data));
+	for (i = 0; i < size; i++)
+		ut_asserteq(0, data[i]);
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_vstore, UT_TESTF_SCAN_FDT);
-- 
2.30.0.284.gd98b1dd5eaa7-goog



More information about the U-Boot mailing list