*******************************LoongEmbedded********************************

作者:LoongEmbedded

时间:2010.12.03

类别:WINCE嵌入式系统

********************************LoongEmbedded********************************

 

 

Filesys.dll由对象存储,ROM文件系统和存储管理器组成,其中:

对象存储:包含RAM注册表,数据库和RAM文件系统。

存储管理器:其功能由系统中的fsdmgr.dll模块来实现,它由块设备驱动程序管理器(block driver manager)、分区管理器(partition managerr)和文件系统驱动程序管理器(file system driver manager,也叫FSD manager),见下图

图1

 

1.对象存储

对象存储实质是一个内存堆,由filesys.dll控制,只要后备电源有电,则对象存储中的信息就能够得到保持,RAM存储芯片构成了对象存储的物理基础,这里的RAM芯片是指SDRAM。对象存储最多可达256MB的RAM,WINCE6.0为对象存储中的每一个对象都分配了一个唯一的对象标识符(windows CE object identifier,CEOID)该标识符的作用就是用于访问对象存储中的对象,那么什么是对象呢?


下面这些都是对象:

*** 注册表中的一个键

*** 注册表中的一个值

*** 一个文件

*** 文件数据中大小为4-KB的一部分

*** 数据库中的一条记录,做多可保存4KB数据

*** 数据库中的一条记录的扩展信息,也可保存4KB数据

*** 一个数据库

 

1.1   RAM注册表

WINCE6.0的注册表是用来保存应用程序,驱动程序和用户的设定以及其他一些配置信息的,WINCE6.0支持基于RAM的注册表(RAM-Based Registry )和基于Hive的注册表(Hive-Based Registry),其中基于RAM的注册表把整个注册表作为一个对象存储堆存放在系统的内存中。

 

基于RAM的注册表,其所有的数据保存在对象存储中(也即保存在内存堆中,更直观来说是保存在SDRAM中),这样,只要SDRAM保存不停地刷新,那么RAM注册表中的数据就会一直保持。但如果SDRAM断电,数据就会丢失。所以基于RAM的注册表用在经常热启动(warm boot)的系统中比较有效率,而如果用在经常冷启动(colde boot)的系统的效率就较低。其中有电池作为后备电源为SDRAM供电的单用户设备是最适合使用基于RAM的注册表的。

 

1.2   RAM文件系统

WINCE6.0提供3中文件系统,分别是RAM文件系统、ROM文件系统和可安装文件系统。WINCE6.0中使用的文件系统,其根目录为“/”,所有的文件系统都被mount到根目录“/”下面,ROM文件系统通常直接挂载到/Windows目录,RAM文件系统通常直接挂载到根目录下,也就是说,根目录下除了挂载的外存目录和/Windows目录之外的所有文件都位于RAM文件系统中,见下图

图2

RAM文件系统由FSD(file system driver) Manager管理,WINCE6.0文件系统的配置,由注册表实现,一般在[HKLM/System/StorageManager]中,比如:

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH/FATFS]

    "Flags"=dword:14

         "Folder"="ResidentFlash"

    "FormatExfat"=dword:1

    "CheckForFormat"=dword:1

    "EnableWriteBack"=dword:1

IF IMGHIVEREG   

    "MountAsBootable"=dword:1

ENDIF ;IMGHIVEREG

 

在定制WinCE操作系统时,我们可以选择ROM-only 的文件系统或RAM and ROM的文件系统。当选择RAM and ROM的文件系统时,根目录文件系统在内存当中,掉电即丢失。为了实现根文件系统和注册表的保存,即在冷启动时不丢失,我们需要选择ROM and RAM file system的文件系统和HIVE-Based注册表,以将存储空间Mount成根目录,并配置注册表使其支持HIVE-Based注册表。

 

1.3   属性数据库

WINCE6.0提供CEDB(WINCE Database)和EDB(Embedded Database)这两种数据库,其中CEDB在字节流的基础上,对文件进行进一步的抽象,提供了与关系型数据库类似的数据结构化存储和访问。

 

2. ROM文件系统

WINCE6.0的内部文件系统控制对ROM的访问,也提供了对位于RAM的对象存储的文件存储,WINCE6.0支持两种可用的文件系统:RAM and ROM文件系统和ROM文件系统。RAM and ROM文件系统提供了对象存储里的文件存储以及对ROM的访问,而ROM文件系统不允许应用程序将文件存储在对象存储里,通过根目录下的windows目录可以访问ROM中的数据。ROM文件系统连接到统一文件系统中的“/Windows”文件夹,这意味着ROM中的所有文件均可作为“/Windows”文件夹中的只读文件来访问。

 

3.存储管理器(storage manager)

 

存储管理器负责管理系统中所有的外围存储设备,包括管理它们所有的文件系统和块驱动。所有的文件、数据和容量都是通过存储管理器来操作的,存储管理器的功能由系统中的fsdmgr.dll模块实现,由下面三部分组成:

⑴文件系统驱动程序管理器(File System Driver Manager,FSD Manager)。

⑵分区管理器(Partition Manager)。

⑶块设备驱动程序管理器(Block Driver Manager)

存储管理器的体系结构如下图所示:

图3

从上图可以知道存储管理器是一个分层结构,由文件系统过滤器(File system filters)、文件系统驱动程序(File system dirver)、分区驱动程序(Partition driver)和存储驱动程序(Block driver)组成。下面是common.reg总关于存储管理器的注册表信息

; This tells Filesys to load FSDMGR

[HKEY_LOCAL_MACHINE/System/StorageManager]

    "Dll"="fsdmgr.dll"

    "PNPUnloadDelay"=dword:1000

fsdmgr.dll是存储管理器的表现形式,"PNPUnloadDelay"是指存储管理器在接收到即插即用设备的卸载通知后的延时时间,具体存储管理器需要管理的存储设备的注册表信息在HKEY_LOCAL_MACHINE/System/StorageManager/Profiles下。

 

 

3.1 文件系统过滤器

 

文件系统过滤器是一个导出文件系统入口的DLL,这些入口映射到标准的文件系统函数,比如CreateFile函数和CreateDriectory函数。文件系统过滤器用于处理对文件系统的调用,此后文件系统才能获得这些调用,也就是说存储管理器在调用文件系统API之前先调用文件系统过滤器的过滤函数,这样就允许对文件访问进行某些特殊的处理,因为文件系统过滤器拦截对文件系统的调用,所以可以对文件数据的加密、解密、压缩甚至扫描文件是否存在病毒等。

 

文件系统过滤器是轻量级(lightweight)的文件系统驱动(FSDs),它导出钩子函数(hook functions)是FSD_HookVolume()和FSD_UnhookVolume(),而不是磁盘挂载函数FSD_MountDisk()和FSD_UnmountDisk(),下面介绍介绍这个几个函数:

⑴FSD_HookVolume():在存储管理器加载文件系统过滤器的时候会调用这个入口函数,此函数是由文件系统的导出函数,并且被文件系统磁盘管理器(file system disk manager,FSDMGR)直接调用。

⑵ FSD_UnhookVolume():在存储管理器卸载文件系统过滤器的时候会调用这个入口函数,此函数是由文件系统的导出函数,并且被文件系统磁盘管理器(file system disk manager,FSDMGR)直接调用。

⑶ FSD_MountDisk():设备管理器调用这个函数来挂载包含具体文件类型的指定磁盘,比如可以在根目录下挂载ResidentFlash盘符,这个盘符是基于FATFS文件系统来操作nandflash。

 

⑷ FSD_UnmountDisk():设备管理器调用这个函数来卸载指定的盘符。

 

还有很重要的一点是文件系统驱动管理器(FSD Manager)加载文件系统驱动(FSDs,files system drivers)和文件系统过滤器。

 

3.1.1 文件系统过滤器的注册表路径

 

HKEY_LOCAL_MACHINE/System/StorageManager/Filters

表示文件系统过滤器对所有的文件类型都有效,也就是说没有筛选。

 

HKEY_LOCAL_MACHINE/System/StorageManager/ MyFileSystem /Filters

MyFileSystem是指具体的文件系统,如FATFS、EXFAT、CD/UDFS等文件系统,这个路径指文件系统过滤器对指定的文件系统有效。

 

HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/ MyFileSystem /Filters

表示文件系统过滤器对自动加载的指定的文件系统有效,这里的自动加载是指由存储管理器来直接加载存储设备的驱动(block driver)。

 

HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/ MyProfileName / MyFileSystem /Filters

MyProfileName是指Profile的名字,这个路径指文件系统过滤器对指定存储硬件的文件系统有效,比如我们项目的Platform.reg下相关内容如下:

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFLASH]

    "Prefix"="DSK"

    "Dll"="smflash.dll"

    "Index"=dword:1

    "Order"=dword:0

    "Profile"="NANDFLASH"

    "IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"

IF IMGHIVEREG

    "Flags"=dword:00001000

ENDIF ;IMGHIVEREG

…………………….

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH/FATFS/Filters/CacheFilt]

    "Dll"="cachefilt.dll"

"LockIOBuffers"=dword:1

这里的MyProfileName是NANDFLASH,MyFileSystem是FATFS,表示文件过滤器(在此为cache的过滤器cachefilt.dll,不知是否该这样理解?)对加载在NANDFLASH上的文件系统有效,也就是如果要读写NANDFLASH上的数据,只有以FATFS文件系统格式才能访问,否则被文件过滤器过滤掉,这样就无法读写NANDFLASH上的数据。

 

3.1.2 文件系统过滤器注册表值

用任何有效的注册表键值来,比如添加过滤器的名字,过滤DLL的值和过滤器的order的值,通过这些操作可以建立文件系统过滤器,比如

 

[HKEY_LOCAL_MACHINE/System/StorageManager/.../Filters/FilterName]

"dll"="filter.dll"

"Order"=dword:x

堆栈上过滤器的order是由高到低,最高order(0)的过滤器被首先加载,更低order的过滤器后面接着加载。如果order的值没有指定,那么order的值默认被设置为0xFFFFFFFF,但如果多于一个的过滤器没有指定order的值,那么这些没有指定order的值的过滤器的加载顺序是不明确的。

 

3.1.3 文件系统过滤器的sample

 

文件系统过滤器的例子在下面的目录下

%_WINCEROOT%/Public/Common/Oak/Drivers/FSD/EncFilt

%_WINCEROOT%/Public/Common/Oak/Drivers/FSD/FSDSpy

其相关的注册表信息如下:

[HKEY_LOCAL_MACHINE/System/StorageManager/FATFS/filters/FSDSPY]

   "Dll"="fsdspy.dll"

   "Order"=dword:0

[HKEY_LOCAL_MACHINE/System/StorageManager/FATFS/filters/ENCRYPT]

   "Dll"="fsdenc.dll"

   "Order"=dword:1

 

3.2 文件系统驱动

 

文件系统驱动是实现对应的文件系统的DLL,文件驱动将存储设备上的数据组织为文件和文件夹来对设备进行操作。应用程序操作文件是通过wince 文件系统提供的接口进行操作,如:可以通过CreateFile函数,打开或创建一个文件。接下来,系统是如何去完成这个任务的呢?比如我们要操作SD卡上的文件,SD卡上也有自己的文件系统,用于组织和管理文件,wince文件系统是如果操作这些文件的呢?这时候,FSD(文件系统驱动)就发挥它的作用了。文件的操作共涉及到六个层次:

⑴应用程序:用户通过应用程序操作文件。

⑵wince文件系统:操作系统的一部分,根据用户的请求,判断操作的是那个设备上的文件,以便调用相应的驱动。

⑶文件系统驱动:操作系统没办法直接和设备驱动进行交互,需要通过文件系统驱动,实现与设备驱动的操作,以实现文件操作。

⑷分区驱动:主要实现对存储设备的逻辑划分。

⑸设备驱动:实现了设备上的操作,包括文件操作等。

⑹设备上的文件系统:组织和管理设备上的文件存储。

从以上的分析可以知道,文件系统在操作系统和设备驱动之间起到了一个连接作用。在实现的时候,文件系统驱动基于设备驱动,实现了wince文件系统中的文件操作函数,如CreateFile等。

 

3.3 分区驱动

分区是对存储设备的逻辑划分,WINCE6.0允许物理磁盘(我们常用的是nandflash)包含多个分区,并且每个分区可以格式化为不同的文件系统,但是每个设备只能由一个分区驱动程序来管理。下面是src/bootloader/eboot/nand.cpp文件的WriteOSImageToBootMedia函数中关于建立分区的代码

 

图4

图4的代码主要是通过分区驱动在nandflash建立一个使用BINFS文件系统的分区,这个分区用于保存NK映像。

图5

图5的代码主要是通过分区驱动在nandflash建立一个使用FAT32文件系统的分区,这个分区建立在除去NK映像占用的其余nandflash空间。

 

分区驱动程序实际上是存储驱动程序的转换器。它公开与存储驱动程序相同的接口,并将分区的块地址(逻辑地址)转换为存储设备块的真实地址(物理地址)。然后,它将调用传递给存储驱动程序。分区驱动程序是一个DLL(mspart.dll),在common.reg的相关注册表信息如下:

; HIVE BOOT SECTION

; Partition driver key.

[HKEY_LOCAL_MACHINE/System/StorageManager/MSPART]

    "Dll"="mspart.dll"

; END HIVE BOOT SECTION

 

3.4 存储驱动程序

存储驱动程序是用于和存储设备直接打交道,可以读写存储设备,存储驱动程序也称为“块驱动程序”,因为它们提供对数据存储的随即寻址块的访问。对于存储设备为nand flash的系统,其存储驱动就是nandflash驱动

​javascript:void(0)​

 

 

 

4.存储管理器加载设备

 

4.1存储管理器加载设备的两种方式

WINCE里面对于块设备的加载可以有两种方式,一种就是通过device manager来加

载然后通知存储管理器做后续的加载工作,而另一种则是直接由存储管理器来加载,这种方式可以通过注册表:Autoload键值来实现。一般是采用第一种加载方式,对于设备管理器加载的驱动的话只能靠Flags = 0x1000 来决定, 这需要通过platform.reg中下面的注册表信息的Flags的值来决定。

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFLASH]

    "Prefix"="DSK"

    "Dll"="smflash.dll"

    "Index"=dword:1

    "Order"=dword:0

    "Profile"="NANDFLASH"

    "IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"

IF IMGHIVEREG

    "Flags"=dword:00001000                 //就是这个flags

ENDIF ;IMGHIVEREG

关于Flags在VS2005中help的描述如下

图6

"Flags"=dword:00001000告诉设备管理器在hive-base注册表初始化的第一个阶段来加载驱动。

 

那既然是选择第一种方式来加载设备,那么就需要在hive-base注册表初始化的第一个阶段来启动存储管理器和设备管理器,这是由platform.reg下面的注册表信息的Flags来决定的

[HKEY_LOCAL_MACHINE/Init/BootVars]

    "Flags"=dword:3

    "RegistryFlags"=dword:1

Flags的值有哪些呢?又表示什么意义呢?见下面VS2005中help文档的相关部分:

图7

"Flags"=dword:3就是告诉系统在hive-base注册表初始化的第一个阶段来启动存储管理器和设备管理器的。

 

4.2 设备管理器结合存储管理器来加载设备

 

Oal.exe加载kernel.dll,kernel.dll加载filesys.dll,filesys.dll加载device.dll,到此设备管理器就加载起来了,common.reg中设备管理器的注册表信息如下

[HKEY_LOCAL_MACHINE/init]

        "Launch20"="device.dll"

因为存储管理(fsdmgr.dll模块来实现)是filesys.dll的一部分,所以存储管理器也在运行中,已准备好。

 

下面就来看看存储管理器是如何加载设备的,见下图

图8

⑴设备管理器从 HKEY_LOCAL_MACHINE/Driver/BuiltIn 项加载驱动程序。正常情况下,任何内置的磁盘设备(例如,硬盘,)列在该项下面,所以将加载块驱动程序。块驱动程序通告一个特定的设备类标识符 BLOCK_DRIVER_GUID {A4E7EDDA-E575-4252-9D6B-4195D48BB865},比如下面是我的WINCE6.0+2443系统中platform.reg里关于块驱动注册表信息:

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFLASH]

    "Prefix"="DSK"

    "Dll"="smflash.dll"

    "Index"=dword:1

    "Order"=dword:0

    "Profile"="NANDFLASH"

    "IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"

IF IMGHIVEREG

    "Flags"=dword:00001000

ENDIF ;IMGHIVEREG

 

⑵ (The Storage Manager consists of the Block Driver Manager, the Partition Manager, and the File System Driver (FSD) Manager.)存储管理器中的块驱动管理器收到并且识别出这是一个块设备后,块驱动管理器向存储管理器索要这个块驱动相应的profile注册表键值的信息,

 

⑶ Storage Manager looks up the profile information for the device and loads the appropriate partition driver

存储管理器查询块设备的profile信息并且根据这个信息来加载相称的分区驱动,比如下面是我的项目的相关注册表信息

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH]

    "DefaultFileSystem"="BINFS"

    "PartitionDriver"="mspart.dll"

    "Name"="Microsoft Flash Disk"

通过上面的HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH注册表信息就找到分区驱动mspart.dll,这样存储管理器就加载分区驱动了。这里[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH]的NANDFLASH要和⑴中的"Profile"="NANDFLASH"保持一致。

 

⑷存储管理器加载分区驱动程序后,存储管理器的分区管理器(Partition Manager)将请求分区驱动程序枚举磁盘上的分区,并标识每个分区上的文件系统。分区驱动程序将从主启动记录 (MBR) 中读取有关分区和文件系统的信息,并向存储管理器中的文件系统管理器(File System Driver (FSD) Manager)提供文件系统信息。图4和图5就是分别在nandflash建立BINFS分区和FATFS分区,其中BINFS分区用于保存系统映像,而FATFS分区是基于除去系统映像占用的nandflash空间之外的剩余nandflash空间,见WINCE6.0中storage manager下面显示的分区及其文件系统的属性

图9

图10

图11

 

⑸分区驱动被加载后就会通过块设备驱动提供的接口来读取块设备上的分区信息,这个信

息一般就是同过读取MBR的分区表得到的,如果分区类型在注册表里分区表中有相应的值,分区驱动就会根据这个来加载相应的文件系统驱动。在这里,注册表里分区表PartitionTable在Common.reg中,如下:

; The partition table contain entries where the volume name is the partition type (in %02X format)

; The value is the name of the filesystem.  This is used to look up the module to load etc.

; Explicitly call out 07 partition type as MSIFS, which means an Microsoft Installable File SYstem,

; such as NTFS or EXFAT.  The actual filesystem name is determined by running the detectors.

 

[HKEY_LOCAL_MACHINE/System/StorageManager/PartitionTable]

    "01"="FATFS"

    "04"="FATFS"

    "06"="FATFS"

    "07"="MSIFS"

    "0B"="FATFS"

    "0C"="FATFS"

    "0E"="FATFS"

    "0F"="FATFS"

    "20"="BOOT"

    "21"="BINFS"

    "22"="RAWFS"

    "23"="RAWFS"

    "25"="IMGFS"

    "26"="BINARY"

假如新增加一种文件系统,就必须添加到这个表中,如果我们要加载的文件系统类似不在这个表中,系统将不能正常启动,停在下面的串口

-OEMInit

#### FMD_DRIVER:::FMD_OEMIoControl

FMD_OEMIoControl: unrecognized IOCTL (0x71f8c).

#### FMD_DRIVER:::FMD_INIT

 (NAND ID:0xecf1) --> OK.

 NUM_OF_BLOCKS    = 1024

 PAGES_PER_BLOCK  = 64

 SECTORS_PER_PAGE = 4

NUMBLOCKS : 1024(0x400), SECTORSPERBLOCK = 64(0x40), BYTESPERSECTOR = 2048(0x800)

#### FMD_DRIVER:::FMD_OEMIoControl

FMD_OEMIoControl: unrecognized IOCTL (0x71c24).

 

⑹文件系统起来后,就会分析这个分区的数据是不是有效的,如果是有效的的分区的,那么文件系统驱动就成功的mount在了这个块设备上了,也就是和块设备关联在了一起,而要是数据不是有效的话,那么,它会试着格式化这个分区,如果能格式化成功,那么mount也就成功了,如果不能格式化的话,那么就mount失败,这个分区就是无效的了。

 

⑺分区驱动接着会去枚举下一个分区,直到所有分区都枚举完为止,这样文件系统的加载过程就算完成了。

 

5.实现基于hive的注册表

5.1 需要选择的组件

图12

5.2 platform.reg中相关的注册表内容

; HIVE BOOT SECTION

[HKEY_LOCAL_MACHINE/Drivers/Resources/IRQ]

   "Identifier"=dword:1

   "Minimum"=dword:1

   "Space"=dword:20

   "Ranges"="1-0x20"

;  "Shared"=""

 

[HKEY_LOCAL_MACHINE/Drivers/Resources/IO]

   "Identifier"=dword:2

   "Minimum"=dword:0

   "Space"=dword:10000

   "Ranges"="0-0xFFFF"

; END HIVE BOOT SECTION

 

…………………………

;;for hive based registry

; HIVE BOOT SECTION

IF IMGHIVEREG

[HKEY_LOCAL_MACHINE/Init/BootVars]

    "Flags"=dword:3

    "RegistryFlags"=dword:1

ENDIF ;IMGHIVEREG

; END HIVE BOOT SECTION

 

; HIVE BOOT SECTION

IF BSP_NONANDFS !

 

   

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFLASH]

    "Prefix"="DSK"

    "Dll"="smflash.dll"

    "Index"=dword:1

    "Order"=dword:0

    "Profile"="NANDFLASH"

    "IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"

IF IMGHIVEREG

    "Flags"=dword:00001000

ENDIF ;IMGHIVEREG

   

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH]

    "DefaultFileSystem"="BINFS"

    "PartitionDriver"="mspart.dll"

    "Name"="Microsoft Flash Disk"

 

   

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH/BINFS]

    "MountHidden"=dword:1

    "MountAsROM"=dword:1

 

    

[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/NANDFLASH]

    "DriverPath"="Drivers//BuiltIn//NANDFLASH"

    ; LoadFlags 0x01 == load synchronously

    "LoadFlags"=dword:1

    "BootPhase"=dword:0

IF IMGHIVEREG

    "MountAsBootable"=dword:1

ENDIF ;IMGHIVEREG

   

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH/FATFS]

    "Flags"=dword:14

         "Folder"="ResidentFlash"

    "FormatExfat"=dword:1

    "CheckForFormat"=dword:1

    "EnableWriteBack"=dword:1

IF IMGHIVEREG   

    "MountAsBootable"=dword:1

ENDIF ;IMGHIVEREG

 

[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/NANDFLASH/Filters/CacheFilt]

    "Dll"="cachefilt.dll"

    "LockIOBuffers"=dword:1

 

[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NANDFLASH/FATFS/Filters/CacheFilt]

    "Dll"="cachefilt.dll"

    "LockIOBuffers"=dword:1

 

ENDIF ; BSP_NONANDFS

; END HIVE BOOT SECTION

 

上面注册表项的值后面再继续详细学习和实践了。

 

5.3 mount在根目录的盘符

图13