首頁  >  文章  >  運維  >  linux mtd是什麼

linux mtd是什麼

青灯夜游
青灯夜游原創
2022-05-11 17:22:484586瀏覽

在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檔案下的內容如下:

linux mtd是什麼

MTD裝置通常可分為四層

上依序為:裝置節點、MTD設備層、MTD原始設備層及硬體驅動層。

linux 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函數裡面呼叫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视频教程

以上是linux mtd是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn