Skip to content

Instantly share code, notes, and snippets.

@janderssonse
Created July 9, 2021 22:33
Show Gist options
  • Save janderssonse/b2fed403de83348408d0c9b53972294a to your computer and use it in GitHub Desktop.
Save janderssonse/b2fed403de83348408d0c9b53972294a to your computer and use it in GitHub Desktop.
Att bygga ett minimalt operativsystem med Linuxkärnan och Busybox för Qemu

Att bygga ett minimalt operativsystem med Linuxkärnan och Busybox för Qemu

Denna korta instruktion visar hur man kan bygga en minimal Linuxkärna med ett minimalt initramfs-root-filsystem och prova dem i Qemu. Vi tittar på två alternativ för initramfs-root-filsystemet:

  • att utgå från Busybox-källkoden (inspirerad av Mitchel Humpherys),
  • med hjälp av Buildroot.

Vi visar också hur man kan kompilera och testa ett användarprogram, Hello_world och en inläsningsbar kärnmodul, Hello_world.

Allmänt

export OPT=/opt
export BUILDS=/some/where/mini_linux
mkdir -p $BUILDS

Linuxkärnan

Kommentar: $OPT/linux är där du extraherar källkoden för kärnan.

export LINUX=$OPT/linux (här extraherar du koden för kärnan)
export LINUX_BUILD=$BUILDS/linux
mkdir -p $LINUX_BUILD
cd $LINUX
make O=$LINUX_BUILD allnoconfig
cd $LINUX_BUILD
make menuconfig

Konfigurera kärnan:

64-bit kernel ---> yes
General setup ---> Initial RAM filesystem and RAM disk (initramfs/initrd) support ---> yes
General setup ---> Configure standard kernel features ---> Enable support for printk ---> yes
Executable file formats / Emulations ---> Kernel support for ELF binaries ---> yes
Executable file formats / Emulations ---> Kernel support for scripts starting with #! ---> yes
Device Drivers ---> Generic Driver Options ---> Maintain a devtmpfs filesystem to mount at /dev ---> yes
Device Drivers ---> Generic Driver Options ---> Automount devtmpfs at /dev, after the kernel mounted the rootfs ---> yes
Device Drivers ---> Character devices ---> Enable TTY ---> yes
Device Drivers ---> Character devices ---> Serial drivers ---> 8250/16550 and compatible serial support ---> yes
Device Drivers ---> Character devices ---> Serial drivers ---> Console on 8250/16550 and compatible serial port ---> yes
File systems ---> Pseudo filesystems ---> /proc file system support ---> yes
File systems ---> Pseudo filesystems ---> sysfs file system support ---> yes

Bygg kärnan:

time make -j8
...
Kernel: arch/x86/boot/bzImage is ready  (#1)

real    2m37.247s
user    1m58.541s
sys     0m25.542s

Busybox

Kommentar: $OPT/busybox är där du extraherar källkoden för Busybox.

export BUSYBOX=$OPT/busybox _här ska källkoden för Busybox vara_
export BUSYBOX_BUILD=$BUILDS/busybox
mkdir -p $BUSYBOX_BUILD
cd $BUSYBOX
make O=$BUSYBOX_BUILD defconfig
cd $BUSYBOX_BUILD
make menuconfig

Konfigurera Busybox:

Busybox Settings ---> Build Options ---> Build BusyBox as a static binary (no shared libs) ---> yes

Bygg Busybox:

time make -j8
...
Final link with: m

real    0m20.356s
user    0m46.959s
sys     0m10.628s

Installera Busybox:

make install

Skapa initramfs:

export INITRAMFS_BUILD=$BUILDS/initramfs
mkdir -p $INITRAMFS_BUILD
cd $INITRAMFS_BUILD
mkdir -p bin sbin etc proc sys usr/bin usr/sbin
cp -a $BUSYBOX_BUILD/_install/* .

Lägg till ett skript,$INITRAMFS_BUILD/inittill initramfs, och låt innehållet vara följande:

#!/bin/sh

mount -t proc none /proc
mount -t sysfs none /sys

cat <<!


Boot took $(cut -d' ' -f1 /proc/uptime) seconds

        _       _     __ _                  
  /\/\ (_)_ __ (_)   / /(_)_ __  _   ___  __
 /    \| | '_ \| |  / / | | '_ \| | | \ \/ /
/ /\/\ \ | | | | | / /__| | | | | |_| |>  < 
\/    \/_|_| |_|_| \____/_|_| |_|\__,_/_/\_\ 


Welcome to mini_linux


!
exec /bin/sh

Skapa arkivet initramfs:

chmod +x init
find . -print0 | cpio --null -ov --format=newc \
  | gzip -9 > $BUILDS/initramfs.cpio.gz

Starta upp Qemu (<CTRL>a x för att avsluta)

qemu-system-x86_64 -kernel $LINUX_BUILD/arch/x86_64/boot/bzImage \
  -initrd $BUILDS/initramfs.cpio.gz -nographic \
  -append "console=ttyS0"

Kommentar: för bättre prestanda, lägg till flaggan-enable-kvmom din värd har KVM aktiverat:

qemu-system-x86_64 -kernel $LINUX_BUILD/arch/x86_64/boot/bzImage \
  -initrd $BUILDS/initramfs.cpio.gz -nographic \
  -append "console=ttyS0" -enable-kvm
...


Boot took 0.45 seconds

        _       _     __ _                  
  /\/\ (_)_ __ (_)   / /(_)_ __  _   ___  __
 /    \| | '_ \| |  / / | | '_ \| | | \ \/ /
/ /\/\ \ | | | | | / /__| | | | | |_| |>  < 
\/    \/_|_| |_|_| \____/_|_| |_|\__,_/_/\_\ 


Welcome to mini_linux


/ # ls /
bin      etc      linuxrc  root     sys
dev      init     proc     sbin     usr
/ # QEMU: Terminated

Buildroot

Vi antar att en verktygskedja är tillgänglig i/opt/toolchains/x86_64-unknown-linux-gnu med prefix x86_64-unknown-linux-gnu, gcc-version 5.x, kärn-headers 4.3.x, biblioteket glibc C och stöd för C++. Detta är rimliga standardvärden om du använder en verktygskedja genererad av crosstool-NG. Anpassa efter din egen situatuon. Viktigt:

  • Du kan inte använda din värddators ursprungliga verktygskedja (se dokumentationen för Buildroot för att förstå varför).
  • Om du inte redan har en verktygskedja kan du bygga en med crosstool-NG (eller själva Buildroot) och använda den senare för andra projekt.
  • crosstool-NG är det rekommenderade verktyget för att bygga en egen verktygskedja, men undvik att använda uClibc (inget IPV6-stöd) och föredra uClibc-ng eller glibc.
  • Ydu kan också använda den inbyggda verktygskedjan från Buildroot, men var medveten om att det kommer att ta längre tid än att använda en befintlig verktygskedja. Var också medveten om att i många fall kommer du att behöva bygga om verktygskedjan efter att ha modifierat Buildroot-konfigurationen.
  • Ännu inte övertygad? Se crosstool-NG, bygg och använd din egen verktygskedja. Gå till denna gist för en snabbstart i crosstool-NG.
export BUILDROOT=$OPT/buildroot _här läggs källkoden för Buildroot_
export BUILDROOT_BUILD=$BUILDS/buildroot
mkdir -p $BUILDROOT_BUILD
cd $BUILDROOT_BUILD
touch Config.in external.mk
echo 'name: mini_linux' > external.desc
echo 'desc: minimal linux system with buildroot' >> external.desc
mkdir configs overlay
cd $BUILDROOT
make O=$BUILDROOT_BUILD BR2_EXTERNAL=$BUILDROOT_BUILD qemu_x86_64_defconfig
cd $BUILDROOT_BUILD
make menuconfig

Konfigurera Buildroot:

Build options ---> Location to save buildroot config ---> $(BR2_EXTERNAL)/configs/mini_linux_defconfig
Build options ---> Download dir ---> /some/where/buildroot_dl
Build options ---> Number of jobs to run simultaneously (0 for auto) ---> 8
Build options ---> Enable compiler cache ---> yes
Build options ---> Compiler cache location ---> /some/where/buildroot_ccache
Toolchain ---> Toolchain type ---> External toolchain
Toolchain ---> Toolchain ---> Custom toolchain
Toolchain ---> Toolchain origin ---> Pre-installed toolchain
Toolchain ---> Toolchain path ---> /opt/toolchains/x86_64-unknown-linux-gnu
Toolchain ---> Toolchain prefix ---> x86_64-unknown-linux-gnu
Toolchain ---> External toolchain gcc version ---> 5.x
Toolchain ---> External toolchain kernel headers series ---> 4.3.x
Toolchain ---> External toolchain C library ---> glibc/eglibc
Toolchain ---> Toolchain has C++ support? ---> yes
System configuration ---> System hostname ---> mini_linux
System configuration ---> System banner ---> Welcome to mini_linux
System configuration ---> Run a getty (login prompt) after boot ---> TTY port ---> ttyS0
System configuration ---> Network interface to configure through DHCP --->
System configuration ---> Root filesystem overlay directories ---> $(BR2_EXTERNAL)/overlay
Kernel ---> Linux Kernel ---> no
Filesystem images ---> cpio the root filesystem (for use as an initial RAM filesystem) ---> yes
Filesystem images ---> Compression method ---> gzip

Spara konfigurationen:

make savedefconfig

Lägg till ett skript i katalogen overlay,$BUILDROOT_BUILD/overlay/init med följande konfiguration:

#!/bin/sh
/bin/mount -t devtmpfs devtmpfs /dev
/bin/mount -t proc none /proc
/bin/mount -t sysfs none /sys
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
cat <<!


Boot took $(cut -d' ' -f1 /proc/uptime) seconds

        _       _     __ _                  
  /\/\ (_)_ __ (_)   / /(_)_ __  _   ___  __
 /    \| | '_ \| |  / / | | '_ \| | | \ \/ /
/ /\/\ \ | | | | | / /__| | | | | |_| |>  < 
\/    \/_|_| |_|_| \____/_|_| |_|\__,_/_/\_\ 


Welcome to mini_linux


!
exec /bin/sh

Bygg root-filsystemet:

chmod +x overlay/init
time make
...
real    1m52.905s
user    0m50.682s
sys     0m36.928s

Starta upp Qemu (<CTRL>a x för att avsluta)

qemu-system-x86_64 -kernel $LINUX_BUILD/arch/x86_64/boot/bzImage \
  -initrd $BUILDROOT_BUILD/images/rootfs.cpio.gz -nographic \
  -append "console=ttyS0"

Kommentar: för bättre prestanda, lägg tll flaggan -enable-kvm om din värd har KVM aktiverat.

...


Boot took 0.57 seconds

        _       _     __ _                  
  /\/\ (_)_ __ (_)   / /(_)_ __  _   ___  __
 /    \| | '_ \| |  / / | | '_ \| | | \ \/ /
/ /\/\ \ | | | | | / /__| | | | | |_| |>  < 
\/    \/_|_| |_|_| \____/_|_| |_|\__,_/_/\_\ 


Welcome to mini_linux


/ # ls /
bin      init     linuxrc  opt      run      tmp
dev      lib      media    proc     sbin     usr
etc      lib64    mnt      root     sys      var
/ # QEMU: Terminated

Lägg till och kör ett eget program

Skapa en ny katalog för ditt program:

export APPS=$BUILDS/apps
mkdir -p $APPS
cd $APPS

Lägg till källkoden för ett program, $APPS/hello_world.c med följande innehåll:

#include <stdio.h>

int main(int argc, char **argv) {
	printf("mini_linux says: Hello world!\n");
	return 0;
}

Lägg till en make-file, $APPS/Makefile med följande innehåll (ersätt defintitionenCROSS_COMPILE med det som passar i ditt specifika fall):

CROSS_COMPILE	:= /opt/toolchains/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-
CC		:= $(CROSS_COMPILE)gcc

hello_world: hello_world.o
	$(CC) -o $@ $<

hello_world.o: hello_world.c
	$(CC) -c -o $@ $<

clean:
	rm -f hello_world hello_world.o

Kompilera programmet, kopiera in det in katalogen overlay i Buildroot och bygg om root-filsystemet:

make
...
cp hello_world $BUILDROOT_BUILD/overlay
...
cd $BUILDROOT_BUILD
make

Starta upp Qemu (<CTRL>a x för att avsluta)

qemu-system-x86_64 -kernel $LINUX_BUILD/arch/x86_64/boot/bzImage \
  -initrd $BUILDROOT_BUILD/images/rootfs.cpio.gz -nographic \
  -append "console=ttyS0"

Kommentar: för bättre prestanda, lägg till flaggan -enable-kvm om din värd har KVM aktiverad.

...


Boot took 0.57 seconds

        _       _     __ _                  
  /\/\ (_)_ __ (_)   / /(_)_ __  _   ___  __
 /    \| | '_ \| |  / / | | '_ \| | | \ \/ /
/ /\/\ \ | | | | | / /__| | | | | |_| |>  < 
\/    \/_|_| |_|_| \____/_|_| |_|\__,_/_/\_\ 


Welcome to mini_linux


/ # ls
bin          init         media        root         tmp
dev          lib          mnt          run          usr
etc          lib64        opt          sbin         var
hello_world  linuxrc      proc         sys
/ # ./hello_world
mini_linux says: Hello world!
/ # QEMU: Terminated

Lägg till stöd för inläsbara moduler i Linuxkärnan

cd $LINUX_BUILD
make menuconfig

Ändra kärnkonfigurationen:

Enable loadable module support ---> yes

Bygg om kärnan och dess moduler (ingen i vårat fall) och installera dem i katalogen overlay i Buildroot:

make -j8
make -j8 modules
make modules_install INSTALL_MOD_PATH=$BUILDROOT_BUILD/overlay

Lägga till en egen kärnmodul

Skapa en ny katalog för den egna kärnmodulen:

export MODULES=$BUILDS/modules
mkdir -p $MODULES
cd $MODULES

Lägg till källkodsfilen för en modul, $MODULES/hello_world.c med följande innehåll:

/* hello_world.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int __init first_init(void)
{
  pr_info("mini_linux module says: Hello world!\n");
  return 0;
}

static void __exit first_exit(void)
{
  pr_info("Bye\n");
}

module_init(first_init);
module_exit(first_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My first module");
MODULE_AUTHOR("The Doctor");

Lägg till en make-fil, $MODULES/Makefile med följande innehåll:

ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
obj-m := hello_world.o

else
# normal makefile
KDIR ?= $(LINUX_BUILD)

default:
	$(MAKE) -C $(KDIR) M=$$PWD

modules_install:
	$(MAKE) -C $(KDIR) M=$$PWD $@

clean:
	rm -rf *.o .*.cmd *.ko hello_world.mod.c modules.order Module.symvers .tmp_versions
endif

Kompilera modulen, installera den i Buildroots overlay-katalog och bygg om root-filsystemet:

make
...
make modules_install INSTALL_MOD_PATH=$BUILDROOT_BUILD/overlay
...
cd $BUILDROOT_BUILD
make

Starta upp Qemu (<CTRL>a x för att avsluta)

qemu-system-x86_64 -kernel $LINUX_BUILD/arch/x86_64/boot/bzImage \
  -initrd $BUILDROOT_BUILD/images/rootfs.cpio.gz -nographic \
  -append "console=ttyS0"

Kommentar: för bättre prestanda, lägg till flaggan -enable-kvm om din värd har KVM aktiverat.

...


Boot took 0.57 seconds

        _       _     __ _                  
  /\/\ (_)_ __ (_)   / /(_)_ __  _   ___  __
 /    \| | '_ \| |  / / | | '_ \| | | \ \/ /
/ /\/\ \ | | | | | / /__| | | | | |_| |>  < 
\/    \/_|_| |_|_| \____/_|_| |_|\__,_/_/\_\ 


Welcome to mini_linux


/ # ls lib/modules/4.8.0\+/extra
hello_world.ko
/ # lsmod
Module                  Size  Used by    Not tainted
/ # insmod lib/modules/4.8.0\+/extra/hello_world.ko
hello_world: loading out-of-tree module taints kernel.
mini_linux module says: Hello world!
/ # lsmod
Module                  Size  Used by    Tainted: G  
hello_world              704  -
/ # QEMU: Terminated

Att installera bygget på en usb-stick med extlinux

Se denna gist för hur du kan använda extlinux för att installera din distribution på t.ex en USB-lagringsenhet

Denna instruktion bygger på material från https://gist.github.com/pacalet/660fa6472e0bcd53f71fc31f167c628f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment