Project

General

Profile

Actions

Bug #605

open

Some write paths verify without respecting --no-verify

Added by Vincent Fazio 2 days ago. Updated about 20 hours ago.

Status:
New
Priority:
Normal
Category:
-
Target version:
Start date:
08/13/2025
Due date:
% Done:

0%

Estimated time:
Affected versions:
Needs backport to:
Affected hardware:
Affected OS:

Description

From #520

If an erase is unaligned, there is a subsequent write to fill in data that should not have been erased. Some write functions implement a verify_range call, but not all functions look to verify the write was persisted (in fact, it only looks like the WRITE_JEDEC{1} verifies writes).

I've only visually instrumented the code, but this looks like it may still be the case.

Any time a write is issued to a chip that uses WRITE_JEDEC/WRITE_JEDEC1:

static int jedec_write_page(struct flashctx *flash, const uint8_t *src,
					 unsigned int start, unsigned int page_size)
{
	int tries = 0, failed;
	const uint8_t *s = src;
	const chipaddr bios = flash->virtual_memory;
	chipaddr dst = bios + start;
	chipaddr d = dst;

	for (; tries < MAX_REFLASH_TRIES; tries++) {
		/* Issue JEDEC Start Program command */
		start_program_jedec_common(flash);

		/* transfer data from source to destination */
		for (unsigned int i = 0; i < page_size; i++) {
			/* If the data is 0xFF, don't program it */
			if (*src != 0xFF)
				chip_writeb(flash, *src, dst);
			dst++;
			src++;
		}

		toggle_ready_jedec(flash, dst - 1);

		dst = d;
		src = s;
		failed = verify_range(flash, src, start, page_size);  // This is not respecting flashctx->flags.verify_after_write
		if (!failed)
			break;

		msg_cerr("retrying.\n");
	}

	if (failed) {
		msg_cerr(" page 0x%" PRIxPTR " failed!\n", (d - bios) / page_size);
	}

	return failed;
}

static int write_byte_program_jedec_common(const struct flashctx *flash, const uint8_t *src,
					   chipaddr dst)
{
	int tries = 0;

	/* If the data is 0xFF, don't program it and don't complain. */
	if (*src == 0xFF) {
		return 0;
	}

	for (; tries < MAX_REFLASH_TRIES; tries++) {
		const chipaddr bios = flash->virtual_memory;
		/* Issue JEDEC Byte Program command */
		start_program_jedec_common(flash);

		/* transfer data from source to destination */
		chip_writeb(flash, *src, dst);
		toggle_ready_jedec(flash, bios);

		if (chip_readb(flash, dst) == *src)  // This is implicitly verifying and causing a retry without respecting flashctx->flags.verify_after_write
			break;
	}

	return (tries >= MAX_REFLASH_TRIES) ? 1 : 0;
}

It looks like writes are verified regardless of whether flashrom was instructed to not verify them. I do not know if these are governed by a JEDEC spec that specifies that retries must be attempted.

I haven't verified other write functions/paths.

This probably isn't super important, but it would keep things consistent

Actions #1

Updated by Vincent Fazio 2 days ago

  • Assignee set to Anastasia Klimchuk
Actions #2

Updated by Anastasia Klimchuk about 20 hours ago

I think you are right, verifying here is needed to implement retries - to make a decision whether more retries is needed.

I also thought, possibly that the people using jedec write are relying on the retry behaviour? Retry count is defined as 16, which is quite a lot. It can be disruptive to cut that off and stop retrying, if someone relies on that.

On a closer look, chips using WRITE_JEDEC/WRITE_JEDEC1 are on non-SPI buses (parallel, fwh) so maybe retries make sense for those specifically - I understand those often needed a special treatment. I also understand that they are less commonly used now - so even if this extra verification happens it doesn't affect the mainstream usage.

I am thinking, maybe this can be left as is.

In any case, checking jedec spec is a good idea, I will do this.
I will also check other write functions.

Actions

Also available in: Atom PDF