在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, .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中文網其他相關文章!

Linux是一個基於Unix的多用戶、多任務操作系統,強調簡單性、模塊化和開放性。其核心功能包括:文件系統:以樹狀結構組織,支持多種文件系統如ext4、XFS、Btrfs,使用df-T查看文件系統類型。進程管理:通過ps命令查看進程,使用PID管理進程,涉及優先級設置和信號處理。網絡配置:靈活設置IP地址和管理網絡服務,使用sudoipaddradd配置IP。這些功能在實際操作中通過基本命令和高級腳本自動化得以應用,提升效率並減少錯誤。

進入Linux維護模式的方法包括:1.編輯GRUB配置文件,添加"single"或"1"參數並更新GRUB配置;2.在GRUB菜單中編輯啟動參數,添加"single"或"1"。退出維護模式只需重啟系統。通過這些步驟,你可以在需要時快速進入維護模式,並安全地退出,確保系統的穩定性和安全性。

Linux的核心組件包括內核、shell、文件系統、進程管理和內存管理。 1)內核管理系統資源,2)shell提供用戶交互界面,3)文件系統支持多種格式,4)進程管理通過fork等系統調用實現,5)內存管理使用虛擬內存技術。

Linux系統的核心組成部分包括內核、文件系統和用戶空間。 1.內核管理硬件資源並提供基本服務。 2.文件系統負責數據存儲和組織。 3.用戶空間運行用戶程序和服務。

維護模式是Linux系統中通過單用戶模式或救援模式進入的特殊運行級別,用於系統維護和修復。 1.進入維護模式使用命令“sudosystemctlisolaterescue.target”。 2.在維護模式中,可以檢查並修復文件系統,使用命令“fsck/dev/sda1”。 3.高級用法包括重置root用戶密碼,需掛載文件系統為讀寫模式並編輯密碼文件。

維護模式用於系統維護和修復,允許管理員在簡化環境中工作。 1.系統修復:修復損壞的文件系統和啟動加載器。 2.密碼重置:重置root用戶密碼。 3.軟件包管理:安裝、更新或刪除軟件包。通過修改GRUB配置或使用特定鍵進入維護模式,執行維護任務後可安全退出。

Linux網絡配置可以通過以下步驟完成:1.配置網絡接口,使用ip命令臨時設置或編輯配置文件持久化設置。 2.設置靜態IP,適合需要固定IP的設備。 3.管理防火牆,使用iptables或firewalld工具來控製網絡流量。

維護模式在Linux系統管理中扮演關鍵角色,幫助進行系統修復、升級和配置變更。 1.進入維護模式可以通過GRUB菜單選擇或使用命令“sudosystemctlisolaterescue.target”。 2.在維護模式下,可以執行文件系統修復和系統更新等操作。 3.高級用法包括重置root密碼等任務。 4.常見錯誤如無法進入維護模式或掛載文件系統,可通過檢查GRUB配置和使用fsck命令修復。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver Mac版
視覺化網頁開發工具

記事本++7.3.1
好用且免費的程式碼編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境