Linux MTD系统剖析
MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。
如上图所示,MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。
Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。
MTD原始设备层:用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c: MTD原始设备接口相关实现,mtdpart.c : MTD分区接口相关实现。
MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。其中mtdchar.c : MTD字符设备接口相关实现,mtdblock.c : MTD块设备接口相关实现。
设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备
MTD数据结构:
1.Linux内核使用mtd_info结构体表示MTD原始设备,这其中定义了大量关于MTD的数据和操作函数(后面将会看到),所有的mtd_info结构体存放在mtd_table结构体数据里。在/drivers/mtd/mtdcore.c里:
struct mtd_info *mtd_table[MAX_MTD_DEVICES];
- struct mtd_info *mtd_table[MAX_MTD_DEVICES];
2.Linux内核使用mtd_part结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。
struct mtd_part { struct mtd_info mtd; /* 分区信息, 大部分由master决定 */ struct mtd_info *master; /* 分区的主分区 */ uint64_t offset; /* 分区的偏移地址 */ int index; /* 分区号 (Linux3.0后不存在该字段) */ struct list_head list; /* 将mtd_part链成一个链表mtd_partitons */ int registered; };
mtd_info结构体主要成员,为了便于观察,将重要的数据放在前面,不大重要的编写在后面。
struct mtd_info { u_char type; /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */ uint32_t flags; /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */ uint64_t size; /* mtd设备的大小 */ uint32_t erasesize; /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */ uint32_t writesize; /* 写大小, 对于norFlash是字节,对nandFlash为一页 */ uint32_t oobsize; /* OOB字节数 */ uint32_t oobavail; /* 可用的OOB字节数 */ unsigned int erasesize_shift; /* 默认为0,不重要 */ unsigned int writesize_shift; /* 默认为0,不重要 */ unsigned int erasesize_mask; /* 默认为1,不重要 */ unsigned int writesize_mask; /* 默认为1,不重要 */ const char *name; /* 名字, 不重要*/ int index; /* 索引号,不重要 */ int numeraseregions; /* 通常为1 */ struct mtd_erase_region_info *eraseregions; /* 可变擦除区域 */ void *priv; /* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */ struct module *owner; /* 一般设置为THIS_MODULE */ /* 擦除函数 */ int (*erase) (struct mtd_info *mtd, struct erase_info *instr); /* 读写flash函数 */ int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); /* 带oob读写Flash函数 */ int (*read_oob) (struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); int (*write_oob) (struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops); int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); /* Sync */ void (*sync) (struct mtd_info *mtd); /* Chip-supported device locking */ int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); /* 电源管理函数 */ int (*suspend) (struct mtd_info *mtd); void (*resume) (struct mtd_info *mtd); /* 坏块管理函数 */ int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len); unsigned long (*get_unmapped_area) (struct mtd_info *mtd, unsigned long len, unsigned long offset, unsigned long flags); struct backing_dev_info *backing_dev_info; struct notifier_block reboot_notifier; /* default mode before reboot */ /* ECC status information */ struct mtd_ecc_stats ecc_stats; int subpage_sft; struct device dev; int usecount; int (*get_device) (struct mtd_info *mtd); void (*put_device) (struct mtd_info *mtd); };
mtd_info结构体中的read()、write()、read_oob()、write_oob()、erase()是MTD设备驱动要实现的主要函数,幸运的是Linux大牛已经帮我们实现了一套适合大部分FLASH设备的mtd_info成员函数。
如果MTD设备只有一个分区,那么使用下面两个函数注册和注销MTD设备。
int add_mtd_device(struct mtd_info *mtd) int del_mtd_device (struct mtd_info *mtd)
如果MTD设备存在其他分区,那么使用下面两个函数注册和注销MTD设备。
int add_mtd_partitions(struct mtd_info *master,const struct mtd_partition *parts,int nbparts) int del_mtd_partitions(struct mtd_info *master)
其中mtd_partition结构体表示分区的信息
struct mtd_partition { char *name; /* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */ uint64_t size; /* 分区大小 */ uint64_t offset; /* 分区偏移值 */ uint32_t mask_flags; /* 掩码标识,不重要 */ struct nand_ecclayout *ecclayout; /* OOB布局 */ struct mtd_info **mtdp; /* pointer to store the MTD object */ }; 其中nand_ecclayout结构体: struct nand_ecclayout { __u32 eccbytes; /* ECC字节数 */ __u32 eccpos[64]; /* ECC校验码在OOB区域存放位置 */ __u32 oobavail; /* 除了ECC校验码之外可用的OOB字节数 */ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; };
关于nand_ecclayout结构体实例,更多可参考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64实例。
MTD设备层:
mtd字符设备接口:
/drivers/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它,可以直接访问Flash设备,与前面的字符驱动一样,通过file_operations结构体里面的open()、read()、write()、ioctl()可以读写Flash,通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)
mtd块设备接口:
/drivers/mtd/mtdblock.c文件实现了MTD块设备接口,主要原理是将Flash的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。 但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。
MTD硬件驱动层:
Linux内核再MTD层下实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c),因此芯片级的NAND驱动不再需要实现mtd_info结构体中的read()、write()、read_oob()、write_oob()等成员函数。
MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。
struct nand_chip {void __iomem *IO_ADDR_R; /* 读8位I/O线地址 */void __iomem *IO_ADDR_W; /* 写8位I/O线地址 *//* 从芯片中读一个字节 */uint8_t (*read_byte)(struct mtd_info *mtd); /* 从芯片中读一个字 */u16 (*read_word)(struct mtd_info *mtd); /* 将缓冲区内容写入芯片 */void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); /* 读芯片读取内容至缓冲区/ */void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);/* 验证芯片和写入缓冲区中的数据 */int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);/* 选中芯片 */void (*select_chip)(struct mtd_info *mtd, int chip);/* 检测是否有坏块 */int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);/* 标记坏块 */int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);/* 命令、地址、数据控制函数 */void (*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);/* 设备是否就绪 */int (*dev_ready)(struct mtd_info *mtd);/* 实现命令发送 */void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);/* 擦除命令的处理 */void (*erase_cmd)(struct mtd_info *mtd, int page);/* 扫描坏块 */int (*scan_bbt)(struct mtd_info *mtd);int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);/* 写一页 */int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf, int page, int cached, int raw);int chip_delay; /* 由板决定的延迟时间 *//* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */unsigned int options; /* 用位表示的NAND芯片的page大小,如某片NAND芯片* 的一个page有512个字节,那么page_shift就是9 */int page_shift;/* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可* 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14*/int phys_erase_shift;/* 用位表示的bad block table的大小,通常一个bbt占用一个block,* 所以bbt_erase_shift通常与phys_erase_shift相等*/int bbt_erase_shift;/* 用位表示的NAND芯片的容量 */int chip_shift;/* NADN FLASH芯片的数量 */int numchips;/* NAND芯片的大小 */uint64_t chipsize;int pagemask;int pagebuf;int subpagesize;uint8_t cellinfo;int badblockpos;nand_state_t state;uint8_t *oob_poi;struct nand_hw_control *controller;struct nand_ecclayout *ecclayout; /* ECC布局 */struct nand_ecc_ctrl ecc; /* ECC校验结构体,里面有大量的函数进行ECC校验 */struct nand_buffers *buffers;struct nand_hw_control hwcontrol;struct mtd_oob_ops ops;uint8_t *bbt;struct nand_bbt_descr *bbt_td;struct nand_bbt_descr *bbt_md;struct nand_bbt_descr *badblock_pattern;void *priv; };
最后,我们来用图表的形式来总结一下,MTD设备层、MTD原始设备层、FLASH硬件驱动层之间的联系。
转载于:https://www.cnblogs.com/tkid/p/3909487.html
Linux MTD系统剖析相关推荐
- Linux MTD系统剖析【转】
转自:http://blog.csdn.net/lwj103862095/article/details/21545791 版权声明:本文为博主原创文章,未经博主允许不得转载. MTD,Memory ...
- Linux MTD子系统(1):系统层次分析
目录 1. MTD子系统简介 2. MTD子系统的框架分层 3. MTD子系统重要的数据结构 3.1 struct mtd_info 3.2 struct mtd_part 3.3 struct mt ...
- Linux MTD架构下的nand flash驱动详解
转载自:http://blog.csdn.net/wang_zheng_kai/article/details/18988521 有了前面的基础(Nandflash详解:https://blog.cs ...
- linux mtd 块设备,Linux系统中/dev/mtd与/dev/mtdblock的区别,即MTD字符设备和块设备的区别...
转:http://www.crifan.com/linux_system_in__dev__mtd_and__dev__mtdblock_distinction_character_devices_a ...
- linux启动过程剖析,分析Linux系统的启动过程
导读 一直使用linux系统,却对系统启动过程及系统初始化和各种服务的启动不太清楚.今天终于搞明白整个是怎么一回事了.本来想自己写篇文章,刚好在网上看到一篇不错的介绍,很详细,就直接拿来了. Linu ...
- linux 解析pdf下载工具,Linux高级系统级性能分析工具-perf.pdf
Linux高级系统级性能分析工具-perf Linux 的系统级性能剖析工具‐perf (二) 承刚 TAOBAO Kernel Team chenggang.qin@ 第三章 Perf top ...
- linux显示mem进行排序,Linux查看系统负载(CPU和MEM考虑)
查看占用CPU最高的10个进程 [tidb@:vg_adn_tidbCkhsTest:172.31.30.62 ~/tidb-ansible]$ps aux | grep -v PID | sort ...
- Linux MTD子系统 _从模型分析到Flash驱动模板
MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...
- Linux MTD子系统学习(二)
Linux MTD spi-nor驱动分析 3.1 spi-nor设备驱动框架 3.2 spi-nor设备注册 如果希望一个spi设备可以在linux系统下很好的工作,除了写驱动,还要向内核申明和注册 ...
最新文章
- 强强联合!智源x清华AIR,共启 AI 健康研究新篇章
- C# in depth 阅读笔记-- 委托
- AWS S3宕机的启发: 云必须分散化
- access 提供程序无法确定object 值_Python | 加一行注释,让你的程序提速10+倍!numba库十分钟上手指南...
- 一文详解DeepMind最新模型SUNDAE,了解迭代去噪模型的前世今生
- boost::hana::members用法的测试程序
- 操作系统原理之进程调度与死锁(三)
- linux定时任务生产java服务无法执行问题群友案例
- 智慧楼宇管理运营端app、运维管理、工单管理、报修管理、维保管理、巡检查询、巡检管理、能源管理、维保查询、智慧社区、巡检统计、工单统计、能源管理、智能楼宇、设备监控、智能社区、系统运营、楼宇运维小程序
- linux命令we,Linux 命令执行过程
- php练手的项目,learnphp.beginmaker.com
- 仓库管理软件,仓库管理系统,希创条码,wms仓库管理软件
- java struts validate_重写ActionForm中的Validate()方法
- 游戏模型与动漫之间,有多大差距?
- android按钮被遮住,解决Android 虚拟按键遮住了页面内容的问题
- Java学习 --- 设计模式七大原则的依赖倒转原则
- 多个日期时间段进行合并计算时长,剔除重叠时间段
- Mac使用命令行工具解压和压缩rar文件
- 学校计算机用房地面用什么材料,学校食堂地面防滑该用什么材料?
- 买笔记本要注意什么呢?
热门文章
- 【Qt5.8】Qt5.8中QTableWidget 类介绍
- 类属性的特征java_java定义类、属性、方法
- 嵌入式烤箱能不能放台面上_2021年开放式厨房怎么设计?先来做做嵌入式家电的功课吧!...
- android 中的invalidate 和 postInvalidate
- pygame用精灵编组的问题的猜想和验证(未完待续)
- 关联容器的插入操作简单举例
- linux下source命令使用详解
- TCP 协议如何解决粘包、半包问题
- Leetcode题库263.丑数(c实现)
- EXECUTE IMMEDIATE用法小解