Flash名稱的由來,Flash的擦除操做是以block塊爲單位的,與此相對應的是其餘不少存儲設備,是以bit位爲最小讀取/寫入的單位,Flash是一次性地擦除整個塊:在發送一個擦除命令後,一次性地將一個block,常見的塊的大小是128KB/256KB,所有擦除爲1,也就是裏面的內容所有都是0xFF了,因爲是一會兒就擦除了,相對來講,擦除用的時間很短,能夠用一閃而過來形容,因此,叫作Flash Memory。因此通常將Flash翻譯爲 (快速)閃存。算法
NAND Flash 在嵌入式系統中有着普遍的應用,負載平均和壞塊管理是與之相關的兩個核心議題。Uboot 和 Linux 系統對 NAND 的操做都封裝了對這兩個問題的處理方法。 本文首先講述Nandflash基礎知識,而後介紹現有的幾類壞塊管理(BBM)方法,經過分析典型嵌入式系統的 NAND 存儲表,指出了輕量級管理方法的優點所在,分析了當前普遍使用的輕量級管理方法,指出其缺陷所在並詳細說明了改進方法。sql
基礎知識 編程
Flash的硬件實現機制緩存
Flash的內部存儲是MOSFET,裏面有個懸浮門(Floating Gate),是真正存儲數據的單元。安全
在Flash以前,紫外線可擦除(uv-erasable)的EPROM,就已經採用了Floating Gate存儲數據這一技術了。服務器
典型的Flash內存物理結構
性能
數據在Flash內存單元中是以電荷(electrical charge) 形式存儲的。存儲電荷的多少,取決於圖中的外部門(external gate)所被施加的電壓,其控制了是向存儲單元中衝入電荷仍是使其釋放電荷。而數據的表示,以所存儲的電荷的電壓是否超過一個特定的閾值Vth來表示,所以,Flash的存儲單元的默認值,不是0(其餘常見的存儲設備,好比硬盤燈,默認值爲0),而是1,而若是將電荷釋放掉,電壓下降到必定程度,表述數字0。加密
NandFlash的簡介
Nand flash成本相對低,說白了就是便宜,缺點是使用中數據讀寫容易出錯,因此通常都須要有對應的軟件或者硬件的數據校驗算法,統稱爲ECC。但優勢是,相對來講容量比較大,如今常見的Nand Flash都是1GB,2GB,更大的8GB的都有了,相對來講,價格便宜,所以適合用來存儲大量的數據。其在嵌入式系統中的做用,至關於PC上的硬盤,用於存儲大量數據。
SLC和MLC
Nand Flash按照內部存儲數據單元的電壓的不一樣層次,也就是單個內存單元中,是存儲1位數據,仍是多位數據,能夠分爲SLC和MLC。那麼軟件如何識別系統上使用過的SLC仍是MLC呢?
Nand Flash設計中,有個命令叫作Read ID,讀取ID,讀取好幾個字節,通常最少是4個,新的芯片,支持5個甚至更多,從這些字節中,能夠解析出不少相關的信息,好比此Nand Flash內部是幾個芯片(chip)所組成的,每一個chip包含了幾片(Plane),每一片中的頁大小,塊大小,等等。在這些信息中,其中有一個,就是識別此flash是SLC仍是MLC。 spa
oob / Redundant Area / Spare Area翻譯
每個頁,對應還有一塊區域,叫作空閒區域(spare area)/冗餘區域(redundant area),而Linux系統中,通常叫作OOB(Out Of Band),這個區域,是最初基於Nand Flash的硬件特性:數據在讀寫時候相對容易錯誤,因此爲了保證數據的正確性,必需要有對應的檢測和糾錯機制,此機制被叫作EDC(Error Detection Code)/ECC(Error Code Correction, 或者 Error Checking and Correcting),因此設計了多餘的區域,用於放置數據的校驗值。
Oob的讀寫操做,通常是隨着頁的操做一塊兒完成的,即讀寫頁的時候,對應地就讀寫了oob。
關於oob具體用途,總結起來有:
Bad Block Management壞塊管理
Nand Flash因爲其物理特性,只有有限的擦寫次數,超過那個次數,基本上就是壞了。在使用過程當中,有些Nand Flash的block會出現被用壞了,當發現了,要及時將此block標註爲壞塊,再也不使用。於此相關的管理工做,屬於Nand Flash的壞塊管理的一部分工做。
Wear-Leveling負載平衡
Nand Flash的block管理,還包括負載平衡。
正是因爲Nand Flash的block,都是有必定壽命限制的,因此若是你每次都往同一個block擦除而後寫入數據,那麼那個block就很容易被用壞了,因此咱們要去管理一下,將這麼屢次的對同一個block的操做,平均分佈到其餘一些block上面,使得在block的使用上,相對較平均,這樣相對來講,能夠更能充分利用Nand Flash。
ECC錯誤校驗碼
Nand Flash物理特性上使得其數據讀寫過程當中會發生必定概率的錯誤,因此要有個對應的錯誤檢測和糾正的機制,因而纔有此ECC,用於數據錯誤的檢測與糾正。Nand Flash的ECC,常見的算法有海明碼和BCH,這類算法的實現,能夠是軟件也能夠是硬件。不一樣系統,根據本身的需求,採用對應的軟件或者是硬件。
相對來講,硬件實現這類ECC算法,確定要比軟件速度要快,可是多加了對應的硬件部分,因此成本相對要高些。若是系統對於性能要求不是很高,那麼能夠採用軟件實現這類ECC算法,可是因爲增長了數據讀取和寫入先後要作的數據錯誤檢測和糾錯,因此性能相對要下降一些,即Nand Flash的讀取和寫入速度相對會有所影響。
其中,Linux中的軟件實現ECC算法,即NAND_ECC_SOFT模式,就是用的對應的海明碼。
而對於目前常見的MLC的Nand Flash來講,因爲容量比較大,動輒2GB,4GB,8GB等,經常使用BCH算法。BCH算法,相對來講,算法比較複雜。
筆者因爲水平有限,目前仍未徹底搞懂BCH算法的原理。
BCH算法,一般是由對應的Nand Flash的Controller中,包含對應的硬件BCH ECC模塊,實現了BCH算法,而做爲軟件方面,須要在讀取數據後,寫入數據以前,分別操做對應BCH相關的寄存器,設置成BCH模式,而後讀取對應的BCH狀態寄存器,得知是否有錯誤,和生成的BCH校驗碼,用於寫入。
其具體代碼是如何操做這些寄存器的,因爲是和具體的硬件,具體的nand flash的controller不一樣而不一樣,沒法用同一的代碼。若是你是nand flash驅動開發者,天然會獲得對應的起nand flash的controller部分的datasheet,按照手冊說明,去操做便可。
不過,額外說明一下的是,關於BCH算法,每每是要從專門的作軟件算法的廠家購買的,可是Micron以前在網上放出一個免費版本的BCH算法。
位反轉
Nand Flash的位反轉現象,主要是由如下一些緣由/效應所致使:
漂移效應指的是,Nand Flash中cell的電壓值,慢慢地變了,變的和原始值不同了。
此現象有時候也叫作,過分編程效應(over-program effect)。
對於某個頁面的編程操做,即寫操做,引發非相關的其餘的頁面的某個位跳變了。
此效應是,對一個頁進行數據讀取操做,卻使得對應的某個位的數據,產生了永久性的變化,即Nand Flash上的該位的值變了。
以上兩種類型的位反轉,其實對於從Nand Flash讀取出來的數據來講,解決其中的錯誤的位的方法,都是同樣的,即經過必定的校驗算法,常稱爲ECC,去檢測出來,或檢測並糾正錯誤。
若是隻是單獨檢測錯誤,那麼若是發現數據有誤,那麼再從新讀取一次便可。
實際中更多的作法是,ECC校驗發現有錯誤,會有對應的算法去找出哪位錯誤而且糾正過來。
其中對錯誤的檢測和糾正,具體的實現方式,有軟件算法,也有硬件實現,即硬件Nand Flash的控制器controller自己包含對應的硬件模塊以實現數據的校驗和糾錯的。
咱們寫驅動,是寫Nand Flash 控制器的驅動,而不是Nand Flash 芯片的驅動,由於獨立的Nand Flash芯片,通常來講,是不多直接拿來用的,多數都是硬件上有對應的硬件的Nand Flash的控制器,去操做和控制Nand Flash,包括提供時鐘信號,提供硬件ECC校驗等等功能,咱們所寫的驅動軟件,是去操做Nand Flash的控制器
而後由控制器去操做Nand Flash芯片,實現咱們所要的功能。
因爲Nand Flash讀取和編程操做來講,通常最小單位是頁,因此Nand Flash在硬件設計時候,就考慮到這一特性,對於每一片(Plane),都有一個對應的區域專門用於存放,將要寫入到物理存儲單元中去的或者剛從存儲單元中讀取出來的,一頁的數據,這個數據緩存區,本質上就是一個緩存buffer,可是隻是此處datasheet裏面把其叫作頁寄存器page register而已,實際將其理解爲頁緩存,更貼切原意。
而正是由於有些人不瞭解此內部結構,才容易產生以前遇到的某人的誤解,覺得內存裏面的數據,經過Nand Flash的FIFO,寫入到Nand Flash裏面去,就覺得馬上實現了實際數據寫入到物理存儲單元中了,而實際上只是寫到了這個頁緩存中,只有當你再發送了對應的編程第二階段的確認命令,即0x10,以後,實際的編程動做纔開始,纔開始把頁緩存中的數據,一點點寫到物理存儲單元中去。
具體標記的地方是,對於如今常見的頁大小爲2K的Nand Flash,是塊中第一個頁的oob起始位置的第1個字節(舊的小頁面,pagesize是512B甚至256B的Nand Flash,壞塊標記是第6個字節),若是不是0xFF,就說明是壞塊。相對應的是,全部正常的塊,好的塊,裏面全部數據都是0xFF的。
對於壞塊的標記,本質上,也只是對應的flash上的某些字節的數據是非0xFF而已,因此,只要是數據,就是能夠讀取和寫入的。也就意味着,能夠寫入其餘值,也就把這個壞塊標記信息破壞了。對於出廠時的壞塊,通常是不建議將標記好的信息擦除掉的。
uboot中有個命令是
nand scrub
就能夠將塊中全部的內容都擦除了,包括壞塊標記,不管是出廠時的,仍是後來使用過程當中出現而新標記的。
nand erase
只擦除好的塊,對於已經標記壞塊的塊,不要輕易擦除掉,不然就很難區分哪些是出廠時就壞的,哪些是後來使用過程當中用壞的了。
NAND 壞塊管理都是基於壞塊表(BBT)的,經過這張表來標識系統中的全部壞塊。因此,不一樣的管理方法之間的差別能夠經過如下幾個問題來找到答案。
Uboot 是目前使用最爲普遍的 bootloader,它提供了兩種輕量級壞塊管理方法,可稱之爲基本型和改進型。經過下表,咱們能夠看到二者的差別。
雖然 uboot 的改進型壞塊管理方法的作了一些改進,但它仍然有三個主要的缺點。
針對現有管理方法的缺陷,本文提出了一種更加安全高效的管理方法,將從如下三個方面闡述其實現原理。
首先,使用一個統一的備用好塊池,爲全部存放在 NAND 中的模塊提供可替換的好塊。這樣,就不須要在每一個模塊後面放置一個保留區,提升了 NAND 的空間利用率。
共用好塊池示意圖
爲了實現共用好塊池,須要創建一個從壞塊到好塊的映射,因此,除了 BBT 以外,還需定義一個替換表(SBT)。這樣一來,當讀第 i 個塊的數據時,若是發現 BBT 中記錄該塊爲壞塊,就去 SBT 中查詢其替換塊;若是寫第 i 個塊出錯,須要在 BBT 中標記該塊爲壞塊,同時從好塊池中獲取一個新的好塊,假設其序號爲 j,而後將此好塊的序號 j 寫入 SBT 中的第 i 個字節,並且 SBT 的第 j 個字節寫序號 i。SBT 中的這種雙向映射可確保數據的可靠性。此外,好塊池中的塊也有可能成爲壞塊,若是掃描時發現是壞塊,則將 SBT 中的對應位置標記爲 0x00,若是是在寫的過程當中出錯,則除了在 SBT 對應位置標記 0x00 以外,還要更新雙向映射數據。
BBT/SBT 映射示意圖
傳統方法僅檢查 BBT 所在塊的簽名,將讀到的前幾個字節和一個特徵字符串進行比較,若是一致,就認爲當前塊的數據爲 BBT,而後讀取接下來的 BBT 數據,但並不對 BBT 的數據作校驗。若是 BBT 保存在 NAND 中,數據的有效性是能夠獲得驗證的,由於 NAND 控制器或驅動通常都會對數據作 ECC 校驗。可是,大多數控制器使用的 ECC 算法也僅僅能糾正一個 bit、發現 2 兩個 bit 的錯誤。若是 BBT 保存在其餘的沒有 ECC 校驗機制的存儲體中,好比 NOR Flash,沒有對 BBT 的數據進行校驗顯然是不安全的。
爲了更加可靠和靈活地驗證 BBT/SBT 數據,定義下面這個結構體來描述 BBM 信息。
BBM 頭信息
typedef struct {
UINT8 acSignature[4];/* BBM 簽名 */
UINT32 ulBBToffset;/* BBT 偏移 */ UINT32 ulSBToffset;/* SBT 偏移 */ UINT16 usBlockNum;/* BBM 管理的 block 數目 */ UINT16 usSBTstart;/* SBT 所在位置的起始 block 序號 */ UINT16 usSBtop;/* SBT top block */ UINT16 usSBnum;/* SBT number */ UINT32 ulBBTcrc;/* BBT 數據 CRC 校驗碼 */ UINT32 ulSBTcrc;/* SBT 數據 CRC 校驗碼 */ UINT32 ulHeadcrc;/* BBM 頭信息 CRC 校驗碼 */ } BBM_HEAD
BBT/SBT 的保存形式
使用三重 CRC 校驗機制,不管 BBT 保存在哪一種存儲體中,均可以更加嚴格地驗證數據的有效性。
傳統的方法僅保存一份 BBT 數據,若是在寫 BBT 時系統掉電,則 BBT 丟失,系統將可能沒法正常啓動或工做。爲安全起見,本文所述方法將同時保留三個備份,若是在寫某個備份時掉電,則還有兩個無缺的備份。最壞的狀況是,若是在寫第一個備份時掉電,則當前最新的一個壞塊信息丟失。
讀取壞塊表時,順序讀取三個備份,若是發現三個備份的數據不一致,用記錄的壞塊數最多的備份爲當前的有效備份,同時馬上更新另外兩備份。
本文介紹了NandFlash基礎知識和幾類 NAND 壞塊管理方法,指出了 uboot 的輕量級管理方法的缺陷,提出了一種改進的方法,提升了 NAND 的利用率及壞塊管理的安全性,可對嵌入式開發起到有很好的借鑑做用。