linux mtd是什么

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)?{ ????????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?parse_fn)(master,?pparts,?data); ????????put_partition_parser(parser); ????????if?(ret?>?0)?{ ????????????printk(KERN_NOTICE?"%d?%s?partitions?found?on?MTD?device?%sn", ???????????????????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?=?; ????ranges?=?;???/*?CS0:?NAND?*/ ????nand@0,0?{ ????????partition@1?{ ????????????label?=?"Bootloader"; ????????????reg?=?; ????????}; ????????partition@2?{ ????????????label?=?"Kernel"; ????????????reg?=?; ????????}; ????????partition@3?{ ????????????label?=?"User"; ????????????reg?=?; ????????}; ????????partition@4?{ ????????????label?=?"File?System"; ????????????reg?=?; ????????}; ????};

Linux mtd system的分析就到這邊,有感悟時會持續會更新。

相關推薦:《Linux視頻教程

以上就是

? 版權聲明
THE END
喜歡就支持一下吧
點贊11 分享