summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward O'Callaghan <quasisec@google.com>2023-01-30 11:58:20 +1100
committerEdward O'Callaghan <quasisec@chromium.org>2023-02-21 12:56:22 +0000
commit86babd06276196facd3c0948b466ccb665e846a7 (patch)
tree2c4f23c8a38c2f548b1c72ddc0003b66026e1ac6
parentae07072e0aacc475aade990c77c193826433f07d (diff)
downloadflashrom-86babd06276196facd3c0948b466ccb665e846a7.tar.gz
flashrom-86babd06276196facd3c0948b466ccb665e846a7.tar.bz2
flashrom-86babd06276196facd3c0948b466ccb665e846a7.zip
jedec.c: Move printlock stuff into printlock.c
Change-Id: Iacaa16c81e141aac30feb6871700c4fdc9eec8e9 Signed-off-by: Edward O'Callaghan <quasisec@google.com> Reviewed-on: https://review.coreboot.org/c/flashrom/+/72607 Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-by: Thomas Heijligen <src@posteo.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r--Makefile2
-rw-r--r--jedec.c189
-rw-r--r--meson.build1
-rw-r--r--printlock.c213
4 files changed, 215 insertions, 190 deletions
diff --git a/Makefile b/Makefile
index 25c01e054..69818ce01 100644
--- a/Makefile
+++ b/Makefile
@@ -379,7 +379,7 @@ endif
###############################################################################
# Flash chip drivers and bus support infrastructure.
-CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
+CHIP_OBJS = jedec.o printlock.o stm50.o w39.o w29ee011.o \
sst28sf040.o 82802ab.o \
sst49lfxxxc.o sst_fwhub.o edi.o flashchips.o spi.o spi25.o spi25_statusreg.o \
spi95.o opaque.o sfdp.o en29lv640b.o at45db.o s25f.o \
diff --git a/jedec.c b/jedec.c
index e33ce931e..db01c08e3 100644
--- a/jedec.c
+++ b/jedec.c
@@ -478,192 +478,3 @@ int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start,
return 0;
}
-
-struct unlockblock {
- unsigned int size;
- unsigned int count;
-};
-
-typedef int (*unlockblock_func)(const struct flashctx *flash, chipaddr offset);
-static int regspace2_walk_unlockblocks(const struct flashctx *flash, const struct unlockblock *block, unlockblock_func func)
-{
- chipaddr off = flash->virtual_registers + 2;
- while (block->count != 0) {
- unsigned int j;
- for (j = 0; j < block->count; j++) {
- if (func(flash, off))
- return -1;
- off += block->size;
- }
- block++;
- }
- return 0;
-}
-
-#define REG2_RWLOCK ((1 << 2) | (1 << 0))
-#define REG2_LOCKDOWN (1 << 1)
-#define REG2_MASK (REG2_RWLOCK | REG2_LOCKDOWN)
-
-static int printlock_regspace2_block(const struct flashctx *flash, chipaddr lockreg)
-{
- uint8_t state = chip_readb(flash, lockreg);
- msg_cdbg("Lock status of block at 0x%0*" PRIxPTR " is ", PRIxPTR_WIDTH, lockreg);
- switch (state & REG2_MASK) {
- case 0:
- msg_cdbg("Full Access.\n");
- break;
- case 1:
- msg_cdbg("Write Lock (Default State).\n");
- break;
- case 2:
- msg_cdbg("Locked Open (Full Access, Locked Down).\n");
- break;
- case 3:
- msg_cdbg("Write Lock, Locked Down.\n");
- break;
- case 4:
- msg_cdbg("Read Lock.\n");
- break;
- case 5:
- msg_cdbg("Read/Write Lock.\n");
- break;
- case 6:
- msg_cdbg("Read Lock, Locked Down.\n");
- break;
- case 7:
- msg_cdbg("Read/Write Lock, Locked Down.\n");
- break;
- }
- return 0;
-}
-
-static int printlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
-{
- const unsigned int elems = flash->chip->total_size * 1024 / block_size;
- struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
- return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block);
-}
-
-int printlock_regspace2_uniform_64k(struct flashctx *flash)
-{
- return printlock_regspace2_uniform(flash, 64 * 1024);
-}
-
-int printlock_regspace2_block_eraser_0(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
-}
-
-int printlock_regspace2_block_eraser_1(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
-}
-
-/* Try to change the lock register at address lockreg from cur to new.
- *
- * - Try to unlock the lock bit if requested and it is currently set (although this is probably futile).
- * - Try to change the read/write bits if requested.
- * - Try to set the lockdown bit if requested.
- * Return an error immediately if any of this fails. */
-static int changelock_regspace2_block(const struct flashctx *flash, chipaddr lockreg, uint8_t cur, uint8_t new)
-{
- /* Only allow changes to known read/write/lockdown bits */
- if (((cur ^ new) & ~REG2_MASK) != 0) {
- msg_cerr("Invalid lock change from 0x%02x to 0x%02x requested at 0x%0*" PRIxPTR "!\n"
- "Please report a bug at flashrom@flashrom.org\n",
- cur, new, PRIxPTR_WIDTH, lockreg);
- return -1;
- }
-
- /* Exit early if no change (of read/write/lockdown bits) was requested. */
- if (((cur ^ new) & REG2_MASK) == 0) {
- msg_cdbg2("Lock bits at 0x%0*" PRIxPTR " not changed.\n", PRIxPTR_WIDTH, lockreg);
- return 0;
- }
-
- /* Normally the lockdown bit can not be cleared. Try nevertheless if requested. */
- if ((cur & REG2_LOCKDOWN) && !(new & REG2_LOCKDOWN)) {
- chip_writeb(flash, cur & ~REG2_LOCKDOWN, lockreg);
- cur = chip_readb(flash, lockreg);
- if ((cur & REG2_LOCKDOWN) == REG2_LOCKDOWN) {
- msg_cwarn("Lockdown can't be removed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- return -1;
- }
- }
-
- /* Change read and/or write bit */
- if ((cur ^ new) & REG2_RWLOCK) {
- /* Do not lockdown yet. */
- uint8_t wanted = (cur & ~REG2_RWLOCK) | (new & REG2_RWLOCK);
- chip_writeb(flash, wanted, lockreg);
- cur = chip_readb(flash, lockreg);
- if (cur != wanted) {
- msg_cerr("Changing lock bits failed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- return -1;
- }
- msg_cdbg("Changed lock bits at 0x%0*" PRIxPTR " to 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- }
-
- /* Eventually, enable lockdown if requested. */
- if (!(cur & REG2_LOCKDOWN) && (new & REG2_LOCKDOWN)) {
- chip_writeb(flash, new, lockreg);
- cur = chip_readb(flash, lockreg);
- if (cur != new) {
- msg_cerr("Enabling lockdown FAILED at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- return -1;
- }
- msg_cdbg("Enabled lockdown at 0x%0*" PRIxPTR ".\n", PRIxPTR_WIDTH, lockreg);
- }
-
- return 0;
-}
-
-static int unlock_regspace2_block_generic(const struct flashctx *flash, chipaddr lockreg)
-{
- uint8_t old = chip_readb(flash, lockreg);
- /* We don't care for the lockdown bit as long as the RW locks are 0 after we're done */
- return changelock_regspace2_block(flash, lockreg, old, old & ~REG2_RWLOCK);
-}
-
-static int unlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
-{
- const unsigned int elems = flash->chip->total_size * 1024 / block_size;
- struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
- return regspace2_walk_unlockblocks(flash, blocks, &unlock_regspace2_block_generic);
-}
-
-int unlock_regspace2_uniform_64k(struct flashctx *flash)
-{
- return unlock_regspace2_uniform(flash, 64 * 1024);
-}
-
-int unlock_regspace2_uniform_32k(struct flashctx *flash)
-{
- return unlock_regspace2_uniform(flash, 32 * 1024);
-}
-
-int unlock_regspace2_block_eraser_0(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
-}
-
-int unlock_regspace2_block_eraser_1(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
-}
diff --git a/meson.build b/meson.build
index 2f11c3fa2..baa108465 100644
--- a/meson.build
+++ b/meson.build
@@ -61,6 +61,7 @@ srcs = files(
'helpers_fileio.c',
'ich_descriptors.c',
'jedec.c',
+ 'printlock.c',
'layout.c',
'libflashrom.c',
'opaque.c',
diff --git a/printlock.c b/printlock.c
new file mode 100644
index 000000000..d05251e98
--- /dev/null
+++ b/printlock.c
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
+ * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
+ * Copyright (C) 2007-2012 Carl-Daniel Hailfinger
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ * Copyright (C) 2014 Stefan Tauner
+ *
+ * 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 "flash.h"
+#include "chipdrivers.h"
+
+
+struct unlockblock {
+ unsigned int size;
+ unsigned int count;
+};
+
+typedef int (*unlockblock_func)(const struct flashctx *flash, chipaddr offset);
+static int regspace2_walk_unlockblocks(const struct flashctx *flash, const struct unlockblock *block, unlockblock_func func)
+{
+ chipaddr off = flash->virtual_registers + 2;
+ while (block->count != 0) {
+ unsigned int j;
+ for (j = 0; j < block->count; j++) {
+ if (func(flash, off))
+ return -1;
+ off += block->size;
+ }
+ block++;
+ }
+ return 0;
+}
+
+#define REG2_RWLOCK ((1 << 2) | (1 << 0))
+#define REG2_LOCKDOWN (1 << 1)
+#define REG2_MASK (REG2_RWLOCK | REG2_LOCKDOWN)
+
+static int printlock_regspace2_block(const struct flashctx *flash, chipaddr lockreg)
+{
+ uint8_t state = chip_readb(flash, lockreg);
+ msg_cdbg("Lock status of block at 0x%0*" PRIxPTR " is ", PRIxPTR_WIDTH, lockreg);
+ switch (state & REG2_MASK) {
+ case 0:
+ msg_cdbg("Full Access.\n");
+ break;
+ case 1:
+ msg_cdbg("Write Lock (Default State).\n");
+ break;
+ case 2:
+ msg_cdbg("Locked Open (Full Access, Locked Down).\n");
+ break;
+ case 3:
+ msg_cdbg("Write Lock, Locked Down.\n");
+ break;
+ case 4:
+ msg_cdbg("Read Lock.\n");
+ break;
+ case 5:
+ msg_cdbg("Read/Write Lock.\n");
+ break;
+ case 6:
+ msg_cdbg("Read Lock, Locked Down.\n");
+ break;
+ case 7:
+ msg_cdbg("Read/Write Lock, Locked Down.\n");
+ break;
+ }
+ return 0;
+}
+
+static int printlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
+{
+ const unsigned int elems = flash->chip->total_size * 1024 / block_size;
+ struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
+ return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block);
+}
+
+int printlock_regspace2_uniform_64k(struct flashctx *flash)
+{
+ return printlock_regspace2_uniform(flash, 64 * 1024);
+}
+
+int printlock_regspace2_block_eraser_0(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
+}
+
+int printlock_regspace2_block_eraser_1(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
+}
+
+/* Try to change the lock register at address lockreg from cur to new.
+ *
+ * - Try to unlock the lock bit if requested and it is currently set (although this is probably futile).
+ * - Try to change the read/write bits if requested.
+ * - Try to set the lockdown bit if requested.
+ * Return an error immediately if any of this fails. */
+static int changelock_regspace2_block(const struct flashctx *flash, chipaddr lockreg, uint8_t cur, uint8_t new)
+{
+ /* Only allow changes to known read/write/lockdown bits */
+ if (((cur ^ new) & ~REG2_MASK) != 0) {
+ msg_cerr("Invalid lock change from 0x%02x to 0x%02x requested at 0x%0*" PRIxPTR "!\n"
+ "Please report a bug at flashrom@flashrom.org\n",
+ cur, new, PRIxPTR_WIDTH, lockreg);
+ return -1;
+ }
+
+ /* Exit early if no change (of read/write/lockdown bits) was requested. */
+ if (((cur ^ new) & REG2_MASK) == 0) {
+ msg_cdbg2("Lock bits at 0x%0*" PRIxPTR " not changed.\n", PRIxPTR_WIDTH, lockreg);
+ return 0;
+ }
+
+ /* Normally the lockdown bit can not be cleared. Try nevertheless if requested. */
+ if ((cur & REG2_LOCKDOWN) && !(new & REG2_LOCKDOWN)) {
+ chip_writeb(flash, cur & ~REG2_LOCKDOWN, lockreg);
+ cur = chip_readb(flash, lockreg);
+ if ((cur & REG2_LOCKDOWN) == REG2_LOCKDOWN) {
+ msg_cwarn("Lockdown can't be removed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ return -1;
+ }
+ }
+
+ /* Change read and/or write bit */
+ if ((cur ^ new) & REG2_RWLOCK) {
+ /* Do not lockdown yet. */
+ uint8_t wanted = (cur & ~REG2_RWLOCK) | (new & REG2_RWLOCK);
+ chip_writeb(flash, wanted, lockreg);
+ cur = chip_readb(flash, lockreg);
+ if (cur != wanted) {
+ msg_cerr("Changing lock bits failed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ return -1;
+ }
+ msg_cdbg("Changed lock bits at 0x%0*" PRIxPTR " to 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ }
+
+ /* Eventually, enable lockdown if requested. */
+ if (!(cur & REG2_LOCKDOWN) && (new & REG2_LOCKDOWN)) {
+ chip_writeb(flash, new, lockreg);
+ cur = chip_readb(flash, lockreg);
+ if (cur != new) {
+ msg_cerr("Enabling lockdown FAILED at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ return -1;
+ }
+ msg_cdbg("Enabled lockdown at 0x%0*" PRIxPTR ".\n", PRIxPTR_WIDTH, lockreg);
+ }
+
+ return 0;
+}
+
+static int unlock_regspace2_block_generic(const struct flashctx *flash, chipaddr lockreg)
+{
+ uint8_t old = chip_readb(flash, lockreg);
+ /* We don't care for the lockdown bit as long as the RW locks are 0 after we're done */
+ return changelock_regspace2_block(flash, lockreg, old, old & ~REG2_RWLOCK);
+}
+
+static int unlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
+{
+ const unsigned int elems = flash->chip->total_size * 1024 / block_size;
+ struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
+ return regspace2_walk_unlockblocks(flash, blocks, &unlock_regspace2_block_generic);
+}
+
+int unlock_regspace2_uniform_64k(struct flashctx *flash)
+{
+ return unlock_regspace2_uniform(flash, 64 * 1024);
+}
+
+int unlock_regspace2_uniform_32k(struct flashctx *flash)
+{
+ return unlock_regspace2_uniform(flash, 32 * 1024);
+}
+
+int unlock_regspace2_block_eraser_0(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
+}
+
+int unlock_regspace2_block_eraser_1(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
+}