Linux에서 mtd는 "메모리 기술 장치"를 의미하며 저장 장치의 하위 시스템입니다. MTD 시스템은 NOR FLASH 및 NAND FLASH 장치에 대한 통합 인터페이스를 제공하기 위해 Linux에 도입되었습니다. MTD 장치는 일반적으로 장치 노드, MTD 장치 계층, MTD 원래 장치 계층 및 하드웨어 드라이버 계층의 네 가지 계층으로 나눌 수 있습니다.
이 튜토리얼의 운영 환경: linux5.9.8 시스템, Dell G3 컴퓨터.
리눅스 MTD란 무엇인가요?
MTD는 "Memory Technology Device"의 약자로 "메모리 기술 장치"를 의미하며 Linux 저장 장치의 하위 시스템입니다.
Linux 커널에는 NOR FLASH 및 NAND FLASH 장치에 대한 통합 인터페이스를 제공하기 위해 MTD 계층이 도입되었습니다. MTD는 기본 FLASH 메모리에서 파일 시스템을 분리합니다.
이 MTD 시스템을 설계하는 목적은 메모리 장치에 대한 추상화 계층과 인터페이스를 제공하는 것이므로 하드웨어 드라이버 설계자는 기본 하드웨어 장치에 대한 가장 간단한 읽기/쓰기/삭제 기능만 삭제하면 됩니다. MTD 저장 장치 하위 시스템이 데이터를 상위 사용자에게 표시하는 방식에 대해 걱정할 필요가 없습니다.
MTD 프레임워크
Linux의 MTD 장치는 drivers/mtd/ 아래에 있습니다.
MTD 파일 아래의 내용은 다음과 같습니다.
MTD 장치는 일반적으로 4개의 계층으로 나눌 수 있습니다.
위에서 아래로: 장치 노드, MTD 장치 계층, MTD 원래 장치 계층 및 하드웨어 드라이버 계층.
1.cmdlinepart.c
mtd 파티션 테이블이 cmd 매개변수를 통해 u-boot에 의해 Linux로 전송될 때 Linux 커널은 mtdparts를 등록하고 추가할 필요가 없으며 단지 MTD의 명령줄 파티션 옵션을 켜기만 하면 됩니다. 이 방법을 사용하려면 u-boot가 MTD를 지원해야 하며 전송된 mtd 파티션 매개변수가 형식 요구 사항을 충족해야 합니다.
2.devices 폴더
우리가 spi 플래시 장치를 가지고 있고 그것을 관리하기 위해 mtd를 사용하고 싶을 때, 우리는 보통 이를 devices 폴더 아래에 넣습니다. 예를 들어 devices 폴더 아래 m25p80.c가 spi 플래시의 전형적인 예입니다. 장치.
3.chips/nand/onenand 폴더
nand 플래시 드라이버는 nand 폴더 아래에 있습니다.
onenand 플래시 드라이버는 onenand 폴더 아래에 있습니다.
플래시도 상당히 복잡하며 다음에서 찾을 수 있습니다. 파일:
칩: cfi/jedec 인터페이스 범용 드라이버
장치: 플래시 기본 드라이버(spi 플래시) 없음
maps: 플래시 매핑 관계 관련 기능 없음
4. 코어 파일
mtdchar.c: MTD 문자 장치 인터페이스 관련 구현, 장치 번호 31;
mtdblock.c: MTD 블록 장치 인터페이스 관련 구현, 장치 번호 90,
mtdcore.c: MTD 원래 장치 인터페이스 관련 구현
mtdpart.c: MTD 파티션 인터페이스 관련 구현.
5.ubi
ubifs 파일 시스템을 사용하는 경우 장치 드라이버에서 UBI 활성화 -> MTD(Memory Technology Device) 지원 -> UBI -Unsorted block image를 선택해야 합니다.
파일 시스템 -> 기타 파일 시스템에서 UBIFS 파일 시스템 지원을 선택하세요.
MTD 파티션 테이블 구현
부팅 프로세스 중에 콘솔에서 다음과 유사한 정보를 자주 볼 수 있습니다.
0x000000000000-0x000000100000 : "Bootloade" 0x000000100000-0x000002000000 : "Kernel" 0x000002000000-0x000003000000 : "User" 0x000003000000-0x000008000000 : "File System"
이것은 MTD가 제공하는 가장 직관적인 표현 형식으로 우리에게 보여줍니다. 메모리의 다양한 파티션. 모듈의 파티션 구조. 이러한 파티션은 어떻게 구현됩니까? 파티션 테이블을 구현하는 방법에는 여러 가지가 있으며 아래에 설명되어 있습니다.
참고: 파티션 테이블을 구현하기 위한 전제 조건은 MTD 장치 드라이버가 성공해야 한다는 것입니다. 드라이버가 성공하지 못했습니다.
커널에 추가하는 것은 드라이버 이식 책에서 흔히 볼 수 있는 방법입니다. 가장 중요한 것은 플랫폼 장치에 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 드라이버가 완료되었으므로 드라이버의 프로브 인터페이스 기능을 호출해야 합니다. add_mtd_partitions(s3c_mtd, 프로브 함수에 설정 ->partitions, set->nr_partitions);파티션 테이블 추가. add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);
实现分区表的添加。
在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)
2.u-boot 매개변수 전송
🎜🎜u-boot에서 mtdparts 정보를 bootargs에 추가할 수 있습니다. u-boot가 시작된 후 bootargs의 정보를 커널로 전송하고 커널은 이를 구문 분석합니다. bootargs의 mtdparts 부분은 다음과 같습니다. 예: 🎜🎜mtdparts=nand.0:1M(Bootloader)ro,31M(Kernel)ro,16M(User),96M(File System)
, 보다 구체적인 mtdparts 형식은 관련 정보를 참조하세요. 🎜🎜커널이 mtdparts 정보를 구문 분석하려면 위에서 언급한 대로 커널에서 장치 드라이버 -> MTD(메모리 기술 장치) 지원 ->명령줄 파티션 테이블 구문 분석 옵션을 활성화해야 합니다. 🎜在内核中添加分区表的时候,我们是在平台设备里面加入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参数的解析。
在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视频教程》
위 내용은 리눅스 mtd가 뭐예요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!