fw_setenv: lock the flash only if it was locked before

With current implementation of fw_setenv, it is always locks u-boot-env
region if lock interface is implemented for such mtd device. You can
not control lock of this region with fw_setenv, there is no option for
it in config or in application itself. Because of this situation may
happen problems like in this thread on xilinx forum:
https://forums.xilinx.com/t5/Embedded-Linux/Flash-be-locked-after-use-fw-setenv-from-user-space
/td-p/1027851

A short summary of that link is: some person has issue with some spi
chip which has lock interface but doesn't locks properly which leads to
lock of whole flash memory on lock of u-boot-env region. As resulted
solution hack was added into spi-nor.c driver for this chip with lock
disablement.

Instead fix this problem by adding logic to fw_setenv only lock the
flash if it was already locked when we attempted to use it.

Signed-off-by: Ivan Mikhaylov <fr0st61te@gmail.com>
This commit is contained in:
Ivan Mikhaylov 2020-07-10 19:54:18 +03:00 committed by Tom Rini
parent d045cbacf2
commit db82015929

24
tools/env/fw_env.c vendored
View File

@ -995,6 +995,7 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
of the data */
loff_t blockstart; /* running start of the current block -
MEMGETBADBLOCK needs 64 bits */
int was_locked; /* flash lock flag */
int rc;
/*
@ -1080,6 +1081,12 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
}
erase.length = erasesize;
if (DEVTYPE(dev) != MTD_ABSENT) {
was_locked = ioctl(fd, MEMISLOCKED, &erase);
/* treat any errors as unlocked flash */
if (was_locked < 0)
was_locked = 0;
}
/* This only runs once on NOR flash and SPI-dataflash */
while (processed < write_total) {
@ -1099,7 +1106,8 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
if (DEVTYPE(dev) != MTD_ABSENT) {
erase.start = blockstart;
ioctl(fd, MEMUNLOCK, &erase);
if (was_locked)
ioctl(fd, MEMUNLOCK, &erase);
/* These do not need an explicit erase cycle */
if (DEVTYPE(dev) != MTD_DATAFLASH)
if (ioctl(fd, MEMERASE, &erase) != 0) {
@ -1127,8 +1135,10 @@ static int flash_write_buf(int dev, int fd, void *buf, size_t count)
return -1;
}
if (DEVTYPE(dev) != MTD_ABSENT)
ioctl(fd, MEMLOCK, &erase);
if (DEVTYPE(dev) != MTD_ABSENT) {
if (was_locked)
ioctl(fd, MEMLOCK, &erase);
}
processed += erasesize;
block_seek = 0;
@ -1149,7 +1159,9 @@ static int flash_flag_obsolete(int dev, int fd, off_t offset)
int rc;
struct erase_info_user erase;
char tmp = ENV_REDUND_OBSOLETE;
int was_locked; /* flash lock flag */
was_locked = ioctl(fd, MEMISLOCKED, &erase);
erase.start = DEVOFFSET(dev);
erase.length = DEVESIZE(dev);
/* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */
@ -1159,9 +1171,11 @@ static int flash_flag_obsolete(int dev, int fd, off_t offset)
DEVNAME(dev));
return rc;
}
ioctl(fd, MEMUNLOCK, &erase);
if (was_locked)
ioctl(fd, MEMUNLOCK, &erase);
rc = write(fd, &tmp, sizeof(tmp));
ioctl(fd, MEMLOCK, &erase);
if (was_locked)
ioctl(fd, MEMLOCK, &erase);
if (rc < 0)
perror("Could not set obsolete flag");