uboot中nandflash bbt创建过程

本文详细解析了U-Boot环境下NAND Flash的坏块检测流程,从board_init_r函数开始,逐步深入到nand_block_isbad及nand_block_checkbad函数,解释了如何通过读取OOB信息判断块的好坏,以及坏块表(BBT)的创建和使用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

arm/lib/board.c

board_init_r()

{

……

nand_init();

env_relocate();

……

}

 

common\env_common.c

void env_relocate(void)

{

……

env_relocate_spec();

……

}

 

common\env_nand.c

void env_relocate_spec(void)

{

readenv(CONFIG_ENV_OFFSET, (u_char *)buf);

}

 

drivers/mtd/nand/nand_base.c

static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)

{

……

if (nand_block_isbad(&nand_info[0], offset))

{}

……

}

 

drivers/mtd/nand/nand_base.c

static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)

{

return nand_block_checkbad(mtd, offs, 1, 0);

}

 

drivers/mtd/nand/nand_base.c

static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,       int allowbbt)

{

chip->scan_bbt(mtd);

 

/* Return info from the table */

return nand_isbad_bbt(mtd, ofs, allowbbt);

}

 

drivers/mtd/nand/nand_bbt.c

int nand_default_bbt(struct mtd_info *mtd)

{

if (!this->badblock_pattern)

nand_create_default_bbt_descr(this);

 

return nand_scan_bbt(mtd, this->badblock_pattern);

 

}

 

drivers/mtd/nand/nand_bbt.c

int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)

{

//bbt表分配内存

nand_memory_bbt(mtd, bd)

}

 

drivers/mtd/nand/nand_bbt.c

static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)

{

struct nand_chip *this = mtd->priv;

 

bd->options &= ~NAND_BBT_SCANEMPTY;

return create_bbt(mtd, this->buffers->databuf, bd, -1);

}

 

比如对于一个 Samsuny KF2G08 256Mnand,共有2048Block,其中每个块的共有64页,一个页的大小为2048+64Byte,即一个页中主存储区的大小2048Byte, spare 区域的大小为64Byte,其中的OOB信息就存储在spare区域。对于 large page型的nand,即一个页的主存储区大于512Bytenand,一个块是否为好坏,用这个块的第一个page和第二个pagespare区的第一个字节来标记,若这两个块中spare区中的第一个字节值都为0xFF则该坏为好坏,否则为坏块,nand_chip->bbt数组的大小,本例中为512Byte。大小的计算方法为:512 * 8 / 2 =  2048。即用两个bit表示一个块是好的还是坏的。

create_bbt中有一个循环,通过调用scan_block_fast()对每一个块是否完好的信息进行读取,并进行判断,若为坏块,填充对应的bbt数组。scan_block_fast()最终会调用nand_read_oob_std()进行真正OOB信息读取。在读取到信息之后,nand_scan_fast中调用 check_short_pattern进行判断读取到的OOB信息,该信息中的第1个字节反映了是否为坏块。若为坏块,则返回非零到create_bbt函数中,在create_bbt中往nand_chip->bbt 这个数组中填充该块是否为坏块。一个坏块标记占用2bituboot中用两个bit "11"来标志对应的坏为坏块。两个bit "00"标志对应的块为好坏。

 

最后读取完整个nandOOB信息后,通过nand_isbad_bbt用来判断指定的块是否为坏坏。

 

spare区中存储的是OOB信息,一个block中的第一个page和第二个pagespare区中的第一个字节用来保存块是否完好的信息外,spare区的其它内容为ECC校验信息,用来表示主存储区的数据的校验值,每512Byte会生成一个校验值,一个校验值为3个Byte,可以用此来判断讲到的数据是否反转。

 

nand_read_buf用来一个一个读取字节内容。

 

 

create_bbt 0 len 2, chip -1

create_bbt 1 scanlen 0, readlen 1

create_bbt 2 from 0x00000000, numblocks 0x00001000

create_bbt 4 from 0x00000000, buf[0] 0, len 0x00000002

 scan_block_fast j 0, offs 0x00000000, len 2 , ops.ooblen 64

        nand_read_oob 0 from 0x00000000

        nand_do_read_oob 0 chip->oob_poi[0] 0, page 0x00000000, sndcmd 1, len 64, readlen 64

        nand_command_lp column 0x00000800, ctrl 0x00000005

        nand_command_lp page_addr 0x00000000, ctrl 0x00000005

        nand_read_oob_std 0 NAND_CMD_READOOB 0x00000050, page 0, sndcmd 1

        nand_read_buf buf:f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

        nand_read_oob_std 1 chip->oob_poi[0] f0, mtd->oobsize 0x00000040

        nand_do_read_oob 1 chip->oob_poi[0] f0, page 0x00000000, sndcmd 0, len 64

        nand_do_read_oob 2 buf[0] 0, sndcmd 0

        nand_read_oob 1 from 0x00000000, ret 0

        check_short_pattern 0 td->len 1, p[td->offs + i] f0, td->pattern[i] ff

create_bbt 5 from 0x00000000, buf[0] f0, len 0x00000002, ret 1

        create_bbt 6, this->bbt[i >> 3] 0

****####create_bbt 7, i 0x00000000, i>>1 0x00000000, bbt[i>>3] 3, Bad eraseblock 0 at 0x000000000000, ret 1, mtd->ecc_stats.badblocks 1

<think>嗯,用户之前已经问过如何在Linux 4.4内核中同时适配SPI NOR和NAND Flash,现在他们想进一步在NAND Flash上划分包含rootfs的分区。我需要仔细分析他们的需求,确保回答准确。 首先,用户的需求是给NAND Flash分区,并且包含rootfs。这意味着他们可能需要一个可启动的系统,其中rootfs存放在NAND的一个分区里。之前的回答已经涉及到了设备树配置、驱动适配和MTD层整合,现在需要扩展分区部分。 我需要回忆Linux设备树中MTD分区的配置方法。通常,在设备树中定义fixed-partitions,然后为每个分区指定地址和大小。用户需要确保rootfs分区的起始地址和大小正确,避免与其他分区重叠。同时,可能需要考虑uboot环境变量或其他引导相关部分的分区。 接下来,用户可能需要内核启动参数来指定rootfs的位置,例如使用root=/dev/mtdblockX或者通过UBI卷名。这里需要注意,如果使用UBI,可能需要额外的配置,比如启用UBI支持,创建UBI卷等。但用户的问题中没有提到UBI,可能只是简单的块设备分区。 另外,需要考虑NAND Flash的特性,比如坏块管理。如果使用传统的块设备分区,可能需要确保文件系统能够处理坏块,比如使用JFFS2或YAFFS2。而如果使用UBIFS,则需要配置UBI层。用户提到的是rootfs,常见的是使用UBIFS,所以可能需要提到UBI的配置步骤。 然后,我需要检查之前回答中的设备树分区示例是否正确。之前的示例中,NAND的分区可能没有正确指定,因为reg属性在设备树中的地址是从每个设备的起始地址开始计算的。例如,NOR的分区从0开始,而NAND的分区也需要从0开始,因为它们位于不同的MTD设备上。因此,在设备树中,每个flash节点下的partitions应该独立定义,各自的分区reg属性从0开始。 用户可能还需要在启动参数中指定rootfs的位置,比如使用root=ubi0:rootfs或者root=/dev/mtdblockX。需要根据文件系统类型来建议正确的启动参数。 此外,内核配置方面,需要确保相关的文件系统支持已启用,比如Squashfs、UBIFS等。如果使用UBI,还需要CONFIG_MTD_UBI和CONFIG_UBIFS_FS。 最后,需要提醒用户进行验证,比如查看/proc/mtd确认分区正确,使用mtdinfo检查分区详情,并进行读写测试。同时,注意NAND Flash的擦除块大小和页面大小,确保分区对齐,避免性能问题或错误。 可能的问题点包括分区地址错误导致重叠,文件系统不支持,或者内核配置未启用必要选项。需要逐一检查这些方面,确保用户能够顺利实现分区并挂载rootfs。</think>在已有SPI NAND Flash适配的基础上,划分包含rootfs的分区需要以下关键步骤: --- ### **Step 1 - 设备树分区配置** ```dts &nand_flash { partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; /* 建议保留头部空间 */ partition@0 { label = "spl"; reg = <0x0 0x200000>; // 2MB for bootloader }; partition@200000 { label = "uboot-env"; reg = <0x200000 0x100000>; // 1MB环境变量 }; partition@300000 { label = "kernel"; reg = <0x300000 0x500000>; // 5MB内核 }; partition@800000 { label = "rootfs"; reg = <0x800000 0x7800000>; // 120MB根文件系统 }; partition@8000000 { label = "userdata"; reg = <0x8000000 0x8000000>; // 128MB用户数据 }; }; }; ``` --- ### **Step 2 - 内核配置** ```bash # 必须配置的选项 CONFIG_MTD_PARTITIONED_MASTER=y CONFIG_MTD_CMDLINE_PARTS=y # 允许命令行传递分区 CONFIG_MTD_BLOCK=y # 启用块设备访问 CONFIG_MTD_SPI_NAND=y CONFIG_UBIFS_FS=y # 如果使用UBIFS CONFIG_MTD_UBI=y ``` --- ### **Step 3 - NAND特性处理** ```c // 在驱动初始化时配置ECC和OOB static int nand_flash_init(struct spi_device *spi) { struct nand_chip *chip = ...; chip->ecc.mode = NAND_ECC_HW; // 硬件ECC chip->ecc.strength = 4; // 根据具体NAND芯片配置 chip->options = NAND_NO_SUBPAGE_WRITE;// 禁止子页写入 chip->bbt_options = NAND_BBT_USE_FLASH;// 使用flash BBT } ``` --- ### **Step 4 - 文件系统适配** #### **方案A:传统块设备方式** ```dts partition@800000 { label = "rootfs"; reg = <0x800000 0x7800000>; read-only; }; ``` 内核启动参数: ```bash root=/dev/mtdblock3 rootfstype=squashfs ro ``` #### **方案B:UBI卷方式(推荐)** ```dts partition@800000 { label = "ubi"; reg = <0x800000 0x7800000>; }; ``` ```bash # 内核启动参数 root=ubi0:rootfs rootfstype=ubifs ubi.mtd=3 ``` --- ### **Step 5 - 用户空间验证** #### 查看分区信息: ```bash cat /proc/mtd # 输出示例: mtd3: 07800000 00020000 "rootfs" ``` #### UBI操作流程(方案B): ```bash # 格式化UBI卷 ubiformat /dev/mtd3 -y # 附加MTD设备 ubiattach -m 3 # 创建卷 ubimkvol /dev/ubi0 -N rootfs -s 120MiB # 挂载测试 mount -t ubifs ubi0:rootfs /mnt ``` --- ### **关键问题排查** 1. **分区地址溢出**: - 验证`reg`地址范围不超过NAND总容量 - 使用`mtdinfo /dev/mtd3`检查分区详情 2. **ECC错误**: ```dmesg | grep "corrected bitflips" # 持续出现需要调整ecc.strength值 3. **UBI初始化失败**: ```bash dmesg | grep ubi # 常见错误:PEB大小不匹配(需确保CONFIG_MTD_UBI_BEB_LIMIT正确) ``` --- ### **典型文件系统布局** | MTD分区 | 起始地址 | 大小 | 用途 | 文件系统 | |---------|----------|---------|------------|----------| | mtd0 | 0x0 | 2MB | Bootloader | raw | | mtd1 | 0x200000 | 1MB | U-Boot Env | jffs2 | | mtd2 | 0x300000 | 5MB | Kernel | squashfs | | mtd3 | 0x800000 | 120MB | RootFS | ubifs | | mtd4 | 0x8000000| 128MB | UserData | ext4 | --- 通过以上配置,系统将实现: 1. 独立的分区管理 2. 硬件ECC保护 3. 坏块自动处理 4. 支持UBIFS的特性(压缩、损耗均衡) 最终可通过`mount`命令验证: ```bash # 预期输出 /dev/ubi0_0 on / type ubifs (ro,relatime,assert=read-only) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haospark

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值