linux mtd的概念是什么

88次阅读
没有评论

共计 5975 个字符,预计需要花费 15 分钟才能阅读完成。

本篇内容主要讲解“linux mtd 的概念是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“linux mtd 的概念是什么”吧!

在 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 系统的目的是,对于内存类的设备,提供一个抽象层,一个接口,使得对于硬件驱动设计者来说,只需要去提供最简单的底层硬件设备的读 / 写 / 擦除函数就可以了,数据对于上层使用者来说是如何表示的,可以不关心,因为 MTD 存储设备子系统都帮你做好了。

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,
 .twrph2 = 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 函数里面调用 add_mtd_partitions(s3c_mtd, sets- partitions, sets- nr_partitions); 实现分区表的添加。

2.u-boot 传参

在 u -boot 下可以通过添加 mtdparts 信息到 bootargs 中,u-boot 启动后会将 bootargs 中的信息传送给 kernel,,kernel 在启动的时候会解析 bootargs 中 mtdparts 的部分,这边举个例子:

mtdparts=nand.0:1M(Bootloader)ro,31M(Kernel)ro,16M(User),96M(File System),更具体的 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 中会将这些参数解析好,存在里面 LIST_HEAD(part_parsers) 链表里面,然后我们在驱动的 probe 函数中,通过调用 mtd_device_parse_register(mtd, probe_types, ppdata, NULL, 0); 函数。

mtd_device_parse_register() 函数位于 drivers/mtd/mtdcore.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;
}

可以看到该函数会先执行 parse_mtd_partitions(mtd, types, real_parts, parser_data); 函数,后面还是通过 add_mtd_partitions() 函数来实现分区表的添加。

parse_mtd_partitions() 函数位于 drivers/mtd/mtdpart.c 中,内容如下:

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;
}

进入 parse_mtd_partitions() 函数会先判断 types 的类型,如果为空则给默认值,types 的类型一般就两种,如下:

static const char * const default_mtd_part_types[] = {
  cmdlinepart ,
  ofpart ,
 NULL
};

第一个 cmdlinepart 即 u -boot 传参的方式,第二个 ofpart 即下面要讲到的使用 dts 传参的方式,判断完类型后,就通过 get_partition_parser 去解析 part_parsers 链表里面的数据,这样就完成 u -boot 参数的解析。

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 文件实现分区信息写入 LIST_HEAD(part_parsers) 链表,dts 则是用过 ofpart.c 文件实现分区信息写入 LIST_HEAD(part_parsers) 链表,所以同样要把 ofpart.c 文件的宏打开,在调用 mtd_device_parse_register(mtd, probe_types, ppdata, NULL, 0); 函数的时候 types 要设置成 ofpart。

如果去对比 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 的概念是什么”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-03发表,共计5975字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)