A tiny educational Linux (under 1 MB) that boots in QEMU or VirtualBox with 16 MB RAM, with optional AX.25 packet radio support.
- Tiny: the base system is 926 KB (kernel + initramfs) and boots with 16 MB RAM.
- Amateur radio: AX.25, NET/ROM, ROSE, KISS and 6PACK in the kernel, the
AX.25 tools and the Dire Wolf sound card modem. Dire Wolf and
kissattachgive an AX.25 network interface (ax0). A connection between two stations is not tested yet (see ROADMAP.md). - Persistent disk: a read-only squashfs root with an ext2 overlay for your changes.
- Configured with menuconfig: profiles (base, persistent, ham radio) and one option for each feature.
- Built from source without root: all programs are static (musl). The images run in QEMU and VirtualBox (ISO).
Download a file from the
latest release
and start it in QEMU (only qemu-system-x86_64 is needed):
tar xf smallham-v0.6-base-initramfs-x86_64.tar.xz
cd smallham-v0.6-base-initramfs-x86_64
./run.sh # type 'reboot' to leaveThe other files are described in Release files. For VirtualBox see Run with VirtualBox.
Install the packages in Requirements, then build the base image and start it in QEMU:
git clone https://github.com/dandidev/smallham-linux.git
cd smallham-linux
make defconfig
make
make run # type 'reboot' to leaveThis project builds a very small Linux system, mainly for learning. You can see
how a Linux system is put together from the ground up: the Linux kernel,
BusyBox and a few optional programs. The system is 64-bit (x86_64); the output
file names show it, e.g. smallham-ham-squashfs-vbox-x86_64.iso.
What you can learn and practice with it:
- compiling and configuring the Linux kernel
- initramfs and the boot process
- a custom init system
- core utilities with BusyBox
- configuration with Kconfig and Makefiles
- images that run in QEMU and VirtualBox
The amateur radio part is optional. The goal is to run it on minimal hardware, for example to simulate repeater stations or radio towers on ordinary computers.
- An x86_64 Linux computer. The build was tested on Arch Linux.
- Internet access:
makedownloads the sources (Linux kernel, BusyBox, musl, ...). - No root access is needed.
- Free disk space:
| Configuration | Free space needed | Used after the build |
|---|---|---|
Base image (defconfig) |
about 2 GB | about 1.8 GB |
Ham radio setup (ham_defconfig) |
about 2.5 GB | about 2.1 GB |
Most of it is the kernel source (1.5 GB). The images themselves are only a few MB.
Packages (Arch Linux):
sudo pacman -S base-devel bc git curl cmake libelf squashfs-tools e2fsprogs util-linux qemu-system-x86
# for the VirtualBox ISO:
sudo pacman -S syslinux cdrtools qemu-img
# for 'make release':
sudo pacman -S zipkconfig-frontends (kconfig-mconf, kconfig-conf) is not in the official
repositories. Install it from the AUR, for example with an AUR helper:
yay -S kconfig-frontendsYou only need the built files and one of these programs:
- QEMU:
qemu-system-x86_64(tested with QEMU 11.1) - VirtualBox: version 6.1 or newer, because the disk needs the VirtIO SCSI controller (tested with 7.2)
Memory (RAM) for the virtual machine:
| Configuration | Smallest RAM that boots | Recommended RAM |
|---|---|---|
| Base image | 16 MB | 16 MB |
| Ham radio setup | 20 MB (24 MB to run Dire Wolf) | 32 MB |
Measured sizes of the built system:
Base image (defconfig) |
Ham radio setup (ham_defconfig) |
|
|---|---|---|
Kernel (bzImage) |
813 KB | 1.6 MB |
| initramfs | 113 KB (the whole system) | 11 KB (only the disk mounter) |
| Root filesystem | inside the initramfs | 1.0 MB squashfs in the disk image (192 KB without the ham programs) |
| Total on disk | 926 KB | 2.6 MB (the disk image itself is 8 MB with free space) |
| VirtualBox ISO | 1.4 MB | 2.2 MB (+ 1.2 MB .vmdk disk) |
| RAM used after boot | 1.5 MB | 5.2 MB (8.8 MB with Dire Wolf running) |
The ham programs in the root filesystem (xz compressed): Dire Wolf 490 KB,
call 246 KB, ALSA configuration 147 KB, kissattach + kissparms +
netromd 108 KB, Dire Wolf data files 52 KB.
The base image has only the kernel and a BusyBox shell. You add every other
feature with make menuconfig:
make defconfig # base image (used when there is no .config)
make base_squashfs_defconfig # base system on a persistent disk (Persistent system profile)
make ham_defconfig # ham radio setup: disk, network, USB sound, AX.25, Dire Wolf
make base_vbox_defconfig # base image for VirtualBox (ISO)
make ham_vbox_defconfig # ham radio setup for VirtualBox (ISO + disk)
make menuconfig # add or remove features
make savedefconfig # save the current selection to ./defconfigTo keep a selection, copy ./defconfig to configs/<name>_defconfig. Then
make <name>_defconfig loads it.
In make menuconfig press ? to read the help of an option.
How the options are used:
| What | Where | How |
|---|---|---|
| Kernel | configs/kernel/*.config |
starts with everything off (allnoconfig), then adds the files of the selected options; all drivers are built in (no modules) |
| BusyBox | configs/busybox/*.config |
the same way as the kernel |
| Root filesystem | rootfs/<name>/ |
the selected directories are copied over each other (base always) |
| Programs | packages/*.mk |
built with musl and copied to the root filesystem |
scripts/check-config.sh stops the build if an option did not get into the
final config. This happens with a misspelled option name or a missing dependency.
A profile turns on a group of options with one choice. You can still turn off any option of the group or add others. Your changes are kept when you change the profile later.
None– no group (the base image)Persistent system– persistent disk, network, common tools, vi, system log (no ham radio)Ham radio station– the same asmake ham_defconfig
- Image name: part of the output file names. By default it comes from the profile (
baseorham), the root filesystem (initramfsorsquashfs) and the platform (-vboxfor VirtualBox), e.g.base-initramfs,base-squashfs,ham-squashfs-vbox - Target platform:
QEMU(disk: virtio-blk,/dev/vda) orVirtualBox (ISO)(disk: VirtIO SCSI,/dev/sda) - Root filesystem:
initramfs only: the whole system is in RAM, changes are lost on rebootPersistent disk: a read-only squashfs plus a writable ext2 partition, joined with overlayfs (fs_init); changes are kept
- Console: VGA screen and PS/2 keyboard, or serial port (
ttyS0, QEMU runs with-nographic) - ACPI:
poweroffswitches off the virtual machine (without it usereboot)
NET– network (virtio-net, IPv4, DHCP withifupandudhcpc)USB– USB host controllers (xHCI, EHCI), for USB devices passed to the VMUSB_STORAGE– USB drives, with FAT filesystemSOUND– USB sound cards (ALSA)HAM– AX.25, NET/ROM, ROSE, MKISS (KISS), 6PACK, BPQ, Baycom, YAM, pseudo terminals
BB_TOOLS– grep, sed, find, head, tail, less, top, ...BB_EDITOR– viBB_SYSLOG– syslogd, logread
- AX.25 tools (
kissattach,kissparms,netromd), AX.25 apps (call,listen,ax25ipd), Dire Wolf,aplay - Default config files, if you want them:
/usr/etc/ax25/axports,/etc/direwolf.conf
A feature has three parts: a Kconfig option, a config file and a few lines in the Makefile. Example: USB serial adapters (CP210x).
Kconfig:
config USB_SERIAL
bool "USB serial adapters (CP210x)"
depends on USB
configs/kernel/usb-serial.config:
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_CP210X=y
Makefile, next to the other options:
ifeq ($(CONFIG_USB_SERIAL),y)
KERNEL_FRAGMENTS += usb-serial
endifBusyBox commands (BUSYBOX_FRAGMENTS) and root filesystem files (ROOTFS_OVERLAYS)
are added the same way.
A package is a packages/<name>.mk file. The main Makefile includes it. The
file tells what to build and what to copy with three lists (FEATURE is a
Kconfig option without CONFIG_):
PKG_FEATURES += FEATURE|<make target> # build it
PKG_BINS += FEATURE|<built program> # copy it to /usr/bin
PKG_DIRS += FEATURE|<built dir>:<rootfs dir> # copy a data directoryBuild the programs as static binaries with $(MUSL_CC). See packages/ax25-tools.mk.
makeThe output files are in build/out/. Their names are
smallham-<image name>-x86_64-..., so the files of different configurations
(and later of other architectures) do not overwrite each other. make dbg-vars
shows the name for your configuration.
File (example: ham_defconfig) |
What it is |
|---|---|
smallham-ham-squashfs-x86_64-bzImage |
the kernel |
smallham-ham-squashfs-x86_64-initramfs.cpio.xz |
the initramfs (the whole system, or only fs_init with the persistent disk) |
smallham-ham-squashfs-x86_64-disk.img |
the disk image, only with Persistent disk |
smallham-ham-squashfs-x86_64-rootfs.squashfs |
the read-only root filesystem (also inside the disk image), only with Persistent disk |
Partitions of the disk image:
| Partition | Content | Used as |
|---|---|---|
1 (vda1) |
squashfs (xz), read-only root | lower layer of the overlay |
2 (vda2) |
ext2, writable | upper layer of the overlay (your changes) |
Note: make builds the disk image again, and this deletes your changes on the
writable partition. You can change the sizes, e.g. make DISK_SIZE_MB=16 SQUASHFS_SIZE_MB=8.
Make targets:
| Target | What it does |
|---|---|
make |
builds the kernel, the initramfs and the disk image |
make run |
starts the system in QEMU |
make iso |
makes the VirtualBox ISO (and .vmdk) |
make run-script |
writes the make run QEMU command as a script next to the output files |
make release |
builds all release variants into build/release/<version>/ (see Release files) |
make menuconfig, defconfig, <name>_defconfig, oldconfig, savedefconfig |
configuration |
make IMAGE_NAME=<name> |
build with another image name (other output file names) |
make dbg-vars |
shows the selected config files, packages and the kernel command line |
make clean-distro |
deletes the root filesystem and the output files, except the disk image |
make clean |
deletes everything, also the downloaded sources (~2 GB to download again) |
make release builds every variant one after the other and puts the files
into build/release/<version>/. The version comes from the git tag
(git describe), so run it in a clean checkout of a release tag. Your
.config is restored at the end.
| File | Configuration | What it is |
|---|---|---|
smallham-<version>-base-initramfs-x86_64.tar.xz |
defconfig |
QEMU: kernel + initramfs (the whole system in RAM), run.sh |
smallham-<version>-base-squashfs-x86_64.tar.xz |
base_squashfs_defconfig |
QEMU: base system on a persistent disk, run.sh |
smallham-<version>-ham-squashfs-x86_64.tar.xz |
ham_defconfig |
QEMU: ham radio setup on a persistent disk, run.sh |
smallham-<version>-base-initramfs-vbox-x86_64.iso |
base_vbox_defconfig |
VirtualBox: boots from the ISO alone |
smallham-<version>-ham-squashfs-vbox-x86_64.zip |
ham_vbox_defconfig |
VirtualBox: ISO + .vmdk disk |
smallham-<version>-sources.tar |
source code of SmallHam and of the programs in the images, except the kernel (list: SOURCES.md inside) |
|
linux-<kernel version>.tar.xz |
source code of the kernel (unmodified, the same file as on kernel.org) | |
SHA256SUMS |
checksums: sha256sum -c SHA256SUMS |
The .tar.xz and .zip files also contain the license texts of the programs
(licenses/) and a short README.txt.
make run builds the kernel and the initramfs if the configuration changed,
then starts QEMU. It does not build the disk image again if it exists, so your
changes are kept. Run make if you changed what goes into the root filesystem.
make run # default RAM: 30 MB
make run QEMU_MEM=20 # change RAM size (MB)
make run QEMU_EXTRA="-device qemu-xhci -device usb-host,vendorid=0x08bb,productid=0x2902"QEMU_EXTRA is given to QEMU as it is. The example passes a USB device of
your computer to the VM. Use the ids from lsusb on your computer; QEMU must
have access to /dev/bus/usb. With NET the VM uses QEMU's user network
(udhcpc gets 10.0.2.15).
To leave the system type reboot. QEMU runs with -no-reboot, so it stops
instead of starting again. With the ACPI option poweroff works too.
With the serial console leave QEMU with Ctrl-A X.
You can copy the files from build/out/ to any computer with QEMU and start
them there. make dbg-vars shows the kernel command line (-append) of your
configuration.
- Base image (
defconfig): copy the bzImage and the initramfs
qemu-system-x86_64 -m 16 -no-reboot \
-kernel smallham-base-initramfs-x86_64-bzImage \
-initrd smallham-base-initramfs-x86_64-initramfs.cpio.xz \
-append "notsc"- Ham radio setup (
ham_defconfig, persistent disk): copy also the disk image
qemu-system-x86_64 -m 32 -no-reboot \
-kernel smallham-ham-squashfs-x86_64-bzImage \
-initrd smallham-ham-squashfs-x86_64-initramfs.cpio.xz \
-drive file=smallham-ham-squashfs-x86_64-disk.img,format=raw,if=virtio \
-append "notsc squashfs_dev=/dev/vda1 rw_dev=/dev/vda2" \
-netdev user,id=net0 -device virtio-net-pci,netdev=net0- Serial console: add
console=ttyS0to-appendand-nographicto QEMU - ISO (
ham_vbox_defconfig): the kernel command line is inside the ISO.-boot dis needed, because the disk has no boot loader.
qemu-system-x86_64 -m 32 -no-reboot -boot d -cdrom smallham-ham-squashfs-vbox-x86_64.iso \
-device virtio-scsi-pci,id=scsi0 \
-drive file=smallham-ham-squashfs-vbox-x86_64-disk.img,format=raw,if=none,id=disk0 \
-device scsi-hd,drive=disk0,bus=scsi0.0 \
-netdev user,id=net0 -device virtio-net-pci,netdev=net0(For the base image only -cdrom smallham-base-initramfs-vbox-x86_64.iso is needed.)
Load a VirtualBox configuration (or select Target platform: VirtualBox (ISO)
in make menuconfig), then make the ISO:
make ham_vbox_defconfig # or: make base_vbox_defconfig
make isoOutput in build/out/:
File (example: ham_vbox_defconfig) |
What it is |
|---|---|
smallham-ham-squashfs-vbox-x86_64.iso |
bootable CD image with the kernel and the initramfs |
smallham-ham-squashfs-vbox-x86_64-disk.vmdk |
the persistent disk in VirtualBox format (only with Persistent disk) |
Copy these files to any computer with VirtualBox and set up a VM:
- Type: Linux, 64-bit. Memory: 16 MB for the base image, 32 MB for the ham radio setup
- Optical drive (IDE): the
.isofile, boot from it - Persistent disk: add a VirtIO SCSI storage controller and attach the
.vmdkfile to it - Network: adapter type Paravirtualized Network (virtio-net)
The same from the command line:
VBoxManage createvm --name smallham --ostype Linux_64 --register
VBoxManage modifyvm smallham --memory 32 --boot1 dvd --boot2 disk --nic1 nat --nictype1 virtio --graphicscontroller vboxvga --audio-enabled off
VBoxManage storagectl smallham --name IDE --add ide
VBoxManage storagectl smallham --name VSCSI --add virtio-scsi
VBoxManage storageattach smallham --storagectl IDE --port 1 --device 0 --type dvddrive --medium smallham-ham-squashfs-vbox-x86_64.iso
VBoxManage storageattach smallham --storagectl VSCSI --port 0 --device 0 --type hdd --medium smallham-ham-squashfs-vbox-x86_64-disk.vmdk
VBoxManage startvm smallhamWith a bridge the VM can be reached from your computer and your local network. Run these commands on your computer as root.
- Create the virbr0 bridge
ip link add name virbr0 type bridge
ip addr add 192.168.122.1/24 dev virbr0
ip link set virbr0 up
ethtool -K virbr0 tx off rx off
#ip addr show virbr0- Allow QEMU to use the bridge
echo "allow virbr0" >> /etc/qemu/bridge.conf- DHCP with dnsmasq (
port=5353turns off its DNS part; the VM gets public DNS servers)
# vim /etc/dnsmasq.conf
port=5353
interface=virbr0
bind-interfaces
listen-address=192.168.122.1
dhcp-range=192.168.122.100,192.168.122.150,12h
dhcp-option=3,192.168.122.1
dhcp-option=6,8.8.8.8,8.8.4.4- Iptables (
${interface}is your computer's network interface to the internet, e.g.eth0)
iptables -A INPUT -i virbr0 -j ACCEPT
iptables -A OUTPUT -o virbr0 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i virbr0 -o ${interface} -j ACCEPT
iptables -t nat -A POSTROUTING -o ${interface} -j MASQUERADE- Turn on forwarding
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward- Start QEMU with the bridge (persistent disk)
qemu-system-x86_64 -m 32 -no-reboot \
-kernel build/out/smallham-ham-squashfs-x86_64-bzImage \
-initrd build/out/smallham-ham-squashfs-x86_64-initramfs.cpio.xz \
-drive file=build/out/smallham-ham-squashfs-x86_64-disk.img,format=raw,if=virtio \
-append "notsc squashfs_dev=/dev/vda1 rw_dev=/dev/vda2" \
-device qemu-xhci -device usb-host,vendorid=0x08bb,productid=0x2902 \
-netdev bridge,id=net0,br=virbr0 \
-device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56There are no users: everything runs as root. This is why Dire Wolf shows a
warning at start. The commands below need the options in brackets
(make menuconfig).
The network starts at boot from /etc/network/interfaces (eth0 with DHCP).
To set it by hand:
ip link set eth0 up
udhcpc -i eth0
# or a fixed address:
ip addr add 10.0.2.15/24 dev eth0
ip route add default via 10.0.2.2ls -la /sys/class/sound/
cat /proc/asound/cards
lsusbFor a test without a real sound card, QEMU can emulate a USB speaker (output only):
make run QEMU_EXTRA="-audiodev none,id=snd0 -device qemu-xhci -device usb-audio,audiodev=snd0"Dire Wolf is the sound card modem. With -p it gives a virtual KISS TNC on a
pseudo terminal (link: /tmp/kisstnc). kissattach connects it to an AX.25
network interface (ax0).
- AX.25 port (or turn on
AX25_DEFAULT_CONFIG). Use your own callsign instead of N0CALL.
mkdir -p /usr/etc/ax25
echo "radio N0CALL-1 9600 255 2 KISS" > /usr/etc/ax25/axports- Dire Wolf configuration (or turn on
DIREWOLF_DEFAULT_CONFIG)
echo "ADEVICE plughw:0,0" > /etc/direwolf.confDire Wolf needs a sound input. The QEMU USB speaker (see Sound card) has only an output, so with it take the input from UDP (no packets arrive, but Dire Wolf starts and the KISS TNC works):
echo "ADEVICE udp:7355 plughw:0,0" > /etc/direwolf.conf- Start
direwolf -t 0 -p -c /etc/direwolf.conf > /tmp/direwolf.log 2>&1 &
kissattach /tmp/kisstnc radio 10.1.1.1
kissparms -c 1 -p radio # CRC off: Dire Wolf expects plain KISS
ip addr show ax0-t 0 turns off the colors. Without kissparms -c 1 Dire Wolf says
"Invalid transmit channel" for the frames of the Linux KISS driver.
Without root, on your computer. The read-only root is also a separate file:
cd build/out
unsquashfs -ls smallham-ham-squashfs-x86_64-rootfs.squashfs # read-only rootYour changes are on the second partition of the disk image (the numbers are
for the default partition sizes, see sfdisk -l <disk image>):
dd if=smallham-ham-squashfs-x86_64-disk.img of=/tmp/rw.ext2 bs=512 skip=14336
debugfs -R "ls -l /rw_root" /tmp/rw.ext2 # your changesWith root:
sudo losetup -fP build/out/smallham-ham-squashfs-x86_64-disk.img
#losetup -a
#lsblk
sudo mkdir -p /mnt/ro /mnt/rw
sudo mount -o ro /dev/loop0p1 /mnt/ro # squashfs (read-only root)
sudo mount /dev/loop0p2 /mnt/rw # ext2 (your changes: rw_root/)| Path | Content |
|---|---|
Kconfig, configs/*_defconfig |
feature selection |
configs/kernel/, configs/busybox/ |
config files of the features |
rootfs/ |
root filesystem files (base, network, ...) |
fs_init/ |
small init program for the persistent disk (mounts squashfs + overlay) |
packages/ |
extra programs (musl, AX.25, Dire Wolf, ALSA, ...) |
patches/ |
patches for the programs |
scripts/ |
helper scripts for the config files |
build/out/ |
output files: kernel, initramfs, disk image, ISO |
sources/, toolchain/, build/ |
downloaded sources, libraries, build output (not in git) |
Planned work and things that are not tested yet: ROADMAP.md. The changes of each version: CHANGELOG.md.
The files of this project (Makefile, Kconfig, configs/, packages/,
scripts/, rootfs/, fs_init/) are licensed under the GNU General Public
License version 2 (GPL-2.0-only), the same as the Linux kernel and BusyBox.
See LICENSE.
The programs that make downloads and builds (Linux kernel, BusyBox, musl,
Dire Wolf, AX.25 tools, ALSA, ncurses, ...) have their own licenses. The files
in patches/ change these programs and have the license of the program they
change.