0

0

linux mtd是什么

青灯夜游

青灯夜游

发布时间:2022-05-11 17:22:48

|

5443人浏览过

|

来源于php中文网

原创

在linux中,mtd是指“内存技术设备”,是存储设备中的一个子系统。linux引入mtd系统是为了给nor flash和nand flash设备提供统一接口。mtd设备通常可分为四层:设备节点、mtd设备层、mtd原始设备层、硬件驱动层。

linux 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文件下的内容如下:

1.png

MTD设备通常可分为四层

上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。

2.png

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函数里面调用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 system的分析就到这边,有感悟时会持续会更新。

相关推荐:《Linux视频教程

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

463

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

135

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

64

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

26

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

14

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

524

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

53

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 9.3万人学习

Git 教程
Git 教程

共21课时 | 3.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号