本篇內(nèi)容主要講解“l(fā)inux mtd的概念是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“l(fā)inux mtd的概念是什么”吧!
天水ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!
在linux中,mtd是指“內(nèi)存技術(shù)設(shè)備”,是存儲(chǔ)設(shè)備中的一個(gè)子系統(tǒng)。linux引入MTD系統(tǒng)是為了給NOR FLASH和NAND FLASH設(shè)備提供統(tǒng)一接口。MTD設(shè)備通??煞譃樗膶樱涸O(shè)備節(jié)點(diǎn)、MTD設(shè)備層、MTD原始設(shè)備層、硬件驅(qū)動(dòng)層。
本教程操作環(huán)境:linux5.9.8系統(tǒng)、Dell G3電腦。
Linux MTD是什么?
MTD全稱“Memory Technology Device”,意思為“內(nèi)存技術(shù)設(shè)備”,是Linux的存儲(chǔ)設(shè)備中的一個(gè)子系統(tǒng)。
在Linux內(nèi)核中,引入MTD層為NOR FLASH和NAND FLASH設(shè)備提供統(tǒng)一接口。MTD將文件系統(tǒng)與底層FLASH存儲(chǔ)器進(jìn)行了隔離。
設(shè)計(jì)此MTD系統(tǒng)的目的是,對(duì)于內(nèi)存類的設(shè)備,提供一個(gè)抽象層,一個(gè)接口,使得對(duì)于硬件驅(qū)動(dòng)設(shè)計(jì)者來說,只需要去提供最簡單的底層硬件設(shè)備的讀/寫/擦除函數(shù)就可以了,數(shù)據(jù)對(duì)于上層使用者來說是如何表示的,可以不關(guān)心,因?yàn)镸TD存儲(chǔ)設(shè)備子系統(tǒng)都幫你做好了。
MTD框架
Linux的MTD設(shè)備位于drivers/mtd/下面。
MTD文件下的內(nèi)容如下:
MTD設(shè)備通??煞譃樗膶?/p>
上到下依次是:設(shè)備節(jié)點(diǎn)、MTD設(shè)備層、MTD原始設(shè)備層和硬件驅(qū)動(dòng)層。
1.cmdlinepart.c
當(dāng)mtd分區(qū)表由u-boot通過cmd參數(shù)傳輸給linux時(shí),linux內(nèi)核可以不用對(duì)mtdparts進(jìn)行注冊添加,只需要將MTD中的command line partition選項(xiàng)開啟即可。使用這種的方法u-boot下需要對(duì)MTD進(jìn)行支持,且所傳輸?shù)膍td分區(qū)參數(shù)要符合格式要求。
2.devices文件夾
當(dāng)我們有一個(gè)spi flash設(shè)備時(shí)且要使用mtd進(jìn)行管理,我們一般會(huì)將其放在devices文件夾下,如devices文件夾下面的m25p80.c就是一個(gè)典型的spi flash設(shè)備。
3.chips/nand/onenand文件夾
nand flash 驅(qū)動(dòng)在nand文件夾下;
onenand flash 驅(qū)動(dòng)在onenand文件夾下;
nor flash比較雜,下面幾個(gè)文件下都會(huì)有:
chips:cfi/jedec接口通用驅(qū)動(dòng)
devices:nor flash底層驅(qū)動(dòng)(spi flash)
maps:nor flash映射關(guān)系相關(guān)函數(shù)
4.核心文件
mtdchar.c : MTD字符設(shè)備接口相關(guān)實(shí)現(xiàn),設(shè)備號(hào)31;
mtdblock.c : MTD塊設(shè)備接口相關(guān)實(shí)現(xiàn),設(shè)備號(hào)90,;
mtdcore.c: MTD原始設(shè)備接口相關(guān)實(shí)現(xiàn);
mtdpart.c : MTD分區(qū)接口相關(guān)實(shí)現(xiàn)。
5.ubi
ubifs文件的支持層,當(dāng)使用ubifs文件系統(tǒng)時(shí),需要將Device Drivers -> Memory Technology Device (MTD) support -> UBI -Unsorted block image 中的Enable UBI選中。
將File systems -> Miscellaneous filesystems中的UBIFS file system support選中。
MTD分區(qū)表的實(shí)現(xiàn)
在開機(jī)過程從console經(jīng)??梢钥吹筋愃埔韵滦畔?,
0x000000000000-0x000000100000 : "Bootloade" 0x000000100000-0x000002000000 : "Kernel" 0x000002000000-0x000003000000 : "User" 0x000003000000-0x000008000000 : "File System"
這就是MTD給我們一種最直觀的表示形式,給我們展示了內(nèi)存中各模塊的分區(qū)結(jié)構(gòu),但這些分區(qū)是怎樣實(shí)現(xiàn)的呢?分區(qū)表的實(shí)現(xiàn)方式有幾種,下面進(jìn)行分別說明:
注:分區(qū)表實(shí)現(xiàn)的前提是MTD設(shè)備驅(qū)動(dòng)已經(jīng)成功了,否則連驅(qū)動(dòng)都沒成功就無分區(qū)可說了。
在內(nèi)核中添加這是一個(gè)比較經(jīng)常使用的方法,隨便一本驅(qū)動(dòng)移植的書上應(yīng)該都有,主要就是在平臺(tái)設(shè)備里面添加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); }
因?yàn)槲覀兊腗TD驅(qū)動(dòng)已經(jīng)完成了,當(dāng)device和driver匹配后會(huì)調(diào)用驅(qū)動(dòng)中的probe接口函數(shù),我們需要在probe函數(shù)里面調(diào)用add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);
實(shí)現(xiàn)分區(qū)表的添加。
在u-boot下可以通過添加mtdparts信息到bootargs中,u-boot啟動(dòng)后會(huì)將bootargs中的信息傳送給kernel,,kernel在啟動(dòng)的時(shí)候會(huì)解析bootargs中mtdparts的部分,這邊舉個(gè)例子:
mtdparts=nand.0:1M(Bootloader)ro,31M(Kernel)ro,16M(User),96M(File System)
,更具體的mtdparts格式可以查閱下相關(guān)資料。
為了使kernel能夠解析mtdparts信息,我們需要將內(nèi)核中的Device Drivers -> Memory Technology Device (MTD) support ->Command line partition table parsing選項(xiàng)開啟,這在上面已經(jīng)說過。
在內(nèi)核中添加分區(qū)表的時(shí)候,我們是在平臺(tái)設(shè)備里面加入mtd_partition信息。這邊通過u-boot傳參則取消平臺(tái)設(shè)備里面的partition信息,那我們需要怎樣解析u-boot的傳過來的mtdparts呢。
u-boot傳參過來后,cmdlinepart.c中會(huì)將這些參數(shù)解析好,存在里面LIST_HEAD(part_parsers)
鏈表里面,然后我們在驅(qū)動(dòng)的probe函數(shù)中,通過調(diào)用mtd_device_parse_register(mtd, probe_types,&ppdata, NULL, 0);
函數(shù)。
mtd_device_parse_register()
函數(shù)位于drivers/mtd/mtdcore.c 中,內(nèi)容如下:
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; }
可以看到該函數(shù)會(huì)先執(zhí)行parse_mtd_partitions(mtd, types, &real_parts, parser_data);
函數(shù),后面還是通過add_mtd_partitions()
函數(shù)來實(shí)現(xiàn)分區(qū)表的添加。
parse_mtd_partitions()
函數(shù)位于drivers/mtd/mtdpart.c中,內(nèi)容如下:
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; }
進(jìn)入parse_mtd_partitions()
函數(shù)會(huì)先判斷types的類型,如果為空則給默認(rèn)值,types的類型一般就兩種,如下:
static const char * const default_mtd_part_types[] = { "cmdlinepart", "ofpart", NULL };
第一個(gè)"cmdlinepart"即u-boot傳參的方式,第二個(gè)"ofpart"即下面要講到的使用dts傳參的方式,判斷完類型后,就通過get_partition_parser
去解析part_parsers
鏈表里面的數(shù)據(jù),這樣就完成u-boot參數(shù)的解析。
在Linux3.14以后的linux版本中,加入一個(gè)新的知識(shí)DTS(Device tree),dts其實(shí)就是為了解決ARM Linux中的冗余代碼,在Linux2.6版本的arch/arm/plat.xxx和arch/arm/mach.xxx中充斥著大量的垃圾代碼,采用Device Tree后,許多硬件的細(xì)節(jié)可以直接透過它傳遞給Linux,而不再需要在kernel中進(jìn)行大量的冗余編碼,關(guān)于dts可以自行查閱資料。
dts傳參的原理其實(shí)和u-boot一樣,區(qū)別在于:u-boot的時(shí)候是通過cmdlinepart.c文件實(shí)現(xiàn)分區(qū)信息寫入LIST_HEAD(part_parsers)
鏈表,dts則是用過ofpart.c文件實(shí)現(xiàn)分區(qū)信息寫入LIST_HEAD(part_parsers)
鏈表,所以同樣要把ofpart.c文件的宏打開,在調(diào)用mtd_device_parse_register(mtd, probe_types,&ppdata, NULL, 0);
函數(shù)的時(shí)候types要設(shè)置成ofpart。
如果去對(duì)比Linux2.6版本和Linux3.14版本,會(huì)發(fā)現(xiàn)drivers/mtd/ofpart.c和drivers/mtd/mtdpart.c文件有所不同,Linux3.8版本里面多了Device tree這一部分的內(nèi)容,感興趣的可以自己深究下。
這邊舉個(gè)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>; }; };
到此,相信大家對(duì)“l(fā)inux mtd的概念是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!