1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-26 22:52:34 +02:00

ichspi.c: warn user and disable writes when a protected address range is detected

This includes not only the notorious read-only flash descriptors and locked ME
regions, but also the more rarely used PRs (Protected Ranges).
The user can enforce write support by specifying ich_spi_force=yes in the
programmer options, but we don't tell him the exact syntax interactively. He
has to read it up in the man page.

Corresponding to flashrom svn r1494.

Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
This commit is contained in:
Stefan Tauner 2012-02-16 01:13:00 +00:00
parent 65922a3860
commit 5210e72d13
2 changed files with 89 additions and 25 deletions

View File

@ -315,6 +315,21 @@ important opcodes are inaccessible due to lockdown; or if more than one flash
chip is attached). The other options (swseq, hwseq) select the respective mode
(if possible).
.sp
ICH8 and later southbridges may also have locked address ranges of different
kinds if a valid descriptor was written to it. The flash address space is then
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
to 5 so called "Protected Regions", which are freely chosen address ranges
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
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
If you have an Intel chipset with an ICH6 or later southbridge and if you want
to set specific IDSEL values for a non-default flash chip or an embedded
controller (EC), you can use the

View File

@ -1421,7 +1421,8 @@ static int ich_spi_send_multicommand(struct flashctx *flash,
#define ICH_BRWA(x) ((x >> 8) & 0xff)
#define ICH_BRRA(x) ((x >> 0) & 0xff)
static void do_ich9_spi_frap(uint32_t frap, int i)
/* returns 0 if region is unused or r/w */
static int ich9_handle_frap(uint32_t frap, int i)
{
static const char *const access_names[4] = {
"locked", "read-only", "write-only", "read-write"
@ -1436,19 +1437,26 @@ static void do_ich9_spi_frap(uint32_t frap, int i)
int offset = ICH9_REG_FREG0 + i * 4;
uint32_t freg = mmio_readl(ich_spibar + offset);
msg_pdbg("0x%02X: 0x%08x (FREG%i: %s)\n",
offset, freg, i, region_names[i]);
base = ICH_FREG_BASE(freg);
limit = ICH_FREG_LIMIT(freg);
if (base > limit) {
/* this FREG is disabled */
msg_pdbg("%s region is unused.\n", region_names[i]);
return;
msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n",
offset, freg, i, region_names[i]);
return 0;
}
msg_pdbg("0x%02X: 0x%08x ", offset, freg);
if (rwperms == 0x3) {
msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i,
region_names[i], base, (limit | 0x0fff),
access_names[rwperms]);
return 0;
}
msg_pdbg("0x%08x-0x%08x is %s\n", base, (limit | 0x0fff),
access_names[rwperms]);
msg_pinfo("FREG%i: WARNING: %s region (0x%08x-0x%08x) is %s.\n", i,
region_names[i], base, (limit | 0x0fff),
access_names[rwperms]);
return 1;
}
/* In contrast to FRAP and the master section of the descriptor the bits
@ -1460,21 +1468,25 @@ static void do_ich9_spi_frap(uint32_t frap, int i)
#define ICH_PR_PERMS(pr) (((~((pr) >> PR_RP_OFF) & 1) << 0) | \
((~((pr) >> PR_WP_OFF) & 1) << 1))
static void prettyprint_ich9_reg_pr(int i)
/* returns 0 if range is unused (i.e. r/w) */
static int ich9_handle_pr(int i)
{
static const char *const access_names[4] = {
"locked", "read-only", "write-only", "read-write"
static const char *const access_names[3] = {
"locked", "read-only", "write-only"
};
uint8_t off = ICH9_REG_PR0 + (i * 4);
uint32_t pr = mmio_readl(ich_spibar + off);
int rwperms = ICH_PR_PERMS(pr);
unsigned int rwperms = ICH_PR_PERMS(pr);
msg_pdbg2("0x%02X: 0x%08x (PR%u", off, pr, i);
if (rwperms != 0x3)
msg_pdbg2(")\n0x%08x-0x%08x is %s\n", ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr) | 0x0fff, access_names[rwperms]);
else
msg_pdbg2(", unused)\n");
if (rwperms == 0x3) {
msg_pdbg2("0x%02X: 0x%08x (PR%u is unused)\n", off, pr, i);
return 0;
}
msg_pdbg("0x%02X: 0x%08x ", off, pr);
msg_pinfo("PR%u: WARNING: 0x%08x-0x%08x is %s.\n", i, ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr) | 0x0fff, access_names[rwperms]);
return 1;
}
/* Set/Clear the read and write protection enable bits of PR register @i
@ -1537,6 +1549,8 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
uint16_t spibar_offset, tmp2;
uint32_t tmp;
char *arg;
int ich_spi_force = 0;
int ich_spi_rw_restricted = 0;
int desc_valid = 0;
struct ich_descriptors desc = {{ 0 }};
enum ich_spi_mode {
@ -1631,6 +1645,22 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
}
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);
msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
prettyprint_ich9_reg_hsfs(tmp2);
@ -1665,17 +1695,36 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
msg_pdbg("BRWA 0x%02x, ", ICH_BRWA(tmp));
msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
/* Decode and print FREGx and FRAP registers */
/* Handle FREGx and FRAP registers */
for (i = 0; i < 5; i++)
do_ich9_spi_frap(tmp, i);
ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
}
/* try to disable PR locks before printing them */
if (!ichspi_lock)
for (i = 0; i < 5; i++)
for (i = 0; i < 5; i++) {
/* if not locked down try to disable PR locks first */
if (!ichspi_lock)
ich9_set_pr(i, 0, 0);
for (i = 0; i < 5; i++)
prettyprint_ich9_reg_pr(i);
ich_spi_rw_restricted |= ich9_handle_pr(i);
}
if (ich_spi_rw_restricted) {
msg_pinfo("Please send a verbose log to "
"flashrom@flashrom.org if this board is not "
"listed on\n"
"http://flashrom.org/Supported_hardware#Supported_mainboards "
"yet.\n");
if (!ich_spi_force)
programmer_may_write = 0;
msg_pinfo("Writes have been disabled. You can enforce "
"write support with the\nich_spi_force "
"programmer option, but it will most likely "
"harm your hardware!\nIf you force flashrom "
"you will get no support if something "
"breaks.\n");
if (ich_spi_force)
msg_pinfo("Continuing with write support "
"because the user forced us to!\n");
}
tmp = mmio_readl(ich_spibar + ICH9_REG_SSFS);
msg_pdbg("0x90: 0x%02x (SSFS)\n", tmp & 0xff);