RZX-50: Доступ к консоли U-Boot

Antony продолжает исследование приставки Ritmix RZX-50. На этот раз жертвой экспериментов стал начальный загрузчик консоли — U-Boot.

Аннотация:
в данной статье рассматривается несложная модификация ПЗУ Ritmix RZX-50, обеспечивающая доступ к консоли U-Boot.

Статья может быть интересна разработчикам ПО для RZX-50.

Внимание! Для приставки, в которой ПЗУ построено на базе микросхемы NAND-flash описанная ниже методика не подойдёт. Прошу обладателей такой приставки связаться с автором.

Что такое U-Boot и зачем он нужен?

U-Boot — встроенное ПО RZX-50, загрузчик ОС. U-Boot является довольно популярным загрузчиком и нередко применяется во встраиваемых системах на базе RISC-процессоров (ARM, MIPS, PowerPC и др.). U-Boot распространяется под лицензией GPLv2.

На первый взгляд, по своему назначению U-Boot походит на BIOS персонального компьютера. Но по внешнему виду, устройству и возможностям разительно отличается.

Как правило, современная ПЭВМ обладает большими возможностями по изменению конфигурации аппаратных средств: часто возможно поменять центральный процессор и ОЗУ, а шины PCI, PCI Express и USB предоставляют широчайшие возможности по подключению периферии. В тоже время отсутствуют жёсткие ограничения на время старта. Требований по загрузке через сетевой интерфейс к BIOS не предъявляется, и эта функциональность реализуется ПЗУ, привязанной к конкретной сетевой плате. От BIOS также не требуется загружать ОС — для этого есть LILO, GRUB, NTLDR и др.

Требования встраиваемых систем (RZX-50 в том числе) к загрузчику совсем иные. Конфигурация аппаратуры, как правило, фиксирована или может варьироваться лишь незначительно.
Необходимо, чтобы от момента нажатия на рычаг POWER RZX-50 до момента, когда устройством можно пользоваться, проходило как можно меньше времени. Поэтому U-Boot должен очень быстро передать управление ядру ОС Linux. В режиме отладки, когда разработчик желает поэкспериментировать с разными образами ОС, необходимо предоставить соответствующие средства. Также очень желательно предоставлять средства для простейшей диагностики.

Какую работу обычно выполняет U-Boot? Вот грубый приблизительный перечень:

  • после снятия сигнала СБРОС U-Boot стартует из ПЗУ, проводит инициализацию важнейшей аппаратуры (UART, контроллер памяти, устанавливает режим работы процессора);
  • активирует необходимые драйверы (например, если U-Boot настроен на взаимодействие с пользователем через видеомонитор и клавиатуру, то необходимо, чтобы соответствующие драйверы сделали своё дело);
  • в зависимости от настроек автоматической загрузки либо переходит в режим диалога с пользователем, либо выполняет сценарий загрузки и запуска ядра ОС (обычно это Linux).

Что не так со штатным U-Boot RZX-50?

При старте U-Boot инициализирует консольное устройство и, если задана загрузка «по-умолчанию», выполняет соответствующие ей действия. В U-Boot реализована функция автозагрузки (англ. autoboot).

Суть автозагрузки:

  • преступать к загрузке операционной системы без каких-либо действий со стороны пользователя (весьма актуально для RZX-50);
  • перед тем, как перейти к загрузке ОС U-Boot даёт пользователю шанс — на экран выводится сообщение типа
    Hit any key to stop autoboot:  7
    

В описанном примере «7» — число секунд, в течении которых U-Boot будет ждать от пользователя нажатия на клавишу; в U-Boot этот параметр носит название bootdelay. По мере течения времени число секунд уменьшается до 0, после чего начинается загрузка ОС. Если пользователь воспользовался предоставленной возможностью, то он попадает в режим интерактивного взаимодействия с U-Boot, проще говоря, U-Boot будет печатать приглашение, а пользователь в ответ вводить команды (совсем как bash в интерактивном режиме).

Заметим, что заводской U-Boot RZX-50 лишает пользователя возможности получить доступ к консоли — первое же сообщение автозагрузки выглядит так:

Hit any key to stop autoboot:  0

Так-что даже зажимание какой-либо клавиши в эмуляторе терминала (т.е. символы будут поступать на вход U-Boot непрерывно) с последующим сбросом RZX-50 не позволят прервать автозагрузку.

Какую пользу несёт разблокировка U-Boot’а?

Рано или поздно захочется обновить ядро Linux. Это удобно делать, если есть возможность из U-Boot управлять загрузкой ядра.

Что понадобится для работы?

  • Ritmix RZX-50 с доработками, описанными в статье UART на Ritmix RZX-50;
  • ПЭВМ, подключённая к UART RZX-50, с программой эмулятора терминала.

Примечание: конечно можно произвести разблокировку загрузчика и на Ritmix RZX-50 без выведенного UART’а; однако воспользоваться плодами данной операции вряд ли получится, т.к. U-Boot взаимодействует с пользователем только через UART.

Разблокировку доступа к консоли U-Boot произведём, доведя значение параметра bootdelay до приемлемого положительного числа. На наше счастье значение bootdelay хранится в образе U-Boot в текстовой форме. Изменим это значение при помощи встроенного в RZX-50 Linux’а.

Но сначала немного теории.

Немного о структуре загрузочного ПЗУ RZX-50

Прежде чем исправлять U-Boot надо разобраться где он находится.

Напомню, что в качестве загрузочного ПЗУ в RZX-50 используется microSDHC-карта, спрятанная внутри приставки и недоступная для извлечения пользователем без вскрытия корпуса. В dingux данное устройство доступно как /dev/mmcblk0. В результате изучения содержимого указанной microSDHC-карты была построена таблица 1.

Таблица 1. Структура заводской прошивки microSDHC

смещение размер описание
0 около 952 КБ U-Boot + MBR
4 МБ 3 МБ ядро Linux-2.6.24
12 МБ 100 МБ /, ext3
112 МБ 60 МБ /usr/mtdblock2, ext3
172 МБ 80 МБ /usr/mtdblock3, ext3
252 МБ 3500 МБ /mnt/memory, fat
3752 МБ 4,5 МБ не используется

Примечание: Здесь и далее 1 байт = 8 бит, 1 КБ = 1024 байт, 1 МБ = 1024 КБ.

Вот структура секции, условно названной в таблице 1 «U-Boot + MBR», уточнена в таблице 2:

Таблица 2. структура секции «U-Boot + MBR»

смещение размер описание
0 8 байт branch + nop
0x1BE 66 байт MBR
0x200 около 952 КБ U-Boot

Примечание: размер U-Boot’а приведён ориентировочно на основании размера файла mbr-uboot-msc.bin из заводской прошивки для RZX-50 (v.1.0027)

Данная секция с одной стороны хранит код загрузчика, а с другой стороны таблицу разделов, которую ядро Linux использует для монтирования файловых систем.

Первые 8 байт содержат две инструкции, которые процессор выполнит сразу после снятия сигнала СБРОС и которые приведут к передаче управления на 0x204 байта «вперёд» (на начало U-Boot’а), не позволяя таким образом использовать данные MBR в качестве инструкций процессора:

__start:
    10000080        b       
    00000000        nop

Примечание: инструкция nop находится в слоте задержки инструкции ветвления и ей нельзя пренебречь.

Таким образом, для того, чтобы изменить U-Boot достаточно ограничиться рассмотрением первых 952 КБ microSDHC-карты, но для простоты счёта будем оперировать первым мегабайтом.

Модифицируем U-Boot

Включаем RZX-50 и дожидаемся приглашения dingux в эмуляторе терминала:

Welcome to dingux
(none) login:

Регистрируемся как пользователь root и попадаем в консоль Linux. Все описываемые ниже действия будем производить именно в этой консоли.

Итак, перейдём в /tmp и сохраним оригинальное состояние первого мегабайта загрузочной microSDHC-карты в файл uboot.1M.orig:

# cd /tmp
# dd if=/dev/mmcblk0 of=uboot.1M.orig bs=1M count=1

Примечание: тут и далее символ # — приглашение dingux, вводить его не надо!

Теперь определим смещение, с которым в uboot.1M.orig находится строка bootdelay=0.

Примечание: На выполнение указаной ниже связки команд hexdump + grep RZX-50 тратит около 30 секунд, запаситесь терпением.

# hexdump -C uboot.1M.orig | grep bootdel -C 1
00061f30  3a 20 22 25 73 22 20 6e  6f 74 20 64 65 66 69 6e  |: "%s" not defin|
00061f40  65 64 0a 00 0d 0a 00 00  62 6f 6f 74 64 65 6c 61  |ed......bootdela|
00061f50  79 00 00 00 62 6f 6f 74  63 6d 64 00 48 69 74 20  |y...bootcmd.Hit |
--
00065520  20 30 78 34 30 30 30 30  30 20 30 78 33 30 30 30  | 0x400000 0x3000|
00065530  30 30 3b 62 6f 6f 74 6d  00 62 6f 6f 74 64 65 6c  |00;bootm.bootdel|
00065540  61 79 3d 30 00 62 61 75  64 72 61 74 65 3d 35 37  |ay=0.baudrate=57|
--
00065610  30 20 30 78 33 30 30 30  30 30 3b 62 6f 6f 74 6d  |0 0x300000;bootm|
00065620  00 62 6f 6f 74 64 65 6c  61 79 3d 30 00 62 61 75  |.bootdelay=0.bau|
00065630  64 72 61 74 65 3d 35 37  36 30 30 00 6c 6f 61 64  |drate=57600.load|

Мы получили следующий результат: имеются две строки bootdelay=0: одна со смещением 415033 (0x00065539), другая со смещением 415265 (0x00065621). После ряда экспериментов установлено, что достаточно исправить первую (со смещением 415033).

Отступление: прозорливый читатель может заметить, что приведённое описание полагается на то, что подстрока bootdel (та, которую ищем при помощи grep) должна иметь смещение, остаток от деления на 16 которого должен быть меньше или равен 9. Иначе вывод hexdump может быть, например, таким:

00065520  33 30 30 30 30 30 3b 62  6f 6f 74 6d 00 62 6f 6f  |300000;bootm.boo|
00065530  74 64 65 6c 61 79 3d 30  00 62 61 75 64 72 61 74  |tdelay=0.baudrat|

В указанном случае bootdel найти не получится — тогда следует поискать строки типа lay=0; за очень небольшое число попыток смещения строк bootdelay=0 будут найдены.

Запомним смещением к bootdelay=0 в переменную BOOTDELAY_OFFSET:

# BOOTDELAY_OFFSET=415033

Теперь заменим bootdelay=0 на bootdelay=9, используя тот незатейливый инструментарий, который заложен в dingux.

Проверим себя, правильно ли определёно смещение строки bootdelay=0. По прежнему, находясь в /tmp выполняем:

# dd skip=$BOOTDELAY_OFFSET if=uboot.1M.orig bs=1 count=11 2>/dev/null

Если всё вычислено правильно, то на терминал будет выдано bootdelay=0.

# cp uboot.1M.orig uboot.1M.unblocked
# echo "bootdelay=9" > tempfile
# dd if=tempfile seek=$BOOTDELAY_OFFSET of=uboot.1M.unblocked \
> conv=notrunc bs=1 count=11
11+0 records in
11+0 records out

Проверяем внесённые изменения при помощи cmp:

# cmp -l uboot.1M.orig uboot.1M.unblocked
415044  60  71

Выдача 415044 63 71 показывает, что файлы отличаются на один байт, расположенный со смещением 415044: в первом файле на этом месте 63 (восьмеричное) (т.е. код символа 0), а во втором 71 (восьмеричное) (код символа 9).

Теперь запишем uboot.1M.unblocked на microSDHC-карту:

# dd if=uboot.1M.unblocked of=/dev/mmcblk0 bs=1M count=1

Перегружаем RZX-50 при помощи команды reboot и зажимаем какую-нибудь клавишу в эмуляторе терминала (читатель может удивиться — ведь мы поставили период задержки автозагрузки в 9 секунд, куда спешить? Но так надо!).

Неожиданность — U-Boot неправильно считает время (по крайней мере на экземпляре RZX-50 автора), девять секунд пролетаю почти мгновенно.

Если всё прошло удачно, то попадаем в консоль U-Boot.

Приглашение U-Boot выглядит так:

CETUS #

Список команд U-Boot можно получить при помощи команды help.

Читатель может спросить, кто такой CETUS? Разгадка очень проста. Cetus (в пер. с лат. кит) — макетная плата (англ. reference design), созданная для того, чтобы облегчить разработку потребительской электроники на базе JZ4755. По всей видимости, по своему устройству RZX-50 мало отличается от Cetus, а раз так, разработчики не стали утруждать себя и использовали имеющийся U-Boot. Данное наблюдение позволяет предположить, что и Linux для Cetus будет работать на RZX-50.

Примечание: дополнительно проверить, что U-Boot не в ладах с подсчётом времени, можно при помощи команды sleep, которая работает аналогично одноимённой команде Unix — ждёт указанное в первом аргументе число секунд, после чего завершает работу.

Например:

CETUS # sleep 600

На выполнение sleep 600 U-Boot тратит около одной секунды. Подобное пренебрежение точностью отсчёта времени может привести к тому, что не будут работать все протоколы, предусматривающие временные ограничения на выполняемые действия (например, DHCP и Y-modem).

Как загрузить заводской Linux из U-Boot?

Очень просто.

CETUS # msc read 0x80600000 0x400000 0x300000

MSC readSD init ok
 3145728 bytes OK: protocol

CETUS # bootm
## Booting image at 80600000 ...
   Image Name:   Linux-2.6.24.3L009-g40fe766b-dir
   Image Type:   MIPS Linux Kernel Image (gzip compressed)
   Data Size:    1177155 Bytes =  1.1 MB
   Load Address: 80010000
   Entry Point:  801f0710
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK

Starting kernel ...

О том, как с пользой задействовать U-Boot будет рассказано в следующих статьях.

Заключительные замечания

В статье dmesg Ritmix RZX-50 предлагается простая, но эффективная техника — записывать shell-скрипты на microSD-карту и исполнять их из меню консоли, таким образом действия вроде разблокировки U-Boot’а можно значительно упростить.

Кроме описываемого выше варианта разблокировки существуют и другие, возможно более простые методы:

  • получить от Ritmix образ U-Boot (RZX-50_fw_0.rar), модифицировать его на ПЭВМ при помощи любого hex-редактора и залить при помощи штатной программы-восстановителя (см. RZX-50_fw_how2.doc и RZX-50_fw_prog.rar);
    Недостаток данного метода — необходимость использовать ОС Windows, а также известная сложность письменного изложения инструкций по модификации бинарного образа U-Boot при помощи интерактивного hex-редактора;
  • разобрать приставку, извлечь microSDHC-карту, модифицировать на ПЭВМ и установить microSDHC-карту обратно.
    Недостаток — необходим разбор приставки, а кроме того данный способ неприменим для приставок с загрузкой с NAND-flash (см. статью Раздетая Dingoo A380, в приставке применяется MLC-large block NAND Flash K9LBG08U0M-PCB0).
 



Добавить комментарий

Комментарии доступны через Intensedebate. Включите JavaScript.