網上不少介紹三星24x0系列的BINFS啓動方式實現,有些內容上描述的不是非常全面
下面就WinCE6上的BINFS實現,從基本原理到修改BSP,再到如何燒錄啓動做一個較全面的講解
一 BINFS到底是什麼?
其實BINFS就是MS給CE做的一種存放系統鏡像的一個文件系統。
一說文件系統,大家可能比較頭大。那麼這麼說,其實就是一個結構體(說是文件系統確實比較勉強,結構體可能更合
適),裏面有記錄各模塊的起始地址,大小等的信息,你要找模塊可以根據這個信息到後面找。
二 爲什麼要用BINFS?有什麼好處?
其實我覺得最大的好處是“按需加載系統模塊到內存”,這裏衍生出兩個優點:
1 開機需要加載的核心部分很少,大大減少開機讀取系統的時間
2 不需要爲操作系統預留全尺寸的內存大小,只需預留最小開機核心的大小,剩下的作爲通用內存空間,所以使系統
內存使用有了很大靈活性,可用系統內存大大增加
三 BINFS的實現基礎
這裏不得不說WinCE的燒寫和引導方式
在默認情況下,大家都知道WinCE會生成nk.bin和nk.nb0
bin其實就是nb0的壓縮形式
nb0怎麼可以壓縮?
因爲nb0中有很多空白區域
bin是如何壓縮的?
很簡單的描述下,就是用一個結構體記錄一下,起始地址,大小,校驗和,然後後面就是實際的內容
這樣的一個一個結構體順序排在一起就組成了bin這個簡單的壓縮格式,實際上只是壓縮了nb0裏面不必要的0,而不是
對數據做了算法壓縮,所以很好理解,所以你用winrar等去壓縮bin,發現可以更小,呵呵
最簡單最簡單的燒寫和啓動WinCE的方法是:
直接把nk.bin燒到存儲設備上,比如NAND上
假設nk.bin是30MB,那麼就在NAND上順序留下30MB給NK.bin
啓動的時候把nk.bin按照那個結構體,解壓到內存中,跳轉到起始地址,就可以運行了
但是我發現有趣的是,很多開發板廠家並不是這麼做的
他們實際上是用了BINFS來存放解壓出來的系統鏡像
這裏大家可能比較疑惑一個問題,明明很多開發板都沒有用“BINFS”,你怎麼說他們用了BINFS?
實際上這裏有一個重要的誤會
BINFS是一個文件系統,但是大家關注BINFS是因爲想實現上面說的加快開機和節省內存的好處,實際上需要完成這種
好處,BINFS是一個文件系統基礎,真正做到將系統鏡像分爲兩個部分還需要用到multi-bin技術
所以這個就是誤會所在,很多開發板確實用了BINFS文件系統,但是他們只是把系統鏡像全部寫入到BINFS分區,啓動
時再全部讀出來,這樣就沒有達到前面說的“好處”
怎麼確定我的系統現在有沒有用BINFS?
看看自己的燒寫代碼,如果用了bootpart的庫進行分區,寫入,比如
- BP_OpenPartition(NEXT_FREE_LOC, dwNumSectors, PART_BINFS, TRUE, PART_OPEN_ALWAYS);
複製代碼
這裏就是典型的建立了一個BINFS分區
然後使用BP_WriteData將鏡像內容寫入到這個分區
如果你的程序沒有使用這麼一套機制,那麼說明你的系統沒有使用BINFS
前面說到除了BINFS作爲文件系統的支持,還需要multi-bin技術,那麼這個multi-bin技術是做什麼的呢
實際上,我們想到,系統可以分爲多塊,我們只需要把核心啓動的內容放到內存中,然後其它用到的從固態存儲器中(
使用了BINFS文件系統)讀出來就可以了,這個就是我們前面說到的“好處”的實現原理
那麼如何將系統鏡像分開來,這個就是需要一些BSP裏面的修改了,後面在實現方法中介紹
那麼最簡單的分配就是將系統鏡像分爲兩塊
一塊用來存放系統啓動時候需要在內存中運行的“最小內核”
一塊用來存放系統後續需要“按需加載”的模塊文件
我們一般也都是這麼做的
編譯的時候我們會通過配置文件告訴系統什麼地址範圍是在內存中運行的內核,什麼地址範圍是在存儲器(使用BINFS
存放鏡像)上的系統其它模塊,然後啓動時候只需要加載最小內核,然後由最小內核使用BINFS文件系統驅動來讀取存
儲器BINFS分區上的其它所需模塊
系統怎麼知道那些文件在什麼地址?怎麼知道哪些文件是在最小內核裏還是存儲器BINFS分區上的?
系統有記錄各文件地址的結構體,有了文件地址就自然知道是放在什麼地方的了,別忘了前面說的配置文件,裏面已
經告訴了各塊的起止地址,很容易就可以判斷到。關於結構體是如何記錄模塊地址等內容,不是本文討論範圍,這裏
就先放下,大家知道系統有方法知道文件的地址和大小就可以了。
所以爲什麼一些開發板系統用了BINFS,卻沒有那些“好處”,就是因爲雖然用了BINFS文件系統,但是把全部內容都
放進了最小內核,所以沒有達到任何的優勢效果。
就是說我們在實現了BINFS文件系統之後需要做的就是將“最小內核”和“系統其它文件”分離開來
四 BINFS的實現
前面已經較詳細的說明了原理,其實說到這裏文章題目已經需要有些改變了,我們實際上討論的是“使用BINFS實現
multi-bin來節省系統內存”,而不只是實現BINFS文件系統。因爲我怕標題太長,大家有些費解,而且很多人把這個
就稱爲BINFS,所以才取了這個題目。實際上將這種技術單單叫做BINFS是不準確的。
1 首先說說如何實現BINFS文件系統
前面說了,BINFS文件系統是基礎,爲什麼?因爲分離系統鏡像之後,系統“最小內核”會使用BINFS去讀系統其它模
塊,所以我們必須將系統鏡像使用BINFS文件系統寫入固態存取器(後面無特別說明,所有"存儲器"均指“固態存儲器
”,內存指"SDRAM"或"DDR"等程序運行介質)
那麼我們可不可以不用BINFS,用FAT?理論上應該是可以的,不過需要修改MS的系統加載模塊的程序,我不知道是不
是所有涉及到的模塊都有開源,所以這個我們不討論
其實MS對WinCE設備的存儲器分區啓動管理有點像PC的
在WinCE中首先在存儲器一開始,存放的是MBR(master boot record,我沒記錯的話...),熟悉文件系統的朋友一看就
明白了MBR是幹什麼的。MBR在CE中主要是記錄後面的存儲器空間是如何分區的,這個記錄應該和PC上是一樣的,起始
sector號碼,總共有幾個Sectors,分區使用什麼文件系統。但是不同的是,MBR不需要承擔引導代碼的功能
在MBR之後,按照分區記錄中的起始地址,就是各個分區,大家不妨想象爲PC上的分區,只不過我們現在C盤不用FAT或
者NTFS,而是使用一種叫做BINFS的文件系統。
我們需要創建,修改MBR,增加刪除,查詢,讀取分區信息和內容。這些功能都是bootpart庫裏面的,大家可以查詢相
關內容,這裏不詳細說明bootpart庫是如何使用的。
只要瞭解過磁盤分區概念的朋友,應該很快就可以操作bootpart函數,而且一般的EBoot在燒寫這裏都是有例子的。大
家可以參考,這裏只是列出基本步驟
a) BP_LowLevelFormat 用來格式化所有存儲空間
b) BP_OpenPartition 打開某個分區,如果不存在可以創建該分區,比如BINFS
c) BP_WriteData 往分區裏寫數據
d) BP_ReadData 讀取分區裏的數據
這些是一些基本的操作函數,具體實現細節大家需要多參考EBoot裏面的代碼,實際需要考慮的問題還可能包括整個存
儲器的佈局
2 往BINFS分區中寫入鏡像
如果創建好了BINFS分區,那麼下面要做的就是把鏡像寫入BINFS分區
如果大家下載的是BIN文件,首先需要把BIN文件解壓縮出來,解壓縮代碼可以參考EBoot裏面的代碼
然後調用BP_WriteData可以寫入BINFS分區
詳細步驟大家還是多看示例代碼,過程並不複雜
3 如何將系統鏡像分成多個部分
這裏就是說的multi-bin的,把鏡像分爲“最小內核”與“系統其它文件”
MS幫助文件裏面有How to Implement BinFS ,這裏將大致流程介紹了一下
首先就是需要修改config.bib文件,對CE比較瞭解的朋友知道,CE的地址等配置都是在config.bib裏面修改的,所以
我們要去改config.bib文件
這裏可以看到現在系統對於鏡像的劃分,例如
- Name Address Size Type
- NK 88200000 03000000 RAMIMAGE
- RAM 8B200000 04E00000 RAM
複製代碼
這個很容易理解,NK是唯一的一個bin文件,存放RAMIMAGE
這裏面RAMIMAGE是關鍵字,告訴系統這個是需要啓動的“最小內核”,現在是48MB...
RAM是告訴系統可用的內存起始地址和大小
首先我們需要把NK給分開成爲兩部分,即“最小內核”與“系統其它文件”
修改如下
- Name Address Size Type
- XIPKERNEL 88200000 00400000 RAMIMAGE
- CHAIN 88600000 00001000 RESERVED
- NK 88601000 02BFF000 NANDIMAGE
- RAM 88601000 079FF000 RAM
複製代碼
我們好好看下這個配置,這裏完成的是將系統鏡像內容分爲兩部分
XIPKERNEL,就是我們的“最小內核”,就是RAMIMAGE
NK,就是“系統其它文件”,就是NANDIMAGE(關鍵字,不可改)
好了,這裏有些問題大家可能要問。CHAIN是什麼?CHAIN是實現multi-bin的必須部分,是告訴系統各bin文件位置的
信息。一定需要了解CHAIN的內容?
其實CHAIN也是結構體...,大家如果把chain.bin解壓出來,會發現是這個結構體
- {
- bin個數
- bin信息描述結構體[bin個數]
- }
複製代碼
這裏說的bin就是把系統鏡像拆分開的子區塊,我們這裏就是2個,分別是XIPKERNEL和NK
信息描述會記錄各個bin的起始位置,實際大小和最大大小,分區名稱等
實際大小就是編譯出來的實際大小,最大大小就是我們在config.bib裏面指定的大小
還有一些其它的配置也需要修改
- AUTOSIZE=ON
- COMPRESSION=ON
- DLLADDR_AUTOSIZE=ON
- KERNELFIXUPS=ON
- PROFILE=OFF
- RAM_AUTOSIZE=OFF
- ROMFLAGS=0
- ROM_AUTOSIZE=OFF
- ROMSIZE=03000000
- ROMSTART=88000000
- ROMWIDTH=32
- XIPSCHAIN=88600000
複製代碼
這裏你能訂製的就是後面4項,我這裏ROMSTART=88000000,因爲前面還有一些地址配置因爲與系統鏡像生成無關,所
以我就沒有貼上來,不過爲了防止大家搞不清這個88000000是怎麼來的,還是貼一下
- Name Address Size Type
- ARGS 88000000 00001000 RESERVED
- VPU 88001000 000FF000 RESERVED
- FRAMEBUFFER 88100000 00100000 RESERVED
複製代碼
88000000就是我內存映射到的起始地址
這裏需要注意XIPSCHAIN,這個一定要設置爲CHAIN的起始地址
帶了XIPSCHAIN,纔會生成後面需要的xip.bin
MS的幫助文件裏面的例子是用的NK作爲RAMIMAGE的名字,EXT作爲NANDIMAGE的名字
當然名字不是最重要的,但是實際使用中,大家會發現使用NK作爲RAMIMAGE的名字虧大了
爲什麼呢?
這就是我們下面需要做的
把各分區都配置好之後,下面需要決定把哪些內容放到什麼分區下了
如前面所述,我們需要把啓動需要的“最小內核”放到RAMIMAGE裏面
首先定義一下哪些是“最小內核”
其實說白了就是系統可以使用BINFS讀取在存儲器上文件所需要的最小系統文件
這裏其實需要了解WinCE的啓動過程,但是我們並不深入到函數,只是模塊級的
系統啓動後需要初始化,所以關於初始化的OAL層都需要放進來,然後我們需要使用device.exe來加載我們的存儲器驅
動,這樣才能訪問存儲器,所以關於設備驅動加載,總線枚舉的模塊都要加上,還有我們需要的BINFS驅動模塊,還有
mspart分區模塊,不然無法找到BINFS分區的位置。這些都是較通用的模塊,還有一些模塊你一定要注意,就是你的存
儲器驅動所依賴的驅動模塊,比如ceddk?你的bsp裏的gpio驅動?dma驅動?等等。如果沒有加入全的話就會出現加載
不了存儲器驅動,也就沒法找到分區,沒法訪問BINFS...
有人說如果需要用HIVE的話,還要加載FAT驅動,實際上並不需要,因爲我們的目的是要完成“可以訪問BINFS”,
boot.hv一定是要放到RAMIMAGE裏的,所以基礎註冊表都是有的,可以讓你完成對存儲器驅動的加載,而這之後都可以
用BINFS訪問“系統其它文件”了,所以FAT驅動是不需要放到RAMIMAGE裏面的,在用到FAT時,BINFS已經好用了
同時default.hv,user.hv也都是不需要放到RAMIMAGE裏面的
如果你使用非英文的系統,還有一個文件不要忘記
wince.nls,少了這個你也會啓動不了
下面給出例子,我相信可以涵蓋大部分平臺應用了
- MODULES
- nk.exe $(_FLATRELEASEDIR)/oal.exe XIPKERNEL SHZ
- kernel.dll $(_FLATRELEASEDIR)/kern.dll XIPKERNEL SHZ
- coredll.dll $(_FLATRELEASEDIR)/coredll.dll XIPKERNEL SH
- k.coredll.dll $(_FLATRELEASEDIR)/k.coredll.dll XIPKERNEL SHMK
- oalioctl.dll $(_FLATRELEASEDIR)/oalioctl.dll XIPKERNEL SHK
- filesys.dll $(_FLATRELEASEDIR)/filesys.dll XIPKERNEL SHK
- fsdmgr.dll $(_FLATRELEASEDIR)/fsdmgr.dll XIPKERNEL SHMK
- mspart.dll $(_FLATRELEASEDIR)/mspart.dll XIPKERNEL SHK
- romfsd.dll $(_FLATRELEASEDIR)/romfsd.dll XIPKERNEL SHK
- binfs.dll $(_FLATRELEASEDIR)/binfs.dll XIPKERNEL SHK
- fpcrt.dll $(_FLATRELEASEDIR)/fpcrt.dll XIPKERNEL SH
- k.fpcrt.dll $(_FLATRELEASEDIR)/fpcrt.dll XIPKERNEL SHMK
- ceddk.dll $(_FLATRELEASEDIR)/ceddk.dll XIPKERNEL SHQ
- device.dll $(_FLATRELEASEDIR)/device.dll XIPKERNEL SHMK
- udevice.exe $(_FLATRELEASEDIR)/udevice.exe XIPKERNEL SHM
- devmgr.dll $(_FLATRELEASEDIR)/devmgr.dll XIPKERNEL SHMK
- regenum.dll $(_FLATRELEASEDIR)/regenum.dll XIPKERNEL SHK
- busenum.dll $(_FLATRELEASEDIR)/busenum.dll XIPKERNEL SHK
- pm.dll $(_FLATRELEASEDIR)/pm.dll XIPKERNEL SHMK
- nandfmd.dll $(_FLATRELEASEDIR)/nandfmd.dll XIPKERNEL SHK
- FILES
- boot.hv $(_FLATRELEASEDIR)/boot.hv XIPKERNEL SH
- wince.nls $(_FLATRELEASEDIR)/wince.nls XIPKERNEL SHU
複製代碼
這裏的nandfmd.dll是我的NAND驅動,可以改成你自己的
可能有一些還是可以優化掉的,但是我還沒有嘗試,大家可以給出意見
上面這段代碼放到哪裏?
放到config.bib最後!沒錯,是config.bib,不是platform.bib
這裏再回頭來說說使用NK當作RAMIMAGE名稱的缺點
大家看到,我們只要把需要的模塊改成XIPKERNEL就好了,但是系統默認的都是用的NK這個名字,如果我們使用NK當作
RAMIMAGE的名字的話,我們要把其他所有不要加進來的改名字...這個工作量太大了,所以我們把NK當作了NANDIMAGE
的名字
4 配置註冊表
到了這一步還沒有完成,我們需要配置些註冊表
其實我默認的註冊表還真沒有什麼需要改的
大家看看MS的幫助文件裏面關於註冊表的配置,這裏列出一些設置
- [HKEY_LOCAL_MACHINE/System/StorageManager/PartitionTable]
- "21"="BINFS"
- [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/FlashDisk/BINFS]
- "MountHidden"=dword:1
- "MountAsROM"=dword:1
複製代碼
這裏不得不說一下RAM and ROM file system和ROM-Only file system
很多帖子都說用BINFS一定要用RAM and ROM file system,實際上並不是這樣
使用ROM-Only file system一樣可以,但是大家需要記住,在使用ROM-Only file system時,把FAT mount爲根目錄
五 BINFS的燒寫和啓動
上面把BSP那裏該修改的都修改了,只要編譯就可以了,關於如何編譯系統,其實是一個非常非常重要的問題,一定要
重視,參考http://www.armce.com/bbs/thread-804-1-1.html
不正確的編譯,會影響你本來應該正確的結果!
下面又是一個問題,現在生成了4個可以用的bin,分別是
XIKERNEL.bin,nk.bin,chain.bin,xip.bin
那麼到底該怎麼燒寫呢?
實際上大家從大小就可以看出XIP包含了所有其他bin的內容,所以大家直接把XIP.bin下載解壓,然後用bootpart的函
數燒寫到存儲器上就可以了
啓動的時候怎麼引導?和原來啓動系統一樣,但是記住,不需要把全部的xip.bin裏面指定的大小都讀取出來了,最多
只要讀你在config.bib裏面指定的RAMIMAGE大小就可以了
RAMIMAGE大小怎麼確定的?這個你可以先放的比較大,比如10MB,然後看編譯出來的RAMIMAGE分區有多大,再調整,
一般都是3MB以內吧,我這裏保守的用4MB
六 調試技巧
調試BINFS的multi-bin啓動,需要反覆的燒寫,設置有一點不正確經常就是卡在某個地方,對於我們用中文鏡像的就
更痛苦了,release版都有30-40MB,debug版不改存儲佈局,燒都燒不進去
我建議大家新建一個項目,然後選擇thin client,不妨將顯示驅動也加入,其他驅動都不要,然後一定選擇debug版
本,debug版本的調試信息非常重要
花這點時間去編譯一個thin client是非常值得的,調試速度很快
下面給一些調試建議
1 引導之後就死機,什麼消息都沒有
估計是內存配置有問題,或者燒寫的有問題,或者沒有把需要的內核模塊加進去
2 死在OEMInit之後
後面應該開始加載NAND驅動了,看看你的關於設備管理,驅動加載和總線枚舉的模塊有沒有加全
如果已經有NAND驅動的信息出來了,看看NAND驅動是不是因爲什麼原因沒有加載起來,比如缺少某個dll支持
3 其他
如果NAND正常了,BINFS沒問題了,大家需要根據自己的BSP來看看其他的問題
wwfiney@ARMCE