Какая разница между загрузкой ядра Linux и автономного приложения? - PullRequest
1 голос
/ 30 мая 2019

У меня есть плата на базе 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 передает управление, и просто запустить его, как я сделал для автономного приложения?

1 Ответ

1 голос
/ 30 мая 2019

Ядро Linux разработано для работы на тысячах различных систем, от небольших встроенных устройств до больших серверов. Было бы непрактично включать код для каждой возможной архитектуры, платы или конфигурации в ядро, поэтому вместо этого ядро ​​определяет набор требований к загрузке, которые должны быть выполнены, прежде чем оно сможет работать. Обычно задачей загрузчика является настройка надлежащей среды и выполнение этих требований.

Напротив, «автономное приложение» обычно пишется для конкретной целевой системы (архитектура, плата, конфигурация) и заботится о настройке в основном всего самого себя.

Вот почему u-boot по-разному обрабатывает оба случая. Если вы загружаете ядро ​​Linux, то u-boot настраивает все так, как ожидает ядро. Если вы загружаете отдельное приложение, то предполагается, что приложение будет делать все, что нужно.

...