MTD分区
有三种分区的方法:
- 控制器驱动提供分区表
- bootloader命令行
- 变相使用bootloader命令行
控制器驱动分区
在控制器驱动中写死,初始化flash时设置。参考 mtd子系统 代码流程
在内核的flash控制器驱动提供分区信息,并注册(mtd_device_register()函数)
分区数据结构
数据结构对应mtd_device_register()函数的第三个参数,是分区的结构体数组指针。
例如:
#define MTD_PARTITION(na, off, sz, flgs) \
{ \
.name = na, .offset = off, \
.size = sz, .mask_flags = flgs, \
}
struct mtd_partition parts[MAX_MTD_PARTITIONS] = {
MTD_PARTITION("boot", MTDPART_OFS_APPEND, SZ_1M, MTD_WRITEABLE),
MTD_PARTITION("env", MTDPART_OFS_APPEND, SZ_256K, MTD_WRITEABLE),
MTD_PARTITION("kernel0", MTDPART_OFS_APPEND, SZ_8M, 0),
};
bootloader命令行分区
u-boot将分区信息(形如:mtdparts=xxx)添加到bootargs中,kernel在启动的时候会解析mtdparts。
示例: " ... mtdparts=samsung-nand0:256k(boot)ro,8m(kernel)ro,16m(ubi-img),-(user)"
注意:中间不能有空格。
内核配置
内核中的mtd驱动必须要支持,即内核配置时需要选上
Device Drivers --->
Memory Technology Device (MTD) support --->
Command line partition table parsing
即:CONFIG_MTD_CMDLINE_PARTS=y
mtdparts的格式
mtdparts=<mtddef>[;<mtddef]
<mtddef> := <mtd-id>:<partdef>[,<partdef>]
<partdef> := <size>[@offset][<name>][ro]
<mtd-id> := unique id used in mapping driver/device
<size> := standard linux memsize OR "-" to denote all remaining space
<name> := (NAME)
因此你在使用的时候需要按照下面的格式来设置:
mtdparts=mtd-id:<size1>@<offset1>(<name1>),<size2>@<offset2>(<name2>)
注意事项
1. mtd-id 必须要跟当前控制器驱动指定的mtd->name一致。
2. 在bootargs参数列表中, 可以指定当前flash的mtd-id,指定 mtdids:nand0=gen_nand.1,前面的nand0则表示第一个flash
3. size在设置的时候有三种方法:
a. 可以为实际的size:" ... mtdparts=samsung-nand0:0x4000(boot)ro,0x800000(kernel)ro,0x1000000(ubi-img),-(config)"
b. 用简写的单位:" ... mtdparts=samsung-nand0:256k(boot)ro,8m(kernel)ro,16m(ubi-img),-(config)"
支持的单位:k,K,m,M,g,G,t,T,p,P,e,E。
c. 也可以为'-'这表示剩余的所有空间。
4. mtdparts=tq2440-0:1m@0(spl)ro,1m(u-boot)ro,3m(kernel)ro,-(rootfs) 等价于
mtdparts=tq2440-0:1m(spl)ro,1m(u-boot)ro,3m(kernel)ro,-(rootfs)
详见:drivers/mtd/cmdlinepart.c 注释
mtdparts命令
为了实现mtdparts分区命令的支持需要在U-boot-2010.06/include/configs/at91sam9263ek.h中添加相关的宏定义
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
加入MTD分区信息:
#define MTDIDS_DEFAULT "nand0=atmel_nand"
#define MTDPARTS_DEFAULT "mtdparts=atmel_nand:15M@0(cramfs)," \
"15M(jffs2)," \
"30M(yaffs2)," \
"-(user)"
保存后退出,回到根目录,重新make
命令用法:
mtdparts 查看分区信息
mtdparts 恢复默认分区
setenv mtdparts xxx 设置分区信息
源码分析(mtdparts)
获得命令行内容
解析bootargs环境变量时,若有“mtdparts”,则将cmdline指向后边的字符串,后边控制器probe时会调用到它。
drivers/mtd/cmdlinepart.c
static int __init mtdpart_setup(char *s)
{
cmdline = s;
return 1;
}
__setup("mtdparts=", mtdpart_setup);
static struct mtd_part_parser cmdline_parser = {
.parse_fn = parse_cmdline_partitions,
.name = "cmdlinepart",
};
cmdline_parser_init(void)
register_mtd_parser(&cmdline_parser)
根据命令行进行分区
xxx_fmc_probe //xxx_fmc.c drivers/mtd/nand/
mtd_device_register(mtd, parts, nr_parts) //mtd.h include/linux/mtd
ret = mtd_device_parse_register(master, NULL, NULL, parts, nr_parts) //mtdcore.c drivers/mtd
parse_mtd_partitions(mtd, types, &parsed, parser_data) //mtdpart.c drivers/mtd
(*parser->parse_fn)(master, &pparts->parts, data)
//drvers/mtd/cmdlinepart.c=>cmdline_parser_init=> register_mtd_parser(&cmdline_parser)
parse_cmdline_partitions //cmdlinepart.c drivers/mtd
const char *mtd_id = master->name;
mtdpart_setup_real(cmdline) //cmdlinepart.c drivers/mtd
对于每一个命令行的分区 (对于每一个mtd-id)
调用newpart()解析分区
保存命令行mtdparts=xxx:yyy的xxx
将解析出来的添加到partitions链表
如果mtd_id与所有的xxx都不相同,则直接退出。
如果解析命令行成功,且分区数目大于0,则使用命令行分区
如果命令行没提供或者解析错误,则使用驱动提供的分区。
后续分析见 mtd子系统 控制器驱动流程
变相使用命令行
例如:在内核里边,修改代码,将配置写死。
EMMC分区
一般使用命令行,或者变相使用命令行。
使用bootloader命令行
示例
设置bootargs环境变量添加 "blkdevparts=mmcblk0:1m(boot),8m(kernel),256m(ext4-img),-(user)"
格式
总格式:blkdevparts=<blkdev-def>[;<blkdev-def>]
<blkdev-def> 格式: <blkdev-id>:<partdef>[,<partdef>]
<partdef> 格式: <size>[@<offset>](part-name)
<blkdev-id>
block device disk name, embedded device used fixed block device,
it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
<size>
partition size, in bytes, such as: 512, 1m, 1G.
<offset>
partition start address, in bytes.
(part-name)
partition name, kernel send uevent with "PARTNAME". application can create
a link to block device partition with the name "PARTNAME".
user space application can access partition by partition name.
Example:
eMMC disk name is "mmcblk0" and "mmcblk0boot0"
bootargs:
'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'
dmesg:
mmcblk0: p1(data0) p2(data1) p3()
mmcblk0boot0: p1(boot) p2(kernel)
详见:kernel/Documentation/block/cmdline-partition.txt
注意
对于“blkdevparts=”后边紧跟的这个名字,格式是固定的,必须是mmcblkm或者mmcblkmbootn
这个是控制器的序号,详见 MMC子系统分析 控制器源代码分析
源码分析(blkdevparts)
获得命令行内容
解析bootargs环境变量时,若有“blkdevparts”,则将cmdline指向后边的字符串,后边控制器probe时会调用到它。
kernel/block/partitions/cmdline.c
static int __init cmdline_parts_setup(char *s)
{
cmdline = s;
return 1;
}
__setup("blkdevparts=", cmdline_parts_setup);
根据命令行进行分区
调用到此处的流程见 MMC子系统分析 控制器源代码分析
mmc_rescan //core.c drivers/mmc/core/
mmc_attach_mmc
mmc_add_card
device_add
bus_probe_device
__device_attach
bus_for_each_drv
driver_probe_device
mmc_blk_probe
mmc_add_disk
device_add_disk
blkdev_get
__blkdev_get
rescan_partitions
check_partition
调用check_part[]数组成员
cmdline_partition
kernel/block/partitions/cmdline.c
static char *cmdline;
struct cmdline_parts *bdev_parts;
cmdline_partition()
//传进来的参数名为state
char bdev[BDEVNAME_SIZE];
//cmdline现在已经指向 "mmcblk0:1m(boot),8m(kernel),256m(ext4-img),-(user)" //解析每一个由;分开的分区
cmdline_parts_parse(&bdev_parts, cmdline) //cmdline-parser.c kernel/block/
//解析每一个由:开始的分区
parse_parts(next_parts, pbuf) //cmdline-parser.c kernel/block/
//解析每一个由,分开的分区
parse_subpart(next_subpart, buf); //cmdline-parser.c kernel/block/
bdevname(state->bdev, bdev); //block/partition-generic.c
从state->bdev->bd_disk获得disk名字(一般是mmcblk)\
从state->bdev->bd_part->partno获得设备号
将其组成字符串,赋值给bdev
cmdline_parts_find(bdev_parts, bdev); //block/cmdline-parser.c
将bdev(控制器初始化时生成的)与所有bdev_parts->name(解析命令行生成的,是 "blkdevparts="到 ":"
之间的字符串)比较,
如果没有匹配的,则返回
//获得容量
disk_size = get_capacity(state->bdev->bd_disk) << 9;
//根据命令行设置分区数据(偏移、大小等)
cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state);
若成功,则之后会打印:mmcblk0: p1(boot) p2(kernel) p3(ext4-img) p4(user)
变相使用命令行
kernel/block/partitions/cmdline.c => cmdline_partition 直接在开始给cmdline赋值,例如:
cmdline = "mmcblk0:1m(boot),512k(env),8m(kernel),8m(config),-(user)"
















