Как найти точку входа ARM Linux, когда она не распаковывается?

Я пытаюсь загрузить Linux через U-boot на пользовательской плате с i.MX6 (ядром ядра является ARM Cortex A9)

Мы, похоже, успешно поместили Das U-Boot (2009.08). Но загрузка Linux завершается с ошибкой в ​​последнем сообщении U-Boot: "Запуск ядра..."

Вот моя соответствующая среда:

bootargs=console=ttymxc1,115200 vmalloc=400M root=/dev/mmcblk0p1 rootwait consoleblank=0 earlyprintk video=mxcfb0:dev=lcd,LCD-ORTUS,if=RGB24 video=mxcfb1:dev=hdmi,1280x720M@60,if=RGB24 calibration tsdev=tsc2004 fbmem=10M,28M
bootcmd=ext2load mmc 0:1 10800000 /boot/uImage ; bootm 10800000

Выход для загрузки

Loading file "/boot/uImage" from mmc device 0:1 (xxa1) 
4043552 bytes read 
## Booting kernel from Legacy Image at 10800000 ... 
 Image Name: Linux-3.0.35 
 Image Type: ARM Linux Kernel Image (uncompressed) 
 Data Size: 4043488 Bytes = 3.9 MB 
 Load Address: 10008000 
 Entry Point: 10008000 
 Verifying Checksum ... OK 
 Loading Kernel Image ... OK 
OK 
Starting kernel ...

Когда я objdump ядро, по адресу 80008000, я вижу точку входа в arch/arm/kernel/head.S, а не arch/arm/boot/compress/head.S

Я вижу, что ядро ​​даже не распаковывает. Я попытался добавить некоторый код манипуляции регистром, чтобы сигнализировать GPIO в сжатом /head.S без ответа.

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

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

EDIT: Я добавил некоторые следы в U-Boot. Как раз перед вызовом ядра указатель theKernel составляет 10008000, а не 10800000. Означает ли это, что U-boot прыгает в неправильном месте?

3 ответа

Кажется, мы успешно поместили Das U-Boot.

Там видно, что это ошибочное предположение.

Перед вызовом ядра указатель theKernel равен 10008000, а не 10800000.

Какую версию U-Boot вы используете? В обеих версиях U-Boot 2012.10 и 2013.04 переменная theKernel объявляется и используется кодом для таких дуг, как AVR32 и MIPS. Нет кода ARM, который должен использовать theKernel.

u-boot-2012.10$ find . -print | xargs grep theKernel
./arch/avr32/lib/bootm.c: void (*theKernel)(int magic, void *tagtable);
./arch/avr32/lib/bootm.c: theKernel = (void *)images->ep;
./arch/avr32/lib/bootm.c: theKernel, params_start);
./arch/avr32/lib/bootm.c: theKernel(ATAG_MAGIC, params_start);
./arch/microblaze/lib/bootm.c: void (*theKernel) (char *, ulong, ulong);
./arch/microblaze/lib/bootm.c: theKernel = (void (*)(char *, ulong, ulong))images->ep;
./arch/microblaze/lib/bootm.c: (ulong) theKernel, rd_data_start, (ulong) of_flat_tree);
./arch/microblaze/lib/bootm.c: theKernel (commandline, rd_data_start, (ulong) of_flat_tree);
./arch/mips/lib/bootm.c: void (*theKernel) (int, char **, char **, int *);
./arch/mips/lib/bootm.c: theKernel = (void (*)(int, char **, char **, int *))images->ep;
./arch/mips/lib/bootm.c: (ulong) theKernel);
./arch/mips/lib/bootm.c: theKernel(linux_argc, linux_argv, linux_env, 0);
./arch/mips/lib/bootm_qemu_mips.c: void (*theKernel) (int, char **, char **, int *);
./arch/mips/lib/bootm_qemu_mips.c: theKernel = (void (*)(int, char **, char **, int *))images->ep;
./arch/mips/lib/bootm_qemu_mips.c: (ulong) theKernel);
./arch/mips/lib/bootm_qemu_mips.c: theKernel(0, NULL, NULL, 0);
./arch/nds32/lib/bootm.c: void (*theKernel)(int zero, int arch, **** params);
./arch/nds32/lib/bootm.c: theKernel = (void (*)(int, int, ****))images->ep;
./arch/nds32/lib/bootm.c: (ulong)theKernel);
./arch/nds32/lib/bootm.c: theKernel(0, machid, bd->bi_boot_params);
u-boot-2012.10$

Пожалуйста, объясните, как вы можете отслеживать переменную, которая не должна определяться или назначаться на процессоре ARM.

Следующий вывод после печати U-Boot "Запуск ядра..." должен быть "Uncompressing Linux...". Для арки Freescale этот вывод текста зависит от правильной передачи machine type number (aka arch_id) U-Boot в ядро. Вы должны убедиться, что этот machine type number правильно определен в U-Boot.

Как выглядит ваш файл конфигурации для U-Boot?

Я попытался добавить некоторый код манипуляции регистром, чтобы сигнализировать GPIO в сжатом /head.S без ответа.

Вы проверили этот код, чтобы убедиться, что он работает так, как вы ожидаете? Вы пытались выполнить операции GPIO из командной строки U-Boot?

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

Для арки ARM это переход к адресу, указанному в команде bootm. Поскольку адрес загрузки uImage и bootm указывают тот же адрес 0x10800000, это должно быть хорошо (при условии, что U-Boot настроен правильно и построен для ARM).

Перед вызовом ядра указатель theKernel равен 10008000, а не 10800000. Означает ли это, что U-boot прыгает в неправильном месте?

YES. Если вы проверите исходный код (для AVR32 или MIPS), вы обнаружите, что theKernel назначается из заголовка изображения, в частности значения точки входа. U-Boot затем переместится в это место. Но реальная проблема заключается в том, что ваш ARM Cortex A9 не должен использовать этот код или эту переменную. Кажется, что U-Boot не настроен для правильной арки и/или тип машины может быть неправильно определен.

КОРРЕКЦИИ:

Как указывал OP, более старые версии U-Boot использовали переменную theKernel даже для арки ARM.

Строка вывода U-Boot:

Loading Kernel Image ... OK

указывает, что U-Boot (успешно) скопировал образ ядра (без заголовка информации об изображении) с адреса bootm 0x10800000 (плюс смещение 0x40 для длины заголовка) на адрес загрузки 0x10008000. Эта операция перемещения памяти выполняется процедурой bootm_load_os() в common/cmd_bootm.c.

Итак, значение 0x10008000, о котором вы сообщили, верно для theKernel. Нет никаких указаний на то, что U-Boot прыгает в неправильное место.

Как уже упоминалось, вы должны убедиться, что тип машины правильно определен. Значение будет использоваться в __arch_decomp_setup() в arch/arm/plat-mxc/include/mach/uncompress.h, чтобы текст мог выводиться во время декомпрессии перед загрузкой ядра.


Кажется, вы не загружаете файл ядра vmlinux, поэтому вам не нужно беспокоиться о точках входа. Код декомпрессии в начале изображения будет перемещать ядро ​​по мере необходимости и переходить к правильной точке входа, когда это будет сделано. Вам просто нужно перейти к началу изображения, которое, похоже, делает uBoot правильно.

Я бы включил отладку ядра, особенно параметры отладки earlyprintk и lowlevel, и попробуйте снова загрузиться. По крайней мере, вы доберетесь, где это происходит.

Изменить: Как указано, мой ответ применяется только в том случае, если uBoot делает это правильно. В этом случае есть вероятность, что это не так. Возможно, вы можете создать и попытаться загрузить фиктивное "ядро", которое просто включает некоторые светодиоды или выводит некоторые регистровые значения в последовательные (в частности, r0, r1 и r2). Тогда вы можете, по крайней мере, проверить и/или исключить uBoot в качестве виновника.


Может быть, файл, загружаемый U-Boot, на самом деле является двоичным изображением файла vmlinux вместо самораспаковывающегося zImage/bzImage? Это просто предположение, я не эксперт в этом.

Этот вопрос, который я недавно спросил об Unix Stack Exchange, может вас заинтересовать: https://unix.stackexchange.com/questions/197225/is-vmlinuz-and-bzimage-really-the-same

licensed under cc by-sa 3.0 with attribution.