1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-29 16:03:47 +02:00

Enable writes with active ME

Replace the `ich_spi_force` logic with more helpful warnings. These can
be hidden later, in case the necessary switches are detected. Also,
demote some warnings about settings that are the default nowadays (e.g.
SPI configuration lock, inaccessible ME region).

Change-Id: I94a5e7074b845c227e43d76d04dd1a71082a1cef
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/26261
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
This commit is contained in:
Nico Huber 2016-05-03 13:38:28 +02:00 committed by Nico Huber
parent f9a3055480
commit 7590d1a937
2 changed files with 39 additions and 54 deletions

View File

@ -490,14 +490,7 @@ partitioned in multiple so called "Flash Regions" containing the host firmware,
the ME firmware and so on respectively. The flash descriptor can also specify up the ME firmware and so on respectively. The flash descriptor can also specify up
to 5 so called "Protected Regions", which are freely chosen address ranges to 5 so called "Protected Regions", which are freely chosen address ranges
independent from the aforementioned "Flash Regions". All of them can be write independent from the aforementioned "Flash Regions". All of them can be write
and/or read protected individually. If flashrom detects such a lock it will and/or read protected individually.
disable write support unless the user forces it with the
.sp
.B " flashrom \-p internal:ich_spi_force=yes"
.sp
syntax. If this leads to erase or write accesses to the flash it would most
probably bring it into an inconsistent and unbootable state and we will not
provide any support in such a case.
.sp .sp
If you have an Intel chipset with an ICH2 or later southbridge and if you want If you have an Intel chipset with an ICH2 or later southbridge and if you want
to set specific IDSEL values for a non-default flash chip or an embedded to set specific IDSEL values for a non-default flash chip or an embedded

View File

@ -221,6 +221,13 @@
#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */ #define ICH7_REG_OPTYPE 0x56 /* 16 Bits */
#define ICH7_REG_OPMENU 0x58 /* 64 Bits */ #define ICH7_REG_OPMENU 0x58 /* 64 Bits */
enum ich_access_protection {
NO_PROT = 0,
READ_PROT = 1,
WRITE_PROT = 2,
LOCKED = 3,
};
/* ICH SPI configuration lock-down. May be set during chipset enabling. */ /* ICH SPI configuration lock-down. May be set during chipset enabling. */
static int ichspi_lock = 0; static int ichspi_lock = 0;
@ -1547,12 +1554,15 @@ static int ich_spi_send_multicommand(struct flashctx *flash,
#define ICH_BRWA(x) ((x >> 8) & 0xff) #define ICH_BRWA(x) ((x >> 8) & 0xff)
#define ICH_BRRA(x) ((x >> 0) & 0xff) #define ICH_BRRA(x) ((x >> 0) & 0xff)
/* returns 0 if region is unused or r/w */ static const enum ich_access_protection access_perms_to_protection[] = {
static int ich9_handle_frap(uint32_t frap, int i) LOCKED, WRITE_PROT, READ_PROT, NO_PROT
{ };
static const char *const access_names[4] = { static const char *const access_names[] = {
"locked", "read-only", "write-only", "read-write" "locked", "read-only", "write-only", "read-write"
}; };
static enum ich_access_protection ich9_handle_frap(uint32_t frap, int i)
{
const int rwperms_unknown = ARRAY_SIZE(access_names); const int rwperms_unknown = ARRAY_SIZE(access_names);
static const char *const region_names[5] = { static const char *const region_names[5] = {
"Flash Descriptor", "BIOS", "Management Engine", "Flash Descriptor", "BIOS", "Management Engine",
@ -1582,23 +1592,23 @@ static int ich9_handle_frap(uint32_t frap, int i)
/* this FREG is disabled */ /* this FREG is disabled */
msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n", msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n",
offset, freg, i, region_name); offset, freg, i, region_name);
return 0; return NO_PROT;
} }
msg_pdbg("0x%02X: 0x%08x ", offset, freg); msg_pdbg("0x%02X: 0x%08x ", offset, freg);
if (rwperms == 0x3) { if (rwperms == 0x3) {
msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i, msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i,
region_name, base, limit, access_names[rwperms]); region_name, base, limit, access_names[rwperms]);
return 0; return NO_PROT;
} }
if (rwperms == rwperms_unknown) { if (rwperms == rwperms_unknown) {
msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) has unknown permissions.\n", msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) has unknown permissions.\n",
i, region_name, base, limit); i, region_name, base, limit);
return 0; return NO_PROT;
} }
msg_pwarn("FREG%i: Warning: %s region (0x%08x-0x%08x) is %s.\n", i, msg_pinfo("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i,
region_name, base, limit, access_names[rwperms]); region_name, base, limit, access_names[rwperms]);
return 1; return access_perms_to_protection[rwperms];
} }
/* In contrast to FRAP and the master section of the descriptor the bits /* In contrast to FRAP and the master section of the descriptor the bits
@ -1610,12 +1620,8 @@ static int ich9_handle_frap(uint32_t frap, int i)
#define ICH_PR_PERMS(pr) (((~((pr) >> PR_RP_OFF) & 1) << 0) | \ #define ICH_PR_PERMS(pr) (((~((pr) >> PR_RP_OFF) & 1) << 0) | \
((~((pr) >> PR_WP_OFF) & 1) << 1)) ((~((pr) >> PR_WP_OFF) & 1) << 1))
/* returns 0 if range is unused (i.e. r/w) */ static enum ich_access_protection ich9_handle_pr(const size_t reg_pr0, int i)
static int ich9_handle_pr(const size_t reg_pr0, int i)
{ {
static const char *const access_names[3] = {
"locked", "read-only", "write-only"
};
uint8_t off = reg_pr0 + (i * 4); uint8_t off = reg_pr0 + (i * 4);
uint32_t pr = mmio_readl(ich_spibar + off); uint32_t pr = mmio_readl(ich_spibar + off);
unsigned int rwperms = ICH_PR_PERMS(pr); unsigned int rwperms = ICH_PR_PERMS(pr);
@ -1627,13 +1633,13 @@ static int ich9_handle_pr(const size_t reg_pr0, int i)
if (rwperms == 0x3) { if (rwperms == 0x3) {
msg_pdbg2("0x%02X: 0x%08x (%sPR%u is unused)\n", off, pr, prefix, i); msg_pdbg2("0x%02X: 0x%08x (%sPR%u is unused)\n", off, pr, prefix, i);
return 0; return NO_PROT;
} }
msg_pdbg("0x%02X: 0x%08x ", off, pr); msg_pdbg("0x%02X: 0x%08x ", off, pr);
msg_pwarn("%sPR%u: Warning: 0x%08x-0x%08x is %s.\n", prefix, i, ICH_FREG_BASE(pr), msg_pwarn("%sPR%u: Warning: 0x%08x-0x%08x is %s.\n", prefix, i, ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr), access_names[rwperms]); ICH_FREG_LIMIT(pr), access_names[rwperms]);
return 1; return access_perms_to_protection[rwperms];
} }
/* Set/Clear the read and write protection enable bits of PR register @i /* Set/Clear the read and write protection enable bits of PR register @i
@ -1696,7 +1702,6 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
uint16_t tmp2; uint16_t tmp2;
uint32_t tmp; uint32_t tmp;
char *arg; char *arg;
int ich_spi_force = 0;
int ich_spi_rw_restricted = 0; int ich_spi_rw_restricted = 0;
int desc_valid = 0; int desc_valid = 0;
struct ich_descriptors desc = {{ 0 }}; struct ich_descriptors desc = {{ 0 }};
@ -1805,27 +1810,11 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
} }
free(arg); free(arg);
arg = extract_programmer_param("ich_spi_force");
if (arg && !strcmp(arg, "yes")) {
ich_spi_force = 1;
msg_pspew("ich_spi_force enabled.\n");
} else if (arg && !strlen(arg)) {
msg_perr("Missing argument for ich_spi_force.\n");
free(arg);
return ERROR_FATAL;
} else if (arg) {
msg_perr("Unknown argument for ich_spi_force: \"%s\" "
"(not \"yes\").\n", arg);
free(arg);
return ERROR_FATAL;
}
free(arg);
tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFS); tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFS);
msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2); msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
prettyprint_ich9_reg_hsfs(tmp2); prettyprint_ich9_reg_hsfs(tmp2);
if (tmp2 & HSFS_FLOCKDN) { if (tmp2 & HSFS_FLOCKDN) {
msg_pwarn("Warning: SPI Configuration Lockdown activated.\n"); msg_pinfo("SPI Configuration is locked down.\n");
ichspi_lock = 1; ichspi_lock = 1;
} }
if (tmp2 & HSFS_FDV) if (tmp2 & HSFS_FDV)
@ -1863,7 +1852,7 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
for (i = 0; i < num_freg; i++) for (i = 0; i < num_freg; i++)
ich_spi_rw_restricted |= ich9_handle_frap(tmp, i); ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
if (ich_spi_rw_restricted) if (ich_spi_rw_restricted)
msg_pwarn("Not all flash regions are freely accessible by flashrom. This is " msg_pinfo("Not all flash regions are freely accessible by flashrom. This is "
"most likely\ndue to an active ME. Please see " "most likely\ndue to an active ME. Please see "
"https://flashrom.org/ME for details.\n"); "https://flashrom.org/ME for details.\n");
} }
@ -1876,16 +1865,19 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i); ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
} }
if (ich_spi_rw_restricted) { switch (ich_spi_rw_restricted) {
if (!ich_spi_force) case WRITE_PROT:
programmer_may_write = 0; msg_pwarn("At least some flash regions are write protected. For write operations,\n"
msg_pinfo("Writes have been disabled for safety reasons. You can enforce write\n" "you should use a flash layout and include only writable regions. See\n"
"support with the ich_spi_force programmer option, but you will most likely\n" "manpage for more details.\n");
"harm your hardware! If you force flashrom you will get no support if\n" break;
"something breaks. On a few mainboards it is possible to enable write\n" case READ_PROT:
"access by setting a jumper (see its documentation or the board itself).\n"); case LOCKED:
if (ich_spi_force) msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
msg_pinfo("Continuing with write support because the user forced us to!\n"); "layout and include only accessible regions. For write operations, you'll\n"
"additionally need the --noverify-all switch. See manpage for more details.\n"
);
break;
} }
tmp = mmio_readl(ich_spibar + swseq_data.reg_ssfsc); tmp = mmio_readl(ich_spibar + swseq_data.reg_ssfsc);