Tina Linux 存儲開發指南
1 概述
1.1 編寫目的
介紹TinaLinux Flash,分區,文件系統等存儲相關信息,指導方案的開發定制。
1.2 適用范圍
Tina V3.0 及其后續版本。
1.3 相關人員
適用于TinaLinux 平臺的客戶及相關技術人員。
2 分區管理
2.1 分區配置文件
在全志平臺中,通過sys_partition.fex 文件配置分區。在Tina 中,可以在lunch 選擇方案后,通過命令cconfigs 快速跳轉到分區配置目錄,通常情況下,其路徑如下。
tina/device/config/chips/<芯片編號>/configs/<方案名>/linux/sys_partition.fex
tina/device/config/chips/<芯片編號>/configs/<方案名>/linux/sys_partition_nor.fex
#以上路徑不存在,則使用
tina/device/config/chips/<芯片編號>/configs/<方案名>/sys_partition.fex
?
說明 sys_partition_nor.fex 適用于nor。 sys_partition.fex 適用于rawnand/spinand/mmc。
2.2 分區配置格式
以rootfs 分區為例:
[partition]
name = rootfs
size = 20480
downloadfile = "rootfs.fex"
user_type = 0x8000
每個分區以[partition] 標識,分區屬性及其意義如下表。
屬性 | 含義 | 必選 | 備注 |
---|---|---|---|
name | 分區名 | Y | |
size | 分區大小 | Y | 單位:扇區(512B),注1 |
downlodefile | 分區燒入的鏡像文件 | N | 注2 |
verify | 量產后校驗標識 | N | (默認)1:使能;0:禁用,注3 |
user_type | 分區屬性 | N | 注 4 |
keydata | 量產時是否擦除本分區 | N | 0x8000:使用;其他無效 |
說明:
最后一個分區(UDISK),不設置size,表示分配所有剩余空間。
downloadfile 支持絕對路徑和相對路徑,相對于tina/out/<方案名>/image。
verify 決定是否校驗downloadfile 中指定的鏡像,若為ext4 稀疏鏡像,務必禁用。
歷史遺留,目前只對UBI 方案有效。bit0為1 時,表示創建靜態卷,反之為動態卷。
創建downloadfile 的資源鏡像包看章節分區資源鏡像文件。 [partition] 標識用戶空間的邏輯分區,在UBI 方案中,表現為UBI 卷。此外,在sys_partiton.fex中存在特殊的配置MBR,用于配置MBR 空間大小,此配置在UBI 方案中無效。例如:
[mbr]
size = 2048
MBR 分區以Kbyte 為單位,對用戶不可見,屬于隱藏空間,其大小也必須滿足對齊原則。
警告 一般情況下,不建議用戶修改mbr 分區的大小。
2.3 常見分區及其用途
分區名 | 用途 | 大小 | 備注 |
---|---|---|---|
boot | 內核鏡像分區 | 比實際鏡像等大或稍大即可 | |
rootfs | 根文件系統鏡像 | 比實際鏡像等大或稍大即可 | |
extend | 擴展系統鏡像 | 參考OTA 文檔 | 參考OTA 文檔僅小容量OTA 方案使用 |
recovery | 恢復系統鏡像 | 參考OTA 文檔 | 僅限大容量OTA 方案使用 |
private | 存儲SN、MAC 等數據 | 使用默認大小即可 | 量產時默認不丟失 |
misc | 存儲系統狀態、刷機狀態 | 使用默認大小即可 | |
env | 存放Uboot 使用的數據 | 使用默認大小即可 | |
pstore | 內核奔潰日志轉存分區 | 使用默認大小即可 | |
rootfs_data | 根目錄覆蓋分區 | 根據需求配置 | 注1 |
UDISK | 用戶數據分區 | 不需要配置大小 | 注2 |
說明:
rootfs_data 分區通過overlayfs 覆蓋根文件系統,以支持squashfs 根文件系統的可寫,此時對根文件系統寫入的數 據實際是保存到rootfs_data 分區,因此rootfs_data 分區的容量標識著根文件系統最大可寫數據量。
UDISK 作為最后一個分區,不需要設置size,表示分配剩余所有空間給UDISK。
2.4 分區大小與對齊
分區大小的對齊要求與不同介質(nor/nand/mmc)、不同存儲方案相關。不按對齊要求配置,可能出現文件系統異常,分區邊界數據丟失等現象。對齊規則如下表。
介質 | 對齊大小 | 備注 |
---|---|---|
nor | 64K | 對齊物理擦除塊大小,注1 |
(nftl) spinand | 驅動超級塊大小 | 注2 |
(ubi) spinand | 2 × 物理塊- 2 × 頁 | 注3 |
rawnand | 驅動超級塊大小 | 與物料相關,16M 對齊可基本兼容 |
emmc | 16M | 與物料相關,16M 對齊可基本兼容 |
說明
nor 的擦除塊常見為64K,即在sys_partition_nor.fex 中分區size 進行128 對齊。在id 表配置為4K 擦除且使能內核CONFIG_MTD_SPI_NOR_USE_4K_SECTORS 時,也可使用4K 對齊。推薦使用默認64K 對齊。
在常見的128M Spi Nand 中,為256K 對齊,即在sys_partition.fex 中分區size 進行512 對齊。
在常見的128M Spi Nand 中,需要和邏輯擦除塊(super block)對齊,1 個super block 包含兩個物理擦除塊,常見的物理擦除塊128K,1 個邏輯的超級塊為256K,但是需要使用每個物理塊的第一個page(2K)來作為ubi 所需的信息頭部,所以實際的為(256k-2*2k),為252K 對齊,即在sys_partition.fex 中分區size 進行504 對齊。
警告 如果分區不對齊,可能會出現以下情況。 ? nor/rawnand/spinand 可能會導致數據丟失。 ? mmc 不會造成數據丟失,但可能導致性能損失。
如果分區使用ubifs 文件系統,分區最小為5M ,否則大概率提示空間不夠。 如果分區使用ext4 文件系統,分區最小為3M ,否則無法形成日志,會有掉電變磚風險。
技巧
在ext4 與日志章節有描述判斷創建的ext4 文件系統是否支持日志的方法。
在分區資源鏡像文件章節指導如何創建帶文件系統的資源鏡像、分區大小、文件系統大小、文件大小更多內容,請參考總容量說明。
2.5 分區與文件系統
常見的分區與文件系統對應關系如下表。
分區名 | 默認文件系統 | 文件系統特性 | 備注 |
---|---|---|---|
rootfs | squashfs | 壓縮、只讀 | 為了安全,根文件系統建議只讀 |
rootfs_data | jffs2/ext4/ubifs | 可寫 | 注1 |
UIDSK | jffs2/ext4/ubifs | 可寫 | 注1 |
boot | vfat | 裸數據分區,部分方案為vfat | |
private | vfat | 注2 | |
misc | none | 裸數據分區 | |
env | none | 裸數據分區 | |
pstore | pstore | 轉存奔潰日志 |
說明
可寫的分區,nor 為jffs2;UBI 方案為ubifs;其他為ext4。
private 默認為裸數據,使用dragonSN 工具燒錄后會成為vfat 文件系統。
只讀文件系統推薦使用squashfs。可寫文件系統,nor 推薦jffs2,UBI 方案推薦ubifs,其他推薦ext4。更多文件系統信息,請參考文件系統支持情況。
2.6 分區資源鏡像文件
在sys_partition.fex中通過downloadfile 指定需要燒錄到分區的資源鏡像文件。大多數情況下,資源鏡像文件都構建在文件系統上,通過某些命令實現把系統需要的文件,例如音頻文件、視頻文件等資源,打包成一個帶文件系統的鏡像包,并在燒錄時把鏡像包燒寫入存儲 介質。 創建不同文件系統鏡像的命令不一樣,常見有以下幾種:
文件系統 | 創建鏡像命令 |
---|---|
vfat | mkfs.vfat |
ext4 | make_ext4fs |
ubifs | mkfs.ubifs |
squashfs | mksquashfs4 |
為了最大程度利用空間,一般會使文件系統等于物理分區大小,即創建文件系統時使用分區表劃定的分區大小來創建。
如果不希望硬編碼大小,則可在打包時從分區表獲得大小,再傳給文件系統創建工具,具體的實現可以參考tina/scripts/pack_img.sh 中的make_data_res() 和make_user_res() 等函數。
2.6.1 創建squashfs 鏡像
生成squashfs 的命令,可參考編譯過程的log 得到,或者在網上搜索squashfs 生成方式。 例如在scripts/pack_img.sh 中定義一個函數
function make_user_squash()
{
local SOURCE_DATE_EPOCH=$(${PACK_TOPDIR}/scripts/get_source_date_epoch.sh)
# 這一行指定要打包到文件系統的數據
local USER_PART_FILE_PATH=${PACK_TOPDIR}/target/allwinner/方案名字/user_sq
local USER_PART_SQUASHFS=${PACK_TOPDIR}/out/${PACK_BOARD}/image/user_sq.squashfs
local USER_PART_DOWNLOAD_FILE=${PACK_TOPDIR}/out/${PACK_BOARD}/image/user_sq.fex
cd ${ROOT_DIR}/image
[ -e $USER_PART_FILE_PATH ] && {
#這里用了gzip,需要更高壓縮率可改成xz
${PACK_TOPDIR}/out/host/bin/mksquashfs4 $USER_PART_FILE_PATH $USER_PART_SQUASHFS
-noappend -root-owned -comp gzip -b 256k
-processors 1 -fixed-time $SOURCE_DATE_EPOCH
dd if=${USER_PART_SQUASHFS} of=${USER_PART_DOWNLOAD_FILE} bs=128k conv=sync
}
cd -
}
找個地方調用下即可。 這里不用傳入分區表的原因是,制作squashfs 不需要指定文件系統大小,只讀的文件系統大小完全取決于文件內容。
2.6.2 創建vfat 鏡像
mkfs.vfat <輸出鏡像> -C <文件系統大小>
mcopy -s -v -i <輸出鏡像> <資源文件所在文件夾>/* ::
可參考pack_img.sh(在其中搜索mkfs.vfat 找到相關代碼)。
2.6.3 創建ext4 鏡像
使用tina/out/host/bin/make_ext4fs 創建ext4 鏡像,推薦的使用方法如下:
make_ext4fs -l <文件系統大小> -b <塊大小> -m 0 -j <日志塊個數> <輸出的鏡像保存路徑> <資源文件所在文件
夾>
其中, ? -m 0: 表示不需要要為root 保留空間。 ? -j < 日志塊個數>: 日志總大小為塊大小* 日志塊個數。
例如:
make_ext4fs -l 20m -b 1024 -m 0 -j 1024 ${ROOT_DIR}/img/data.fex ${FILE_PATH}
如果空間不夠大,會顯示類似如下的錯誤日志:
$ ./bin/make_ext4fs -l 10m -b 1024 -m 0 -j 1024 data.fex ./bin
Creating filesystem with parameters:
Size: 10485760
Block size: 1024
Blocks per group: 8192
Inodes per group: 1280
Inode size: 256
Journal blocks: 1024
Label:
Blocks: 10240
Block groups: 2
Reserved blocks: 0
Reserved block group size: 63
error: ext4_allocate_best_fit_partial: failed to allocate 7483 blocks, out of space?
上述錯誤中,資源文件達到100+M,但是創建的鏡像-l 指定的大小只有10M,導致空間不夠而報錯。只需要擴大鏡像大小即可。 如需使用分區大小作為文件系統大小,可參考pack_img.sh(在其中搜索make_ext4fs 找到相關代碼)。
技巧 鏡像大小可以根據分區大小設置,也可以根據資源大小設置,后通過稀疏和resize 處理,即可保證最短燒錄時間和動態匹配分區大小。見稀疏ext4 鏡像和動態resize 章節。
2.6.3.1 稀疏ext4 鏡像
如果資源文件只有10M,但創建了100M 的鏡像文件,導致燒錄100M 的文件拖慢了燒錄速度。此時可以采用稀疏ext4 鏡像。
tina/out/host/bin/img2simg <原鏡像> <輸出鏡像>
稀疏鏡像的原理,類似與把文件系統沒用到的無效數據全刪掉,把文件系統壓縮。可參考pack_img.sh 中的函數sparse_ext4() 的實現與運用。
2.6.3.2 動態resize
如果擔心創建鏡像時指定的大小與實際的分區大小不匹配,可以在設備啟動后執行resize2fs 動態調整文件系統的大小。 例如:
resize2fs /dev/by-name/UDISK
命令后不指定大小,則默認為分區大小。通過這方法可以讓打包鏡像創建的文件系統大小匹配分區大小。 此命令可直接寫入啟動腳本,在掛載前執行。每次啟動都執行一遍不會有不良影響。
2.6.4 創建ubifs 鏡像
使用tina/out/host/bin/make.ubifs 創建ubifs 鏡像,推薦的使用方法如下:
mkfs.ubifs -x <壓縮方式> -b <超級頁大小> -e <邏輯擦除塊大小> -c <最大邏輯擦除塊個數> -r <資源文件所在 文件夾> -o <輸出的鏡像保存路徑> 壓縮方式可選none lzo zlib, 壓縮率zlib > lzo > none 對常見的128MB spinand,1 page = 2048 bytes, 1 block = 64 page, 則 超級頁大小為2048 * 2 = 4096 邏輯擦除塊大小為2048 * 2 * 64 = 262144 最大邏輯擦除塊個數,可簡單設置為一個較大的值,例如128MB / ( 2048 bytes * 2 * 64) = 512 則最終的命令為: mkfs.ubifs -x zlib -b 4096 -e 262144 -c 512 -r ${FILE_PATH} -o ${ROOT_DIR}/img/data_ubifs. fex
2.7 根文件系統改用ubifs
使用suqashfs + overlayfs(ubifs) 方案實現根目錄可寫,但是ubifs 會占用大量的空間存放元數據,造成空間浪費。理論上,UBIFS 可直接作為根文件系統,其穩定性和可壓縮性足夠保證安全和提高空間利用率。
警告 請謹慎使用,UBIFS 作為根文件系統只是理論安全,全志暫無量產方案佐證。
修改步驟如下:
執行cdevice ,修改跳轉目錄下的Makefile 在FEATURES 變量中添加ubifs 和nand
執行make menuconfig 使能在Target Image 頁面下使能ubifs 在Utilities->mtdutils 頁面中使能mtd-utils-mkfs.ubifs
執行cconfigs ,修改跳轉目錄下的env-XXX.cfg 把rootfstype 值改為ubifs 在對應 存儲介質的setargs_XXX 的root 值改為root=ubi0_X ,其中X 表示對應的第幾個分區;刪除 ubi.block 項。
執行make kernel_menuconfig,取消使能overlayfs
在sys_partition.fex 中刪除rootfs_data 分區
2.8 總容量說明
在全志的驅動中,會預留一部分空間存儲特殊數據,因此提供給用戶分區空間不等于實際Flash總容量。
分區表可用空間= flash總容量- 保留空間
不同存儲介質,其保留空間會有差異。
存儲介質 | 保留空間 | 備注 |
---|---|---|
nor | 512K | 對應bootloader 分區,包含分區表,boot0,uboot |
(nftl) nand | 總容量的1/10~1/8 | 注1,注2 |
(UBI) spinand | ||
mmc | 20M | 包含boot0,uboot 等 |
最新spinor 的存儲分布, 隱藏空間1MB,其中mbr 占用16KB,mbr 往前共占用1008KB,uboot 往前共占用64KB,其中包括boot0 和uboot 中間4KB 的預留區域,這段區域用于存放flash 的spi 采樣點等信息。
|boot0|4kb|uboot|mbr |分區表可見的用戶分區|
說明
(nftl) nand 的隱藏空間對用戶不可見,包含分區表MBR 分區,boot0,uboot, 磨損算法、壞塊保留等。對128M 的 spinand 來說,用戶可用空間一般為108M。
由于出廠壞塊的存在,可能會導致每一顆Flash 呈現的用戶可用總容量不同,但全志(nftl) nand 保證總容量不會隨著使 用過程出現壞塊而導致可用容量減少。
UBI 方案中,除了必要的mtd 物理分區之外(boot0/uboot/pstore 等),其余空間劃分到一個mtd 物理分區。在此 mtd 物理分區中根據sys_partition.fex 的劃分構建ubi 卷。UBI 的機制,每個塊都需要預留1~2 個頁作為EC/VID 頭。因此可用容量會小于mtd 物理分區容量。
對于非ubi 方案,用戶空間可通過下面的命令查看用戶可用分區大小,大小單位為KB。
# cat /proc/partitions major minor #blocks name 93 0 112384 nand0 93 1 256 nand0p1 93 2 5120 nand0p2 93 3 10240 nand0p3 93 4 10240 nand0p4 93 5 7168 nand0p5 93 6 64 nand0p6 93 7 512 nand0p7 93 8 256 nand0p8 93 9 76463 nand0p9
如例子中的結果,nand0 分為多個分區,每個nand0px 對應一個分區表中的分區。對于ubi 方案,整個nand 分為若干mtd。可使用以下命令查看
# cat /proc/mtd dev: size erasesize name mtd0: 00100000 00040000 "boot0" mtd1: 00300000 00040000 "uboot" mtd2: 00100000 00040000 "secure_storage" mtd3: 00080000 00040000 "pstore" mtd4: 07a80000 00040000 "sys"
如例子中的結果,整個nand 分為5 個mtd。 ? mtd0 存放boot0, size 1 MB ? mtd1 存放uboot, size 3 MB ? mtd2 存放secure_storage, size 1 MB ? mtd3 存放pstore, size 512 KB ? mtd4 則會進一步分為多個ubi 卷,占用剩余所有空間
以上所有mtd 的size 相加,應該恰好等于flash 總size。分區表中定義的每個邏輯分區,會對應mtd sys 上的ubi 卷。可使用以下命令查看
# ubinfo -a UBI version: 1 Count of UBI devices: 1 UBI control device major/minor: 10:51 Present UBI devices: ubi0 ubi0 Volumes count: 12 Logical eraseblock size: 258048 bytes, 252.0 KiB Total amount of logical eraseblocks: 489 (126185472 bytes, 120.3 MiB) Amount of available logical eraseblocks: 0 (0 bytes) Maximum count of volumes 128 Count of bad physical eraseblocks: 1 Count of reserved physical eraseblocks: 19 Current maximum erase counter value: 3 Minimum input/output unit size: 4096 bytes Character device major/minor: 247:0 Present volumes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 Volume ID: 0 (on ubi0) Type: static Alignment: 1 Size: 1 LEBs (258048 bytes, 252.0 KiB) Data bytes: 258048 bytes (252.0 KiB) State: OK Name: mbr Character device major/minor: 247:1 ----------------------------------- Volume ID: 1 (on ubi0) Type: dynamic Alignment: 1 Size: 2 LEBs (516096 bytes, 504.0 KiB) State: OK Name: boot-resource Character device major/minor: 247:2 ----------------------------------- ... #此處省略若干卷 ----------------------------------- Volume ID: 11 (on ubi0) Type: dynamic Alignment: 1 Size: 242 LEBs (62447616 bytes, 59.6 MiB) State: OK Name: UDISK Character device major/minor: 247:12
如例子中的結果 ? volume 0 為mbr, 占1 LEBs(252 KB),對應分區表本身 ? volume 1 為boot-resource, 占2 LEBs(504 KB),對應分區表中第一個分區 ? … ? volume 11 為UDISK, 占242 LEBs(59.8 MB),對應分區表中最后一個分區 常見的關于容量的疑惑與解答。
問:df 查看UDISK 分區大小,明明分區有50M,怎么顯示總大小只有40+M? 答:df 顯示的是文件系統的大小,文件系統本身需要額外的空間存儲元數據,導致實際可用空間 會比分區大小略少。
問:df 查看boot 分區大小,為什么顯示的大小比實際分區大? 答:boot 分區是通過鏡像燒寫的形式格式化的fs,創建鏡像時設置的文件系統的大小并不等于分 區實際大小,導致此時文件系統大小并不能體現實際分區大小。
問:df 查看squashfs 使用率總是100%? 答:squashfs 是只讀壓縮文件系統,文件系統大小取決于總文件大小,使用率總是100%,跟分 區大小無關。
說明
文件大小 我們常說的文件大小,指的是文件內容有多少字節。但在一個文件系統中,空間分配以塊為單位,必然會造成內部碎片。假 設塊為4K,如果文件大小為1K,文件系統依然為其分配4K 的塊,就會造成3K 的空間浪費。
文件系統大小 文件系統大小,指的是文件系統元數據中標識的可用大小。形象來說,是df 命令或者statfs() 函數反饋的大小。文件系 統大小不一定等于分區大小,既可大于分區大小,也可小于分區大小。
分區大小 在劃分分區時規定的大小,往往是sys_partition.fex 中指定的大小。
2.9 特殊隱藏空間
不管是nor,nand 還是mmc,都需要一些隱藏空間存儲特殊數據,例如boot0/uboot/dtb/sys_config。用戶無法使用這些隱藏空間。 此外,nand 驅動還需要額外的空間以實現磨損平衡、壞塊管理算法,因此nand 的隱藏空間更大。
隱藏空間大小見總容量說明。
3 系統掛載
Tina 目前支持兩種啟動方式,分別是busybox 和procd,不同啟動方式,其自動掛載的配置不同。 此處的自動掛載指開機冷掛載以及熱插拔掛載,其中冷掛載指啟動時掛載,熱掛載指TF/U 盤等插拔設備時的掛載。
3.1 塊設備節點
Tina 中設備節點都在/dev 目錄下,對于不同存儲介質,生成的設備節點會不一樣。
存儲 | 介質設備 | 節點備注 |
---|---|---|
nand | /dev/nand{a,b,c…} | MBR 分區表 |
nand | /dev/nand0p{1,2,3…} | GPT 分區表 |
mmc | /dev/mmcblk0p{1,2,3…} | |
nor | /dev/mtdblock{0,1,2…} | |
TF | 卡/dev/mmcblk{0,1}p{1,2…} | 注1 |
U 盤 | /dev/sda{1,2…} | |
SATA | 硬盤/dev/sda{1,2…} |
說明
若使用mmc 做內部存儲介質,由于mmc 占用了mmcblk0的設備名,此時TF 卡的設備名序號遞增為mmcblk1,否則生 成mmcblk0的設備名。因此配置fstab 時尤其注意TF 設備名是否正確。 對sys_partition.fex 中設置的內部存儲介質的設備節點,會自動動態在/dev/by-name 中創建軟鏈 接。例如:
root@TinaLinux:/# ll /dev/by-name/ drwxr-xr-x 2 root root 220 Mar 1 15:05 . drwxr-xr-x 7 root root 3060 Mar 1 15:05 .. lrwxrwxrwx 1 root root 12 Mar 1 15:05 UDISK -> /dev/nand0p9 lrwxrwxrwx 1 root root 12 Mar 1 15:05 boot -> /dev/nand0p2 lrwxrwxrwx 1 root root 12 Mar 1 15:05 env -> /dev/nand0p1 lrwxrwxrwx 1 root root 12 Mar 1 15:05 misc -> /dev/nand0p6 lrwxrwxrwx 1 root root 12 Mar 1 15:05 private -> /dev/nand0p8 lrwxrwxrwx 1 root root 12 Mar 1 15:05 pstore -> /dev/nand0p7 lrwxrwxrwx 1 root root 12 Mar 1 15:05 recovery -> /dev/nand0p5 lrwxrwxrwx 1 root root 12 Mar 1 15:05 rootfs -> /dev/nand0p3 lrwxrwxrwx 1 root root 12 Mar 1 15:05 rootfs_data -> /dev/nand0p4
因此,在fstab 也可以使用/dev/by-name/XXXX的形式匹配設備。塊設備如果有分區,會形成分區設備節點,以mmc、U 盤為例介紹設備節點名與分區的關系:
設備節點名 | 含義 |
---|---|
/dev/mmcblk0 | 表示整個mmc 空間,包含所有分區 |
/dev/mmcblk0p1 | 表示mmc 中的第1 個分區 |
/dev/mmcblk0p2 | 表示mmc 中的第2 個分區 |
/dev/sda | 表示整個U 盤,包含所有分區 |
/dev/sda1 | 表示U 盤內的第1 個分區 |
/dev/sda2 | 表示U 盤內的第2 個分區 |
熱插拔塊設備分區有以下特殊情況。
塊設備沒有分區 有一些特殊的TF 卡/U 盤沒有分區,而是直接使用整個存儲,表現為只有/dev/mmcblk1 和 /dev/sda ,而沒有分區節點/dev/mmcblk1p1 和/dev/sda1 。此時需要直接掛載整個存儲 設備,Tina 大部分方案都支持這種特殊情況。
塊設備有多個分區 有一些特殊的TF 卡/U 盤被分為多個分區,表現為存在多個/dev/mmcblk1p{1,2…} 和 /dev/sda{1,2…}。默認情況下,Tina 的fstab 配置為只支持掛載熱插拔存儲設備的第一個 分區到/mnt/SDCARD 或者/mnt/exUDISK。
3.2 掛載點
3.2.1 默認掛載設備目錄
Tina 中對常見的分區和熱插拔塊設備,有默認的掛載點。
存儲介質 | 掛載節點 | 設備節點 | 備注 |
---|---|---|---|
nor/nand/mmc | /mnt/UDISK | /dev/by-name/UDISK | 注1 |
TF 卡 | /mnt/SDCARD 或/mnt/extsd | /dev/mmcblk{0,1}p1 | 注2 |
U 盤 | /mnt/exUDISK | /dev/sda1 | 注3 |
SATA 磁盤 | /mnt/exUDISK | /dev/sda1 | 注3 |
說明
/dev/by-name/UDISK 為sys_partition.fex 的UDISK 分區的軟連接。
當無分區時,默認掛載整個TF 卡; 當有1 個或多個分區時,只掛載第一分區。
當無分區時,默認掛載整個設備(/dev/sda),當有1 個或多個分區時,只掛載第一個分區。
3.2.2 新建掛載點
掛載文件系統需要有掛載點。 如果掛載點所在目錄可寫,則在掛載之前先創建目錄即可。
mkdir -p xxx
若掛載點所在目錄為只讀,則需要在制作文件系統時提前創建好。 如創建非空目錄,則在對應方案的base-files 目錄創建。
procd-init: target/allwinner/方案/base-files busybox-init: target/allwinner/方案/busybox-init-base-files
如創建空目錄,由于git 不管理空目錄,因此需在Makefile 中動態創建,可仿照現有Makefile中創建UDISK 目錄的寫法。
procd-init: package/base-files/Makefile busybox-init: package/busybox-init-base-files/Makefile
3.3 procd 啟動下的掛載
procd 啟動時,自動掛載由procd、fstools、fstab 配合完成。如果需要修改冷/熱掛載規則,只需要修改fstab 配置文件即可。 SDK 中,配置文件位于:
tina/target/allwinner/<方案名>/base-files/etc
若只是調試或臨時修改掛載規則,只需要修改小機端的配置文件:
/etc/config/fstab
3.3.1 fstab 編寫格式
fstab 由多個config 組成,每個config 的基本格式示例如下:
config ‘xxxx’ option xxxx ‘xx’ option xxxx ‘xx’ option xxxx ‘xx’
config 有3 種類型,分別是mount|global|swap 。Tina SDK 中沒使用swap,在本文中不做介紹。
3.3.2 global 類型config
global 類型的config 是全局配置,示例如下。
config 'global' option anon_swap '0' option anon_mount '0' option auto_swap '1' option auto_mount '1' option delay_root '5' option check_fs '1'
配置項的意義如下表:
配置名稱 | 可選值 | 意義 |
---|---|---|
anon_mount | 0/1 | 注1 |
anon_swap | 0/1 | swap 使用,此處省略 |
auto_mount | 0/1 | 只適用于設置熱插拔是否自動掛載塊設備 |
auto_swap | 0/1 | swap 使用,此處忽略 |
check_fs | 0/1 | 建議配置為1,注2 |
delay_root | 1,2,3… | 注3 |
說明
anon_mount: 當fstab 中無匹配要掛載設備的uuid/label/device 屬性的配置節時, 是否采用默認掛載為 /mnt/“$device-name”。
check_fs: 是否在掛載前用/usr/sbin/e2fsck 檢查文件系統一致性(只適用于ext 系統)。
delay_root: 對應fstab 中target 為”/” 或”/overlay” 的設備節點不存在時,最長等待delay_root 秒。
3.3.3 mount 類型config
mount 類型的config 是具體的設備掛載配置,示例如下
config 'mount' option target '/mnt/UDISK' option device '/dev/by-name/UDISK' option options 'rw,sync' option enabled '1'
配置項的意義如下表:
配置名稱 | 意義 | 備注 |
---|---|---|
target | 掛載點 | 必須是絕對路徑,必須有效 |
device | 設備名 | 通過設備名指定待掛載的設備,注1 |
uuid | 設備UUID | 通過fs 的UUID 指定待掛載的設備,注1 |
label | 設備label | 通過fs 的label 指定待掛載的設備,注1 |
enabled | 是否使能 | 該節點是否有效(0/1) |
options | 掛載屬性 | 例如只讀掛載等,注2 |
device/uuid/label 是匹配掛載的設備,三者中至少要有一個有效。
默認掛載支持的屬性如下表:
配置名稱 | 意義 | 缺省值 |
---|---|---|
ro / rw | 只讀/ 可讀寫 | rw |
nosuid / suid | 忽略suid/sgid 的文件屬性 | suid |
nodev / dev | 不允許/允許訪問設備文件 | dev |
noexec / exec | 不允許/允許執行程序 | exec |
sync / async | 同步/異步寫入 | async |
mand / nomand | 允許/不允許強制鎖 | nomand |
irsync | 同步更新文件夾 | 無效 |
noatime / atime | 不更新/更新訪問時間(atime) | atime |
nodiratime / diratime | 不更新/更新目錄訪問時間(atime) | diratime |
relatime / norelatime | 允許/不允許根據ctime/mtime 更新actime n | orelatime |
strictatime | 禁止根據內核行為來更新atime, 但允許用戶空間修改 | 無效 |
3.4 busybox 啟動下的掛載
busybox 啟動時,通過pseudo_init 和rcS 完成大部分默認的掛載工作。
存儲節點 | 掛載路徑 | 用途 |
---|---|---|
/dev/by-name/UDISK | /mnt/UDISK | 用戶數據 |
/dev/by-name/rootfs_data | /overlay | 作為overlay 使得rootfs 可寫 |
/dev/mmcblk{0,1}p1 | /mnt/SDCARD 或/mnt/extsd | TF 卡 |
/dev/sda1 | /mnt/exUDISK | U 盤 |
busybox 啟動使用默認掛載配置即可,如果需要修改,需要自行修改腳本。
tina/package/busybox-init-base-files/busybox-init-base-files/usr/bin/hotplug.sh
3.5 掛載文件系統
在分區表中增加的分區默認是空分區,如需掛載成文件系統使用,則首先需要在分區中寫入一個文件系統。 方式一,在PC 端預先生成好一個文件系統,并在分區表中指定為download_file,則啟動后可直接掛載。例如rootfs 分區就是在PC 端制作好文件系統,燒錄時寫入rootfs 分區。 方式二,在小機端進行格式化。例如UDISK 分區就是在第一次啟動時,由啟動腳本進行格式化。客戶可自行在某一啟動腳本或應用中調用格式化工具(mkfs.xxx)進行格式化。如需參考,可仿照UDISK 分區的格式化:
procd-init: package/base-files/files/lib/preinit/79_format_partition busybox-init: package/busybox-init-base-files/files/pseudo_init
3.5.1 注意事項
一些格式化工具并未默認選中,需要時請自行在make menuconfig 界面配置。部分文件系統對分區大小有最低要求,如ext4,ubifs,如果在小機端調用格式化分區時報錯,可根據報錯信息提示增大分區。 對于private 分區默認為空,使用DragonSN 工具寫號后,則為vfat 格式的文件系統。對于ubi 方案來說,如果需要使用基于塊設備的文件系統,則需要在ubi 之上模擬塊設備。在用戶空間可調用ubiblock 工具完成,注意這樣模擬出的塊設備是只讀的,如需可寫建議直接使用 ubifs。
詳見后文ubi 方案特殊說明。
4 文件系統支持情況
存儲介質 | jffs2 | squashfs | ext4 | vfat | ntfs | exfat | ubifs |
---|---|---|---|---|---|---|---|
(NFTL) nand | N | Y | Y | Y | Y | N | N |
(UBI) spinand | N | Y | Y(ro) | Y(ro) | Y(ro) | N | Y |
mmc | N | Y | Y | Y | Y | N | N |
nor | Y | Y | N | N | N | N | N |
TF 卡 | N | N | Y | Y | Y | N | N |
U 盤 | N | N | Y | Y | Y | N | N |
說明
(ro) 表示只能實現只讀: ubi 卷可通過模擬塊設備,實現塊文件系統的讀,但不支持寫。
vfat(fat32)使用內核原生的支持,exfat 需要在Linux-5.7 后社區才正式支持,因此此處標注為不支持。
ntfs 依賴于第三方工具ntfs-3g。
TF 卡/U 盤等,建議使用vfat 實現Window/Linux/MacOS 的最大兼容參考文章《多平臺大型文件系統比較》。
vfat/ntfs/exfat 等Window 文件系統,不建議用做嵌入式存儲,除非您能保證其掉電安全和移植文件系統修復工具。
警告 關于文件系統的選擇,有以下幾點需要注意:
全志NFTL nand 可使用塊文件系統(ext4) 全志在驅動中實現磨損平衡和壞塊管理,向上呈現為塊設 備。因此可支持ext4,不需要且不支持常見的flash 文件系統(jffs2/yaffs/ubifs 等)。
為了保證掉電不變磚,根文件系統務必只讀(squashfs),或者ext4 掛載為ro 模式。
ext4/ubifs 等文件系統分區大小必須足夠大,以確保能正確創建日志塊,否則有掉電變磚風險分區大小 請參考章節分區大小與對齊。
4.1 ext4 與日志
4.1.1 ext4 的日志
與服務器等長期穩定供電的情況不同,嵌入式設備隨時有掉電的可能。不管在任意時間掉電,文件系統都需要保持一致性,換句話說,保證文件不會因為掉電丟失。如果文件系統只讀,則不需要日志。日志只是確保寫的安全。
說明 什么是文件系統的一致性? 文件系統元數據塊記錄了有什么文件,數據塊則保存了實際的文件內容。一致性則表示,元數據塊記錄了存在某個文件,必定存 在對應的數據塊,換句話說,就是保證元數據和數據的一致。 如果出現,元數據記錄文件A 存在,但文件A 的數據塊是無效的,或者明明數據塊是有效的,但元數據并沒任何記錄,導致系 統并不知道文件存在,就出現了文件系統的不一致。
警告 保證文件不丟失,只保證之前寫入的文件數據正常,而非正在寫,且因為掉電導致沒寫完整的文件。對大多數文 件系統而言,更多時候會直接丟棄這沒寫完整的文件以保證一致性。
ext4 通過日志的形式保證文件系統一致性。其支持3 種日志模式:
日志模式 | 原理 | 特點 |
---|---|---|
journal | 元數據與數據都寫入日志 | 最安全,但性能最慢 |
writeback | 只有元數據寫入日志,但不保證數據先落盤 | 性能最快,但最不安全 |
ordered | 只有元數據寫入日志,且保證數據先落盤,元數據后落盤 | 折中,默認方案 |
考慮安全和性能的折中,建議使用ordered 的日志模式。系統默認使用的就是ordered 模式。我們在mount 命令中顯示的掛載參數可顯示使用的哪種日志。
$mount /dev/by-name/UDISK on /mnt/UDISK type ext4 (rw,....,data=ordered)
4.1.2 分區大小與日志
有時候分區太小,系統會默認把日志功能關閉。可以通過以下方法判斷:
$dumpe2fs <分區or 鏡像文件> ... Filesystem features: has_journal ... ... Journal backup: inode blocks Journal features: (none) 日志大小: 1024k Journal length: 1024 Journal sequence: 0x00000001 Journal start: 0 ...
在Filesystem features 中有has_journal 的標志表示支持日志。在Jorunal 片段中也詳細描述了日志塊的大小等信息。 如果創建的文件系統沒有日志,對大多數用戶而言,擴大分區大小是最簡單的做法。專業的做法可以通過縮小塊大小,取消預留塊等方式為日志騰挪出空間。 按以往經驗,對小容量(<100M) 的存儲而言,在資源文件之外預留3-5M 的空間用于文件系統的元數據即可。
4.1.3 修復ext4
ext4 文件系統每次重啟后,建議都進行一次修復,確保文件系統穩定。 修復可以參考以下命令:
e2fsck -y <分區>
4.1.4 修復fat
TF 卡掛載fat 文件系統,fat 文件系統不是日志型文件系統,在掉電、帶電插拔等場景下不能保證文件系統數據的安全,所以建議啟動都進行一次修復。修復可以參考以下命令:
fsck_msdos -pfS /dev/mmcblk0p1
如章節global 類型config中描述,如果使用procd 引導啟動,在fstab 中使能check_fs,也可實現在掛載前自動修復。
5 UBI VS. NFTL
對nand 存儲介質,全志有兩套解決方案,分別是NFTL spi/raw nand 和UBI spi nand。UBI 存儲方案常用于小容量spinand,其實現原理跟NFTL 存儲方案完全不同。
5.1 NFTL Nand
這是全志實現的不開源的Nand 驅動,NFTL 全稱為NAND Flash Translation Layer,其可實現屏蔽Nand 的特性,對上呈現為塊設備。 我們常見的mmc 設備也是塊設備,可以簡單理解為,MMC = Nand Flash + 控制器+NFTL。所以通過全志的NFTL nand 驅動后,我們可以像mmc 設備一樣,以塊設備操作Nand。 例如,上層可以直接裸讀寫塊設備,常見的ota 更新也是基于這樣的實現:
dd if=boot.fex of=/dev/by-name/boot
技巧
詳細的OTA 方法,請參見OTA 相關文檔。
全志的NFTL Nand 驅動中,預留一部分空間做算法和關鍵數據保存。預留空間大致為1/10 ~1/8 的可用空間。這里的可用空間是指剔除出廠壞塊之外的空間。由于每一顆Flash 的出廠壞塊數量不盡相同,因此最終呈現給用戶的可用空間不盡相同。用戶也不需要擔心使用過程中出現的壞塊導致用戶可用空間變小,在算法實現中,使用壞塊會體現在預留空間而不是用戶空間。 此外,Nand 的磨損平衡、壞塊管理等特性全由NFTL 驅動實現。換句話說,驅動保證用戶數據的穩定,用戶可將其按塊設備使用。
5.2 UBI (spi) Nand
當前UBI 方案僅適用于小容量spinand。 UBI 方案是社區普遍使用的Flash 存儲方案,其構建在mtd 設備之上,由UBI 子系統屏蔽Nand 特性,對接UBIFS 文件系統。其層次結構由上往下大致如下:
層次 | 層級 | 功能 |
---|---|---|
0 (最上層) | UBIFS | ubifs 文件系統 |
1 UBI | 子系統 | Nand 特性管理 |
2 | MTD 子系統 | 封裝Flash,向上提供統一接口 |
3 (最下層) | Flash | 具體的Flash 驅動 |
我們把MTD 分區稱為物理分區,把UBI 卷(分區) 成為邏輯分區,因為 ? MTD 分區是按Flash 的物理地址區間劃分分區 ? UBI 卷(分區) 是動態映射的區間 全志的UBI 方案中,創建了這些MTD 物理分區:
分區名 | 大小 | 作用 |
---|---|---|
boot0 | 4/8 個物理塊 | 存放boot0 |
uboot | 4/20M | 存放uboot |
secure storage | 8 個物理塊 | 存放關鍵數據 |
pstore | 512K | 奔潰日志轉存 |
sys | 剩余空間 | 提供給ubi 子系統劃分邏輯分區 |
驅動會在sys 的MTD 物理分區上根據sys_partition.fex構建UBI 邏輯分區(卷)。 UBI 設備向上呈現為字符設備,無法直接使用諸如ext4 這樣基于塊設備的文件系統。但UBI 子系統支持模擬只讀的塊設備,即把UBI 邏輯卷模擬成只讀的塊設備。基于此,可以做到根文件系統依然使用squashfs 這樣的塊文件系統。 社區為UBI 設備專門設計了ubifs 文件系統。經過驗證,其配合UBI 子系統可保證數據掉電安全以及提供通用文件系統所有功能,甚至還提供文件系統壓縮功能。 除此之外,UBI 設備更新(OTA 更新)也不能直接裸寫設備,需要通過ubiupdateval 命令更新。 技巧:詳細的OTA 方法,請參見OTA 相關文檔。
5.3 ubi 相關工具
5.3.1 ubinfo
輸出指定ubi 設備信息。 例子:
ubinfo /dev/by-name/rootfs #查看rootfs卷的信息 ubinfo -a #查看所有卷的信息
可參考總容量說明
5.3.2 ubiupdatevol
更新指定卷上的數據。 例子:
ubiupdatevol -t /dev/by-name/boot #清除boot卷的數據 ubiupdatevol /dev/by-name/boot /tmp/boot.img #將/tmp/boot.img寫到boot卷,卷上原有數據會完全丟失
可參考總容量說明
可參考模擬塊設備
5.3.3 ubiblock
基于一個ubi 卷,生成模擬的只讀塊設備 例子:
ubiblock -c /dev/by-name/test #將test卷生成一個塊設備節點
可參考模擬塊設備
5.3.4 其他
在tina 方案上,燒錄固件時已經完成mtd 和ubi 卷的創建,啟動時自動attach 并掛載對應的分區,無需再自行處理。因此以下命令一般不會用到。 ubiformat: 將裸mtd 格式化成ubi ubiattach: 將mtd 關聯到ubi ubidetach: 將ubi 與mtd 解除關聯ubimkvol: 創建ubi 卷 ubirmvol: 移除ubi 卷
6 rootfs_data 及UDISK
6.1 overlayfs 簡介
Tina 默認根文件系統格式使用squashfs 格式,這是一種只讀壓縮的文件系統。很多應用則需要文件系統可寫,特別是/etc 等存放較多配置文件的目錄,為了滿足可寫的需求,Tina 默認使用overlayfs 技術。overlayfs 是一種堆疊文件系統,可以將底層文件系統和頂層文件系統的目錄進行合并呈現。
6.2 使用rootfs_data 作為overlayfs
Tina 常用的方式是專門劃分一個rootfs_data 分區, 先格式化成可寫的文件系統(如ext4/ubifs), 再進一步掛載為overyfs, 成為新的根, 讓上層應用認為rootfs 是可寫的。 rootfs_data 分區的大小就決定了應用能修改多少文件。具體原理和細節請參考網上公開資料,此處僅舉簡單例子輔助理解。
底層(即rootfs 分區的文件系統)不存在文件A,應用創建A,則A 只存在于上層(即 rootfs_data 分區)。
底層存在文件B,應用刪除B,則B 仍然存在于底層,但上層會創建一個特殊文件屏蔽掉,導 致對應用來說B 就看不到了,起到刪除的效果。
底層存在文件C,上層修改C,則C 會先被整個拷貝到上層,C 本身多大就需占用多大的上 層空間,在這個基礎上應用對上層的C 進行修改。 基于以上理解,可按需配置rootfs_data 的大小。一般開發期間會配置得較大,量產時可減小 (考慮實際只會修改少量配置文件)甚至去除(需要確認所有應用均不依賴rootfs 可寫)。
6.3 使用UDISK 作為overlayfs
如果希望overlayfs 的空間盡可能較大,也可考慮直接使用UDISK 分區作為上層文件系統空間。 可將target/allwinner/xxx/base-files/etc/config/fstab 中的rootfs_data 分區及UDISK 分區的掛載配置disable 掉。
config 'mount' option target '/overlay' option device '/dev/by-name/rootfs_data' option options 'rw,sync,noatime' option enabled '0' #此行改成0 config 'mount' option target '/mnt/UDISK' option device '/dev/by-name/UDISK' option options 'rw,async,noatime' option enabled '0'
再新增一個配置,將UDISK 直接掛載到/overlay 目錄。
config 'mount' option target '/overlay' option device '/dev/by-name/UDISK' option options 'rw,sync,noatime' option enabled '1'
6.4 如何清空rootfs_data 和UDISK
出于恢復出廠設置或其他需要,有時需要清空rootfs_data 和UDISK。 一般不建議在文件系統仍處于掛載狀態時直接操作對應的底層分區,因此建議需要清空時,不要直接操作對應塊設備,而是先設置標志并重啟,再在掛載對應分區前的啟動腳本中檢測到對應標志后,對分區進行重新格式化。 當前79_format_partition 中實現了一個clean_parts 功能, 會檢測env 分區中的parts_clean 變量并清空對應分區的頭部。清空后,rootfs_data 和UDISK 分區會自動重新觸發格式化。
# to clean rootfs_data and UDISK, please run fw_setenv parts_clean rootfs_data:UDISK reboot
具體實現請查看
package/base-files/files/lib/preinit/79_format_partition
7 關鍵數據保護
設備上保存的一些關鍵的數據,例如mac,SN 號等,一般要求在重新刷機時不丟失。以下介紹刷機數據不丟失的解決方案。
7.1 邏輯分區保護方案
7.1.1 分區設置
此處的邏輯分區,是指在分區表(sys_partition.fex/sys_partition_nor.fex) 中定義的分區。名字為private 的分區會特殊處理,默認刷機數據不丟失。 其他名字的分區,如果指定keydata=0x8000 屬性,則刷機數據不丟失。對于private 分區或設置了keydata=0x8000 屬性的分區,請勿設置downloadfile。
7.1.2 實現原理
對private 分區(配置了keydata=0x8000 屬性同理) 保護的方式是,擦除之前先申請一片內存,然后根據flash 中的舊分區表,讀出private 分區內容。 接著進行擦除,然后再按照新的分區表,將private 分區內容寫回flash 上新分區所在位置。
7.1.3 常見用法
使用全志的DragonSN 工具,選擇私有key 模式,將key 寫入private 分區。寫入后private分區默認會是一個vfat 文件系統,啟動后掛載/dev/by-name/private,即可讀出key。DragonSN 的具體用法請參考工具自帶文檔。
不使用DragonSN 工具, 由應用自行負責寫入數據和讀出數據, 直接在用戶空間操作/dev/by-name/private 節點即可。量產時可自行開發PC 端工具,通過adb 命令來完成key 的寫入。
7.1.4 ubi 方案特殊說明
7.1.4.1 模擬塊設備
對于nand nftl 方案,emmc 方案,nor 方案,邏輯分區是對應到一個塊設備,即對于private分區,可以直接讀寫/dev/by-name/private 節點,也可以借助DragonSN 工具制作成一個vfat文件系統,再掛載使用,掛載后文件系統是可讀寫的。 但對于nand ubi 方案,邏輯分區是對應到ubi 卷,由于ubi 的特性,無法再直接寫數據到/dev/by-name/private 節點,需要通過ubiupdatevol 工具來更新卷,或者自行在應用中按照ubi 卷更新步驟操作。 當基于ubi 卷構建vfat 文件系統時,需要先基于ubi 卷模擬塊設備,且掛載上的vfat 文件系統是只讀的。操作示例如下。
#查看private分區對應的ubi節點 root@TinaLinux:/# ll /dev/by-name/private lrwxrwxrwx 1 root root 11 Jan 1 00:00 /dev/by-name/private -> /dev/ ubi0_4 #創建模擬的塊設備 root@TinaLinux:/# ubiblock -c /dev/ubi0_4 block ubiblock0_4: created from ubi0:4(private) #掛載 root@TinaLinux:/# mkdir /tmp/private root@TinaLinux:/# mount -t vfat /dev/ubiblock0_4 /tmp/private/ #可以讀取內容 root@TinaLinux:/# ls /tmp/private/ ULI magic.bin #查看掛載情況,為ro root@TinaLinux:/# mount | grep private /dev/ubiblock0_4 on /tmp/private type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437, iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
7.1.4.2 在設備端制作vfat 鏡像
由于ubifs 需占用17 個LEB,比較占空間,對于只在工廠一次性寫入信息,后續只讀的場景,一種可考慮的方案是使用vfat 文件系統。 首先選上kernel 的loopback 支持:
make kernel_menuconfig 選上Device Drivers --> [*] Block Devices --> <*>Loopback device support
分區表中建立分區,假設為test 分區隨后可以在小機端準備一個vfat 鏡像:
dd if=/dev/zero of=/mnt/UDISK/test.img bs=1M count=1 mkfs.vfat /mnt/UDISK/test.img mkdir -p /tmp/test mount /mnt/UDISK/test.img /tmp/test 此時可向/tmp/test 寫入文件 umount /tmp/test
將鏡像寫入卷中:
ubiupdatevol /dev/by-name/test /mnt/UDISK/test
后續按上文介紹的方法,使用模擬塊設備掛載,注意使用模擬塊設備掛載后就是只讀的了。
7.1.5 可能造成數據丟失的情況
出現以下情況,會導致private 分區數據丟失。
配置了強制擦除,例如sys_config.fex 中配置了eraseflag = 0x11。
無法讀取flash 上的分區表或private 分區。這個可能的原因包括flash 上的數據被破壞了 等。
新的分區表不包含private 分區。
在燒錄過程中掉電。如上所述,燒錄時是讀出-> 擦除-> 寫回,在擦除之后,寫回之前掉電,則數據丟失。 檢測到private 分區,開始執行保護private 分區的代碼,但執行過程中出錯,如malloc 失敗,private 無法讀取等,則會導致燒錄失敗。出現malloc 失敗問題一般是因為板子上燒錄了Android固件。因為安卓的private 分區比較大,而tina 的uboot 分配給malloc 的空間比較小。 這個時候,需要打包一份不保護private 分區的tina 固件先進行一次燒錄,即可解決問題。具體的:將sys_config.fex 的eraseflag 改為0x11,強制擦除。或者臨時移除sys_partition.fex中的private 分區。
7.2 物理區域保護方案
另一種保護數據不丟失的思路是,在flash 上劃定一塊物理區域,燒錄時默認不擦除。在Tina 上實現的secure storage 區域即具有這種特性。secure storage 區域用于保存key,可代替private 分區,理論上更為安全(被燒錄時誤擦除和被別的應用誤寫的可能性較低)。
7.2.1 nand nftl 方案實現
nand nftl 方案中,預留了一塊物理區域,用于secure storage。這塊區域不是邏輯分區,用戶空間不可見。燒錄時不會擦除這塊區域。在用戶空間讀寫secure storage 需要使用ioctl,由內核nand 驅動來協助完成。
7.2.2 nand ubi 方案實現
nand ubi 方案中,預留了一塊物理區域,用于secure storage,對上表現為一個mtd 分區。用戶空間可見。燒錄時不會擦除這塊區域。在用戶空間讀寫secure storage 需要使用ioctl,由內核來協助完成。理論上也可以直接讀寫mtd 設備節點,但不推薦,使用這種方式應用需要自行處理壞塊等問題。
7.2.3 emmc 方案實現
預留了一塊物理區域,默認是偏移6M-6.25M 的區域,作為secure storage。在用戶空間讀寫,可以直接通過mmcblk0 節點讀寫指定偏移。
7.2.4 nor 方案實現
暫未實現。
7.2.5 常見用法
使用全志的DragonSN 工具,選擇安全key 模式,將key 寫入secure storage 區域。啟動后在用戶空間調用庫讀出key。DragonSN 的具體用法請參考工具自帶文檔。
不使用DragonSN 工具,由應用自行在用戶空間調用庫寫入數據和讀出數據。量產時可自行開發PC 端工具,通過adb 命令來完成key 的寫入。
7.2.6 secure storage 格式
secure storage 有預設的格式,簡單總結如下 ? secure storage 總大小為256KB,因為有備份,所以實際能用128KB。 ? 128KB 分為32 個item, 即每個item 是4KB。 ? item0 用作secure_sotrage_map,所以用戶能用的實際為31 個item。 ? 每個item 內部為鍵值對的格式,包含CRC 校驗,其中用戶可存儲的key 長度最多為3KB。 ? secure_storage_map 中是以“name:length” 的格式保存所有item 的信息,所以所有item的“name:length” 字符串長度總和不能超過secure_storage_map 中data 的長度。一般而言,31 個3KB 的key 可以滿足需求,如果無法滿足,例如需要更多數量的key,則一種解決方式是上層應用自行將多個key 拼接起來,只要總大小不超過3KB 即可當成一個key 寫入 secure storage。讀出時應用自行反向解析出目標key 即可。
7.2.7 在uboot 中讀寫
基于以上介紹的格式,uboot 中封裝了pst 命令。
pst - read data from secure storageerase flag in secure storage Usage: pst pst read|erase [name] pst read, then dump all data pst read name, then dump the dedicate data pst write name, string, write the name = string pst erase, then erase all secure storage data pst erase key_burned_flag, then erase the dedicate data
7.2.8 在用戶空間讀寫
Tina 提供了讀寫庫。
make menuconfig 選中Allwinner --> <*> libsec_key --> [*] Enable secure storage key support
如果選上demo,則會編譯出demo 程序sec_key_test。
root@TinaLinux:/# sec_key_test -h -w : write key to sst and private -r : read key from sst or private -t 0: write some key to secure storage -t 1: repetitve read + verify some key from secure storage -t 2: repetitve write + verify some key from secure storage -t 3: verify some key from secure storage -t 4: write some key to private -t 5: repetitve read + verify some key from private -t 6: repetitve write + verify some key from private -t 7: verify some key from private -l : list -d : printf hex -h : help
更詳細的使用方式請參考:
tina/package/allwinner/libkey/readme.txt
7.3 secure storage 區域與private 分區比較
刷機不丟失的特性: ? private 分區每次刷機,是先讀出到dram,擦除flash,再寫入flash。刷機中途掉電可能丟失 ? secure storage 則是刷機過程完全不會擦除。理論上secure storage 的數據更安全。
用戶空間誤操作的可能: ? private 分區可以用常規分區更新命令清除掉。 ? secure storage 需要通過ioctl 專用接口訪問。
數據格式: ? private 分區可以裸分區讀寫,也可以格式化成文件系統。 ? secure storage 已限制為鍵值對,key 的長度也有限制。
存放位置: ? private 分區大小由分區表配置,是一個可見的普通分區。 ? secure storage 是flash 上的保留區域,大小固定,分區表中不可見。
? private 分區沒有備份,請避免寫入時掉電。或者自行在private 分區中構建備份。 ? secure storage 默認是雙備份。
在uboot 訪問: ? private 分區,uboot 通過通用的讀寫flash 接口或文件系統接口訪問,取決于數據格式。 ? sectre storage 區域,有固定格式,通過uboot 提供的secure storage 專用接口訪問。
校驗: ? private 分區如果是裸數據,是否校驗由應用自行處理。如果是文件系統,則由文件系統特性決定。 ? secure storage 格式中帶了crc 校驗。
-
存儲
+關注
關注
13文章
4265瀏覽量
85675 -
Linux
+關注
關注
87文章
11230瀏覽量
208933 -
開發指南
+關注
關注
0文章
34瀏覽量
7531 -
Tina
+關注
關注
2文章
45瀏覽量
16957
發布評論請先 登錄
相關推薦
評論