1. 介绍

MTD,即Memory Technology Device,值得是内存技术设备

字符设备和块设备的区别在于前者只能被顺序读写,后者可以随机访问;同时,两者读写数据的基本单元不同

字符设备: 以字节为基本单位,在Linux中,字符设备实现的比较简单,不需要缓冲区即可直接读写,内核例程和用户态API一一对应,用户层的Read函数直接对应了内核中的Read例程,这种映射关系由字符设备的file_operations维护

块设备: 以块为单位接受输入和返回输出,对这种设备的读写是按块进行的,其接口相对于字符设备复杂,没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求

由于块设备的I/O性能与CPU相比很差,因此,块设备的数据流往往会引入文件系统的cache机制

注意:MTD设备既非块设备也不是字符设备,但可以同时提供字符设备和块设备接口来操作

2. 概述

Linux中MTD的所有源码位于/drivers/mtd子目录下

MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层

硬件驱动层负责在init时驱动Flash硬件并建立从具体设备到MTD原始设备映射关系

TIP: 映射关系通常包括 分区信息、I/O映射及特定函数的映射

drivers/mtd/chips : CFI/JEDEC接口通用驱动

drivers/mtd/nand : NAND通用驱动和部分底层驱动程序

drivers/mtd/maps : NOR Flash映射关系相关函数

drivers/mtd/devices : NOR Flash底层驱动

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字符设备和块设备

3. 数据结构

MTD重要的数据结构包括mtd_info、mtd_part、mtd_partition、map_info、nand_chip、nand_ecclayout

mtd_info表示mtd原始设备, 所有mtd_info结构体被存放在mtd_info数组mtd_table中

成员

作用

type

mtd类型, 包括MTD_NORFLASH,MTD_NANDFLASH等(See mtd-abi.h)

flags

标志位, MTD_WRITEABLE,MTD_NO_ERASE等(See mtd-abi.h)

size

mtd设备的大小

erasesize

主要的擦除大小, 即Flash的块大小 (tip: mtd设备可能有多个erasesize)

writesize

写大小, 对于norFlash是字节,对nandFlash为一页

oobsize

每块oob数据量, eg 16

oobavail

name

命名

index

ecclayout

nand_ecclayout结构体指针, 表示的是ecc布局,可参考硬件手册的OOB中ecc布局

numeraseregions

可变擦除区域的数目, 通常为1

eraseregions

mtd_erase_region_info结构体指针, 可变擦除区域

erase

擦除Flash函数

read/write

读写Flash函数

read_oob/write_oob

带oob读写Flash函数

suspend/resume

Power Management functions

priv

私有数据, cfi接口flash指向map_info结构, 或指向自定义flash相关结构体

mtd_part表示MTD分区,其中包含了mtd_info,每一个分区都是被看成一个MTD原始设备

成员

作用

mtd

分区信息, 大部分由master决定

master

分区的主分区

offset

分区的偏移地址

index

分区号 (3.0后不存在该字段)

list

将mtd_part链成一个链表mtd_partitons

mtd_partition的主要数据结构

成员

作用

name

size

offset

mask_flags

ecclayout

mtdp

map_info的主要数据结构

成员

作用

name

名称

size

大小

phys

物理地址

bankwidth

总线宽度(in octets)

virt

虚拟地址,通常通过ioremap将物理地址进行映射得到

read/copy_from/write/copy_to

读写函数

map_priv_1/map_priv_2

驱动可用的私有数据

nand_chip的主要数据结构

成员

作用

IO_ADDR_R/IO_ADDR_W

读/写8根io线的地址

read_byte/read_word

从芯片读一个字节/字

read_buf/write_buf

读芯片读取内容至缓冲区/将缓冲区内容写入芯片

verify_buf

select_chip

block_bad

检查是否坏块

block_markbad

标识坏块

cmd_ctrl

硬件相关控制函数

init_size

dev_ready

cmdfunc

命令处理函数

waitfunc

erase_cmd

擦除命令

scan_bbt

扫描坏块

errstat

write_page

options

与具体的NAND 芯片相关的选项, 如NAND_USE_FLASH_BBT等(nand.h)

page_shift

ecclayout

nand_ecclayout类型结构体, ECC布局信息

ecc

nand_ecc_ctrl类型结构体, ECC控制结构

nand_ecclayout的主要数据结构

成员

作用

eccbytes

ecc的字节数(For 512B-per-page, eccbytes is 3)

eccpos

ecc数据在oob中的位置

oobavail

oob中可用的字节数, MTD 会根据其它三个变量自动计算得到

oobfree

nand_oobfree类型结构体, 显示定义空闲的oob 字节

4. MTD相关层实现

4.1 MTD设备层

mtd字符设备接口:

mtdchar.c 实现了字符设备接口,通过它,用户可以直接操作Flash 设备。

? 通过read()、write()系统调用可以读写Flash。

? 通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)

TIP: mtd_read和mtd_write直接直接调用mtd_info的read 函数,因此,字符设备接口跳过patition这一层

mtd块设备接口:

主要原理是将Flash的erase block中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。

但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。

块设备模拟驱动按照block 号和偏移量来定位文件,因此在Flash 上除了文件数据,基本没有额外的控制数据。

4.2 MTD原始设备层

MTD原始设备层

4.3 硬件驱动层

4.3.1 NOR Flash驱动结构

Linux系统实现了针对cfi,jedec等接口的通用NOR Flash驱动

在上述接口驱动基础上,芯片级驱动较简单

定义具体内存映射结构体map_info,然后通过接口类型后调用do_map_probe()

以h720x-flash.c为例(位于drivers/mtd/maps)

- 定义map_info结构体, 初始化成员name, size, phys, bankwidth

- 通过ioremap映射成员virt(虚拟内存地址)

- 通过函数simple_map_init初始化map_info成员函数read,write,copy_from,copy_to

- 调用do_map_probe进行cfi接口探测, 返回mtd_info结构体

- 通过parse_mtd_partitions, add_mtd_partitions注册mtd原始设备

4.3.2 NAND Flash驱动结构

Linux实现了通用NAND驱动(drivers/mtd/nand/nand_base.c)

tip: For more, check 内核中的NAND代码布局

芯片级驱动需要实现nand_chip结构体

MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。

? NAND芯片级初始化主要有以下几个步骤:

- 分配nand_chip内存,根据目标板及NAND控制器初始化nand_chip中成员函数(若未初始化则使用nand_base.c中的默认函数),将mtd_info中的priv指向nand_chip(或板相关私有结构),设置ecc模式及处理函数

- 以mtd_info为参数调用nand_scan()探测NAND FLash。

nand_scan()会读取nand芯片ID,并根据mtd->priv即nand_chip中成员初始化mtd_info

- 若有分区,则以mtd_info和mtd_partition为参数调用add_mtd_partitions()添加分区信息

-

? MTD对NAND芯片的读写主要分三部分:

A、struct mtd_info中的读写函数,如read,write_oob等,这是MTD原始设备层与FLASH硬件层之间的接口;

B、struct nand_ecc_ctrl中的读写函数,如read_page_raw,write_page等,主要用来做一些与ecc有关的操作;

C、struct nand_chip中的读写函数,如read_buf,cmdfunc等,与具体的NAND controller相关,就是这部分函数与硬件交互,通常需要我们自己来实现。

tip: nand_chip中的读写函数虽然与具体的NAND controller相关,但是MTD也为我们提供了默认的读写函数,如果NAND controller比较通用(使用PIO模式),那么对NAND芯片的读写与MTD提供的这些函数一致,就不必自己实现这些函数。

上面三部分读写函数相互配合完成对NAND芯片的读写

首先,MTD上层需要读写NAND芯片时,会调用struct mtd_info中的读写函数,接着struct mtd_info中的读写函数就会调用struct nand_chip或struct nand_ecc_ctrl中的读写函数,最后,若调用的是struct nand_ecc_ctrl中的读写函数,那么它又会接着调用struct nand_chip中的读写函数。

eg:  以读为例

MTD上层会调用struct mtd_info中的读page函数,即nand_read函数。

接着nand_read函数会调用struct nand_chip中cmdfunc函数,这个cmdfunc函数与具体的NAND controller相关,它的作用是使NAND controller向NAND 芯片发出读命令,NAND芯片收到命令后,就会做好准备等待NAND controller下一步的读取。

接着nand_read函数又会调用struct nand_ecc_ctrl中的read_page函数,而read_page函数又会调用struct nand_chip中read_buf函数,从而真正把NAND芯片中的数据读取到buffer中(所以这个read_buf的意思其实应该是read into buffer,另外,这个buffer是struct mtd_info中的nand_read函数传下来的)。

read_buf函数返回后,read_page函数就会对buffer中的数据做一些处理,比如校验ecc,以及若数据有错,就根据ecc对数据修正之类的,最后read_page函数返回到nand_read函数中。

对NAND芯片的其它操作,如写,擦除等,都与读操作类似

4.3.3 Flash转换层

Tranlation Layer

逻辑块地址(Logical Block Address)对应到Flash存储器的物理位置,使系统能把Flash当作普通的硬盘一样处理

FTL主要用于NOR Flash;NFTL用于NAND Flash

闪存转换层要做下面的操作来完成写请求:

- 将这个扇区所在擦除块的数据读到内存中,放在缓存中

- 将缓存中与这个扇区对应的内容用新的内容替换。

- 对该擦除块执行擦除操作。

- 将缓冲中的数据写回该擦除块。

参考:

<>

linux mtd 命令,Linux MTD介绍相关推荐

  1. linux objdump命令,Linux objdump命令

    一.简介 objdump命令是用查看目标文件或者可执行的目标文件的构成的gcc工具. 二.选项 三.实例 1)显示文件头信息 objdump -f test 2)显示Section Header信息 ...

  2. linux unset命令,Linux unset命令

    Linux unset命令 Linux unset命令用于删除变量或函数. unset为shell内建指令,可删除变量或函数. 语法unset [-fv][变量或函数名称] 参数:-f 仅删除函数. ...

  3. linux sfdisk命令,Linux sfdisk命令

    Linux sfdisk命令 Linux sfdisk命令是硬盘分区工具程序. sfdisk为硬盘分区工具程序,可显示分区的设置信息,并检查分区是否正常. 语法 sfdisk [-?Tvx][-d ] ...

  4. linux tf命令,Linux系统命令介绍之vmstat命令详解

    今天小编要跟大家介绍的vmstat命令详解.熟悉Linux系统和使用Linux系统工作的小伙伴都知道Linux的命令有很多,而真正在工作中用到的命令应该不超过几十个,为了让大家更好的掌握这些命令,小编 ...

  5. alias linux 执行命令,Linux系统alias命令编写实现命令别名方法介绍

    编写alias命令 Linux操作系统中打开一些应用,有时需要进入对应的文件夹,打开对应的程序,不是很方便.alias命令是一种命令别名命名法,可以将一些复杂的命令简化成一个我们自己命名的相对简单好记 ...

  6. linux cut 命令,Linux cut命令的用法介绍

    Linux cut命令用于根据字段提取文件内容.文本文件没有像数据库那样的行/列,有时我们只需要单列数据.根据分隔符剪切已识别的列(例如:冒号':',分号';',逗号','等). 对于下面示例,我们采 ...

  7. linux bsd命令,linux ps命令详解(BSD风格)

    linux ps命令详解(BSD风格) linux中ps只显示进程的静态快照,及瞬间的进程状态,它拥有众多的风格,可分为3组:UNIX风格,BSD风格,GNU风格,本文介绍BSD风格的ps指令. 参数 ...

  8. type在linux什么命令,Linux type命令

    用途说明 type命令用来显示指定命令的类型.一个命令的类型可以是如下几种: alias 别名 keyword 关键字,Shell保留字 function 函数,Shell函数 builtin 内建命 ...

  9. linux tf命令,Linux 基础命令

    目录操作 ls 查看文件夹 -l:表示以列表的形式进行显示 -h: 表示以较高可读性的形式进行展示 -a:表示显示所有文件和文件夹包含隐藏文件/文件夹 示例: ls -lha /root  //显示r ...

最新文章

  1. 50个Android开发人员必备UI效果源码[转载]
  2. 糖尿病(消渴)的中药简见简方(转载)
  3. 人工智能云计算大数据物联网
  4. 微信公众平台开发——问题篇
  5. 择天记手游的服务器维护世界,3月8日停服更新公告
  6. JavaScript使用正则表达
  7. Oracle存储过程基本语法
  8. linux通过操作界面和命令行的方式查看ip地址、mac地址
  9. repo init 是啥意思
  10. [Verilog] 薄膜建盤4X4 電路程式設計
  11. 五种MATLAB画圆方式程序
  12. 杭电1003 java_杭电ACM 1003题
  13. SMILES的基本规则
  14. 孙宇晨大举进驻NFT艺术的背后:区块链+艺术还能有怎样的玩法?
  15. MinIO异常the region is wrong; expecting ‘us-east-1‘
  16. 6.16 实现音乐的背景播放功能 [原创iOS开发-Xcode教程]
  17. 数据分析的数据来源都有哪些?
  18. 全球半导体今年出货有望创新高,蓝牙芯片需求强劲
  19. LaTeX无图片编号
  20. 32位和64位系统支持的最大内存

热门文章

  1. 重新装mysql出现乱码,数据库出现乱码的原因和解决办法
  2. 美国大学倒闭危机!1/4高校或将破产,清华本科留学率下降
  3. 计算机考证一级一般多少钱
  4. 性别分为男子组和女子组
  5. 现身说法,如何给上司送礼物
  6. 模拟前端ADC芯片LH001-91,用于开发心电、脑电医疗设备
  7. 个人所得税年度应纳税额抵扣-云服务器ECS入门-考试题及答案-申报更正流程
  8. 女神节送什么比较好?适合女生用的蓝牙耳机推荐
  9. LTE上行物理层传输机制(1)-PUSCH上行跳频之Type1频率跳频
  10. 影响我此生的几首歌(转载)