NAND simulator

NAND simulator 사용법을 간단히 정리해 보았다.

NAND simulator 소개

NAND simulator는 시스템의 RAM을 사용하여 NAND chip을 시뮬레이션하는 툴이다. 특히 bad block, bit flip 등을 시뮬레이션할 수 있기 때문에 실제 NAND FLASH로 테스트하기 어려운 것도 쉽게 테스트 할 수 있도록 해 주고, 실제 embedded 보드 없이도 host에서 검증할 수 있게 해준다.
물론 RAM으로 NAND 동작을 시뮬레이션하는 것이므로 동작에 대한 시뮬레이션만 가능하고, 시간이나 성능 측정은 안된다.

Linux Kernel에는 nandsim이라는 NAND simulator가 내장되어 있는데, 소스 코드는 drivers/mtd/nand/nandsim.c 또는 drivers/mtd/nand/raw/nandsim.c 파일이고, CONFIG_MTD_NAND_NANDSIM (Device Drivers -> Memory Technology Device (MTD) support -> Raw/Parallel NAND Device Support -> Support for NAND Flash Simulator) 설정을 모듈로 enable하면 된다. (참고로 ECC mode는 “NAND_ECC_SOFT_BCH”로 세팅됨)

효용성에 비하여 embedded 개발자에게 있어서 잘 알려져 있지 않아서 정리하다보니 조금 긴 글이 되었다. 😅

사전 준비

  1. Kernel이 CONFIG_MTD_NAND_NANDSIM 설정이 enable 되어 빌드되어 있어야 한다.
    만약에 WSL을 사용시에는 이 설정이 enable 되어 있지 않은데, 이 경우에는 WSL2 관련 정리 페이지를 참조하여 WSL Kernel configuration에서 CONFIG_MTD_NAND_NANDSIM 설정을 M(즉 Module)으로 세팅하여 빌드한 후, 빌드된 WSL Kernel을 사용하면 된다.
    또, 빌드가 끝나면 모듈 라이브러리를 시스템 lib 경로에 설치하기 위하여 아래와 같이 실행한다.
    $ sudo make modules_install
    
  2. Kernel이 nandsim을 지원하는 환경이 되면, 아래와 같이 실행시 에러가 출력되지 않는다. (단, 이 경우 ID 값이 주어지지 않았으므로 128MiB 크기의 디폴트 NAND 디바이스로 생성됨)
    $ sudo modprobe nandsim
    
  3. 아래와 같이 simulated NAND device를 제거할 수 있다.
    $ sudo rmmod nandsim
    
  4. 추가로 테스트시 MTD 유틸을 사용하기 위하여 아래와 같이 mtd-utils 패키지를 (NAND 디바이스 관련 툴) 설치한다.
    $ sudo apt install mtd-utils
    

NAND 디바이스 생성

  1. dmesg 내용을 쉽게 확인하기 위하여 아래와 같이 기존 내용은 clear 시킨다.
    $ sudo dmesg -c
    
  2. 시뮬레이션하려는 NAND chip의 ID를 얻는다. (“Read ID”(0x90) 명령으로 얻은 ID 값으로 deice ID로 시작하는 최대 5바이트 ID 값임, NAND chip data sheet에 나와 있음)
  3. 이제 아래 예와 같이 ID 값을 주어서 simulated NAND device를 생성할 수 있다.
    • MT29F2G08AAC (DEVICE ID=0x2CDA9095) 예
      $ sudo modprobe nandsim first_id_byte=0x2C second_id_byte=0xDA third_id_byte=0x90 fourth_id_byte=0x95
      
    • 또는 ID 값을 아래 예와 같이 id_byte 옵션으로 연이어 줄 수도 있다.
      $ sudo modprobe nandsim id_bytes=0x2C,0xDA,0x90,0x95
      
    • S/W BCH 설정은 아래 예와 같이 bch 옵션으로 세팅할 수 있다. (에러가 발생하면 dmesg로 에러 내용 찾아볼 것)
      $ sudo modprobe nandsim id_bytes=0x2C,0xDA,0x90,0x95 bch=4
      
  4. NAND device 생성시 에러가 출력되지 않았으면, NAND device가 제대로 생성되었는지 아래 예와 같이 dmesg 명령으로 확인해 볼 수 있다.
    $ dmesg
    nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
    nand: Micron NAND 256MiB 3,3V 8-bit
    nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
    flash size: 256 MiB
    page size: 2048 bytes
    OOB area size: 64 bytes
    sector size: 128 KiB
    pages number: 131072
    pages per sector: 64
    bus width: 8
    bits in sector size: 17
    bits in page size: 11
    bits in OOB size: 6
    flash size with OOB: 270336 KiB
    page address bytes: 5
    sector address bytes: 3
    options: 0x8
    Scanning device for bad blocks
    Creating 1 MTD partitions on "NAND 256MiB 3,3V 8-bit":
    0x000000000000-0x000010000000 : "NAND simulator partition 0"
    
  5. NAND device가 제대로 생성되었으면 이제 아래와 같이 /proc/mtd 목록에 나타날 것이다.
    $ cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 10000000 00020000 "NAND simulator partition 0"
    
  6. 또, 아래 예와 같이 이 NAND device의 정보를 확인할 수 있다.
    $ mtdinfo /dev/mtd0
    mtd0
    Name:                           NAND simulator partition 0
    Type:                           nand
    Eraseblock size:                131072 bytes, 128.0 KiB
    Amount of eraseblocks:          2048 (268435456 bytes, 256.0 MiB)
    Minimum input/output unit size: 2048 bytes
    Sub-page size:                  512 bytes
    OOB size:                       64 bytes
    Character device major/minor:   90:0
    Bad blocks are allowed:         true
    Device is writable:             true
    

NAND 디바이스 기본 테스트

  1. 아래와 같이 MTD 파티션을 erase 할 수 있다.
    $ sudo flash_erase /dev/mtd0 0 0
    
  2. 아래 예와 같이 MTD 파티션에 데이터를 write 할 수 있다.
    $ dd if=/dev/urandom of=test.bin bs=128k count=10
    $ sudo nandwrite -m -p /dev/mtd0 test.bin
    
  3. 아래와 같이 MTD 파티션의 데이터를 덤프뜰 수 있다. (length 옵션을 주지 않으면 MTD 크기만큼 덤프됨)
    $ sudo nanddump -f test.read.bin /dev/mtd0 -l 1310720
    

    읽은 데이터가 원본 데이터와 동일한지 비교해 보면 아래 예와 같이 동일함을 확인할 수 있다.

    $ md5sum test.*
    3d5b2e1460744619ccc97983ff740375  test.bin
    3d5b2e1460744619ccc97983ff740375  test.read.bin
    

    nanddump는 아래 예와 같이 -o 옵션을 주면 OOB 데이터도 덤프뜰 수 있다. (OOB Data 영역에 OOB 데이터가 표시됨)

    $ sudo nanddump -f mtd_dump.txt -o -p /dev/mtd0
    
  4. 아래와 같이 nandtest 툴로 테스트도 가능하다. (-k 옵션을 주면 테스트 후에 원본 데이터를 다시 복구함)
    $ sudo nandtest -k /dev/mtd0
    

NAND 디바이스 파티션, bad block 생성 테스트

  1. MTD 파티션 생성은 아래 예와 같이 parts 옵션으로 block 개수를 주면 된다.
    $ sudo modprobe nandsim id_bytes=0x1,0xA1,0x0,0x15 parts=24,256,296
    

    아래와 같이 확인해 보면, 기대대로 128MiB 용량의 FLASH에서 4개의 파티션이 각각 24 block, 256 block, 296 block, 448 block의 크기로 생성되었음을 확인할 수 있다. (마지막 block 수 = 전체 block 수 - 사용된 block 수 = 1024 - 24 - 256 - 296 = 448)

    $ cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 00300000 00020000 "NAND simulator partition 0"
    mtd1: 02000000 00020000 "NAND simulator partition 1"
    mtd2: 02500000 00020000 "NAND simulator partition 2"
    mtd3: 03800000 00020000 "NAND simulator partition 3"
    $ mtdinfo /dev/mtd0
    mtd0
    Name:                           NAND simulator partition 0
    Type:                           nand
    Eraseblock size:                131072 bytes, 128.0 KiB
    Amount of eraseblocks:          24 (3145728 bytes, 3.0 MiB)
    Minimum input/output unit size: 2048 bytes
    Sub-page size:                  512 bytes
    OOB size:                       64 bytes
    Character device major/minor:   90:0
    Bad blocks are allowed:         true
    Device is writable:             true
    $ mtdinfo /dev/mtd1
    mtd1
    Name:                           NAND simulator partition 1
    Type:                           nand
    Eraseblock size:                131072 bytes, 128.0 KiB
    Amount of eraseblocks:          256 (33554432 bytes, 32.0 MiB)
    Minimum input/output unit size: 2048 bytes
    Sub-page size:                  512 bytes
    OOB size:                       64 bytes
    Character device major/minor:   90:2
    Bad blocks are allowed:         true
    Device is writable:             true
    $ mtdinfo /dev/mtd2
    mtd2
    Name:                           NAND simulator partition 2
    Type:                           nand
    Eraseblock size:                131072 bytes, 128.0 KiB
    Amount of eraseblocks:          296 (38797312 bytes, 37.0 MiB)
    Minimum input/output unit size: 2048 bytes
    Sub-page size:                  512 bytes
    OOB size:                       64 bytes
    Character device major/minor:   90:4
    Bad blocks are allowed:         true
    Device is writable:             true
    $ mtdinfo /dev/mtd3
    mtd3
    Name:                           NAND simulator partition 3
    Type:                           nand
    Eraseblock size:                131072 bytes, 128.0 KiB
    Amount of eraseblocks:          448 (58720256 bytes, 56.0 MiB)
    Minimum input/output unit size: 2048 bytes
    Sub-page size:                  512 bytes
    OOB size:                       64 bytes
    Character device major/minor:   90:6
    Bad blocks are allowed:         true
    Device is writable:             true
    
  2. Bad block 생성은 아래 예와 같이 badblocks 옵션으로 bad block 값을 주면 된다. (block 값은 0부터 시작이고, 아래 예에서는 1, 10, 100, 310, 410 block을 bad block으로 지정하였음)
    $ sudo modprobe nandsim id_bytes=0x1,0xA1,0x0,0x15 parts=24,256,296 badblocks=1,10,100,310,410
    

    파티션을 확인해 보면 아래와 같이 나온다.

    $ cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 00300000 00020000 "NAND simulator partition 0"
    mtd1: 02000000 00020000 "NAND simulator partition 1"
    mtd2: 02500000 00020000 "NAND simulator partition 2"
    mtd3: 03800000 00020000 "NAND simulator partition 3"
    

    각 MTD 파티션의 bad block을 확인해 보면 아래와 같이 기대대로 나온다.

    $ cat /sys/class/mtd/mtd0/bad_blocks
    2
    $ cat /sys/class/mtd/mtd1/bad_blocks
    1
    $ cat /sys/class/mtd/mtd2/bad_blocks
    2
    $ cat /sys/class/mtd/mtd3/bad_blocks
    0
    

    아래 예와 같이 bad block이 있는 파티션을 flash_erase 명령으로 erase 해 보면, bad block이 발생되어 skip 되는 것을 확인할 수 있다. (아래 예에서 bad block 위치는 0x20000, 0x140000 이고, 이는 각각 block 번호 1, 10에 해당함)

    $ sudo flash_erase /dev/mtd0 0 0
    Erasing 128 Kibyte @ 0 --  0 % complete flash_erase: Skipping bad block at 00020000
    Erasing 128 Kibyte @ 120000 -- 37 % complete flash_erase: Skipping bad block at 00140000
    Erasing 128 Kibyte @ 2e0000 -- 100 % complete
    

    nandtest 툴로 테스트해 보면, 아래와 같이 지정된 block이 bad block으로 감지되었음을 확인할 수 있다.

    $ sudo nandtest -k /dev/mtd0
    ECC corrections: 0
    ECC failures   : 0
    Bad blocks     : 2
    BBT blocks     : 0
    Bad block at 0x00020000 1)...
    Bad block at 0x00140000 1)...
    002e0000: checking...of 1)...
    Finished pass 1 successfully
    $ sudo nandtest -k /dev/mtd1
    ECC corrections: 0
    ECC failures   : 0
    Bad blocks     : 1
    BBT blocks     : 0
    Bad block at 0x00980000 1)...
    01fe0000: checking...of 1)...
    Finished pass 1 successfully
    $ sudo nandtest -k /dev/mtd2
    ECC corrections: 0
    ECC failures   : 0
    Bad blocks     : 2
    BBT blocks     : 0
    Bad block at 0x003c0000 1)...
    Bad block at 0x01040000 1)...
    024e0000: checking...of 1)...
    Finished pass 1 successfully
    

    또, mtdinfo 툴로 -M 옵션을 주면, bad block은 BAD로 표시가 된다. (아래 예에서는 세팅한대로 MTD0에서 1번, 10번 block이 BAD로 표시되었음)

    $ sudo mtdinfo /dev/mtd0 -M
    mtd0
    Name:                           NAND simulator partition 0
    Type:                           nand
    Eraseblock size:                131072 bytes, 128.0 KiB
    Amount of eraseblocks:          24 (3145728 bytes, 3.0 MiB)
    Minimum input/output unit size: 2048 bytes
    Sub-page size:                  512 bytes
    OOB size:                       64 bytes
    Character device major/minor:   90:0
    Bad blocks are allowed:         true
    Device is writable:             true
    Eraseblock map:
      0: 00000000          1: 00020000    BAD   2: 00040000          3: 00060000
      4: 00080000          5: 000a0000          6: 000c0000          7: 000e0000
      8: 00100000          9: 00120000         10: 00140000    BAD  11: 00160000
     12: 00180000         13: 001a0000         14: 001c0000         15: 001e0000
     16: 00200000         17: 00220000         18: 00240000         19: 00260000
     20: 00280000         21: 002a0000         22: 002c0000         23: 002e0000
    

    또, 아래와 같이 nanddump 툴로 확인해 보면, 해당 bad block은 skip 되었음을 확인할 수 있다.

    $ sudo nanddump -f mtd_dump.txt -o -p /dev/mtd0
    

    만약 bad block도 dump 뜨고 싶으면, 아래 예와 같이 --bb=dumpbad 옵션을 추가하면 된다.

    $ sudo nanddump -f mtd_dump.txt -o -p --bb=dumpbad /dev/mtd0
    

    Bad block의 첫번째 page에서 OOB 데이터의 첫 바이트 값이 0xFF가 아닌 0x00으로 bad block 마킹되었음을 확인할 수 있다. (참고로 이 NAND chip은 page 크기가 512 바이트를 초과하므로 large page이고 이 경우에는 OOB 영역 offset 0 위치에 마킹됨, 한편 page 크기가 512 바이트 이하인 small page인 경우에는 offset 5 위치에 마킹됨)

  3. Weak block은 (erase 시 bad block이 발생할 수 있는 block) 아래 예와 같이 weakblocks 옵션으로 block 값을 주면 된다. (형식은 block_번호:최대_erase_가능한_횟수(생략하면 디폴트 3회))
    $ sudo modprobe nandsim id_bytes=0x1,0xA1,0x0,0x15 parts=24,256,296 badblocks=1,10,100,310,410 weakblocks=11:2,101:3
    

    이후 nandtest로 -p 옵션으로 테스트 회수를 지정하면, weakblocks 옵션으로 지정한 회수 이후에는 “erasing… MEMERASE: Input/output error”가 발생하며 -m 옵션을 추가하면 해당 block은 bad block으로 마킹됨을 확인할 수 있다.

  4. 아래 예와 같이 weakpages 옵션으로 weak page를 (write시 에러가 발생할 수 있는 page) 세팅할 수도 있는데, (형식은 page_번호:최대_write_가능한_횟수(생략하면 디폴트 3회))
    $ sudo modprobe nandsim id_bytes=0x1,0xA1,0x0,0x15 parts=24,256,296 badblocks=1,10,100,310,410 weakpages=200:2,300
    

    이후 nandtest로 -p 옵션으로 테스트 회수를 지정하면, weakpages 옵션으로 지정한 회수 이후에는 “write: Input/output error”가 발생하며 -m 옵션을 추가하면 해당 block은 bad block으로 마킹됨을 확인할 수 있다.

  5. BBT는 아래 예와 같이 “bbt” 옵션으로 생성할 수 있다. (1 또는 2 가능)
    $ sudo modprobe nandsim id_bytes=0x1,0xA1,0x0,0x15 parts=24,256,296 badblocks=0,1 bbt=1
    

    BBT는 bootloader와 Kernel 간에 동일한 규약을 사용하는데, Kernel은 scan하여 BBT가 없으면 good block을 찾아서 (primary 용 1block, secondary 용 1block) BBT를 구성한다. BBT 데이터는 2bit에 1block의 bad block 여부를 저장하는데 binary로 bit 11이면 good block이다. BBT block은 자신이 BBT block임을 표시하기 위하여 해당 block의 첫 page의 OOB 영역 중에서 offset 8~11 위치에 BBT 식별자 문자열을 저장한다. (이 문자열은 primary BBT인 경우에는 “Bbt0”, secondary BBT인 경우에는 “1tbB” 이고, 저장 위치는 Kernel 소스에 따라 다를 수 있음)
    또, bad block이 발생하여 BBT가 업데이트될 때마다 BBT 식별자 문자열 바로 다음 위치에 버전값을 증가시킨다.
    이후 bad block이 발생하면 해당 block의 OOB 영역에 마킹이 되고, BBT의 데이터도 해당 block이 bad로 마킹되고, BBT 버전값은 +1 증가된다.
    참고로 BBT block은 normal 어플리케이션이 erase/write 하지 않도록, 의도적으로 bad block으로 마킹된다. (mtdinfo 툴로 -M 옵션으로 확인해 보면, 실제로 BBT block들은 bad block으로 표시되는 것을 확인할 수 있음)

NAND 디바이스 제거

테스트 완료 후에, simulated NAND device를 제거하고 싶으면 아래와 같이 하면 된다.

$ sudo rmmod nandsim

이후 cat /proc/mtd 명령으로 확인해보면 simulated MTD 디바이스가 모두 삭제되었음을 확인할 수 있다.

MTD NAND 관련 소스 검증 예

팀 소스에서 MTD NAND 관련 API와 이를 활용하는 툴이 있었는데, refactoring을 하게 되었다. 개발과 검증을 직접 보드에서 하는 대신에 nandsim을 이용하여 편리하게 host에서 사전 검증할 수 있었고, 개발 및 검증 시간도 대폭 줄었다. 역시 시뮬레이션은 좋은 것이다. 😛
참고로 아래와 같이 시뮬레이션 테스트를 asciinema로 녹화하였다. (기존 소스에서는 문제가 좀 있었는데 NAND simulator로 확인하면서 새로 refactoring을 하니 정상 동작되었다)

UBIFS 이미지 확인 예

  1. UBI/UBIFS 이미지는 ubireader_extract_images 툴로 내용을 확인할 수 있다. 여기서는 NAND 디바이스로 마운트시키는 예를 들어본다.
  2. 아래 예와 같이 nandsim으로 simulated NAND device를 생성한다. (편의상 파티션 1개만 생성)
    $ sudo modprobe nandsim id_bytes=0x20,0xaa,0x00,0x15
    

    아래와 같이 확인해보면 256MiB NAND 디바이스가 생성되었음을 확인할 수 있다.

    $ cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 10000000 00020000 "NAND simulator partition 0"
    
  3. 아래와 같이 MTD 영역을 erase 한다.
    $ sudo flash_erase /dev/mtd0 0 0
    
  4. 아래와 같이 UBI 모듈을 insert 시킨다. (Kernel config에서 CONFIG_MTD_UBI, CONFIG_UBIFS_FS 항목이 enable되어 있어야 함)
    $ sudo modprobe ubi mtd=0
    
  5. 아래와 같이 UBI format 한 후에 attach 시킨다. (예로 MTD0 사용)
    $ sudo ubiformat /dev/mtd0
    $ sudo ubiattach /dev/ubi_ctrl -m 0
    
  6. 아래 예와 같이 UBI 볼륨을 생성한다. (예로 이름은 rootfs, 크기는 128MiB로 하였음)
    $ sudo ubimkvol /dev/ubi0 -N rootfs -s 128MiB
    
  7. 이제 아래와 같이 확인할 UBIFS 이미지를 볼륨에 적용한다. (아래 예에서는 ubifs.img 파일 사용)
    $ sudo ubiupdatevol /dev/ubi0_0 ubifs.img
    

    결과로 ubinfo 명령으로 확인해 보면 아래와 같이 정상적으로 확인된다.

    $ ubinfo -a
    UBI version:                    1
    Count of UBI devices:           1
    UBI control device major/minor: 10:61
    Present UBI devices:            ubi0
    
    ubi0
    Volumes count:                           1
    Logical eraseblock size:                 129024 bytes, 126.0 KiB
    Total amount of logical eraseblocks:     2048 (264241152 bytes, 252.0 MiB)
    Amount of available logical eraseblocks: 963 (124250112 bytes, 118.4 MiB)
    Maximum count of volumes                 128
    Count of bad physical eraseblocks:       0
    Count of reserved physical eraseblocks:  40
    Current maximum erase counter value:     1
    Minimum input/output unit size:          2048 bytes
    Character device major/minor:            245:0
    Present volumes:                         0
    
    Volume ID:   0 (on ubi0)
    Type:        dynamic
    Alignment:   1
    Size:        1041 LEBs (134313984 bytes, 128.0 MiB)
    State:       OK
    Name:        rootfs
    Character device major/minor: 245:1
    
  8. 이제 아래 예와 같이 마운트시킬 디렉토리를 생성한 후, 마운트 시키고 디렉토리 내용을 확인할 수 있다.
    $ mkdir ubimount
    $ sudo mount -t ubifs ubi0:rootfs ubimount/
    $ ls -l ubimount/
    
  9. 작업이 끝났으면 아래와 같이 UBI detach, unmount 및 simulated NAND 디바이스를 제거할 수 있다.
    $ sudo ubidetach /dev/ubi_ctrl -m 0
    $ sudo umount ubimount/
    $ sudo rmmod nandsim
    
  10. 참고로 UBIFS 이미지가 아닌 UBI 이미지는 아래와 같이 바로 write 한 후, 마운트하면 된다. (편의상 설명없이 전체 과정만 기술하였음)
    $ sudo modprobe nandsim id_bytes=0x20,0xaa,0x00,0x15
    $ sudo nandwrite /dev/mtd0 ubi.img
    $ sudo modprobe ubi mtd=/dev/mtd0,4096
    $ sudo mount -t ubifs /dev/ubi0_0 ubimount/
    $ ls -l ubimount/
    $ sudo umount ubimount/
    $ sudo rmmod nandsim
    

squashfs 테스트 예

  1. 테스트 할 squashfs 이미지 파일을 준비한다.
    이미지 내용을 확인하려면 아래와 같이 마운트해서 확인하고, 언마운트시킬 수 있다. (예로 rootfs.squashfs 파일 사용)
    $ sudo mount -o loop -t squashfs rootfs.squashfs /mnt/mtd/
    $ ls -l /mnt/mtd/
    $ sudo umount /mnt/mtd
    

    또는 아래 예와 같이 간단히 unsquashfs 명령으로 풀어서 확인할 수 있다.

    $ unsquashfs rootfs.squashfs
    $ ls -l squashfs-root/
    
  2. 아래 예와 같이 simulated MTD 디바이스를 생성한 후(테스트로 bad block 2개를 추가하였음), 해당 파티션을 erase 한다.
    $ sudo modprobe nandsim id_bytes=0xAD,0xDA,0x90,0x95 badblocks=8,18
    $ sudo flash_erase /dev/mtd0 0 0
    Erasing 128 Kibyte @ e0000 --  0 % complete flash_erase: Skipping bad block at 00100000
    Erasing 128 Kibyte @ 220000 --  0 % complete flash_erase: Skipping bad block at 00240000
    Erasing 128 Kibyte @ ffe0000 -- 100 % complete
    
  3. 아래와 같이 squashfs 이미지를 write 한다.
    $ sudo nandwrite -p /dev/mtd0 rootfs.squashfs
    

    아래와 같이 dd dump해서 비교해 볼 수 있다.

    $ sudo dd if=/dev/mtd0 of=mtd_dd_dump.bin bs=1MiB count=14
    

    결과로 rootfs.squashfs 파일과 mtd_dd_dump.bin을 비교해보면 bad block이 있어서 다르다. 즉, dd 툴은 bad block 처리를 하지 않아서, NAND read 나 write로 적합하지 않음을 알 수 있다. 아래와 같이 nanddump 툴로 read해서 비교해 보면, bad block은 skip 하므로 rootfs.squashfs 파일과 동일함을 확인할 수 있다.

    $ sudo nanddump /dev/mtd0 -f mtd_nand_dump.bin -l 0xE00000
    
  4. 테스트를 끝냈으면 아래와 같이 simulated NAND 디바이스를 제거한다.
    $ sudo rmmod nandsim
    

squashfs on top of UBI 테스트 예

  1. squashfs 이미지는 UBI 이미지로 wrapping 할 수 있는데, 이것을 시뮬레이션 해 본다.
    아래와 같이 ubinize.cfg 파일을 작성한다. (입력 파일은 image 아규먼트로 지정한 rootfs.squashfs 파일이 됨)
    [squashfs]
    mode=ubi
    image=rootfs.squashfs
    vol_id=0
    vol_size=28MiB
    vol_type=dynamic
    vol_name=squashfs
    vol_flags=autoresize
    
  2. 아래 예와 같이 ubinize 툴로 UBI 이미지를 생성한다. (아래 예에서는 결과로 ubi-rootfs.squashfs 이름의 UBI 이미지가 생성됨)
    $ ubinize -o ubi-rootfs.squashfs -m 2048 -p 128KiB -s 512 -O 2048 ubinize.cfg
    
  3. 아래 예와 같이 simulated MTD 디바이스를 생성한 후(테스트로 bad block 2개를 추가하였음), 해당 파티션을 erase 한다.
    $ sudo modprobe nandsim id_bytes=0xAD,0xDA,0x90,0x95 badblocks=8,18
    $ sudo flash_erase /dev/mtd0 0 0
    Erasing 128 Kibyte @ e0000 --  0 % complete flash_erase: Skipping bad block at 00100000
    Erasing 128 Kibyte @ 220000 --  0 % complete flash_erase: Skipping bad block at 00240000
    Erasing 128 Kibyte @ ffe0000 -- 100 % complete
    
  4. 생성된 UBI 이미지를 아래 예와 같이 MTD에 write 한다.
    $ sudo nandwrite -p /dev/mtd0 ubi-rootfs.squashfs
    
  5. 이 파티션을 rootfs로 사용하기 위하여 아래와 같이 ubi block 모듈을 로딩한다.
    $ sudo modprobe ubi mtd=0,2048 block=0,0
    

    성공적으로 되었으면 아래와 같이 디바이스 노드가 생성되었음을 확인할 수 있다.

    $ ls /dev/ubi*
    /dev/ubi0  /dev/ubi0_0  /dev/ubiblock0_0  /dev/ubi_ctrl
    
  6. 이제 아래와 같이 마운트시킬 수 있다.
    $ sudo mount -t squashfs -r /dev/ubiblock0_0 /mnt/mtd/
    

    마운트가 되었으면, 아래와 같이 확인해 보면 rootfs 파일들이 정상적으로 보인다.

    $ ls -l /mnt/mtd/
    
  7. nanddump 툴로 /dev/mtd0을 덤프 뜨면 UBI 이미지가 읽힌다. squashfs 이미지를 읽으려면 아래와 같이 dd 툴로 읽을 수도 있다.
    $ sudo dd if=/dev/ubiblock0_0 of=mtd0_squash_dump.bin bs=1MiB
    
  8. 테스트를 끝냈으면 아래와 같이 simulated NAND 디바이스를 제거한다.
    $ sudo rmmod nandsim
    

결론

NAND simulator를 이용하여 실제 NAND 디바이스를 장착한 보드가 없이도, 원하는대로 bad block을 생성해 가면서 테스트를 할 수 있었고, 이것이 바로 시뮬레이터의 힘이라는 것을 다시 한 번 느꼈다.
Driver를 직접 개발하지 않는 대부분의 개발자들은 이런 시뮬레이터의 존재 자체를 모르고, 실제 타겟 디바이스로만 테스트 및 검증을 하려고 하는데, 이 경우 시간도 오래 걸리고 여러 제약이 있어서 오히려 놓치는 부분이 생길 수 있기에, 공유하기 위하여 시간을 들여서 기록해 보았다. 😋

카테고리:

업데이트: