[coreboot-gerrit] New patch to review for coreboot: 5d20769 vboot: add vbnv flash driver

Stefan Reinauer (stefan.reinauer@coreboot.org) gerrit at coreboot.org
Wed Apr 1 23:37:36 CEST 2015


Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9229

-gerrit

commit 5d20769e7b10a15085cd84189ddf6fc480e31af6
Author: Daisuke Nojiri <dnojiri at chromium.org>
Date:   Wed Oct 29 11:18:11 2014 -0700

    vboot: add vbnv flash driver
    
    this adds a driver for vboot to read and write nvdata in spi flash.
    it's assumed that flash contents are erased to 1-bits and write
    operations can only change 1-bits to 0-bits.
    
    when all nvram space is used, the driver will erase the whole block
    and start the next write from the beginning.
    
    BUG=chrome-os-partner:32774
    BRANCH=ToT
    TEST=Built for cosmos.
    
    Change-Id: I40858f847151aa0770e1101e905476d270550f60
    Signed-off-by: Stefan Reinauer <reinauer at chromium.org>
    Original-Commit-Id: 09713828b7b0cabd13a08de3f34e32bc4dbef4a4
    Original-Change-Id: Ia9049f342b21fa4c289cb7b9254ab89ec1ef1699
    Original-Signed-off-by: Daisuke Nojiri <dnojiri at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/226525
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
---
 src/vendorcode/google/chromeos/vbnv_flash.c | 161 ++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)

diff --git a/src/vendorcode/google/chromeos/vbnv_flash.c b/src/vendorcode/google/chromeos/vbnv_flash.c
index 1271777..cf7c002 100644
--- a/src/vendorcode/google/chromeos/vbnv_flash.c
+++ b/src/vendorcode/google/chromeos/vbnv_flash.c
@@ -17,12 +17,173 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <2api.h>
+#include <cbfs.h>
+#include <cbfs_core.h>
+#include <console/console.h>
+#include <spi_flash.h>
+#include <string.h>
+#include <vboot_nvstorage.h>
 #include "chromeos.h"
 
+#if IS_ENABLED(CONFIG_VBOOT_VERIFY_FIRMWARE)
+#define BLOB_SIZE VBNV_BLOCK_SIZE
+#elif IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE)
+#define BLOB_SIZE VB2_NVDATA_SIZE
+#else
+#error unable to determine BLOB_SIZE
+#endif
+
+/* FMAP descriptor of the NVRAM area */
+static struct vboot_region nvram_region;
+
+/* offset of the current nvdata in nvram */
+static int blob_offset = -1;
+
+/* cache of the current nvdata */
+static uint8_t cache[BLOB_SIZE];
+
+/* spi_flash struct used when saving data */
+static struct spi_flash *spi_flash = NULL;
+
+/*
+ * This code assumes that flash is erased to 1-bits, and write operations can
+ * only change 1-bits to 0-bits. So if the new contents only change 1-bits to
+ * 0-bits, we can reuse the current blob.
+ */
+static inline uint8_t erase_value(void)
+{
+	return 0xff;
+}
+
+static inline int can_overwrite(uint8_t current, uint8_t new)
+{
+	return (current & new) == new;
+}
+
+static inline int is_initialized(void)
+{
+	return blob_offset >= 0;
+}
+
+static int init_vbnv(void)
+{
+	uint8_t buf[BLOB_SIZE];
+	uint8_t empty_blob[BLOB_SIZE];
+	int offset;
+	int i;
+
+	vboot_locate_region("RW_NVRAM", &nvram_region);
+	if (nvram_region.size < BLOB_SIZE) {
+		printk(BIOS_ERR, "%s: failed to locate NVRAM\n", __func__);
+		return 1;
+	}
+
+	/* Prepare an empty blob to compare against. */
+	for (i = 0; i < BLOB_SIZE; i++)
+		empty_blob[i] = erase_value();
+
+	/*
+	 * after the loop, offset is supposed to point the blob right before the
+	 * first empty blob, the last blob in the nvram if there is no empty
+	 * blob, or 0 if the nvram has never been used.
+	 */
+	for (i = 0, offset = 0; i <= nvram_region.size - BLOB_SIZE;
+			i += BLOB_SIZE) {
+		if (vboot_get_region(i, BLOB_SIZE, buf) == NULL) {
+			printk(BIOS_ERR, "failed to read nvdata\n");
+			return 1;
+		}
+		if (!memcmp(buf, empty_blob, BLOB_SIZE))
+			break;
+		offset = i;
+	}
+
+	/* reread the nvdata and write it to the cache */
+	if (vboot_get_region(offset, BLOB_SIZE, cache) == NULL) {
+		printk(BIOS_ERR, "failed to read nvdata\n");
+		return 1;
+	}
+
+	blob_offset = offset;
+
+	return 0;
+}
+
+static int vbnv_flash_probe(void)
+{
+	if (!spi_flash) {
+		spi_flash = spi_flash_probe(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
+		if (!spi_flash) {
+			printk(BIOS_ERR, "failed to probe spi flash\n");
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int erase_nvram(void)
+{
+	if (vbnv_flash_probe())
+		return 1;
+
+	if (spi_flash->erase(spi_flash, nvram_region.offset_addr,
+			     nvram_region.size)) {
+		printk(BIOS_ERR, "failed to erase nvram\n");
+		return 1;
+	}
+
+	printk(BIOS_INFO, "nvram is cleared\n");
+	return 0;
+}
+
 void read_vbnv(uint8_t *vbnv_copy)
 {
+	if (!is_initialized())
+		if (init_vbnv())
+			return;  /* error */
+	memcpy(vbnv_copy, cache, BLOB_SIZE);
 }
 
 void save_vbnv(const uint8_t *vbnv_copy)
 {
+	int new_offset = blob_offset;
+	int i;
+
+	if (!is_initialized())
+		if (init_vbnv())
+			return;  /* error */
+
+	/* Bail out if there have been no changes. */
+	if (!memcmp(vbnv_copy, cache, BLOB_SIZE))
+		return;
+
+	/* See if we can overwrite the current blob with the new one */
+	for (i = 0; i < BLOB_SIZE; i++) {
+		if (!can_overwrite(cache[i], vbnv_copy[i])) {
+			/* unable to overwrite. need to use the next blob */
+			new_offset += BLOB_SIZE;
+			if (new_offset > nvram_region.size - BLOB_SIZE) {
+				if (erase_nvram())
+					return;  /* error */
+				new_offset = 0;
+			}
+			break;
+		}
+	}
+
+	if (vbnv_flash_probe())
+		return;  /* error */
+
+	if (spi_flash->write(spi_flash, new_offset,
+			     BLOB_SIZE, vbnv_copy) != BLOB_SIZE) {
+		printk(BIOS_ERR, "failed to write nvdata\n");
+		return;  /* error */
+	}
+
+	/* write was successful. safely move pointer forward */
+	blob_offset = new_offset;
+	memcpy(cache, vbnv_copy, BLOB_SIZE);
+
+	return;
 }



More information about the coreboot-gerrit mailing list