Skip to content

Commit

Permalink
flashrom.c: Fail immediately when trying to write/erase wp regions
Browse files Browse the repository at this point in the history
Change-Id: Ic39b4acf1da73d093ce3a7df71c1c549d92240d5
Signed-off-by: Michał Iwanicki <[email protected]>
  • Loading branch information
m-iwanicki committed Dec 6, 2024
1 parent 912ee02 commit 4dc3fa9
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
/util/ich_descriptors_tool/.obj

target/

subprojects/cmocka-*/
subprojects/packagecache/
39 changes: 39 additions & 0 deletions flashrom.c
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,38 @@ static int unlock_flash_wp(struct flashctx *const flash,
return ret;
}

static int write_protect_check(struct flashctx *flash) {
bool check_wp = false;
size_t wp_start, wp_len;
enum flashrom_wp_mode mode;
struct flashrom_wp_cfg *cfg = NULL;
const struct romentry *entry = NULL;
const struct flashrom_layout *const layout = get_layout(flash);

if (flashrom_wp_cfg_new(&cfg) == FLASHROM_WP_OK &&
flashrom_wp_read_cfg(cfg, flash) == FLASHROM_WP_OK )
{
flashrom_wp_get_range(&wp_start, &wp_len, cfg);
mode = flashrom_wp_get_mode(cfg);
if (mode != FLASHROM_WP_MODE_DISABLED && wp_len != 0)
check_wp = true;
}
flashrom_wp_cfg_release(cfg);

while ((entry = layout_next_included(layout, entry))) {
if ((!flash->flags.skip_unwritable_regions &&
check_for_unwritable_regions(flash, entry->region.start, entry->region.end - entry->region.start)
)
||
(check_wp && entry->region.start < wp_start + wp_len && wp_start <= entry->region.end))
{
return -1;
}
}

return 0;
}

int prepare_flash_access(struct flashctx *const flash,
const bool read_it, const bool write_it,
const bool erase_it, const bool verify_it)
Expand All @@ -1752,6 +1784,13 @@ int prepare_flash_access(struct flashctx *const flash,
return 1;
}

if ((write_it || erase_it) && !flash->flags.force) {
if(write_protect_check(flash)) {
msg_cerr("Requested regions are write protected. Aborting.\n");
return 1;
}
}

if (map_flash(flash) != 0)
return 1;

Expand Down
44 changes: 37 additions & 7 deletions ichspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,19 @@ struct hwseq_data {
struct fd_region fd_regions[MAX_FD_REGIONS];
};

#define MAX_PR_REGISTERS 6
struct pr_register {
enum ich_access_protection level;
uint32_t base;
uint32_t limit;
};

struct _pr_access {
uint8_t count;
struct pr_register registers[MAX_PR_REGISTERS];
};
struct _pr_access pr_access;

static struct hwseq_data *get_hwseq_data_from_context(const struct flashctx *flash)
{
return flash->mst->opaque.data;
Expand Down Expand Up @@ -1464,6 +1477,17 @@ static void ich_get_region(const struct flashctx *flash, unsigned int addr, stru
region->end = limit;
region->read_prot = (level == LOCKED) || (level == READ_PROT);
region->write_prot = (level == LOCKED) || (level == WRITE_PROT);
if (region->write_prot != true) {
for (ssize_t pr = 0; pr < pr_access.count; pr++) {
struct pr_register pr_reg = pr_access.registers[pr];
if (pr_reg.level == WRITE_PROT &&
region->start < pr_reg.base + pr_reg.limit && pr_reg.base <= region->end)
{
region->write_prot = true;
break;
}
}
}
break;
}
}
Expand Down Expand Up @@ -1950,28 +1974,32 @@ static enum ich_access_protection ich9_handle_region_access(struct fd_region *fd
#define ICH_PR_PERMS(pr) (((~((pr) >> PR_RP_OFF) & 1) << 0) | \
((~((pr) >> PR_WP_OFF) & 1) << 1))

static enum ich_access_protection ich9_handle_pr(const size_t reg_pr0, unsigned int i)
static struct pr_register ich9_handle_pr(const size_t reg_pr0, unsigned int i)
{
uint8_t off = reg_pr0 + (i * 4);
uint32_t pr = mmio_readl(ich_spibar + off);
unsigned int rwperms_idx = ICH_PR_PERMS(pr);
enum ich_access_protection rwperms = access_perms_to_protection[rwperms_idx];
struct pr_register pr_reg = {
.level = access_perms_to_protection[rwperms_idx],
.base = ICH_FREG_BASE(pr),
.limit = ICH_FREG_LIMIT(pr),
};

/* From 5 on we have GPR registers and start from 0 again. */
const char *const prefix = i >= 5 ? "G" : "";
if (i >= 5)
i -= 5;

if (rwperms == NO_PROT) {
if (pr_reg.level == NO_PROT) {
msg_pdbg2("0x%02"PRIX8": 0x%08"PRIx32" (%sPR%u is unused)\n", off, pr, prefix, i);
return NO_PROT;
return pr_reg;
}

msg_pdbg("0x%02"PRIX8": 0x%08"PRIx32" ", off, pr);
msg_pwarn("%sPR%u: Warning: 0x%08"PRIx32"-0x%08"PRIx32" is %s.\n", prefix, i, ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr), access_names[rwperms]);
ICH_FREG_LIMIT(pr), access_names[pr_reg.level]);

return rwperms;
return pr_reg;
}

/* Set/Clear the read and write protection enable bits of PR register @i
Expand Down Expand Up @@ -2170,6 +2198,7 @@ static int init_ich_default(const struct programmer_cfg *cfg, void *spibar, enum
size_t num_freg, num_pr, reg_pr0;
struct hwseq_data hwseq_data = { 0 };
init_chipset_properties(&swseq_data, &hwseq_data, &num_freg, &num_pr, &reg_pr0, ich_gen);
pr_access.count = num_pr;

int ret = get_ich_spi_mode_param(cfg, &ich_spi_mode);
if (ret)
Expand Down Expand Up @@ -2243,7 +2272,8 @@ static int init_ich_default(const struct programmer_cfg *cfg, void *spibar, enum
/* if not locked down try to disable PR locks first */
if (!ichspi_lock)
ich9_set_pr(reg_pr0, i, 0, 0);
ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
pr_access.registers[i] = ich9_handle_pr(reg_pr0, i);
ich_spi_rw_restricted |= pr_access.registers[i].level;
}

switch (ich_spi_rw_restricted) {
Expand Down

0 comments on commit 4dc3fa9

Please sign in to comment.