У меня есть плата на базе MIPS (MediaTek mt7620) с проприетарным и закрытым загрузчиком (u-boot) с отключенной функциональностью, такой как booting a standalone application
. (Мне не разрешено менять / перезагружать этот загрузчик, потому что многие пользователи используют эту плату, и если мы обновляли загрузчик, и он не удался, мы столкнулись бы с множеством кирпичей :) (загрузчик поддерживает протокол boot over tftp
))
Я пытаюсь изменить последовательность загрузки, предоставляемую производителем платы: загрузчик ПЗУ -> флэш-загрузчик (u-boot) -> ядро linux на: загрузчик ПЗУ -> флэш-загрузчик (u-boot) -> загрузочная ловушка -> ядро Linux. Для другой платы (mt7621) с u-boot, которая поддерживает booting a standalone application
, я смог создать некоторый boot trap
u-boot образ (автономное приложение) и поместить его во флэш-память вместо ядра Linux (я переместил ядро Linux). вниз). (этот boot trap
делает некоторую работу, загружает и загружает ядро Linux, используя ranand_read/do_bootm
функции, предоставляемые u-boot через таблицу переходов.
Как я уже говорил, u-boot для платы на базе mt7620 не поддерживает booting a standalone application
, поэтому я решил создать boot trap
в качестве образа Linux для u-boot (не как отдельное приложение для u-boot). образ), сохраняя код boot trap
почти таким же (я изменил только сигнатуру функции: для образа автономного приложения u-boot передается 2 аргумента, для образа u-boot linux - 4; и адреса загрузки / ввода).
Это журнал с последовательного порта,
для платы на базе mt7621:
## Booting image at bc140000 ...
Image Name: Boot trap
Image Type: MIPS U-Boot Standalone Program (uncompressed)
Data Size: 524 Bytes = 0.5 kB
Load Address: a0600000
Entry Point: a0600000
Verifying Checksum ... OK
OK
boot trap: got a control
boot trap: load a real kernel...
.......................
boot trap: boot a real kernel...
## Booting image at 88000000 ...
Image Name: OpenWrt Linux-3.10.14
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 1494179 Bytes = 1.4 MB
Load Address: 80001000
Entry Point: 80001000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 80001000) ...
## Giving linux memsize in MB, 256
Starting kernel ...
LINUX started...
и для платы на базе mt7620:
## Booting image at bc140000 ...
Image Name: Boot trap
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 345 Bytes = 0.3 kB
Load Address: 80001000
Entry Point: 80001000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 80001000) ...
## Giving linux memsize in MB, 256
Starting kernel ...
Как видите, код в «загрузочной ловушке» (как образ Linux U-boot) застрял, у меня нет отладчика JTAG
, поэтому я могу только догадываться, что какое-то исключение произошло и плата застряла в бесконечности цикл внутри этого обработчика исключений.
Я вижу в исходных кодах u-boot для платы на базе mt7621 (у меня они есть :)) такие строчки кода:
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
...
switch (hdr->ih_type) {
case IH_TYPE_STANDALONE:
appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
(*appl)(argc-1, &argv[1]); // <--- pass a control to a standalone app
return 0;
...
switch (hdr->ih_os) {
default:
case IH_OS_LINUX:
do_bootm_linux (cmdtp, flag, argc, argv,
addr, len_ptr, verify);
break;
...
и следующие строки:
void do_bootm_linux (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
ulong addr, ulong * len_ptr, int verify)
{
...
void (*theKernel) (int, char **, char **, int *);
theKernel = (void (*)(int, char **, char **, int *)) ntohl (hdr->ih_ep);
...
theKernel (linux_argc, linux_argv, linux_env, 0); // <--- pass a control to a linux kernel
}
Итак, вопрос в том, в чем разница между загрузкой ядра Linux и автономного приложения? Почему linux должен установить указатель стека после получения элемента управления (linux / arch / mips / kernel / head.S), если у нас уже есть действительная среда C? Почему linux должен проделать такую большую работу, прежде чем передать элемент управления первой функции C (в автономном приложении мы можем поместить код функции C непосредственно в адрес, u-boot передает управление)?
Почему невозможно поместить код в адрес, на который u-boot передает управление, и просто запустить его, как я сделал для автономного приложения?