Вопрос или проблема
Я пытаюсь создать образ Linux-дистрибутива для ARM с использованием big endian. Поскольку я на Gentoo, кросс-компиляция не может быть проще. Я уже все собрал, но затем столкнулся с проблемой загрузки его/ядра.
Я нацелен на Cubieboard с процессором AllWinner A10. В качестве загрузчика я использую u-boot. Поскольку u-boot не поддерживает big endian ARM, я внес правки именно перед передачей управления ядру:
diff -Naur u-boot-2016.01-1/arch/arm/lib/bootm.c u-boot-2016.01-2/arch/arm/lib/bootm.c
--- u-boot-2016.01-1/arch/arm/lib/bootm.c 2016-01-12 15:06:54.000000000 +0100
+++ u-boot-2016.01-2/arch/arm/lib/bootm.c 2017-07-09 14:13:29.675865446 +0200
@@ -315,7 +315,16 @@
0, machid, r2);
} else
#endif
+ {
+ {
+ unsigned long v;
+ __asm volatile ("mrc p15, 0, %0, c1, c0, 0\n\t"
+ "orr %0, %0, #(1 << 7)\n\t" /* Переключение на bigendian */
+ "mcr p15, 0, %0, c1, c0, 0" : "=&r" (v));
+ }
+
kernel_entry(0, machid, r2);
+ }
}
#endif
}
Изначально я использовал немного другую синтаксис, но в конце концов взял известный работоспособный код из загрузчика APEX (его arm-kernel-shim). (Тем не менее, регистр такой же, как я имел и что я прочитал в документации ARM.)
Также, поскольку u-boot должен быть little endian, я подготовил другой набор инструментов для него – с целью arm-linux-gnueabihf
. Насколько я вижу, сам u-boot загружается нормально.
(Главное) ядро скомпилировано с набором инструментов для цели armeb-linux-gnueabihf
. Из скомпилированного образа (arch/arm/boot/Image
в дереве исходных/рабочих файлов ядра) я создал загружаемый образ (используя mkimage
из своего сборки u-boot):
mkimage -C none -A arm -T kernel -n Linux-4.9.9-gentoo -d /usr/armeb-linux-gnueabihf/usr/src/linux/arch/arm/boot/Image -ep 0x48000000 -a 0x48000000 /usr/armeb-linux-gnueabihf/boot/uimage
Я также взял файл DTB из ядра:
cp /usr/armeb-linux-gnueabihf/usr/src/linux/arch/arm/boot/dts/sun4i-a10-cubieboard.dtb /usr/armeb-linux-gnueabihf/boot/
Когда я загружаю все это на карту µSD и пытаюсь загрузиться, я получаю следующий вывод на последовательном консоли:
U-Boot SPL 2016.01 (Jul 16 2017 - 13:52:00)
DRAM: 1024 MiB
CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2
Trying to boot from MMC
U-Boot 2016.01 (Jul 16 2017 - 13:52:00 +0200) Allwinner Technology
CPU: Allwinner A10 (SUN4I)
I2C: ready
DRAM: 1 GiB
MMC: SUNXI SD/MMC: 0
In: serial
Out: serial
Err: serial
SCSI: SUNXI SCSI INIT
SATA link 0 timeout.
AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part ccc apst
Net: eth0: ethernet@01c0b000
starting USB...
USB0: USB EHCI 1.00
USB1: USB OHCI 1.0
USB2: USB EHCI 1.00
USB3: USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
Hit any key to stop autoboot: 0
=> setenv bootargs console=tty0 console=ttyS0,115200 earlyprintk hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1280x800p60 root=PARTUUID=AC9D6C6F-01 rootwait panic=10
=> ext2load mmc 0 0x48000000 boot/uimage
5025856 bytes read in 592 ms (8.1 MiB/s)
=> ext2load mmc 0 0x51000000 boot/sun4i-a10-cubieboard.dtb
28542 bytes read in 237 ms (117.2 KiB/s)
=> bootm 0x48000000 - 0x51000000
## Booting kernel from Legacy Image at 48000000 ...
Image Name: Linux-4.9.9-gentoo
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 5025792 Bytes = 4.8 MiB
Load Address: 48000000
Entry Point: 48000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 51000000
Booting using the fdt blob at 0x51000000
Loading Kernel Image ... OK
Loading Device Tree to 49ff6000, end 49ffff7d ... OK
Starting kernel ...
И он просто зависает на этом месте – никакого прогресса, никакого вывода, ничего. Мой вопрос: как двигаться дальше/как узнать, что на самом деле происходит? Я что-то упустил, сделал что-то не так (или не сделал что-то)?
Некоторые другие вещи, которые я пробовал, но безуспешно:
-
перестановка слов в образе ядра (как делает APEX) (это привело к
неопределенной инструкции
при загрузке), -
использование сжатого образа ядра,
-
использование старого файла FEX вместо FDT.
Обновление 2017/07/21: Мне частично удалось решить свою проблему. Я прислушался к подсказке из комментария Тома Рини и попробовал упаковать zImage в uImage, что дало возможность загрузки ядра. С помощью кастомной программы инициализации (просто простое Hello World, скомпилированное либо BE, либо LE) я подтвердил подозрение другого Тома Рини: моё оригинальное ядро было не big endian, а little. Чтобы это исправить, я добавил следующие две строки в начало конфигурационного файла ядра .config
:
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
CONFIG_CPU_BIG_ENDIAN=y
Я взял вдохновение из инструкции для Nvidia Jetson TK1. Я также добавил следующую строку в arch/arm/mach-sunxi/Kconfig
в конце раздела A10:
select ARCH_SUPPORTS_BIG_ENDIAN
Оказалось, что этого достаточно для сборки и загрузки ядра big endian, так как само ядро переключает CPU в режим big endian. Однако оно делает это с помощью инструкции setend
— её действие распространяется только на само ядро, а не на пользовательское пространство (как объясняет ссылка в ответе Мюррея Дженсена).
Я собираюсь попробовать:
-
перейти к точке входа декомпрессора ядра через исключение, или (если не получится)
-
внести изменения в ядро, чтобы оно создавалo процессы в режиме big endian (хотя я как бы чувствую, что это может быть рискованно…).
Ответ или решение
Чтобы успешно загрузить Linux на ARM с поддержкой большого эндьянса с использованием U-Boot на Cubieboard с процессором Allwinner A10, необходимо выполнить несколько ключевых шагов и учесть особенности архитектуры. Ниже приведены основные шаги и рекомендации, которые помогут вам решить возникшие проблемы.
1. Подготовка U-Boot
Поскольку U-Boot не поддерживает большой эндьянс (BE) ARM, ваш патч для переключения на большую эндьянскость в коде U-Boot кажется обоснованным. Однако важно убедиться, что U-Boot корректно передаёт управление ядру.
- Проверьте, что ваши изменения соответствуют спецификациям ARM и что вы правильно работаете с регистрами. Можно использовать другие версии U-Boot или более свежие патчи, если они доступны.
2. Компиляция ядра Linux
Чтобы ядро Linux работало с большой эндьянскостью, вы должны установить соответствующие конфигурационные параметры в файле .config
:
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
CONFIG_CPU_BIG_ENDIAN=y
Эти параметры гарантируют, что ядро будет собрано с поддержкой большого эндьянса.
3. Использование условной компоновки
Поскольку команда setend
устанавливает только режим для ядра, вам, возможно, придётся изменить способ запуска ядра, чтобы передачи управления происходило через обработчик исключений, как упоминалось в руководствах по архитектуре ARM. Это гарантирует, что система будет работать в требуемом режиме большой эндьянскости во всем процессе.
4. Упаковка в uImage
Как вы уже выяснили, использование zImage
и упаковка его в uImage
может позволить вашему ядру загружаться корректно, поскольку это может включать дополнительные операции совместимости, необходимые вашему оборудованию. Пример команды:
mkimage -C none -A arm -T kernel -n Linux-4.9.9-gentoo -d /path/to/zImage /path/to/uImage
5. Проверка загрузки
После загрузки проверьте, что U-Boot успешно загружает и выполняет ядро. Если возникают проблемы, например, "undefined instruction", возможно, ядро всё еще собралось как LITTLE ENDIAN. Убедитесь, что все соответствующие компоненты системы (ядро, библиотеки) собраны с поддержкой большого эндьянса.
6. Программирование и отладка
Если вы все еще не можете загрузить ядро:
- Убедитесь, что используете правильную версию DTB, соответствующую вашей сборке ядра.
- Используйте отладочные функции. На этапе загрузки проверяйте вывод UART и ищите подтасовки в логах, которые могут указать на проблемы с мочением внутренней структуры объектов.
- Создайте простой тестовый образ, содержащий базовую команду, чтобы убедиться, что ваше ядро действительно загрузилось в большом эндьянсе.
Заключение
Сложности, с которыми вы сталкиваетесь, связаны с различиями в настройках эндьянса, архитектурных особенностях и способом загрузки. Важно сочетать правильную конфигурацию U-Boot, ядра и убедиться, что вся система правильно обрабатывает переключения между режимами. Успехов в ваших дальнейших экспериментах с ARM и Linux!