Porting NAND flash 實作中的相關知識筆記

前言

會在此文章中看到以下紀錄

  1. 在工作時有碰到 nand flash 相關問題的處理方式
  2. 順道了解 nand flash 在 embedded linux platform 的運作方式
  3. nand flash 的基本知識

以下資料,由些從公司智庫取得,有些是從網路文章、書籍等取得

Nand flash 的基本知識

flash 的種類

在公司主要提到的是 NAND flash 以及 NOR flash

  • NOR flash
    • Intel 於 1988 年發表
    • 支援隨機存取,讀資料的方式跟 RAM 接近,給 address,data 就能讀出
    • NOR 的特點是原地執行 (XIP, eXecute In Place),這樣應用程序可以直接在 flash memory 內運行,不必再把資料讀到系統 RAM 中
    • 每次寫入 / 擦除都是以 1 block 為單位; 1 block = 16~128 KBytes
    • 小容量 (1~4MB) 時具有很高的成本效益,但是很低的寫入和擦除速度大大影響了它的性能
    • NOR flash 佔據了容量為 1~16MB 閃存市場的大部分,因隨機存取快,應用在手機中
    • NOR的擦寫週期壽命是一萬~十萬次
    • 適合用於儲存不需經常更新的程式,例如 BIOS 或韌體
  • NAND flash
    • Toshiba 於 1989 年發表
    • 適用於大容量,更低的寫入和擦除時間,高密度 (單元尺寸是 NOR Flash 的一半),高壽命 (10倍左右),低製造成本
    • I/O pin 只有 8 個,只允許連續讀取,所以不適合用於電腦主記憶體 (不支援隨機存取)
    • 讀寫操作以 1 page 為單位,擦除 (Erase) 以 1 block 為單位
    • 1 block = 32 pages; 每個 block 的單位依照廠商製造的不同有區別,介於 8~32 KBytes 之間
    • NAND 擦除單元更小,因此擦除速度 (4ms) 比NOR的 (5s) 快
    • 適合於資料儲存,例如:MMC、固態硬碟 (SSD)、USB 3.0 隨身碟、手機、數位相機
    • 甚至手機、MP3 撥放器用 NAND Flash 當作存放多媒體檔案的媒介,原因在於成本、空間、還有寫入資料的速度
    • NAND 閃存中每個區塊的最大擦寫次數是一百萬次

NAND flash v.s NOR flash

比較項目 NAND flash NOR flash
讀取速度 middle fast
寫入速度 fast slow
擦除速度 fast slow
容量 large small
成本 low high
市佔率 upper lower


source: http://cmchao.logdown.com/posts/60216

相關專有名詞

  • Page
    Page 乃 nand flash 讀取時的最小單位 ,目前常見的 page size 為 2k bytes,視產品設計與製程技術等等而定
  • Spare
    Spare 是每個 page 後面都會接一段額外的容量去儲存此 page 相關的資訊,通常會存 ECC,完成 bit correction 的目的
  • OOB (out of boundary)
    就是 Spare,我們也比較常用這個說法
  • Small page / Large page
    大於等於 2k bytes page 就是 large,相對都是 small page
  • Block
    Block 是 寫入時的最小單位 ,理論上是 64 page 為一個 block,依容量也會決定一顆 nand flash 之中會有多少個 block

how to read write

  • nand flash 主要都是以 page/block 來當作讀/寫 的最小單位
  • 由於物理性質,write 的時候「只能從1寫成0」
  • 所以由上述,假設你要寫入一個數值,要從原本的 0 寫成 1,就一定要先 erase block
  • erase block 之後再將數值復原

所以平常 write 的動作如下

  1. read a hole block in to RAM (DDR)
  2. change RAM data
  3. erase block
  4. write data from ram into block (program)

read 就是讀取一個 page,無太多限制

Life cycle

主要分成 Endurance 以及 Retention

  • Endurance: Erase block 是一個不可逆的動作,會使得 nand flash 的寫入次數下降,通常為 1k-100k 次
  • Retention: 當資料放到 nand 中,可以保證保留資料的時間,一般來說是 10 years

Bad block

就是 chip 之中有可以讀取後,會無法還原成原本數值的 block,會分成:

  1. factory-bad: 指的是出廠就已經出現問題的 bad block
  2. worn-out: 即使用多次 erase 後導致的 bad block

ECC / OOB

ECC 就是所謂的 error correction code,每次 read 的時候,都需要透過每個 page 中的 spare (oob) 來進行校正檢查,一般用的檢查有三種

  • 漢明碼(Hamming code)
  • Reed-Solomon
  • Binary BCH8

BBT

BBT 就是 bad block table,之後 bbt 有 scan 到新的 bad block information 都會記在此

Porting and test nand flash on embedded linux platform

U-boot

nand read / nand write

Kernel

Porting drivers

Define nand flash partition (MTD)

https://redmine.internal.ihmi.net/issues/23609

What is MTD?

Problem: Get oops while ramdisk while running flash_eraseall

flash_eraseall is a busybox open source code and show at: https://github.com/brgl/busybox/blob/master/miscutils/flash_eraseall.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
[root@freescale root]# ll /usr/bin/flash_eraseall
-rwxrwxr-x 1 messageb messageb 13684 Mar 28 2017 /usr/bin/flash_eraseall
[root@freescale root]# ll /usr/bin/kobs-ng
-rwxrwxr-x 1 messageb messageb 675508 Mar 28 2017 /usr/bin/kobs-ng
[root@freescale root]# cp /usr/bin/flash_eraseall /tmp/
[root@freescale root]# cp /usr/bin/kobs-ng /tmp/
[root@freescale root]# ll /tmp/
-rw-r--r-- 1 root root 16549 Jan 1 00:00 Xorg.0.log
-rw-r--r-- 1 root root 20 Jan 1 00:00 agent.pid
drwxr-xr-x 2 root root 80 Jan 1 00:00 dbus
drwxr-xr-x 4 root root 80 Jan 1 00:00 extend
-rw-r--r-- 1 root root 0 Jan 1 00:00 flag_mount
-rwxr-xr-x 1 root root 13684 Jan 1 00:01 flash_eraseall
-rw-r--r-- 1 root root 4 Jan 1 00:00 inetd.pid
-rwxr-xr-x 1 root root 675508 Jan 1 00:01 kobs-ng
prw-rw-rw- 1 root root 0 Jan 1 00:00 msg
-rw-r--r-- 1 root root 4 Jan 1 00:00 pure-ftpd.pid
-rw-r--r-- 1 root root 4 Jan 1 00:00 sshd.pid
-rw-r--r-- 1 root root 20 Jan 1 00:00 sysmsg.pid
-rw-r--r-- 1 root root 9 Jan 1 00:00 usbpath
-rw-r--r-- 1 root root 0 Jan 1 00:00 utmp
-rw-r--r-- 1 root root 20 Jan 1 00:00 xvkbd.pid
[ 187.747631] mtd_ioctl 80044d19, arg 1
[ 187.751320] gpmi_nand_switch_ecc: HW ECC selected
[ 187.758934] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read only 1242 bytes, retry
[ 187.771352] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read only 1242 bytes, retry
[ 187.783642] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read only 1242 bytes, retry
[ 187.795939] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read 1242 bytes
[ 187.806681] CPU: 0 PID: 300 Comm: sh Tainted: G O 4.1.15+ #236
[ 187.813649] Hardware name: Freescale i.MX6 Ultralite (Device Tree)
[ 187.819898] [<8001314c>] (unwind_backtrace) from [<80011294>] (show_stack+0x10/0x14)
[ 187.827704] [<80011294>] (show_stack) from [<801cf230>] (ubi_io_read+0x1e0/0x2b8)
[ 187.835305] [<801cf230>] (ubi_io_read) from [<801cd0ac>] (ubi_eba_read_leb+0x254/0x35c)
[ 187.843334] [<801cd0ac>] (ubi_eba_read_leb) from [<801cc02c>] (ubi_leb_read+0x68/0xb8)
[ 187.851375] [<801cc02c>] (ubi_leb_read) from [<80118890>] (ubifs_leb_read+0x2c/0x90)
[ 187.859182] [<80118890>] (ubifs_leb_read) from [<8011b4e8>] (fallible_read_node+0x60/0x174)
[ 187.867580] [<8011b4e8>] (fallible_read_node) from [<8011d32c>] (ubifs_tnc_locate+0x124/0x1a0)
[ 187.876237] [<8011d32c>] (ubifs_tnc_locate) from [<80110e68>] (do_readpage+0x1a8/0x430)
[ 187.884266] [<80110e68>] (do_readpage) from [<801121ac>] (ubifs_readpage+0x418/0x460)
[ 187.892144] [<801121ac>] (ubifs_readpage) from [<8007445c>] (filemap_fault+0x284/0x428)
[ 187.900195] [<8007445c>] (filemap_fault) from [<8008d9d8>] (__do_fault+0x3c/0xa4)
[ 187.907722] [<8008d9d8>] (__do_fault) from [<80090808>] (handle_mm_fault+0x340/0xcf0)
[ 187.915595] [<80090808>] (handle_mm_fault) from [<80014c64>] (do_page_fault+0x118/0x284)
[ 187.923708] [<80014c64>] (do_page_fault) from [<8000923c>] (do_DataAbort+0x34/0xb4)
[ 187.931409] [<8000923c>] (do_DataAbort) from [<80011c58>] (__dabt_svc+0x38/0x60)
[ 187.938833] Exception stack(0x86609e70 to 0x86609eb8)
[ 187.943899] 9e60: 000a338c 00000c6c 00000000 00000000
[ 187.952114] 9e80: 86d8c480 86f2f800 87323180 000a338c 000a7e30 00000000 86cfe740 86f2e600
[ 187.960326] 9ea0: 00000000 86609eb8 803a5c50 8016e2d8 20000013 ffffffff
[ 187.966986] [<80011c58>] (__dabt_svc) from [<8016e2d8>] (__clear_user_std+0x34/0x68)
[ 187.974774] UBIFS error (ubi0:0 pid 300): ubifs_leb_read: reading 1242 bytes from LEB 13:9760 failed, error -74
[ 187.984894] CPU: 0 PID: 300 Comm: sh Tainted: G O 4.1.15+ #236
[ 187.991862] Hardware name: Freescale i.MX6 Ultralite (Device Tree)
[ 187.998087] [<8001314c>] (unwind_backtrace) from [<80011294>] (show_stack+0x10/0x14)
[ 188.005886] [<80011294>] (show_stack) from [<801188e0>] (ubifs_leb_read+0x7c/0x90)
[ 188.013478] [<801188e0>] (ubifs_leb_read) from [<8011b4e8>] (fallible_read_node+0x60/0x174)
[ 188.021871] [<8011b4e8>] (fallible_read_node) from [<8011d32c>] (ubifs_tnc_locate+0x124/0x1a0)
[ 188.030524] [<8011d32c>] (ubifs_tnc_locate) from [<80110e68>] (do_readpage+0x1a8/0x430)
[ 188.038570] [<80110e68>] (do_readpage) from [<801121ac>] (ubifs_readpage+0x418/0x460)
[ 188.046442] [<801121ac>] (ubifs_readpage) from [<8007445c>] (filemap_fault+0x284/0x428)
[ 188.054468] [<8007445c>] (filemap_fault) from [<8008d9d8>] (__do_fault+0x3c/0xa4)
[ 188.061997] [<8008d9d8>] (__do_fault) from [<80090808>] (handle_mm_fault+0x340/0xcf0)
[ 188.069874] [<80090808>] (handle_mm_fault) from [<80014c64>] (do_page_fault+0x118/0x284)
[ 188.078006] [<80014c64>] (do_page_fault) from [<8000923c>] (do_DataAbort+0x34/0xb4)
[ 188.085705] [<8000923c>] (do_DataAbort) from [<80011c58>] (__dabt_svc+0x38/0x60)
[ 188.093112] Exception stack(0x86609e70 to 0x86609eb8)
[ 188.098227] 9e60: 000a338c 00000c6c 00000000 00000000
[ 188.106450] 9e80: 86d8c480 86f2f800 87323180 000a338c 000a7e30 00000000 86cfe740 86f2e600
[ 188.114641] 9ea0: 00000000 86609eb8 803a5c50 8016e2d8 20000013 ffffffff
[ 188.121301] [<80011c58>] (__dabt_svc) from [<8016e2d8>] (__clear_user_std+0x34/0x68)
[ 188.129081] UBIFS error (ubi0:0 pid 300): try_read_node: cannot read node type 1 from LEB 13:9760, error -74
[ 188.139350] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read only 1242 bytes, retry
[ 188.151630] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read only 1242 bytes, retry
[ 188.163889] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read only 1242 bytes, retry
[ 188.176135] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 1242 bytes from PEB 15:13856, read 1242 bytes
[ 188.186872] CPU: 0 PID: 300 Comm: sh Tainted: G O 4.1.15+ #236

Analyze problem

問題點不是system()
而是 flash_eraseall 這支程式
透過 file command 去看這個檔案可以發現

1
2
file flash_eraseall
flash_eraseall: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.26, not stripped

而之前加上ls可以過是因為

1
2
file busybox
busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, stripped

busybox 也是 dynamic link
因此只要之前有 call 到 libc 就可以了
表示如果flash_eraseall有用到其他libary的話還是會出現那個問題
因此在設計時 要非常注意執行檔再切換 ECC 時無論是執行檔還是連結 libary 的位置

Solved skill

  1. Add related libc to ramdisk.
  2. Build flash_eraseall binary using static build.

BENAND

subpage

What is nand torture?

See me