[U-Boot] freescale i.MX28 mxsboot NAND booting on mx28evk bad blocks

Trent Piepho tpiepho at gmail.com
Thu Apr 11 14:03:12 CEST 2013


>> I don't think the image u-boot mxsboot generates includes any OOB
>> data.  For me, it made an image which is *exactly* 24 blocks of 128
>> kiB each.  If the FCB blocks had OOB data then there would need to
>> be some multiple of 64 OBB bytes in the image (16 kiB I would think).
>> I think maybe this is the problem.  The update_nand_full script
>> calls "nand write.raw ${loadaddr} 0x0 ${fcb_sz}" and write.raw
>> expects loadaddr to contain $fcb_sz pages of (2048 + 64) bytes each.
>
>
> I'm not sure what you mean. According to u-boot:
>
> Device 0: nand0, sector size 128 KiB
>   Page size      2048 b
>   OOB size         64 b
>
> The page size is 2048 bytes, with 64 bytes of oob data, for a total of
> 2112 bytes.
>
> When I burn the first part of the image with u-boot:
>
> MX28EVK U-Boot > nand write.raw ${loadaddr} 0x0 ${fcb_sz}
>
> NAND write:  540672 bytes written: OK

I'm talking about the image file as generated by mxsimage.  If I hex dump
that, it's clearly written entirely with 2048 byte pages.  If you hexdump
your image are the FCB blocks exactly 128k apart?  Or are they 64 * 2112 =
132k apart?  It should be the latter, as 132k * 4 = 540672 bytes.

> If you look at the mxsboot source code:
>
>   for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
>         offset = i * nand_writesize;
>        memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize);
>    }
>
> It appears to be writing the FCB including oob data.

Looks wrong to me!  Notice that offset is equal to i * nand_writesize, not
i * (nand_writesize + nand_oobsize).  I think this only produce a bootable
image because:

The FCB data is only 1036 bytes in size.  The remaining 1012 bytes of data
and 64 oob bytes in the page aren't used.  And the 63 pages after the first
aren't used either.  So they can be full of garbage and it doesn't matter.
 The image mxsboot creates is ok for the first 1036 bytes.  Everything
after that is wrong, but it doesn't matter.

There are four copies of the FCB blocks.  The ROM bootloader looks for the
first valid one and uses it.  The first one is ok in the mxsboot image.
 All the rest are corrupted since they are written in the wrong location.
 But since the first one was ok the bootloader never even looks at the bad
ones.  Unless the NAND page goes bad, then the whole point of having
redundant copies will be defeated.

Now, look at the mx28_nand_fcb_block() that generates the FCB block.  It
calls memset() to fill the entire 2112 bytes with ZERO.  The mx28_nand_fcb
struct is 512 bytes, so the copy to copy the fcb struct to the buffer at
offset 12, and then the code to write the fcb ecc at offset 512+12 only
writes the first 1036 bytes.  The remaining bytes, including the OOB, will
all be zero.  And a ZERO byte in the first OOB byte makes the NAND block as
bad.  So that's why burning the mxsboot generated image with nand write.raw
makes the blocks bad.  Using kobs-ng doesn't write the OOB data and erase
any bad block markers, which is better.  I guess this is not just a bug in
mxsboot, but also a deficiency in u-boot's nand support.  It allows one to
write 2048 bytes in ECC mode or 2112 bytes in raw mode.  What one should
actually do to flash these blocks is write 2048 bytes in raw mode.

>> This is why writing with nandwrite doesn't work.  The ROM bootloader
>> expects the FCB blocks, which contain the BCH parameters, to be in
>> raw mode and apparently expects the rest to be in BCH mode.
>
>
> Unless I am misunderstanding the u-boot instructions, the FCB blocks are
> written in raw mode:

It's not the flashing that is in the wrong mode, but the image mxsboot
generates that is wrong.

> There are no explicit instructions for nandwrite in u-boot, I simply
split the mxsboot NAND image into two pieces to match the pieces that
u-boot wrote:
>
> dd if=test.nand bs=2112 count=256 of=test-head.nand
> dd if=test.nand bs=1 skip=524288 of=test-tail.nand
>
> And then wrote the first piece with nandwrite -oob at offset 0 and the
second with regular nandwrite at offset 0x80000. This worked exactly the
same as using u-boot, including the four blocks being marked as bad by
Linux.

If the four blocks were already marked as bad, then nandwrite will not
write them.  So maybe you only have a working image because it was already
working and wasn't modified?  Can you erase flash in u-boot, verify that
nand does not boot, and the make a working nand using just nandwrite --oob?
 I think you will also need to use the option --noecc to write in raw mode.

>> U-boot appears to write the OOB data (with all zeros), causing the
>> pages to become marked as bad.
>
>
> If you look at the mxsboot source code, they appear to be trying to
calculate the ecc and generate the oob data, but maybe they are doing it
wrong?

Look closer, they don't.  The ECC they generate is just the 512 bytes of
ecc data for the 512 bytes of FCB data.  This is a special ecc just used
for the FCBs.  Nothing will actually write past the 1036th byte of the
block and so it will still be all zero past that including the oob data.

>> A "smart" flasher like kobs-ng seems more in line with what the
>> hardware calls for.
>
> Yes, but unfortunately I'm not sure that's something that could be
implemented within a running u-boot?

It would be harder.  I think you'd need to write a u-boot app to do it.

>> cope with bad blocks.  It just creates a blank DBBT table.  What you
>> need to do is query the mtd driver and get the bad block list and
>> then use that to construct an accurate DBBT and then not use those
>> bad blocks.  kobs-ng can do this (not sure if it actually does).
>
>
> Does the ROM IPL pay any attention to bad blocks? I don't know exactly
how it works, but from what I've heard it doesn't sound like it deals with
bad blocks very well if at all.

It is supposed to use something called the DBBT to skip bad blocks.
 mxsboot doesn't generate a real DBBT so bad blocks probably aren't handled.

>> I'd like to burn from Linux.  It's easier to create an end user
>> firmware update system in linux than in u-boot.
>
>
> Yes, agreed. We've been evaluating our bootloader options for the project
I'm working on. Initially we were going to have u-boot be the bootloader
and directly load our production kernel. However, as you say, it is
somewhat difficult to create a flexible update/recovery system within
u-boot. Next we looked into using the freescale bootlets to directly load a
bootloader/recovery linux kernel with a bundled initramfs that would be
used for the update/recovery process, and then have it use kexec to load
the production kernel. This worked out pretty well.
>
> What I think we're going to go with is actually a hybrid of both u-boot
and a stripped-down linux/initramfs bootloader/recovery kernel. The
bootstream actually contains two copies of whatever object is going to be
loaded (I'm guessing, but I assume that is because the ROM IPL doesn't
handle bad blocks, so if the first copy can't be read it will just try the
second). Our recovery kernel/initramfs is probably going to be about 5M, so
it would take about 10M to be loaded directly. u-boot is less than 1M, so
by including both, it actually uses *less* space (2*1+5=7, vs 2*5=10). In
addition, the recommendation seems to be to have the IPL load the minimal
amount possible, so with this implementation the IPL loads a tiny u-boot,
which again is a lot smarter and more reliable about loading the larger
recovery kernel, which can then either perform recovery options or kexec
the production kernel.

I've done that before.  The u-boot env was written from Linux to tell
u-boot which kernel to boot, the firmware update kernel and rootfs or the
main kernel and rootfs.

Another way is to use initramfs for your main filesystem.  If you have no
filesystems mounted from flash, then you can just flash without rebooting.
 You need a small filesystem for this of course.


More information about the U-Boot mailing list