共計 5975 個字符,預計需要花費 15 分鐘才能閱讀完成。
本篇內容主要講解“linux mtd 的概念是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“linux mtd 的概念是什么”吧!
在 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,
.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);
}
因為我們的 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 的概念是什么”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!