[U-Boot] SPI flash protection

Hi,
I am looking to add U-Boot support for the LaCie Network Space v2 board.
The SoC is a Kirkwood 88F6281_A0 and the boot device is a Macronix SPI flash (MX25L4005A). My problem is that the embedded stock U-Boot (1.1.4 version patched by Marvell and LaCie) enable write protection for the SPI flash. Then, after an U-Boot update, turn off this protection is needed to allow saving U-Boot environment.
It is not clear for me how to proceed. Disable the write protection from the board setup code could be an idea but a problem is that the SPI flash API don't export any helpful method... Maybe I should add one ?
An another idea is disabling the write protection anyway while initializing the flash (from the low level macronix driver). It is quite straightforward but I don't know if a flash driver is allowed to do that. After all, a flash could be protected for some good reasons.
My last idea is doing nothing and let an another piece of software handle the problem...
Thanks in advance for advices.
Simon
PS: some pointers about this project:
git : http://git.lacie-nas.org/u-boot-lacie.git (branch netspace_v2) wiki: http://www.lacie-nas.org/doku.php?id=network_space_v2#u-boot

Hi Simon :)
Le 29/01/2011 18:00, Simon Guinot a écrit :
Hi,
I am looking to add U-Boot support for the LaCie Network Space v2 board.
The SoC is a Kirkwood 88F6281_A0 and the boot device is a Macronix SPI flash (MX25L4005A). My problem is that the embedded stock U-Boot (1.1.4 version patched by Marvell and LaCie) enable write protection for the SPI flash. Then, after an U-Boot update, turn off this protection is needed to allow saving U-Boot environment.
It is not clear for me how to proceed. Disable the write protection from the board setup code could be an idea but a problem is that the SPI flash API don't export any helpful method... Maybe I should add one ?
An another idea is disabling the write protection anyway while initializing the flash (from the low level macronix driver). It is quite straightforward but I don't know if a flash driver is allowed to do that. After all, a flash could be protected for some good reasons.
My last idea is doing nothing and let an another piece of software handle the problem...
Thanks in advance for advices.
My personal take: let users of the board do their own mistakes and thus, do not protect the Flash, *except* for U-Boot itself.
So, if SPI Flash protection is possible on block or sector levels, protect the blocks/sectors where U-Boot is located, including the environment.
Saveenv should unprotect and re-protect the environment sector/block.
As for the kernel and rootfs... You can either leave them unprotected or protected.
Simon
PS: some pointers about this project:
git : http://git.lacie-nas.org/u-boot-lacie.git (branch netspace_v2)
You should keep this branch based on u-boot/master generally, and on u-boot-arm/master right now because it has the most recent ARM commits.
Amicalement,

Hi Albert,
On Sun, Jan 30, 2011 at 10:36:17AM +0100, Albert ARIBAUD wrote:
Hi Simon :)
Le 29/01/2011 18:00, Simon Guinot a écrit :
Hi,
I am looking to add U-Boot support for the LaCie Network Space v2 board.
The SoC is a Kirkwood 88F6281_A0 and the boot device is a Macronix SPI flash (MX25L4005A). My problem is that the embedded stock U-Boot (1.1.4 version patched by Marvell and LaCie) enable write protection for the SPI flash. Then, after an U-Boot update, turn off this protection is needed to allow saving U-Boot environment.
It is not clear for me how to proceed. Disable the write protection from the board setup code could be an idea but a problem is that the SPI flash API don't export any helpful method... Maybe I should add one ?
An another idea is disabling the write protection anyway while initializing the flash (from the low level macronix driver). It is quite straightforward but I don't know if a flash driver is allowed to do that. After all, a flash could be protected for some good reasons.
My last idea is doing nothing and let an another piece of software handle the problem...
Thanks in advance for advices.
My personal take: let users of the board do their own mistakes and thus, do not protect the Flash, *except* for U-Boot itself.
So, if SPI Flash protection is possible on block or sector levels, protect the blocks/sectors where U-Boot is located, including the environment.
For a Macronix SPI flash, the status register export 3 bits (or 4 depending the model and size) to configure the block protection.
Here is the protect area map for a MX25L4005A 4Mb flash:
bit 2 1 0 | protect level ____________|_______________ 0 0 0 | none 0 0 1 | block 7 0 1 0 | block 6-7 0 1 1 | block 4-7 1 * * | all
As you can figure, deal with a per block protection in a generic way is not easy..
Saveenv should unprotect and re-protect the environment sector/block.
If I understand well, macronix_{erase,write}() are called from either "saveenv" or "spi erase/write" commands and the low level macronix functions don't have any flash map knowledge. Then, leave protect or not a flash sector after a write/erase operation is not an easy decision.
Maybe the status register protection can be configured during the board initialization ? after all, the required flash informations (as device size, u-boot and environment localization) are available within the board setup code.
As for the kernel and rootfs... You can either leave them unprotected or protected.
As a side note, the Macronix Linux driver (m25p80) don't deal either with the block protect bits.
Simon
PS: some pointers about this project:
git : http://git.lacie-nas.org/u-boot-lacie.git (branch netspace_v2)
You should keep this branch based on u-boot/master generally, and on u-boot-arm/master right now because it has the most recent ARM commits.
OK, done :)
Simon

Le 30/01/2011 15:56, Simon Guinot a écrit :
So, if SPI Flash protection is possible on block or sector levels, protect the blocks/sectors where U-Boot is located, including the environment.
For a Macronix SPI flash, the status register export 3 bits (or 4 depending the model and size) to configure the block protection.
Here is the protect area map for a MX25L4005A 4Mb flash:
bit 2 1 0 | protect level ____________|_______________ 0 0 0 | none 0 0 1 | block 7 0 1 0 | block 6-7 0 1 1 | block 4-7 1 * * | all
As you can figure, deal with a per block protection in a generic way is not easy..
We don't necessarily have a generic per-block protection scheme at the HW level, but we can still use one as an API leve, i.e. have protect and unprotect functions which take generic start and end addresses and do what they can with the HW underneath (IIRC, protect on and protect off commands can use any address, and will check with the HW).
In your case, the HW seems to allow protecting 1, 2, 4 or all blocks from top of SPI Flash (I assume the boot process fetches code from a protectable areas, inside block 7 I imagine). I also assume you put U-Boot in the top blocks -- 7 alone, or 7 and 6 if too big for one block, etc.
Can the HW erase only one sector inside a block? If not, then you'd have to sacrifice a whole block for the env. Otherwise, you can lump together a sector for env and the sectors for U-Boot, hopefully in a single block.
Saveenv should unprotect and re-protect the environment sector/block.
If I understand well, macronix_{erase,write}() are called from either "saveenv" or "spi erase/write" commands and the low level macronix functions don't have any flash map knowledge. Then, leave protect or not a flash sector after a write/erase operation is not an easy decision.
Maybe the status register protection can be configured during the board initialization ? after all, the required flash informations (as device size, u-boot and environment localization) are available within the board setup code.
Can't the status register be re-programmed? Is it a kind of "protect now and until power-off" mechanism? If it is, then rewriting the environment will not be possible with this protection mechanism, and you might have to fake protection by software inside the driver if you need it. :(
As a side note, the Macronix Linux driver (m25p80) don't deal either with the block protect bits.
Simon
PS: some pointers about this project:
git : http://git.lacie-nas.org/u-boot-lacie.git (branch netspace_v2)
You should keep this branch based on u-boot/master generally, and on u-boot-arm/master right now because it has the most recent ARM commits.
OK, done :)
Fine. :)
Simon
Amicalement,

On Sun, Jan 30, 2011 at 06:19:20PM +0100, Albert ARIBAUD wrote:
Le 30/01/2011 15:56, Simon Guinot a écrit :
So, if SPI Flash protection is possible on block or sector levels, protect the blocks/sectors where U-Boot is located, including the environment.
For a Macronix SPI flash, the status register export 3 bits (or 4 depending the model and size) to configure the block protection.
Here is the protect area map for a MX25L4005A 4Mb flash:
bit 2 1 0 | protect level ____________|_______________ 0 0 0 | none 0 0 1 | block 7 0 1 0 | block 6-7 0 1 1 | block 4-7 1 * * | all
As you can figure, deal with a per block protection in a generic way is not easy..
We don't necessarily have a generic per-block protection scheme at the HW level, but we can still use one as an API leve, i.e. have protect and unprotect functions which take generic start and end addresses and do what they can with the HW underneath (IIRC, protect on and protect off commands can use any address, and will check with the HW).
Do you suggest to add a protect function to the SPI flash subsystem ?
In your case, the HW seems to allow protecting 1, 2, 4 or all blocks from top of SPI Flash (I assume the boot process fetches code from a protectable areas, inside block 7 I imagine). I also assume you put U-Boot in the top blocks -- 7 alone, or 7 and 6 if too big for one block, etc.
Block size is 64KB. The compiled U-Boot image is about 220KB and environment is 4KB. So, 4 blocks are required for U-Boot.
Can the HW erase only one sector inside a block? If not, then you'd have to sacrifice a whole block for the env. Otherwise, you can lump together a sector for env and the sectors for U-Boot, hopefully in a single block.
Sector size is 4KB. Both blocks and sectors can be erased/written individually.
Looking at macronix_erase(), I can see:
/* * This function currently uses sector erase only. * probably speed things up by using bulk erase * when possible. */
sector_size =3D mcx->params->page_size * mcx->params->pages_per_sector * mcx->params->sectors_per_block;
if (offset % sector_size || len % sector_size) { debug("SF: Erase offset/length not multiple of sector size\n"); return -1; }
The comments and the variable name "sector_size" are misleading. The effective granularity is block size: 64KB. Maybe a bug...
Saveenv should unprotect and re-protect the environment sector/block.
If I understand well, macronix_{erase,write}() are called from either "saveenv" or "spi erase/write" commands and the low level macronix functions don't have any flash map knowledge. Then, leave protect or not a flash sector after a write/erase operation is not an easy decision.
Maybe the status register protection can be configured during the board initialization ? after all, the required flash informations (as device size, u-boot and environment localization) are available within the board setup code.
Can't the status register be re-programmed? Is it a kind of "protect now and until power-off" mechanism? If it is, then rewriting the environment will not be possible with this protection mechanism, and you might have to fake protection by software inside the driver if you need it. :(
The status register can be re-programmed. The "block protect" bits and the "write enable" bit are persistent (not reseted after a power-off). I am not sure I understand well what do you mean by "fake protection by software inside the driver"...
Simon

Le 31/01/2011 01:31, Simon Guinot a écrit :
On Sun, Jan 30, 2011 at 06:19:20PM +0100, Albert ARIBAUD wrote:
Le 30/01/2011 15:56, Simon Guinot a écrit :
So, if SPI Flash protection is possible on block or sector levels, protect the blocks/sectors where U-Boot is located, including the environment.
For a Macronix SPI flash, the status register export 3 bits (or 4 depending the model and size) to configure the block protection.
Here is the protect area map for a MX25L4005A 4Mb flash:
bit 2 1 0 | protect level ____________|_______________ 0 0 0 | none 0 0 1 | block 7 0 1 0 | block 6-7 0 1 1 | block 4-7 1 * * | all
As you can figure, deal with a per block protection in a generic way is not easy..
We don't necessarily have a generic per-block protection scheme at the HW level, but we can still use one as an API leve, i.e. have protect and unprotect functions which take generic start and end addresses and do what they can with the HW underneath (IIRC, protect on and protect off commands can use any address, and will check with the HW).
Do you suggest to add a protect function to the SPI flash subsystem ?
If it is not there already, yes: analogous to what the NOR Flash provides, so that from the U-Boot command line, erasing U-Boot on the SPI Flash would require un-protecting it first.
In your case, the HW seems to allow protecting 1, 2, 4 or all blocks from top of SPI Flash (I assume the boot process fetches code from a protectable areas, inside block 7 I imagine). I also assume you put U-Boot in the top blocks -- 7 alone, or 7 and 6 if too big for one block, etc.
Block size is 64KB. The compiled U-Boot image is about 220KB and environment is 4KB. So, 4 blocks are required for U-Boot.
Can the HW erase only one sector inside a block? If not, then you'd have to sacrifice a whole block for the env. Otherwise, you can lump together a sector for env and the sectors for U-Boot, hopefully in a single block.
Sector size is 4KB. Both blocks and sectors can be erased/written individually.
Looking at macronix_erase(), I can see:
/* * This function currently uses sector erase only. * probably speed things up by using bulk erase * when possible. */ sector_size =3D mcx->params->page_size * mcx->params->pages_per_sector * mcx->params->sectors_per_block; if (offset % sector_size || len % sector_size) { debug("SF: Erase offset/length not multiple of sector size\n"); return -1; }
The comments and the variable name "sector_size" are misleading. The effective granularity is block size: 64KB. Maybe a bug...
Dunno. Still, the function takes a generic offset/length, and could be passed these from the U-Boot command line.
Saveenv should unprotect and re-protect the environment sector/block.
If I understand well, macronix_{erase,write}() are called from either "saveenv" or "spi erase/write" commands and the low level macronix functions don't have any flash map knowledge. Then, leave protect or not a flash sector after a write/erase operation is not an easy decision.
Maybe the status register protection can be configured during the board initialization ? after all, the required flash informations (as device size, u-boot and environment localization) are available within the board setup code.
Can't the status register be re-programmed? Is it a kind of "protect now and until power-off" mechanism? If it is, then rewriting the environment will not be possible with this protection mechanism, and you might have to fake protection by software inside the driver if you need it. :(
The status register can be re-programmed. The "block protect" bits and the "write enable" bit are persistent (not reseted after a power-off). I am not sure I understand well what do you mean by "fake protection by software inside the driver"...
Never mind what I meant -- since the status register can be reprogrammed, you can do a protect off then protect on without problems. :)
Simon
Amicalement,

Dear Albert ARIBAUD, Simon Guinot,
Here is the protect area map for a MX25L4005A 4Mb flash:
bit 2 1 0 | protect level
____________|_______________ 0 0 0 | none 0 0 1 | block 7 0 1 0 | block 6-7 0 1 1 | block 4-7 1 * * | all
Block size is 64KB. The compiled U-Boot image is about 220KB and environment is 4KB. So, 4 blocks are required for U-Boot.
I don't know your particular hardware, but is not u-boot (or the initial bootloader if there is any) fetched from the *beginning* of the flash?
If so, you would have to *hardware* protect the *entire* flash.
In this case, a *software* protection mechanism like for NOR flash would be a better choice.
Best Regards, Reinhard

Hi Reinhard,
On Mon, Jan 31, 2011 at 08:17:36AM +0100, Reinhard Meyer wrote:
Dear Albert ARIBAUD, Simon Guinot,
Here is the protect area map for a MX25L4005A 4Mb flash:
bit 2 1 0 | protect level ____________|_______________ 0 0 0 | none 0 0 1 | block 7 0 1 0 | block 6-7 0 1 1 | block 4-7 1 * * | all
Block size is 64KB. The compiled U-Boot image is about 220KB and environment is 4KB. So, 4 blocks are required for U-Boot.
I don't know your particular hardware, but is not u-boot (or the initial bootloader if there is any) fetched from the *beginning* of the flash?
If so, you would have to *hardware* protect the *entire* flash.
Yes you are right. Moreover the protected blocks (for a same register value) _could_ be different on an another Macronix device. For example, larger flash use 4 bits instead of 3 for block protection.
In this case, a *software* protection mechanism like for NOR flash would be a better choice.
Or no protection at all. After all, there is no such mechanism implemented for u-boot and Linux...
Best regards,
Simon

Le 01/02/2011 10:09, Simon Guinot a écrit :
In this case, a *software* protection mechanism like for NOR flash would be a better choice.
Or no protection at all. After all, there is no such mechanism implemented for u-boot and Linux...
Actually yes, there is, for NOR at least: in U-boot, sectors of NOR containing U-Boot and the environment are marked protected and thus trying to erase them will fail if you don't unprotect them first.
As for Linux, you can define this when declaring the NOR device in the machine specific code.
Best regards,
Simon
Amicalement,

On Saturday, January 29, 2011 12:00:48 Simon Guinot wrote:
It is not clear for me how to proceed. Disable the write protection from the board setup code could be an idea but a problem is that the SPI flash API don't export any helpful method... Maybe I should add one ?
An another idea is disabling the write protection anyway while initializing the flash (from the low level macronix driver). It is quite straightforward but I don't know if a flash driver is allowed to do that. After all, a flash could be protected for some good reasons.
current behavior is for SPI flash drivers to clear all protection bits during init. sst.c does exactly this.
if you wanted to extend the SPI flash API to include protect support as well as add a "protect" subcommand to "sf" (all of this would be behind a define like CONFIG_SPI_FLASH_PROTECTION), that'd be great. otherwise, in the short term, i'd suggest you implement something like sst_unlock in the macronix driver. i can take care of merging that. -mike
participants (4)
-
Albert ARIBAUD
-
Mike Frysinger
-
Reinhard Meyer
-
Simon Guinot