U-boot 'nand markbad' не имеет никакого эффекта - PullRequest
1 голос
/ 24 сентября 2019

Ситуация: плата с процессорным процессором Arm, рядом с которым расположена вспышка Nand.При включении питания загрузчик U-boot запускается и копирует содержимое флэш-памяти в ОЗУ, затем передает управление этому коду в ОЗУ.Система Linux с некоторым кодом приложения, созданным через Buildroot, запускается.Вся ее файловая система хранится как один файл UBIFS во флэш-памяти, и он начинает использовать это.

Когда установлен определенный байт, загрузчик сохраняет контроль и запускает передачу TFTP для загрузки и сохранения новой флэш-памяти.image.

Триггер: плата вернулась с дефектом.Запуск ядра Linux ясно показывает проблему:

[    1.931150] Creating 8 MTD partitions on "atmel_nand":
[    1.936285] 0x000000000000-0x000000040000 : "at91bootstrap"
[    1.945280] 0x000000040000-0x0000000c0000 : "bootloader"
[    1.954065] 0x0000000c0000-0x000000100000 : "bootloader env"
[    1.963262] 0x000000100000-0x000000140000 : "bootloader redundant env"
[    1.973221] 0x000000140000-0x000000180000 : "spare"
[    1.981552] 0x000000180000-0x000000200000 : "device tree"
[    1.990466] 0x000000200000-0x000000800000 : "kernel"
[    1.999210] 0x000000800000-0x000010000000 : "rootfs"
...
[    4.016251] ubi0: attached mtd7 (name "rootfs", size 248 MiB)
[    4.022181] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
[    4.029040] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
[    4.035941] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096
[    4.042960] ubi0: good PEBs: 1980, bad PEBs: 4, corrupted PEBs: 0
[    4.049033] ubi0: user volume: 2, internal volumes: 1, max. volumes count: 128
[    4.056359] ubi0: max/mean erase counter: 2/0, WL threshold: 4096, image sequence number: 861993884
[    4.065476] ubi0: available PEBs: 0, total reserved PEBs: 1980, PEBs reserved for bad PEB handling: 36
[    4.074898] ubi0: background thread "ubi_bgt0d" started, PID 77
...
[    4.298009] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "rootfs", R/O mode
[    4.306415] UBIFS (ubi0:0): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
[    4.316418] UBIFS (ubi0:0): FS size: 155926528 bytes (148 MiB, 1228 LEBs), journal size 9023488 bytes (8 MiB, 72 LEBs)
[    4.327197] UBIFS (ubi0:0): reserved for root: 0 bytes (0 KiB)
[    4.333095] UBIFS (ubi0:0): media format: w4/r0 (latest is w5/r0), UUID AE9F77DC-04AF-433F-92BC-D3375C83B518, small LPT model
[    4.346924] VFS: Mounted root (ubifs filesystem) readonly on device 0:15.
[    4.356186] devtmpfs: mounted
[    4.367038] Freeing unused kernel memory: 1024K
[    4.371812] Run /sbin/init as init process
[    4.568143] UBIFS (ubi0:1): background thread "ubifs_bgt0_1" started, PID 83
[    4.644809] UBIFS (ubi0:1): recovery needed
[    4.685823] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 235:4096, read only 126976 bytes, retry
[    4.732212] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 235:4096, read only 126976 bytes, retry
[    4.778705] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 235:4096, read only 126976 bytes, retry
[    4.824159] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 235:4096, read 126976 bytes

..., которая вызывает исключение, но ядро ​​продолжает работать, затем обнаруживается другая ошибка:

[    5.071518] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 709:4096, read only 126976 bytes, retry
[    5.118110] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 709:4096, read only 126976 bytes, retry
[    5.164447] ubi0 warning: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 709:4096, read only 126976 bytes, retry
[    5.210987] ubi0 error: ubi_io_read: error -74 (ECC error) while reading 126976 bytes from PEB 709:4096, read 126976 bytes

...но впечатляюще, система все еще оживает и ведет себя почти нормально. Почему ядро ​​не помечает эти флэш-блоки как плохие? Эти данные все равно не могут быть прочитаны, и, по крайней мере, следующее мигание изображения может пропустить плохие блоки ...

Исследование:поэтому ядро ​​обнаружило неисправный PEB # 235 (десятичный) в разделе «rootfs» флеш-памяти.Каждый PEB имеет размер 128 КБ, поэтому ошибка находится где-то за пределами байта 30 801 920 (десятичный).Поскольку раздел «rootfs» начинается только с байта 0x800000 флэш-памяти, фактически поврежденная страница должна быть где-то за байтом 39 190 528 (десятичный) или 0x2560000.И, конечно же, при использовании утилиты nand read в U-boot:

U-Boot> nand read 0x20000000 0x2560000 0x1000
NAND read: device 0 offset 0x2560000, size 0x1000
 4096 bytes read: OK
U-Boot> nand read 0x20000000 0x2561000 0x1000
NAND read: device 0 offset 0x2561000, size 0x1000
 4096 bytes read: OK
U-Boot> nand read 0x20000000 0x2562000 0x1000
NAND read: device 0 offset 0x2562000, size 0x1000
PMECC: Too many errors
NAND read from offset 2562000 failed -5
 0 bytes read: ERROR

, поэтому поврежденная страница находится со смещением 8K в этом блоке флэш-памяти.Из различных других постов я узнал, что nand flash с 2K-страницами, организованными по 128K-блокам, имеет дополнительные 64 байта «Out of Band» на каждые 2048 байтов полезной нагрузки, в результате чего каждая страница имеет общий размер 2112 байт.В любом случае весь блок размером 128 Кбайт придется использовать неиспользуемым, так как это размер стирания.Нет проблем, есть место для хранения, я просто хочу убедиться, что следующее мигание пропустит этот плохой блок.Поскольку ни ядро ​​Linux, ни загрузчик не потрудились пометить плохой блок, я сделаю это вручную в U-boot:

U-Boot> nand markbad 2562000
block 0x02562000 successfully marked as bad

Аналогичное расследование для 2-й страницы плохой флеш-памяти показывает, что другая ошибканаходится на флэш-адресе 0x60a1000:

U-Boot> nand read 0 60A1000 800
NAND read: device 0 offset 0x60a1000, size 0x800
PMECC: Too many errors
NAND read from offset 60a1000 failed -5
 0 bytes read: ERROR

, поэтому и здесь утилита nand markbad используется для ручного наложения постоянной отметки на этот блок:

U-Boot> nand markbad 60a1000
block 0x060a1000 successfully marked as bad

и чтобы убедиться, что все учтено:

U-Boot> nand bad
Device 0 bad blocks:
  02560000
  060a0000

Так же, как и должно быть - с начала каждого блока 128 КБ оба блока помечены.

Проблема: поэтому я узнал, что64 байта OOB разделены на 2 байта маркера, 38 байтов кода с исправлением ошибок и 24 байта журнала.Из всех байтов OOB, сопровождающих каждые 2048 байтов полезной нагрузки, только самый первый фрагмент из 64 байтов, сопровождающий первую страницу размером 2 КБ, предоставляет свой 2-байтовый код маркера, чтобы указать состояние всего блока размером 128 КБ.Эти 2 байта должны быть изменены в самом устройстве флэш-памяти , чтобы этот статус был постоянным.Поэтому в моем сеансе U-boot вместо запуска системы Linux я перезапустил процессор и остался в U-boot:

U-Boot> reset
resetting ...
RomBOOT
 ba_offset = 0xc ...
AT91Bootstrap 3.6.0-00029-g0cd4e6a (Wed Nov 12 12:14:04 CET 2014)
NAND: ONFI flash detected
NAND: Manufacturer ID: 0x2c Chip ID: 0x32
NAND: Disable On-Die ECC
PMECC: page_size: 0x800, oob_size: 0x40, pmecc_cap: 0x4, sector_size: 0x200
NAND: Initialize PMECC params, cap: 0x4, sector: 0x200
NAND: Image: Copy 0x80000 bytes from 0x40000 to 0x26f00000
NAND: Done to load image
U-Boot 2013.10-00403-g1f9a20a (Nov 12 2014 - 12:14:27)
CPU: SAMA5D31
Crystal frequency:       12 MHz
CPU clock        :      528 MHz
Master clock     :      132 MHz
DRAM:  128 MiB
NAND:  256 MiB
MMC:   mci: 0
In:    serial
Out:   serial
Err:   serial
Net:   macb0
Hit any key to stop autoboot:  0
U-Boot> nand info
Device 0: nand0, sector size 128 KiB
  Page size      2048 b
  OOB size         64 b
  Erase size   131072 b
U-Boot> nand bad
Device 0 bad blocks:
U-Boot> 

Плохие блоки были забыты - маркеркод не применялся постоянно?Конечно, эта версия U-boot выглядит довольно старой.С тех пор была ли улучшена утилита nand markbad ?

Обходной путь: Я сам изменил байты OOB первой страницы в блоке bad.Я прочитал все 2112 байт первой страницы в ОЗУ, затем изменил код маркера 2 байта и записал 2112 байт из ОЗУ во флэш-память.Технически, я должен был стереть всю флеш-страницу 128 КБ, а затем записать все 128 КБ содержимого.Но моя лень была оспорена сегодня.Nand flash можно произвольно переключать с 1 на 0 - это сложная обратная операция, требующая стирания для восстановления всей страницы размером 128 Кбайт до all-0xFF.Я заметил, что все маркеры «хорошего блока» закодированы как 0xFFFF, поэтому я решил, что вместо этого должно быть достаточно записи «0x0000».

U-Boot> nand read.raw 0x20200000 0x2560000 1
NAND read:  2112 bytes read: OK

Формат и read.raw - этонемного странно, в отличие от nand.read , который ожидает size в качестве последнего аргумента в байтах, он хочет вместо этого size , выраженный в количестве страниц.Первая страница - это все, что нам нужно, поэтому аргумент «1» делает свое дело.Содержимое, которое теперь было перенесено в ОЗУ, можно проверить с помощью утилиты U-boot md :

U-Boot> md 0x20200000 0x210
20200000: 23494255 00000001 00000000 01000000    UBI#............
20200010: 00080000 00100000 9cfb6033 00000000    ........3`......
...
202007e0: 00000000 00000000 00000000 00000000    ................
202007f0: 00000000 00000000 00000000 00000000    ................
20200800: ffffffff ffffffff ffffffff ffffffff    ................
20200810: ffffffff ffffffff ffffffff ffffffff    ................
20200820: ffffffff b0c9aa24 0008fdb8 00000000    ....$...........
20200830: 00000000 00000000 00000000 00000000    ................

Обратите внимание, что утилита md ожидает своего размер аргумент в другом формате: этот ожидает его в единицах слов.Просто чтобы держать нас в курсе.Дамп по адресу 0x20200800 ясно показывает, как markbad не справился со своей задачей: 2 байта маркера плохого блока все еще весело работают на 0xFFFF.

Затем, чтобы изменить эти байты, еще одна загрузка U-bootполезность полезна:

U-Boot> mm 0x20200800
20200800: ffffffff ? 00000000
20200804: ffffffff ? q

Это немного грубо, я изменил 4 первые OOB-байты вместо просто 2 первого маркера байтов.Наконец, чтобы записать измененное содержимое обратно во флэш-память:

U-Boot> nand write.raw 0x20200000 0x2560000 1
NAND write:  2112 bytes written: OK

Достаточно забавно, диагностика nand bad не замечает только что отмеченный блок, даже после некоторого nand read попытки, которые do не удаются.

U-Boot> nand bad
Device 0 bad blocks:
U-Boot>

Но это не повод для тревоги.2-й плохой блок был помечен вручную аналогичным образом, и при следующем сбросе:

U-Boot> reset
resetting ...
RomBOOT
 ba_offset = 0xc ...
AT91Bootstrap 3.6.0-00029-g0cd4e6a (Wed Nov 12 12:14:04 CET 2014)
...
U-Boot 2013.10-00403-g1f9a20a (Nov 12 2014 - 12:14:27)
...
Hit any key to stop autoboot:  0
U-Boot> nand bad
Device 0 bad blocks:
  02560000
  060a0000
U-Boot>

И вот, маркировка «плохой блок» сохранилась!Следующая операция флеш-памяти аккуратно пропущена через поврежденные блоки, сохраняя согласованное ядро ​​и файловую систему в различных разделах флеш-памяти.Это было намерение с самого начала, но, похоже, оно требовало тщательной ручной работы.Разве нет автоматизированного способа?

1 Ответ

0 голосов
/ 26 сентября 2019

U-Boot сильно изменился с 2014 года. Патчи, которые могут иметь отношение к вашей проблеме, включают:

  • dc0b69fa9f97 ("mtd: nand: mxs_nand: разрешить включение поддержки BBT")
  • c4adf9db5d38 («spl: nand: sunxi: убрать поддержку так называемого режима« синдрома ») *
  • 8d1809a96699 (« spl: nand: simple: заменить readb () специальным чипом read_buf ()")

Пожалуйста, повторите тестирование с помощью U-Boot Git HEAD.Если по-прежнему чего-то не хватает, сообщите об этом в список разработчиков U-Boot или, что еще лучше, отправьте свой патч.

...