I want to build a dedicated Linux system that only ever runs one binary program. This program takes control of the screen via the OpenGL driver and displays patterns. There needs to be keyboard input as well to configure the patterns. Since running this one program will be the sole purpose of the machine, I don't need any GUI, networking, etc. Also, I probably don't need any process scheduling in the kernel since only one process will ever run.
Is it possible to replace /sbin/init with my own binary to achieve this? After the kernel loads, it would then immediately execute my own binary, and that would run the entire time the machine was on. Basically, I want to emulate the way a microcontroller works, but with the benefit of being able to use an x86 CPU with different hardware devices and drivers.
It might be possible to replace /sbin/init
by your program, but you should be aware that process 1 has some specific duties. So I think it is not advisable to replace it.
Remember that a Linux kernel can also start some processes magically, outside of the usual fork
from a process inherited by the init process. I'm thinking of things like /sbin/modprobe
or /sbin/hotplug
etc.
Also, udev
(or systemd
) have some special roles. On some systems, fan control was related to such things (I really forgot the details). If unlucky, you could burn your hardware if fan is not working well (but AFAIK this is no more true on recent hardware).
By seeking with string
the vmlinux
in a recent 3.15.3 kernel, I find that it knows about:
I would recommend instead keeping some existing init program, and configure it to run only your program.
Minimal init hello world program step-by-step
Compile a hello world without any dependencies that ends in an infinite loop. 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
We cannot use sys_exit
, or else the kernel panics.
Then:
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"
This creates a filesystem with our hello world at /init
, which is the first userland program that the kernel will run. We could also have added more files to d/
and they would be accessible from the /init
program when the kernel runs.
Then cd
into the Linux kernel tree, build is as usual, and run it in 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"
And you should see a line:
FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR
on the emulator screen! Note that it is not the last line, so you have to look a bit further up.
You can also use C programs if you link them statically:
#include <stdio.h>
#include <unistd.h>
int main() {
printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
sleep(0xFFFFFFFF);
return 0;
}
with:
gcc -static init.c -o init
You can run on real hardware with a USB on /dev/sdX
and:
make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX
Great source on this subject: http://landley.net/writing/rootfs-howto.html It also explains how to use gen_initramfs_list.sh
, which is a script from the Linux kernel source tree to help automate the process.
Next step: setup BusyBox so you can interact with the system through a shell. Buildroot is a great way to do it .
Tested on Ubuntu 16.10, QEMU 2.6.1.
您可以将程序放到initrd ,然后从initrd的init运行它。
Simply use a boot paramter eg) init=/bin/bash
init is the process 1, used by kernel to start user space, which as a few specific duties like reaping children periodical to clean out zombies. Sounds like you don't even need that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.