我想构建一个只运行一个二进制程序的专用Linux系统。该程序通过OpenGL驱动程序控制屏幕并显示模式。还需要键盘输入来配置模式。由于运行这个程序将是机器的唯一目的,我不需要任何GUI,网络等。此外,我可能不需要内核中的任何进程调度,因为只有一个进程将永远运行
是否可以用我自己的二进制文件替换/ sbin / init来实现这个目的?在内核加载之后,它会立即执行我自己的二进制文件,这将在机器运行的整个时间内运行。基本上,我想模仿微控制器的工作方式,但是能够使用具有不同硬件设备和驱动程序的x86 CPU。
答案 0 :(得分:5)
您的程序可能会替换/sbin/init
,但您应该知道进程1有一些特定的职责。所以我认为不宜替换它。
请记住,Linux内核也可以通过init进程继承的进程在通常的fork
之外神奇地启动某些进程。我在想/sbin/modprobe
或/sbin/hotplug
等等。
此外,udev
(或systemd
)也有一些特殊的角色。在某些系统上,风扇控制与这些事情有关(我真的忘记了细节)。如果运气不好,如果风扇运行不正常,您可能会烧坏硬件(但AFAIK在最近的硬件上并不是这样)。
通过在最近的3.15.3内核中string
寻找vmlinux
,我发现它知道:
我建议改为保留一些现有的init程序,并将其配置为仅运行程序。
答案 1 :(得分:5)
最小的初始化hello world程序
编译一个没有任何以无限循环结尾的依赖关系的hello世界。 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"
这将在/init
创建一个带有我们的hello world的文件系统,这是内核将运行的第一个userland程序。我们还可以向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
您可以使用/dev/sdX
上的USB和
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,以便您可以通过shell与系统进行交互。 Buildroot is a great way to do it。
在Ubuntu 16.10,QEMU 2.6.1上测试。
答案 2 :(得分:2)
您可以将程序设置为initrd,然后从initrd的init中运行它。
答案 3 :(得分:1)
只需使用引导参数,例如{} {}}
init是进程1,由内核用来启动用户空间,作为一些特定的职责,比如收获儿童期刊来清理僵尸。听起来你甚至都不需要它。