龔 銳,石 偉,劉 威,張劍鋒,王 蕾
(國防科技大學計算機學院,湖南 長沙 410073)
嵌入式系統中,一般需要多種不同的非易失存儲介質,用于存儲代碼和數據。這些非易失存儲介質包括EEPROM、NOR Flash和NAND Flash等。其中,NOR Flash具有穩定可靠的特點,并且具備直接執行XIP(Execute In Place)的優勢,可以通過控制器將其內部地址直接映射成CPU可直接訪問的地址,從而使得存儲其中的代碼可以直接執行。但是,NOR Flash容量較小,所以一般用于存儲可執行的啟動代碼。
相對于NOR Flash,NAND Flash具有更大的存儲容量和更快的寫入速度,因此一般作為大容量的存儲設備使用。但是,NAND Flash的器件特性導致其出廠時就有一定的壞塊存在,并且在使用過程中,也可能由于反復擦寫出現壞塊。因此,使用NAND Flash時,需要首先加載驅動,由驅動對NAND Flash進行壞塊管理、讀寫控制和壽命管理等。所以,NAND Flash并不具備XIP能力,存儲其中的代碼不能直接執行,必須由驅動加載到內存中才能執行。
因此,在嵌入式系統中,一般同時具有NOR Flash和NAND Flash 2種存儲介質。NOR Flash用于存儲啟動代碼,包括bootloader、Uboot等,NAND Flash用于存儲OS鏡像和文件系統。這種啟動方案增加了PCB板面積,不利于系統小型化,也不利于控制系統成本和功耗。
本文首先提出了一種軟硬件結合的方法,實現了基于NAND Flash的直接啟動。該方法利用NAND Flash器件保證第1塊必定為好塊的特點,在第1個好塊中存儲好塊尋找程序,并在啟動時直接執行。軟件將尋找到的好塊信息填寫在CPU片內NAND Flash控制器中的硬件塊映射表中,從而實現NAND Flash中部分地址的直接映射。這種方法使得NAND Flash具備了XIP能力,不需要復雜的驅動就可以實現CPU對NAND Flash的直接訪問,并使得存儲其中的代碼可以直接執行。通過該方法,在系統中可以去掉NOR Flash,實現僅需NAND Flash的啟動方案。
基于上述啟動方案,本文進一步提出了一種基于NAND Flash的安全啟動方案,實現了僅需NAND Flash的安全啟動。該方案為簡化片內BootROM代碼,將一部分代碼作為擴展BootROM存儲于片外NAND Flash中。片內可信根只執行簡單的Hash比對,對存儲于片外NAND Flash中第1塊內的擴展BootROM代碼進行校驗。再由第1塊代碼通過簽名驗證的方式,對后續的固件代碼進行驗證。從而建立起逐級的可信鏈,實現系統的安全啟動。
本文的主要貢獻包括以下2個方面:
(1)提出了一種軟硬件結合的方法,實現了NAND Flash中部分地址的直接映射,從而使得NAND Flash中存儲的代碼可以直接執行,實現了僅需NAND Flash的系統啟動方案;
(2)提出了一種基于上述啟動特性的CPU安全啟動方案,通過將BootROM擴展存儲至NAND Flash中,簡化了片內固化的BootROM設計,并實現了多級驗簽機制。
通過本文提出的方法,可以實現僅需NAND Flash的系統啟動方案,并在此系統上實現安全啟動,從而有效降低系統的成本和功耗,且提高了系統的安全特性。
目前主流的Flash存儲器根據其內部架構和實現技術可以分為NOR Flash和NAND Flash[1]。 其中,NOR Flash是由Intel公司于1988年推出的,NAND Flash是由東芝公司于1989年推出的。
NOR Flash具有較快的讀速度,并且具備直接執行(XIP)功能,但其容量較低且價格較高,所以一般作為系統的啟動代碼存儲器,也就是說直接映射為內存(Memory)空間使用。NAND Flash讀取速度較慢,但其寫和擦除操作較NOR Flash更快,且存儲容量更大,價格較低。因此,NAND Flash多用于數據存儲,也就是說作為外存(Storage)使用。
NAND Flash采用基于塊和頁的組織結構。一片NAND Flash芯片劃分為多個塊,擦除以塊為單位進行,擦除后整塊的數據均為全1。每一個塊內又分為若干個頁,頁是讀取和寫入的基本單位。以當前典型的4 Gb的NAND Flash芯片為例,一般塊大小為256 KB,全片共2 048個塊,每塊又分為64個4 KB的頁。對NAND Flash進行讀取訪問時,由控制器發出塊號和頁號等信息,NAND Flash器件返回該頁的全部數據。
NAND Flash芯片在出廠時,并不保證所有的塊都是好塊,即都可用,僅保證第1塊一定是好塊。在寫入時,如果遇到壞塊,一般往后順延一個塊寫入。一個塊是否為好塊,標識在NAND Flash的OOB(Out of Band)空間,不同廠家的標識方法略有不同。如東芝的壞塊標識是該塊的第1頁和第2頁的OOB空間第1個字節非全1[2],Gigadevice的壞塊標識是該塊第1頁OOB的第1個字節非全1[3],Kioxia的壞塊標識是該塊所有存儲空間均為全0[4]。因此,訪問NAND Flash時,一般需要使用廠家提供的驅動進行塊頁地址映射、壞塊識別與跳過等操作。
由于NOR Flash和NAND Flash的固有特性,一般系統中同時具有NOR Flash和NAND Flash 2種存儲介質。NOR Flash用于存儲啟動代碼,NAND Flash用于存儲文件系統。文獻[5]提出了一種全硬件支持的NOR Flash直接地址訪問控制器。本文提出一種軟硬件結合的方法,支持NAND Flash的直接地址訪問,并實現了相關的控制器設計。采用本文提出的方法,可以實現NAND Flash中存儲代碼的直接執行,并實現了壞塊管理的功能。基于本文的控制器,可以取消系統中的NOR Flash,從而縮小PCB板面積,有利于系統小型化,同時控制系統成本和功耗。
信息系統面臨多種現實的安全風險。為了應對這些安全風險,一般需要在硬件的支持下,實現硬件資源隔離[6]、安全啟動[7]等安全機制。其中,安全啟動是比較常見的信任鏈建立機制,其啟動流程如圖1所示。通過可信根對片外固件進行驗簽,確保固件沒有被非法篡改過;再由固件對OS進行驗簽,確保OS的合法性;最后由OS對應用進行驗簽,保證最終執行的應用的合法性。

Figure 1 Traditional secure boot flow圖1 傳統的安全啟動流程
傳統的安全啟動流程需要以板級的TCM/TPM(Trusted Cryptography Model/Trusted Platform Model)芯片作為可信根[7]。隨著CPU的進一步發展,出現了將可信根內置于CPU內的方案[8,9]。CPU內置的可信根一般由片內ROM及ROM中存儲的BootROM代碼、efuse和密碼加速引擎構成。BootROM代碼為CPU啟動后執行的代碼,efuse中存儲公鑰的Hash。片外被驗簽的第1級固件的Hash值運用私鑰進行運算,得到簽名,并與片外第1級固件一起存儲。啟動后CPU執行BootROM程序,將片外的第1級固件搬到片內SRAM區域,再啟動密碼加速引擎,得到固件計算Hash值并用片內efuse存儲的公鑰進行計算,得到的值與片外存儲的簽名進行比對,一致則說明固件沒有被篡改過,是安全可信的。
傳統的安全啟動方案需要可信根至少執行Hash和非對稱算法2種運算,使得固化于片內的BootROM代碼設計復雜,所需的ROM容量大,不利于控制芯片面積和成本。本文提出的擴展BootROM的安全啟動方案,利用NAND Flash啟動的特性,將部分BootROM擴展存儲至片外NAND Flash第1塊中,片內BootROM只需要計算Hash就可以驗證擴展BootROM,有利于減少片內ROM容量,降低代碼復雜度。同時,安全啟動也要和片外啟動固件的存儲相結合。文獻[10]提出了一種基于NOR Flash的安全啟動控制器設計方案。而本文提出的是基于NAND Flash的安全啟動方案,可以實現單NAND Flash系統的安全啟動。
為了縮小PCB板面積,實現系統小型化,降低系統的成本與功耗,本文設計實現了一種僅需NAND Flash的系統啟動方案。該方案取消了一般系統中存在的NOR Flash芯片,將系統啟動代碼直接存儲在NAND Flash中。此時NAND Flash芯片中前-部分存儲系統啟動代碼,通過特殊設計的地址直接映射方式,實現CPU在啟動后對這部分代碼的直接訪問和執行;NAND Flash后一部分主要的存儲空間仍然存儲OS鏡像和文件系統,通過加載驅動的方式進行訪問。
為實現NAND Flash前一部分存儲空間的地址直接映射,本文提出了一種軟硬件結合的方法。在硬件上,在CPU中設計實現了一種全新的NAND Flash控制器,該控制器由Cache、地址映射邏輯、塊映射表和接口邏輯等組成,具體結構如圖2所示。

Figure 2 Block diagram of NAND Flash controller圖2 NAND Flash控制器結構框圖
系統啟動后,CPU取指執行時通過軟件可見的Memory地址直接訪問NAND Flash控制器,獲取啟動代碼。由于NAND Flash接口訪問速度較慢,且一般采用整頁讀取的方式進行操作,本文在NAND Flash控制器內設計實現了一個Cache,該Cache的行大小為一整頁的容量。CPU通過Memory地址訪問時,首先判斷該地址的代碼是否在Cache中命中,如果命中,則直接返回;如果不命中,則需要訪問片外NAND Flash器件取回相應的啟動代碼。
Cache不命中時,由地址映射邏輯將Memory地址按照NAND Flash的特性映射為塊號和頁號。需要注意的是,這里的塊號為邏輯塊號,是由Memory地址直接映射得到,并沒有考慮物理上NAND Flash可能存在的壞塊。這些邏輯塊號還需要由塊映射邏輯映射到物理塊號,物理塊號才保證是NAND Flash中的好塊。
經過塊映射邏輯得到的物理塊號和頁號,由Flash控制模塊產生符合NAND Flash接口時序和協議要求的訪問序列,訪問片外NAND Flash,取回一整頁數據,并回填至Cache中,返回相應的代碼、數據給CPU核。
上述結構中,最關鍵的結構為塊映射邏輯,本文設計實現了如圖3所示的硬件塊映射表,通過邏輯塊號訪問硬件塊映射表,獲得該邏輯塊號對應的物理塊號。

Figure 3 Block mapping table圖3 塊映射表
系統啟動時,CPU并不知道片外NAND Flash中的壞塊信息,此時塊映射表中的信息是無效的。本文利用NAND Flash器件保證第1塊為好塊的物理特性,將塊映射表0號入口固定復位為0,也即將0號邏輯Block固定映射為0號物理Block。通過在NAND Flash器件的0號物理Block空間存放的好塊尋找程序,CPU直接訪問0號物理Block并執行該程序。該部分代碼從1號物理Block開始,尋找N-1塊物理好塊,并將其物理塊號填入硬件塊映射表。好塊尋找算法偽代碼如算法1所示。
算法1好塊尋找算法
輸入:塊映射表BMT項數N;
輸出:塊映射表BMT。
①for(i=1;i=i+1;i≤N)
②PBN=BMT[i-1]+1;
③while(NANDFlash[PBN] is bad block)
④PBN=PBN+1;
⑤endwhile
⑥BMT[i]=PBN;
⑦endfor
該算法先將塊映射表BMT中前一項記錄的物理塊號加1,作為當前物理塊號PBN。通過訪問該PBN在NAND Flash器件中對應的塊,讀取其壞塊信息,判斷當前物理塊是否為好塊。如果為好塊,則將PBN填入BMT中對應表項,否則將PBN加1,繼續尋找好塊。
通過執行位于0塊空間的算法1,填好塊映射表,即可實現CPU所見的存儲空間地址到實際的物理塊、頁號的轉換。實際可直接映射的物理空間大小A取決于塊映射表大小N和物理塊大小B,即A=N×B。假設映射表大小為8項,NAND Flash物理塊大小為256 KB,則能夠地址直接映射的空間大小為2 MB。也就是說NAND Flash空間中前一部分空間在這種方案下可以實現地址直接映射和訪問,存儲于其上的啟動程序代碼可以直接執行。但是,超過這部分地址空間的塊,還是需要通過驅動來進行訪問。因此,在前一部分可以直接地址映射和執行的NAND Flash空間內,除了需要存儲啟動代碼外,還需要存儲NAND Flash驅動,以便訪問后續塊空間。
本文提出的這種軟硬件結合的地址直接映射方法,充分利用了NAND Flash中第1塊為好塊的特性,在第1塊中存儲好塊尋找程序,通過直接執行該算法,填寫硬件塊映射表,從而在無驅動支持下,實現軟件可見存儲地址到物理塊、頁號的直接映射。基于本文提出的方法,可以取消系統中常見的NOR Flash芯片,實現單NAND Flash啟動,從而有效減少系統成本、體積和功耗。
傳統的安全啟動流程要求片內BootROM至少可以執行非對稱和Hash 2種類型的密碼運算,對片內BootROM的存儲容量和代碼復雜度要求比較高。特別是非對稱密碼算法運算復雜,即便是調用片內的硬件密碼引擎,也需要有比較復雜的軟件驅動,需要占用大量的片內BootROM存儲容量。
一般來說,片內BootROM存儲在ROM或eFlash中。ROM中的代碼在芯片生產時即確定,eFlash可以在芯片生產回片后再燒錄。但是,現在先進工藝下均沒有eFlash器件。所以,需要先進工藝的高性能CPU只能采用片內ROM存儲BootROM代碼。片內ROM的容量大小會影響芯片面積,進而影響芯片的成本。而BootROM代碼的復雜度又會帶來驗證的復雜度,必須在芯片流片前將BootROM代碼中所有的分支都驗證到,保證BootROM代碼是無錯的。因此,簡化BootROM代碼,壓縮BootROM鏡像大小,降低其復雜度,對于降低芯片成本、驗證復雜度和流片風險都有很大的作用。
具體到本文提出的單NAND Flash啟動方法,由于必須首先執行片外NAND Flash中第1塊上的好塊尋找程序,才能填寫硬件好塊映射表,進而對后續地址進行直接地址映射。所以,如果采用傳統的安全啟動方案,需要BootROM代碼對片外第1塊的代碼先進行驗簽,驗簽通過后執行,再由第1塊代碼驗簽后續代碼(如圖4所示)。這不僅使得BootROM程序復雜,鏡像容量大,還使得本來可以1次完成的固件驗簽,至少需要2次驗簽才能完成,不利于系統快速啟動。

Figure 4 Traditional NAND Flash secure boot flow圖4 基于傳統方法的NAND Flash安全啟動流程
為了解決傳統的基于驗簽的安全啟動流程運用于NAND Flash啟動時導致的ROM容量過大,BootROM代碼復雜,需要多次驗簽等缺點,本文提出了一種基于擴展BootROM的NAND Flash安全啟動方法。
本文提出的方法將片外NAND Flash上第1塊的代碼的Hash值存儲在片內efuse中。CPU啟動時,執行片內BootROM代碼,將片外NAND Flash中第1塊的代碼拷貝到片內SRAM,再用相同的算法計算Hash值,并與片內efuse中存儲的Hash值進行比較,如果比較通過,則認為片外NAND Flash上第1塊的代碼沒有被篡改過,是安全可信的,可以執行。具體流程如圖5所示。

Figure 5 NAND Flash secure boot flow based on extended BootROM圖5 基于擴展BootROM的NAND Flash安全啟動流程
本文提出的方法中,對片外第1級只采用Hash比對,因此當在片內efuse中寫入Hash值以后,片外第1級固件就不能再更改了。片外NAND Flash中第1塊的代碼類似于不可更新的BootROM,本文稱之為擴展BootROM。與存放于片內的BootROM相比,擴展BootROM具有一定的靈活性,因為不用在芯片流片前就確定代碼鏡像,回片后有一次燒錄機會。此外,對于一款芯片,片內BootROM的代碼完全相同,但是擴展BootROM還可以根據不同的板級設計有所區別。比如,板級集成了不同廠家的NAND Flash芯片時,由于不同廠家的壞塊標識略有不同,因此好塊尋找算法具體實現也有所區別。在擴展BootROM中實現好塊尋找算法,可以根據不同的NAND Flash器件,在回片后在片外Flash的第1塊上燒錄不同的擴展BootROM代碼,并將其Hash值燒錄到片內的efuse中。
與傳統的基于驗簽的方法相比,本文提出的方法在片內BootROM中只需執行Hash運算,減少了非對稱運算的時間和代碼量,有效減少了ROM容量。
基于本文提出的軟硬件結合的地址映射方法,設計實現了一款SPI接口的NAND Flash控制器。該控制器對內采用APB3接口,連接到片上總線NoC,對外采用標準的SPI接口,連接NAND Flash芯片。該SPI NAND Flash控制器的主要設計參數如表1所示。

Table 1 Design parameters
由于SPI NAND Flash采取整頁讀出的方式,為了減少SPI接口訪問,盡可能多地重復使用一次讀出的數據和代碼,本文設計的SPI NAND Flash控制器內的Cache必須具備將一整頁數據全部緩存的能力。當前主流的NAND Flash的頁大小一般為2 KB(總容量不大于2 Gbit器件)或4 KB(總容量不小于4 Gbit器件)。因此,本文將Cache行大小設計為2 KB,Cache行數設計為2。這樣對于頁大小為2 KB的器件,可以緩存2個頁的數據,對于頁大小為4 KB的器件,可以緩存1個頁的數據。
為了實現地址的直接映射,本文采用了硬件塊映射表的結構,該映射表的大小決定了可以直接映射的地址空間大小。本文設計的塊映射表大小為4。當前主流的NAND Flash的塊大小一般為128 KB(總容量不大于2 Gbit器件)或256 KB(總容量不小于4 Gbit器件)。對于塊大小為128 KB的器件,可以直接尋址512 KB的空間,對于塊大小為256 KB的器件,可以直接尋址1 MB的空間。一般來說,該直接尋址空間已經足夠存儲完整的Uboot代碼。因此,采用本文設計的SPI NAND Flash控制器可以實現僅需NAND Flash系統的直接啟動。
為了驗證本文提出的安全啟動方案的有效性,設計了一個驗證SoC,其框圖如圖6所示。該SoC采用開源的32位RISC-V架構處理器內核PULPino[11]。該內核通過NoC連接本文設計的SPI NAND Flash控制器,NoC上還掛接了256 KB的SRAM、efuse和密碼計算引擎。

Figure 6 SoC diagram圖6 SoC框圖
本文對比了采用傳統驗簽流程和采用擴展BootROM方式進行驗簽時對片內ROM的容量需求,具體如圖7所示。

Figure 7 Comparison of BootROM code capacity圖7 BootROM容量比較
采用傳統驗簽流程時,使用標準的X.509證書格式。X.509標準是國際電信聯盟ITU(International Telecommunication Union)制定的公鑰證書格式標準,已經廣泛應用于眾多互聯網協議和電子簽名服務中。實現基于X.509證書的驗簽,至少需要進行非對稱和Hash 2種運算,本文采用RSA2048和SHA256 2種類型的運算。而采用擴展BootROM的方式,僅需要在片內ROM中實現Hash算法,本文采用了SHA256算法。可以看出,采用傳統驗簽流程,片內ROM容量大小至少需要30 KB以上,而采用擴展BootROM的方式,片內ROM僅需16 KB。因此,本文提出的方法可以大大簡化片內BootROM的軟件設計,減少片內ROM容量,有利于降低BootROM軟件驗證風險和縮小芯片面積,降低芯片成本和功耗。
本文還對比了采用傳統驗簽流程和采用擴展BootROM方式進行驗簽時所需的執行時間,具體如圖8所示。圖8中采用了歸一化的執行時間比較,以X.509驗簽執行的時鐘周期為1,擴展BootROM校驗方法執行的時間為X.509驗簽執行時間的89%。測試執行時間時,假設處理器核、片上網絡、Crypto單元、SRAM和ROM等都工作在500 MHz,SPI接口工作在125 MHz。采用X.509驗簽時,片內BootROM首先執行RSA2048和SHA256 2種類型的運算,對片外NAND Flash上第1塊中的128 KB代碼進行驗簽;然后執行第1塊的代碼,尋找好塊,填寫好塊映射表,再由第1塊的代碼執行RSA2048和SHA256算法驗簽后續算法。采用擴展BootROM校驗方法時,片內BootROM僅需執行SHA256算法計算片外NAND Flash第1塊中的128 KB代碼的Hash值;然后再由第1塊的代碼執行RSA2048和SHA256算法驗簽后續算法。可以看出,本文提出的安全啟動方法從NAND Flash直接啟動,相比于傳統驗簽方法可以大大節省啟動時間。

Figure 8 Comparison of normalized secure boot execution time圖8 歸一化安全啟動執行時間比較
針對NAND Flash存儲器固有的壞塊導致不能直接尋址,不能支持存儲系統啟動代碼直接執行的特點,本文提出了一種軟硬件結合的方法,實現了NAND Flash中部分地址的直接映射,從而使得NAND Flash中存儲的代碼可以直接執行,實現了僅需NAND Flash的系統啟動方案。本文還提出了一種基于上述啟動特性的CPU安全啟動方案,通過將BootROM擴展存儲至NAND Flash中,簡化了片內固化的BootROM設計,并實現了多級驗簽機制。
通過本文提出的方法,可以實現僅需NAND Flash的系統啟動方案,并在此系統上實現了安全啟動,從而有效降低了系統的成本和功耗,且提高了系統的安全特性。