Edward O'Callaghan has submitted this change. ( https://review.coreboot.org/c/flashrom/+/72607 )
(
1 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: jedec.c: Move printlock stuff into printlock.c ......................................................................
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 --- M Makefile M jedec.c M meson.build A printlock.c 4 files changed, 229 insertions(+), 190 deletions(-)
Approvals: build bot (Jenkins): Verified Stefan Reinauer: Looks good to me, approved Thomas Heijligen: Looks good to me, but someone else must approve
diff --git a/Makefile b/Makefile index 25c01e0..69818ce 100644 --- a/Makefile +++ b/Makefile @@ -379,7 +379,7 @@ ############################################################################### # 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 e33ce93..db01c08 100644 --- a/jedec.c +++ b/jedec.c @@ -478,192 +478,3 @@
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 2f11c3f..baa1084 100644 --- a/meson.build +++ b/meson.build @@ -61,6 +61,7 @@ '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 0000000..d05251e --- /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); +}