例如Samsung K9F1208U0B,数据存储容量为64MB,采用块页式存储管理。8个I/O 引脚充当数据、地址、命令的复用端口。
芯片内部存储布局及存储操作特点:
一片Nand flash为一个设备(device), 其数据存储分层为:
1 (Device) = 4096 (Blocks)
1 (Block) - = 32 (Pages/Rows) 页与行是相同的意思,叫法不一样
1 (Page) = 528 (Bytes) = 数据块大小(512Bytes) + OOB 块大小(16Bytes)
在每一页中,最后16个字节(又称OOB)用于Nand Flash命令执行完后设置状态用,剩余512个字节又分为前半部分和后半部分。可以通过Nand Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位通过
Nand Flash内置的指针指向各自的首地址。
存储操作特点:
1. 擦除操作的最小单位是块。
2. Nand Flash芯片每一位(bit)只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前要一定将相应块擦除(擦除即是将相应块得位全部变为1).
3. OOB部分的第六字节(即517字节)标志是否是坏块,如果不是坏块该值为FF,否则为坏块。
4. 除OOB第六字节外,通常至少把OOB的前3个字节存放Nand Flash硬件ECC码。
BBT:bad block table,即坏块表。各家对nand的坏块管理方法都有差异。比如专门用nand做存储的,会把bbt放到block0,因为第0块一定是好的块。但是如果nand本身被用来boot,那么第0块就要存放程序,不能放bbt了。
有的把bbt放到最后一块,当然,这一块不能为坏块。
有的bbt中用2个bits表示1个block的状态,所以1个字节可以表示4个blocks。
bbt的大小跟nand大小有关,nand越大,需要的bbt也就越大。
所以具体代码具体分析。
ECC:
NAND Flash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出 错。一般使用一种比较专用的校验——ECC。ECC能纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的 错误不保证能检测。
ECC一般每256字节原始数据生成3字节ECC校验数据,这三字节共24比特分成两部分:6比特的列校验和16比特的行校验,多余的两个比特置1.
当往NAND Flash的page中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存到PAGE的OOB(out-of-band)数据区中。其位置就是eccpos[]。
校验的时候,根据上述ECC生成原理不难推断:将从OOB区中读出的原ECC校验和新ECC校验和按位异或,若结果为0,则表示不存在错(或是出现了 ECC无法检测的错误);若3个字节异或结果中存在11个比特位为1,表示存在一个比特错误,且可纠正;若3个字节异或结果中只存在1个比特位为1,表示 OOB区出错;其他情况均表示出现了无法纠正的错误。
NAND basics
NAND memory has quite unique characteristics.
- When it is erased, all bits are set to 1' (you will see 0xff on all bytes in a hexdump)
- You can change as many bits as you want to '0'
- You cannot set a bit back to '1' by using a regular write. You have to erase a whole erase block to do so
- The number of erase cycles per block is limited. Once you have reached the limit, some bits will not get back to 0xff
- In the case of the chip in the Neo1973, this is 100000 guaranteed per-block erase cycles.
NAND page
A NAND page consists of a number of data bytes (512 in the Neo1973 GTA01 case, 2048 in the GTA02 case) plus a number of out-of-band (OOB) bytes (GTA01: 16, GTA02: 64).
Only the data bytes are used for application data. The OOB bytes are used for
- Marking an erase block as bad (first or second page of erase block)
- Storing ECC (error correction codes)
- Storing filesystem specific information (JFFS2)
NAND erase block
A erase block consists of multiple pages. In the Neo1973 GTA01 case, every erase block has 32 pages, resulting in 16kBytes (hex: 0x4000) of data bytes (without OOB). GTA02 has 128kByte large erase blocks.
Problem
Bad Blocks
NAND memory apparently gets shipped with blocks that are already bad. The vendor just marks those blocks as bad, thus resulting in higher yield and lower per-unit cost.
The flash contains four kinds of blocks (16kBytes):
- Factory-Default bad blocks
- Samsung marks the 6th OOB byte as non 0xFF in the first and/or second page in blocks that are bad
- Worn-out bad blocks
- Good blocks
- The first block.
- This block is guaranteed to not require error correction up to 1000 writes. This is needed as initial boot code can't do ECC.
We are also guaranteed that a minimum of 4026 blocks (out of the total 4096) are good. This means up to 70 blocks (1.3MBytes) can be dead, resulting in a total guaranteed amount of working NAND storage of 65961984 bytes.
Backup
You may want to backup the "Factory-Default bad blocks" just in case you accidentally delete it.
The u-boot command "nand bad" lists the offsets of the bad blocks.
Solution
The solution is split into various pieces, one at each level.
Boot loader
first-stage
The boot loader itself contains a small first-stage boot loader for the S3C2410 Steppingstone.
This code (mostly written in ARM assembly) was altered to detect and skip bad blocks. This means, the first stage bootloader can itself extend over bad blocks.
This also means that the flashing routine needs to detect and skip bad blocks, resulting in a u-boot image that can have gaping holes ;) The existing "traditional" sjf2410-linux JTAG flashing program is not detecting bad blocks (Note: this might be changed through a compile option, see below)
Environment
The u-boot environment is traditionally stored at a fixed location within the NAND flash. This is not acceptable, since it could be a factory-set bad block.
The solution that was implemented for Openmoko/Neo1973 was to put the in-flash address of the environment into the out-of-band (OOB) area of the first block (the one which is guaranteed to be good). Since the environment address is unlikely to change often, the 1000 erase cycles guaranteed for the first block are good enough.
The exact location is byte 8..15 of the 16byte OOB area, starting with the four ASCII bytes ENVO, followed by the little-endian 32bit unsigned integer of the NAND address where the environment is located.
The u-boot "dynenv get" command can be used to read out a pre-programmed Environment offset from NAND, and the "dynenv set" can be used to write the offset (if the last eight bytes of OOB area are erased (0xff)).
Bad Block Table (BBT)
Since the usual bad block marker in the OOB area does not allow us to distinguish between factory-bad and worn-out-bad blocks, we need to store this information elsewhere. This place is called bad-block table (BBT) and is stored as a bitmap in the last two good blocks at the end of NAND. To increase security, a backup of those two blocks is kept in the two preceding good blocks as well.
The BBT location itself is identified by special markers (BBT0/BBT1) in the OOB area of the first page of the respective erase blocks.
The BBT consists of two bits per block which distinguish the three conditions (factory-bad/worn-out/good).
Both u-boot and Linux implement the same BBT layout and thus interoperate quite well.
BBT creation
The BBT is created once a BBT-implementing u-boot is started for the first time. The BBT scanning code assumes that the NAND is completely erased, i.e. only contains 0xff as content. Any block that contains bytes != 0xff in the OOB is marked as "factory bad" block.
Flashing kernel/rootfs from u-boot
The kernel is contained in its own partition. We have to flash it using the nand write.e command, and read it later again via nand read.e command. Those two variants (as opposed to their non-".e"-postfixed versions) simply skip bad blocks
As opposed to using fixed NAND flash addresses, we can use the mtd partition names. Thus, the magic of device-specific dynamic partition layout is all hidden neatly from the user. A flash command using a partiton name looks like:
nand write.e 0x32000000 kernel
Where 0x32000000 is the source address in RAM, and 'kernel' is the name of the kernel partition.
Kernel
Bad block table
In order to maintain the BBT created by u-boot, the kernel needs to have BBT support enabled. Unfortunately the mainline kernel doesn't have a CONFIG option for it, so if you're not using the -moko kernel tree, you have to manually patch the s3c2410 nand driver to enable the BBT option.
Flash Tool
sjf2410 (during development)
The sjf2410-linux tool has a compile-time option to check (and skip) bad blocks. If we use this for flashing u-boot, we will preserve the bad block info, once u-boot steppingstone code has been enhanced to skip bad blocks.
However, even if the bad-block skipping works, sjf2410-linux only supports the extremely slow parallel-port based JTAG adaptors. Also, the o