在linux中,mtd是指“内存技术设备”,是存储设备中的一个子系统。linux引入MTD系统是为了给NOR FLASH和NAND FLASH设备提供统一接口。MTD设备通常可分为四层:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。
本教程操作环境:linux5.9.8系统、Dell G3电脑。 Linux MTD是什么? MTD全称“Memory Technology Device”,意思为“内存技术设备”,是Linux的存储设备中的一个子系统。 在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。
MTD框架 Linux的MTD设备位于drivers/mtd/下面。 MTD文件下的内容如下:
MTD设备通常可分为四层 上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。
1.cmdlinepart.c 当mtd分区表由u-boot通过cmd参数传输给linux时,linux内核可以不用对mtdparts进行注册添加,只需要将MTD中的command line partition选项开启即可。使用这种的方法u-boot下需要对MTD进行支持,且所传输的mtd分区参数要符合格式要求。 2.devices文件夹 当我们有一个spi flash设备时且要使用mtd进行管理,我们一般会将其放在devices文件夹下,如devices文件夹下面的m25p80.c就是一个典型的spi flash设备。 3.chips/nand/onenand文件夹 nand flash 驱动在nand文件夹下; onenand flash 驱动在onenand文件夹下; nor flash比较杂,下面几个文件下都会有: chips:cfi/jedec接口通用驱动 devices:nor flash底层驱动(spi flash) maps:nor flash映射关系相关函数 4.核心文件 mtdchar.c : MTD字符设备接口相关实现,设备号31; mtdblock.c : MTD块设备接口相关实现,设备号90,; mtdcore.c: MTD原始设备接口相关实现; mtdpart.c : MTD分区接口相关实现。 5.ubi ubifs文件的支持层,当使用ubifs文件系统时,需要将Device Drivers -> Memory Technology Device (MTD) support -> UBI -Unsorted block image 中的Enable UBI选中。 将File systems -> Miscellaneous filesystems中的UBIFS file system support选中。 MTD分区表的实现 在开机过程从console经常可以看到类似以下信息, 0x000000000000-0x000000100000 : "Bootloade" 0x000000100000-0x000002000000 : "Kernel" 0x000002000000-0x000003000000 : "User" 0x000003000000-0x000008000000 : "File System" 这就是MTD给我们一种最直观的表示形式,给我们展示了内存中各模块的分区结构,但这些分区是怎样实现的呢?分区表的实现方式有几种,下面进行分别说明: 注:分区表实现的前提是MTD设备驱动已经成功了,否则连驱动都没成功就无分区可说了。 1.内核中添加在内核中添加这是一个比较经常使用的方法,随便一本驱动移植的书上应该都有,主要就是在平台设备里面添加mtd_partition,添加类似下面的信息,这边就不过多描述 struct mtd_partition s3c_nand_part[] = {
{
.name = "Bootloader",
.offset = 0,
.size = (1 * SZ_1M),
.mask_flags = MTD_CAP_NANDFLASH,
},
{
.name = "Kernel",
.offset = (1 * SZ_1M),
.size = (31 * SZ_1M) ,
.mask_flags = MTD_CAP_NANDFLASH,
},
{
.name = "User",
.offset = (32 * SZ_1M),
.size = (16 * SZ_1M) ,
},
{
.name = "File System",
.offset = (48 * SZ_1M),
.size = (96 * SZ_1M),
}
};
static struct s3c_nand_set s3c_nand_sets[] = {
[0] = {
.name = "nand",
.nr_chips = 1,
.nr_partitions = ARRAY_SIZE(s3c_nand_part),
.partitions = ok6410_nand_part,
},
};
static struct s3c_platform_nand s3c_nand_info = {
.tacls = 25,
.twrph0 = 55,
.twrph1 = 40,
.nr_sets = ARRAY_SIZE(s3c_nand_sets),
.sets = ok6410_nand_sets,
};
static void __init s3c_machine_init(void)
{
s3c_nand_set_platdata(&s3c_nand_info);
}因为我们的MTD驱动已经完成了,当device和driver匹配后会调用驱动中的probe接口函数,我们需要在probe函数里面调用 2.u-boot传参在u-boot下可以通过添加mtdparts信息到bootargs中,u-boot启动后会将bootargs中的信息传送给kernel,,kernel在启动的时候会解析bootargs中mtdparts的部分,这边举个例子:
为了使kernel能够解析mtdparts信息,我们需要将内核中的Device Drivers -> Memory Technology Device (MTD) support ->Command line partition table parsing选项开启,这在上面已经说过。 在内核中添加分区表的时候,我们是在平台设备里面加入mtd_partition信息。这边通过u-boot传参则取消平台设备里面的partition信息,那我们需要怎样解析u-boot的传过来的mtdparts呢。 u-boot传参过来后,cmdlinepart.c中会将这些参数解析好,存在里面
int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
struct mtd_part_parser_data *parser_data,
const struct mtd_partition *parts,
int nr_parts)
{
int err;
struct mtd_partition *real_parts;
err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
if (err <= 0 && nr_parts && parts) {
real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
GFP_KERNEL);
if (!real_parts)
err = -ENOMEM;
else
err = nr_parts;
}
if (err > 0) {
err = add_mtd_partitions(mtd, real_parts, err);
kfree(real_parts);
} else if (err == 0) {
err = add_mtd_device(mtd);
if (err == 1)
err = -ENODEV;
}
return err;
}可以看到该函数会先执行
int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct mtd_part_parser *parser;
int ret = 0;
if (!types)
types = default_mtd_part_types;
for ( ; ret <= 0 && *types; types++) {
parser = get_partition_parser(*types);
if (!parser && !request_module("%s", *types))
parser = get_partition_parser(*types);
if (!parser)
continue;
ret = (*parser->parse_fn)(master, pparts, data);
put_partition_parser(parser);
if (ret > 0) {
printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
ret, parser->name, master->name);
break;
}
}
return ret;
}进入 static const char * const default_mtd_part_types[] = {
"cmdlinepart",
"ofpart",
NULL
};第一个"cmdlinepart"即u-boot传参的方式,第二个"ofpart"即下面要讲到的使用dts传参的方式,判断完类型后,就通过 3.dts传参在Linux3.14以后的linux版本中,加入一个新的知识DTS(Device tree),dts其实就是为了解决ARM Linux中的冗余代码,在Linux2.6版本的arch/arm/plat.xxx和arch/arm/mach.xxx中充斥着大量的垃圾代码,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码,关于dts可以自行查阅资料。 dts传参的原理其实和u-boot一样,区别在于:u-boot的时候是通过cmdlinepart.c文件实现分区信息写入 如果去对比Linux2.6版本和Linux3.14版本,会发现drivers/mtd/ofpart.c和drivers/mtd/mtdpart.c文件有所不同,Linux3.8版本里面多了Device tree这一部分的内容,感兴趣的可以自己深究下。 这边举个dts的例子: pinctrl-0 = <&s3c_nand_flash>;
ranges = <0 0 0x000000000000 0x000008000000>; /* CS0: NAND */
nand@0,0 {
partition@1 {
label = "Bootloader";
reg = <0x000000000000 0x000000100000>;
};
partition@2 {
label = "Kernel";
reg = <0x000000100000 0x000002000000>;
};
partition@3 {
label = "User";
reg = <0x000002000000 0x000003000000>;
};
partition@4 {
label = "File System";
reg = <0x000003000000 0x000008000000>;
};
};Linux mtd system的分析就到这边,有感悟时会持续会更新。 相关推荐:《Linux视频教程》 以上就是linux mtd是什么的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
