#c #linux #linux-kernel #kernel #hardware
#c #linux #linux-ядро #ядро #аппаратное обеспечение
Вопрос:
Я хочу создать выделенную систему Linux, в которой выполняется только одна двоичная программа. Эта программа управляет экраном через драйвер OpenGL и отображает шаблоны. Для настройки шаблонов также необходим ввод с клавиатуры. Поскольку запуск этой одной программы будет единственной целью машины, мне не нужен никакой графический интерфейс, сеть и т.д. Кроме того, мне, вероятно, не нужно никакого планирования процессов в ядре, поскольку когда-либо будет выполняться только один процесс.
Возможно ли заменить / sbin / init моим собственным двоичным файлом для достижения этой цели? После загрузки ядра оно немедленно выполнило бы мой собственный двоичный файл, и это работало бы все время, пока машина была включена. В принципе, я хочу эмулировать способ работы микроконтроллера, но с преимуществом возможности использовать процессор x86 с различными аппаратными устройствами и драйверами.
Ответ №1:
Пошаговая программа минимальной инициализации hello world
Скомпилируйте 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 FOOBARn"
.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 world по адресу /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 FOOBARn");
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, чтобы вы могли взаимодействовать с системой через оболочку. Buildroot — отличный способ сделать это.
Протестировано на Ubuntu 16.10, QEMU 2.6.1.
Ответ №2:
Возможно, его можно заменить /sbin/init
вашей программой, но вы должны знать, что у процесса 1 есть некоторые специфические обязанности. Поэтому я думаю, что не рекомендуется заменять его.
Помните, что ядро Linux также может запускать некоторые процессы волшебным образом, помимо обычного fork
, из процесса, унаследованного процессом инициализации. Я думаю о таких вещах, как /sbin/modprobe
или /sbin/hotplug
и т.д.
Кроме того, у udev
(или systemd
) есть некоторые особые роли. В некоторых системах управление вентилятором было связано с такими вещами (я действительно забыл детали). Если не повезет, вы можете сжечь свое оборудование, если вентилятор не работает должным образом (но, AFAIK, это больше не относится к новейшему оборудованию).
Выполнив поиск с помощью string
the vmlinux
в недавнем ядре 3.15.3, я обнаружил, что оно знает о:
- /bin/init
- /bin/sh
- /sbin/request-key
- /sbin/ tomoyo-init
- /sbin/modprobe
- /sbin/poweroff
- /sbin/ hotplug
Я бы рекомендовал вместо этого сохранить какую-нибудь существующую программу инициализации и настроить ее для запуска только вашей программы.
Комментарии:
1. Спасибо. Полагаю, я мог бы справиться с этими обязанностями в своей собственной программе, предполагая, что они не мешают ее работе. Я мог бы также отключить загрузку модуля и т.д. Или любую другую функцию ядра, для которой потребуется поддержка от init.
2. Некоторые другие вещи, которые приходят на ум, — это поддержка горячего подключения и загрузка модуля . Ядро иногда вызывает помощников пользовательского пространства , в зависимости от конфигурации и версии. Вам понадобится статически заполняемый каталог /dev / и т.д. Ваша программа, конечно, может
fork()
другие.
Ответ №3:
Вы можете поместить свою программу в initrd, а затем запустить ее из init init от initrd.
Ответ №4:
Просто используйте параметр загрузки, например) init=/bin/bash
init — это процесс 1, используемый ядром для запуска пользовательского пространства, который выполняет несколько специфических обязанностей, таких как периодическая обработка дочерних элементов для очистки от зомби. Похоже, вам даже это не нужно.