12

Я пытаюсь запустить приложение Linux, и все, что я хочу запустить - это одно приложение без загрузки. Мне нужна сеть и все (без дисплея, периферии и т.д.). Я не хочу, чтобы другие приложения работали, чтобы приложение, которое я запускаю, имело 100% ЦП. Это возможно?

6 ответов6

8

Минимальная программа initrd CPIO hello world, пошаговая инструкция

Скомпилируйте привет мир без каких-либо зависимостей, который заканчивается бесконечным циклом. init.S:

.global _start
_start:
    mov $1, %rax
    mov $1, %rdi
    mov $message, %rsi
    mov $message_len, %rdx
    syscall
    jmp .
    message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
    .equ message_len, . - message

Мы не можем использовать sys_exit , иначе ядро паникует.

Затем:

mkdir d
as --64 -o init.o init.S
ld -o init d/init.o
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"

Это создает файловую систему с нашим миром hello в /init , которая является первой пользовательской программой, которую будет запускать ядро. Мы могли бы также добавить больше файлов в d/ и они были бы доступны из программы /init при запуске ядра.

Затем cd в дерево ядра Linux, выполните сборку как обычно и запустите ее в QEMU:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"

И вы должны увидеть строку:

FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR

на экране эмулятора! Обратите внимание, что это не последняя строка, поэтому вам нужно посмотреть немного дальше.

Вы также можете использовать программы на C, если статически связываете их:

#include <stdio.h>
#include <unistd.h>

int main() {
    printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
    sleep(0xFFFFFFFF);
    return 0;
}

с:

gcc -static init.c -o init

Вы можете работать на реальном оборудовании с USB на /dev/sdX и:

make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX

Отличный источник на эту тему: http://landley.net/writing/rootfs-howto.html Также объясняется, как использовать gen_initramfs_list.sh , который является скриптом из дерева исходных текстов ядра Linux, чтобы помочь автоматизировать процесс.

Следующий шаг: настройте BusyBox, чтобы вы могли взаимодействовать с системой: https://unix.stackexchange.com/questions/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

Протестировано на Ubuntu 16.10, QEMU 2.6.1.

3

Похоже, вы пытаетесь установить киоск. Большинство руководств по Интернету фокусируются на веб-браузере, таком как Firefox, как на отдельном приложении, которое запускается. Посмотрите на это руководство для идей.

3

вы можете запустить ядро с параметром init=/path/to/myapp определенным в вашем загрузчике.

2

Конечно, вы можете запустить только одно пользовательское приложение после загрузки ядра. Но он не будет иметь 100% ЦП, потому что будут некоторые другие процессы, связанные с ядром, которые должны существовать. Обычно это делается на устройствах со встроенным Linux, например, беспроводных маршрутизаторах. У меня также есть опыт из первых рук, делающий это для многопоточного приложения.

После загрузки ядра запускается сценарий инициализации или запуска. Читайте об уровнях запуска Linux и процессе init. Существуют различные схемы запуска, поэтому невозможно быть конкретным. Но Linux позволит вам точно настроить, какие приложения и демоны будут выполняться в вашей ситуации. За исключением файла запуска в корневом каталоге, файлы, которые необходимо изменить, находятся в /etc и, в частности, /etc/init.d

Кстати, если вы не являетесь суперпрограммистом или не запускаете удаленный GDB-сервер, вам понадобится какая-то консоль отладки (консоль ПК или последовательный порт) для вашего приложения. Это позволит вам получать уведомления о сбоях сегмента, ошибках шины и ошибках подтверждения. Так что планируйте иметь что-то вроде "периферийного" помимо "сетевого".

2

Если вы действительно хотите ничего, кроме ядра Linux, работы в сети и вашего приложения, единственный способ сделать это - это:

  • Вам нужно будет сделать ваше приложение модулем ядра - убедитесь, что оно отлажено и хорошо протестировано. Этот модуль ядра должен был бы инициализировать то, что обычно делается через пользовательское пространство, например, устанавливать IP-адреса интерфейса и все такое хорошее.
  • Вам нужно будет загрузить и настроить (make menuconfig) свое собственное ядро и удалить все функции, не связанные с работой системы и работой в сети. Вы захотите отключить блокировку слоя, я не знаю, как это сделать на последних ядрах через make menuconfig .
  • Затем вам нужно включить ваш модуль в ядро, чтобы он был частью ядра, а не загружаемым модулем. Скорее всего, вы отключите загружаемые модули на шаге выше. Если вы знаете достаточно C/C++ для создания модуля ядра, это должно быть легко для вас.
  • Вам нужно изменить любую часть ядра, которая паникует, если init не может этого не сделать, или будьте готовы жить с 1 дополнительным процессом в пространстве пользователя.

Я знаю, что модули ядра могут создавать процессы - простой ps aux покажет многие в типичной системе (все они в скобках). Вы, вероятно, хотите, чтобы ваш модуль создал процесс ядра. Чтобы избавиться от всех процессов, созданных ядром, кроме ваших, вам необходимо отключить потоки [ kthreadd ], управление питанием [ pm ], слой событий [ events ] и другие.


Если вам нужна более практичная настройка процесса ядра + 1 пользовательского пространства, это возможно.

В Linux есть опция командной строки ядра, называемая init= - это то, что запускается ядром после завершения загрузки. Программа должна быть на корневом устройстве, которое указано с помощью root= или в initrd (загружается вашим загрузчиком).

Если эта программа закроется, Linux начнет паниковать, поэтому убедитесь, что она никогда не завершится.

Во многих современных дистрибутивах Linux он настроен, поэтому программа init в initrd выполняет некоторую дополнительную инициализацию пользовательского пространства перед запуском /sbin/init или /sbin/systemd . Вам нужно выяснить, что делает ваш дистрибутив здесь (информация для Debian здесь) и найти, где вы можете указать конечную программу "handoff", и оттуда вы можете указать ей запускать ваше приложение вместо init или systemd .

systemd управляет множеством базовых функций, таких как сборка /dev , установка имени хоста и других вещей, поэтому, если вы проявите гибкость, вы можете вместо этого взглянуть на настройку systemd для запуска отдельного процесса и, при необходимости, перезапустить его в случае сбоя. Если я не ошибаюсь, он в основном делает это для однопользовательского режима или режима восстановления - он запускает оболочку.

У вас будет запущено 2 процесса (systemd и ваша программа), но система не будет паниковать, если ваша программа закроется или выйдет из строя.

Рассмотрим также просто облегченную установку Debian - у установки "netinst" не так много работы, кроме ядра, оболочки и пары сервисов - или рассмотрим OpenWRT/LEDE - у нее есть веб-сервер для Luci, работающий по умолчанию, и пара других услуг, но легко отключается.

1

Есть некоторые системные приложения, которые должны быть запущены, кроме них, конечно, вы можете выделить остальные ресурсы компьютера для этого приложения. Чтобы получить минимум, вы можете взглянуть на действительно маленькие дистрибутивы Linux, такие как TinyCore Linux и т.д.

Также это будет зависеть от самого приложения, каких сервисов оно требует помимо сети и т.д.

Я думаю, что если вы сможете предоставить более конкретную информацию, вы получите более подробный ответ.

Как то, что приложение и т.д.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .